@memberjunction/ng-core-entity-forms 5.42.0 → 5.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.js +122 -173
- package/dist/lib/custom/Lists/list-form.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.js +190 -248
- 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/RecordProcesses/record-process-form.component.d.ts +16 -0
- package/dist/lib/custom/RecordProcesses/record-process-form.component.d.ts.map +1 -0
- package/dist/lib/custom/RecordProcesses/record-process-form.component.js +54 -0
- package/dist/lib/custom/RecordProcesses/record-process-form.component.js.map +1 -0
- 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.d.ts.map +1 -1
- package/dist/lib/custom/Templates/template-param-dialog.component.js +25 -46
- package/dist/lib/custom/Templates/template-param-dialog.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.js +100 -130
- 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 +8 -0
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.js +412 -489
- 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.js +42 -61
- 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-timeline.component.js +8 -17
- 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 +183 -188
- 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 -49
- package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
- package/dist/lib/custom/custom-forms.module.js +64 -16
- 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 +280 -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 +68 -14
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.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 +44 -32
- 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 +28 -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 +167 -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/MJApplication/mjapplication.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJApplication/mjapplication.form.component.js +59 -51
- 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 +56 -46
- 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/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 +137 -87
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityActionInvocation/mjentityactioninvocation.form.component.js +10 -8
- package/dist/lib/generated/Entities/MJEntityActionInvocation/mjentityactioninvocation.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/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/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 +56 -24
- package/dist/lib/generated/Entities/MJOpenApp/mjopenapp.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.js +19 -17
- package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.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 +46 -26
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRemoteOperation/mjremoteoperation.form.component.js +12 -6
- package/dist/lib/generated/Entities/MJRemoteOperation/mjremoteoperation.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 +36 -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/MJUser/mjuser.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js +145 -109
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js.map +1 -1
- package/dist/lib/generated/generated-forms.module.d.ts +356 -335
- package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
- package/dist/lib/generated/generated-forms.module.js +304 -226
- 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/package.json +38 -36
- 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,240 @@
|
|
|
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, ViewChild } from '@angular/core';
|
|
8
|
+
import { RegisterClassEx } from '@memberjunction/global';
|
|
9
|
+
import { BaseFormPanel } from '@memberjunction/ng-base-forms';
|
|
10
|
+
import { Metadata, AuthorizationEvaluator } from '@memberjunction/core';
|
|
11
|
+
// CodeGen-generated Remote Operation classes for AISkill.ExportMarkdown / AISkill.ImportMarkdown
|
|
12
|
+
// (see metadata/remote-operations/.remote-operations.json) — requires `mj codegen` to have run
|
|
13
|
+
// against the migration that seeds them before this file compiles.
|
|
14
|
+
import { AISkillExportMarkdownOperation, AISkillImportMarkdownOperation } from '@memberjunction/core-entities';
|
|
15
|
+
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
16
|
+
import * as i0 from "@angular/core";
|
|
17
|
+
import * as i1 from "@memberjunction/ng-ui-components";
|
|
18
|
+
import * as i2 from "@memberjunction/ng-base-forms";
|
|
19
|
+
import * as i3 from "@memberjunction/ng-agents";
|
|
20
|
+
const _c0 = ["importFileInput"];
|
|
21
|
+
function AISkillSharingPanel_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
22
|
+
i0.ɵɵelementStart(0, "p", 2);
|
|
23
|
+
i0.ɵɵtext(1, "Save this skill first to share it or export/import SKILL.md.");
|
|
24
|
+
i0.ɵɵelementEnd();
|
|
25
|
+
} }
|
|
26
|
+
function AISkillSharingPanel_Conditional_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
27
|
+
const _r2 = i0.ɵɵgetCurrentView();
|
|
28
|
+
i0.ɵɵelementStart(0, "button", 8);
|
|
29
|
+
i0.ɵɵlistener("click", function AISkillSharingPanel_Conditional_2_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenPermissionsDialog()); });
|
|
30
|
+
i0.ɵɵelement(1, "i", 9);
|
|
31
|
+
i0.ɵɵtext(2, " Manage Permissions ");
|
|
32
|
+
i0.ɵɵelementEnd();
|
|
33
|
+
} }
|
|
34
|
+
function AISkillSharingPanel_Conditional_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
35
|
+
i0.ɵɵelement(0, "i", 10);
|
|
36
|
+
i0.ɵɵtext(1, " Exporting\u2026 ");
|
|
37
|
+
} }
|
|
38
|
+
function AISkillSharingPanel_Conditional_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
39
|
+
i0.ɵɵelement(0, "i", 11);
|
|
40
|
+
i0.ɵɵtext(1, " Export SKILL.md ");
|
|
41
|
+
} }
|
|
42
|
+
function AISkillSharingPanel_Conditional_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
43
|
+
i0.ɵɵelement(0, "i", 10);
|
|
44
|
+
i0.ɵɵtext(1, " Importing\u2026 ");
|
|
45
|
+
} }
|
|
46
|
+
function AISkillSharingPanel_Conditional_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
47
|
+
i0.ɵɵelement(0, "i", 12);
|
|
48
|
+
i0.ɵɵtext(1, " Import SKILL.md ");
|
|
49
|
+
} }
|
|
50
|
+
function AISkillSharingPanel_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
51
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
52
|
+
i0.ɵɵelementStart(0, "div", 3);
|
|
53
|
+
i0.ɵɵconditionalCreate(1, AISkillSharingPanel_Conditional_2_Conditional_1_Template, 3, 0, "button", 5);
|
|
54
|
+
i0.ɵɵelementStart(2, "button", 6);
|
|
55
|
+
i0.ɵɵlistener("click", function AISkillSharingPanel_Conditional_2_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r1); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.ExportMarkdown()); });
|
|
56
|
+
i0.ɵɵconditionalCreate(3, AISkillSharingPanel_Conditional_2_Conditional_3_Template, 2, 0)(4, AISkillSharingPanel_Conditional_2_Conditional_4_Template, 2, 0);
|
|
57
|
+
i0.ɵɵelementEnd();
|
|
58
|
+
i0.ɵɵelementStart(5, "button", 6);
|
|
59
|
+
i0.ɵɵlistener("click", function AISkillSharingPanel_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r1); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.TriggerImport()); });
|
|
60
|
+
i0.ɵɵconditionalCreate(6, AISkillSharingPanel_Conditional_2_Conditional_6_Template, 2, 0)(7, AISkillSharingPanel_Conditional_2_Conditional_7_Template, 2, 0);
|
|
61
|
+
i0.ɵɵelementEnd();
|
|
62
|
+
i0.ɵɵelementStart(8, "input", 7, 0);
|
|
63
|
+
i0.ɵɵlistener("change", function AISkillSharingPanel_Conditional_2_Template_input_change_8_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnImportFileSelected($event)); });
|
|
64
|
+
i0.ɵɵelementEnd()();
|
|
65
|
+
} if (rf & 2) {
|
|
66
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
67
|
+
i0.ɵɵadvance();
|
|
68
|
+
i0.ɵɵconditional(ctx_r2.CanShareSkills ? 1 : -1);
|
|
69
|
+
i0.ɵɵadvance();
|
|
70
|
+
i0.ɵɵproperty("disabled", ctx_r2.IsExporting);
|
|
71
|
+
i0.ɵɵadvance();
|
|
72
|
+
i0.ɵɵconditional(ctx_r2.IsExporting ? 3 : 4);
|
|
73
|
+
i0.ɵɵadvance(2);
|
|
74
|
+
i0.ɵɵproperty("disabled", ctx_r2.IsImporting);
|
|
75
|
+
i0.ɵɵadvance();
|
|
76
|
+
i0.ɵɵconditional(ctx_r2.IsImporting ? 6 : 7);
|
|
77
|
+
} }
|
|
78
|
+
function AISkillSharingPanel_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
79
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
80
|
+
i0.ɵɵelementStart(0, "mj-skill-permissions-dialog", 13);
|
|
81
|
+
i0.ɵɵlistener("Closed", function AISkillSharingPanel_Conditional_3_Template_mj_skill_permissions_dialog_Closed_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnPermissionsDialogClosed()); });
|
|
82
|
+
i0.ɵɵelementEnd();
|
|
83
|
+
} if (rf & 2) {
|
|
84
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
85
|
+
i0.ɵɵproperty("Skill", ctx_r2.Record);
|
|
86
|
+
} }
|
|
87
|
+
/** `MJ: Authorizations.Name` gating the Manage Permissions action — seeded in metadata/authorizations/.agent-skills.json. */
|
|
88
|
+
const CAN_SHARE_SKILLS_AUTH_NAME = 'Can Share Skills';
|
|
89
|
+
/**
|
|
90
|
+
* Adds Manage Permissions / Export SKILL.md / Import SKILL.md actions to the generated
|
|
91
|
+
* `MJ: AI Skills` form via the BaseFormPanel slot system (Pattern 1 — see PANELS.md) rather than a
|
|
92
|
+
* full custom form override, since the generated form's field panels and related-entity grids are
|
|
93
|
+
* otherwise fine as-is.
|
|
94
|
+
*
|
|
95
|
+
* - Manage Permissions opens the dedicated `<mj-skill-permissions-dialog>` (from
|
|
96
|
+
* `@memberjunction/ng-agents`), which reads/writes the dedicated `MJ: AI Skill Permissions`
|
|
97
|
+
* table (per-user / per-role View/Run/Edit/Delete) — the same open-by-default, dedicated-table
|
|
98
|
+
* model AI Agents use. It is gated behind the "Can Share Skills" authorization; authoring/using
|
|
99
|
+
* your own skills never requires it.
|
|
100
|
+
* - Export/Import call the `AISkill.ExportMarkdown` / `AISkill.ImportMarkdown` Remote Operations
|
|
101
|
+
* (typed, provider-routed — see guides/REMOTE_OPERATIONS_GUIDE.md), which wrap
|
|
102
|
+
* `SkillImportExportService` in `@memberjunction/ai-agents` server-side.
|
|
103
|
+
*/
|
|
104
|
+
let AISkillSharingPanel = class AISkillSharingPanel extends BaseFormPanel {
|
|
105
|
+
constructor() {
|
|
106
|
+
super(...arguments);
|
|
107
|
+
this.PermissionsDialogVisible = false;
|
|
108
|
+
this.IsExporting = false;
|
|
109
|
+
this.IsImporting = false;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Whether the current user may manage this skill's permission grid (per-user / per-role
|
|
113
|
+
* View/Run/Edit/Delete on the skill). `BaseFormPanel` has no Provider input (the panel slot
|
|
114
|
+
* system doesn't thread one through yet), so this uses the global default provider —
|
|
115
|
+
* consistent with the rest of the not-yet-multi-provider-migrated panel system today.
|
|
116
|
+
*/
|
|
117
|
+
get CanShareSkills() {
|
|
118
|
+
const md = Metadata.Provider; // global-provider-ok: BaseFormPanel slots have no Provider input; panel system is single-provider today
|
|
119
|
+
if (!md?.CurrentUser) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
const auth = md.Authorizations?.find(a => a.Name === CAN_SHARE_SKILLS_AUTH_NAME);
|
|
123
|
+
if (!auth) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
return new AuthorizationEvaluator().CurrentUserCanExecuteWithAncestors(auth, md);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
get CanExportImport() {
|
|
134
|
+
return !!this.Record?.IsSaved;
|
|
135
|
+
}
|
|
136
|
+
OpenPermissionsDialog() {
|
|
137
|
+
this.PermissionsDialogVisible = true;
|
|
138
|
+
}
|
|
139
|
+
OnPermissionsDialogClosed() {
|
|
140
|
+
this.PermissionsDialogVisible = false;
|
|
141
|
+
}
|
|
142
|
+
async ExportMarkdown() {
|
|
143
|
+
this.IsExporting = true;
|
|
144
|
+
try {
|
|
145
|
+
const result = await new AISkillExportMarkdownOperation().Execute({ skillID: this.Record.ID }, { provider: Metadata.Provider } // global-provider-ok: BaseFormPanel slots have no Provider input; panel system is single-provider today
|
|
146
|
+
);
|
|
147
|
+
if (!result.Success || !result.Output) {
|
|
148
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Export failed: ${result.ErrorMessage ?? 'unknown error'}`, 'error', 5000);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
this.downloadTextFile(result.Output.markdown, `${result.Output.suggestedFileName}.SKILL.md`);
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Export failed: ${error.message}`, 'error', 5000);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
this.IsExporting = false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Opens the hidden file input; the actual import happens in `OnImportFileSelected`. */
|
|
161
|
+
TriggerImport() {
|
|
162
|
+
this.importFileInput?.nativeElement.click();
|
|
163
|
+
}
|
|
164
|
+
async OnImportFileSelected(event) {
|
|
165
|
+
const input = event.target;
|
|
166
|
+
const file = input.files?.[0];
|
|
167
|
+
input.value = ''; // allow re-selecting the same file next time
|
|
168
|
+
if (!file) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this.IsImporting = true;
|
|
172
|
+
try {
|
|
173
|
+
const markdownText = await file.text();
|
|
174
|
+
const result = await new AISkillImportMarkdownOperation().Execute({ markdownText, updateSkillID: this.Record.ID }, { provider: Metadata.Provider } // global-provider-ok: BaseFormPanel slots have no Provider input; panel system is single-provider today
|
|
175
|
+
);
|
|
176
|
+
if (!result.Success || !result.Output) {
|
|
177
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Import failed: ${result.ErrorMessage ?? 'unknown error'}`, 'error', 5000);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (result.Output.warnings.length > 0) {
|
|
181
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Imported "${result.Output.skillName}" with ${result.Output.warnings.length} warning(s): ${result.Output.warnings.join('; ')}`, 'warning', 8000);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Imported "${result.Output.skillName}".`, 'success', 3000);
|
|
185
|
+
}
|
|
186
|
+
// Refresh this record's fields (Instructions/Description/Category may have changed).
|
|
187
|
+
await this.Record.Load(this.Record.ID);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Import failed: ${error.message}`, 'error', 5000);
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
this.IsImporting = false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
downloadTextFile(text, fileName) {
|
|
197
|
+
const blob = new Blob([text], { type: 'text/markdown' });
|
|
198
|
+
const url = URL.createObjectURL(blob);
|
|
199
|
+
const anchor = document.createElement('a');
|
|
200
|
+
anchor.href = url;
|
|
201
|
+
anchor.download = fileName;
|
|
202
|
+
anchor.click();
|
|
203
|
+
URL.revokeObjectURL(url);
|
|
204
|
+
}
|
|
205
|
+
static { this.ɵfac = /*@__PURE__*/ (() => { let ɵAISkillSharingPanel_BaseFactory; return function AISkillSharingPanel_Factory(__ngFactoryType__) { return (ɵAISkillSharingPanel_BaseFactory || (ɵAISkillSharingPanel_BaseFactory = i0.ɵɵgetInheritedFactory(AISkillSharingPanel)))(__ngFactoryType__ || AISkillSharingPanel); }; })(); }
|
|
206
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AISkillSharingPanel, selectors: [["mj-ai-skill-sharing-panel"]], viewQuery: function AISkillSharingPanel_Query(rf, ctx) { if (rf & 1) {
|
|
207
|
+
i0.ɵɵviewQuery(_c0, 5);
|
|
208
|
+
} if (rf & 2) {
|
|
209
|
+
let _t;
|
|
210
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.importFileInput = _t.first);
|
|
211
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 4, consts: [["importFileInput", ""], ["SectionKey", "aiSkillSharing", "SectionName", "Sharing & Portability", "Icon", "fa fa-share-nodes", 3, "Form", "FormContext"], [1, "ai-skill-sharing-hint"], [1, "ai-skill-sharing-actions"], [3, "Skill"], ["mjButton", "", "variant", "secondary", "size", "sm"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], ["type", "file", "accept", ".md,.SKILL.md,text/markdown", 1, "ai-skill-sharing-file-input", 3, "change"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-shield-halved"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-file-export"], [1, "fa-solid", "fa-file-import"], [3, "Closed", "Skill"]], template: function AISkillSharingPanel_Template(rf, ctx) { if (rf & 1) {
|
|
212
|
+
i0.ɵɵelementStart(0, "mj-collapsible-panel", 1);
|
|
213
|
+
i0.ɵɵconditionalCreate(1, AISkillSharingPanel_Conditional_1_Template, 2, 0, "p", 2)(2, AISkillSharingPanel_Conditional_2_Template, 10, 5, "div", 3);
|
|
214
|
+
i0.ɵɵelementEnd();
|
|
215
|
+
i0.ɵɵconditionalCreate(3, AISkillSharingPanel_Conditional_3_Template, 1, 1, "mj-skill-permissions-dialog", 4);
|
|
216
|
+
} if (rf & 2) {
|
|
217
|
+
i0.ɵɵproperty("Form", ctx.FormComponent)("FormContext", ctx.FormContext);
|
|
218
|
+
i0.ɵɵadvance();
|
|
219
|
+
i0.ɵɵconditional(!ctx.CanExportImport ? 1 : 2);
|
|
220
|
+
i0.ɵɵadvance(2);
|
|
221
|
+
i0.ɵɵconditional(ctx.PermissionsDialogVisible ? 3 : -1);
|
|
222
|
+
} }, dependencies: [i1.MJButtonDirective, i2.MjCollapsiblePanelComponent, i3.SkillPermissionsDialogComponent], styles: [".ai-skill-sharing-hint[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.875rem;\n margin: 0;\n}\n\n.ai-skill-sharing-actions[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n align-items: center;\n}\n\n.ai-skill-sharing-file-input[_ngcontent-%COMP%] {\n display: none;\n}"] }); }
|
|
223
|
+
};
|
|
224
|
+
AISkillSharingPanel = __decorate([
|
|
225
|
+
RegisterClassEx(BaseFormPanel, {
|
|
226
|
+
key: 'ai-skills:sharing-portability',
|
|
227
|
+
skipNullKeyWarning: true,
|
|
228
|
+
metadata: { entity: 'MJ: AI Skills', slot: 'after-fields', sortKey: 50 },
|
|
229
|
+
})
|
|
230
|
+
], AISkillSharingPanel);
|
|
231
|
+
export { AISkillSharingPanel };
|
|
232
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AISkillSharingPanel, [{
|
|
233
|
+
type: Component,
|
|
234
|
+
args: [{ standalone: false, selector: 'mj-ai-skill-sharing-panel', template: "<mj-collapsible-panel\n SectionKey=\"aiSkillSharing\"\n SectionName=\"Sharing & Portability\"\n Icon=\"fa fa-share-nodes\"\n [Form]=\"FormComponent\"\n [FormContext]=\"FormContext\">\n\n @if (!CanExportImport) {\n <p class=\"ai-skill-sharing-hint\">Save this skill first to share it or export/import SKILL.md.</p>\n } @else {\n <div class=\"ai-skill-sharing-actions\">\n @if (CanShareSkills) {\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"OpenPermissionsDialog()\">\n <i class=\"fa-solid fa-shield-halved\"></i> Manage Permissions\n </button>\n }\n\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"IsExporting\" (click)=\"ExportMarkdown()\">\n @if (IsExporting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Exporting\u2026\n } @else {\n <i class=\"fa-solid fa-file-export\"></i> Export SKILL.md\n }\n </button>\n\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"IsImporting\" (click)=\"TriggerImport()\">\n @if (IsImporting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Importing\u2026\n } @else {\n <i class=\"fa-solid fa-file-import\"></i> Import SKILL.md\n }\n </button>\n <input #importFileInput type=\"file\" accept=\".md,.SKILL.md,text/markdown\" class=\"ai-skill-sharing-file-input\" (change)=\"OnImportFileSelected($event)\" />\n </div>\n }\n</mj-collapsible-panel>\n\n@if (PermissionsDialogVisible) {\n <mj-skill-permissions-dialog\n [Skill]=\"Record\"\n (Closed)=\"OnPermissionsDialogClosed()\">\n </mj-skill-permissions-dialog>\n}\n", styles: [".ai-skill-sharing-hint {\n color: var(--mj-text-muted);\n font-size: 0.875rem;\n margin: 0;\n}\n\n.ai-skill-sharing-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n align-items: center;\n}\n\n.ai-skill-sharing-file-input {\n display: none;\n}\n"] }]
|
|
235
|
+
}], null, { importFileInput: [{
|
|
236
|
+
type: ViewChild,
|
|
237
|
+
args: ['importFileInput']
|
|
238
|
+
}] }); })();
|
|
239
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AISkillSharingPanel, { className: "AISkillSharingPanel", filePath: "src/lib/panels/ai-skill-sharing/ai-skill-sharing-panel.component.ts", lineNumber: 41 }); })();
|
|
240
|
+
//# sourceMappingURL=ai-skill-sharing-panel.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-skill-sharing-panel.component.js","sourceRoot":"","sources":["../../../../src/lib/panels/ai-skill-sharing/ai-skill-sharing-panel.component.ts","../../../../src/lib/panels/ai-skill-sharing/ai-skill-sharing-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewChild, ElementRef } from '@angular/core';\nimport { RegisterClassEx } from '@memberjunction/global';\nimport { BaseFormPanel } from '@memberjunction/ng-base-forms';\nimport { Metadata, AuthorizationEvaluator } from '@memberjunction/core';\nimport { MJAISkillEntity } from '@memberjunction/core-entities';\n// CodeGen-generated Remote Operation classes for AISkill.ExportMarkdown / AISkill.ImportMarkdown\n// (see metadata/remote-operations/.remote-operations.json) — requires `mj codegen` to have run\n// against the migration that seeds them before this file compiles.\nimport { AISkillExportMarkdownOperation, AISkillImportMarkdownOperation } from '@memberjunction/core-entities';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\n\n/** `MJ: Authorizations.Name` gating the Manage Permissions action — seeded in metadata/authorizations/.agent-skills.json. */\nconst CAN_SHARE_SKILLS_AUTH_NAME = 'Can Share Skills';\n\n/**\n * Adds Manage Permissions / Export SKILL.md / Import SKILL.md actions to the generated\n * `MJ: AI Skills` form via the BaseFormPanel slot system (Pattern 1 — see PANELS.md) rather than a\n * full custom form override, since the generated form's field panels and related-entity grids are\n * otherwise fine as-is.\n *\n * - Manage Permissions opens the dedicated `<mj-skill-permissions-dialog>` (from\n * `@memberjunction/ng-agents`), which reads/writes the dedicated `MJ: AI Skill Permissions`\n * table (per-user / per-role View/Run/Edit/Delete) — the same open-by-default, dedicated-table\n * model AI Agents use. It is gated behind the \"Can Share Skills\" authorization; authoring/using\n * your own skills never requires it.\n * - Export/Import call the `AISkill.ExportMarkdown` / `AISkill.ImportMarkdown` Remote Operations\n * (typed, provider-routed — see guides/REMOTE_OPERATIONS_GUIDE.md), which wrap\n * `SkillImportExportService` in `@memberjunction/ai-agents` server-side.\n */\n@RegisterClassEx(BaseFormPanel, {\n key: 'ai-skills:sharing-portability',\n skipNullKeyWarning: true,\n metadata: { entity: 'MJ: AI Skills', slot: 'after-fields', sortKey: 50 },\n})\n@Component({\n standalone: false,\n selector: 'mj-ai-skill-sharing-panel',\n templateUrl: './ai-skill-sharing-panel.component.html',\n styleUrls: ['./ai-skill-sharing-panel.component.css'],\n})\nexport class AISkillSharingPanel extends BaseFormPanel<MJAISkillEntity> {\n @ViewChild('importFileInput') importFileInput!: ElementRef<HTMLInputElement>;\n\n public PermissionsDialogVisible = false;\n\n public IsExporting = false;\n public IsImporting = false;\n\n /**\n * Whether the current user may manage this skill's permission grid (per-user / per-role\n * View/Run/Edit/Delete on the skill). `BaseFormPanel` has no Provider input (the panel slot\n * system doesn't thread one through yet), so this uses the global default provider —\n * consistent with the rest of the not-yet-multi-provider-migrated panel system today.\n */\n public get CanShareSkills(): boolean {\n const md = Metadata.Provider; // global-provider-ok: BaseFormPanel slots have no Provider input; panel system is single-provider today\n if (!md?.CurrentUser) {\n return false;\n }\n const auth = md.Authorizations?.find(a => a.Name === CAN_SHARE_SKILLS_AUTH_NAME);\n if (!auth) {\n return false;\n }\n try {\n return new AuthorizationEvaluator().CurrentUserCanExecuteWithAncestors(auth, md);\n } catch {\n return false;\n }\n }\n\n public get CanExportImport(): boolean {\n return !!this.Record?.IsSaved;\n }\n\n public OpenPermissionsDialog(): void {\n this.PermissionsDialogVisible = true;\n }\n\n public OnPermissionsDialogClosed(): void {\n this.PermissionsDialogVisible = false;\n }\n\n public async ExportMarkdown(): Promise<void> {\n this.IsExporting = true;\n try {\n const result = await new AISkillExportMarkdownOperation().Execute(\n { skillID: this.Record.ID },\n { provider: Metadata.Provider } // global-provider-ok: BaseFormPanel slots have no Provider input; panel system is single-provider today\n );\n if (!result.Success || !result.Output) {\n MJNotificationService.Instance.CreateSimpleNotification(\n `Export failed: ${result.ErrorMessage ?? 'unknown error'}`,\n 'error',\n 5000\n );\n return;\n }\n this.downloadTextFile(result.Output.markdown, `${result.Output.suggestedFileName}.SKILL.md`);\n } catch (error) {\n MJNotificationService.Instance.CreateSimpleNotification(\n `Export failed: ${(error as Error).message}`,\n 'error',\n 5000\n );\n } finally {\n this.IsExporting = false;\n }\n }\n\n /** Opens the hidden file input; the actual import happens in `OnImportFileSelected`. */\n public TriggerImport(): void {\n this.importFileInput?.nativeElement.click();\n }\n\n public async OnImportFileSelected(event: Event): Promise<void> {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n input.value = ''; // allow re-selecting the same file next time\n if (!file) {\n return;\n }\n\n this.IsImporting = true;\n try {\n const markdownText = await file.text();\n const result = await new AISkillImportMarkdownOperation().Execute(\n { markdownText, updateSkillID: this.Record.ID },\n { provider: Metadata.Provider } // global-provider-ok: BaseFormPanel slots have no Provider input; panel system is single-provider today\n );\n if (!result.Success || !result.Output) {\n MJNotificationService.Instance.CreateSimpleNotification(\n `Import failed: ${result.ErrorMessage ?? 'unknown error'}`,\n 'error',\n 5000\n );\n return;\n }\n if (result.Output.warnings.length > 0) {\n MJNotificationService.Instance.CreateSimpleNotification(\n `Imported \"${result.Output.skillName}\" with ${result.Output.warnings.length} warning(s): ${result.Output.warnings.join('; ')}`,\n 'warning',\n 8000\n );\n } else {\n MJNotificationService.Instance.CreateSimpleNotification(\n `Imported \"${result.Output.skillName}\".`,\n 'success',\n 3000\n );\n }\n // Refresh this record's fields (Instructions/Description/Category may have changed).\n await this.Record.Load(this.Record.ID);\n } catch (error) {\n MJNotificationService.Instance.CreateSimpleNotification(\n `Import failed: ${(error as Error).message}`,\n 'error',\n 5000\n );\n } finally {\n this.IsImporting = false;\n }\n }\n\n private downloadTextFile(text: string, fileName: string): void {\n const blob = new Blob([text], { type: 'text/markdown' });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = fileName;\n anchor.click();\n URL.revokeObjectURL(url);\n }\n}\n","<mj-collapsible-panel\n SectionKey=\"aiSkillSharing\"\n SectionName=\"Sharing & Portability\"\n Icon=\"fa fa-share-nodes\"\n [Form]=\"FormComponent\"\n [FormContext]=\"FormContext\">\n\n @if (!CanExportImport) {\n <p class=\"ai-skill-sharing-hint\">Save this skill first to share it or export/import SKILL.md.</p>\n } @else {\n <div class=\"ai-skill-sharing-actions\">\n @if (CanShareSkills) {\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"OpenPermissionsDialog()\">\n <i class=\"fa-solid fa-shield-halved\"></i> Manage Permissions\n </button>\n }\n\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"IsExporting\" (click)=\"ExportMarkdown()\">\n @if (IsExporting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Exporting…\n } @else {\n <i class=\"fa-solid fa-file-export\"></i> Export SKILL.md\n }\n </button>\n\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"IsImporting\" (click)=\"TriggerImport()\">\n @if (IsImporting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Importing…\n } @else {\n <i class=\"fa-solid fa-file-import\"></i> Import SKILL.md\n }\n </button>\n <input #importFileInput type=\"file\" accept=\".md,.SKILL.md,text/markdown\" class=\"ai-skill-sharing-file-input\" (change)=\"OnImportFileSelected($event)\" />\n </div>\n }\n</mj-collapsible-panel>\n\n@if (PermissionsDialogVisible) {\n <mj-skill-permissions-dialog\n [Skill]=\"Record\"\n (Closed)=\"OnPermissionsDialogClosed()\">\n </mj-skill-permissions-dialog>\n}\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, framework-free logic for the entity-agnostic Model Predictions panel.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the Angular component so the band computation, value
|
|
5
|
+
* formatting, and feature-importance parsing can be unit-tested without
|
|
6
|
+
* standing up Angular or a real entity record. NONE of this is entity-specific
|
|
7
|
+
* or domain-specific — it operates purely on numbers, strings, and the model's
|
|
8
|
+
* generic `ProblemType` / `FeatureImportance` JSON.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The neutral tercile a numeric prediction falls into. No moral direction is
|
|
12
|
+
* implied — `low`/`mid`/`high` describe position on the value axis only.
|
|
13
|
+
*/
|
|
14
|
+
export type PredictionBand = 'low' | 'mid' | 'high';
|
|
15
|
+
/** Generic problem types a trained model can have. */
|
|
16
|
+
export type ModelProblemType = 'classification' | 'regression';
|
|
17
|
+
/** One normalized feature-importance driver for display. */
|
|
18
|
+
export interface PredictionDriver {
|
|
19
|
+
/** Raw feature name as the model stored it. */
|
|
20
|
+
name: string;
|
|
21
|
+
/** Importance magnitude (absolute value of the raw contribution). */
|
|
22
|
+
importance: number;
|
|
23
|
+
/** Importance as a 0–100 share of the strongest driver, for the bar width. */
|
|
24
|
+
relativePct: number;
|
|
25
|
+
}
|
|
26
|
+
/** How a prediction's primary value should be rendered. */
|
|
27
|
+
export type PredictionValueKind = 'probability' | 'numeric' | 'class';
|
|
28
|
+
/** Maximum number of feature-importance drivers shown per card. */
|
|
29
|
+
export declare const MAX_DRIVERS = 5;
|
|
30
|
+
/**
|
|
31
|
+
* Coerce a dynamic field value into a finite number, or null when it isn't one.
|
|
32
|
+
*/
|
|
33
|
+
export declare function toNumber(value: unknown): number | null;
|
|
34
|
+
/**
|
|
35
|
+
* Decide how to render a value given the model's problem type and the value.
|
|
36
|
+
* - regression + numeric → 'numeric'
|
|
37
|
+
* - classification + value in [0,1] → 'probability' (a confidence/score we can gauge)
|
|
38
|
+
* - everything else (a class label, a missing value) → 'class'
|
|
39
|
+
*/
|
|
40
|
+
export declare function valueKind(problemType: ModelProblemType, numeric: number | null): PredictionValueKind;
|
|
41
|
+
/**
|
|
42
|
+
* Neutral tercile for a 0–1 value. Position on the value axis only — no
|
|
43
|
+
* assumption that high is good or bad. Values are clamped to [0,1].
|
|
44
|
+
*/
|
|
45
|
+
export declare function bandFor(value: number): PredictionBand;
|
|
46
|
+
/** Round a 0–1 probability to an integer 0–100 gauge fill, clamped. */
|
|
47
|
+
export declare function gaugePct(value: number): number;
|
|
48
|
+
/**
|
|
49
|
+
* Format the primary value for display:
|
|
50
|
+
* - probability → "72%"
|
|
51
|
+
* - numeric (regression) → grouped number, up to 4 decimals
|
|
52
|
+
* - class label → the label string
|
|
53
|
+
* - missing/empty → "—" (em dash)
|
|
54
|
+
*/
|
|
55
|
+
export declare function formatValue(rawValue: unknown, numeric: number | null, kind: PredictionValueKind): string;
|
|
56
|
+
/**
|
|
57
|
+
* Pick the human label for a prediction: prefer the model's target variable,
|
|
58
|
+
* then the bound column name, then a generic fallback.
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolveLabel(targetVariable: string | null, targetColumn: string | null): string;
|
|
61
|
+
/**
|
|
62
|
+
* Parse a model's `FeatureImportance` JSON (`Record<string, number>`) into the
|
|
63
|
+
* top-N sorted drivers with relative bar widths. Returns [] on null / invalid /
|
|
64
|
+
* empty input — the caller omits the drivers section cleanly when empty.
|
|
65
|
+
*/
|
|
66
|
+
export declare function parseDrivers(featureImportanceJson: string | null): PredictionDriver[];
|
|
67
|
+
/** Format a last-scored timestamp to a short date, or null when absent/invalid. */
|
|
68
|
+
export declare function formatLastScored(lastScoredAt: Date | string | null): string | null;
|
|
69
|
+
//# sourceMappingURL=model-prediction.logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-prediction.logic.d.ts","sourceRoot":"","sources":["../../../../src/lib/panels/model-predictions/model-prediction.logic.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD,sDAAsD;AACtD,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAE/D,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB;IAC7B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,2DAA2D;AAC3D,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtE,mEAAmE;AACnE,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAStD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,mBAAmB,CASpG;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAKrD;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAWxG;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAM/F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB,EAAE,CAwBrF;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CASlF"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, framework-free logic for the entity-agnostic Model Predictions panel.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the Angular component so the band computation, value
|
|
5
|
+
* formatting, and feature-importance parsing can be unit-tested without
|
|
6
|
+
* standing up Angular or a real entity record. NONE of this is entity-specific
|
|
7
|
+
* or domain-specific — it operates purely on numbers, strings, and the model's
|
|
8
|
+
* generic `ProblemType` / `FeatureImportance` JSON.
|
|
9
|
+
*/
|
|
10
|
+
/** Maximum number of feature-importance drivers shown per card. */
|
|
11
|
+
export const MAX_DRIVERS = 5;
|
|
12
|
+
/**
|
|
13
|
+
* Coerce a dynamic field value into a finite number, or null when it isn't one.
|
|
14
|
+
*/
|
|
15
|
+
export function toNumber(value) {
|
|
16
|
+
if (typeof value === 'number') {
|
|
17
|
+
return Number.isFinite(value) ? value : null;
|
|
18
|
+
}
|
|
19
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
20
|
+
const n = Number(value);
|
|
21
|
+
return Number.isFinite(n) ? n : null;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Decide how to render a value given the model's problem type and the value.
|
|
27
|
+
* - regression + numeric → 'numeric'
|
|
28
|
+
* - classification + value in [0,1] → 'probability' (a confidence/score we can gauge)
|
|
29
|
+
* - everything else (a class label, a missing value) → 'class'
|
|
30
|
+
*/
|
|
31
|
+
export function valueKind(problemType, numeric) {
|
|
32
|
+
const isRegression = problemType === 'regression';
|
|
33
|
+
if (isRegression && numeric != null) {
|
|
34
|
+
return 'numeric';
|
|
35
|
+
}
|
|
36
|
+
if (!isRegression && numeric != null && numeric >= 0 && numeric <= 1) {
|
|
37
|
+
return 'probability';
|
|
38
|
+
}
|
|
39
|
+
return 'class';
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Neutral tercile for a 0–1 value. Position on the value axis only — no
|
|
43
|
+
* assumption that high is good or bad. Values are clamped to [0,1].
|
|
44
|
+
*/
|
|
45
|
+
export function bandFor(value) {
|
|
46
|
+
const v = Math.max(0, Math.min(1, value));
|
|
47
|
+
if (v < 1 / 3)
|
|
48
|
+
return 'low';
|
|
49
|
+
if (v < 2 / 3)
|
|
50
|
+
return 'mid';
|
|
51
|
+
return 'high';
|
|
52
|
+
}
|
|
53
|
+
/** Round a 0–1 probability to an integer 0–100 gauge fill, clamped. */
|
|
54
|
+
export function gaugePct(value) {
|
|
55
|
+
return Math.round(Math.max(0, Math.min(1, value)) * 100);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Format the primary value for display:
|
|
59
|
+
* - probability → "72%"
|
|
60
|
+
* - numeric (regression) → grouped number, up to 4 decimals
|
|
61
|
+
* - class label → the label string
|
|
62
|
+
* - missing/empty → "—" (em dash)
|
|
63
|
+
*/
|
|
64
|
+
export function formatValue(rawValue, numeric, kind) {
|
|
65
|
+
if (kind === 'probability' && numeric != null) {
|
|
66
|
+
return `${gaugePct(numeric)}%`;
|
|
67
|
+
}
|
|
68
|
+
if (kind === 'numeric' && numeric != null) {
|
|
69
|
+
return numeric.toLocaleString(undefined, { maximumFractionDigits: 4 });
|
|
70
|
+
}
|
|
71
|
+
if (rawValue == null || rawValue === '') {
|
|
72
|
+
return '—';
|
|
73
|
+
}
|
|
74
|
+
return String(rawValue);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Pick the human label for a prediction: prefer the model's target variable,
|
|
78
|
+
* then the bound column name, then a generic fallback.
|
|
79
|
+
*/
|
|
80
|
+
export function resolveLabel(targetVariable, targetColumn) {
|
|
81
|
+
const target = targetVariable?.trim();
|
|
82
|
+
if (target)
|
|
83
|
+
return target;
|
|
84
|
+
const col = targetColumn?.trim();
|
|
85
|
+
if (col)
|
|
86
|
+
return col;
|
|
87
|
+
return 'Prediction';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse a model's `FeatureImportance` JSON (`Record<string, number>`) into the
|
|
91
|
+
* top-N sorted drivers with relative bar widths. Returns [] on null / invalid /
|
|
92
|
+
* empty input — the caller omits the drivers section cleanly when empty.
|
|
93
|
+
*/
|
|
94
|
+
export function parseDrivers(featureImportanceJson) {
|
|
95
|
+
if (!featureImportanceJson) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
let parsed;
|
|
99
|
+
try {
|
|
100
|
+
parsed = JSON.parse(featureImportanceJson);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
const entries = Object.entries(parsed)
|
|
109
|
+
.map(([name, raw]) => ({ name, importance: Math.abs(toNumber(raw) ?? 0) }))
|
|
110
|
+
.filter(d => d.importance > 0)
|
|
111
|
+
.sort((a, b) => b.importance - a.importance)
|
|
112
|
+
.slice(0, MAX_DRIVERS);
|
|
113
|
+
const max = entries.length > 0 ? entries[0].importance : 0;
|
|
114
|
+
return entries.map(d => ({
|
|
115
|
+
...d,
|
|
116
|
+
relativePct: max > 0 ? Math.round((d.importance / max) * 100) : 0,
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
/** Format a last-scored timestamp to a short date, or null when absent/invalid. */
|
|
120
|
+
export function formatLastScored(lastScoredAt) {
|
|
121
|
+
if (!lastScoredAt) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const d = lastScoredAt instanceof Date ? lastScoredAt : new Date(lastScoredAt);
|
|
125
|
+
if (isNaN(d.getTime())) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
return d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=model-prediction.logic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-prediction.logic.js","sourceRoot":"","sources":["../../../../src/lib/panels/model-predictions/model-prediction.logic.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, framework-free logic for the entity-agnostic Model Predictions panel.\n *\n * Extracted from the Angular component so the band computation, value\n * formatting, and feature-importance parsing can be unit-tested without\n * standing up Angular or a real entity record. NONE of this is entity-specific\n * or domain-specific — it operates purely on numbers, strings, and the model's\n * generic `ProblemType` / `FeatureImportance` JSON.\n */\n\n/**\n * The neutral tercile a numeric prediction falls into. No moral direction is\n * implied — `low`/`mid`/`high` describe position on the value axis only.\n */\nexport type PredictionBand = 'low' | 'mid' | 'high';\n\n/** Generic problem types a trained model can have. */\nexport type ModelProblemType = 'classification' | 'regression';\n\n/** One normalized feature-importance driver for display. */\nexport interface PredictionDriver {\n /** Raw feature name as the model stored it. */\n name: string;\n /** Importance magnitude (absolute value of the raw contribution). */\n importance: number;\n /** Importance as a 0–100 share of the strongest driver, for the bar width. */\n relativePct: number;\n}\n\n/** How a prediction's primary value should be rendered. */\nexport type PredictionValueKind = 'probability' | 'numeric' | 'class';\n\n/** Maximum number of feature-importance drivers shown per card. */\nexport const MAX_DRIVERS = 5;\n\n/**\n * Coerce a dynamic field value into a finite number, or null when it isn't one.\n */\nexport function toNumber(value: unknown): number | null {\n if (typeof value === 'number') {\n return Number.isFinite(value) ? value : null;\n }\n if (typeof value === 'string' && value.trim() !== '') {\n const n = Number(value);\n return Number.isFinite(n) ? n : null;\n }\n return null;\n}\n\n/**\n * Decide how to render a value given the model's problem type and the value.\n * - regression + numeric → 'numeric'\n * - classification + value in [0,1] → 'probability' (a confidence/score we can gauge)\n * - everything else (a class label, a missing value) → 'class'\n */\nexport function valueKind(problemType: ModelProblemType, numeric: number | null): PredictionValueKind {\n const isRegression = problemType === 'regression';\n if (isRegression && numeric != null) {\n return 'numeric';\n }\n if (!isRegression && numeric != null && numeric >= 0 && numeric <= 1) {\n return 'probability';\n }\n return 'class';\n}\n\n/**\n * Neutral tercile for a 0–1 value. Position on the value axis only — no\n * assumption that high is good or bad. Values are clamped to [0,1].\n */\nexport function bandFor(value: number): PredictionBand {\n const v = Math.max(0, Math.min(1, value));\n if (v < 1 / 3) return 'low';\n if (v < 2 / 3) return 'mid';\n return 'high';\n}\n\n/** Round a 0–1 probability to an integer 0–100 gauge fill, clamped. */\nexport function gaugePct(value: number): number {\n return Math.round(Math.max(0, Math.min(1, value)) * 100);\n}\n\n/**\n * Format the primary value for display:\n * - probability → \"72%\"\n * - numeric (regression) → grouped number, up to 4 decimals\n * - class label → the label string\n * - missing/empty → \"—\" (em dash)\n */\nexport function formatValue(rawValue: unknown, numeric: number | null, kind: PredictionValueKind): string {\n if (kind === 'probability' && numeric != null) {\n return `${gaugePct(numeric)}%`;\n }\n if (kind === 'numeric' && numeric != null) {\n return numeric.toLocaleString(undefined, { maximumFractionDigits: 4 });\n }\n if (rawValue == null || rawValue === '') {\n return '—';\n }\n return String(rawValue);\n}\n\n/**\n * Pick the human label for a prediction: prefer the model's target variable,\n * then the bound column name, then a generic fallback.\n */\nexport function resolveLabel(targetVariable: string | null, targetColumn: string | null): string {\n const target = targetVariable?.trim();\n if (target) return target;\n const col = targetColumn?.trim();\n if (col) return col;\n return 'Prediction';\n}\n\n/**\n * Parse a model's `FeatureImportance` JSON (`Record<string, number>`) into the\n * top-N sorted drivers with relative bar widths. Returns [] on null / invalid /\n * empty input — the caller omits the drivers section cleanly when empty.\n */\nexport function parseDrivers(featureImportanceJson: string | null): PredictionDriver[] {\n if (!featureImportanceJson) {\n return [];\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(featureImportanceJson);\n } catch {\n return [];\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return [];\n }\n const entries = Object.entries(parsed as Record<string, unknown>)\n .map(([name, raw]) => ({ name, importance: Math.abs(toNumber(raw) ?? 0) }))\n .filter(d => d.importance > 0)\n .sort((a, b) => b.importance - a.importance)\n .slice(0, MAX_DRIVERS);\n\n const max = entries.length > 0 ? entries[0].importance : 0;\n return entries.map(d => ({\n ...d,\n relativePct: max > 0 ? Math.round((d.importance / max) * 100) : 0,\n }));\n}\n\n/** Format a last-scored timestamp to a short date, or null when absent/invalid. */\nexport function formatLastScored(lastScoredAt: Date | string | null): string | null {\n if (!lastScoredAt) {\n return null;\n }\n const d = lastScoredAt instanceof Date ? lastScoredAt : new Date(lastScoredAt);\n if (isNaN(d.getTime())) {\n return null;\n }\n return d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { OnInit } from '@angular/core';
|
|
2
|
+
import { BaseFormPanel } from '@memberjunction/ng-base-forms';
|
|
3
|
+
import { PredictionBand, PredictionDriver } from './model-prediction.logic';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* A fully-resolved, entity-agnostic prediction card view-model. One per active
|
|
7
|
+
* scoring binding on the current record's entity.
|
|
8
|
+
*/
|
|
9
|
+
export interface PredictionCard {
|
|
10
|
+
/** Binding ID — used as the @for track key. */
|
|
11
|
+
bindingId: string;
|
|
12
|
+
/** Human label for the prediction (model target → bound column → fallback). */
|
|
13
|
+
label: string;
|
|
14
|
+
/** True when the model is a 0–1 probability we can render as a gauge. */
|
|
15
|
+
isProbability: boolean;
|
|
16
|
+
/** True for regression models showing a raw numeric value. */
|
|
17
|
+
isNumeric: boolean;
|
|
18
|
+
/** True for classification models showing a class label. */
|
|
19
|
+
isClass: boolean;
|
|
20
|
+
/** Pre-formatted primary value string ("72%", "1,240.5", "Renewing", "—"). */
|
|
21
|
+
displayValue: string;
|
|
22
|
+
/** 0–100 fill for the probability gauge (only meaningful when isProbability). */
|
|
23
|
+
gaugePct: number;
|
|
24
|
+
/** Neutral band for the gauge segment styling (only meaningful when isProbability). */
|
|
25
|
+
band: PredictionBand | null;
|
|
26
|
+
/** Top feature-importance drivers, or empty when unavailable. */
|
|
27
|
+
drivers: PredictionDriver[];
|
|
28
|
+
/** Provenance: "Pipeline Name v3". */
|
|
29
|
+
provenance: string;
|
|
30
|
+
/** "Last scored" timestamp string, or null when unavailable. */
|
|
31
|
+
lastScored: string | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Model Prediction panel — an **entity-agnostic** form panel that surfaces any
|
|
35
|
+
* predictions a trained ML model has written onto the current record via a
|
|
36
|
+
* `MJ: ML Model Scoring Bindings` row.
|
|
37
|
+
*
|
|
38
|
+
* It registers against the `'*'` wildcard entity, so it mounts on EVERY entity
|
|
39
|
+
* form — but renders **nothing** unless the record's entity has at least one
|
|
40
|
+
* active scoring binding. The 99% of forms with no model see an invisible,
|
|
41
|
+
* one-RunView-cheap panel.
|
|
42
|
+
*
|
|
43
|
+
* Driven entirely by metadata (bindings + models); there is no entity-specific,
|
|
44
|
+
* domain-specific, or "renewal/risk"-specific logic anywhere. Members/renewal
|
|
45
|
+
* is only ever a test example.
|
|
46
|
+
*
|
|
47
|
+
* Self-mounts via the `after-fields` slot. Reusable as a plain component too
|
|
48
|
+
* (composition) by binding `[Record]` + `[FormComponent]`.
|
|
49
|
+
*/
|
|
50
|
+
export declare class ModelPredictionPanel extends BaseFormPanel implements OnInit {
|
|
51
|
+
/** The resolved cards to render. Empty → panel renders nothing. */
|
|
52
|
+
Cards: PredictionCard[];
|
|
53
|
+
/** True once the binding lookup has completed (success or empty). */
|
|
54
|
+
Loaded: boolean;
|
|
55
|
+
/** Entity-ID we last loaded cards for, to avoid redundant lookups. */
|
|
56
|
+
private loadedForEntityId;
|
|
57
|
+
ngOnInit(): Promise<void>;
|
|
58
|
+
/** True when there is at least one card to show — gates the whole template. */
|
|
59
|
+
get HasPredictions(): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Look up active scoring bindings for THIS record's entity and build a card
|
|
62
|
+
* per binding. Idempotent + cheap: a single RunView (cached by the server),
|
|
63
|
+
* skipped entirely when we've already loaded for this entity.
|
|
64
|
+
*/
|
|
65
|
+
private loadCards;
|
|
66
|
+
/** Active scoring bindings whose target entity is the current record's entity. */
|
|
67
|
+
private loadBindingsForEntity;
|
|
68
|
+
/** Load the distinct models referenced by the bindings, keyed by model ID. */
|
|
69
|
+
private loadModelsForBindings;
|
|
70
|
+
/** Map each binding (+ its model) to a display card. Skips bindings whose model is missing. */
|
|
71
|
+
private buildCards;
|
|
72
|
+
/** Build one card from a binding + model + the record's bound-column value. */
|
|
73
|
+
private buildCard;
|
|
74
|
+
/** RunView scoped to the form's provider when available (multi-provider safe). */
|
|
75
|
+
private runView;
|
|
76
|
+
/** Context user for server-side scoping — the form provider's current user. */
|
|
77
|
+
private contextUser;
|
|
78
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ModelPredictionPanel, never>;
|
|
79
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ModelPredictionPanel, "mj-model-prediction-panel", never, {}, {}, never, never, false, never>;
|
|
80
|
+
}
|
|
81
|
+
/** Tree-shake guard — call this from the consuming module's loader. */
|
|
82
|
+
export declare function LoadModelPredictionPanel(): void;
|
|
83
|
+
//# sourceMappingURL=model-prediction.panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-prediction.panel.d.ts","sourceRoot":"","sources":["../../../../src/lib/panels/model-predictions/model-prediction.panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG9D,OAAO,EACH,cAAc,EACd,gBAAgB,EASnB,MAAM,0BAA0B,CAAC;;AAElC;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC3B,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,aAAa,EAAE,OAAO,CAAC;IACvB,8DAA8D;IAC9D,SAAS,EAAE,OAAO,CAAC;IACnB,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,YAAY,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5B,iEAAiE;IACjE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAea,oBAAqB,SAAQ,aAAc,YAAW,MAAM;IACrE,mEAAmE;IAC5D,KAAK,EAAE,cAAc,EAAE,CAAM;IACpC,qEAAqE;IAC9D,MAAM,UAAS;IACtB,sEAAsE;IACtE,OAAO,CAAC,iBAAiB,CAAuB;IAEnC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC,+EAA+E;IAC/E,IAAW,cAAc,IAAI,OAAO,CAEnC;IAED;;;;OAIG;YACW,SAAS;IA4BvB,kFAAkF;YACpE,qBAAqB;IAkBnC,8EAA8E;YAChE,qBAAqB;IA4BnC,+FAA+F;IAC/F,OAAO,CAAC,UAAU;IAelB,+EAA+E;IAC/E,OAAO,CAAC,SAAS;IAsBjB,kFAAkF;IAClF,OAAO,CAAC,OAAO;IAKf,+EAA+E;IAC/E,OAAO,CAAC,WAAW;yCAhJV,oBAAoB;2CAApB,oBAAoB;CAmJhC;AAED,uEAAuE;AACvE,wBAAgB,wBAAwB,IAAI,IAAI,CAAuB"}
|