@memberjunction/ng-core-entity-forms 5.43.0 → 5.45.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/dist/__tests__/model-prediction.logic.test.d.ts +2 -0
- package/dist/__tests__/model-prediction.logic.test.d.ts.map +1 -0
- package/dist/__tests__/model-prediction.logic.test.js +140 -0
- package/dist/__tests__/model-prediction.logic.test.js.map +1 -0
- package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.js +79 -105
- package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js +7 -10
- package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/add-action-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/add-action-dialog.component.js +46 -51
- package/dist/lib/custom/AIAgents/add-action-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts +2 -0
- package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js +300 -378
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js +22 -29
- package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/new-agent-dialog.component.js +15 -17
- package/dist/lib/custom/AIAgents/new-agent-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js +27 -34
- package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.d.ts +11 -0
- package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js +48 -47
- package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +438 -454
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
- package/dist/lib/custom/AIPromptRuns/chat-message-viewer.component.js +48 -51
- package/dist/lib/custom/AIPromptRuns/chat-message-viewer.component.js.map +1 -1
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +253 -282
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
- package/dist/lib/custom/Actions/action-execution-log-form.component.js +24 -33
- package/dist/lib/custom/Actions/action-execution-log-form.component.js.map +1 -1
- package/dist/lib/custom/Actions/action-form.component.js +263 -311
- package/dist/lib/custom/Actions/action-form.component.js.map +1 -1
- package/dist/lib/custom/Entities/entity-form.component.d.ts +6 -0
- package/dist/lib/custom/Entities/entity-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Entities/entity-form.component.js +475 -493
- package/dist/lib/custom/Entities/entity-form.component.js.map +1 -1
- package/dist/lib/custom/Lists/list-form.component.d.ts +1 -0
- package/dist/lib/custom/Lists/list-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Lists/list-form.component.js +126 -175
- package/dist/lib/custom/Lists/list-form.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.d.ts +1 -0
- package/dist/lib/custom/Queries/query-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.js +196 -252
- package/dist/lib/custom/Queries/query-form.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-run-dialog.component.js +19 -23
- package/dist/lib/custom/Queries/query-run-dialog.component.js.map +1 -1
- package/dist/lib/custom/SearchScopes/searchscopeprovider-form.component.js +23 -24
- package/dist/lib/custom/SearchScopes/searchscopeprovider-form.component.js.map +1 -1
- package/dist/lib/custom/Templates/template-param-dialog.component.js +14 -23
- package/dist/lib/custom/Templates/template-param-dialog.component.js.map +1 -1
- package/dist/lib/custom/Templates/template-params-grid.component.d.ts +1 -0
- package/dist/lib/custom/Templates/template-params-grid.component.d.ts.map +1 -1
- package/dist/lib/custom/Templates/template-params-grid.component.js +5 -3
- package/dist/lib/custom/Templates/template-params-grid.component.js.map +1 -1
- package/dist/lib/custom/Templates/templates-form.component.d.ts +2 -1
- package/dist/lib/custom/Templates/templates-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Templates/templates-form.component.js +10 -4
- package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.d.ts +2 -1
- package/dist/lib/custom/Tests/test-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.js +105 -133
- package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.js +187 -205
- package/dist/lib/custom/Tests/test-run-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts +10 -1
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.js +417 -492
- package/dist/lib/custom/Tests/test-suite-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-run-form.component.js +100 -126
- package/dist/lib/custom/Tests/test-suite-run-form.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js +166 -184
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.d.ts +15 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.js +283 -158
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-node.component.d.ts +10 -0
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-node.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-node.component.js +80 -26
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-node.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js +11 -18
- package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts +0 -2
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +263 -258
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/flow/agent-run-flow.component.d.ts +108 -0
- package/dist/lib/custom/ai-agent-run/flow/agent-run-flow.component.d.ts.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/agent-run-flow.component.js +665 -0
- package/dist/lib/custom/ai-agent-run/flow/agent-run-flow.component.js.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/agent-run-flow.model.d.ts +94 -0
- package/dist/lib/custom/ai-agent-run/flow/agent-run-flow.model.d.ts.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/agent-run-flow.model.js +257 -0
- package/dist/lib/custom/ai-agent-run/flow/agent-run-flow.model.js.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/constellation.component.d.ts +38 -0
- package/dist/lib/custom/ai-agent-run/flow/constellation.component.d.ts.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/constellation.component.js +200 -0
- package/dist/lib/custom/ai-agent-run/flow/constellation.component.js.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/flame-cascade.component.d.ts +44 -0
- package/dist/lib/custom/ai-agent-run/flow/flame-cascade.component.d.ts.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/flame-cascade.component.js +180 -0
- package/dist/lib/custom/ai-agent-run/flow/flame-cascade.component.js.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/flow-svg.util.d.ts +12 -0
- package/dist/lib/custom/ai-agent-run/flow/flow-svg.util.d.ts.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/flow-svg.util.js +46 -0
- package/dist/lib/custom/ai-agent-run/flow/flow-svg.util.js.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/flowchart.component.d.ts +64 -0
- package/dist/lib/custom/ai-agent-run/flow/flowchart.component.d.ts.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/flowchart.component.js +267 -0
- package/dist/lib/custom/ai-agent-run/flow/flowchart.component.js.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/pan-zoom.d.ts +53 -0
- package/dist/lib/custom/ai-agent-run/flow/pan-zoom.d.ts.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/pan-zoom.js +111 -0
- package/dist/lib/custom/ai-agent-run/flow/pan-zoom.js.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/subway-lines.component.d.ts +42 -0
- package/dist/lib/custom/ai-agent-run/flow/subway-lines.component.d.ts.map +1 -0
- package/dist/lib/custom/ai-agent-run/flow/subway-lines.component.js +193 -0
- package/dist/lib/custom/ai-agent-run/flow/subway-lines.component.js.map +1 -0
- package/dist/lib/custom/custom-forms.module.d.ts +58 -51
- package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
- package/dist/lib/custom/custom-forms.module.js +52 -13
- package/dist/lib/custom/custom-forms.module.js.map +1 -1
- package/dist/lib/custom/shared/entity-selector-dialog.component.d.ts +2 -0
- package/dist/lib/custom/shared/entity-selector-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/shared/entity-selector-dialog.component.js +25 -25
- package/dist/lib/custom/shared/entity-selector-dialog.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js +302 -216
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentChannel/mjaiagentchannel.form.component.js +25 -21
- package/dist/lib/generated/Entities/MJAIAgentChannel/mjaiagentchannel.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js +152 -78
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRunStep/mjaiagentrunstep.form.component.js +23 -21
- package/dist/lib/generated/Entities/MJAIAgentRunStep/mjaiagentrunstep.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentSession/mjaiagentsession.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentSession/mjaiagentsession.form.component.js +56 -34
- package/dist/lib/generated/Entities/MJAIAgentSession/mjaiagentsession.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentSkill/mjaiagentskill.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJAIAgentSkill/mjaiagentskill.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJAIAgentSkill/mjaiagentskill.form.component.js +66 -0
- package/dist/lib/generated/Entities/MJAIAgentSkill/mjaiagentskill.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.js +55 -19
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js +46 -10
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAISkill/mjaiskill.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJAISkill/mjaiskill.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJAISkill/mjaiskill.form.component.js +169 -0
- package/dist/lib/generated/Entities/MJAISkill/mjaiskill.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJAISkillAction/mjaiskillaction.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJAISkillAction/mjaiskillaction.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJAISkillAction/mjaiskillaction.form.component.js +64 -0
- package/dist/lib/generated/Entities/MJAISkillAction/mjaiskillaction.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJAISkillPermission/mjaiskillpermission.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJAISkillPermission/mjaiskillpermission.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJAISkillPermission/mjaiskillpermission.form.component.js +82 -0
- package/dist/lib/generated/Entities/MJAISkillPermission/mjaiskillpermission.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJAISkillSubAgent/mjaiskillsubagent.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJAISkillSubAgent/mjaiskillsubagent.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJAISkillSubAgent/mjaiskillsubagent.form.component.js +64 -0
- package/dist/lib/generated/Entities/MJAISkillSubAgent/mjaiskillsubagent.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJAction/mjaction.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAction/mjaction.form.component.js +35 -17
- package/dist/lib/generated/Entities/MJAction/mjaction.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJActionExecutionLog/mjactionexecutionlog.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJActionExecutionLog/mjactionexecutionlog.form.component.js +23 -5
- package/dist/lib/generated/Entities/MJActionExecutionLog/mjactionexecutionlog.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJApplication/mjapplication.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJApplication/mjapplication.form.component.js +78 -52
- package/dist/lib/generated/Entities/MJApplication/mjapplication.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCollection/mjcollection.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJCollection/mjcollection.form.component.js +25 -7
- package/dist/lib/generated/Entities/MJCollection/mjcollection.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCollectionArtifact/mjcollectionartifact.form.component.js +11 -7
- package/dist/lib/generated/Entities/MJCollectionArtifact/mjcollectionartifact.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversation/mjconversation.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJConversation/mjconversation.form.component.js +105 -47
- package/dist/lib/generated/Entities/MJConversation/mjconversation.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversationDetail/mjconversationdetail.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJConversationDetail/mjconversationdetail.form.component.js +73 -59
- package/dist/lib/generated/Entities/MJConversationDetail/mjconversationdetail.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversationWidgetInstance/mjconversationwidgetinstance.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJConversationWidgetInstance/mjconversationwidgetinstance.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJConversationWidgetInstance/mjconversationwidgetinstance.form.component.js +86 -0
- package/dist/lib/generated/Entities/MJConversationWidgetInstance/mjconversationwidgetinstance.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.js +30 -12
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCredentialType/mjcredentialtype.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJCredentialType/mjcredentialtype.form.component.js +27 -9
- package/dist/lib/generated/Entities/MJCredentialType/mjcredentialtype.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJDuplicateRunDetailMatch/mjduplicaterundetailmatch.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJDuplicateRunDetailMatch/mjduplicaterundetailmatch.form.component.js +24 -4
- package/dist/lib/generated/Entities/MJDuplicateRunDetailMatch/mjduplicaterundetailmatch.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js +490 -412
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityDocument/mjentitydocument.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEntityDocument/mjentitydocument.form.component.js +47 -29
- package/dist/lib/generated/Entities/MJEntityDocument/mjentitydocument.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEnvironment/mjenvironment.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEnvironment/mjenvironment.form.component.js +29 -11
- package/dist/lib/generated/Entities/MJEnvironment/mjenvironment.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJExperiment/mjexperiment.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJExperiment/mjexperiment.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJExperiment/mjexperiment.form.component.js +99 -0
- package/dist/lib/generated/Entities/MJExperiment/mjexperiment.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJExperimentSession/mjexperimentsession.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJExperimentSession/mjexperimentsession.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJExperimentSession/mjexperimentsession.form.component.js +101 -0
- package/dist/lib/generated/Entities/MJExperimentSession/mjexperimentsession.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJExperimentSessionIteration/mjexperimentsessioniteration.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJExperimentSessionIteration/mjexperimentsessioniteration.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJExperimentSessionIteration/mjexperimentsessioniteration.form.component.js +115 -0
- package/dist/lib/generated/Entities/MJExperimentSessionIteration/mjexperimentsessioniteration.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJExternalDataSource/mjexternaldatasource.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJExternalDataSource/mjexternaldatasource.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJExternalDataSource/mjexternaldatasource.form.component.js +113 -0
- package/dist/lib/generated/Entities/MJExternalDataSource/mjexternaldatasource.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJExternalDataSourceType/mjexternaldatasourcetype.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJExternalDataSourceType/mjexternaldatasourcetype.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJExternalDataSourceType/mjexternaldatasourcetype.form.component.js +95 -0
- package/dist/lib/generated/Entities/MJExternalDataSourceType/mjexternaldatasourcetype.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJFile/mjfile.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJFile/mjfile.form.component.js +63 -9
- package/dist/lib/generated/Entities/MJFile/mjfile.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJFileStorageProvider/mjfilestorageprovider.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJFileStorageProvider/mjfilestorageprovider.form.component.js +32 -14
- package/dist/lib/generated/Entities/MJFileStorageProvider/mjfilestorageprovider.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJMLAlgorithm/mjmlalgorithm.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLAlgorithm/mjmlalgorithm.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLAlgorithm/mjmlalgorithm.form.component.js +161 -0
- package/dist/lib/generated/Entities/MJMLAlgorithm/mjmlalgorithm.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMLAlgorithmUseCase/mjmlalgorithmusecase.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLAlgorithmUseCase/mjmlalgorithmusecase.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLAlgorithmUseCase/mjmlalgorithmusecase.form.component.js +89 -0
- package/dist/lib/generated/Entities/MJMLAlgorithmUseCase/mjmlalgorithmusecase.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMLAlgorithmUseCaseRanking/mjmlalgorithmusecaseranking.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLAlgorithmUseCaseRanking/mjmlalgorithmusecaseranking.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLAlgorithmUseCaseRanking/mjmlalgorithmusecaseranking.form.component.js +76 -0
- package/dist/lib/generated/Entities/MJMLAlgorithmUseCaseRanking/mjmlalgorithmusecaseranking.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMLModel/mjmlmodel.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLModel/mjmlmodel.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLModel/mjmlmodel.form.component.js +141 -0
- package/dist/lib/generated/Entities/MJMLModel/mjmlmodel.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMLModelScoringBinding/mjmlmodelscoringbinding.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLModelScoringBinding/mjmlmodelscoringbinding.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLModelScoringBinding/mjmlmodelscoringbinding.form.component.js +88 -0
- package/dist/lib/generated/Entities/MJMLModelScoringBinding/mjmlmodelscoringbinding.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMLTrainingPipeline/mjmltrainingpipeline.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLTrainingPipeline/mjmltrainingpipeline.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLTrainingPipeline/mjmltrainingpipeline.form.component.js +143 -0
- package/dist/lib/generated/Entities/MJMLTrainingPipeline/mjmltrainingpipeline.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMLTrainingRun/mjmltrainingrun.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLTrainingRun/mjmltrainingrun.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLTrainingRun/mjmltrainingrun.form.component.js +110 -0
- package/dist/lib/generated/Entities/MJMLTrainingRun/mjmltrainingrun.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJOpenApp/mjopenapp.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJOpenApp/mjopenapp.form.component.js +54 -24
- package/dist/lib/generated/Entities/MJOpenApp/mjopenapp.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJQuery/mjquery.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJQuery/mjquery.form.component.js +54 -46
- package/dist/lib/generated/Entities/MJQuery/mjquery.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.js +24 -6
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRole/mjrole.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJRole/mjrole.form.component.js +54 -18
- package/dist/lib/generated/Entities/MJRole/mjrole.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJSchemaInfo/mjschemainfo.form.component.js +8 -6
- package/dist/lib/generated/Entities/MJSchemaInfo/mjschemainfo.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJScopedPromptPart/mjscopedpromptpart.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJScopedPromptPart/mjscopedpromptpart.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJScopedPromptPart/mjscopedpromptpart.form.component.js +78 -0
- package/dist/lib/generated/Entities/MJScopedPromptPart/mjscopedpromptpart.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJTemplate/mjtemplate.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJTemplate/mjtemplate.form.component.js +30 -12
- package/dist/lib/generated/Entities/MJTemplate/mjtemplate.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js +181 -109
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJUserRoutine/mjuserroutine.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJUserRoutine/mjuserroutine.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJUserRoutine/mjuserroutine.form.component.js +169 -0
- package/dist/lib/generated/Entities/MJUserRoutine/mjuserroutine.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJUserRoutineRecipient/mjuserroutinerecipient.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJUserRoutineRecipient/mjuserroutinerecipient.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJUserRoutineRecipient/mjuserroutinerecipient.form.component.js +82 -0
- package/dist/lib/generated/Entities/MJUserRoutineRecipient/mjuserroutinerecipient.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJUserRoutineRun/mjuserroutinerun.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJUserRoutineRun/mjuserroutinerun.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJUserRoutineRun/mjuserroutinerun.form.component.js +100 -0
- package/dist/lib/generated/Entities/MJUserRoutineRun/mjuserroutinerun.form.component.js.map +1 -0
- package/dist/lib/generated/generated-forms.module.d.ts +362 -335
- package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
- package/dist/lib/generated/generated-forms.module.js +299 -203
- package/dist/lib/generated/generated-forms.module.js.map +1 -1
- package/dist/lib/panels/ai-agents/agent-realtime.panel.js +44 -44
- package/dist/lib/panels/ai-agents/agent-realtime.panel.js.map +1 -1
- package/dist/lib/panels/ai-skill-sharing/ai-skill-sharing-panel.component.d.ts +43 -0
- package/dist/lib/panels/ai-skill-sharing/ai-skill-sharing-panel.component.d.ts.map +1 -0
- package/dist/lib/panels/ai-skill-sharing/ai-skill-sharing-panel.component.js +240 -0
- package/dist/lib/panels/ai-skill-sharing/ai-skill-sharing-panel.component.js.map +1 -0
- package/dist/lib/panels/model-predictions/model-prediction.logic.d.ts +69 -0
- package/dist/lib/panels/model-predictions/model-prediction.logic.d.ts.map +1 -0
- package/dist/lib/panels/model-predictions/model-prediction.logic.js +130 -0
- package/dist/lib/panels/model-predictions/model-prediction.logic.js.map +1 -0
- package/dist/lib/panels/model-predictions/model-prediction.panel.d.ts +83 -0
- package/dist/lib/panels/model-predictions/model-prediction.panel.d.ts.map +1 -0
- package/dist/lib/panels/model-predictions/model-prediction.panel.js +293 -0
- package/dist/lib/panels/model-predictions/model-prediction.panel.js.map +1 -0
- package/dist/lib/shared/components/template-editor.component.d.ts +4 -2
- package/dist/lib/shared/components/template-editor.component.d.ts.map +1 -1
- package/dist/lib/shared/components/template-editor.component.js +10 -9
- package/dist/lib/shared/components/template-editor.component.js.map +1 -1
- package/package.json +38 -37
- package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.d.ts +0 -82
- package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.d.ts.map +0 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.js +0 -1033
- package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.js.map +0 -1
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Component } from '@angular/core';
|
|
8
|
+
import { RegisterClassEx } from '@memberjunction/global';
|
|
9
|
+
import { BaseFormPanel } from '@memberjunction/ng-base-forms';
|
|
10
|
+
import { LogError, Metadata, RunView } from '@memberjunction/core';
|
|
11
|
+
import { bandFor, formatLastScored, formatValue, gaugePct, parseDrivers, resolveLabel, toNumber, valueKind, } from './model-prediction.logic';
|
|
12
|
+
import * as i0 from "@angular/core";
|
|
13
|
+
import * as i1 from "@memberjunction/ng-base-forms";
|
|
14
|
+
const _forTrack0 = ($index, $item) => $item.bindingId;
|
|
15
|
+
const _forTrack1 = ($index, $item) => $item.name;
|
|
16
|
+
function ModelPredictionPanel_Conditional_0_For_3_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
17
|
+
i0.ɵɵelementStart(0, "span", 11);
|
|
18
|
+
i0.ɵɵtext(1, "\u00B7");
|
|
19
|
+
i0.ɵɵelementEnd();
|
|
20
|
+
i0.ɵɵelementStart(2, "span", 12);
|
|
21
|
+
i0.ɵɵtext(3);
|
|
22
|
+
i0.ɵɵelementEnd();
|
|
23
|
+
} if (rf & 2) {
|
|
24
|
+
const card_r1 = i0.ɵɵnextContext().$implicit;
|
|
25
|
+
i0.ɵɵadvance(3);
|
|
26
|
+
i0.ɵɵtextInterpolate1("Scored ", card_r1.lastScored);
|
|
27
|
+
} }
|
|
28
|
+
function ModelPredictionPanel_Conditional_0_For_3_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
29
|
+
i0.ɵɵelementStart(0, "div", 9)(1, "div", 13);
|
|
30
|
+
i0.ɵɵelement(2, "div", 14);
|
|
31
|
+
i0.ɵɵelementEnd();
|
|
32
|
+
i0.ɵɵelementStart(3, "div", 15)(4, "span");
|
|
33
|
+
i0.ɵɵtext(5, "0%");
|
|
34
|
+
i0.ɵɵelementEnd();
|
|
35
|
+
i0.ɵɵelementStart(6, "span");
|
|
36
|
+
i0.ɵɵtext(7, "50%");
|
|
37
|
+
i0.ɵɵelementEnd();
|
|
38
|
+
i0.ɵɵelementStart(8, "span");
|
|
39
|
+
i0.ɵɵtext(9, "100%");
|
|
40
|
+
i0.ɵɵelementEnd()()();
|
|
41
|
+
} if (rf & 2) {
|
|
42
|
+
const card_r1 = i0.ɵɵnextContext().$implicit;
|
|
43
|
+
i0.ɵɵattribute("aria-label", card_r1.label + " " + card_r1.displayValue + ", " + card_r1.band + " band");
|
|
44
|
+
i0.ɵɵadvance(2);
|
|
45
|
+
i0.ɵɵstyleProp("width", card_r1.gaugePct, "%");
|
|
46
|
+
i0.ɵɵclassProp("mpp-band-low", card_r1.band === "low")("mpp-band-mid", card_r1.band === "mid")("mpp-band-high", card_r1.band === "high");
|
|
47
|
+
} }
|
|
48
|
+
function ModelPredictionPanel_Conditional_0_For_3_Conditional_13_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
49
|
+
i0.ɵɵelementStart(0, "div", 18)(1, "span", 19);
|
|
50
|
+
i0.ɵɵtext(2);
|
|
51
|
+
i0.ɵɵelementEnd();
|
|
52
|
+
i0.ɵɵelementStart(3, "span", 20);
|
|
53
|
+
i0.ɵɵelement(4, "span", 21);
|
|
54
|
+
i0.ɵɵelementEnd()();
|
|
55
|
+
} if (rf & 2) {
|
|
56
|
+
const driver_r2 = ctx.$implicit;
|
|
57
|
+
i0.ɵɵadvance();
|
|
58
|
+
i0.ɵɵproperty("title", driver_r2.name);
|
|
59
|
+
i0.ɵɵadvance();
|
|
60
|
+
i0.ɵɵtextInterpolate(driver_r2.name);
|
|
61
|
+
i0.ɵɵadvance(2);
|
|
62
|
+
i0.ɵɵstyleProp("width", driver_r2.relativePct, "%");
|
|
63
|
+
} }
|
|
64
|
+
function ModelPredictionPanel_Conditional_0_For_3_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
+
i0.ɵɵelementStart(0, "div", 10)(1, "div", 16);
|
|
66
|
+
i0.ɵɵelement(2, "i", 17);
|
|
67
|
+
i0.ɵɵtext(3, " Top drivers ");
|
|
68
|
+
i0.ɵɵelementEnd();
|
|
69
|
+
i0.ɵɵrepeaterCreate(4, ModelPredictionPanel_Conditional_0_For_3_Conditional_13_For_5_Template, 5, 4, "div", 18, _forTrack1);
|
|
70
|
+
i0.ɵɵelementEnd();
|
|
71
|
+
} if (rf & 2) {
|
|
72
|
+
const card_r1 = i0.ɵɵnextContext().$implicit;
|
|
73
|
+
i0.ɵɵadvance(4);
|
|
74
|
+
i0.ɵɵrepeater(card_r1.drivers);
|
|
75
|
+
} }
|
|
76
|
+
function ModelPredictionPanel_Conditional_0_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
77
|
+
i0.ɵɵelementStart(0, "div", 2)(1, "div", 3)(2, "div", 4);
|
|
78
|
+
i0.ɵɵtext(3);
|
|
79
|
+
i0.ɵɵelementEnd();
|
|
80
|
+
i0.ɵɵelementStart(4, "div", 5);
|
|
81
|
+
i0.ɵɵelement(5, "i", 6);
|
|
82
|
+
i0.ɵɵelementStart(6, "span");
|
|
83
|
+
i0.ɵɵtext(7);
|
|
84
|
+
i0.ɵɵelementEnd();
|
|
85
|
+
i0.ɵɵconditionalCreate(8, ModelPredictionPanel_Conditional_0_For_3_Conditional_8_Template, 4, 1);
|
|
86
|
+
i0.ɵɵelementEnd()();
|
|
87
|
+
i0.ɵɵelementStart(9, "div", 7)(10, "span", 8);
|
|
88
|
+
i0.ɵɵtext(11);
|
|
89
|
+
i0.ɵɵelementEnd()();
|
|
90
|
+
i0.ɵɵconditionalCreate(12, ModelPredictionPanel_Conditional_0_For_3_Conditional_12_Template, 10, 9, "div", 9);
|
|
91
|
+
i0.ɵɵconditionalCreate(13, ModelPredictionPanel_Conditional_0_For_3_Conditional_13_Template, 6, 0, "div", 10);
|
|
92
|
+
i0.ɵɵelementEnd();
|
|
93
|
+
} if (rf & 2) {
|
|
94
|
+
const card_r1 = ctx.$implicit;
|
|
95
|
+
i0.ɵɵadvance(3);
|
|
96
|
+
i0.ɵɵtextInterpolate(card_r1.label);
|
|
97
|
+
i0.ɵɵadvance(4);
|
|
98
|
+
i0.ɵɵtextInterpolate(card_r1.provenance);
|
|
99
|
+
i0.ɵɵadvance();
|
|
100
|
+
i0.ɵɵconditional(card_r1.lastScored ? 8 : -1);
|
|
101
|
+
i0.ɵɵadvance(2);
|
|
102
|
+
i0.ɵɵclassProp("mpp-value-muted", card_r1.displayValue === "\u2014");
|
|
103
|
+
i0.ɵɵadvance();
|
|
104
|
+
i0.ɵɵtextInterpolate1(" ", card_r1.displayValue, " ");
|
|
105
|
+
i0.ɵɵadvance();
|
|
106
|
+
i0.ɵɵconditional(card_r1.isProbability ? 12 : -1);
|
|
107
|
+
i0.ɵɵadvance();
|
|
108
|
+
i0.ɵɵconditional(card_r1.drivers.length > 0 ? 13 : -1);
|
|
109
|
+
} }
|
|
110
|
+
function ModelPredictionPanel_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
111
|
+
i0.ɵɵelementStart(0, "mj-collapsible-panel", 0)(1, "div", 1);
|
|
112
|
+
i0.ɵɵrepeaterCreate(2, ModelPredictionPanel_Conditional_0_For_3_Template, 14, 8, "div", 2, _forTrack0);
|
|
113
|
+
i0.ɵɵelementEnd()();
|
|
114
|
+
} if (rf & 2) {
|
|
115
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
116
|
+
i0.ɵɵproperty("Form", ctx_r2.FormComponent)("FormContext", ctx_r2.FormContext)("BadgeCount", ctx_r2.Cards.length);
|
|
117
|
+
i0.ɵɵadvance(2);
|
|
118
|
+
i0.ɵɵrepeater(ctx_r2.Cards);
|
|
119
|
+
} }
|
|
120
|
+
/**
|
|
121
|
+
* Model Prediction panel — an **entity-agnostic** form panel that surfaces any
|
|
122
|
+
* predictions a trained ML model has written onto the current record via a
|
|
123
|
+
* `MJ: ML Model Scoring Bindings` row.
|
|
124
|
+
*
|
|
125
|
+
* It registers against the `'*'` wildcard entity, so it mounts on EVERY entity
|
|
126
|
+
* form — but renders **nothing** unless the record's entity has at least one
|
|
127
|
+
* active scoring binding. The 99% of forms with no model see an invisible,
|
|
128
|
+
* one-RunView-cheap panel.
|
|
129
|
+
*
|
|
130
|
+
* Driven entirely by metadata (bindings + models); there is no entity-specific,
|
|
131
|
+
* domain-specific, or "renewal/risk"-specific logic anywhere. Members/renewal
|
|
132
|
+
* is only ever a test example.
|
|
133
|
+
*
|
|
134
|
+
* Self-mounts via the `after-fields` slot. Reusable as a plain component too
|
|
135
|
+
* (composition) by binding `[Record]` + `[FormComponent]`.
|
|
136
|
+
*/
|
|
137
|
+
let ModelPredictionPanel = class ModelPredictionPanel extends BaseFormPanel {
|
|
138
|
+
constructor() {
|
|
139
|
+
super(...arguments);
|
|
140
|
+
/** The resolved cards to render. Empty → panel renders nothing. */
|
|
141
|
+
this.Cards = [];
|
|
142
|
+
/** True once the binding lookup has completed (success or empty). */
|
|
143
|
+
this.Loaded = false;
|
|
144
|
+
/** Entity-ID we last loaded cards for, to avoid redundant lookups. */
|
|
145
|
+
this.loadedForEntityId = null;
|
|
146
|
+
}
|
|
147
|
+
async ngOnInit() {
|
|
148
|
+
await this.loadCards();
|
|
149
|
+
}
|
|
150
|
+
/** True when there is at least one card to show — gates the whole template. */
|
|
151
|
+
get HasPredictions() {
|
|
152
|
+
return this.Cards.length > 0;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Look up active scoring bindings for THIS record's entity and build a card
|
|
156
|
+
* per binding. Idempotent + cheap: a single RunView (cached by the server),
|
|
157
|
+
* skipped entirely when we've already loaded for this entity.
|
|
158
|
+
*/
|
|
159
|
+
async loadCards() {
|
|
160
|
+
const entityId = this.Record?.EntityInfo?.ID ?? null;
|
|
161
|
+
if (!entityId) {
|
|
162
|
+
this.Loaded = true;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (entityId === this.loadedForEntityId) {
|
|
166
|
+
return; // already resolved for this entity
|
|
167
|
+
}
|
|
168
|
+
this.loadedForEntityId = entityId;
|
|
169
|
+
try {
|
|
170
|
+
const bindings = await this.loadBindingsForEntity(entityId);
|
|
171
|
+
if (bindings.length === 0) {
|
|
172
|
+
this.Cards = [];
|
|
173
|
+
this.Loaded = true;
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const models = await this.loadModelsForBindings(bindings);
|
|
177
|
+
this.Cards = this.buildCards(bindings, models);
|
|
178
|
+
}
|
|
179
|
+
catch (e) {
|
|
180
|
+
LogError(`[ModelPredictionPanel] Failed to load predictions: ${e instanceof Error ? e.message : String(e)}`);
|
|
181
|
+
this.Cards = [];
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
this.Loaded = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/** Active scoring bindings whose target entity is the current record's entity. */
|
|
188
|
+
async loadBindingsForEntity(entityId) {
|
|
189
|
+
const rv = this.runView();
|
|
190
|
+
const result = await rv.RunView({
|
|
191
|
+
EntityName: 'MJ: ML Model Scoring Bindings',
|
|
192
|
+
ExtraFilter: `TargetEntityID='${entityId}' AND TargetColumn IS NOT NULL`,
|
|
193
|
+
OrderBy: '__mj_CreatedAt ASC',
|
|
194
|
+
ResultType: 'entity_object',
|
|
195
|
+
}, this.contextUser());
|
|
196
|
+
if (!result.Success) {
|
|
197
|
+
LogError(`[ModelPredictionPanel] Binding lookup failed: ${result.ErrorMessage}`);
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
return result.Results ?? [];
|
|
201
|
+
}
|
|
202
|
+
/** Load the distinct models referenced by the bindings, keyed by model ID. */
|
|
203
|
+
async loadModelsForBindings(bindings) {
|
|
204
|
+
const modelIds = [...new Set(bindings.map(b => b.MLModelID).filter((id) => !!id))];
|
|
205
|
+
const byId = new Map();
|
|
206
|
+
if (modelIds.length === 0) {
|
|
207
|
+
return byId;
|
|
208
|
+
}
|
|
209
|
+
const inList = modelIds.map(id => `'${id}'`).join(',');
|
|
210
|
+
const rv = this.runView();
|
|
211
|
+
const result = await rv.RunView({
|
|
212
|
+
EntityName: 'MJ: ML Models',
|
|
213
|
+
ExtraFilter: `ID IN (${inList})`,
|
|
214
|
+
ResultType: 'entity_object',
|
|
215
|
+
}, this.contextUser());
|
|
216
|
+
if (!result.Success) {
|
|
217
|
+
LogError(`[ModelPredictionPanel] Model lookup failed: ${result.ErrorMessage}`);
|
|
218
|
+
return byId;
|
|
219
|
+
}
|
|
220
|
+
for (const model of result.Results ?? []) {
|
|
221
|
+
byId.set(model.ID, model);
|
|
222
|
+
}
|
|
223
|
+
return byId;
|
|
224
|
+
}
|
|
225
|
+
/** Map each binding (+ its model) to a display card. Skips bindings whose model is missing. */
|
|
226
|
+
buildCards(bindings, models) {
|
|
227
|
+
const cards = [];
|
|
228
|
+
for (const binding of bindings) {
|
|
229
|
+
const model = binding.MLModelID ? models.get(binding.MLModelID) : undefined;
|
|
230
|
+
if (!model) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
cards.push(this.buildCard(binding, model));
|
|
234
|
+
}
|
|
235
|
+
return cards;
|
|
236
|
+
}
|
|
237
|
+
/** Build one card from a binding + model + the record's bound-column value. */
|
|
238
|
+
buildCard(binding, model) {
|
|
239
|
+
// The column name is data-driven (from the binding), so reading it
|
|
240
|
+
// dynamically via Get() is the legitimate use of the dynamic accessor.
|
|
241
|
+
const rawValue = binding.TargetColumn ? this.Record.Get(binding.TargetColumn) : null;
|
|
242
|
+
const numeric = toNumber(rawValue);
|
|
243
|
+
const kind = valueKind(model.ProblemType, numeric);
|
|
244
|
+
return {
|
|
245
|
+
bindingId: binding.ID,
|
|
246
|
+
label: resolveLabel(model.TargetVariable, binding.TargetColumn),
|
|
247
|
+
isProbability: kind === 'probability',
|
|
248
|
+
isNumeric: kind === 'numeric',
|
|
249
|
+
isClass: kind === 'class',
|
|
250
|
+
displayValue: formatValue(rawValue, numeric, kind),
|
|
251
|
+
gaugePct: kind === 'probability' && numeric != null ? gaugePct(numeric) : 0,
|
|
252
|
+
band: kind === 'probability' && numeric != null ? bandFor(numeric) : null,
|
|
253
|
+
drivers: parseDrivers(model.FeatureImportance),
|
|
254
|
+
provenance: `${model.Pipeline} v${model.Version}`,
|
|
255
|
+
lastScored: formatLastScored(binding.LastScoredAt),
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/** RunView scoped to the form's provider when available (multi-provider safe). */
|
|
259
|
+
runView() {
|
|
260
|
+
const provider = this.FormComponent?.ProviderToUse;
|
|
261
|
+
return provider ? RunView.FromMetadataProvider(provider) : new RunView();
|
|
262
|
+
}
|
|
263
|
+
/** Context user for server-side scoping — the form provider's current user. */
|
|
264
|
+
contextUser() {
|
|
265
|
+
return this.FormComponent?.ProviderToUse?.CurrentUser ?? new Metadata().CurrentUser;
|
|
266
|
+
}
|
|
267
|
+
static { this.ɵfac = /*@__PURE__*/ (() => { let ɵModelPredictionPanel_BaseFactory; return function ModelPredictionPanel_Factory(__ngFactoryType__) { return (ɵModelPredictionPanel_BaseFactory || (ɵModelPredictionPanel_BaseFactory = i0.ɵɵgetInheritedFactory(ModelPredictionPanel)))(__ngFactoryType__ || ModelPredictionPanel); }; })(); }
|
|
268
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ModelPredictionPanel, selectors: [["mj-model-prediction-panel"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [["SectionKey", "modelPredictions", "SectionName", "Model Predictions", "Icon", "fa-solid fa-wand-magic-sparkles", 3, "Form", "FormContext", "BadgeCount"], [1, "mpp-cards"], [1, "mpp-card"], [1, "mpp-card-head"], [1, "mpp-label"], [1, "mpp-provenance"], ["aria-hidden", "true", 1, "fa-solid", "fa-diagram-project", "mpp-prov-icon"], [1, "mpp-value-row"], [1, "mpp-value"], ["role", "img", 1, "mpp-gauge"], [1, "mpp-drivers"], ["aria-hidden", "true", 1, "mpp-dot"], [1, "mpp-scored"], [1, "mpp-gauge-track"], [1, "mpp-gauge-fill"], [1, "mpp-gauge-scale"], [1, "mpp-drivers-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-ranking-star"], [1, "mpp-driver"], [1, "mpp-driver-name", 3, "title"], [1, "mpp-driver-bar-track"], [1, "mpp-driver-bar-fill"]], template: function ModelPredictionPanel_Template(rf, ctx) { if (rf & 1) {
|
|
269
|
+
i0.ɵɵconditionalCreate(0, ModelPredictionPanel_Conditional_0_Template, 4, 3, "mj-collapsible-panel", 0);
|
|
270
|
+
} if (rf & 2) {
|
|
271
|
+
i0.ɵɵconditional(ctx.HasPredictions ? 0 : -1);
|
|
272
|
+
} }, dependencies: [i1.MjCollapsiblePanelComponent], styles: ["\n\n\n\n\n\n.mpp-cards[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 4px 2px;\n}\n\n.mpp-card[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-card);\n padding: 14px 16px;\n}\n\n\n\n.mpp-card-head[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: 8px;\n margin-bottom: 8px;\n}\n\n.mpp-label[_ngcontent-%COMP%] {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.mpp-provenance[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n.mpp-prov-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.mpp-dot[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n\n\n\n.mpp-value-row[_ngcontent-%COMP%] {\n margin: 2px 0 10px;\n}\n\n.mpp-value[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n font-weight: 700;\n line-height: 1.1;\n color: var(--mj-text-primary);\n font-variant-numeric: tabular-nums;\n}\n\n.mpp-value-muted[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-weight: 500;\n}\n\n\n\n.mpp-gauge[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n}\n\n.mpp-gauge-track[_ngcontent-%COMP%] {\n position: relative;\n height: 10px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.mpp-gauge-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-brand-primary);\n transition: width 0.3s ease;\n}\n\n\n\n.mpp-band-low[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 55%, transparent);\n}\n.mpp-band-mid[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 78%, transparent);\n}\n.mpp-band-high[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.mpp-gauge-scale[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n margin-top: 4px;\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n font-variant-numeric: tabular-nums;\n}\n\n\n\n.mpp-drivers[_ngcontent-%COMP%] {\n margin-top: 12px;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n}\n\n.mpp-drivers-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 0.72rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-secondary);\n margin-bottom: 8px;\n}\n\n.mpp-driver[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: minmax(80px, 38%) 1fr;\n align-items: center;\n gap: 10px;\n margin-bottom: 6px;\n}\n\n.mpp-driver-name[_ngcontent-%COMP%] {\n font-size: 0.8rem;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mpp-driver-bar-track[_ngcontent-%COMP%] {\n display: block;\n height: 7px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.mpp-driver-bar-fill[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full, 9999px);\n background: color-mix(in srgb, var(--mj-brand-primary) 70%, transparent);\n transition: width 0.3s ease;\n}"] }); }
|
|
273
|
+
};
|
|
274
|
+
ModelPredictionPanel = __decorate([
|
|
275
|
+
RegisterClassEx(BaseFormPanel, {
|
|
276
|
+
key: 'model-predictions:model-prediction',
|
|
277
|
+
skipNullKeyWarning: true,
|
|
278
|
+
metadata: {
|
|
279
|
+
entity: '*', // wildcard — appears on every entity form, self-hides when N/A
|
|
280
|
+
slot: 'after-fields',
|
|
281
|
+
sortKey: 40,
|
|
282
|
+
},
|
|
283
|
+
})
|
|
284
|
+
], ModelPredictionPanel);
|
|
285
|
+
export { ModelPredictionPanel };
|
|
286
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ModelPredictionPanel, [{
|
|
287
|
+
type: Component,
|
|
288
|
+
args: [{ standalone: false, selector: 'mj-model-prediction-panel', template: "<!--\n Entity-agnostic model-prediction panel. Renders NOTHING unless the current\n record's entity has active scoring bindings (HasPredictions gate). Driven\n entirely by metadata \u2014 no entity-specific or domain-specific markup.\n-->\n@if (HasPredictions) {\n <mj-collapsible-panel\n SectionKey=\"modelPredictions\"\n SectionName=\"Model Predictions\"\n Icon=\"fa-solid fa-wand-magic-sparkles\"\n [Form]=\"FormComponent\"\n [FormContext]=\"FormContext\"\n [BadgeCount]=\"Cards.length\">\n\n <div class=\"mpp-cards\">\n @for (card of Cards; track card.bindingId) {\n <div class=\"mpp-card\">\n\n <!-- Header: label + provenance -->\n <div class=\"mpp-card-head\">\n <div class=\"mpp-label\">{{ card.label }}</div>\n <div class=\"mpp-provenance\">\n <i class=\"fa-solid fa-diagram-project mpp-prov-icon\" aria-hidden=\"true\"></i>\n <span>{{ card.provenance }}</span>\n @if (card.lastScored) {\n <span class=\"mpp-dot\" aria-hidden=\"true\">\u00B7</span>\n <span class=\"mpp-scored\">Scored {{ card.lastScored }}</span>\n }\n </div>\n </div>\n\n <!-- Value -->\n <div class=\"mpp-value-row\">\n <span class=\"mpp-value\" [class.mpp-value-muted]=\"card.displayValue === '\u2014'\">\n {{ card.displayValue }}\n </span>\n </div>\n\n <!-- Probability gauge \u2014 neutral 3-band tercile. No moral direction. -->\n @if (card.isProbability) {\n <div class=\"mpp-gauge\" role=\"img\"\n [attr.aria-label]=\"card.label + ' ' + card.displayValue + ', ' + card.band + ' band'\">\n <div class=\"mpp-gauge-track\">\n <div class=\"mpp-gauge-fill\"\n [class.mpp-band-low]=\"card.band === 'low'\"\n [class.mpp-band-mid]=\"card.band === 'mid'\"\n [class.mpp-band-high]=\"card.band === 'high'\"\n [style.width.%]=\"card.gaugePct\"></div>\n </div>\n <div class=\"mpp-gauge-scale\">\n <span>0%</span>\n <span>50%</span>\n <span>100%</span>\n </div>\n </div>\n }\n\n <!-- Top drivers (feature importance) \u2014 omitted cleanly when unavailable -->\n @if (card.drivers.length > 0) {\n <div class=\"mpp-drivers\">\n <div class=\"mpp-drivers-title\">\n <i class=\"fa-solid fa-ranking-star\" aria-hidden=\"true\"></i>\n Top drivers\n </div>\n @for (driver of card.drivers; track driver.name) {\n <div class=\"mpp-driver\">\n <span class=\"mpp-driver-name\" [title]=\"driver.name\">{{ driver.name }}</span>\n <span class=\"mpp-driver-bar-track\">\n <span class=\"mpp-driver-bar-fill\" [style.width.%]=\"driver.relativePct\"></span>\n </span>\n </div>\n }\n </div>\n }\n\n </div>\n }\n </div>\n\n </mj-collapsible-panel>\n}\n", styles: ["/* Entity-agnostic model-prediction panel.\n Design-token-clean: every color is a --mj-* semantic token. The gauge bands\n are intentionally NEUTRAL \u2014 they encode position on the value axis (low/mid/high)\n via opacity of a single brand color, never green=good / red=bad. */\n\n.mpp-cards {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 4px 2px;\n}\n\n.mpp-card {\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-card);\n padding: 14px 16px;\n}\n\n/* ---- Header ---- */\n.mpp-card-head {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: 8px;\n margin-bottom: 8px;\n}\n\n.mpp-label {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.mpp-provenance {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n.mpp-prov-icon {\n color: var(--mj-brand-primary);\n}\n\n.mpp-dot {\n color: var(--mj-text-disabled);\n}\n\n/* ---- Primary value ---- */\n.mpp-value-row {\n margin: 2px 0 10px;\n}\n\n.mpp-value {\n font-size: 1.75rem;\n font-weight: 700;\n line-height: 1.1;\n color: var(--mj-text-primary);\n font-variant-numeric: tabular-nums;\n}\n\n.mpp-value-muted {\n color: var(--mj-text-disabled);\n font-weight: 500;\n}\n\n/* ---- Gauge (neutral tercile) ---- */\n.mpp-gauge {\n margin-bottom: 4px;\n}\n\n.mpp-gauge-track {\n position: relative;\n height: 10px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.mpp-gauge-fill {\n height: 100%;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-brand-primary);\n transition: width 0.3s ease;\n}\n\n/* Band shading: same brand hue, varied opacity = neutral position cue only. */\n.mpp-band-low {\n background: color-mix(in srgb, var(--mj-brand-primary) 55%, transparent);\n}\n.mpp-band-mid {\n background: color-mix(in srgb, var(--mj-brand-primary) 78%, transparent);\n}\n.mpp-band-high {\n background: var(--mj-brand-primary);\n}\n\n.mpp-gauge-scale {\n display: flex;\n justify-content: space-between;\n margin-top: 4px;\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n font-variant-numeric: tabular-nums;\n}\n\n/* ---- Drivers ---- */\n.mpp-drivers {\n margin-top: 12px;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n}\n\n.mpp-drivers-title {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 0.72rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-secondary);\n margin-bottom: 8px;\n}\n\n.mpp-driver {\n display: grid;\n grid-template-columns: minmax(80px, 38%) 1fr;\n align-items: center;\n gap: 10px;\n margin-bottom: 6px;\n}\n\n.mpp-driver-name {\n font-size: 0.8rem;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mpp-driver-bar-track {\n display: block;\n height: 7px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.mpp-driver-bar-fill {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full, 9999px);\n background: color-mix(in srgb, var(--mj-brand-primary) 70%, transparent);\n transition: width 0.3s ease;\n}\n"] }]
|
|
289
|
+
}], null, null); })();
|
|
290
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ModelPredictionPanel, { className: "ModelPredictionPanel", filePath: "src/lib/panels/model-predictions/model-prediction.panel.ts", lineNumber: 80 }); })();
|
|
291
|
+
/** Tree-shake guard — call this from the consuming module's loader. */
|
|
292
|
+
export function LoadModelPredictionPanel() { }
|
|
293
|
+
//# sourceMappingURL=model-prediction.panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-prediction.panel.js","sourceRoot":"","sources":["../../../../src/lib/panels/model-predictions/model-prediction.panel.ts","../../../../src/lib/panels/model-predictions/model-prediction.panel.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit } from '@angular/core';\nimport { RegisterClassEx } from '@memberjunction/global';\nimport { BaseFormPanel } from '@memberjunction/ng-base-forms';\nimport { LogError, Metadata, RunView } from '@memberjunction/core';\nimport { MJMLModelEntity, MJMLModelScoringBindingEntity } from '@memberjunction/core-entities';\nimport {\n PredictionBand,\n PredictionDriver,\n bandFor,\n formatLastScored,\n formatValue,\n gaugePct,\n parseDrivers,\n resolveLabel,\n toNumber,\n valueKind,\n} from './model-prediction.logic';\n\n/**\n * A fully-resolved, entity-agnostic prediction card view-model. One per active\n * scoring binding on the current record's entity.\n */\nexport interface PredictionCard {\n /** Binding ID — used as the @for track key. */\n bindingId: string;\n /** Human label for the prediction (model target → bound column → fallback). */\n label: string;\n /** True when the model is a 0–1 probability we can render as a gauge. */\n isProbability: boolean;\n /** True for regression models showing a raw numeric value. */\n isNumeric: boolean;\n /** True for classification models showing a class label. */\n isClass: boolean;\n /** Pre-formatted primary value string (\"72%\", \"1,240.5\", \"Renewing\", \"—\"). */\n displayValue: string;\n /** 0–100 fill for the probability gauge (only meaningful when isProbability). */\n gaugePct: number;\n /** Neutral band for the gauge segment styling (only meaningful when isProbability). */\n band: PredictionBand | null;\n /** Top feature-importance drivers, or empty when unavailable. */\n drivers: PredictionDriver[];\n /** Provenance: \"Pipeline Name v3\". */\n provenance: string;\n /** \"Last scored\" timestamp string, or null when unavailable. */\n lastScored: string | null;\n}\n\n/**\n * Model Prediction panel — an **entity-agnostic** form panel that surfaces any\n * predictions a trained ML model has written onto the current record via a\n * `MJ: ML Model Scoring Bindings` row.\n *\n * It registers against the `'*'` wildcard entity, so it mounts on EVERY entity\n * form — but renders **nothing** unless the record's entity has at least one\n * active scoring binding. The 99% of forms with no model see an invisible,\n * one-RunView-cheap panel.\n *\n * Driven entirely by metadata (bindings + models); there is no entity-specific,\n * domain-specific, or \"renewal/risk\"-specific logic anywhere. Members/renewal\n * is only ever a test example.\n *\n * Self-mounts via the `after-fields` slot. Reusable as a plain component too\n * (composition) by binding `[Record]` + `[FormComponent]`.\n */\n@RegisterClassEx(BaseFormPanel, {\n key: 'model-predictions:model-prediction',\n skipNullKeyWarning: true,\n metadata: {\n entity: '*', // wildcard — appears on every entity form, self-hides when N/A\n slot: 'after-fields',\n sortKey: 40,\n },\n})\n@Component({\n standalone: false,\n selector: 'mj-model-prediction-panel',\n templateUrl: './model-prediction.panel.html',\n styleUrls: ['./model-prediction.panel.css'],\n})\nexport class ModelPredictionPanel extends BaseFormPanel implements OnInit {\n /** The resolved cards to render. Empty → panel renders nothing. */\n public Cards: PredictionCard[] = [];\n /** True once the binding lookup has completed (success or empty). */\n public Loaded = false;\n /** Entity-ID we last loaded cards for, to avoid redundant lookups. */\n private loadedForEntityId: string | null = null;\n\n public async ngOnInit(): Promise<void> {\n await this.loadCards();\n }\n\n /** True when there is at least one card to show — gates the whole template. */\n public get HasPredictions(): boolean {\n return this.Cards.length > 0;\n }\n\n /**\n * Look up active scoring bindings for THIS record's entity and build a card\n * per binding. Idempotent + cheap: a single RunView (cached by the server),\n * skipped entirely when we've already loaded for this entity.\n */\n private async loadCards(): Promise<void> {\n const entityId = this.Record?.EntityInfo?.ID ?? null;\n if (!entityId) {\n this.Loaded = true;\n return;\n }\n if (entityId === this.loadedForEntityId) {\n return; // already resolved for this entity\n }\n this.loadedForEntityId = entityId;\n\n try {\n const bindings = await this.loadBindingsForEntity(entityId);\n if (bindings.length === 0) {\n this.Cards = [];\n this.Loaded = true;\n return;\n }\n const models = await this.loadModelsForBindings(bindings);\n this.Cards = this.buildCards(bindings, models);\n } catch (e) {\n LogError(`[ModelPredictionPanel] Failed to load predictions: ${e instanceof Error ? e.message : String(e)}`);\n this.Cards = [];\n } finally {\n this.Loaded = true;\n }\n }\n\n /** Active scoring bindings whose target entity is the current record's entity. */\n private async loadBindingsForEntity(entityId: string): Promise<MJMLModelScoringBindingEntity[]> {\n const rv = this.runView();\n const result = await rv.RunView<MJMLModelScoringBindingEntity>(\n {\n EntityName: 'MJ: ML Model Scoring Bindings',\n ExtraFilter: `TargetEntityID='${entityId}' AND TargetColumn IS NOT NULL`,\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'entity_object',\n },\n this.contextUser(),\n );\n if (!result.Success) {\n LogError(`[ModelPredictionPanel] Binding lookup failed: ${result.ErrorMessage}`);\n return [];\n }\n return result.Results ?? [];\n }\n\n /** Load the distinct models referenced by the bindings, keyed by model ID. */\n private async loadModelsForBindings(\n bindings: MJMLModelScoringBindingEntity[],\n ): Promise<Map<string, MJMLModelEntity>> {\n const modelIds = [...new Set(bindings.map(b => b.MLModelID).filter((id): id is string => !!id))];\n const byId = new Map<string, MJMLModelEntity>();\n if (modelIds.length === 0) {\n return byId;\n }\n const inList = modelIds.map(id => `'${id}'`).join(',');\n const rv = this.runView();\n const result = await rv.RunView<MJMLModelEntity>(\n {\n EntityName: 'MJ: ML Models',\n ExtraFilter: `ID IN (${inList})`,\n ResultType: 'entity_object',\n },\n this.contextUser(),\n );\n if (!result.Success) {\n LogError(`[ModelPredictionPanel] Model lookup failed: ${result.ErrorMessage}`);\n return byId;\n }\n for (const model of result.Results ?? []) {\n byId.set(model.ID, model);\n }\n return byId;\n }\n\n /** Map each binding (+ its model) to a display card. Skips bindings whose model is missing. */\n private buildCards(\n bindings: MJMLModelScoringBindingEntity[],\n models: Map<string, MJMLModelEntity>,\n ): PredictionCard[] {\n const cards: PredictionCard[] = [];\n for (const binding of bindings) {\n const model = binding.MLModelID ? models.get(binding.MLModelID) : undefined;\n if (!model) {\n continue;\n }\n cards.push(this.buildCard(binding, model));\n }\n return cards;\n }\n\n /** Build one card from a binding + model + the record's bound-column value. */\n private buildCard(binding: MJMLModelScoringBindingEntity, model: MJMLModelEntity): PredictionCard {\n // The column name is data-driven (from the binding), so reading it\n // dynamically via Get() is the legitimate use of the dynamic accessor.\n const rawValue = binding.TargetColumn ? this.Record.Get(binding.TargetColumn) : null;\n const numeric = toNumber(rawValue);\n const kind = valueKind(model.ProblemType, numeric);\n\n return {\n bindingId: binding.ID,\n label: resolveLabel(model.TargetVariable, binding.TargetColumn),\n isProbability: kind === 'probability',\n isNumeric: kind === 'numeric',\n isClass: kind === 'class',\n displayValue: formatValue(rawValue, numeric, kind),\n gaugePct: kind === 'probability' && numeric != null ? gaugePct(numeric) : 0,\n band: kind === 'probability' && numeric != null ? bandFor(numeric) : null,\n drivers: parseDrivers(model.FeatureImportance),\n provenance: `${model.Pipeline} v${model.Version}`,\n lastScored: formatLastScored(binding.LastScoredAt),\n };\n }\n\n /** RunView scoped to the form's provider when available (multi-provider safe). */\n private runView(): RunView {\n const provider = this.FormComponent?.ProviderToUse;\n return provider ? RunView.FromMetadataProvider(provider) : new RunView();\n }\n\n /** Context user for server-side scoping — the form provider's current user. */\n private contextUser() {\n return this.FormComponent?.ProviderToUse?.CurrentUser ?? new Metadata().CurrentUser;\n }\n}\n\n/** Tree-shake guard — call this from the consuming module's loader. */\nexport function LoadModelPredictionPanel(): void { /* no-op marker */ }\n","<!--\n Entity-agnostic model-prediction panel. Renders NOTHING unless the current\n record's entity has active scoring bindings (HasPredictions gate). Driven\n entirely by metadata — no entity-specific or domain-specific markup.\n-->\n@if (HasPredictions) {\n <mj-collapsible-panel\n SectionKey=\"modelPredictions\"\n SectionName=\"Model Predictions\"\n Icon=\"fa-solid fa-wand-magic-sparkles\"\n [Form]=\"FormComponent\"\n [FormContext]=\"FormContext\"\n [BadgeCount]=\"Cards.length\">\n\n <div class=\"mpp-cards\">\n @for (card of Cards; track card.bindingId) {\n <div class=\"mpp-card\">\n\n <!-- Header: label + provenance -->\n <div class=\"mpp-card-head\">\n <div class=\"mpp-label\">{{ card.label }}</div>\n <div class=\"mpp-provenance\">\n <i class=\"fa-solid fa-diagram-project mpp-prov-icon\" aria-hidden=\"true\"></i>\n <span>{{ card.provenance }}</span>\n @if (card.lastScored) {\n <span class=\"mpp-dot\" aria-hidden=\"true\">·</span>\n <span class=\"mpp-scored\">Scored {{ card.lastScored }}</span>\n }\n </div>\n </div>\n\n <!-- Value -->\n <div class=\"mpp-value-row\">\n <span class=\"mpp-value\" [class.mpp-value-muted]=\"card.displayValue === '—'\">\n {{ card.displayValue }}\n </span>\n </div>\n\n <!-- Probability gauge — neutral 3-band tercile. No moral direction. -->\n @if (card.isProbability) {\n <div class=\"mpp-gauge\" role=\"img\"\n [attr.aria-label]=\"card.label + ' ' + card.displayValue + ', ' + card.band + ' band'\">\n <div class=\"mpp-gauge-track\">\n <div class=\"mpp-gauge-fill\"\n [class.mpp-band-low]=\"card.band === 'low'\"\n [class.mpp-band-mid]=\"card.band === 'mid'\"\n [class.mpp-band-high]=\"card.band === 'high'\"\n [style.width.%]=\"card.gaugePct\"></div>\n </div>\n <div class=\"mpp-gauge-scale\">\n <span>0%</span>\n <span>50%</span>\n <span>100%</span>\n </div>\n </div>\n }\n\n <!-- Top drivers (feature importance) — omitted cleanly when unavailable -->\n @if (card.drivers.length > 0) {\n <div class=\"mpp-drivers\">\n <div class=\"mpp-drivers-title\">\n <i class=\"fa-solid fa-ranking-star\" aria-hidden=\"true\"></i>\n Top drivers\n </div>\n @for (driver of card.drivers; track driver.name) {\n <div class=\"mpp-driver\">\n <span class=\"mpp-driver-name\" [title]=\"driver.name\">{{ driver.name }}</span>\n <span class=\"mpp-driver-bar-track\">\n <span class=\"mpp-driver-bar-fill\" [style.width.%]=\"driver.relativePct\"></span>\n </span>\n </div>\n }\n </div>\n }\n\n </div>\n }\n </div>\n\n </mj-collapsible-panel>\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter, OnInit, OnDestroy, OnChanges, SimpleChanges, AfterViewInit } from '@angular/core';
|
|
2
2
|
import { MJTemplateEntity, MJTemplateContentEntity } from '@memberjunction/core-entities';
|
|
3
3
|
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
4
|
+
import { MJConfirmService } from '@memberjunction/ng-ui-components';
|
|
4
5
|
import { LanguageDescription } from '@codemirror/language';
|
|
5
6
|
import { CodeEditorComponent } from '@memberjunction/ng-code-editor';
|
|
6
7
|
import { SystemPlaceholder, SystemPlaceholderCategory } from '@memberjunction/ai-core-plus';
|
|
@@ -13,6 +14,7 @@ export interface TemplateEditorConfig {
|
|
|
13
14
|
}
|
|
14
15
|
export declare class TemplateEditorComponent extends BaseAngularComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {
|
|
15
16
|
private notificationService;
|
|
17
|
+
private confirmService;
|
|
16
18
|
template: MJTemplateEntity | null;
|
|
17
19
|
config: TemplateEditorConfig;
|
|
18
20
|
contentChange: EventEmitter<MJTemplateContentEntity[]>;
|
|
@@ -39,7 +41,7 @@ export declare class TemplateEditorComponent extends BaseAngularComponent implem
|
|
|
39
41
|
private destroy$;
|
|
40
42
|
private get _metadata();
|
|
41
43
|
private activeTimeouts;
|
|
42
|
-
constructor(notificationService: MJNotificationService);
|
|
44
|
+
constructor(notificationService: MJNotificationService, confirmService: MJConfirmService);
|
|
43
45
|
ngOnInit(): Promise<void>;
|
|
44
46
|
ngOnChanges(changes: SimpleChanges): Promise<void>;
|
|
45
47
|
private organizePlaceholdersByCategory;
|
|
@@ -56,7 +58,7 @@ export declare class TemplateEditorComponent extends BaseAngularComponent implem
|
|
|
56
58
|
*/
|
|
57
59
|
refreshAndDiscardChanges(): Promise<void>;
|
|
58
60
|
createDefaultTemplateContent(): Promise<void>;
|
|
59
|
-
selectTemplateContent(index: number, confirmSwitch?: boolean): void
|
|
61
|
+
selectTemplateContent(index: number, confirmSwitch?: boolean): Promise<void>;
|
|
60
62
|
loadContentTypes(): void;
|
|
61
63
|
addNewTemplateContent(): Promise<void>;
|
|
62
64
|
deleteTemplateContent(index: number): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-editor.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/shared/components/template-editor.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAa,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9I,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAE1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"template-editor.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/shared/components/template-editor.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,8 +8,8 @@ import { DEFAULT_SYSTEM_PLACEHOLDERS, SYSTEM_PLACEHOLDER_CATEGORIES } from '@mem
|
|
|
8
8
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
9
9
|
import * as i0 from "@angular/core";
|
|
10
10
|
import * as i1 from "@memberjunction/ng-notifications";
|
|
11
|
-
import * as i2 from "@
|
|
12
|
-
import * as i3 from "@
|
|
11
|
+
import * as i2 from "@memberjunction/ng-ui-components";
|
|
12
|
+
import * as i3 from "@angular/forms";
|
|
13
13
|
import * as i4 from "@memberjunction/ng-code-editor";
|
|
14
14
|
const _c0 = ["codeEditor"];
|
|
15
15
|
const _forTrack0 = ($index, $item) => $item.ID || $index;
|
|
@@ -463,9 +463,10 @@ function TemplateEditorComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
|
463
463
|
} }
|
|
464
464
|
export class TemplateEditorComponent extends BaseAngularComponent {
|
|
465
465
|
get _metadata() { return this.ProviderToUse; }
|
|
466
|
-
constructor(notificationService) {
|
|
466
|
+
constructor(notificationService, confirmService) {
|
|
467
467
|
super();
|
|
468
468
|
this.notificationService = notificationService;
|
|
469
|
+
this.confirmService = confirmService;
|
|
469
470
|
this.template = null;
|
|
470
471
|
this.config = {
|
|
471
472
|
allowEdit: true,
|
|
@@ -625,10 +626,10 @@ export class TemplateEditorComponent extends BaseAngularComponent {
|
|
|
625
626
|
// Sync editor value after creating default content
|
|
626
627
|
this.syncEditorValue();
|
|
627
628
|
}
|
|
628
|
-
selectTemplateContent(index, confirmSwitch = true) {
|
|
629
|
+
async selectTemplateContent(index, confirmSwitch = true) {
|
|
629
630
|
// If we're adding new content and user clicks on existing content, ask for confirmation
|
|
630
631
|
if (this.isAddingNewContent && confirmSwitch) {
|
|
631
|
-
if (!
|
|
632
|
+
if (!(await this.confirmService.Confirm({ title: 'Discard changes?', message: 'Switch content version and lose your unsaved changes?', detail: 'Your changes to the new content version will be lost.' }))) {
|
|
632
633
|
return;
|
|
633
634
|
}
|
|
634
635
|
}
|
|
@@ -885,7 +886,7 @@ export class TemplateEditorComponent extends BaseAngularComponent {
|
|
|
885
886
|
// Always exclude "Select Type..." option for all content
|
|
886
887
|
return this.contentTypeOptions.filter(option => option.value !== '');
|
|
887
888
|
}
|
|
888
|
-
static { this.ɵfac = function TemplateEditorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TemplateEditorComponent)(i0.ɵɵdirectiveInject(i1.MJNotificationService)); }; }
|
|
889
|
+
static { this.ɵfac = function TemplateEditorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TemplateEditorComponent)(i0.ɵɵdirectiveInject(i1.MJNotificationService), i0.ɵɵdirectiveInject(i2.MJConfirmService)); }; }
|
|
889
890
|
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TemplateEditorComponent, selectors: [["mj-template-editor"]], viewQuery: function TemplateEditorComponent_Query(rf, ctx) { if (rf & 1) {
|
|
890
891
|
i0.ɵɵviewQuery(_c0, 5);
|
|
891
892
|
} if (rf & 2) {
|
|
@@ -895,12 +896,12 @@ export class TemplateEditorComponent extends BaseAngularComponent {
|
|
|
895
896
|
i0.ɵɵconditionalCreate(0, TemplateEditorComponent_Conditional_0_Template, 4, 2, "div", 1);
|
|
896
897
|
} if (rf & 2) {
|
|
897
898
|
i0.ɵɵconditional(ctx.template ? 0 : -1);
|
|
898
|
-
} }, dependencies: [i2.CheckboxControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.MJDropdownComponent, i3.MJNumericInputComponent, i4.CodeEditorComponent], styles: [".template-editor[_ngcontent-%COMP%] {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n}\n\n.section-header[_ngcontent-%COMP%] h6[_ngcontent-%COMP%] {\n font-size: 0.9em;\n}\n\n.param-row[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-card) !important;\n}\n\n.content-item[_ngcontent-%COMP%] {\n transition: box-shadow 0.2s ease;\n}\n\n.content-item[_ngcontent-%COMP%]:hover {\n box-shadow: 0 2px 4px var(--mj-shadow-sm);\n}\n\n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n}\n\n.badge[_ngcontent-%COMP%] {\n display: inline-block;\n font-size: 0.7em;\n line-height: 1;\n}\n\n\n\n.template-editor[_ngcontent-%COMP%] .mj-input[_ngcontent-%COMP%], \n.template-editor[_ngcontent-%COMP%] .mj-textarea[_ngcontent-%COMP%], \n.template-editor[_ngcontent-%COMP%] mj-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.template-editor[_ngcontent-%COMP%] [mjButton][_ngcontent-%COMP%] {\n min-width: auto;\n}\n\n\n\n.content-versions-tabs[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n border-bottom: 2px solid var(--mj-border-default);\n padding-bottom: 8px;\n}\n\n.content-tabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.content-version-tab[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface);\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n position: relative;\n}\n\n.content-version-tab.active[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.content-version-tab[_ngcontent-%COMP%] .tab-label[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 0.85em;\n color: var(--mj-text-secondary);\n}\n\n.content-version-tab[_ngcontent-%COMP%] .tab-meta[_ngcontent-%COMP%] {\n font-size: 0.7em;\n color: var(--mj-text-muted);\n}\n\n.content-version-tab[_ngcontent-%COMP%] .tab-meta[_ngcontent-%COMP%] .inactive-label[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.content-version-tab[_ngcontent-%COMP%] .delete-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-status-error);\n padding: 4px;\n border-radius: 3px;\n transition: all 0.2s;\n cursor: pointer;\n}\n\n.content-version-tab[_ngcontent-%COMP%] .delete-btn[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n}\n\n\n\n.content-version-tab.adding-new[_ngcontent-%COMP%] {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n}\n\n.content-version-tab.adding-new[_ngcontent-%COMP%] .new-label[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-status-success);\n font-size: 0.85em;\n}\n\n\n\n.content-version-tab.add-new[_ngcontent-%COMP%] {\n border: 1px dashed var(--mj-status-success);\n background: var(--mj-bg-surface-card);\n}\n\n.content-version-tab.add-new[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n border-style: solid;\n}\n\n.content-version-tab.add-new[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n font-size: 0.75em;\n}\n\n.content-version-tab.add-new[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--mj-status-success);\n font-size: 0.85em;\n}\n\n\n\n.content-editor-container[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n\n\n.content-metadata-bar[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 16px 20px;\n}\n\n.metadata-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr auto;\n gap: 20px;\n align-items: end;\n}\n\n.form-group[_ngcontent-%COMP%] {\n margin: 0;\n}\n\n.form-label[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n font-size: 0.9em;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-control-plaintext[_ngcontent-%COMP%] {\n font-size: 0.9em;\n padding: 4px 0;\n}\n\n.form-check[_ngcontent-%COMP%] {\n margin-top: 8px;\n}\n\n.form-check-label[_ngcontent-%COMP%] {\n font-size: 0.9em;\n}\n\n.badge-success[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n padding: 3px 8px;\n border-radius: 10px;\n font-size: 0.75em;\n font-weight: 600;\n}\n\n.badge-secondary[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-text-muted) 15%, var(--mj-bg-surface));\n color: var(--mj-text-muted);\n border: 1px solid color-mix(in srgb, var(--mj-text-muted) 30%, transparent);\n padding: 3px 8px;\n border-radius: 10px;\n font-size: 0.75em;\n font-weight: 600;\n}\n\n\n\n.content-text-editor[_ngcontent-%COMP%] {\n flex: 1;\n padding: 20px;\n display: flex;\n flex-direction: column;\n}\n\n.editor-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.editor-label[_ngcontent-%COMP%] {\n margin: 0;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.content-type-badge[_ngcontent-%COMP%] {\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 0.75em;\n color: var(--mj-text-inverse);\n}\n\n.content-type-badge.new[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n.content-type-badge.existing[_ngcontent-%COMP%] {\n background: var(--mj-text-muted);\n}\n\n.editor-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.unsaved-indicator[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 0.85em;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.unsaved-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.5em;\n}\n\n.run-btn[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 0.85em;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n cursor: pointer;\n}\n\n.run-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n\n\n.code-editor-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n height: 350px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n}\n\n\n\n.template-help-section[_ngcontent-%COMP%] {\n margin-top: 16px;\n}\n\n.help-tabs[_ngcontent-%COMP%] {\n display: flex;\n border-bottom: 2px solid var(--mj-border-default);\n margin-bottom: 0;\n}\n\n.help-tab[_ngcontent-%COMP%] {\n padding: 8px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 600;\n color: var(--mj-text-muted);\n border-bottom: 3px solid transparent;\n transition: all 0.2s;\n}\n\n.help-tab.active[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n border-bottom-color: var(--mj-status-success);\n}\n\n\n\n.help-content[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-top: none;\n border-radius: 0 0 4px 4px;\n}\n\n\n\n.syntax-help[_ngcontent-%COMP%] {\n font-size: 0.85em;\n}\n\n.syntax-help[_ngcontent-%COMP%] .section-title[_ngcontent-%COMP%] {\n font-weight: 600;\n margin-bottom: 12px;\n color: var(--mj-status-success);\n}\n\n.syntax-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n}\n\n.syntax-item[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n}\n\n.syntax-help[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 4px 6px;\n border-radius: 3px;\n display: inline-block;\n margin-top: 4px;\n color: var(--mj-text-primary);\n}\n\n\n\n.placeholders-help[_ngcontent-%COMP%] {\n font-size: 0.85em;\n}\n\n.placeholders-help[_ngcontent-%COMP%] .section-title[_ngcontent-%COMP%] {\n font-weight: 600;\n margin-bottom: 12px;\n color: var(--mj-status-success);\n}\n\n.placeholders-description[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n\n\n.category-tabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n}\n\n.category-tab[_ngcontent-%COMP%] {\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 20px;\n cursor: pointer;\n font-size: 0.85em;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n color: var(--mj-text-muted);\n}\n\n.category-tab.active[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.category-tab[_ngcontent-%COMP%] .tab-badge[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n color: inherit;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 0.75em;\n margin-left: 4px;\n}\n\n\n\n.placeholder-content[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n}\n\n.category-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 16px;\n}\n\n.category-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.2em;\n}\n\n.category-header[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n.placeholder-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 10px;\n}\n\n\n\n.placeholder-item[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n position: relative;\n transition: all 0.2s;\n max-width: 800px;\n}\n\n.placeholder-item[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.placeholder-item[_ngcontent-%COMP%]:hover .copy-btn[_ngcontent-%COMP%] {\n opacity: 1 !important;\n}\n\n.placeholder-item-inner[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.placeholder-name-row[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n\n.placeholder-code[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: 600;\n font-size: 0.95em;\n}\n\n.copy-btn[_ngcontent-%COMP%] {\n opacity: 0;\n transition: opacity 0.2s;\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-brand-primary);\n border-radius: 4px;\n display: inline-flex;\n align-items: center;\n}\n\n.copy-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.copy-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.85em;\n}\n\n.placeholder-description[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n\n\n.usage-example[_ngcontent-%COMP%] {\n margin-top: 20px;\n padding: 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 20%, var(--mj-bg-surface));\n}\n\n.usage-example-inner[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.usage-example[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n margin-top: 2px;\n}\n\n.usage-example-text[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 0.85em;\n color: var(--mj-brand-primary);\n line-height: 1.5;\n}\n\n.usage-example[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 2px 4px;\n border-radius: 3px;\n}\n\n\n\n.no-content-state[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface-card);\n border: 2px dashed var(--mj-border-default);\n border-radius: 8px;\n padding: 40px;\n text-align: center;\n}\n\n.no-content-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n color: var(--mj-text-muted);\n opacity: 0.6;\n}\n\n.no-content-state[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n margin-bottom: 8px;\n}\n\n.no-content-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n margin-bottom: 20px;\n}"] }); }
|
|
899
|
+
} }, dependencies: [i3.CheckboxControlValueAccessor, i3.NgControlStatus, i3.NgModel, i2.MJDropdownComponent, i2.MJNumericInputComponent, i4.CodeEditorComponent], styles: [".template-editor[_ngcontent-%COMP%] {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n}\n\n.section-header[_ngcontent-%COMP%] h6[_ngcontent-%COMP%] {\n font-size: 0.9em;\n}\n\n.param-row[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-bg-surface-card) !important;\n}\n\n.content-item[_ngcontent-%COMP%] {\n transition: box-shadow 0.2s ease;\n}\n\n.content-item[_ngcontent-%COMP%]:hover {\n box-shadow: 0 2px 4px var(--mj-shadow-sm);\n}\n\n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n}\n\n.badge[_ngcontent-%COMP%] {\n display: inline-block;\n font-size: 0.7em;\n line-height: 1;\n}\n\n\n\n.template-editor[_ngcontent-%COMP%] .mj-input[_ngcontent-%COMP%], \n.template-editor[_ngcontent-%COMP%] .mj-textarea[_ngcontent-%COMP%], \n.template-editor[_ngcontent-%COMP%] mj-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.template-editor[_ngcontent-%COMP%] [mjButton][_ngcontent-%COMP%] {\n min-width: auto;\n}\n\n\n\n.content-versions-tabs[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n border-bottom: 2px solid var(--mj-border-default);\n padding-bottom: 8px;\n}\n\n.content-tabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.content-version-tab[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface);\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n position: relative;\n}\n\n.content-version-tab.active[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.content-version-tab[_ngcontent-%COMP%] .tab-label[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 0.85em;\n color: var(--mj-text-secondary);\n}\n\n.content-version-tab[_ngcontent-%COMP%] .tab-meta[_ngcontent-%COMP%] {\n font-size: 0.7em;\n color: var(--mj-text-muted);\n}\n\n.content-version-tab[_ngcontent-%COMP%] .tab-meta[_ngcontent-%COMP%] .inactive-label[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.content-version-tab[_ngcontent-%COMP%] .delete-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-status-error);\n padding: 4px;\n border-radius: 3px;\n transition: all 0.2s;\n cursor: pointer;\n}\n\n.content-version-tab[_ngcontent-%COMP%] .delete-btn[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n}\n\n\n\n.content-version-tab.adding-new[_ngcontent-%COMP%] {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n}\n\n.content-version-tab.adding-new[_ngcontent-%COMP%] .new-label[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-status-success);\n font-size: 0.85em;\n}\n\n\n\n.content-version-tab.add-new[_ngcontent-%COMP%] {\n border: 1px dashed var(--mj-status-success);\n background: var(--mj-bg-surface-card);\n}\n\n.content-version-tab.add-new[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n border-style: solid;\n}\n\n.content-version-tab.add-new[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n font-size: 0.75em;\n}\n\n.content-version-tab.add-new[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--mj-status-success);\n font-size: 0.85em;\n}\n\n\n\n.content-editor-container[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n\n\n.content-metadata-bar[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 16px 20px;\n}\n\n.metadata-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr auto;\n gap: 20px;\n align-items: end;\n}\n\n.form-group[_ngcontent-%COMP%] {\n margin: 0;\n}\n\n.form-label[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n font-size: 0.9em;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-control-plaintext[_ngcontent-%COMP%] {\n font-size: 0.9em;\n padding: 4px 0;\n}\n\n.form-check[_ngcontent-%COMP%] {\n margin-top: 8px;\n}\n\n.form-check-label[_ngcontent-%COMP%] {\n font-size: 0.9em;\n}\n\n.badge-success[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n padding: 3px 8px;\n border-radius: 10px;\n font-size: 0.75em;\n font-weight: 600;\n}\n\n.badge-secondary[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-text-muted) 15%, var(--mj-bg-surface));\n color: var(--mj-text-muted);\n border: 1px solid color-mix(in srgb, var(--mj-text-muted) 30%, transparent);\n padding: 3px 8px;\n border-radius: 10px;\n font-size: 0.75em;\n font-weight: 600;\n}\n\n\n\n.content-text-editor[_ngcontent-%COMP%] {\n flex: 1;\n padding: 20px;\n display: flex;\n flex-direction: column;\n}\n\n.editor-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.editor-label[_ngcontent-%COMP%] {\n margin: 0;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.content-type-badge[_ngcontent-%COMP%] {\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 0.75em;\n color: var(--mj-text-inverse);\n}\n\n.content-type-badge.new[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n.content-type-badge.existing[_ngcontent-%COMP%] {\n background: var(--mj-text-muted);\n}\n\n.editor-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.unsaved-indicator[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 0.85em;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.unsaved-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.5em;\n}\n\n.run-btn[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 0.85em;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n cursor: pointer;\n}\n\n.run-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n\n\n.code-editor-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n height: 350px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n}\n\n\n\n.template-help-section[_ngcontent-%COMP%] {\n margin-top: 16px;\n}\n\n.help-tabs[_ngcontent-%COMP%] {\n display: flex;\n border-bottom: 2px solid var(--mj-border-default);\n margin-bottom: 0;\n}\n\n.help-tab[_ngcontent-%COMP%] {\n padding: 8px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 600;\n color: var(--mj-text-muted);\n border-bottom: 3px solid transparent;\n transition: all 0.2s;\n}\n\n.help-tab.active[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n border-bottom-color: var(--mj-status-success);\n}\n\n\n\n.help-content[_ngcontent-%COMP%] {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-top: none;\n border-radius: 0 0 4px 4px;\n}\n\n\n\n.syntax-help[_ngcontent-%COMP%] {\n font-size: 0.85em;\n}\n\n.syntax-help[_ngcontent-%COMP%] .section-title[_ngcontent-%COMP%] {\n font-weight: 600;\n margin-bottom: 12px;\n color: var(--mj-status-success);\n}\n\n.syntax-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n}\n\n.syntax-item[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n}\n\n.syntax-help[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 4px 6px;\n border-radius: 3px;\n display: inline-block;\n margin-top: 4px;\n color: var(--mj-text-primary);\n}\n\n\n\n.placeholders-help[_ngcontent-%COMP%] {\n font-size: 0.85em;\n}\n\n.placeholders-help[_ngcontent-%COMP%] .section-title[_ngcontent-%COMP%] {\n font-weight: 600;\n margin-bottom: 12px;\n color: var(--mj-status-success);\n}\n\n.placeholders-description[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n\n\n.category-tabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n}\n\n.category-tab[_ngcontent-%COMP%] {\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 20px;\n cursor: pointer;\n font-size: 0.85em;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n color: var(--mj-text-muted);\n}\n\n.category-tab.active[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.category-tab[_ngcontent-%COMP%] .tab-badge[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n color: inherit;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 0.75em;\n margin-left: 4px;\n}\n\n\n\n.placeholder-content[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n}\n\n.category-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 16px;\n}\n\n.category-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.2em;\n}\n\n.category-header[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n.placeholder-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 10px;\n}\n\n\n\n.placeholder-item[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n position: relative;\n transition: all 0.2s;\n max-width: 800px;\n}\n\n.placeholder-item[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.placeholder-item[_ngcontent-%COMP%]:hover .copy-btn[_ngcontent-%COMP%] {\n opacity: 1 !important;\n}\n\n.placeholder-item-inner[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.placeholder-name-row[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n\n.placeholder-code[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: 600;\n font-size: 0.95em;\n}\n\n.copy-btn[_ngcontent-%COMP%] {\n opacity: 0;\n transition: opacity 0.2s;\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-brand-primary);\n border-radius: 4px;\n display: inline-flex;\n align-items: center;\n}\n\n.copy-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.copy-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.85em;\n}\n\n.placeholder-description[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n\n\n.usage-example[_ngcontent-%COMP%] {\n margin-top: 20px;\n padding: 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 20%, var(--mj-bg-surface));\n}\n\n.usage-example-inner[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.usage-example[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n margin-top: 2px;\n}\n\n.usage-example-text[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 0.85em;\n color: var(--mj-brand-primary);\n line-height: 1.5;\n}\n\n.usage-example[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 2px 4px;\n border-radius: 3px;\n}\n\n\n\n.no-content-state[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface-card);\n border: 2px dashed var(--mj-border-default);\n border-radius: 8px;\n padding: 40px;\n text-align: center;\n}\n\n.no-content-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n color: var(--mj-text-muted);\n opacity: 0.6;\n}\n\n.no-content-state[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n margin-bottom: 8px;\n}\n\n.no-content-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n margin-bottom: 20px;\n}"] }); }
|
|
899
900
|
}
|
|
900
901
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TemplateEditorComponent, [{
|
|
901
902
|
type: Component,
|
|
902
903
|
args: [{ standalone: false, selector: 'mj-template-editor', template: "@if (template) {\n <div class=\"template-editor\" style=\"height: 100%; display: flex; flex-direction: column;\">\n <!-- Content Versions List/Tabs -->\n @if (templateContents.length > 0) {\n <div class=\"content-versions-tabs\">\n <div class=\"content-tabs\">\n @for (content of templateContents; track content.ID || $index; let i = $index) {\n <div class=\"content-version-tab\"\n [class.active]=\"selectedContentIndex === i && !isAddingNewContent\"\n (click)=\"selectTemplateContent(i, false)\">\n <div style=\"flex: 1;\">\n <div class=\"tab-label\">\n {{ content.Type || 'Version ' + (i + 1) }}\n </div>\n <div class=\"tab-meta\">\n P:{{ content.Priority }}\n @if (!content.IsActive) {\n \u2022 <span class=\"inactive-label\">Inactive</span>\n }\n </div>\n </div>\n @if (templateContents.length > 1 && config.allowEdit) {\n <button type=\"button\"\n (click)=\"deleteTemplateContent(i); $event.stopPropagation()\"\n class=\"delete-btn\"\n title=\"Delete this content version\">\n <i class=\"fa-solid fa-trash fa-xs\"></i>\n </button>\n }\n </div>\n }\n @if (isAddingNewContent) {\n <div class=\"content-version-tab adding-new\">\n <i class=\"fa-solid fa-plus text-success\"></i>\n <span class=\"new-label\">New</span>\n </div>\n }\n <!-- Add New Content (Edit Mode Only) -->\n @if (config.allowEdit && !isAddingNewContent) {\n <div class=\"content-version-tab add-new\"\n (click)=\"addNewTemplateContent()\"\n title=\"Add new template content\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New</span>\n </div>\n }\n </div>\n </div>\n }\n <!-- Content Editor -->\n @if (currentTemplateContent) {\n <div class=\"content-editor-container\">\n <!-- Content Metadata Bar -->\n <div class=\"content-metadata-bar\">\n <div class=\"metadata-grid\">\n <div class=\"form-group\">\n <label for=\"contentType\" class=\"form-label\">\n <i class=\"fa-solid fa-tag\"></i> Content Type\n </label>\n @if (config.allowEdit) {\n <mj-dropdown [(ngModel)]=\"currentTemplateContent.TypeID\"\n name=\"contentType\"\n [Data]=\"getContentTypeOptionsForContent()\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n (ValueChange)=\"onContentTypeChange()\">\n </mj-dropdown>\n } @else {\n <div class=\"form-control-plaintext\">\n {{ getContentTypeDisplayText(currentTemplateContent.TypeID) }}\n </div>\n }\n </div>\n <div class=\"form-group\">\n <label for=\"priority\" class=\"form-label\">\n <i class=\"fa-solid fa-sort-numeric-up\"></i> Priority\n </label>\n @if (config.allowEdit) {\n <mj-numeric-input [(ngModel)]=\"currentTemplateContent.Priority\"\n name=\"priority\"\n [Min]=\"1\"\n [Step]=\"1\"\n [Format]=\"'n0'\">\n </mj-numeric-input>\n } @else {\n <div class=\"form-control-plaintext\">\n {{ currentTemplateContent.Priority || '-' }}\n </div>\n }\n </div>\n <div class=\"form-group\">\n <label class=\"form-label\">\n <i class=\"fa-solid fa-toggle-on\"></i> Status\n </label>\n @if (config.allowEdit) {\n <div class=\"form-check\">\n <input type=\"checkbox\"\n id=\"isActive\"\n class=\"form-check-input\"\n [(ngModel)]=\"currentTemplateContent.IsActive\"\n name=\"isActive\">\n <label class=\"form-check-label\" for=\"isActive\">\n Active\n </label>\n </div>\n } @else {\n <div class=\"form-control-plaintext\">\n @if (currentTemplateContent.IsActive) {\n <span class=\"badge-success\">\n <i class=\"fa-solid fa-check-circle\"></i> Active\n </span>\n } @else {\n <span class=\"badge-secondary\">\n <i class=\"fa-solid fa-pause-circle\"></i> Inactive\n </span>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Content Text Editor -->\n <div class=\"content-text-editor\">\n <div class=\"editor-header\">\n <label for=\"templateContent\" class=\"editor-label\">\n <i class=\"fa-solid fa-code\"></i> Template Content\n <span class=\"content-type-badge\"\n [class.new]=\"!currentTemplateContent.ID\"\n [class.existing]=\"!!currentTemplateContent.ID\">\n @if (!currentTemplateContent.ID) {\n New\n } @else {\n {{ getContentTypeDisplayText(currentTemplateContent.TypeID) }}\n }\n </span>\n </label>\n <div class=\"editor-actions\">\n @if (!isAddingNewContent && hasUnsavedChanges) {\n <span class=\"unsaved-indicator\">\n <i class=\"fa-solid fa-circle\"></i>\n Unsaved changes\n </span>\n }\n @if (template.IsSaved && currentTemplateContent && config.showRunButton) {\n <button type=\"button\"\n class=\"run-btn\"\n [disabled]=\"isRunningTemplate\"\n (click)=\"onRunTemplate()\"\n title=\"Test run this template\">\n @if (isRunningTemplate) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Running...\n } @else {\n <i class=\"fa-solid fa-play\"></i>\n Run\n }\n </button>\n }\n </div>\n </div>\n <mj-code-editor\n #codeEditor\n (change)=\"onTemplateTextChange($event)\"\n [readonly]=\"!config.allowEdit\"\n [language]=\"getEditorLanguage()\"\n [languages]=\"supportedLanguages\"\n class=\"code-editor-wrapper\">\n </mj-code-editor>\n <!-- Template Help Section with Tabs -->\n @if (!config.compactMode) {\n <div class=\"template-help-section\">\n <!-- Tab Navigation -->\n <div class=\"help-tabs\">\n <button type=\"button\"\n class=\"help-tab\"\n [class.active]=\"activeHelpTab === 'syntax'\"\n (click)=\"activeHelpTab = 'syntax'\">\n <i class=\"fa-solid fa-code\"></i> Template Syntax\n </button>\n <button type=\"button\"\n class=\"help-tab\"\n [class.active]=\"activeHelpTab === 'placeholders'\"\n (click)=\"activeHelpTab = 'placeholders'\">\n <i class=\"fa-solid fa-at\"></i> System Placeholders\n </button>\n </div>\n <!-- Tab Content -->\n <div class=\"help-content\">\n <!-- Template Syntax Tab -->\n @if (activeHelpTab === 'syntax') {\n <div class=\"syntax-help\">\n <div class=\"section-title\">\n <i class=\"fa-solid fa-lightbulb\"></i> Template Syntax Quick Reference\n </div>\n <div class=\"syntax-grid\">\n <div>\n <div class=\"syntax-item\">\n <strong>Parameters:</strong><br>\n <code>{{'{{'}} paramName {{'}}'}}</code>\n </div>\n <div>\n <strong>Template Includes:</strong><br>\n <code>{{'{% template \"TemplateName\" %}'}}</code>\n </div>\n </div>\n <div>\n <div class=\"syntax-item\">\n <strong>Conditionals:</strong><br>\n <code>{{'{% if condition %}'}} ... {{'{% endif %}'}}</code>\n </div>\n <div>\n <strong>Loops:</strong><br>\n <code>{{'{% for item in items %}'}} ... {{'{% endfor %}'}}</code>\n </div>\n </div>\n </div>\n </div>\n }\n <!-- System Placeholders Tab -->\n @if (activeHelpTab === 'placeholders') {\n <div class=\"placeholders-help\">\n <div class=\"section-title\">\n <i class=\"fa-solid fa-at\"></i> System Placeholders Reference\n </div>\n <p class=\"placeholders-description\">\n System placeholders are automatically available in all AI prompt templates. Simply use them in your template text and they will be replaced with their current values at execution time.\n </p>\n <!-- Category Sub-tabs -->\n <div class=\"category-tabs\">\n @for (categoryGroup of placeholderCategories; track categoryGroup.category.name) {\n <button type=\"button\"\n class=\"category-tab\"\n [class.active]=\"activePlaceholderCategory === categoryGroup.category.name\"\n (click)=\"activePlaceholderCategory = categoryGroup.category.name\">\n <i [class]=\"'fa-solid ' + categoryGroup.category.icon\" style=\"font-size: 0.9em;\"></i>\n {{ categoryGroup.category.name }}\n <span class=\"tab-badge\">\n {{ categoryGroup.placeholders.length }}\n </span>\n </button>\n }\n </div>\n <!-- Active Category Content -->\n <div class=\"placeholder-content\">\n @for (categoryGroup of placeholderCategories; track categoryGroup.category.name) {\n @if (activePlaceholderCategory === categoryGroup.category.name) {\n <div class=\"category-header\">\n <i [class]=\"'fa-solid ' + categoryGroup.category.icon\"\n [style.color]=\"categoryGroup.category.color\"></i>\n <h5>{{ categoryGroup.category.name }}</h5>\n </div>\n <div class=\"placeholder-grid\">\n @for (placeholder of categoryGroup.placeholders; track placeholder.name) {\n <div class=\"placeholder-item\">\n <div class=\"placeholder-item-inner\">\n <div>\n <div class=\"placeholder-name-row\">\n <code class=\"placeholder-code\">{{'{{'}} {{ placeholder.name }} {{'}}'}}</code>\n <button type=\"button\"\n class=\"copy-btn\"\n (click)=\"copyPlaceholder(placeholder.name)\"\n title=\"Copy placeholder to clipboard\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n @if (placeholder.description) {\n <div class=\"placeholder-description\">{{ placeholder.description }}</div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n <!-- Usage Example -->\n <div class=\"usage-example\">\n <div class=\"usage-example-inner\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <div class=\"usage-example-text\">\n <strong>Usage Example:</strong> To use a system placeholder in your template, simply include it in double curly braces.\n For example: <code>\"Today is {{'{{'}} _CURRENT_DATE {{'}}'}} and the current user is {{'{{'}} _USER_NAME {{'}}'}}\"</code>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- No Content State -->\n <div class=\"no-content-state\">\n <i class=\"fa-solid fa-file-plus\"></i>\n <h5>No Template Content</h5>\n <p>Create your first template content version to get started.</p>\n @if (config.allowEdit) {\n <button type=\"button\"\n (click)=\"addNewTemplateContent()\"\n class=\"btn btn-primary\">\n <i class=\"fa-solid fa-plus\"></i> Create First Content Version\n </button>\n }\n </div>\n }\n </div>\n}\n", styles: [".template-editor {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n}\n\n.section-header h6 {\n font-size: 0.9em;\n}\n\n.param-row:hover {\n background-color: var(--mj-bg-surface-card) !important;\n}\n\n.content-item {\n transition: box-shadow 0.2s ease;\n}\n\n.content-item:hover {\n box-shadow: 0 2px 4px var(--mj-shadow-sm);\n}\n\n.loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n}\n\n.badge {\n display: inline-block;\n font-size: 0.7em;\n line-height: 1;\n}\n\n/* Form control sizing */\n.template-editor .mj-input,\n.template-editor .mj-textarea,\n.template-editor mj-dropdown {\n width: 100%;\n}\n\n.template-editor [mjButton] {\n min-width: auto;\n}\n\n/* Content version tabs */\n.content-versions-tabs {\n margin-bottom: 16px;\n border-bottom: 2px solid var(--mj-border-default);\n padding-bottom: 8px;\n}\n\n.content-tabs {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.content-version-tab {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface);\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n position: relative;\n}\n\n.content-version-tab.active {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.content-version-tab .tab-label {\n font-weight: 600;\n font-size: 0.85em;\n color: var(--mj-text-secondary);\n}\n\n.content-version-tab .tab-meta {\n font-size: 0.7em;\n color: var(--mj-text-muted);\n}\n\n.content-version-tab .tab-meta .inactive-label {\n color: var(--mj-status-error);\n}\n\n.content-version-tab .delete-btn {\n background: none;\n border: none;\n color: var(--mj-status-error);\n padding: 4px;\n border-radius: 3px;\n transition: all 0.2s;\n cursor: pointer;\n}\n\n.content-version-tab .delete-btn:hover {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n}\n\n/* New content tab (adding state) */\n.content-version-tab.adding-new {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n}\n\n.content-version-tab.adding-new .new-label {\n font-weight: 600;\n color: var(--mj-status-success);\n font-size: 0.85em;\n}\n\n/* Add new content button */\n.content-version-tab.add-new {\n border: 1px dashed var(--mj-status-success);\n background: var(--mj-bg-surface-card);\n}\n\n.content-version-tab.add-new:hover {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n border-style: solid;\n}\n\n.content-version-tab.add-new i {\n color: var(--mj-status-success);\n font-size: 0.75em;\n}\n\n.content-version-tab.add-new span {\n font-weight: 500;\n color: var(--mj-status-success);\n font-size: 0.85em;\n}\n\n/* Content editor container */\n.content-editor-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n/* Content metadata bar */\n.content-metadata-bar {\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 16px 20px;\n}\n\n.metadata-grid {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr auto;\n gap: 20px;\n align-items: end;\n}\n\n.form-group {\n margin: 0;\n}\n\n.form-label {\n margin-bottom: 4px;\n font-size: 0.9em;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-control-plaintext {\n font-size: 0.9em;\n padding: 4px 0;\n}\n\n.form-check {\n margin-top: 8px;\n}\n\n.form-check-label {\n font-size: 0.9em;\n}\n\n.badge-success {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n padding: 3px 8px;\n border-radius: 10px;\n font-size: 0.75em;\n font-weight: 600;\n}\n\n.badge-secondary {\n background: color-mix(in srgb, var(--mj-text-muted) 15%, var(--mj-bg-surface));\n color: var(--mj-text-muted);\n border: 1px solid color-mix(in srgb, var(--mj-text-muted) 30%, transparent);\n padding: 3px 8px;\n border-radius: 10px;\n font-size: 0.75em;\n font-weight: 600;\n}\n\n/* Content text editor area */\n.content-text-editor {\n flex: 1;\n padding: 20px;\n display: flex;\n flex-direction: column;\n}\n\n.editor-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.editor-label {\n margin: 0;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.content-type-badge {\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 0.75em;\n color: var(--mj-text-inverse);\n}\n\n.content-type-badge.new {\n background: var(--mj-status-success);\n}\n\n.content-type-badge.existing {\n background: var(--mj-text-muted);\n}\n\n.editor-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.unsaved-indicator {\n color: var(--mj-status-warning);\n font-size: 0.85em;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.unsaved-indicator i {\n font-size: 0.5em;\n}\n\n.run-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 0.85em;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n cursor: pointer;\n}\n\n.run-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n/* Code editor border */\n.code-editor-wrapper {\n flex: 1;\n height: 350px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n}\n\n/* Help section tabs */\n.template-help-section {\n margin-top: 16px;\n}\n\n.help-tabs {\n display: flex;\n border-bottom: 2px solid var(--mj-border-default);\n margin-bottom: 0;\n}\n\n.help-tab {\n padding: 8px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 600;\n color: var(--mj-text-muted);\n border-bottom: 3px solid transparent;\n transition: all 0.2s;\n}\n\n.help-tab.active {\n color: var(--mj-status-success);\n border-bottom-color: var(--mj-status-success);\n}\n\n/* Help content area */\n.help-content {\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-top: none;\n border-radius: 0 0 4px 4px;\n}\n\n/* Syntax help */\n.syntax-help {\n font-size: 0.85em;\n}\n\n.syntax-help .section-title {\n font-weight: 600;\n margin-bottom: 12px;\n color: var(--mj-status-success);\n}\n\n.syntax-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n}\n\n.syntax-item {\n margin-bottom: 8px;\n}\n\n.syntax-help code {\n background: var(--mj-bg-surface);\n padding: 4px 6px;\n border-radius: 3px;\n display: inline-block;\n margin-top: 4px;\n color: var(--mj-text-primary);\n}\n\n/* Placeholders help */\n.placeholders-help {\n font-size: 0.85em;\n}\n\n.placeholders-help .section-title {\n font-weight: 600;\n margin-bottom: 12px;\n color: var(--mj-status-success);\n}\n\n.placeholders-description {\n margin-bottom: 16px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Category tabs */\n.category-tabs {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n}\n\n.category-tab {\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 20px;\n cursor: pointer;\n font-size: 0.85em;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s;\n color: var(--mj-text-muted);\n}\n\n.category-tab.active {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.category-tab .tab-badge {\n background: color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n color: inherit;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 0.75em;\n margin-left: 4px;\n}\n\n/* Placeholder content area */\n.placeholder-content {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n}\n\n.category-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 16px;\n}\n\n.category-header i {\n font-size: 1.2em;\n}\n\n.category-header h5 {\n margin: 0;\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n.placeholder-grid {\n display: grid;\n gap: 10px;\n}\n\n/* Placeholder item */\n.placeholder-item {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n position: relative;\n transition: all 0.2s;\n max-width: 800px;\n}\n\n.placeholder-item:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.placeholder-item:hover .copy-btn {\n opacity: 1 !important;\n}\n\n.placeholder-item-inner {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.placeholder-name-row {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n\n.placeholder-code {\n color: var(--mj-status-error);\n font-weight: 600;\n font-size: 0.95em;\n}\n\n.copy-btn {\n opacity: 0;\n transition: opacity 0.2s;\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-brand-primary);\n border-radius: 4px;\n display: inline-flex;\n align-items: center;\n}\n\n.copy-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.copy-btn i {\n font-size: 0.85em;\n}\n\n.placeholder-description {\n color: var(--mj-text-muted);\n margin-top: 4px;\n line-height: 1.4;\n}\n\n/* Usage example box */\n.usage-example {\n margin-top: 20px;\n padding: 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 20%, var(--mj-bg-surface));\n}\n\n.usage-example-inner {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.usage-example i {\n color: var(--mj-brand-primary);\n margin-top: 2px;\n}\n\n.usage-example-text {\n flex: 1;\n font-size: 0.85em;\n color: var(--mj-brand-primary);\n line-height: 1.5;\n}\n\n.usage-example code {\n background: var(--mj-bg-surface);\n padding: 2px 4px;\n border-radius: 3px;\n}\n\n/* No content state */\n.no-content-state {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface-card);\n border: 2px dashed var(--mj-border-default);\n border-radius: 8px;\n padding: 40px;\n text-align: center;\n}\n\n.no-content-state i {\n font-size: 48px;\n margin-bottom: 16px;\n color: var(--mj-text-muted);\n opacity: 0.6;\n}\n\n.no-content-state h5 {\n color: var(--mj-text-secondary);\n margin-bottom: 8px;\n}\n\n.no-content-state p {\n color: var(--mj-text-muted);\n margin-bottom: 20px;\n}\n"] }]
|
|
903
|
-
}], () => [{ type: i1.MJNotificationService }], { template: [{
|
|
904
|
+
}], () => [{ type: i1.MJNotificationService }, { type: i2.MJConfirmService }], { template: [{
|
|
904
905
|
type: Input
|
|
905
906
|
}], config: [{
|
|
906
907
|
type: Input
|
|
@@ -912,5 +913,5 @@ export class TemplateEditorComponent extends BaseAngularComponent {
|
|
|
912
913
|
type: ViewChild,
|
|
913
914
|
args: ['codeEditor']
|
|
914
915
|
}] }); })();
|
|
915
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TemplateEditorComponent, { className: "TemplateEditorComponent", filePath: "src/lib/shared/components/template-editor.component.ts", lineNumber:
|
|
916
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TemplateEditorComponent, { className: "TemplateEditorComponent", filePath: "src/lib/shared/components/template-editor.component.ts", lineNumber: 26 }); })();
|
|
916
917
|
//# sourceMappingURL=template-editor.component.js.map
|