@memberjunction/ng-core-entity-forms 6.2.0-edge.1 → 6.2.0-edge.3
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/lib/custom/AIAgentCategories/ai-agent-category-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-header.panel.js +9 -5
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-header.panel.js.map +1 -1
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-overview.panel.d.ts +4 -0
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-overview.panel.d.ts.map +1 -1
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-overview.panel.js +67 -36
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-overview.panel.js.map +1 -1
- package/dist/lib/custom/AIAgents/agent-form-tabs.d.ts +1 -0
- package/dist/lib/custom/AIAgents/agent-form-tabs.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/agent-form-tabs.js +2 -0
- package/dist/lib/custom/AIAgents/agent-form-tabs.js.map +1 -1
- package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js +529 -521
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +1 -0
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +10 -16
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
- package/dist/lib/custom/AIPrompts/pending-records.d.ts +11 -0
- package/dist/lib/custom/AIPrompts/pending-records.d.ts.map +1 -0
- package/dist/lib/custom/AIPrompts/pending-records.js +21 -0
- package/dist/lib/custom/AIPrompts/pending-records.js.map +1 -0
- package/dist/lib/custom/Companies/company-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/Companies/company-header.panel.js +9 -5
- package/dist/lib/custom/Companies/company-header.panel.js.map +1 -1
- package/dist/lib/custom/Companies/company-overview.panel.d.ts +4 -0
- package/dist/lib/custom/Companies/company-overview.panel.d.ts.map +1 -1
- package/dist/lib/custom/Companies/company-overview.panel.js +68 -37
- package/dist/lib/custom/Companies/company-overview.panel.js.map +1 -1
- package/dist/lib/custom/Conversations/conversation-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/Conversations/conversation-header.panel.js +9 -5
- package/dist/lib/custom/Conversations/conversation-header.panel.js.map +1 -1
- package/dist/lib/custom/Conversations/conversation-overview.panel.d.ts +10 -2
- package/dist/lib/custom/Conversations/conversation-overview.panel.d.ts.map +1 -1
- package/dist/lib/custom/Conversations/conversation-overview.panel.js +138 -76
- package/dist/lib/custom/Conversations/conversation-overview.panel.js.map +1 -1
- package/dist/lib/custom/Employees/employee-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/Employees/employee-header.panel.js +9 -5
- package/dist/lib/custom/Employees/employee-header.panel.js.map +1 -1
- package/dist/lib/custom/Employees/employee-overview.panel.d.ts +4 -0
- package/dist/lib/custom/Employees/employee-overview.panel.d.ts.map +1 -1
- package/dist/lib/custom/Employees/employee-overview.panel.js +68 -37
- package/dist/lib/custom/Employees/employee-overview.panel.js.map +1 -1
- package/dist/lib/custom/Entities/entity-form.component.d.ts +8 -1
- package/dist/lib/custom/Entities/entity-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Entities/entity-form.component.js +241 -147
- package/dist/lib/custom/Entities/entity-form.component.js.map +1 -1
- package/dist/lib/custom/HierarchyPanels/hierarchy-form-panels.d.ts.map +1 -1
- package/dist/lib/custom/HierarchyPanels/hierarchy-form-panels.js +60 -45
- package/dist/lib/custom/HierarchyPanels/hierarchy-form-panels.js.map +1 -1
- package/dist/lib/custom/Lists/list-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Lists/list-form.component.js +1 -0
- package/dist/lib/custom/Lists/list-form.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.js +1 -0
- package/dist/lib/custom/Queries/query-form.component.js.map +1 -1
- package/dist/lib/custom/RecordProcesses/record-process-form.component.d.ts +19 -0
- package/dist/lib/custom/RecordProcesses/record-process-form.component.d.ts.map +1 -1
- package/dist/lib/custom/RecordProcesses/record-process-form.component.js +50 -8
- package/dist/lib/custom/RecordProcesses/record-process-form.component.js.map +1 -1
- package/dist/lib/custom/Rubrics/evaluation-form.component.d.ts +37 -0
- package/dist/lib/custom/Rubrics/evaluation-form.component.d.ts.map +1 -0
- package/dist/lib/custom/Rubrics/evaluation-form.component.js +399 -0
- package/dist/lib/custom/Rubrics/evaluation-form.component.js.map +1 -0
- package/dist/lib/custom/Rubrics/record-forms.component.d.ts +69 -0
- package/dist/lib/custom/Rubrics/record-forms.component.d.ts.map +1 -0
- package/dist/lib/custom/Rubrics/record-forms.component.js +587 -0
- package/dist/lib/custom/Rubrics/record-forms.component.js.map +1 -0
- package/dist/lib/custom/Rubrics/rubric-form.component.d.ts +67 -0
- package/dist/lib/custom/Rubrics/rubric-form.component.d.ts.map +1 -0
- package/dist/lib/custom/Rubrics/rubric-form.component.js +534 -0
- package/dist/lib/custom/Rubrics/rubric-form.component.js.map +1 -0
- package/dist/lib/custom/Rubrics/rubric-form.panels.d.ts +25 -0
- package/dist/lib/custom/Rubrics/rubric-form.panels.d.ts.map +1 -0
- package/dist/lib/custom/Rubrics/rubric-form.panels.js +299 -0
- package/dist/lib/custom/Rubrics/rubric-form.panels.js.map +1 -0
- package/dist/lib/custom/Rubrics/scale-form.component.d.ts +31 -0
- package/dist/lib/custom/Rubrics/scale-form.component.d.ts.map +1 -0
- package/dist/lib/custom/Rubrics/scale-form.component.js +395 -0
- package/dist/lib/custom/Rubrics/scale-form.component.js.map +1 -0
- package/dist/lib/custom/SearchScopes/searchscope-form.component.d.ts.map +1 -1
- package/dist/lib/custom/SearchScopes/searchscope-form.component.js +1 -0
- package/dist/lib/custom/SearchScopes/searchscope-form.component.js.map +1 -1
- package/dist/lib/custom/Templates/templates-form.component.d.ts +13 -4
- package/dist/lib/custom/Templates/templates-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Templates/templates-form.component.js +111 -113
- package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.d.ts +6 -0
- package/dist/lib/custom/Tests/test-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.js +403 -361
- package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.js +1 -0
- package/dist/lib/custom/Tests/test-run-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts +5 -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 +705 -664
- package/dist/lib/custom/Tests/test-suite-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-suite-run-form.component.js +1 -0
- package/dist/lib/custom/Tests/test-suite-run-form.component.js.map +1 -1
- package/dist/lib/custom/Users/user-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/Users/user-header.panel.js +9 -5
- package/dist/lib/custom/Users/user-header.panel.js.map +1 -1
- package/dist/lib/custom/Users/user-overview.panel.d.ts +4 -0
- package/dist/lib/custom/Users/user-overview.panel.d.ts.map +1 -1
- package/dist/lib/custom/Users/user-overview.panel.js +65 -34
- package/dist/lib/custom/Users/user-overview.panel.js.map +1 -1
- 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 +1 -0
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
- package/dist/lib/custom/custom-forms.module.d.ts +56 -48
- package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
- package/dist/lib/custom/custom-forms.module.js +60 -0
- package/dist/lib/custom/custom-forms.module.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 +115 -43
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentArtifactType/mjaiagentartifacttype.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentArtifactType/mjaiagentartifacttype.form.component.js +5 -9
- package/dist/lib/generated/Entities/MJAIAgentArtifactType/mjaiagentartifacttype.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentNoteType/mjaiagentnotetype.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentNoteType/mjaiagentnotetype.form.component.js +15 -18
- package/dist/lib/generated/Entities/MJAIAgentNoteType/mjaiagentnotetype.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentPrompt/mjaiagentprompt.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentPrompt/mjaiagentprompt.form.component.js +5 -9
- package/dist/lib/generated/Entities/MJAIAgentPrompt/mjaiagentprompt.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRubric/mjaiagentrubric.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJAIAgentRubric/mjaiagentrubric.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJAIAgentRubric/mjaiagentrubric.form.component.js +74 -0
- package/dist/lib/generated/Entities/MJAIAgentRubric/mjaiagentrubric.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js +37 -19
- 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 +27 -9
- package/dist/lib/generated/Entities/MJAIAgentSession/mjaiagentsession.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentSessionBridge/mjaiagentsessionbridge.form.component.js +17 -15
- package/dist/lib/generated/Entities/MJAIAgentSessionBridge/mjaiagentsessionbridge.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIBridgeProvider/mjaibridgeprovider.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIBridgeProvider/mjaibridgeprovider.form.component.js +25 -7
- package/dist/lib/generated/Entities/MJAIBridgeProvider/mjaibridgeprovider.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 +31 -13
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIResultCache/mjairesultcache.form.component.js +12 -14
- package/dist/lib/generated/Entities/MJAIResultCache/mjairesultcache.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCommunicationLog/mjcommunicationlog.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJCommunicationLog/mjcommunicationlog.form.component.js +5 -9
- package/dist/lib/generated/Entities/MJCommunicationLog/mjcommunicationlog.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCompanyIntegrationRunAPILog/mjcompanyintegrationrunapilog.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJCompanyIntegrationRunAPILog/mjcompanyintegrationrunapilog.form.component.js +5 -9
- package/dist/lib/generated/Entities/MJCompanyIntegrationRunAPILog/mjcompanyintegrationrunapilog.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJComponent/mjcomponent.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJComponent/mjcomponent.form.component.js +26 -8
- package/dist/lib/generated/Entities/MJComponent/mjcomponent.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJContentItemAttribute/mjcontentitemattribute.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJContentItemAttribute/mjcontentitemattribute.form.component.js +4 -7
- package/dist/lib/generated/Entities/MJContentItemAttribute/mjcontentitemattribute.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJContentSourceParam/mjcontentsourceparam.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJContentSourceParam/mjcontentsourceparam.form.component.js +4 -7
- package/dist/lib/generated/Entities/MJContentSourceParam/mjcontentsourceparam.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 +31 -13
- package/dist/lib/generated/Entities/MJConversation/mjconversation.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversationArtifactPermission/mjconversationartifactpermission.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJConversationArtifactPermission/mjconversationartifactpermission.form.component.js +5 -9
- package/dist/lib/generated/Entities/MJConversationArtifactPermission/mjconversationartifactpermission.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.js +34 -16
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEmployeeRole/mjemployeerole.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEmployeeRole/mjemployeerole.form.component.js +5 -9
- package/dist/lib/generated/Entities/MJEmployeeRole/mjemployeerole.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 +210 -84
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityCommunicationField/mjentitycommunicationfield.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEntityCommunicationField/mjentitycommunicationfield.form.component.js +8 -11
- package/dist/lib/generated/Entities/MJEntityCommunicationField/mjentitycommunicationfield.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityDocumentType/mjentitydocumenttype.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEntityDocumentType/mjentitydocumenttype.form.component.js +15 -18
- package/dist/lib/generated/Entities/MJEntityDocumentType/mjentitydocumenttype.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityFormContribution/mjentityformcontribution.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJEntityFormContribution/mjentityformcontribution.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJEntityFormContribution/mjentityformcontribution.form.component.js +148 -0
- package/dist/lib/generated/Entities/MJEntityFormContribution/mjentityformcontribution.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJEnvironment/mjenvironment.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEnvironment/mjenvironment.form.component.js +53 -56
- package/dist/lib/generated/Entities/MJEnvironment/mjenvironment.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJFeaturePipelineType/mjfeaturepipelinetype.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJFeaturePipelineType/mjfeaturepipelinetype.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJFeaturePipelineType/mjfeaturepipelinetype.form.component.js +62 -0
- package/dist/lib/generated/Entities/MJFeaturePipelineType/mjfeaturepipelinetype.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJInteraction/mjinteraction.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJInteraction/mjinteraction.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJInteraction/mjinteraction.form.component.js +161 -0
- package/dist/lib/generated/Entities/MJInteraction/mjinteraction.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJInteractionEvent/mjinteractionevent.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJInteractionEvent/mjinteractionevent.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJInteractionEvent/mjinteractionevent.form.component.js +78 -0
- package/dist/lib/generated/Entities/MJInteractionEvent/mjinteractionevent.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJInteractionLink/mjinteractionlink.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJInteractionLink/mjinteractionlink.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJInteractionLink/mjinteractionlink.form.component.js +68 -0
- package/dist/lib/generated/Entities/MJInteractionLink/mjinteractionlink.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJInteractionOffer/mjinteractionoffer.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJInteractionOffer/mjinteractionoffer.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJInteractionOffer/mjinteractionoffer.form.component.js +100 -0
- package/dist/lib/generated/Entities/MJInteractionOffer/mjinteractionoffer.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMeeting/mjmeeting.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMeeting/mjmeeting.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMeeting/mjmeeting.form.component.js +119 -0
- package/dist/lib/generated/Entities/MJMeeting/mjmeeting.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMeetingParticipant/mjmeetingparticipant.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMeetingParticipant/mjmeetingparticipant.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMeetingParticipant/mjmeetingparticipant.form.component.js +92 -0
- package/dist/lib/generated/Entities/MJMeetingParticipant/mjmeetingparticipant.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJNumberPool/mjnumberpool.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJNumberPool/mjnumberpool.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJNumberPool/mjnumberpool.form.component.js +87 -0
- package/dist/lib/generated/Entities/MJNumberPool/mjnumberpool.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJPhoneNumber/mjphonenumber.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJPhoneNumber/mjphonenumber.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJPhoneNumber/mjphonenumber.form.component.js +129 -0
- package/dist/lib/generated/Entities/MJPhoneNumber/mjphonenumber.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.js +24 -6
- package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJQueryPermission/mjquerypermission.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJQueryPermission/mjquerypermission.form.component.js +5 -9
- package/dist/lib/generated/Entities/MJQueryPermission/mjquerypermission.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRecommendationItem/mjrecommendationitem.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJRecommendationItem/mjrecommendationitem.form.component.js +8 -11
- package/dist/lib/generated/Entities/MJRecommendationItem/mjrecommendationitem.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRecordChange/mjrecordchange.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJRecordChange/mjrecordchange.form.component.js +24 -16
- package/dist/lib/generated/Entities/MJRecordChange/mjrecordchange.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRecordCloneLog/mjrecordclonelog.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRecordCloneLog/mjrecordclonelog.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRecordCloneLog/mjrecordclonelog.form.component.js +107 -0
- package/dist/lib/generated/Entities/MJRecordCloneLog/mjrecordclonelog.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRecordCloneLogItem/mjrecordclonelogitem.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRecordCloneLogItem/mjrecordclonelogitem.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRecordCloneLogItem/mjrecordclonelogitem.form.component.js +74 -0
- package/dist/lib/generated/Entities/MJRecordCloneLogItem/mjrecordclonelogitem.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJResourceType/mjresourcetype.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJResourceType/mjresourcetype.form.component.js +36 -40
- package/dist/lib/generated/Entities/MJResourceType/mjresourcetype.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 +39 -21
- package/dist/lib/generated/Entities/MJRole/mjrole.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRowLevelSecurityFilter/mjrowlevelsecurityfilter.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJRowLevelSecurityFilter/mjrowlevelsecurityfilter.form.component.js +45 -48
- package/dist/lib/generated/Entities/MJRowLevelSecurityFilter/mjrowlevelsecurityfilter.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRubric/mjrubric.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubric/mjrubric.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubric/mjrubric.form.component.js +135 -0
- package/dist/lib/generated/Entities/MJRubric/mjrubric.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricBand/mjrubricband.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricBand/mjrubricband.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricBand/mjrubricband.form.component.js +87 -0
- package/dist/lib/generated/Entities/MJRubricBand/mjrubricband.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricCategory/mjrubriccategory.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricCategory/mjrubriccategory.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricCategory/mjrubriccategory.form.component.js +107 -0
- package/dist/lib/generated/Entities/MJRubricCategory/mjrubriccategory.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricCriterion/mjrubriccriterion.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricCriterion/mjrubriccriterion.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricCriterion/mjrubriccriterion.form.component.js +155 -0
- package/dist/lib/generated/Entities/MJRubricCriterion/mjrubriccriterion.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricCriterionLevel/mjrubriccriterionlevel.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricCriterionLevel/mjrubriccriterionlevel.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricCriterionLevel/mjrubriccriterionlevel.form.component.js +62 -0
- package/dist/lib/generated/Entities/MJRubricCriterionLevel/mjrubriccriterionlevel.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricEvaluation/mjrubricevaluation.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricEvaluation/mjrubricevaluation.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricEvaluation/mjrubricevaluation.form.component.js +183 -0
- package/dist/lib/generated/Entities/MJRubricEvaluation/mjrubricevaluation.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricEvaluationScore/mjrubricevaluationscore.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricEvaluationScore/mjrubricevaluationscore.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricEvaluationScore/mjrubricevaluationscore.form.component.js +120 -0
- package/dist/lib/generated/Entities/MJRubricEvaluationScore/mjrubricevaluationscore.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricScale/mjrubricscale.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricScale/mjrubricscale.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricScale/mjrubricscale.form.component.js +107 -0
- package/dist/lib/generated/Entities/MJRubricScale/mjrubricscale.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricScaleLevel/mjrubricscalelevel.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricScaleLevel/mjrubricscalelevel.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricScaleLevel/mjrubricscalelevel.form.component.js +103 -0
- package/dist/lib/generated/Entities/MJRubricScaleLevel/mjrubricscalelevel.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJRubricVersion/mjrubricversion.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJRubricVersion/mjrubricversion.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJRubricVersion/mjrubricversion.form.component.js +171 -0
- package/dist/lib/generated/Entities/MJRubricVersion/mjrubricversion.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJTemplateContentType/mjtemplatecontenttype.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJTemplateContentType/mjtemplatecontenttype.form.component.js +15 -18
- package/dist/lib/generated/Entities/MJTemplateContentType/mjtemplatecontenttype.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTest/mjtest.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJTest/mjtest.form.component.js +24 -16
- package/dist/lib/generated/Entities/MJTest/mjtest.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTestSuite/mjtestsuite.form.component.js +27 -25
- package/dist/lib/generated/Entities/MJTestSuite/mjtestsuite.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTestSuiteRun/mjtestsuiterun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJTestSuiteRun/mjtestsuiterun.form.component.js +19 -11
- package/dist/lib/generated/Entities/MJTestSuiteRun/mjtestsuiterun.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 +299 -119
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJVersionLabelItem/mjversionlabelitem.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJVersionLabelItem/mjversionlabelitem.form.component.js +5 -9
- package/dist/lib/generated/Entities/MJVersionLabelItem/mjversionlabelitem.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJWorkQueueDeduplication/mjworkqueuededuplication.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJWorkQueueDeduplication/mjworkqueuededuplication.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueDeduplication/mjworkqueuededuplication.form.component.js +64 -0
- package/dist/lib/generated/Entities/MJWorkQueueDeduplication/mjworkqueuededuplication.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueDelivery/mjworkqueuedelivery.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJWorkQueueDelivery/mjworkqueuedelivery.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueDelivery/mjworkqueuedelivery.form.component.js +94 -0
- package/dist/lib/generated/Entities/MJWorkQueueDelivery/mjworkqueuedelivery.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueMessage/mjworkqueuemessage.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJWorkQueueMessage/mjworkqueuemessage.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueMessage/mjworkqueuemessage.form.component.js +91 -0
- package/dist/lib/generated/Entities/MJWorkQueueMessage/mjworkqueuemessage.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueSubscription/mjworkqueuesubscription.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJWorkQueueSubscription/mjworkqueuesubscription.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueSubscription/mjworkqueuesubscription.form.component.js +105 -0
- package/dist/lib/generated/Entities/MJWorkQueueSubscription/mjworkqueuesubscription.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueTopic/mjworkqueuetopic.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJWorkQueueTopic/mjworkqueuetopic.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueTopic/mjworkqueuetopic.form.component.js +129 -0
- package/dist/lib/generated/Entities/MJWorkQueueTopic/mjworkqueuetopic.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueTransport/mjworkqueuetransport.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJWorkQueueTransport/mjworkqueuetransport.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJWorkQueueTransport/mjworkqueuetransport.form.component.js +85 -0
- package/dist/lib/generated/Entities/MJWorkQueueTransport/mjworkqueuetransport.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJWorkspace/mjworkspace.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJWorkspace/mjworkspace.form.component.js +17 -20
- package/dist/lib/generated/Entities/MJWorkspace/mjworkspace.form.component.js.map +1 -1
- package/dist/lib/generated/generated-forms.module.d.ts +451 -422
- package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
- package/dist/lib/generated/generated-forms.module.js +101 -14
- package/dist/lib/generated/generated-forms.module.js.map +1 -1
- package/dist/lib/panels/ai-agents/agent-realtime.panel.d.ts +7 -1
- package/dist/lib/panels/ai-agents/agent-realtime.panel.d.ts.map +1 -1
- package/dist/lib/panels/ai-agents/agent-realtime.panel.js +89 -43
- 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.js +3 -3
- package/dist/lib/panels/ai-skill-sharing/ai-skill-sharing-panel.component.js.map +1 -1
- package/dist/lib/panels/content-sources/tag-pipeline-configuration.panel.js +5 -5
- package/dist/lib/panels/content-sources/tag-pipeline-configuration.panel.js.map +1 -1
- package/dist/lib/panels/content-sources/website-crawler-settings.panel.js +4 -4
- package/dist/lib/panels/content-sources/website-crawler-settings.panel.js.map +1 -1
- package/dist/lib/panels/form-chrome/entity-relationship-form-role.panel.js +3 -3
- package/dist/lib/panels/form-chrome/entity-relationship-form-role.panel.js.map +1 -1
- package/dist/lib/panels/model-predictions/model-prediction.panel.js +4 -4
- package/dist/lib/panels/model-predictions/model-prediction.panel.js.map +1 -1
- package/dist/lib/panels/record-clone/entity-clone-config-editor.component.d.ts +116 -0
- package/dist/lib/panels/record-clone/entity-clone-config-editor.component.d.ts.map +1 -0
- package/dist/lib/panels/record-clone/entity-clone-config-editor.component.js +820 -0
- package/dist/lib/panels/record-clone/entity-clone-config-editor.component.js.map +1 -0
- package/dist/lib/shared/components/template-editor.component.d.ts +25 -1
- package/dist/lib/shared/components/template-editor.component.d.ts.map +1 -1
- package/dist/lib/shared/components/template-editor.component.js +67 -3
- package/dist/lib/shared/components/template-editor.component.js.map +1 -1
- package/dist/public-api.d.ts +5 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +5 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +47 -43
|
@@ -14,7 +14,7 @@ import { RegisterClass } from '@memberjunction/global';
|
|
|
14
14
|
import { SharedService, NavigationService } from '@memberjunction/ng-shared';
|
|
15
15
|
import { ApplicationManager } from '@memberjunction/ng-base-application';
|
|
16
16
|
import { MJTestFormComponent } from '../../generated/Entities/MJTest/mjtest.form.component';
|
|
17
|
-
import { TestingDialogService, TagsHelper, EvaluationPreferencesService } from '@memberjunction/ng-testing';
|
|
17
|
+
import { TestingDialogService, TagsHelper, EvaluationPreferencesService, RubricPickerOptions } from '@memberjunction/ng-testing';
|
|
18
18
|
import { createCopyOnlyToolbar } from '@memberjunction/ng-code-editor';
|
|
19
19
|
import { MJConfirmService } from '@memberjunction/ng-ui-components';
|
|
20
20
|
import * as i0 from "@angular/core";
|
|
@@ -27,7 +27,8 @@ import * as i6 from "@memberjunction/ng-shared-generic";
|
|
|
27
27
|
import * as i7 from "./entity-link-pill.component";
|
|
28
28
|
const _c0 = () => [1, 2, 3, 4, 5];
|
|
29
29
|
const _c1 = () => [1, 2, 3];
|
|
30
|
-
const _forTrack0 = ($index, $item) => $item.
|
|
30
|
+
const _forTrack0 = ($index, $item) => $item.id;
|
|
31
|
+
const _forTrack1 = ($index, $item) => $item.ID;
|
|
31
32
|
function MJTestFormComponentExtended_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
32
33
|
i0.ɵɵelementStart(0, "span", 14);
|
|
33
34
|
i0.ɵɵtext(1, "\u25CF");
|
|
@@ -257,30 +258,40 @@ function MJTestFormComponentExtended_Conditional_64_For_25_Template(rf, ctx) { i
|
|
|
257
258
|
i0.ɵɵadvance();
|
|
258
259
|
i0.ɵɵtextInterpolate(opt_r4);
|
|
259
260
|
} }
|
|
260
|
-
function
|
|
261
|
+
function MJTestFormComponentExtended_Conditional_64_For_33_Template(rf, ctx) { if (rf & 1) {
|
|
261
262
|
i0.ɵɵelementStart(0, "option", 93);
|
|
262
263
|
i0.ɵɵtext(1);
|
|
263
264
|
i0.ɵɵelementEnd();
|
|
264
265
|
} if (rf & 2) {
|
|
265
|
-
const
|
|
266
|
-
i0.ɵɵproperty("ngValue",
|
|
266
|
+
const rubric_r5 = ctx.$implicit;
|
|
267
|
+
i0.ɵɵproperty("ngValue", rubric_r5.id);
|
|
267
268
|
i0.ɵɵadvance();
|
|
268
|
-
i0.ɵɵtextInterpolate(
|
|
269
|
+
i0.ɵɵtextInterpolate(rubric_r5.name);
|
|
269
270
|
} }
|
|
270
|
-
function
|
|
271
|
-
|
|
272
|
-
i0.ɵɵ
|
|
271
|
+
function MJTestFormComponentExtended_Conditional_64_For_39_Template(rf, ctx) { if (rf & 1) {
|
|
272
|
+
i0.ɵɵelementStart(0, "option", 93);
|
|
273
|
+
i0.ɵɵtext(1);
|
|
274
|
+
i0.ɵɵelementEnd();
|
|
275
|
+
} if (rf & 2) {
|
|
276
|
+
const t_r6 = ctx.$implicit;
|
|
277
|
+
i0.ɵɵproperty("ngValue", t_r6.ID);
|
|
278
|
+
i0.ɵɵadvance();
|
|
279
|
+
i0.ɵɵtextInterpolate(t_r6.Name);
|
|
280
|
+
} }
|
|
281
|
+
function MJTestFormComponentExtended_Conditional_64_For_45_Template(rf, ctx) { if (rf & 1) {
|
|
282
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
283
|
+
i0.ɵɵelementStart(0, "span", 100);
|
|
273
284
|
i0.ɵɵtext(1);
|
|
274
|
-
i0.ɵɵelementStart(2, "button",
|
|
275
|
-
i0.ɵɵlistener("click", function
|
|
276
|
-
i0.ɵɵelement(3, "i",
|
|
285
|
+
i0.ɵɵelementStart(2, "button", 123);
|
|
286
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_For_45_Template_button_click_2_listener($event) { const tag_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); ctx_r0.removeTag(tag_r9); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
287
|
+
i0.ɵɵelement(3, "i", 124);
|
|
277
288
|
i0.ɵɵelementEnd()();
|
|
278
289
|
} if (rf & 2) {
|
|
279
|
-
const
|
|
290
|
+
const tag_r9 = ctx.$implicit;
|
|
280
291
|
i0.ɵɵadvance();
|
|
281
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
292
|
+
i0.ɵɵtextInterpolate1(" ", tag_r9, " ");
|
|
282
293
|
i0.ɵɵadvance();
|
|
283
|
-
i0.ɵɵattribute("aria-label", "Remove tag " +
|
|
294
|
+
i0.ɵɵattribute("aria-label", "Remove tag " + tag_r9);
|
|
284
295
|
} }
|
|
285
296
|
function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf & 1) {
|
|
286
297
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
@@ -313,108 +324,118 @@ function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf &
|
|
|
313
324
|
i0.ɵɵrepeaterCreate(24, MJTestFormComponentExtended_Conditional_64_For_25_Template, 2, 2, "option", 93, i0.ɵɵrepeaterTrackByIdentity);
|
|
314
325
|
i0.ɵɵelementEnd()()();
|
|
315
326
|
i0.ɵɵelementStart(26, "div", 89)(27, "label", 94);
|
|
316
|
-
i0.ɵɵtext(28, "
|
|
327
|
+
i0.ɵɵtext(28, "Rubric");
|
|
317
328
|
i0.ɵɵelementEnd();
|
|
318
329
|
i0.ɵɵelementStart(29, "select", 95);
|
|
319
|
-
i0.ɵɵ
|
|
320
|
-
i0.ɵɵ
|
|
330
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_select_ngModelChange_29_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.RubricID = $event || null); });
|
|
331
|
+
i0.ɵɵelementStart(30, "option", 93);
|
|
332
|
+
i0.ɵɵtext(31, "\u2014 None \u2014");
|
|
333
|
+
i0.ɵɵelementEnd();
|
|
334
|
+
i0.ɵɵrepeaterCreate(32, MJTestFormComponentExtended_Conditional_64_For_33_Template, 2, 2, "option", 93, _forTrack0);
|
|
321
335
|
i0.ɵɵelementEnd()();
|
|
322
|
-
i0.ɵɵelementStart(
|
|
323
|
-
i0.ɵɵtext(
|
|
324
|
-
i0.ɵɵelementEnd();
|
|
325
|
-
i0.ɵɵelementStart(
|
|
326
|
-
i0.ɵɵ
|
|
327
|
-
i0.ɵɵrepeaterCreate(
|
|
328
|
-
i0.ɵɵelementStart(38, "input", 99, 0);
|
|
329
|
-
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_38_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.tagDraft, $event) || (ctx_r0.tagDraft = $event); return i0.ɵɵresetView($event); });
|
|
330
|
-
i0.ɵɵlistener("keydown", function MJTestFormComponentExtended_Conditional_64_Template_input_keydown_38_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onTagInputKeydown($event)); })("blur", function MJTestFormComponentExtended_Conditional_64_Template_input_blur_38_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.addTagFromDraft()); });
|
|
336
|
+
i0.ɵɵelementStart(34, "div", 89)(35, "label", 96);
|
|
337
|
+
i0.ɵɵtext(36, "Test Type");
|
|
338
|
+
i0.ɵɵelementEnd();
|
|
339
|
+
i0.ɵɵelementStart(37, "select", 97);
|
|
340
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_select_ngModelChange_37_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.TypeID, $event) || (ctx_r0.record.TypeID = $event); return i0.ɵɵresetView($event); });
|
|
341
|
+
i0.ɵɵrepeaterCreate(38, MJTestFormComponentExtended_Conditional_64_For_39_Template, 2, 2, "option", 93, _forTrack1);
|
|
331
342
|
i0.ɵɵelementEnd()();
|
|
332
|
-
i0.ɵɵelementStart(40, "
|
|
333
|
-
i0.ɵɵtext(
|
|
343
|
+
i0.ɵɵelementStart(40, "div", 83)(41, "label", 98);
|
|
344
|
+
i0.ɵɵtext(42, "Tags");
|
|
345
|
+
i0.ɵɵelementEnd();
|
|
346
|
+
i0.ɵɵelementStart(43, "div", 99);
|
|
347
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_Template_div_click_43_listener() { i0.ɵɵrestoreView(_r3); const tagInput_r7 = i0.ɵɵreference(47); return i0.ɵɵresetView(tagInput_r7.focus()); });
|
|
348
|
+
i0.ɵɵrepeaterCreate(44, MJTestFormComponentExtended_Conditional_64_For_45_Template, 4, 2, "span", 100, i0.ɵɵrepeaterTrackByIdentity);
|
|
349
|
+
i0.ɵɵelementStart(46, "input", 101, 0);
|
|
350
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_46_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.tagDraft, $event) || (ctx_r0.tagDraft = $event); return i0.ɵɵresetView($event); });
|
|
351
|
+
i0.ɵɵlistener("keydown", function MJTestFormComponentExtended_Conditional_64_Template_input_keydown_46_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onTagInputKeydown($event)); })("blur", function MJTestFormComponentExtended_Conditional_64_Template_input_blur_46_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.addTagFromDraft()); });
|
|
352
|
+
i0.ɵɵelementEnd()();
|
|
353
|
+
i0.ɵɵelementStart(48, "span", 102);
|
|
354
|
+
i0.ɵɵtext(49, "Press Enter or comma to add a tag. Backspace on empty input removes the last tag.");
|
|
334
355
|
i0.ɵɵelementEnd()()()();
|
|
335
|
-
i0.ɵɵelementStart(
|
|
336
|
-
i0.ɵɵelement(
|
|
337
|
-
i0.ɵɵtext(
|
|
356
|
+
i0.ɵɵelementStart(50, "section", 78)(51, "header", 79)(52, "h3");
|
|
357
|
+
i0.ɵɵelement(53, "i", 103);
|
|
358
|
+
i0.ɵɵtext(54, " Execution Settings");
|
|
338
359
|
i0.ɵɵelementEnd()();
|
|
339
|
-
i0.ɵɵelementStart(
|
|
340
|
-
i0.ɵɵtext(
|
|
360
|
+
i0.ɵɵelementStart(55, "div", 82)(56, "div", 89)(57, "label", 104);
|
|
361
|
+
i0.ɵɵtext(58, "Priority");
|
|
341
362
|
i0.ɵɵelementEnd();
|
|
342
|
-
i0.ɵɵelementStart(
|
|
343
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
363
|
+
i0.ɵɵelementStart(59, "input", 105);
|
|
364
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_59_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Priority = $event === "" || $event === null ? null : +$event); });
|
|
344
365
|
i0.ɵɵelementEnd();
|
|
345
|
-
i0.ɵɵelementStart(
|
|
346
|
-
i0.ɵɵtext(
|
|
366
|
+
i0.ɵɵelementStart(60, "span", 102);
|
|
367
|
+
i0.ɵɵtext(61, "Lower numbers run first.");
|
|
347
368
|
i0.ɵɵelementEnd()();
|
|
348
|
-
i0.ɵɵelementStart(
|
|
349
|
-
i0.ɵɵtext(
|
|
369
|
+
i0.ɵɵelementStart(62, "div", 89)(63, "label", 106);
|
|
370
|
+
i0.ɵɵtext(64, "Repeat Count");
|
|
350
371
|
i0.ɵɵelementEnd();
|
|
351
|
-
i0.ɵɵelementStart(
|
|
352
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
372
|
+
i0.ɵɵelementStart(65, "input", 107);
|
|
373
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_65_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.RepeatCount = $event === "" || $event === null ? null : +$event); });
|
|
353
374
|
i0.ɵɵelementEnd();
|
|
354
|
-
i0.ɵɵelementStart(
|
|
355
|
-
i0.ɵɵtext(
|
|
375
|
+
i0.ɵɵelementStart(66, "span", 102);
|
|
376
|
+
i0.ɵɵtext(67, "Number of times to repeat for statistical analysis.");
|
|
356
377
|
i0.ɵɵelementEnd()();
|
|
357
|
-
i0.ɵɵelementStart(
|
|
358
|
-
i0.ɵɵtext(
|
|
378
|
+
i0.ɵɵelementStart(68, "div", 89)(69, "label", 108);
|
|
379
|
+
i0.ɵɵtext(70, "Estimated Duration (seconds)");
|
|
359
380
|
i0.ɵɵelementEnd();
|
|
360
|
-
i0.ɵɵelementStart(
|
|
361
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
381
|
+
i0.ɵɵelementStart(71, "input", 109);
|
|
382
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_71_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.EstimatedDurationSeconds = $event === "" || $event === null ? null : +$event); });
|
|
362
383
|
i0.ɵɵelementEnd()();
|
|
363
|
-
i0.ɵɵelementStart(
|
|
364
|
-
i0.ɵɵtext(
|
|
384
|
+
i0.ɵɵelementStart(72, "div", 89)(73, "label", 110);
|
|
385
|
+
i0.ɵɵtext(74, "Estimated Cost (USD)");
|
|
365
386
|
i0.ɵɵelementEnd();
|
|
366
|
-
i0.ɵɵelementStart(
|
|
367
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
387
|
+
i0.ɵɵelementStart(75, "input", 111);
|
|
388
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_75_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.EstimatedCostUSD = $event === "" || $event === null ? null : +$event); });
|
|
368
389
|
i0.ɵɵelementEnd()();
|
|
369
|
-
i0.ɵɵelementStart(
|
|
370
|
-
i0.ɵɵtext(
|
|
390
|
+
i0.ɵɵelementStart(76, "div", 83)(77, "label", 112);
|
|
391
|
+
i0.ɵɵtext(78, "Max Execution Time (ms)");
|
|
371
392
|
i0.ɵɵelementEnd();
|
|
372
|
-
i0.ɵɵelementStart(
|
|
373
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
393
|
+
i0.ɵɵelementStart(79, "input", 113);
|
|
394
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_79_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.MaxExecutionTimeMS = $event === "" || $event === null ? null : +$event); });
|
|
374
395
|
i0.ɵɵelementEnd();
|
|
375
|
-
i0.ɵɵelementStart(
|
|
376
|
-
i0.ɵɵtext(
|
|
396
|
+
i0.ɵɵelementStart(80, "span", 102);
|
|
397
|
+
i0.ɵɵtext(81);
|
|
377
398
|
i0.ɵɵelementEnd()()()();
|
|
378
|
-
i0.ɵɵelementStart(
|
|
379
|
-
i0.ɵɵelement(
|
|
380
|
-
i0.ɵɵtext(
|
|
399
|
+
i0.ɵɵelementStart(82, "div", 114)(83, "h3");
|
|
400
|
+
i0.ɵɵelement(84, "i", 72);
|
|
401
|
+
i0.ɵɵtext(85, " Input Definition (JSON)");
|
|
381
402
|
i0.ɵɵelementEnd();
|
|
382
|
-
i0.ɵɵelementStart(
|
|
383
|
-
i0.ɵɵlistener("change", function
|
|
403
|
+
i0.ɵɵelementStart(86, "div", 115)(87, "mj-code-editor", 116);
|
|
404
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_87_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.InputDefinition = $event); });
|
|
384
405
|
i0.ɵɵelementEnd()()();
|
|
385
|
-
i0.ɵɵelementStart(
|
|
386
|
-
i0.ɵɵelement(
|
|
387
|
-
i0.ɵɵtext(
|
|
406
|
+
i0.ɵɵelementStart(88, "div", 114)(89, "h3");
|
|
407
|
+
i0.ɵɵelement(90, "i", 73);
|
|
408
|
+
i0.ɵɵtext(91, " Expected Outcomes (JSON)");
|
|
388
409
|
i0.ɵɵelementEnd();
|
|
389
|
-
i0.ɵɵelementStart(
|
|
390
|
-
i0.ɵɵlistener("change", function
|
|
410
|
+
i0.ɵɵelementStart(92, "div", 115)(93, "mj-code-editor", 116);
|
|
411
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_93_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.ExpectedOutcomes = $event); });
|
|
391
412
|
i0.ɵɵelementEnd()()();
|
|
392
|
-
i0.ɵɵelementStart(
|
|
393
|
-
i0.ɵɵelement(
|
|
394
|
-
i0.ɵɵtext(
|
|
413
|
+
i0.ɵɵelementStart(94, "div", 114)(95, "h3");
|
|
414
|
+
i0.ɵɵelement(96, "i", 74);
|
|
415
|
+
i0.ɵɵtext(97, " Configuration (JSON)");
|
|
395
416
|
i0.ɵɵelementEnd();
|
|
396
|
-
i0.ɵɵelementStart(
|
|
397
|
-
i0.ɵɵlistener("change", function
|
|
417
|
+
i0.ɵɵelementStart(98, "div", 115)(99, "mj-code-editor", 116);
|
|
418
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_99_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Configuration = $event); });
|
|
398
419
|
i0.ɵɵelementEnd()()();
|
|
399
|
-
i0.ɵɵelementStart(
|
|
400
|
-
i0.ɵɵtext(
|
|
420
|
+
i0.ɵɵelementStart(100, "section", 117)(101, "div", 118)(102, "div", 119)(103, "div", 120);
|
|
421
|
+
i0.ɵɵtext(104, "Created");
|
|
401
422
|
i0.ɵɵelementEnd();
|
|
402
|
-
i0.ɵɵelementStart(
|
|
403
|
-
i0.ɵɵtext(
|
|
404
|
-
i0.ɵɵpipe(
|
|
423
|
+
i0.ɵɵelementStart(105, "div", 121);
|
|
424
|
+
i0.ɵɵtext(106);
|
|
425
|
+
i0.ɵɵpipe(107, "date");
|
|
405
426
|
i0.ɵɵelementEnd()();
|
|
406
|
-
i0.ɵɵelementStart(
|
|
407
|
-
i0.ɵɵtext(
|
|
427
|
+
i0.ɵɵelementStart(108, "div", 119)(109, "div", 120);
|
|
428
|
+
i0.ɵɵtext(110, "Last updated");
|
|
408
429
|
i0.ɵɵelementEnd();
|
|
409
|
-
i0.ɵɵelementStart(
|
|
410
|
-
i0.ɵɵtext(
|
|
411
|
-
i0.ɵɵpipe(
|
|
430
|
+
i0.ɵɵelementStart(111, "div", 121);
|
|
431
|
+
i0.ɵɵtext(112);
|
|
432
|
+
i0.ɵɵpipe(113, "date");
|
|
412
433
|
i0.ɵɵelementEnd()();
|
|
413
|
-
i0.ɵɵelementStart(
|
|
414
|
-
i0.ɵɵtext(
|
|
434
|
+
i0.ɵɵelementStart(114, "div", 119)(115, "div", 120);
|
|
435
|
+
i0.ɵɵtext(116, "Test ID");
|
|
415
436
|
i0.ɵɵelementEnd();
|
|
416
|
-
i0.ɵɵelementStart(
|
|
417
|
-
i0.ɵɵtext(
|
|
437
|
+
i0.ɵɵelementStart(117, "div", 122);
|
|
438
|
+
i0.ɵɵtext(118);
|
|
418
439
|
i0.ɵɵelementEnd()()()()();
|
|
419
440
|
} if (rf & 2) {
|
|
420
441
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -427,6 +448,12 @@ function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf &
|
|
|
427
448
|
i0.ɵɵadvance();
|
|
428
449
|
i0.ɵɵrepeater(ctx_r0.statusOptions);
|
|
429
450
|
i0.ɵɵadvance(5);
|
|
451
|
+
i0.ɵɵproperty("ngModel", ctx_r0.record.RubricID);
|
|
452
|
+
i0.ɵɵadvance();
|
|
453
|
+
i0.ɵɵproperty("ngValue", null);
|
|
454
|
+
i0.ɵɵadvance(2);
|
|
455
|
+
i0.ɵɵrepeater(ctx_r0.RubricOptions);
|
|
456
|
+
i0.ɵɵadvance(5);
|
|
430
457
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.TypeID);
|
|
431
458
|
i0.ɵɵadvance();
|
|
432
459
|
i0.ɵɵrepeater(ctx_r0.testTypeOptions);
|
|
@@ -454,22 +481,22 @@ function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf &
|
|
|
454
481
|
i0.ɵɵadvance(6);
|
|
455
482
|
i0.ɵɵproperty("value", ctx_r0.record.Configuration || "")("readonly", false)("lineWrapping", true);
|
|
456
483
|
i0.ɵɵadvance(7);
|
|
457
|
-
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(
|
|
484
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(107, 26, ctx_r0.record.__mj_CreatedAt, "medium"));
|
|
458
485
|
i0.ɵɵadvance(6);
|
|
459
|
-
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(
|
|
486
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(113, 29, ctx_r0.record.__mj_UpdatedAt, "medium"));
|
|
460
487
|
i0.ɵɵadvance(6);
|
|
461
488
|
i0.ɵɵtextInterpolate(ctx_r0.record.ID);
|
|
462
489
|
} }
|
|
463
490
|
function MJTestFormComponentExtended_Conditional_65_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
464
|
-
i0.ɵɵelementStart(0, "div",
|
|
465
|
-
i0.ɵɵelement(1, "div",
|
|
466
|
-
i0.ɵɵelementStart(2, "div",
|
|
467
|
-
i0.ɵɵelement(3, "div",
|
|
491
|
+
i0.ɵɵelementStart(0, "div", 129);
|
|
492
|
+
i0.ɵɵelement(1, "div", 130);
|
|
493
|
+
i0.ɵɵelementStart(2, "div", 131);
|
|
494
|
+
i0.ɵɵelement(3, "div", 132)(4, "div", 133);
|
|
468
495
|
i0.ɵɵelementEnd()();
|
|
469
496
|
} }
|
|
470
497
|
function MJTestFormComponentExtended_Conditional_65_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
471
|
-
i0.ɵɵelementStart(0, "div",
|
|
472
|
-
i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_1_For_3_Template, 5, 0, "div",
|
|
498
|
+
i0.ɵɵelementStart(0, "div", 125)(1, "div", 128);
|
|
499
|
+
i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_1_For_3_Template, 5, 0, "div", 129, i0.ɵɵrepeaterTrackByIdentity);
|
|
473
500
|
i0.ɵɵelementEnd()();
|
|
474
501
|
} if (rf & 2) {
|
|
475
502
|
i0.ɵɵadvance(2);
|
|
@@ -477,190 +504,190 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_1_Template(rf, c
|
|
|
477
504
|
} }
|
|
478
505
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
479
506
|
i0.ɵɵelementStart(0, "span");
|
|
480
|
-
i0.ɵɵelement(1, "i",
|
|
507
|
+
i0.ɵɵelement(1, "i", 149);
|
|
481
508
|
i0.ɵɵtext(2);
|
|
482
509
|
i0.ɵɵelementEnd();
|
|
483
510
|
} if (rf & 2) {
|
|
484
|
-
const
|
|
511
|
+
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
485
512
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
486
513
|
i0.ɵɵadvance(2);
|
|
487
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatDuration(
|
|
514
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatDuration(run_r11.DurationSeconds));
|
|
488
515
|
} }
|
|
489
516
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
490
517
|
i0.ɵɵelementStart(0, "span");
|
|
491
|
-
i0.ɵɵelement(1, "i",
|
|
518
|
+
i0.ɵɵelement(1, "i", 150);
|
|
492
519
|
i0.ɵɵtext(2);
|
|
493
520
|
i0.ɵɵelementEnd();
|
|
494
521
|
} if (rf & 2) {
|
|
495
|
-
const
|
|
522
|
+
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
496
523
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
497
524
|
i0.ɵɵadvance(2);
|
|
498
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatCost(
|
|
525
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatCost(run_r11.CostUSD));
|
|
499
526
|
} }
|
|
500
527
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
501
|
-
i0.ɵɵelement(0, "mj-entity-link-pill",
|
|
528
|
+
i0.ɵɵelement(0, "mj-entity-link-pill", 144);
|
|
502
529
|
} if (rf & 2) {
|
|
503
|
-
const
|
|
504
|
-
i0.ɵɵproperty("entityName",
|
|
530
|
+
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
531
|
+
i0.ɵɵproperty("entityName", run_r11.TargetLogEntity)("recordId", run_r11.TargetLogID);
|
|
505
532
|
} }
|
|
506
533
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
507
|
-
i0.ɵɵelementStart(0, "span",
|
|
508
|
-
i0.ɵɵelement(1, "i",
|
|
534
|
+
i0.ɵɵelementStart(0, "span", 146);
|
|
535
|
+
i0.ɵɵelement(1, "i", 137);
|
|
509
536
|
i0.ɵɵelementStart(2, "span");
|
|
510
537
|
i0.ɵɵtext(3);
|
|
511
538
|
i0.ɵɵelementEnd()();
|
|
512
539
|
} if (rf & 2) {
|
|
513
|
-
const
|
|
540
|
+
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
514
541
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
515
|
-
i0.ɵɵproperty("ngClass", "status-" +
|
|
542
|
+
i0.ɵɵproperty("ngClass", "status-" + run_r11.Status.toLowerCase())("title", ctx_r0.getStatusTooltip(run_r11.Status));
|
|
516
543
|
i0.ɵɵadvance();
|
|
517
|
-
i0.ɵɵclassProp("fa-check",
|
|
544
|
+
i0.ɵɵclassProp("fa-check", run_r11.Status === "Passed")("fa-times", run_r11.Status === "Failed")("fa-exclamation", run_r11.Status === "Error")("fa-hourglass-end", run_r11.Status === "Timeout")("fa-forward", run_r11.Status === "Skipped")("fa-spinner", run_r11.Status === "Running")("fa-clock", run_r11.Status === "Pending");
|
|
518
545
|
i0.ɵɵadvance(2);
|
|
519
|
-
i0.ɵɵtextInterpolate(
|
|
546
|
+
i0.ɵɵtextInterpolate(run_r11.Status);
|
|
520
547
|
} }
|
|
521
548
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
522
|
-
i0.ɵɵelementStart(0, "span",
|
|
523
|
-
i0.ɵɵelement(1, "i",
|
|
549
|
+
i0.ɵɵelementStart(0, "span", 151);
|
|
550
|
+
i0.ɵɵelement(1, "i", 153);
|
|
524
551
|
i0.ɵɵelementEnd();
|
|
525
552
|
} }
|
|
526
553
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
527
|
-
i0.ɵɵelementStart(0, "span",
|
|
528
|
-
i0.ɵɵelement(1, "i",
|
|
554
|
+
i0.ɵɵelementStart(0, "span", 154);
|
|
555
|
+
i0.ɵɵelement(1, "i", 155);
|
|
529
556
|
i0.ɵɵelementStart(2, "span");
|
|
530
557
|
i0.ɵɵtext(3);
|
|
531
558
|
i0.ɵɵelementEnd()();
|
|
532
559
|
} if (rf & 2) {
|
|
533
560
|
let tmp_19_0;
|
|
534
|
-
const
|
|
535
|
-
const
|
|
561
|
+
const rating_r12 = ctx;
|
|
562
|
+
const run_r11 = i0.ɵɵnextContext(2).$implicit;
|
|
536
563
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
537
|
-
i0.ɵɵclassProp("rating-low",
|
|
538
|
-
i0.ɵɵproperty("title", ctx_r0.getHumanTooltip(
|
|
564
|
+
i0.ɵɵclassProp("rating-low", rating_r12 <= 4)("rating-medium", rating_r12 >= 5 && rating_r12 <= 6)("rating-good", rating_r12 >= 7 && rating_r12 <= 8)("rating-excellent", rating_r12 >= 9);
|
|
565
|
+
i0.ɵɵproperty("title", ctx_r0.getHumanTooltip(rating_r12, ((tmp_19_0 = ctx_r0.getFeedbackForRun(run_r11.ID)) == null ? null : tmp_19_0.CorrectionSummary) || ((tmp_19_0 = ctx_r0.getFeedbackForRun(run_r11.ID)) == null ? null : tmp_19_0.Comments) || null));
|
|
539
566
|
i0.ɵɵadvance(3);
|
|
540
|
-
i0.ɵɵtextInterpolate(
|
|
567
|
+
i0.ɵɵtextInterpolate(rating_r12);
|
|
541
568
|
} }
|
|
542
569
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
543
|
-
i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_0_Template, 2, 0, "span",
|
|
544
|
-
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_1_Template, 4, 10, "span",
|
|
570
|
+
i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_0_Template, 2, 0, "span", 151);
|
|
571
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_1_Template, 4, 10, "span", 152);
|
|
545
572
|
} if (rf & 2) {
|
|
546
573
|
let tmp_13_0;
|
|
547
574
|
let tmp_14_0;
|
|
548
|
-
const
|
|
575
|
+
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
549
576
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
550
|
-
i0.ɵɵconditional(!((tmp_13_0 = ctx_r0.getFeedbackForRun(
|
|
577
|
+
i0.ɵɵconditional(!((tmp_13_0 = ctx_r0.getFeedbackForRun(run_r11.ID)) == null ? null : tmp_13_0.Rating) ? 0 : -1);
|
|
551
578
|
i0.ɵɵadvance();
|
|
552
|
-
i0.ɵɵconditional((tmp_14_0 = (tmp_14_0 = ctx_r0.getFeedbackForRun(
|
|
579
|
+
i0.ɵɵconditional((tmp_14_0 = (tmp_14_0 = ctx_r0.getFeedbackForRun(run_r11.ID)) == null ? null : tmp_14_0.Rating) ? 1 : -1, tmp_14_0);
|
|
553
580
|
} }
|
|
554
581
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
555
|
-
i0.ɵɵelementStart(0, "span",
|
|
556
|
-
i0.ɵɵelement(1, "i",
|
|
582
|
+
i0.ɵɵelementStart(0, "span", 156);
|
|
583
|
+
i0.ɵɵelement(1, "i", 158);
|
|
557
584
|
i0.ɵɵelementEnd();
|
|
558
585
|
} }
|
|
559
586
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
560
|
-
i0.ɵɵelementStart(0, "span",
|
|
561
|
-
i0.ɵɵelement(1, "i",
|
|
587
|
+
i0.ɵɵelementStart(0, "span", 159);
|
|
588
|
+
i0.ɵɵelement(1, "i", 158);
|
|
562
589
|
i0.ɵɵelementStart(2, "span");
|
|
563
590
|
i0.ɵɵtext(3);
|
|
564
591
|
i0.ɵɵelementEnd()();
|
|
565
592
|
} if (rf & 2) {
|
|
566
|
-
const
|
|
567
|
-
i0.ɵɵclassProp("score-low",
|
|
568
|
-
i0.ɵɵproperty("title", "Auto Score: " + (
|
|
593
|
+
const run_r11 = i0.ɵɵnextContext(2).$implicit;
|
|
594
|
+
i0.ɵɵclassProp("score-low", run_r11.Score < 0.5)("score-medium", run_r11.Score >= 0.5 && run_r11.Score < 0.7)("score-good", run_r11.Score >= 0.7 && run_r11.Score < 0.85)("score-excellent", run_r11.Score >= 0.85);
|
|
595
|
+
i0.ɵɵproperty("title", "Auto Score: " + (run_r11.Score * 100).toFixed(0) + "% automated evaluation");
|
|
569
596
|
i0.ɵɵadvance(3);
|
|
570
|
-
i0.ɵɵtextInterpolate1("", (
|
|
597
|
+
i0.ɵɵtextInterpolate1("", (run_r11.Score * 100).toFixed(0), "%");
|
|
571
598
|
} }
|
|
572
599
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
573
|
-
i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_0_Template, 2, 0, "span",
|
|
574
|
-
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_1_Template, 4, 10, "span",
|
|
600
|
+
i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_0_Template, 2, 0, "span", 156);
|
|
601
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_1_Template, 4, 10, "span", 157);
|
|
575
602
|
} if (rf & 2) {
|
|
576
|
-
const
|
|
577
|
-
i0.ɵɵconditional(
|
|
603
|
+
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
604
|
+
i0.ɵɵconditional(run_r11.Score == null ? 0 : -1);
|
|
578
605
|
i0.ɵɵadvance();
|
|
579
|
-
i0.ɵɵconditional(
|
|
606
|
+
i0.ɵɵconditional(run_r11.Score != null ? 1 : -1);
|
|
580
607
|
} }
|
|
581
608
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
582
|
-
i0.ɵɵelementStart(0, "span",
|
|
609
|
+
i0.ɵɵelementStart(0, "span", 160);
|
|
583
610
|
i0.ɵɵtext(1);
|
|
584
611
|
i0.ɵɵelementEnd();
|
|
585
612
|
} if (rf & 2) {
|
|
586
|
-
const
|
|
613
|
+
const tag_r13 = ctx.$implicit;
|
|
587
614
|
i0.ɵɵadvance();
|
|
588
|
-
i0.ɵɵtextInterpolate(
|
|
615
|
+
i0.ɵɵtextInterpolate(tag_r13);
|
|
589
616
|
} }
|
|
590
617
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
591
|
-
i0.ɵɵelementStart(0, "span",
|
|
618
|
+
i0.ɵɵelementStart(0, "span", 161);
|
|
592
619
|
i0.ɵɵtext(1);
|
|
593
620
|
i0.ɵɵelementEnd();
|
|
594
621
|
} if (rf & 2) {
|
|
595
|
-
const
|
|
622
|
+
const run_r11 = i0.ɵɵnextContext(2).$implicit;
|
|
596
623
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
597
624
|
i0.ɵɵadvance();
|
|
598
|
-
i0.ɵɵtextInterpolate1("+", ctx_r0.getRunTags(
|
|
625
|
+
i0.ɵɵtextInterpolate1("+", ctx_r0.getRunTags(run_r11).length - 3);
|
|
599
626
|
} }
|
|
600
627
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
601
|
-
i0.ɵɵelementStart(0, "div",
|
|
602
|
-
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_For_2_Template, 2, 1, "span",
|
|
603
|
-
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Conditional_3_Template, 2, 1, "span",
|
|
628
|
+
i0.ɵɵelementStart(0, "div", 147);
|
|
629
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_For_2_Template, 2, 1, "span", 160, i0.ɵɵrepeaterTrackByIdentity);
|
|
630
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Conditional_3_Template, 2, 1, "span", 161);
|
|
604
631
|
i0.ɵɵelementEnd();
|
|
605
632
|
} if (rf & 2) {
|
|
606
|
-
const
|
|
633
|
+
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
607
634
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
608
635
|
i0.ɵɵadvance();
|
|
609
|
-
i0.ɵɵrepeater(ctx_r0.getRunTags(
|
|
636
|
+
i0.ɵɵrepeater(ctx_r0.getRunTags(run_r11).slice(0, 3));
|
|
610
637
|
i0.ɵɵadvance(2);
|
|
611
|
-
i0.ɵɵconditional(ctx_r0.getRunTags(
|
|
638
|
+
i0.ɵɵconditional(ctx_r0.getRunTags(run_r11).length > 3 ? 3 : -1);
|
|
612
639
|
} }
|
|
613
640
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
614
|
-
const
|
|
615
|
-
i0.ɵɵelementStart(0, "div",
|
|
616
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template_div_click_0_listener() { const
|
|
617
|
-
i0.ɵɵelementStart(1, "div",
|
|
618
|
-
i0.ɵɵelement(2, "i",
|
|
641
|
+
const _r10 = i0.ɵɵgetCurrentView();
|
|
642
|
+
i0.ɵɵelementStart(0, "div", 135);
|
|
643
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template_div_click_0_listener() { const run_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestRun(run_r11.ID)); });
|
|
644
|
+
i0.ɵɵelementStart(1, "div", 136);
|
|
645
|
+
i0.ɵɵelement(2, "i", 137);
|
|
619
646
|
i0.ɵɵelementEnd();
|
|
620
|
-
i0.ɵɵelementStart(3, "div",
|
|
647
|
+
i0.ɵɵelementStart(3, "div", 138)(4, "div", 139)(5, "span", 140);
|
|
621
648
|
i0.ɵɵtext(6);
|
|
622
649
|
i0.ɵɵelementEnd();
|
|
623
|
-
i0.ɵɵelementStart(7, "span",
|
|
650
|
+
i0.ɵɵelementStart(7, "span", 141);
|
|
624
651
|
i0.ɵɵtext(8);
|
|
625
652
|
i0.ɵɵelementEnd()();
|
|
626
|
-
i0.ɵɵelementStart(9, "div",
|
|
627
|
-
i0.ɵɵelement(11, "i",
|
|
653
|
+
i0.ɵɵelementStart(9, "div", 142)(10, "span");
|
|
654
|
+
i0.ɵɵelement(11, "i", 143);
|
|
628
655
|
i0.ɵɵtext(12);
|
|
629
656
|
i0.ɵɵelementEnd();
|
|
630
657
|
i0.ɵɵconditionalCreate(13, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_13_Template, 3, 1, "span");
|
|
631
658
|
i0.ɵɵconditionalCreate(14, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_14_Template, 3, 1, "span");
|
|
632
|
-
i0.ɵɵconditionalCreate(15, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_15_Template, 1, 2, "mj-entity-link-pill",
|
|
659
|
+
i0.ɵɵconditionalCreate(15, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_15_Template, 1, 2, "mj-entity-link-pill", 144);
|
|
633
660
|
i0.ɵɵelementEnd();
|
|
634
|
-
i0.ɵɵelementStart(16, "div",
|
|
635
|
-
i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_17_Template, 4, 17, "span",
|
|
661
|
+
i0.ɵɵelementStart(16, "div", 145);
|
|
662
|
+
i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_17_Template, 4, 17, "span", 146);
|
|
636
663
|
i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Template, 2, 2);
|
|
637
664
|
i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Template, 2, 2);
|
|
638
665
|
i0.ɵɵelementEnd();
|
|
639
|
-
i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Template, 4, 1, "div",
|
|
666
|
+
i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Template, 4, 1, "div", 147);
|
|
640
667
|
i0.ɵɵelementEnd();
|
|
641
|
-
i0.ɵɵelement(21, "i",
|
|
668
|
+
i0.ɵɵelement(21, "i", 148);
|
|
642
669
|
i0.ɵɵelementEnd();
|
|
643
670
|
} if (rf & 2) {
|
|
644
|
-
const
|
|
671
|
+
const run_r11 = ctx.$implicit;
|
|
645
672
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
646
673
|
i0.ɵɵadvance();
|
|
647
|
-
i0.ɵɵstyleProp("background-color", ctx_r0.getRunStatusColor(
|
|
674
|
+
i0.ɵɵstyleProp("background-color", ctx_r0.getRunStatusColor(run_r11.Status));
|
|
648
675
|
i0.ɵɵadvance();
|
|
649
|
-
i0.ɵɵclassProp("fa-check",
|
|
676
|
+
i0.ɵɵclassProp("fa-check", run_r11.Status === "Passed")("fa-times", run_r11.Status === "Failed")("fa-exclamation", run_r11.Status === "Error")("fa-stopwatch", run_r11.Status === "Timeout")("fa-spinner", run_r11.Status === "Running")("fa-clock", run_r11.Status === "Pending");
|
|
650
677
|
i0.ɵɵadvance(4);
|
|
651
|
-
i0.ɵɵtextInterpolate1("Run #",
|
|
678
|
+
i0.ɵɵtextInterpolate1("Run #", run_r11.ID.substring(0, 8));
|
|
652
679
|
i0.ɵɵadvance();
|
|
653
|
-
i0.ɵɵstyleProp("color", ctx_r0.getRunStatusColor(
|
|
680
|
+
i0.ɵɵstyleProp("color", ctx_r0.getRunStatusColor(run_r11.Status));
|
|
654
681
|
i0.ɵɵadvance();
|
|
655
|
-
i0.ɵɵtextInterpolate(
|
|
682
|
+
i0.ɵɵtextInterpolate(run_r11.Status);
|
|
656
683
|
i0.ɵɵadvance(4);
|
|
657
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r0.getRelativeTime(
|
|
684
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.getRelativeTime(run_r11.StartedAt));
|
|
658
685
|
i0.ɵɵadvance();
|
|
659
|
-
i0.ɵɵconditional(
|
|
686
|
+
i0.ɵɵconditional(run_r11.DurationSeconds ? 13 : -1);
|
|
660
687
|
i0.ɵɵadvance();
|
|
661
|
-
i0.ɵɵconditional(
|
|
688
|
+
i0.ɵɵconditional(run_r11.CostUSD ? 14 : -1);
|
|
662
689
|
i0.ɵɵadvance();
|
|
663
|
-
i0.ɵɵconditional(
|
|
690
|
+
i0.ɵɵconditional(run_r11.TargetLogEntityID && run_r11.TargetLogID ? 15 : -1);
|
|
664
691
|
i0.ɵɵadvance(2);
|
|
665
692
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 17 : -1);
|
|
666
693
|
i0.ɵɵadvance();
|
|
@@ -668,11 +695,11 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template
|
|
|
668
695
|
i0.ɵɵadvance();
|
|
669
696
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 19 : -1);
|
|
670
697
|
i0.ɵɵadvance();
|
|
671
|
-
i0.ɵɵconditional(ctx_r0.getRunTags(
|
|
698
|
+
i0.ɵɵconditional(ctx_r0.getRunTags(run_r11).length > 0 ? 20 : -1);
|
|
672
699
|
} }
|
|
673
700
|
function MJTestFormComponentExtended_Conditional_65_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
674
|
-
i0.ɵɵelementStart(0, "div",
|
|
675
|
-
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template, 22, 26, "div",
|
|
701
|
+
i0.ɵɵelementStart(0, "div", 126);
|
|
702
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template, 22, 26, "div", 134, i0.ɵɵrepeaterTrackByIdentity);
|
|
676
703
|
i0.ɵɵelementEnd();
|
|
677
704
|
} if (rf & 2) {
|
|
678
705
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -680,16 +707,16 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Template(rf, c
|
|
|
680
707
|
i0.ɵɵrepeater(ctx_r0.testRuns);
|
|
681
708
|
} }
|
|
682
709
|
function MJTestFormComponentExtended_Conditional_65_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
683
|
-
const
|
|
684
|
-
i0.ɵɵelementStart(0, "mj-empty-state",
|
|
685
|
-
i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_65_Conditional_3_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(
|
|
710
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
711
|
+
i0.ɵɵelementStart(0, "mj-empty-state", 162);
|
|
712
|
+
i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_65_Conditional_3_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.runTest()); });
|
|
686
713
|
i0.ɵɵelementEnd();
|
|
687
714
|
} }
|
|
688
715
|
function MJTestFormComponentExtended_Conditional_65_Template(rf, ctx) { if (rf & 1) {
|
|
689
716
|
i0.ɵɵelementStart(0, "div", 38);
|
|
690
|
-
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_1_Template, 4, 1, "div",
|
|
691
|
-
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_2_Template, 3, 0, "div",
|
|
692
|
-
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_3_Template, 1, 0, "mj-empty-state",
|
|
717
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_1_Template, 4, 1, "div", 125);
|
|
718
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_2_Template, 3, 0, "div", 126);
|
|
719
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_3_Template, 1, 0, "mj-empty-state", 127);
|
|
693
720
|
i0.ɵɵelementEnd();
|
|
694
721
|
} if (rf & 2) {
|
|
695
722
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -701,15 +728,15 @@ function MJTestFormComponentExtended_Conditional_65_Template(rf, ctx) { if (rf &
|
|
|
701
728
|
i0.ɵɵconditional(ctx_r0.testRunsLoaded && !ctx_r0.loadingRuns && ctx_r0.testRuns.length === 0 ? 3 : -1);
|
|
702
729
|
} }
|
|
703
730
|
function MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
704
|
-
i0.ɵɵelementStart(0, "div",
|
|
705
|
-
i0.ɵɵelement(1, "div",
|
|
706
|
-
i0.ɵɵelementStart(2, "div",
|
|
707
|
-
i0.ɵɵelement(3, "div",
|
|
731
|
+
i0.ɵɵelementStart(0, "div", 129);
|
|
732
|
+
i0.ɵɵelement(1, "div", 130);
|
|
733
|
+
i0.ɵɵelementStart(2, "div", 131);
|
|
734
|
+
i0.ɵɵelement(3, "div", 132)(4, "div", 133);
|
|
708
735
|
i0.ɵɵelementEnd()();
|
|
709
736
|
} }
|
|
710
737
|
function MJTestFormComponentExtended_Conditional_66_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
711
|
-
i0.ɵɵelementStart(0, "div",
|
|
712
|
-
i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template, 5, 0, "div",
|
|
738
|
+
i0.ɵɵelementStart(0, "div", 125)(1, "div", 128);
|
|
739
|
+
i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template, 5, 0, "div", 129, i0.ɵɵrepeaterTrackByIdentity);
|
|
713
740
|
i0.ɵɵelementEnd()();
|
|
714
741
|
} if (rf & 2) {
|
|
715
742
|
i0.ɵɵadvance(2);
|
|
@@ -721,40 +748,40 @@ function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditio
|
|
|
721
748
|
i0.ɵɵtext(2);
|
|
722
749
|
i0.ɵɵelementEnd();
|
|
723
750
|
} if (rf & 2) {
|
|
724
|
-
const
|
|
751
|
+
const suiteTest_r16 = i0.ɵɵnextContext().$implicit;
|
|
725
752
|
i0.ɵɵadvance(2);
|
|
726
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
753
|
+
i0.ɵɵtextInterpolate1(" ", suiteTest_r16.Status);
|
|
727
754
|
} }
|
|
728
755
|
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
729
|
-
const
|
|
730
|
-
i0.ɵɵelementStart(0, "div",
|
|
731
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template_div_click_0_listener() { const
|
|
732
|
-
i0.ɵɵelementStart(1, "div",
|
|
756
|
+
const _r15 = i0.ɵɵgetCurrentView();
|
|
757
|
+
i0.ɵɵelementStart(0, "div", 166);
|
|
758
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template_div_click_0_listener() { const suiteTest_r16 = i0.ɵɵrestoreView(_r15).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestSuite(suiteTest_r16.SuiteID)); });
|
|
759
|
+
i0.ɵɵelementStart(1, "div", 167);
|
|
733
760
|
i0.ɵɵelement(2, "i", 33);
|
|
734
761
|
i0.ɵɵelementEnd();
|
|
735
|
-
i0.ɵɵelementStart(3, "div",
|
|
762
|
+
i0.ɵɵelementStart(3, "div", 168)(4, "div", 169);
|
|
736
763
|
i0.ɵɵtext(5);
|
|
737
764
|
i0.ɵɵelementEnd();
|
|
738
|
-
i0.ɵɵelementStart(6, "div",
|
|
739
|
-
i0.ɵɵelement(8, "i",
|
|
765
|
+
i0.ɵɵelementStart(6, "div", 170)(7, "span");
|
|
766
|
+
i0.ɵɵelement(8, "i", 171);
|
|
740
767
|
i0.ɵɵtext(9);
|
|
741
768
|
i0.ɵɵelementEnd();
|
|
742
769
|
i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_10_Template, 3, 1, "span");
|
|
743
770
|
i0.ɵɵelementEnd()();
|
|
744
|
-
i0.ɵɵelement(11, "i",
|
|
771
|
+
i0.ɵɵelement(11, "i", 148);
|
|
745
772
|
i0.ɵɵelementEnd();
|
|
746
773
|
} if (rf & 2) {
|
|
747
|
-
const
|
|
774
|
+
const suiteTest_r16 = ctx.$implicit;
|
|
748
775
|
i0.ɵɵadvance(5);
|
|
749
|
-
i0.ɵɵtextInterpolate(
|
|
776
|
+
i0.ɵɵtextInterpolate(suiteTest_r16.Suite);
|
|
750
777
|
i0.ɵɵadvance(4);
|
|
751
|
-
i0.ɵɵtextInterpolate1(" Sequence: ",
|
|
778
|
+
i0.ɵɵtextInterpolate1(" Sequence: ", suiteTest_r16.Sequence);
|
|
752
779
|
i0.ɵɵadvance();
|
|
753
|
-
i0.ɵɵconditional(
|
|
780
|
+
i0.ɵɵconditional(suiteTest_r16.Status ? 10 : -1);
|
|
754
781
|
} }
|
|
755
782
|
function MJTestFormComponentExtended_Conditional_66_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
756
|
-
i0.ɵɵelementStart(0, "div",
|
|
757
|
-
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template, 12, 3, "div",
|
|
783
|
+
i0.ɵɵelementStart(0, "div", 163);
|
|
784
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template, 12, 3, "div", 165, i0.ɵɵrepeaterTrackByIdentity);
|
|
758
785
|
i0.ɵɵelementEnd();
|
|
759
786
|
} if (rf & 2) {
|
|
760
787
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -762,13 +789,13 @@ function MJTestFormComponentExtended_Conditional_66_Conditional_2_Template(rf, c
|
|
|
762
789
|
i0.ɵɵrepeater(ctx_r0.suiteTests);
|
|
763
790
|
} }
|
|
764
791
|
function MJTestFormComponentExtended_Conditional_66_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
765
|
-
i0.ɵɵelement(0, "mj-empty-state",
|
|
792
|
+
i0.ɵɵelement(0, "mj-empty-state", 164);
|
|
766
793
|
} }
|
|
767
794
|
function MJTestFormComponentExtended_Conditional_66_Template(rf, ctx) { if (rf & 1) {
|
|
768
795
|
i0.ɵɵelementStart(0, "div", 39);
|
|
769
|
-
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_1_Template, 4, 1, "div",
|
|
770
|
-
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_2_Template, 3, 0, "div",
|
|
771
|
-
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_66_Conditional_3_Template, 1, 0, "mj-empty-state",
|
|
796
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_1_Template, 4, 1, "div", 125);
|
|
797
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_2_Template, 3, 0, "div", 163);
|
|
798
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_66_Conditional_3_Template, 1, 0, "mj-empty-state", 164);
|
|
772
799
|
i0.ɵɵelementEnd();
|
|
773
800
|
} if (rf & 2) {
|
|
774
801
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -780,19 +807,19 @@ function MJTestFormComponentExtended_Conditional_66_Template(rf, ctx) { if (rf &
|
|
|
780
807
|
i0.ɵɵconditional(ctx_r0.suiteTestsLoaded && !ctx_r0.loadingSuites && ctx_r0.suiteTests.length === 0 ? 3 : -1);
|
|
781
808
|
} }
|
|
782
809
|
function MJTestFormComponentExtended_Conditional_67_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
783
|
-
i0.ɵɵelementStart(0, "div",
|
|
784
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
810
|
+
i0.ɵɵelementStart(0, "div", 125);
|
|
811
|
+
i0.ɵɵelement(1, "mj-loading", 173);
|
|
785
812
|
i0.ɵɵelementEnd();
|
|
786
813
|
} }
|
|
787
814
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
788
|
-
i0.ɵɵelementStart(0, "div",
|
|
789
|
-
i0.ɵɵelement(2, "i",
|
|
815
|
+
i0.ɵɵelementStart(0, "div", 183)(1, "div", 189);
|
|
816
|
+
i0.ɵɵelement(2, "i", 190);
|
|
790
817
|
i0.ɵɵelementEnd();
|
|
791
|
-
i0.ɵɵelementStart(3, "div",
|
|
818
|
+
i0.ɵɵelementStart(3, "div", 186)(4, "div", 187);
|
|
792
819
|
i0.ɵɵtext(5);
|
|
793
|
-
i0.ɵɵelement(6, "i",
|
|
820
|
+
i0.ɵɵelement(6, "i", 191);
|
|
794
821
|
i0.ɵɵelementEnd();
|
|
795
|
-
i0.ɵɵelementStart(7, "div",
|
|
822
|
+
i0.ɵɵelementStart(7, "div", 188);
|
|
796
823
|
i0.ɵɵtext(8, "Pass Rate");
|
|
797
824
|
i0.ɵɵelementEnd()()();
|
|
798
825
|
} if (rf & 2) {
|
|
@@ -803,13 +830,13 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17
|
|
|
803
830
|
i0.ɵɵclassProp("fa-arrow-up", ctx_r0.getPassRateTrend() === "up")("fa-arrow-down", ctx_r0.getPassRateTrend() === "down")("fa-minus", ctx_r0.getPassRateTrend() === "stable")("trend-up", ctx_r0.getPassRateTrend() === "up")("trend-down", ctx_r0.getPassRateTrend() === "down");
|
|
804
831
|
} }
|
|
805
832
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
806
|
-
i0.ɵɵelementStart(0, "div",
|
|
807
|
-
i0.ɵɵelement(2, "i",
|
|
833
|
+
i0.ɵɵelementStart(0, "div", 183)(1, "div", 184);
|
|
834
|
+
i0.ɵɵelement(2, "i", 192);
|
|
808
835
|
i0.ɵɵelementEnd();
|
|
809
|
-
i0.ɵɵelementStart(3, "div",
|
|
836
|
+
i0.ɵɵelementStart(3, "div", 186)(4, "div", 187);
|
|
810
837
|
i0.ɵɵtext(5);
|
|
811
838
|
i0.ɵɵelementEnd();
|
|
812
|
-
i0.ɵɵelementStart(6, "div",
|
|
839
|
+
i0.ɵɵelementStart(6, "div", 188);
|
|
813
840
|
i0.ɵɵtext(7, "Avg Score");
|
|
814
841
|
i0.ɵɵelementEnd()()();
|
|
815
842
|
} if (rf & 2) {
|
|
@@ -818,33 +845,33 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17
|
|
|
818
845
|
i0.ɵɵtextInterpolate1("", (ctx_r0.getOverallAvgScore() * 100).toFixed(1), "%");
|
|
819
846
|
} }
|
|
820
847
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
821
|
-
i0.ɵɵelementStart(0, "div",
|
|
822
|
-
i0.ɵɵelement(3, "i",
|
|
848
|
+
i0.ɵɵelementStart(0, "div", 180)(1, "div", 183)(2, "div", 184);
|
|
849
|
+
i0.ɵɵelement(3, "i", 185);
|
|
823
850
|
i0.ɵɵelementEnd();
|
|
824
|
-
i0.ɵɵelementStart(4, "div",
|
|
851
|
+
i0.ɵɵelementStart(4, "div", 186)(5, "div", 187);
|
|
825
852
|
i0.ɵɵtext(6);
|
|
826
853
|
i0.ɵɵelementEnd();
|
|
827
|
-
i0.ɵɵelementStart(7, "div",
|
|
854
|
+
i0.ɵɵelementStart(7, "div", 188);
|
|
828
855
|
i0.ɵɵtext(8, "Total Runs");
|
|
829
856
|
i0.ɵɵelementEnd()()();
|
|
830
|
-
i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_9_Template, 9, 11, "div",
|
|
831
|
-
i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_10_Template, 8, 1, "div",
|
|
832
|
-
i0.ɵɵelementStart(11, "div",
|
|
833
|
-
i0.ɵɵelement(13, "i",
|
|
857
|
+
i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_9_Template, 9, 11, "div", 183);
|
|
858
|
+
i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_10_Template, 8, 1, "div", 183);
|
|
859
|
+
i0.ɵɵelementStart(11, "div", 183)(12, "div", 184);
|
|
860
|
+
i0.ɵɵelement(13, "i", 149);
|
|
834
861
|
i0.ɵɵelementEnd();
|
|
835
|
-
i0.ɵɵelementStart(14, "div",
|
|
862
|
+
i0.ɵɵelementStart(14, "div", 186)(15, "div", 187);
|
|
836
863
|
i0.ɵɵtext(16);
|
|
837
864
|
i0.ɵɵelementEnd();
|
|
838
|
-
i0.ɵɵelementStart(17, "div",
|
|
865
|
+
i0.ɵɵelementStart(17, "div", 188);
|
|
839
866
|
i0.ɵɵtext(18, "Avg Duration");
|
|
840
867
|
i0.ɵɵelementEnd()()();
|
|
841
|
-
i0.ɵɵelementStart(19, "div",
|
|
842
|
-
i0.ɵɵelement(21, "i",
|
|
868
|
+
i0.ɵɵelementStart(19, "div", 183)(20, "div", 184);
|
|
869
|
+
i0.ɵɵelement(21, "i", 150);
|
|
843
870
|
i0.ɵɵelementEnd();
|
|
844
|
-
i0.ɵɵelementStart(22, "div",
|
|
871
|
+
i0.ɵɵelementStart(22, "div", 186)(23, "div", 187);
|
|
845
872
|
i0.ɵɵtext(24);
|
|
846
873
|
i0.ɵɵelementEnd();
|
|
847
|
-
i0.ɵɵelementStart(25, "div",
|
|
874
|
+
i0.ɵɵelementStart(25, "div", 188);
|
|
848
875
|
i0.ɵɵtext(26, "Avg Cost");
|
|
849
876
|
i0.ɵɵelementEnd()()()();
|
|
850
877
|
} if (rf & 2) {
|
|
@@ -881,70 +908,70 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
881
908
|
i0.ɵɵelementEnd();
|
|
882
909
|
} }
|
|
883
910
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
884
|
-
i0.ɵɵelementStart(0, "td",
|
|
911
|
+
i0.ɵɵelementStart(0, "td", 198);
|
|
885
912
|
i0.ɵɵtext(1);
|
|
886
913
|
i0.ɵɵelementEnd();
|
|
887
914
|
} if (rf & 2) {
|
|
888
|
-
const
|
|
915
|
+
const day_r18 = i0.ɵɵnextContext().$implicit;
|
|
889
916
|
i0.ɵɵadvance();
|
|
890
|
-
i0.ɵɵtextInterpolate(
|
|
917
|
+
i0.ɵɵtextInterpolate(day_r18.passCount);
|
|
891
918
|
} }
|
|
892
919
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
893
|
-
i0.ɵɵelementStart(0, "td",
|
|
920
|
+
i0.ɵɵelementStart(0, "td", 199);
|
|
894
921
|
i0.ɵɵtext(1);
|
|
895
922
|
i0.ɵɵelementEnd();
|
|
896
923
|
} if (rf & 2) {
|
|
897
|
-
const
|
|
924
|
+
const day_r18 = i0.ɵɵnextContext().$implicit;
|
|
898
925
|
i0.ɵɵadvance();
|
|
899
|
-
i0.ɵɵtextInterpolate(
|
|
926
|
+
i0.ɵɵtextInterpolate(day_r18.failCount);
|
|
900
927
|
} }
|
|
901
928
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
902
|
-
i0.ɵɵelementStart(0, "td",
|
|
903
|
-
i0.ɵɵelement(2, "div",
|
|
904
|
-
i0.ɵɵelementStart(3, "span",
|
|
929
|
+
i0.ɵɵelementStart(0, "td", 200)(1, "div", 204);
|
|
930
|
+
i0.ɵɵelement(2, "div", 205);
|
|
931
|
+
i0.ɵɵelementStart(3, "span", 206);
|
|
905
932
|
i0.ɵɵtext(4);
|
|
906
933
|
i0.ɵɵelementEnd()()();
|
|
907
934
|
} if (rf & 2) {
|
|
908
|
-
const
|
|
935
|
+
const day_r18 = i0.ɵɵnextContext().$implicit;
|
|
909
936
|
i0.ɵɵadvance(2);
|
|
910
|
-
i0.ɵɵstyleProp("width",
|
|
937
|
+
i0.ɵɵstyleProp("width", day_r18.passRate, "%");
|
|
911
938
|
i0.ɵɵadvance(2);
|
|
912
|
-
i0.ɵɵtextInterpolate1("",
|
|
939
|
+
i0.ɵɵtextInterpolate1("", day_r18.passRate.toFixed(1), "%");
|
|
913
940
|
} }
|
|
914
941
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
915
|
-
i0.ɵɵelementStart(0, "td",
|
|
942
|
+
i0.ɵɵelementStart(0, "td", 201);
|
|
916
943
|
i0.ɵɵtext(1);
|
|
917
944
|
i0.ɵɵelementEnd();
|
|
918
945
|
} if (rf & 2) {
|
|
919
|
-
const
|
|
946
|
+
const day_r18 = i0.ɵɵnextContext().$implicit;
|
|
920
947
|
i0.ɵɵadvance();
|
|
921
|
-
i0.ɵɵtextInterpolate1("", (
|
|
948
|
+
i0.ɵɵtextInterpolate1("", (day_r18.avgScore * 100).toFixed(1), "%");
|
|
922
949
|
} }
|
|
923
950
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Template(rf, ctx) { if (rf & 1) {
|
|
924
|
-
i0.ɵɵelementStart(0, "tr")(1, "td",
|
|
951
|
+
i0.ɵɵelementStart(0, "tr")(1, "td", 196);
|
|
925
952
|
i0.ɵɵtext(2);
|
|
926
953
|
i0.ɵɵpipe(3, "date");
|
|
927
954
|
i0.ɵɵelementEnd();
|
|
928
|
-
i0.ɵɵelementStart(4, "td",
|
|
955
|
+
i0.ɵɵelementStart(4, "td", 197);
|
|
929
956
|
i0.ɵɵtext(5);
|
|
930
957
|
i0.ɵɵelementEnd();
|
|
931
|
-
i0.ɵɵconditionalCreate(6, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_6_Template, 2, 1, "td",
|
|
932
|
-
i0.ɵɵconditionalCreate(7, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_7_Template, 2, 1, "td",
|
|
933
|
-
i0.ɵɵconditionalCreate(8, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_8_Template, 5, 3, "td",
|
|
934
|
-
i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_9_Template, 2, 1, "td",
|
|
935
|
-
i0.ɵɵelementStart(10, "td",
|
|
958
|
+
i0.ɵɵconditionalCreate(6, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_6_Template, 2, 1, "td", 198);
|
|
959
|
+
i0.ɵɵconditionalCreate(7, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_7_Template, 2, 1, "td", 199);
|
|
960
|
+
i0.ɵɵconditionalCreate(8, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_8_Template, 5, 3, "td", 200);
|
|
961
|
+
i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_9_Template, 2, 1, "td", 201);
|
|
962
|
+
i0.ɵɵelementStart(10, "td", 202);
|
|
936
963
|
i0.ɵɵtext(11);
|
|
937
964
|
i0.ɵɵelementEnd();
|
|
938
|
-
i0.ɵɵelementStart(12, "td",
|
|
965
|
+
i0.ɵɵelementStart(12, "td", 203);
|
|
939
966
|
i0.ɵɵtext(13);
|
|
940
967
|
i0.ɵɵelementEnd()();
|
|
941
968
|
} if (rf & 2) {
|
|
942
|
-
const
|
|
969
|
+
const day_r18 = ctx.$implicit;
|
|
943
970
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
944
971
|
i0.ɵɵadvance(2);
|
|
945
|
-
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 8,
|
|
972
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 8, day_r18.date, "mediumDate"));
|
|
946
973
|
i0.ɵɵadvance(3);
|
|
947
|
-
i0.ɵɵtextInterpolate(
|
|
974
|
+
i0.ɵɵtextInterpolate(day_r18.runCount);
|
|
948
975
|
i0.ɵɵadvance();
|
|
949
976
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 6 : -1);
|
|
950
977
|
i0.ɵɵadvance();
|
|
@@ -954,16 +981,16 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
954
981
|
i0.ɵɵadvance();
|
|
955
982
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 9 : -1);
|
|
956
983
|
i0.ɵɵadvance(2);
|
|
957
|
-
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(
|
|
984
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(day_r18.avgDuration));
|
|
958
985
|
i0.ɵɵadvance(2);
|
|
959
|
-
i0.ɵɵtextInterpolate(ctx_r0.formatCost(
|
|
986
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatCost(day_r18.avgCost));
|
|
960
987
|
} }
|
|
961
988
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
962
|
-
i0.ɵɵelementStart(0, "div",
|
|
963
|
-
i0.ɵɵelement(2, "i",
|
|
989
|
+
i0.ɵɵelementStart(0, "div", 181)(1, "h3");
|
|
990
|
+
i0.ɵɵelement(2, "i", 193);
|
|
964
991
|
i0.ɵɵtext(3, " Daily Performance");
|
|
965
992
|
i0.ɵɵelementEnd();
|
|
966
|
-
i0.ɵɵelementStart(4, "div",
|
|
993
|
+
i0.ɵɵelementStart(4, "div", 194)(5, "table", 195)(6, "thead")(7, "tr")(8, "th");
|
|
967
994
|
i0.ɵɵtext(9, "Date");
|
|
968
995
|
i0.ɵɵelementEnd();
|
|
969
996
|
i0.ɵɵelementStart(10, "th");
|
|
@@ -996,134 +1023,134 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
996
1023
|
i0.ɵɵrepeater(ctx_r0.historyData);
|
|
997
1024
|
} }
|
|
998
1025
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
999
|
-
i0.ɵɵelementStart(0, "span",
|
|
1026
|
+
i0.ɵɵelementStart(0, "span", 218);
|
|
1000
1027
|
i0.ɵɵtext(1);
|
|
1001
1028
|
i0.ɵɵelementEnd();
|
|
1002
1029
|
} if (rf & 2) {
|
|
1003
|
-
const
|
|
1030
|
+
const tag_r21 = ctx.$implicit;
|
|
1004
1031
|
i0.ɵɵadvance();
|
|
1005
|
-
i0.ɵɵtextInterpolate(
|
|
1032
|
+
i0.ɵɵtextInterpolate(tag_r21);
|
|
1006
1033
|
} }
|
|
1007
1034
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
1008
|
-
i0.ɵɵelementStart(0, "span",
|
|
1035
|
+
i0.ɵɵelementStart(0, "span", 219);
|
|
1009
1036
|
i0.ɵɵtext(1);
|
|
1010
1037
|
i0.ɵɵelementEnd();
|
|
1011
1038
|
} if (rf & 2) {
|
|
1012
|
-
const
|
|
1039
|
+
const suite_r20 = i0.ɵɵnextContext(2).$implicit;
|
|
1013
1040
|
i0.ɵɵadvance();
|
|
1014
|
-
i0.ɵɵtextInterpolate1("+",
|
|
1041
|
+
i0.ɵɵtextInterpolate1("+", suite_r20.tags.length - 3);
|
|
1015
1042
|
} }
|
|
1016
1043
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
1017
|
-
i0.ɵɵelementStart(0, "div",
|
|
1018
|
-
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template, 2, 1, "span",
|
|
1019
|
-
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template, 2, 1, "span",
|
|
1044
|
+
i0.ɵɵelementStart(0, "div", 212);
|
|
1045
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template, 2, 1, "span", 218, i0.ɵɵrepeaterTrackByIdentity);
|
|
1046
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template, 2, 1, "span", 219);
|
|
1020
1047
|
i0.ɵɵelementEnd();
|
|
1021
1048
|
} if (rf & 2) {
|
|
1022
|
-
const
|
|
1049
|
+
const suite_r20 = i0.ɵɵnextContext().$implicit;
|
|
1023
1050
|
i0.ɵɵadvance();
|
|
1024
|
-
i0.ɵɵrepeater(
|
|
1051
|
+
i0.ɵɵrepeater(suite_r20.tags.slice(0, 3));
|
|
1025
1052
|
i0.ɵɵadvance(2);
|
|
1026
|
-
i0.ɵɵconditional(
|
|
1053
|
+
i0.ɵɵconditional(suite_r20.tags.length > 3 ? 3 : -1);
|
|
1027
1054
|
} }
|
|
1028
1055
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
1029
|
-
i0.ɵɵelementStart(0, "div",
|
|
1056
|
+
i0.ɵɵelementStart(0, "div", 214)(1, "span", 220);
|
|
1030
1057
|
i0.ɵɵtext(2);
|
|
1031
1058
|
i0.ɵɵelementEnd();
|
|
1032
|
-
i0.ɵɵelementStart(3, "span",
|
|
1059
|
+
i0.ɵɵelementStart(3, "span", 216);
|
|
1033
1060
|
i0.ɵɵtext(4, "Pass Rate");
|
|
1034
1061
|
i0.ɵɵelementEnd()();
|
|
1035
1062
|
} if (rf & 2) {
|
|
1036
|
-
const
|
|
1063
|
+
const suite_r20 = i0.ɵɵnextContext().$implicit;
|
|
1037
1064
|
i0.ɵɵadvance();
|
|
1038
|
-
i0.ɵɵclassProp("high",
|
|
1065
|
+
i0.ɵɵclassProp("high", suite_r20.passRate >= 80)("low", suite_r20.passRate < 50);
|
|
1039
1066
|
i0.ɵɵadvance();
|
|
1040
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
1067
|
+
i0.ɵɵtextInterpolate1(" ", suite_r20.passRate.toFixed(1), "% ");
|
|
1041
1068
|
} }
|
|
1042
1069
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
1043
|
-
i0.ɵɵelementStart(0, "div",
|
|
1070
|
+
i0.ɵɵelementStart(0, "div", 214)(1, "span", 215);
|
|
1044
1071
|
i0.ɵɵtext(2);
|
|
1045
1072
|
i0.ɵɵelementEnd();
|
|
1046
|
-
i0.ɵɵelementStart(3, "span",
|
|
1073
|
+
i0.ɵɵelementStart(3, "span", 216);
|
|
1047
1074
|
i0.ɵɵtext(4, "Avg Score");
|
|
1048
1075
|
i0.ɵɵelementEnd()();
|
|
1049
1076
|
} if (rf & 2) {
|
|
1050
|
-
const
|
|
1077
|
+
const suite_r20 = i0.ɵɵnextContext().$implicit;
|
|
1051
1078
|
i0.ɵɵadvance(2);
|
|
1052
|
-
i0.ɵɵtextInterpolate1("", (
|
|
1079
|
+
i0.ɵɵtextInterpolate1("", (suite_r20.avgScore * 100).toFixed(1), "%");
|
|
1053
1080
|
} }
|
|
1054
1081
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_23_Template(rf, ctx) { if (rf & 1) {
|
|
1055
|
-
i0.ɵɵelementStart(0, "div",
|
|
1082
|
+
i0.ɵɵelementStart(0, "div", 214)(1, "span", 215);
|
|
1056
1083
|
i0.ɵɵtext(2);
|
|
1057
1084
|
i0.ɵɵelementEnd();
|
|
1058
|
-
i0.ɵɵelementStart(3, "span",
|
|
1085
|
+
i0.ɵɵelementStart(3, "span", 216);
|
|
1059
1086
|
i0.ɵɵtext(4, "Last Run");
|
|
1060
1087
|
i0.ɵɵelementEnd()();
|
|
1061
1088
|
} if (rf & 2) {
|
|
1062
|
-
const
|
|
1089
|
+
const suite_r20 = i0.ɵɵnextContext().$implicit;
|
|
1063
1090
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
1064
1091
|
i0.ɵɵadvance(2);
|
|
1065
|
-
i0.ɵɵtextInterpolate(ctx_r0.getRelativeTime(
|
|
1092
|
+
i0.ɵɵtextInterpolate(ctx_r0.getRelativeTime(suite_r20.lastRun));
|
|
1066
1093
|
} }
|
|
1067
1094
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template(rf, ctx) { if (rf & 1) {
|
|
1068
|
-
const
|
|
1069
|
-
i0.ɵɵelementStart(0, "div",
|
|
1070
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template_div_click_0_listener() { const
|
|
1071
|
-
i0.ɵɵelementStart(1, "div",
|
|
1095
|
+
const _r19 = i0.ɵɵgetCurrentView();
|
|
1096
|
+
i0.ɵɵelementStart(0, "div", 209);
|
|
1097
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template_div_click_0_listener() { const suite_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.openSuiteFromHistory(suite_r20.suiteId)); });
|
|
1098
|
+
i0.ɵɵelementStart(1, "div", 210)(2, "div", 211);
|
|
1072
1099
|
i0.ɵɵtext(3);
|
|
1073
1100
|
i0.ɵɵelementEnd();
|
|
1074
|
-
i0.ɵɵconditionalCreate(4, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Template, 4, 1, "div",
|
|
1101
|
+
i0.ɵɵconditionalCreate(4, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Template, 4, 1, "div", 212);
|
|
1075
1102
|
i0.ɵɵelementEnd();
|
|
1076
|
-
i0.ɵɵelementStart(5, "div",
|
|
1103
|
+
i0.ɵɵelementStart(5, "div", 213)(6, "div", 214)(7, "span", 215);
|
|
1077
1104
|
i0.ɵɵtext(8);
|
|
1078
1105
|
i0.ɵɵelementEnd();
|
|
1079
|
-
i0.ɵɵelementStart(9, "span",
|
|
1106
|
+
i0.ɵɵelementStart(9, "span", 216);
|
|
1080
1107
|
i0.ɵɵtext(10, "Runs");
|
|
1081
1108
|
i0.ɵɵelementEnd()();
|
|
1082
|
-
i0.ɵɵconditionalCreate(11, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_11_Template, 5, 5, "div",
|
|
1083
|
-
i0.ɵɵconditionalCreate(12, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_12_Template, 5, 1, "div",
|
|
1084
|
-
i0.ɵɵelementStart(13, "div",
|
|
1109
|
+
i0.ɵɵconditionalCreate(11, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_11_Template, 5, 5, "div", 214);
|
|
1110
|
+
i0.ɵɵconditionalCreate(12, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_12_Template, 5, 1, "div", 214);
|
|
1111
|
+
i0.ɵɵelementStart(13, "div", 214)(14, "span", 215);
|
|
1085
1112
|
i0.ɵɵtext(15);
|
|
1086
1113
|
i0.ɵɵelementEnd();
|
|
1087
|
-
i0.ɵɵelementStart(16, "span",
|
|
1114
|
+
i0.ɵɵelementStart(16, "span", 216);
|
|
1088
1115
|
i0.ɵɵtext(17, "Avg Duration");
|
|
1089
1116
|
i0.ɵɵelementEnd()();
|
|
1090
|
-
i0.ɵɵelementStart(18, "div",
|
|
1117
|
+
i0.ɵɵelementStart(18, "div", 214)(19, "span", 215);
|
|
1091
1118
|
i0.ɵɵtext(20);
|
|
1092
1119
|
i0.ɵɵelementEnd();
|
|
1093
|
-
i0.ɵɵelementStart(21, "span",
|
|
1120
|
+
i0.ɵɵelementStart(21, "span", 216);
|
|
1094
1121
|
i0.ɵɵtext(22, "Avg Cost");
|
|
1095
1122
|
i0.ɵɵelementEnd()();
|
|
1096
|
-
i0.ɵɵconditionalCreate(23, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_23_Template, 5, 1, "div",
|
|
1123
|
+
i0.ɵɵconditionalCreate(23, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_23_Template, 5, 1, "div", 214);
|
|
1097
1124
|
i0.ɵɵelementEnd();
|
|
1098
|
-
i0.ɵɵelement(24, "i",
|
|
1125
|
+
i0.ɵɵelement(24, "i", 217);
|
|
1099
1126
|
i0.ɵɵelementEnd();
|
|
1100
1127
|
} if (rf & 2) {
|
|
1101
|
-
const
|
|
1128
|
+
const suite_r20 = ctx.$implicit;
|
|
1102
1129
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
1103
1130
|
i0.ɵɵadvance(3);
|
|
1104
|
-
i0.ɵɵtextInterpolate(
|
|
1131
|
+
i0.ɵɵtextInterpolate(suite_r20.suiteName);
|
|
1105
1132
|
i0.ɵɵadvance();
|
|
1106
|
-
i0.ɵɵconditional(
|
|
1133
|
+
i0.ɵɵconditional(suite_r20.tags.length > 0 ? 4 : -1);
|
|
1107
1134
|
i0.ɵɵadvance(4);
|
|
1108
|
-
i0.ɵɵtextInterpolate(
|
|
1135
|
+
i0.ɵɵtextInterpolate(suite_r20.totalRuns);
|
|
1109
1136
|
i0.ɵɵadvance(3);
|
|
1110
1137
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 11 : -1);
|
|
1111
1138
|
i0.ɵɵadvance();
|
|
1112
1139
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 12 : -1);
|
|
1113
1140
|
i0.ɵɵadvance(3);
|
|
1114
|
-
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(
|
|
1141
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(suite_r20.avgDuration));
|
|
1115
1142
|
i0.ɵɵadvance(5);
|
|
1116
|
-
i0.ɵɵtextInterpolate(ctx_r0.formatCost(
|
|
1143
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatCost(suite_r20.avgCost));
|
|
1117
1144
|
i0.ɵɵadvance(3);
|
|
1118
|
-
i0.ɵɵconditional(
|
|
1145
|
+
i0.ɵɵconditional(suite_r20.lastRun ? 23 : -1);
|
|
1119
1146
|
} }
|
|
1120
1147
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
1121
|
-
i0.ɵɵelementStart(0, "div",
|
|
1148
|
+
i0.ɵɵelementStart(0, "div", 181)(1, "h3");
|
|
1122
1149
|
i0.ɵɵelement(2, "i", 33);
|
|
1123
1150
|
i0.ɵɵtext(3, " Performance by Suite");
|
|
1124
1151
|
i0.ɵɵelementEnd();
|
|
1125
|
-
i0.ɵɵelementStart(4, "div",
|
|
1126
|
-
i0.ɵɵrepeaterCreate(5, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template, 25, 8, "div",
|
|
1152
|
+
i0.ɵɵelementStart(4, "div", 207);
|
|
1153
|
+
i0.ɵɵrepeaterCreate(5, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template, 25, 8, "div", 208, i0.ɵɵrepeaterTrackByIdentity);
|
|
1127
1154
|
i0.ɵɵelementEnd()();
|
|
1128
1155
|
} if (rf & 2) {
|
|
1129
1156
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
@@ -1131,41 +1158,41 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
|
|
|
1131
1158
|
i0.ɵɵrepeater(ctx_r0.suitePerformance);
|
|
1132
1159
|
} }
|
|
1133
1160
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
1134
|
-
const
|
|
1135
|
-
i0.ɵɵelementStart(0, "mj-empty-state",
|
|
1136
|
-
i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(
|
|
1161
|
+
const _r22 = i0.ɵɵgetCurrentView();
|
|
1162
|
+
i0.ɵɵelementStart(0, "mj-empty-state", 221);
|
|
1163
|
+
i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(_r22); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.runTest()); });
|
|
1137
1164
|
i0.ɵɵelementEnd();
|
|
1138
1165
|
} }
|
|
1139
1166
|
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
1140
|
-
const
|
|
1141
|
-
i0.ɵɵelementStart(0, "div",
|
|
1167
|
+
const _r17 = i0.ɵɵgetCurrentView();
|
|
1168
|
+
i0.ɵɵelementStart(0, "div", 172)(1, "div", 174)(2, "div", 175)(3, "span", 176);
|
|
1142
1169
|
i0.ɵɵtext(4, "Time Range:");
|
|
1143
1170
|
i0.ɵɵelementEnd();
|
|
1144
|
-
i0.ɵɵelementStart(5, "button",
|
|
1145
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(
|
|
1171
|
+
i0.ɵɵelementStart(5, "button", 177);
|
|
1172
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("7d")); });
|
|
1146
1173
|
i0.ɵɵtext(6, "7 Days");
|
|
1147
1174
|
i0.ɵɵelementEnd();
|
|
1148
|
-
i0.ɵɵelementStart(7, "button",
|
|
1149
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(
|
|
1175
|
+
i0.ɵɵelementStart(7, "button", 177);
|
|
1176
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("30d")); });
|
|
1150
1177
|
i0.ɵɵtext(8, "30 Days");
|
|
1151
1178
|
i0.ɵɵelementEnd();
|
|
1152
|
-
i0.ɵɵelementStart(9, "button",
|
|
1153
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(
|
|
1179
|
+
i0.ɵɵelementStart(9, "button", 177);
|
|
1180
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("90d")); });
|
|
1154
1181
|
i0.ɵɵtext(10, "90 Days");
|
|
1155
1182
|
i0.ɵɵelementEnd();
|
|
1156
|
-
i0.ɵɵelementStart(11, "button",
|
|
1157
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(
|
|
1183
|
+
i0.ɵɵelementStart(11, "button", 177);
|
|
1184
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("all")); });
|
|
1158
1185
|
i0.ɵɵtext(12, "All Time");
|
|
1159
1186
|
i0.ɵɵelementEnd()();
|
|
1160
|
-
i0.ɵɵelementStart(13, "div",
|
|
1161
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(
|
|
1162
|
-
i0.ɵɵelement(15, "i",
|
|
1187
|
+
i0.ɵɵelementStart(13, "div", 178)(14, "button", 23);
|
|
1188
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.exportHistoryToCSV()); });
|
|
1189
|
+
i0.ɵɵelement(15, "i", 179);
|
|
1163
1190
|
i0.ɵɵtext(16, " Export CSV ");
|
|
1164
1191
|
i0.ɵɵelementEnd()()();
|
|
1165
|
-
i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Template, 27, 5, "div",
|
|
1166
|
-
i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Template, 23, 4, "div",
|
|
1167
|
-
i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_Template, 7, 0, "div",
|
|
1168
|
-
i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template, 1, 0, "mj-empty-state",
|
|
1192
|
+
i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Template, 27, 5, "div", 180);
|
|
1193
|
+
i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Template, 23, 4, "div", 181);
|
|
1194
|
+
i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_Template, 7, 0, "div", 181);
|
|
1195
|
+
i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template, 1, 0, "mj-empty-state", 182);
|
|
1169
1196
|
i0.ɵɵelementEnd();
|
|
1170
1197
|
} if (rf & 2) {
|
|
1171
1198
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -1190,8 +1217,8 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template(rf, c
|
|
|
1190
1217
|
} }
|
|
1191
1218
|
function MJTestFormComponentExtended_Conditional_67_Template(rf, ctx) { if (rf & 1) {
|
|
1192
1219
|
i0.ɵɵelementStart(0, "div", 40);
|
|
1193
|
-
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_1_Template, 2, 0, "div",
|
|
1194
|
-
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_67_Conditional_2_Template, 21, 13, "div",
|
|
1220
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_1_Template, 2, 0, "div", 125);
|
|
1221
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_67_Conditional_2_Template, 21, 13, "div", 172);
|
|
1195
1222
|
i0.ɵɵelementEnd();
|
|
1196
1223
|
} if (rf & 2) {
|
|
1197
1224
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -1201,45 +1228,45 @@ function MJTestFormComponentExtended_Conditional_67_Template(rf, ctx) { if (rf &
|
|
|
1201
1228
|
i0.ɵɵconditional(!ctx_r0.loadingHistory && ctx_r0.historyLoaded ? 2 : -1);
|
|
1202
1229
|
} }
|
|
1203
1230
|
function MJTestFormComponentExtended_Conditional_70_Template(rf, ctx) { if (rf & 1) {
|
|
1204
|
-
const
|
|
1205
|
-
i0.ɵɵelementStart(0, "div", 43)(1, "div",
|
|
1231
|
+
const _r23 = i0.ɵɵgetCurrentView();
|
|
1232
|
+
i0.ɵɵelementStart(0, "div", 43)(1, "div", 222);
|
|
1206
1233
|
i0.ɵɵelement(2, "i", 42);
|
|
1207
1234
|
i0.ɵɵtext(3, " Shortcuts ");
|
|
1208
|
-
i0.ɵɵelementStart(4, "button",
|
|
1209
|
-
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_70_Template_button_click_4_listener() { i0.ɵɵrestoreView(
|
|
1210
|
-
i0.ɵɵelement(5, "i",
|
|
1235
|
+
i0.ɵɵelementStart(4, "button", 223);
|
|
1236
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_70_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r23); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.toggleShortcuts()); });
|
|
1237
|
+
i0.ɵɵelement(5, "i", 124);
|
|
1211
1238
|
i0.ɵɵelementEnd()();
|
|
1212
|
-
i0.ɵɵelementStart(6, "div",
|
|
1239
|
+
i0.ɵɵelementStart(6, "div", 224)(7, "div", 225)(8, "span");
|
|
1213
1240
|
i0.ɵɵtext(9, "Save changes");
|
|
1214
1241
|
i0.ɵɵelementEnd();
|
|
1215
|
-
i0.ɵɵelementStart(10, "span",
|
|
1242
|
+
i0.ɵɵelementStart(10, "span", 226)(11, "kbd");
|
|
1216
1243
|
i0.ɵɵtext(12, "Cmd");
|
|
1217
1244
|
i0.ɵɵelementEnd();
|
|
1218
1245
|
i0.ɵɵelementStart(13, "kbd");
|
|
1219
1246
|
i0.ɵɵtext(14, "S");
|
|
1220
1247
|
i0.ɵɵelementEnd()()();
|
|
1221
|
-
i0.ɵɵelementStart(15, "div",
|
|
1248
|
+
i0.ɵɵelementStart(15, "div", 225)(16, "span");
|
|
1222
1249
|
i0.ɵɵtext(17, "Refresh");
|
|
1223
1250
|
i0.ɵɵelementEnd();
|
|
1224
|
-
i0.ɵɵelementStart(18, "span",
|
|
1251
|
+
i0.ɵɵelementStart(18, "span", 226)(19, "kbd");
|
|
1225
1252
|
i0.ɵɵtext(20, "Cmd");
|
|
1226
1253
|
i0.ɵɵelementEnd();
|
|
1227
1254
|
i0.ɵɵelementStart(21, "kbd");
|
|
1228
1255
|
i0.ɵɵtext(22, "R");
|
|
1229
1256
|
i0.ɵɵelementEnd()()();
|
|
1230
|
-
i0.ɵɵelementStart(23, "div",
|
|
1257
|
+
i0.ɵɵelementStart(23, "div", 225)(24, "span");
|
|
1231
1258
|
i0.ɵɵtext(25, "Run Test");
|
|
1232
1259
|
i0.ɵɵelementEnd();
|
|
1233
|
-
i0.ɵɵelementStart(26, "span",
|
|
1260
|
+
i0.ɵɵelementStart(26, "span", 226)(27, "kbd");
|
|
1234
1261
|
i0.ɵɵtext(28, "Cmd");
|
|
1235
1262
|
i0.ɵɵelementEnd();
|
|
1236
1263
|
i0.ɵɵelementStart(29, "kbd");
|
|
1237
1264
|
i0.ɵɵtext(30, "Enter");
|
|
1238
1265
|
i0.ɵɵelementEnd()()();
|
|
1239
|
-
i0.ɵɵelementStart(31, "div",
|
|
1266
|
+
i0.ɵɵelementStart(31, "div", 225)(32, "span");
|
|
1240
1267
|
i0.ɵɵtext(33, "Switch Tabs");
|
|
1241
1268
|
i0.ɵɵelementEnd();
|
|
1242
|
-
i0.ɵɵelementStart(34, "span",
|
|
1269
|
+
i0.ɵɵelementStart(34, "span", 226)(35, "kbd");
|
|
1243
1270
|
i0.ɵɵtext(36, "1");
|
|
1244
1271
|
i0.ɵɵelementEnd();
|
|
1245
1272
|
i0.ɵɵtext(37, "-");
|
|
@@ -1248,11 +1275,11 @@ function MJTestFormComponentExtended_Conditional_70_Template(rf, ctx) { if (rf &
|
|
|
1248
1275
|
i0.ɵɵelementEnd()()()()();
|
|
1249
1276
|
} }
|
|
1250
1277
|
function MJTestFormComponentExtended_Conditional_71_Template(rf, ctx) { if (rf & 1) {
|
|
1251
|
-
const
|
|
1252
|
-
i0.ɵɵelementStart(0, "mj-slide-panel",
|
|
1253
|
-
i0.ɵɵlistener("Closed", function MJTestFormComponentExtended_Conditional_71_Template_mj_slide_panel_Closed_0_listener() { i0.ɵɵrestoreView(
|
|
1254
|
-
i0.ɵɵelementStart(1, "app-test-run-dialog",
|
|
1255
|
-
i0.ɵɵlistener("PanelClose", function MJTestFormComponentExtended_Conditional_71_Template_app_test_run_dialog_PanelClose_1_listener() { i0.ɵɵrestoreView(
|
|
1278
|
+
const _r24 = i0.ɵɵgetCurrentView();
|
|
1279
|
+
i0.ɵɵelementStart(0, "mj-slide-panel", 227);
|
|
1280
|
+
i0.ɵɵlistener("Closed", function MJTestFormComponentExtended_Conditional_71_Template_mj_slide_panel_Closed_0_listener() { i0.ɵɵrestoreView(_r24); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
|
|
1281
|
+
i0.ɵɵelementStart(1, "app-test-run-dialog", 228);
|
|
1282
|
+
i0.ɵɵlistener("PanelClose", function MJTestFormComponentExtended_Conditional_71_Template_app_test_run_dialog_PanelClose_1_listener() { i0.ɵɵrestoreView(_r24); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
|
|
1256
1283
|
i0.ɵɵelementEnd()();
|
|
1257
1284
|
} if (rf & 2) {
|
|
1258
1285
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -1273,13 +1300,13 @@ function MJTestFormComponentExtended_Conditional_81_Template(rf, ctx) { if (rf &
|
|
|
1273
1300
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.dirtyFieldNames.length, " fields edited ");
|
|
1274
1301
|
} }
|
|
1275
1302
|
function MJTestFormComponentExtended_Conditional_84_Template(rf, ctx) { if (rf & 1) {
|
|
1276
|
-
i0.ɵɵelement(0, "i",
|
|
1303
|
+
i0.ɵɵelement(0, "i", 229);
|
|
1277
1304
|
i0.ɵɵtext(1, " Saving\u2026 ");
|
|
1278
1305
|
} }
|
|
1279
1306
|
function MJTestFormComponentExtended_Conditional_85_Template(rf, ctx) { if (rf & 1) {
|
|
1280
|
-
i0.ɵɵelement(0, "i",
|
|
1307
|
+
i0.ɵɵelement(0, "i", 230);
|
|
1281
1308
|
i0.ɵɵtext(1, " Save changes ");
|
|
1282
|
-
i0.ɵɵelementStart(2, "span",
|
|
1309
|
+
i0.ɵɵelementStart(2, "span", 231)(3, "kbd");
|
|
1283
1310
|
i0.ɵɵtext(4, "\u2318");
|
|
1284
1311
|
i0.ɵɵelementEnd();
|
|
1285
1312
|
i0.ɵɵelementStart(5, "kbd");
|
|
@@ -1336,6 +1363,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1336
1363
|
// Edit state
|
|
1337
1364
|
this.IsSaving = false;
|
|
1338
1365
|
this.TestTypeOptions = [];
|
|
1366
|
+
this.RubricOptions = [];
|
|
1339
1367
|
this.TagDraft = '';
|
|
1340
1368
|
this.StatusOptions = ['Active', 'Pending', 'Disabled'];
|
|
1341
1369
|
}
|
|
@@ -1557,6 +1585,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1557
1585
|
this.loadShortcutsSetting();
|
|
1558
1586
|
// Fire-and-forget: test type list for the edit form
|
|
1559
1587
|
this.loadTestTypeOptions();
|
|
1588
|
+
void this.loadRubricOptions();
|
|
1560
1589
|
// Subscribe to evaluation preferences
|
|
1561
1590
|
this.evalPrefsService.preferences$
|
|
1562
1591
|
.pipe(takeUntil(this.destroy$))
|
|
@@ -1575,6 +1604,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1575
1604
|
}
|
|
1576
1605
|
}
|
|
1577
1606
|
ngOnDestroy() {
|
|
1607
|
+
super.ngOnDestroy();
|
|
1578
1608
|
this.destroy$.next();
|
|
1579
1609
|
this.destroy$.complete();
|
|
1580
1610
|
}
|
|
@@ -2420,6 +2450,18 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
2420
2450
|
get tags() {
|
|
2421
2451
|
return TagsHelper.parseTags(this.record?.Tags);
|
|
2422
2452
|
}
|
|
2453
|
+
/** Active rubrics for the RubricID picker. */
|
|
2454
|
+
async loadRubricOptions() {
|
|
2455
|
+
try {
|
|
2456
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
2457
|
+
const result = await rv.RunView({ EntityName: 'MJ: Rubrics', ExtraFilter: `Status='Active'`, OrderBy: 'Name', ResultType: 'simple', MaxRows: 500 });
|
|
2458
|
+
this.RubricOptions = RubricPickerOptions((result.Results ?? []));
|
|
2459
|
+
this.cdr.markForCheck();
|
|
2460
|
+
}
|
|
2461
|
+
catch (error) {
|
|
2462
|
+
console.warn('Failed to load rubric options:', error);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2423
2465
|
/** Load test types for the Type dropdown. */
|
|
2424
2466
|
async loadTestTypeOptions() {
|
|
2425
2467
|
try {
|
|
@@ -2535,7 +2577,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
2535
2577
|
static { this.ɵfac = /*@__PURE__*/ (() => { let ɵMJTestFormComponentExtended_BaseFactory; return function MJTestFormComponentExtended_Factory(__ngFactoryType__) { return (ɵMJTestFormComponentExtended_BaseFactory || (ɵMJTestFormComponentExtended_BaseFactory = i0.ɵɵgetInheritedFactory(MJTestFormComponentExtended)))(__ngFactoryType__ || MJTestFormComponentExtended); }; })(); }
|
|
2536
2578
|
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJTestFormComponentExtended, selectors: [["mj-test-form"]], hostBindings: function MJTestFormComponentExtended_HostBindings(rf, ctx) { if (rf & 1) {
|
|
2537
2579
|
i0.ɵɵlistener("keydown", function MJTestFormComponentExtended_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, i0.ɵɵresolveDocument)("beforeunload", function MJTestFormComponentExtended_beforeunload_HostBindingHandler($event) { return ctx.handleBeforeUnload($event); }, i0.ɵɵresolveWindow);
|
|
2538
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 89, vars: 51, consts: [["tagInput", ""], [1, "test-form"], [1, "test-header"], ["aria-label", "Breadcrumb", 1, "breadcrumb"], ["href", "javascript:void(0)", 3, "click"], [1, "fas", "fa-vial"], [1, "breadcrumb-text"], [1, "current"], [1, "fas", "fa-chevron-right", "separator"], [1, "fas", "fa-flask"], [1, "header-content"], [1, "header-left"], [1, "test-icon"], [1, "test-info"], ["title", "You have unsaved changes", "aria-label", "Unsaved changes", 1, "dirty-indicator"], [1, "test-meta"], [1, "status-badge", 3, "ngClass"], [1, "fas", 3, "ngClass"], [1, "test-type"], ["title", "You have unsaved changes", 1, "unsaved-pill"], [1, "header-actions"], ["mjButton", "", "variant", "primary", 3, "click"], [1, "fas", "fa-play"], ["mjButton", "", 3, "click", "disabled"], [1, "test-description"], [1, "metrics-bar"], [1, "tabs-container"], ["role", "tablist", 1, "tabs"], ["role", "tab", 1, "tab", 3, "click"], [1, "fas", "fa-th-large"], [1, "fas", "fa-sliders-h"], [1, "fas", "fa-history"], [1, "tab-badge"], [1, "fas", "fa-layer-group"], [1, "fas", "fa-chart-line"], [1, "tab-content"], [1, "overview-tab"], [1, "config-tab"], [1, "runs-tab"], [1, "suites-tab"], [1, "history-tab"], [1, "shortcuts-toggle", 3, "click", "title"], [1, "fas", "fa-keyboard"], [1, "keyboard-shortcuts"], ["Mode", "slide", 3, "Title", "Resizable"], ["role", "region", "aria-label", "Unsaved changes", 1, "save-bar"], [1, "save-bar-message"], ["aria-hidden", "true", 1, "save-bar-dot"], [1, "save-bar-text"], [1, "save-bar-fields"], [1, "save-bar-actions"], ["type", "button", "title", "Save changes (\u2318S)", 1, "save-bar-btn", "save-bar-btn--primary", 3, "click", "disabled"], ["type", "button", "title", "Discard changes", 1, "save-bar-btn", "save-bar-btn--ghost", 3, "click", "disabled"], [1, "fas", "fa-undo"], [1, "fas", "fa-tag"], [1, "fas", "fa-circle"], [1, "metric-card"], [1, "metric-label"], [1, "metric-value"], [1, "metric-progress"], [1, "metric-progress-fill"], [1, "info-section"], [1, "fas", "fa-info-circle"], [1, "info-grid"], [1, "info-item"], [1, "info-label"], [1, "info-value"], [1, "status-badge-inline", 3, "ngClass"], [1, "json-section"], [1, "fas", "fa-code"], [1, "json-tabs"], [1, "json-tab", 3, "click"], [1, "fas", "fa-sign-in-alt"], [1, "fas", "fa-check-double"], [1, "fas", "fa-cog"], [1, "fas", "fa-tags"], [1, "code-editor-container"], ["language", "json", 3, "value", "readonly", "toolbar", "lineWrapping"], [1, "edit-section"], [1, "edit-section-header"], [1, "fas", "fa-pen-to-square"], [1, "edit-section-sub"], [1, "edit-grid"], [1, "edit-field", "edit-field--full"], ["for", "test-name"], [1, "required"], ["id", "test-name", "type", "text", "placeholder", "e.g., Agent Response Quality Test", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-description"], ["id", "test-description", "rows", "3", "placeholder", "What does this test evaluate?", 1, "config-input", "config-textarea", 3, "ngModelChange", "ngModel"], [1, "edit-field"], ["for", "test-status"], [1, "select-wrapper"], ["id", "test-status", 1, "config-input", 3, "ngModelChange", "ngModel"], [3, "ngValue"], ["for", "test-type"], ["id", "test-type", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-tags"], [1, "tag-editor", 3, "click"], [1, "tag-chip-editable"], ["id", "test-tags", "type", "text", 1, "tag-input-inline", 3, "ngModelChange", "keydown", "blur", "placeholder", "ngModel"], [1, "config-hint"], [1, "fas", "fa-cogs"], ["for", "test-priority"], ["id", "test-priority", "type", "number", "placeholder", "0 (lower runs first)", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-repeat"], ["id", "test-repeat", "type", "number", "min", "1", "placeholder", "1", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-duration"], ["id", "test-duration", "type", "number", "placeholder", "0", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-cost"], ["id", "test-cost", "type", "number", "step", "0.000001", "placeholder", "0.00", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-timeout"], ["id", "test-timeout", "type", "number", "placeholder", "Default: 300000 (5 min)", 1, "config-input", 3, "ngModelChange", "ngModel"], [1, "config-section"], [1, "config-editor-container"], ["language", "json", 3, "change", "value", "readonly", "lineWrapping"], [1, "meta-section"], [1, "meta-grid"], [1, "meta-item"], [1, "meta-label"], [1, "meta-value"], [1, "meta-value", "meta-mono"], ["type", "button", 1, "tag-remove", 3, "click"], [1, "fas", "fa-times"], [1, "loading-state"], [1, "runs-list"], ["Icon", "fa-solid fa-circle-play", "Title", "No Test Runs Yet", "Message", "Run this test to see execution history and results here.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play"], [1, "skeleton-list"], [1, "skeleton-card"], [1, "skeleton-icon"], [1, "skeleton-content"], [1, "skeleton-line", "wide"], [1, "skeleton-line", "narrow"], [1, "run-item"], [1, "run-item", 3, "click"], [1, "run-icon"], [1, "fas"], [1, "run-content"], [1, "run-header"], [1, "run-id"], [1, "run-status"], [1, "run-meta"], [1, "fas", "fa-calendar"], [3, "entityName", "recordId"], [1, "run-eval-stack"], [1, "eval-pill", "status-pill", 3, "ngClass", "title"], [1, "run-tags"], [1, "fas", "fa-chevron-right"], [1, "fas", "fa-clock"], [1, "fas", "fa-dollar-sign"], ["title", "Human Review: No rating submitted yet", 1, "eval-pill", "human-pill", "no-feedback"], [1, "eval-pill", "human-pill", "has-feedback", 3, "rating-low", "rating-medium", "rating-good", "rating-excellent", "title"], [1, "fas", "fa-user-slash"], [1, "eval-pill", "human-pill", "has-feedback", 3, "title"], [1, "fas", "fa-user"], ["title", "Auto Score: No automated score available", 1, "eval-pill", "auto-pill", "no-score"], [1, "eval-pill", "auto-pill", "has-score", 3, "score-low", "score-medium", "score-good", "score-excellent", "title"], [1, "fas", "fa-robot"], [1, "eval-pill", "auto-pill", "has-score", 3, "title"], [1, "run-tag"], [1, "run-tag-more"], ["Icon", "fa-solid fa-circle-play", "Title", "No Test Runs Yet", "Message", "Run this test to see execution history and results here.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play", 3, "Action"], [1, "suites-list"], ["Icon", "fa-solid fa-folder-open", "Title", "Not Part of Any Suite", "Message", "This test is not included in any test suites. Add it to a suite to run it with other tests."], [1, "suite-item"], [1, "suite-item", 3, "click"], [1, "suite-icon"], [1, "suite-content"], [1, "suite-name"], [1, "suite-meta"], [1, "fas", "fa-sort-numeric-up"], [1, "history-content"], ["text", "Loading history..."], [1, "history-filters"], [1, "time-range-filters"], [1, "filter-label"], [1, "filter-btn", 3, "click"], [1, "history-actions"], [1, "fas", "fa-download"], [1, "history-kpi-cards"], [1, "history-section"], ["Icon", "fa-solid fa-chart-line", "Title", "No History Available", "Message", "Run this test to start building history and analytics data.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play"], [1, "kpi-card"], [1, "kpi-icon"], [1, "fas", "fa-play-circle"], [1, "kpi-content"], [1, "kpi-value"], [1, "kpi-label"], [1, "kpi-icon", "pass-rate"], [1, "fas", "fa-percentage"], [1, "fas", "trend-icon"], [1, "fas", "fa-star"], [1, "fas", "fa-calendar-alt"], [1, "history-table-container"], [1, "history-table"], [1, "date-cell"], [1, "runs-cell"], [1, "passed-cell"], [1, "failed-cell"], [1, "pass-rate-cell"], [1, "score-cell"], [1, "duration-cell"], [1, "cost-cell"], [1, "pass-rate-bar"], [1, "pass-rate-fill"], [1, "pass-rate-text"], [1, "suite-performance-list"], [1, "suite-perf-card"], [1, "suite-perf-card", 3, "click"], [1, "suite-perf-header"], [1, "suite-perf-name"], [1, "suite-perf-tags"], [1, "suite-perf-stats"], [1, "suite-stat"], [1, "stat-value"], [1, "stat-label"], [1, "fas", "fa-chevron-right", "suite-perf-arrow"], [1, "tag-mini"], [1, "tag-more"], [1, "stat-value", "pass-rate"], ["Icon", "fa-solid fa-chart-line", "Title", "No History Available", "Message", "Run this test to start building history and analytics data.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play", 3, "Action"], [1, "shortcuts-header"], ["title", "Hide shortcuts", 1, "shortcuts-close", 3, "click"], [1, "shortcut-list"], [1, "shortcut-item"], [1, "shortcut-keys"], ["Mode", "slide", 3, "Closed", "Title", "Resizable"], [3, "PanelClose", "PanelMode", "selectedTestId", "selectedSuiteId", "runMode"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-check"], [1, "save-bar-kbd"]], template: function MJTestFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
|
|
2580
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 89, vars: 51, consts: [["tagInput", ""], [1, "test-form"], [1, "test-header"], ["aria-label", "Breadcrumb", 1, "breadcrumb"], ["href", "javascript:void(0)", 3, "click"], [1, "fas", "fa-vial"], [1, "breadcrumb-text"], [1, "current"], [1, "fas", "fa-chevron-right", "separator"], [1, "fas", "fa-flask"], [1, "header-content"], [1, "header-left"], [1, "test-icon"], [1, "test-info"], ["title", "You have unsaved changes", "aria-label", "Unsaved changes", 1, "dirty-indicator"], [1, "test-meta"], [1, "status-badge", 3, "ngClass"], [1, "fas", 3, "ngClass"], [1, "test-type"], ["title", "You have unsaved changes", 1, "unsaved-pill"], [1, "header-actions"], ["mjButton", "", "variant", "primary", 3, "click"], [1, "fas", "fa-play"], ["mjButton", "", 3, "click", "disabled"], [1, "test-description"], [1, "metrics-bar"], [1, "tabs-container"], ["role", "tablist", 1, "tabs"], ["role", "tab", 1, "tab", 3, "click"], [1, "fas", "fa-th-large"], [1, "fas", "fa-sliders-h"], [1, "fas", "fa-history"], [1, "tab-badge"], [1, "fas", "fa-layer-group"], [1, "fas", "fa-chart-line"], [1, "tab-content"], [1, "overview-tab"], [1, "config-tab"], [1, "runs-tab"], [1, "suites-tab"], [1, "history-tab"], [1, "shortcuts-toggle", 3, "click", "title"], [1, "fas", "fa-keyboard"], [1, "keyboard-shortcuts"], ["Mode", "slide", 3, "Title", "Resizable"], ["role", "region", "aria-label", "Unsaved changes", 1, "save-bar"], [1, "save-bar-message"], ["aria-hidden", "true", 1, "save-bar-dot"], [1, "save-bar-text"], [1, "save-bar-fields"], [1, "save-bar-actions"], ["type", "button", "title", "Save changes (\u2318S)", 1, "save-bar-btn", "save-bar-btn--primary", 3, "click", "disabled"], ["type", "button", "title", "Discard changes", 1, "save-bar-btn", "save-bar-btn--ghost", 3, "click", "disabled"], [1, "fas", "fa-undo"], [1, "fas", "fa-tag"], [1, "fas", "fa-circle"], [1, "metric-card"], [1, "metric-label"], [1, "metric-value"], [1, "metric-progress"], [1, "metric-progress-fill"], [1, "info-section"], [1, "fas", "fa-info-circle"], [1, "info-grid"], [1, "info-item"], [1, "info-label"], [1, "info-value"], [1, "status-badge-inline", 3, "ngClass"], [1, "json-section"], [1, "fas", "fa-code"], [1, "json-tabs"], [1, "json-tab", 3, "click"], [1, "fas", "fa-sign-in-alt"], [1, "fas", "fa-check-double"], [1, "fas", "fa-cog"], [1, "fas", "fa-tags"], [1, "code-editor-container"], ["language", "json", 3, "value", "readonly", "toolbar", "lineWrapping"], [1, "edit-section"], [1, "edit-section-header"], [1, "fas", "fa-pen-to-square"], [1, "edit-section-sub"], [1, "edit-grid"], [1, "edit-field", "edit-field--full"], ["for", "test-name"], [1, "required"], ["id", "test-name", "type", "text", "placeholder", "e.g., Agent Response Quality Test", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-description"], ["id", "test-description", "rows", "3", "placeholder", "What does this test evaluate?", 1, "config-input", "config-textarea", 3, "ngModelChange", "ngModel"], [1, "edit-field"], ["for", "test-status"], [1, "select-wrapper"], ["id", "test-status", 1, "config-input", 3, "ngModelChange", "ngModel"], [3, "ngValue"], ["for", "test-rubric"], ["id", "test-rubric", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-type"], ["id", "test-type", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-tags"], [1, "tag-editor", 3, "click"], [1, "tag-chip-editable"], ["id", "test-tags", "type", "text", 1, "tag-input-inline", 3, "ngModelChange", "keydown", "blur", "placeholder", "ngModel"], [1, "config-hint"], [1, "fas", "fa-cogs"], ["for", "test-priority"], ["id", "test-priority", "type", "number", "placeholder", "0 (lower runs first)", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-repeat"], ["id", "test-repeat", "type", "number", "min", "1", "placeholder", "1", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-duration"], ["id", "test-duration", "type", "number", "placeholder", "0", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-cost"], ["id", "test-cost", "type", "number", "step", "0.000001", "placeholder", "0.00", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-timeout"], ["id", "test-timeout", "type", "number", "placeholder", "Default: 300000 (5 min)", 1, "config-input", 3, "ngModelChange", "ngModel"], [1, "config-section"], [1, "config-editor-container"], ["language", "json", 3, "change", "value", "readonly", "lineWrapping"], [1, "meta-section"], [1, "meta-grid"], [1, "meta-item"], [1, "meta-label"], [1, "meta-value"], [1, "meta-value", "meta-mono"], ["type", "button", 1, "tag-remove", 3, "click"], [1, "fas", "fa-times"], [1, "loading-state"], [1, "runs-list"], ["Icon", "fa-solid fa-circle-play", "Title", "No Test Runs Yet", "Message", "Run this test to see execution history and results here.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play"], [1, "skeleton-list"], [1, "skeleton-card"], [1, "skeleton-icon"], [1, "skeleton-content"], [1, "skeleton-line", "wide"], [1, "skeleton-line", "narrow"], [1, "run-item"], [1, "run-item", 3, "click"], [1, "run-icon"], [1, "fas"], [1, "run-content"], [1, "run-header"], [1, "run-id"], [1, "run-status"], [1, "run-meta"], [1, "fas", "fa-calendar"], [3, "entityName", "recordId"], [1, "run-eval-stack"], [1, "eval-pill", "status-pill", 3, "ngClass", "title"], [1, "run-tags"], [1, "fas", "fa-chevron-right"], [1, "fas", "fa-clock"], [1, "fas", "fa-dollar-sign"], ["title", "Human Review: No rating submitted yet", 1, "eval-pill", "human-pill", "no-feedback"], [1, "eval-pill", "human-pill", "has-feedback", 3, "rating-low", "rating-medium", "rating-good", "rating-excellent", "title"], [1, "fas", "fa-user-slash"], [1, "eval-pill", "human-pill", "has-feedback", 3, "title"], [1, "fas", "fa-user"], ["title", "Auto Score: No automated score available", 1, "eval-pill", "auto-pill", "no-score"], [1, "eval-pill", "auto-pill", "has-score", 3, "score-low", "score-medium", "score-good", "score-excellent", "title"], [1, "fas", "fa-robot"], [1, "eval-pill", "auto-pill", "has-score", 3, "title"], [1, "run-tag"], [1, "run-tag-more"], ["Icon", "fa-solid fa-circle-play", "Title", "No Test Runs Yet", "Message", "Run this test to see execution history and results here.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play", 3, "Action"], [1, "suites-list"], ["Icon", "fa-solid fa-folder-open", "Title", "Not Part of Any Suite", "Message", "This test is not included in any test suites. Add it to a suite to run it with other tests."], [1, "suite-item"], [1, "suite-item", 3, "click"], [1, "suite-icon"], [1, "suite-content"], [1, "suite-name"], [1, "suite-meta"], [1, "fas", "fa-sort-numeric-up"], [1, "history-content"], ["text", "Loading history..."], [1, "history-filters"], [1, "time-range-filters"], [1, "filter-label"], [1, "filter-btn", 3, "click"], [1, "history-actions"], [1, "fas", "fa-download"], [1, "history-kpi-cards"], [1, "history-section"], ["Icon", "fa-solid fa-chart-line", "Title", "No History Available", "Message", "Run this test to start building history and analytics data.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play"], [1, "kpi-card"], [1, "kpi-icon"], [1, "fas", "fa-play-circle"], [1, "kpi-content"], [1, "kpi-value"], [1, "kpi-label"], [1, "kpi-icon", "pass-rate"], [1, "fas", "fa-percentage"], [1, "fas", "trend-icon"], [1, "fas", "fa-star"], [1, "fas", "fa-calendar-alt"], [1, "history-table-container"], [1, "history-table"], [1, "date-cell"], [1, "runs-cell"], [1, "passed-cell"], [1, "failed-cell"], [1, "pass-rate-cell"], [1, "score-cell"], [1, "duration-cell"], [1, "cost-cell"], [1, "pass-rate-bar"], [1, "pass-rate-fill"], [1, "pass-rate-text"], [1, "suite-performance-list"], [1, "suite-perf-card"], [1, "suite-perf-card", 3, "click"], [1, "suite-perf-header"], [1, "suite-perf-name"], [1, "suite-perf-tags"], [1, "suite-perf-stats"], [1, "suite-stat"], [1, "stat-value"], [1, "stat-label"], [1, "fas", "fa-chevron-right", "suite-perf-arrow"], [1, "tag-mini"], [1, "tag-more"], [1, "stat-value", "pass-rate"], ["Icon", "fa-solid fa-chart-line", "Title", "No History Available", "Message", "Run this test to start building history and analytics data.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play", 3, "Action"], [1, "shortcuts-header"], ["title", "Hide shortcuts", 1, "shortcuts-close", 3, "click"], [1, "shortcut-list"], [1, "shortcut-item"], [1, "shortcut-keys"], ["Mode", "slide", 3, "Closed", "Title", "Resizable"], [3, "PanelClose", "PanelMode", "selectedTestId", "selectedSuiteId", "runMode"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-check"], [1, "save-bar-kbd"]], template: function MJTestFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
|
|
2539
2581
|
i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "nav", 3)(3, "ol")(4, "li")(5, "a", 4);
|
|
2540
2582
|
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_a_click_5_listener() { return ctx.navigateToTestingDashboard(); });
|
|
2541
2583
|
i0.ɵɵelement(6, "i", 5);
|
|
@@ -2612,7 +2654,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
2612
2654
|
i0.ɵɵelementEnd()()()();
|
|
2613
2655
|
i0.ɵɵelementStart(62, "div", 35);
|
|
2614
2656
|
i0.ɵɵconditionalCreate(63, MJTestFormComponentExtended_Conditional_63_Template, 78, 29, "div", 36);
|
|
2615
|
-
i0.ɵɵconditionalCreate(64, MJTestFormComponentExtended_Conditional_64_Template,
|
|
2657
|
+
i0.ɵɵconditionalCreate(64, MJTestFormComponentExtended_Conditional_64_Template, 119, 32, "div", 37);
|
|
2616
2658
|
i0.ɵɵconditionalCreate(65, MJTestFormComponentExtended_Conditional_65_Template, 4, 3, "div", 38);
|
|
2617
2659
|
i0.ɵɵconditionalCreate(66, MJTestFormComponentExtended_Conditional_66_Template, 4, 3, "div", 39);
|
|
2618
2660
|
i0.ɵɵconditionalCreate(67, MJTestFormComponentExtended_Conditional_67_Template, 3, 2, "div", 40);
|
|
@@ -2728,7 +2770,7 @@ MJTestFormComponentExtended = __decorate([
|
|
|
2728
2770
|
export { MJTestFormComponentExtended };
|
|
2729
2771
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJTestFormComponentExtended, [{
|
|
2730
2772
|
type: Component,
|
|
2731
|
-
args: [{ standalone: false, selector: 'mj-test-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-form\">\n <!-- Header Section -->\n <div class=\"test-header\">\n <!-- Breadcrumb Navigation -->\n <nav class=\"breadcrumb\" aria-label=\"Breadcrumb\">\n <ol>\n <li>\n <a href=\"javascript:void(0)\" (click)=\"navigateToTestingDashboard()\">\n <i class=\"fas fa-vial\"></i>\n <span class=\"breadcrumb-text\">Testing</span>\n </a>\n </li>\n <li class=\"current\">\n <i class=\"fas fa-chevron-right separator\"></i>\n <i class=\"fas fa-flask\"></i>\n <span>{{ record.Name }}</span>\n </li>\n </ol>\n </nav>\n\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"test-icon\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas fa-flask\"></i>\n </div>\n <div class=\"test-info\">\n <h1>\n {{ record.Name }}\n @if (isDirty) {\n <span class=\"dirty-indicator\" title=\"You have unsaved changes\" aria-label=\"Unsaved changes\">\u25CF</span>\n }\n </h1>\n <div class=\"test-meta\">\n <span class=\"status-badge\" [ngClass]=\"getStatusClass()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n {{ record.Status }}\n </span>\n @if (record.Type) {\n <span class=\"test-type\">\n <i class=\"fas fa-tag\"></i>\n {{ record.Type }}\n </span>\n }\n @if (isDirty) {\n <span class=\"unsaved-pill\" title=\"You have unsaved changes\">\n <i class=\"fas fa-circle\"></i> Unsaved\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <app-evaluation-mode-toggle></app-evaluation-mode-toggle>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test\n </button>\n <button mjButton (click)=\"refresh()\" [disabled]=\"isRefreshing\">\n <i class=\"fas\" [ngClass]=\"isRefreshing ? 'fa-sync fa-spin' : 'fa-sync'\"></i>\n {{ isRefreshing ? 'Refreshing...' : 'Refresh' }}\n </button>\n </div>\n </div>\n\n <!-- Test Description -->\n @if (record.Description) {\n <div class=\"test-description\">\n <p>{{ record.Description }}</p>\n </div>\n }\n\n <!-- Metrics Bar -->\n @if (testRunsLoaded && testRuns.length > 0) {\n <div class=\"metrics-bar\">\n <div class=\"metric-card\">\n <div class=\"metric-label\">Total Runs</div>\n <div class=\"metric-value\">{{ testRuns.length }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Pass Rate</div>\n <div class=\"metric-value\">{{ getPassRate().toFixed(1) }}%</div>\n <div class=\"metric-progress\">\n <div class=\"metric-progress-fill\" [style.width.%]=\"getPassRate()\"></div>\n </div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Cost</div>\n <div class=\"metric-value\">{{ formatCost(getAverageCost()) }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Duration</div>\n <div class=\"metric-value\">{{ formatDuration(getAverageDuration()) }}</div>\n </div>\n </div>\n }\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs-container\">\n <div class=\"tabs\" role=\"tablist\">\n <button class=\"tab\"\n [class.active]=\"activeTab === 'overview'\"\n (click)=\"changeTab('overview')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'overview'\">\n <i class=\"fas fa-th-large\"></i>\n <span>Overview</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'config'\"\n (click)=\"changeTab('config')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'config'\">\n <i class=\"fas fa-sliders-h\"></i>\n <span>Configuration</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'runs'\"\n (click)=\"changeTab('runs')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'runs'\">\n <i class=\"fas fa-history\"></i>\n <span>Runs</span>\n @if (testRunsLoaded) {\n <span class=\"tab-badge\">{{ testRuns.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'suites'\"\n (click)=\"changeTab('suites')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'suites'\">\n <i class=\"fas fa-layer-group\"></i>\n <span>Test Suites</span>\n @if (suiteTestsLoaded) {\n <span class=\"tab-badge\">{{ suiteTests.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'analytics'\"\n (click)=\"changeTab('analytics')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'analytics'\">\n <i class=\"fas fa-chart-line\"></i>\n <span>Analytics</span>\n </button>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\" [class.has-savebar]=\"isDirty\">\n <!-- Overview Tab -->\n @if (activeTab === 'overview') {\n <div class=\"overview-tab\">\n <!-- Basic Information -->\n <div class=\"info-section\">\n <h3><i class=\"fas fa-info-circle\"></i> Test Information</h3>\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <div class=\"info-label\">Name</div>\n <div class=\"info-value\">{{ record.Name }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Type</div>\n <div class=\"info-value\">{{ record.Type || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Status</div>\n <div class=\"info-value\">\n <span class=\"status-badge-inline\" [ngClass]=\"getStatusClass()\">{{ record.Status }}</span>\n </div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Priority</div>\n <div class=\"info-value\">{{ record.Priority || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Duration</div>\n <div class=\"info-value\">{{ record.EstimatedDurationSeconds ? formatDuration(record.EstimatedDurationSeconds) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Cost</div>\n <div class=\"info-value\">{{ record.EstimatedCostUSD ? formatCost(record.EstimatedCostUSD) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Repeat Count</div>\n <div class=\"info-value\">{{ record.RepeatCount || 1 }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Max Execution Time</div>\n <div class=\"info-value\">{{ formatTimeout(record.MaxExecutionTimeMS) }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Created</div>\n <div class=\"info-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Updated</div>\n <div class=\"info-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n </div>\n </div>\n <!-- JSON Data Views -->\n <div class=\"json-section\">\n <h3><i class=\"fas fa-code\"></i> Test Definition</h3>\n <div class=\"json-tabs\">\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'input'\"\n (click)=\"setJsonView('input')\">\n <i class=\"fas fa-sign-in-alt\"></i>\n Input Definition\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'expected'\"\n (click)=\"setJsonView('expected')\">\n <i class=\"fas fa-check-double\"></i>\n Expected Outcomes\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'config'\"\n (click)=\"setJsonView('config')\">\n <i class=\"fas fa-cog\"></i>\n Configuration\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'tags'\"\n (click)=\"setJsonView('tags')\">\n <i class=\"fas fa-tags\"></i>\n Tags\n </button>\n </div>\n <div class=\"code-editor-container\">\n <mj-code-editor\n [value]=\"getJsonData()\"\n language=\"json\"\n [readonly]=\"true\"\n [toolbar]=\"jsonToolbar\"\n [lineWrapping]=\"true\">\n </mj-code-editor>\n </div>\n </div>\n </div>\n }\n\n <!-- Configuration Tab -->\n @if (activeTab === 'config') {\n <div class=\"config-tab\">\n <!-- Details -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-pen-to-square\"></i> Details</h3>\n <p class=\"edit-section-sub\">Edit any field \u2014 changes are saved with the bar at the bottom.</p>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-name\">Name <span class=\"required\">*</span></label>\n <input\n id=\"test-name\"\n type=\"text\"\n class=\"config-input\"\n placeholder=\"e.g., Agent Response Quality Test\"\n [(ngModel)]=\"record.Name\"\n />\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-description\">Description</label>\n <textarea\n id=\"test-description\"\n class=\"config-input config-textarea\"\n rows=\"3\"\n placeholder=\"What does this test evaluate?\"\n [ngModel]=\"record.Description\"\n (ngModelChange)=\"record.Description = $event || null\"\n ></textarea>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-status\">Status</label>\n <div class=\"select-wrapper\">\n <select\n id=\"test-status\"\n class=\"config-input\"\n [(ngModel)]=\"record.Status\"\n >\n @for (opt of statusOptions; track opt) {\n <option [ngValue]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-type\">Test Type</label>\n <select\n id=\"test-type\"\n class=\"config-input\"\n [(ngModel)]=\"record.TypeID\"\n >\n @for (t of testTypeOptions; track t.ID) {\n <option [ngValue]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-tags\">Tags</label>\n <div class=\"tag-editor\" (click)=\"tagInput.focus()\">\n @for (tag of tags; track tag) {\n <span class=\"tag-chip-editable\">\n {{ tag }}\n <button type=\"button\" class=\"tag-remove\" (click)=\"removeTag(tag); $event.stopPropagation()\" [attr.aria-label]=\"'Remove tag ' + tag\">\n <i class=\"fas fa-times\"></i>\n </button>\n </span>\n }\n <input\n #tagInput\n id=\"test-tags\"\n type=\"text\"\n class=\"tag-input-inline\"\n [placeholder]=\"tags.length === 0 ? 'Add tags, press Enter or comma...' : ''\"\n [(ngModel)]=\"tagDraft\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTagFromDraft()\"\n />\n </div>\n <span class=\"config-hint\">Press Enter or comma to add a tag. Backspace on empty input removes the last tag.</span>\n </div>\n </div>\n </section>\n\n <!-- Execution Settings -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-cogs\"></i> Execution Settings</h3>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field\">\n <label for=\"test-priority\">Priority</label>\n <input\n id=\"test-priority\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0 (lower runs first)\"\n [ngModel]=\"record.Priority\"\n (ngModelChange)=\"record.Priority = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Lower numbers run first.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-repeat\">Repeat Count</label>\n <input\n id=\"test-repeat\"\n type=\"number\"\n class=\"config-input\"\n min=\"1\"\n placeholder=\"1\"\n [ngModel]=\"record.RepeatCount\"\n (ngModelChange)=\"record.RepeatCount = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Number of times to repeat for statistical analysis.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-duration\">Estimated Duration (seconds)</label>\n <input\n id=\"test-duration\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0\"\n [ngModel]=\"record.EstimatedDurationSeconds\"\n (ngModelChange)=\"record.EstimatedDurationSeconds = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field\">\n <label for=\"test-cost\">Estimated Cost (USD)</label>\n <input\n id=\"test-cost\"\n type=\"number\"\n step=\"0.000001\"\n class=\"config-input\"\n placeholder=\"0.00\"\n [ngModel]=\"record.EstimatedCostUSD\"\n (ngModelChange)=\"record.EstimatedCostUSD = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-timeout\">Max Execution Time (ms)</label>\n <input\n id=\"test-timeout\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"Default: 300000 (5 min)\"\n [ngModel]=\"record.MaxExecutionTimeMS\"\n (ngModelChange)=\"record.MaxExecutionTimeMS = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Leave empty for the default 5 minute timeout. Currently: {{ formatTimeout(record.MaxExecutionTimeMS) }}</span>\n </div>\n </div>\n </section>\n\n <!-- JSON editors (preserved from original layout) -->\n <div class=\"config-section\">\n <h3><i class=\"fas fa-sign-in-alt\"></i> Input Definition (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.InputDefinition || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.InputDefinition = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-check-double\"></i> Expected Outcomes (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.ExpectedOutcomes || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.ExpectedOutcomes = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-cog\"></i> Configuration (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.Configuration || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.Configuration = $event\">\n </mj-code-editor>\n </div>\n </div>\n\n <!-- Metadata (read-only) -->\n <section class=\"meta-section\">\n <div class=\"meta-grid\">\n <div class=\"meta-item\">\n <div class=\"meta-label\">Created</div>\n <div class=\"meta-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Last updated</div>\n <div class=\"meta-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Test ID</div>\n <div class=\"meta-value meta-mono\">{{ record.ID }}</div>\n </div>\n </div>\n </section>\n </div>\n }\n\n <!-- Test Runs Tab -->\n @if (activeTab === 'runs') {\n <div class=\"runs-tab\">\n <!-- Loading State -->\n @if (loadingRuns) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3,4,5]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Runs List -->\n @if (!loadingRuns && testRuns.length > 0) {\n <div class=\"runs-list\">\n @for (run of testRuns; track run) {\n <div class=\"run-item\" (click)=\"openTestRun(run.ID)\">\n <div class=\"run-icon\" [style.background-color]=\"getRunStatusColor(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-stopwatch]=\"run.Status === 'Timeout'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n </div>\n <div class=\"run-content\">\n <div class=\"run-header\">\n <span class=\"run-id\">Run #{{ run.ID.substring(0, 8) }}</span>\n <span class=\"run-status\" [style.color]=\"getRunStatusColor(run.Status)\">{{ run.Status }}</span>\n </div>\n <div class=\"run-meta\">\n <span><i class=\"fas fa-calendar\"></i> {{ getRelativeTime(run.StartedAt) }}</span>\n @if (run.DurationSeconds) {\n <span><i class=\"fas fa-clock\"></i> {{ formatDuration(run.DurationSeconds) }}</span>\n }\n @if (run.CostUSD) {\n <span><i class=\"fas fa-dollar-sign\"></i> {{ formatCost(run.CostUSD) }}</span>\n }\n @if (run.TargetLogEntityID && run.TargetLogID) {\n <mj-entity-link-pill\n [entityName]=\"run.TargetLogEntity\"\n [recordId]=\"run.TargetLogID\">\n </mj-entity-link-pill>\n }\n </div>\n <!-- Evaluation indicators -->\n <div class=\"run-eval-stack\">\n <!-- Status indicator -->\n @if (evalPreferences.showExecution) {\n <span class=\"eval-pill status-pill\"\n [ngClass]=\"'status-' + run.Status.toLowerCase()\"\n [title]=\"getStatusTooltip(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-hourglass-end]=\"run.Status === 'Timeout'\"\n [class.fa-forward]=\"run.Status === 'Skipped'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n <span>{{ run.Status }}</span>\n </span>\n }\n <!-- Human feedback indicator -->\n @if (evalPreferences.showHuman) {\n @if (!getFeedbackForRun(run.ID)?.Rating) {\n <span class=\"eval-pill human-pill no-feedback\"\n title=\"Human Review: No rating submitted yet\">\n <i class=\"fas fa-user-slash\"></i>\n </span>\n }\n @if (getFeedbackForRun(run.ID)?.Rating; as rating) {\n <span class=\"eval-pill human-pill has-feedback\"\n [class.rating-low]=\"rating <= 4\"\n [class.rating-medium]=\"rating >= 5 && rating <= 6\"\n [class.rating-good]=\"rating >= 7 && rating <= 8\"\n [class.rating-excellent]=\"rating >= 9\"\n [title]=\"getHumanTooltip(rating, getFeedbackForRun(run.ID)?.CorrectionSummary || getFeedbackForRun(run.ID)?.Comments || null)\">\n <i class=\"fas fa-user\"></i>\n <span>{{ rating }}</span>\n </span>\n }\n }\n <!-- Auto score indicator -->\n @if (evalPreferences.showAuto) {\n @if (run.Score == null) {\n <span class=\"eval-pill auto-pill no-score\"\n title=\"Auto Score: No automated score available\">\n <i class=\"fas fa-robot\"></i>\n </span>\n }\n @if (run.Score != null) {\n <span class=\"eval-pill auto-pill has-score\"\n [class.score-low]=\"run.Score < 0.5\"\n [class.score-medium]=\"run.Score >= 0.5 && run.Score < 0.7\"\n [class.score-good]=\"run.Score >= 0.7 && run.Score < 0.85\"\n [class.score-excellent]=\"run.Score >= 0.85\"\n [title]=\"'Auto Score: ' + (run.Score * 100).toFixed(0) + '% automated evaluation'\">\n <i class=\"fas fa-robot\"></i>\n <span>{{ (run.Score * 100).toFixed(0) }}%</span>\n </span>\n }\n }\n </div>\n @if (getRunTags(run).length > 0) {\n <div class=\"run-tags\">\n @for (tag of getRunTags(run).slice(0, 3); track tag) {\n <span class=\"run-tag\">{{ tag }}</span>\n }\n @if (getRunTags(run).length > 3) {\n <span class=\"run-tag-more\">+{{ getRunTags(run).length - 3 }}</span>\n }\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (testRunsLoaded && !loadingRuns && testRuns.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-circle-play\"\n Title=\"No Test Runs Yet\"\n Message=\"Run this test to see execution history and results here.\"\n ActionText=\"Run Test Now\"\n ActionIcon=\"fa-solid fa-play\"\n (Action)=\"runTest()\" />\n }\n </div>\n }\n\n <!-- Test Suites Tab -->\n @if (activeTab === 'suites') {\n <div class=\"suites-tab\">\n <!-- Loading State -->\n @if (loadingSuites) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Suites List -->\n @if (!loadingSuites && suiteTests.length > 0) {\n <div class=\"suites-list\">\n @for (suiteTest of suiteTests; track suiteTest) {\n <div class=\"suite-item\" (click)=\"openTestSuite(suiteTest.SuiteID)\">\n <div class=\"suite-icon\">\n <i class=\"fas fa-layer-group\"></i>\n </div>\n <div class=\"suite-content\">\n <div class=\"suite-name\">{{ suiteTest.Suite }}</div>\n <div class=\"suite-meta\">\n <span><i class=\"fas fa-sort-numeric-up\"></i> Sequence: {{ suiteTest.Sequence }}</span>\n @if (suiteTest.Status) {\n <span><i class=\"fas fa-info-circle\"></i> {{ suiteTest.Status }}</span>\n }\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (suiteTestsLoaded && !loadingSuites && suiteTests.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-folder-open\"\n Title=\"Not Part of Any Suite\"\n Message=\"This test is not included in any test suites. Add it to a suite to run it with other tests.\" />\n }\n </div>\n }\n\n <!-- Analytics Tab -->\n @if (activeTab === 'analytics') {\n <div class=\"history-tab\">\n <!-- Loading State -->\n @if (loadingHistory) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading history...\"></mj-loading>\n </div>\n }\n <!-- History Content -->\n @if (!loadingHistory && historyLoaded) {\n <div class=\"history-content\">\n <!-- Filters -->\n <div class=\"history-filters\">\n <div class=\"time-range-filters\">\n <span class=\"filter-label\">Time Range:</span>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '7d'\"\n (click)=\"setHistoryTimeRange('7d')\">7 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '30d'\"\n (click)=\"setHistoryTimeRange('30d')\">30 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '90d'\"\n (click)=\"setHistoryTimeRange('90d')\">90 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === 'all'\"\n (click)=\"setHistoryTimeRange('all')\">All Time</button>\n </div>\n <div class=\"history-actions\">\n <button mjButton (click)=\"exportHistoryToCSV()\" [disabled]=\"historyData.length === 0\">\n <i class=\"fas fa-download\"></i> Export CSV\n </button>\n </div>\n </div>\n <!-- KPI Cards -->\n @if (historyData.length > 0) {\n <div class=\"history-kpi-cards\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-play-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ getTotalRuns() }}</div>\n <div class=\"kpi-label\">Total Runs</div>\n </div>\n </div>\n @if (evalPreferences.showExecution) {\n <div class=\"kpi-card\">\n <div class=\"kpi-icon pass-rate\">\n <i class=\"fas fa-percentage\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">\n {{ getOverallPassRate().toFixed(1) }}%\n <i class=\"fas trend-icon\"\n [class.fa-arrow-up]=\"getPassRateTrend() === 'up'\"\n [class.fa-arrow-down]=\"getPassRateTrend() === 'down'\"\n [class.fa-minus]=\"getPassRateTrend() === 'stable'\"\n [class.trend-up]=\"getPassRateTrend() === 'up'\"\n [class.trend-down]=\"getPassRateTrend() === 'down'\"></i>\n </div>\n <div class=\"kpi-label\">Pass Rate</div>\n </div>\n </div>\n }\n @if (evalPreferences.showAuto) {\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-star\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ (getOverallAvgScore() * 100).toFixed(1) }}%</div>\n <div class=\"kpi-label\">Avg Score</div>\n </div>\n </div>\n }\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-clock\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ formatDuration(getOverallAvgDuration()) }}</div>\n <div class=\"kpi-label\">Avg Duration</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-dollar-sign\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ formatCost(getOverallAvgCost()) }}</div>\n <div class=\"kpi-label\">Avg Cost</div>\n </div>\n </div>\n </div>\n }\n <!-- Daily History Table -->\n @if (historyData.length > 0) {\n <div class=\"history-section\">\n <h3><i class=\"fas fa-calendar-alt\"></i> Daily Performance</h3>\n <div class=\"history-table-container\">\n <table class=\"history-table\">\n <thead>\n <tr>\n <th>Date</th>\n <th>Runs</th>\n @if (evalPreferences.showExecution) {\n <th>Passed</th>\n }\n @if (evalPreferences.showExecution) {\n <th>Failed</th>\n }\n @if (evalPreferences.showExecution) {\n <th>Pass Rate</th>\n }\n @if (evalPreferences.showAuto) {\n <th>Avg Score</th>\n }\n <th>Avg Duration</th>\n <th>Avg Cost</th>\n </tr>\n </thead>\n <tbody>\n @for (day of historyData; track day) {\n <tr>\n <td class=\"date-cell\">{{ day.date | date:'mediumDate' }}</td>\n <td class=\"runs-cell\">{{ day.runCount }}</td>\n @if (evalPreferences.showExecution) {\n <td class=\"passed-cell\">{{ day.passCount }}</td>\n }\n @if (evalPreferences.showExecution) {\n <td class=\"failed-cell\">{{ day.failCount }}</td>\n }\n @if (evalPreferences.showExecution) {\n <td class=\"pass-rate-cell\">\n <div class=\"pass-rate-bar\">\n <div class=\"pass-rate-fill\" [style.width.%]=\"day.passRate\"></div>\n <span class=\"pass-rate-text\">{{ day.passRate.toFixed(1) }}%</span>\n </div>\n </td>\n }\n @if (evalPreferences.showAuto) {\n <td class=\"score-cell\">{{ (day.avgScore * 100).toFixed(1) }}%</td>\n }\n <td class=\"duration-cell\">{{ formatDuration(day.avgDuration) }}</td>\n <td class=\"cost-cell\">{{ formatCost(day.avgCost) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n <!-- Suite Performance -->\n @if (suitePerformance.length > 0) {\n <div class=\"history-section\">\n <h3><i class=\"fas fa-layer-group\"></i> Performance by Suite</h3>\n <div class=\"suite-performance-list\">\n @for (suite of suitePerformance; track suite) {\n <div class=\"suite-perf-card\" (click)=\"openSuiteFromHistory(suite.suiteId)\">\n <div class=\"suite-perf-header\">\n <div class=\"suite-perf-name\">{{ suite.suiteName }}</div>\n @if (suite.tags.length > 0) {\n <div class=\"suite-perf-tags\">\n @for (tag of suite.tags.slice(0, 3); track tag) {\n <span class=\"tag-mini\">{{ tag }}</span>\n }\n @if (suite.tags.length > 3) {\n <span class=\"tag-more\">+{{ suite.tags.length - 3 }}</span>\n }\n </div>\n }\n </div>\n <div class=\"suite-perf-stats\">\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ suite.totalRuns }}</span>\n <span class=\"stat-label\">Runs</span>\n </div>\n @if (evalPreferences.showExecution) {\n <div class=\"suite-stat\">\n <span class=\"stat-value pass-rate\" [class.high]=\"suite.passRate >= 80\" [class.low]=\"suite.passRate < 50\">\n {{ suite.passRate.toFixed(1) }}%\n </span>\n <span class=\"stat-label\">Pass Rate</span>\n </div>\n }\n @if (evalPreferences.showAuto) {\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ (suite.avgScore * 100).toFixed(1) }}%</span>\n <span class=\"stat-label\">Avg Score</span>\n </div>\n }\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ formatDuration(suite.avgDuration) }}</span>\n <span class=\"stat-label\">Avg Duration</span>\n </div>\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ formatCost(suite.avgCost) }}</span>\n <span class=\"stat-label\">Avg Cost</span>\n </div>\n @if (suite.lastRun) {\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ getRelativeTime(suite.lastRun) }}</span>\n <span class=\"stat-label\">Last Run</span>\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right suite-perf-arrow\"></i>\n </div>\n }\n </div>\n </div>\n }\n <!-- Empty State -->\n @if (historyData.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-chart-line\"\n Title=\"No History Available\"\n Message=\"Run this test to start building history and analytics data.\"\n ActionText=\"Run Test Now\"\n ActionIcon=\"fa-solid fa-play\"\n (Action)=\"runTest()\" />\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Keyboard Shortcuts Toggle Button -->\n <button class=\"shortcuts-toggle\" (click)=\"toggleShortcuts()\" [title]=\"showShortcuts ? 'Hide keyboard shortcuts' : 'Show keyboard shortcuts'\">\n <i class=\"fas fa-keyboard\"></i>\n </button>\n\n <!-- Keyboard Shortcuts Hint (Desktop Only) -->\n @if (showShortcuts) {\n <div class=\"keyboard-shortcuts\">\n <div class=\"shortcuts-header\">\n <i class=\"fas fa-keyboard\"></i>\n Shortcuts\n <button class=\"shortcuts-close\" (click)=\"toggleShortcuts()\" title=\"Hide shortcuts\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n <div class=\"shortcut-list\">\n <div class=\"shortcut-item\">\n <span>Save changes</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>S</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Refresh</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>R</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Run Test</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>Enter</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Switch Tabs</span>\n <span class=\"shortcut-keys\"><kbd>1</kbd>-<kbd>5</kbd></span>\n </div>\n </div>\n </div>\n }\n\n <!-- Slide Panel for Test Execution -->\n @if (testingDialogService.IsPanelOpen) {\n <mj-slide-panel\n Mode=\"slide\"\n [Title]=\"testingDialogService.PanelOptions?.testId ? 'Test Execution' : 'Run Test'\"\n [Resizable]=\"true\"\n (Closed)=\"OnPanelClosed()\">\n <app-test-run-dialog\n [PanelMode]=\"true\"\n [selectedTestId]=\"testingDialogService.PanelOptions?.testId ?? null\"\n [selectedSuiteId]=\"testingDialogService.PanelOptions?.suiteId ?? null\"\n [runMode]=\"testingDialogService.PanelOptions?.mode ?? 'test'\"\n (PanelClose)=\"OnPanelClosed()\">\n </app-test-run-dialog>\n </mj-slide-panel>\n }\n\n <!-- Sticky Save Bar \u2014 always in the DOM so CSS transitions can fire reliably.\n Visibility is controlled by the .save-bar--visible class, driven by isDirty. -->\n <div\n class=\"save-bar\"\n [class.save-bar--visible]=\"isDirty\"\n [attr.aria-hidden]=\"!isDirty\"\n role=\"region\"\n aria-label=\"Unsaved changes\"\n >\n <div class=\"save-bar-message\">\n <span class=\"save-bar-dot\" aria-hidden=\"true\">\u25CF</span>\n <span class=\"save-bar-text\">\n <strong>Unsaved changes</strong>\n <span class=\"save-bar-fields\">\n @if (dirtyFieldNames.length === 1) {\n {{ dirtyFieldNames[0] }} edited\n } @else if (dirtyFieldNames.length > 1) {\n {{ dirtyFieldNames.length }} fields edited\n }\n </span>\n </span>\n </div>\n <div class=\"save-bar-actions\">\n <button\n type=\"button\"\n class=\"save-bar-btn save-bar-btn--primary\"\n (click)=\"saveChanges()\"\n [disabled]=\"isSaving || !isDirty\"\n [attr.tabindex]=\"isDirty ? 0 : -1\"\n title=\"Save changes (\u2318S)\"\n >\n @if (isSaving) {\n <i class=\"fas fa-spinner fa-spin\"></i> Saving\u2026\n } @else {\n <i class=\"fas fa-check\"></i> Save changes\n <span class=\"save-bar-kbd\"><kbd>\u2318</kbd><kbd>S</kbd></span>\n }\n </button>\n <button\n type=\"button\"\n class=\"save-bar-btn save-bar-btn--ghost\"\n (click)=\"discardChanges()\"\n [disabled]=\"isSaving || !isDirty\"\n [attr.tabindex]=\"isDirty ? 0 : -1\"\n title=\"Discard changes\"\n >\n <i class=\"fas fa-undo\"></i> Discard\n </button>\n </div>\n </div>\n</div>\n", styles: ["/* ===========================\n Test Form - World-Class UX\n Premium Test Definition Styles\n =========================== */\n\n/* CSS Custom Properties for Theming - using :host for Angular encapsulation */\n:host {\n --test-primary: var(--mj-brand-primary);\n --test-primary-light: var(--mj-brand-primary);\n --test-primary-dark: var(--mj-brand-primary-hover);\n --test-success: var(--mj-status-success);\n --test-success-light: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n --test-error: var(--mj-status-error);\n --test-error-light: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n --test-warning: var(--mj-status-warning);\n --test-warning-light: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n --test-disabled: var(--mj-text-muted);\n --test-bg: var(--mj-bg-surface-card);\n --test-surface: var(--mj-bg-surface);\n --test-border: var(--mj-border-default);\n --test-text: var(--mj-text-primary);\n --test-text-secondary: var(--mj-text-muted);\n --test-text-muted: var(--mj-text-disabled);\n --test-radius-sm: 6px;\n --test-radius-md: 10px;\n --test-radius-lg: 16px;\n --test-shadow-sm: var(--mj-shadow-sm);\n --test-shadow-md: var(--mj-shadow-md);\n --test-shadow-lg: var(--mj-shadow-lg);\n --test-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: block;\n height: 100%;\n}\n\n/* Breadcrumb */\n.breadcrumb {\n margin-bottom: 16px;\n}\n\n.breadcrumb ol {\n display: flex;\n align-items: center;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n font-size: 13px;\n}\n\n.breadcrumb li {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.breadcrumb a {\n color: var(--test-primary);\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n border-radius: 6px;\n transition: background 0.15s;\n}\n\n.breadcrumb a:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n text-decoration: none;\n}\n\n.breadcrumb .separator {\n font-size: 10px;\n color: var(--test-text-muted);\n margin: 0 4px;\n}\n\n.breadcrumb .current {\n color: var(--test-text-secondary);\n font-weight: 500;\n}\n\n.breadcrumb-text {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Base Container */\n.test-form {\n position: relative;\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--test-bg);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* ===========================\n Header Section\n =========================== */\n.test-header {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n padding: 20px;\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 16px;\n gap: 16px;\n}\n\n.header-left {\n display: flex;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Test Icon */\n.test-icon {\n width: 56px;\n height: 56px;\n border-radius: var(--test-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-inverse);\n font-size: 24px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-md);\n transition: var(--test-transition);\n}\n\n.test-icon:hover {\n transform: scale(1.05);\n}\n\n/* Test Info */\n.test-info {\n flex: 1;\n min-width: 0;\n}\n\n.test-info h1 {\n margin: 0 0 8px 0;\n font-size: clamp(18px, 4vw, 24px);\n font-weight: 700;\n color: var(--test-text);\n line-height: 1.2;\n word-wrap: break-word;\n}\n\n.test-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* Status Badge */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border-radius: 20px;\n color: var(--mj-text-inverse);\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.status-badge.status-active { background: var(--mj-status-success); }\n.status-badge.status-disabled { background: var(--mj-text-secondary); }\n.status-badge.status-pending { background: var(--mj-status-warning); }\n\n.status-badge-inline {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border-radius: 10px;\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n}\n\n.status-badge-inline.status-active { background: var(--test-success); }\n.status-badge-inline.status-disabled { background: var(--test-disabled); }\n.status-badge-inline.status-pending { background: var(--test-warning); }\n\n.test-type {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--test-text-secondary);\n padding: 4px 10px;\n background: var(--test-bg);\n border-radius: var(--test-radius-sm);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.header-actions button {\n white-space: nowrap;\n}\n\n/* Test Description */\n.test-description {\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--test-radius-md);\n margin-bottom: 16px;\n border: 1px solid var(--test-border);\n}\n\n.test-description p {\n margin: 0;\n color: var(--test-text-secondary);\n line-height: 1.6;\n font-size: 14px;\n}\n\n/* ===========================\n Metrics Bar\n =========================== */\n.metrics-bar {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 12px;\n}\n\n.metric-card {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n padding: 14px;\n text-align: center;\n transition: var(--test-transition);\n}\n\n.metric-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.metric-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n margin-bottom: 6px;\n}\n\n.metric-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n/* Progress bar in metric card */\n.metric-progress {\n margin-top: 8px;\n height: 4px;\n background: var(--test-border);\n border-radius: 2px;\n overflow: hidden;\n}\n\n.metric-progress-fill {\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 2px;\n transition: width 0.5s ease-out;\n}\n\n/* ===========================\n Tabs Navigation\n =========================== */\n.tabs-container {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.tabs {\n display: flex;\n padding: 0 20px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.tabs::-webkit-scrollbar {\n display: none;\n}\n\n.tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 18px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: var(--test-text-secondary);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--test-transition);\n white-space: nowrap;\n}\n\n.tab:hover {\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.tab.active {\n color: var(--test-primary);\n border-bottom-color: var(--test-primary);\n font-weight: 600;\n}\n\n.tab i {\n font-size: 15px;\n}\n\n.tab-badge {\n background: var(--test-border);\n color: var(--test-text-secondary);\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n transition: var(--test-transition);\n}\n\n.tab.active .tab-badge {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--test-primary);\n}\n\n.tab-shortcut {\n font-size: 10px;\n color: var(--test-text-muted);\n background: var(--test-bg);\n padding: 2px 6px;\n border-radius: 4px;\n font-weight: 600;\n margin-left: 4px;\n}\n\n/* ===========================\n Tab Content Area\n =========================== */\n.tab-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n/* ===========================\n Overview Tab\n =========================== */\n.overview-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: fadeIn 0.3s ease-out;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* Info Section */\n.info-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.info-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.info-section h3 i {\n color: var(--test-primary);\n}\n\n.info-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n}\n\n.info-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.info-label {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.info-value {\n font-size: 14px;\n color: var(--test-text);\n word-wrap: break-word;\n font-weight: 500;\n}\n\n/* JSON Section */\n.json-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.json-section h3 {\n margin: 0 0 16px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.json-section h3 i {\n color: var(--test-primary);\n}\n\n.json-tabs {\n display: flex;\n gap: 4px;\n margin-bottom: 16px;\n background: var(--test-bg);\n border-radius: var(--test-radius-md);\n padding: 4px;\n flex-wrap: wrap;\n}\n\n.json-tab {\n flex: 1;\n min-width: 100px;\n padding: 10px 14px;\n border: none;\n background: transparent;\n color: var(--test-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n border-radius: var(--test-radius-sm);\n transition: var(--test-transition);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n}\n\n.json-tab:hover {\n color: var(--test-text);\n background: var(--mj-bg-overlay);\n}\n\n.json-tab.active {\n background: var(--test-surface);\n color: var(--test-primary);\n font-weight: 600;\n box-shadow: var(--test-shadow-sm);\n}\n\n.json-tab i {\n font-size: 12px;\n}\n\n.code-editor-container {\n border-radius: var(--test-radius-md);\n overflow: hidden;\n border: 1px solid var(--test-border);\n min-height: 200px;\n max-height: 400px;\n}\n\n/* ===========================\n Configuration Tab\n =========================== */\n.config-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: fadeIn 0.3s ease-out;\n}\n\n.config-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.config-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.config-section h3 i {\n color: var(--test-primary);\n}\n\n.config-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 20px;\n}\n\n.config-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.config-item.full-width {\n grid-column: 1 / -1;\n}\n\n.config-item label {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.config-input {\n padding: 10px 14px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n font-size: 14px;\n transition: var(--test-transition);\n background: var(--test-surface);\n}\n\n.config-input:focus {\n outline: none;\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.config-input::placeholder {\n color: var(--test-text-muted);\n}\n\n.config-hint {\n font-size: 11px;\n color: var(--test-text-muted);\n margin-top: 4px;\n}\n\n.config-editor-container {\n border-radius: var(--test-radius-md);\n overflow: hidden;\n border: 1px solid var(--test-border);\n min-height: 200px;\n}\n\n.config-editor-container.small {\n min-height: 100px;\n max-height: 150px;\n}\n\n/* ===========================\n Runs Tab\n =========================== */\n.runs-tab,\n.suites-tab {\n animation: fadeIn 0.3s ease-out;\n}\n\n/* Loading States & Skeletons */\n.loading-state {\n padding: 0;\n}\n\n.skeleton-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.skeleton-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n border: 1px solid var(--test-border);\n}\n\n.skeleton-icon {\n width: 44px;\n height: 44px;\n border-radius: var(--test-radius-md);\n background: linear-gradient(90deg, var(--mj-border-default) 25%, var(--mj-bg-surface-sunken) 50%, var(--mj-border-default) 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n flex-shrink: 0;\n}\n\n.skeleton-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.skeleton-line {\n height: 14px;\n border-radius: 4px;\n background: linear-gradient(90deg, var(--mj-border-default) 25%, var(--mj-bg-surface-sunken) 50%, var(--mj-border-default) 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n}\n\n.skeleton-line.wide { width: 70%; }\n.skeleton-line.narrow { width: 40%; }\n\n@keyframes shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Runs List */\n.runs-list,\n.suites-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.run-item,\n.suite-item {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.run-item:hover,\n.suite-item:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n box-shadow: var(--test-shadow-sm);\n}\n\n.run-icon,\n.suite-icon {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--test-radius-md);\n color: var(--mj-text-inverse);\n font-size: 18px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-sm);\n}\n\n.suite-icon {\n background: var(--mj-status-warning);\n}\n\n.run-content,\n.suite-content {\n flex: 1;\n min-width: 0;\n}\n\n.run-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-id {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.run-status {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.suite-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 4px;\n}\n\n.run-meta,\n.suite-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--test-text-secondary);\n flex-wrap: wrap;\n}\n\n.run-meta span,\n.suite-meta span {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-meta span i,\n.suite-meta span i {\n color: var(--test-text-muted);\n font-size: 11px;\n}\n\n.run-item > i.fa-chevron-right,\n.suite-item > i.fa-chevron-right {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.run-item:hover > i.fa-chevron-right,\n.suite-item:hover > i.fa-chevron-right {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n/* Run Evaluation Stack */\n.run-eval-stack {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n/* Evaluation Pills */\n.eval-pill {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n transition: var(--test-transition);\n}\n\n.eval-pill i {\n font-size: 10px;\n}\n\n/* Status pill colors */\n.eval-pill.status-pill.status-passed {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.status-pill.status-failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.status-pill.status-error {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.status-pill.status-timeout {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.status-pill.status-skipped,\n.eval-pill.status-pill.status-pending {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.eval-pill.status-pill.status-running {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n/* Human feedback pills */\n.eval-pill.human-pill.no-feedback {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n padding: 4px 8px;\n}\n\n.eval-pill.human-pill.has-feedback.rating-low {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.human-pill.has-feedback.rating-medium {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.human-pill.has-feedback.rating-good {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.human-pill.has-feedback.rating-excellent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n/* Auto score pills */\n.eval-pill.auto-pill.no-score {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n padding: 4px 8px;\n}\n\n.eval-pill.auto-pill.has-score.score-low {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.auto-pill.has-score.score-medium {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.auto-pill.has-score.score-good {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.auto-pill.has-score.score-excellent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n/* Run Tags */\n.run-tags {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n.run-tag {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n.run-tag-more {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: var(--test-border);\n color: var(--test-text-muted);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n/* ===========================\n Keyboard Shortcuts Popup\n =========================== */\n/* Keyboard shortcuts toggle button */\n.shortcuts-toggle {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n box-shadow: var(--test-shadow-md);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--test-text-secondary);\n font-size: 14px;\n z-index: 99;\n transition: var(--test-transition);\n opacity: 0.7;\n}\n\n.shortcuts-toggle:hover {\n opacity: 1;\n transform: scale(1.1);\n color: var(--test-primary);\n border-color: var(--test-primary);\n}\n\n.keyboard-shortcuts {\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n padding: 12px 16px;\n box-shadow: var(--test-shadow-lg);\n font-size: 12px;\n color: var(--test-text-secondary);\n z-index: 100;\n max-width: 260px;\n}\n\n.shortcuts-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 10px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--test-border);\n font-weight: 600;\n color: var(--test-text);\n}\n\n.shortcuts-close {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--test-text-muted);\n font-size: 12px;\n padding: 2px 4px;\n border-radius: 4px;\n transition: var(--test-transition);\n}\n\n.shortcuts-close:hover {\n color: var(--test-text);\n background: var(--test-border);\n}\n\n.shortcut-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.shortcut-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.shortcut-keys {\n display: flex;\n gap: 4px;\n}\n\n.shortcut-keys kbd {\n background: var(--test-bg);\n border: 1px solid var(--test-border);\n border-radius: 4px;\n padding: 2px 6px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 11px;\n color: var(--test-text);\n}\n\n/* ===========================\n Responsive Design - Tablet\n =========================== */\n@media (max-width: 1024px) {\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .config-grid {\n grid-template-columns: 1fr;\n }\n\n .keyboard-shortcuts, .shortcuts-toggle {\n display: none;\n }\n}\n\n/* ===========================\n Responsive Design - Mobile\n =========================== */\n@media (max-width: 768px) {\n .test-form {\n height: auto;\n min-height: 100%;\n }\n\n .test-header {\n padding: 16px;\n }\n\n .header-content {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-left {\n width: 100%;\n }\n\n .test-icon {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .test-info h1 {\n font-size: 18px;\n }\n\n .test-meta {\n gap: 8px;\n }\n\n .status-badge {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .header-actions {\n width: 100%;\n justify-content: stretch;\n }\n\n .header-actions button {\n flex: 1;\n }\n\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n gap: 10px;\n }\n\n .metric-card {\n padding: 12px;\n }\n\n .metric-value {\n font-size: 16px;\n }\n\n .tabs {\n padding: 0 12px;\n }\n\n .tab {\n padding: 12px 14px;\n font-size: 13px;\n gap: 6px;\n }\n\n .tab i {\n font-size: 14px;\n }\n\n .tab-shortcut {\n display: none;\n }\n\n .tab-content {\n padding: 16px;\n }\n\n .info-section,\n .json-section,\n .config-section {\n padding: 18px;\n }\n\n .info-grid {\n grid-template-columns: 1fr;\n }\n\n .json-tabs {\n flex-direction: column;\n }\n\n .json-tab {\n min-width: 0;\n justify-content: flex-start;\n }\n\n .run-item,\n .suite-item {\n padding: 14px;\n }\n\n .run-icon,\n .suite-icon {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .run-meta,\n .suite-meta {\n flex-direction: column;\n gap: 4px;\n }\n\n}\n\n/* ===========================\n Responsive Design - Small Mobile\n =========================== */\n@media (max-width: 480px) {\n .test-header {\n padding: 12px;\n }\n\n .header-left {\n gap: 12px;\n }\n\n .test-icon {\n width: 40px;\n height: 40px;\n font-size: 18px;\n border-radius: 8px;\n }\n\n .test-info h1 {\n font-size: 16px;\n }\n\n .metrics-bar {\n grid-template-columns: 1fr 1fr;\n }\n\n .tabs {\n padding: 0 8px;\n }\n\n .tab {\n padding: 10px 12px;\n font-size: 12px;\n }\n\n .tab-badge {\n display: none;\n }\n\n .tab-content {\n padding: 12px;\n }\n\n .run-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n}\n\n/* ===========================\n Touch Device Optimizations\n =========================== */\n@media (hover: none) and (pointer: coarse) {\n .tab,\n .json-tab,\n .run-item,\n .suite-item {\n -webkit-tap-highlight-color: transparent;\n }\n\n .run-item:active,\n .suite-item:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n transform: scale(0.98);\n }\n\n .tab:active,\n .json-tab:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n /* Larger touch targets */\n .tab {\n min-height: 48px;\n }\n\n .run-item,\n .suite-item {\n min-height: 64px;\n }\n}\n\n/* ===========================\n Reduced Motion\n =========================== */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n .skeleton-icon,\n .skeleton-line {\n animation: none;\n background: var(--mj-border-default);\n }\n}\n\n/* ===========================\n History Tab\n =========================== */\n.history-tab {\n animation: fadeIn 0.3s ease-out;\n}\n\n.history-content {\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n/* History Filters */\n.history-filters {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n padding: 16px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n box-shadow: var(--test-shadow-sm);\n}\n\n.time-range-filters {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--test-text-secondary);\n margin-right: 4px;\n}\n\n.filter-btn {\n padding: 8px 16px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n background: var(--test-surface);\n color: var(--test-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.filter-btn:hover {\n border-color: var(--test-primary-light);\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.filter-btn.active {\n background: var(--test-primary);\n color: var(--mj-text-inverse);\n border-color: var(--test-primary);\n}\n\n.history-actions {\n display: flex;\n gap: 8px;\n}\n\n/* KPI Cards */\n.history-kpi-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 16px;\n}\n\n.kpi-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n box-shadow: var(--test-shadow-sm);\n transition: var(--test-transition);\n}\n\n.kpi-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.kpi-icon {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-brand-primary);\n border-radius: var(--test-radius-md);\n color: var(--mj-text-inverse);\n font-size: 20px;\n flex-shrink: 0;\n}\n\n.kpi-icon.pass-rate {\n background: var(--mj-status-success);\n}\n\n.kpi-content {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--test-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n}\n\n.trend-icon {\n font-size: 14px;\n}\n\n.trend-icon.trend-up {\n color: var(--test-success);\n}\n\n.trend-icon.trend-down {\n color: var(--test-error);\n}\n\n/* History Section */\n.history-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.history-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.history-section h3 i {\n color: var(--test-primary);\n}\n\n/* History Table */\n.history-table-container {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 14px;\n}\n\n.history-table th,\n.history-table td {\n padding: 12px 16px;\n text-align: left;\n border-bottom: 1px solid var(--test-border);\n}\n\n.history-table th {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n background: var(--test-bg);\n}\n\n.history-table tbody tr:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, transparent);\n}\n\n.date-cell {\n font-weight: 600;\n color: var(--test-text);\n}\n\n.passed-cell {\n color: var(--test-success);\n font-weight: 600;\n}\n\n.failed-cell {\n color: var(--test-error);\n font-weight: 600;\n}\n\n.pass-rate-cell {\n min-width: 120px;\n}\n\n.pass-rate-bar {\n position: relative;\n height: 24px;\n background: var(--test-bg);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.pass-rate-fill {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 12px;\n transition: width 0.5s ease-out;\n}\n\n.pass-rate-text {\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n font-size: 11px;\n font-weight: 700;\n color: var(--test-text);\n z-index: 1;\n}\n\n/* Suite Performance List */\n.suite-performance-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.suite-perf-card {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 18px;\n background: var(--test-bg);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.suite-perf-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n}\n\n.suite-perf-header {\n flex: 1;\n min-width: 0;\n}\n\n.suite-perf-name {\n font-size: 15px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 6px;\n}\n\n.suite-perf-tags {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.tag-mini {\n display: inline-flex;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.tag-more {\n display: inline-flex;\n padding: 2px 8px;\n background: var(--test-border);\n color: var(--test-text-muted);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.suite-perf-stats {\n display: flex;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.suite-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n}\n\n.suite-stat .stat-value {\n font-size: 16px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n.suite-stat .stat-value.pass-rate.high {\n color: var(--test-success);\n}\n\n.suite-stat .stat-value.pass-rate.low {\n color: var(--test-error);\n}\n\n.suite-stat .stat-label {\n font-size: 10px;\n color: var(--test-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.suite-perf-arrow {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.suite-perf-card:hover .suite-perf-arrow {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n/* ===========================\n Print Styles\n =========================== */\n@media print {\n .test-form {\n background: var(--mj-bg-surface);\n height: auto;\n }\n\n .header-actions,\n .tabs-container,\n .keyboard-shortcuts {\n display: none !important;\n }\n\n .tab-content {\n overflow: visible;\n padding: 0;\n }\n\n .info-section,\n .json-section,\n .config-section {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n}\n\n/* ===========================\n Editable Form Sections (Config tab)\n =========================== */\n\n.edit-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.edit-section-header {\n margin: 0 0 18px 0;\n}\n\n.edit-section-header h3 {\n margin: 0 0 4px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.edit-section-header h3 i {\n color: var(--test-primary);\n}\n\n.edit-section-sub {\n margin: 0;\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.edit-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 18px;\n}\n\n@media (max-width: 720px) {\n .edit-grid {\n grid-template-columns: 1fr;\n }\n}\n\n.edit-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.edit-field--full {\n grid-column: 1 / -1;\n}\n\n.edit-field label {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.edit-field .required {\n color: var(--mj-status-error);\n margin-left: 2px;\n}\n\n.config-textarea {\n resize: vertical;\n min-height: 72px;\n font-family: inherit;\n line-height: 1.5;\n}\n\n.select-wrapper {\n position: relative;\n}\n\n.select-wrapper select.config-input {\n padding-right: 36px;\n appearance: none;\n background-color: var(--test-surface);\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2364748b' d='M1.41 0L6 4.59 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 14px center;\n background-size: 10px 7px;\n}\n\n/* Tag editor (chips + inline input) */\n.tag-editor {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 10px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n background: var(--test-surface);\n transition: var(--test-transition);\n cursor: text;\n min-height: 42px;\n align-items: center;\n}\n\n.tag-editor:focus-within {\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.tag-chip-editable {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 4px 3px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n border-radius: 999px;\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n}\n\n.tag-chip-editable .tag-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: transparent;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-size: 10px;\n transition: background 0.15s;\n}\n\n.tag-chip-editable .tag-remove:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n color: var(--mj-brand-primary-hover);\n}\n\n.tag-input-inline {\n flex: 1;\n min-width: 140px;\n border: none;\n background: transparent;\n outline: none;\n font-size: 13px;\n color: var(--test-text);\n padding: 4px 2px;\n}\n\n.tag-input-inline::placeholder {\n color: var(--test-text-muted);\n}\n\n/* Read-only metadata block at bottom of Config tab */\n.meta-section {\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--test-radius-md);\n padding: 14px 18px;\n border: 1px solid var(--test-border);\n}\n\n.meta-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 14px;\n}\n\n.meta-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.meta-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.meta-value {\n font-size: 12px;\n color: var(--test-text-secondary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.meta-mono {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n font-size: 11px;\n}\n\n/* Dirty indicator next to the title */\n.dirty-indicator {\n display: inline-block;\n margin-left: 8px;\n font-size: 14px;\n color: var(--mj-status-warning);\n line-height: 1;\n animation: pulseDot 1.8s ease-in-out infinite;\n vertical-align: middle;\n}\n\n@keyframes pulseDot {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.85); }\n}\n\n.unsaved-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n border-radius: 999px;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.unsaved-pill i {\n font-size: 6px;\n animation: pulseDot 1.8s ease-in-out infinite;\n}\n\n/* Pad the bottom of the tab content when the save bar is visible\n so the bar doesn't cover the last form field. */\n.tab-content.has-savebar {\n padding-bottom: 84px;\n}\n\n/* ===========================\n Sticky Save Bar\n =========================== */\n\n.save-bar {\n position: absolute;\n left: 16px;\n right: 96px; /* leaves room for the bottom-right chat launcher */\n bottom: 16px;\n z-index: 50;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 12px 16px 12px 20px;\n background: var(--mj-bg-surface-elevated, var(--test-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--test-border));\n border-radius: 14px;\n box-shadow: 0 12px 32px color-mix(in srgb, var(--mj-status-warning) 10%, rgba(0, 0, 0, 0.18));\n backdrop-filter: blur(8px);\n /* Hidden / off-screen state by default. The .save-bar--visible class\n animates it up into view. Using `transition` (not `animation`)\n guarantees the change runs every time isDirty toggles. */\n opacity: 0;\n transform: translateY(calc(100% + 32px));\n pointer-events: none;\n transition:\n transform 420ms cubic-bezier(0.16, 1, 0.3, 1),\n opacity 260ms cubic-bezier(0.16, 1, 0.3, 1);\n will-change: transform, opacity;\n}\n\n.save-bar--visible {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .save-bar {\n transition: opacity 180ms ease-out;\n transform: none;\n }\n .save-bar--visible {\n transform: none;\n }\n}\n\n.save-bar-message {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.save-bar-dot {\n color: var(--mj-status-warning);\n font-size: 12px;\n line-height: 1;\n animation: pulseDot 1.8s ease-in-out infinite;\n}\n\n.save-bar-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.save-bar-text strong {\n font-size: 14px;\n color: var(--test-text);\n font-weight: 700;\n}\n\n.save-bar-fields {\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.save-bar-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.save-bar-btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 9px 16px;\n font-size: 13px;\n font-weight: 600;\n border-radius: 8px;\n border: 1px solid transparent;\n cursor: pointer;\n transition: var(--test-transition);\n font-family: inherit;\n}\n\n.save-bar-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.save-bar-btn--primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, white);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n}\n\n.save-bar-btn--primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n}\n\n.save-bar-btn--primary:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.save-bar-btn--ghost {\n background: transparent;\n color: var(--test-text-secondary);\n border-color: var(--test-border);\n}\n\n.save-bar-btn--ghost:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover, var(--mj-bg-surface-card));\n color: var(--test-text);\n border-color: var(--test-text-muted);\n}\n\n.save-bar-kbd {\n display: inline-flex;\n gap: 3px;\n margin-left: 6px;\n opacity: 0.85;\n}\n\n.save-bar-kbd kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 4px;\n font-size: 10px;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n background: color-mix(in srgb, white 18%, transparent);\n border: 1px solid color-mix(in srgb, white 35%, transparent);\n border-radius: 4px;\n color: inherit;\n}\n\n@media (max-width: 640px) {\n .save-bar {\n left: 8px;\n right: 8px;\n bottom: 88px; /* push above the chat launcher on small screens */\n flex-direction: column;\n align-items: stretch;\n padding: 12px;\n }\n .save-bar-actions {\n justify-content: space-between;\n }\n .save-bar-kbd {\n display: none;\n }\n}\n\n"] }]
|
|
2773
|
+
args: [{ standalone: false, selector: 'mj-test-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-form\">\n <!-- Header Section -->\n <div class=\"test-header\">\n <!-- Breadcrumb Navigation -->\n <nav class=\"breadcrumb\" aria-label=\"Breadcrumb\">\n <ol>\n <li>\n <a href=\"javascript:void(0)\" (click)=\"navigateToTestingDashboard()\">\n <i class=\"fas fa-vial\"></i>\n <span class=\"breadcrumb-text\">Testing</span>\n </a>\n </li>\n <li class=\"current\">\n <i class=\"fas fa-chevron-right separator\"></i>\n <i class=\"fas fa-flask\"></i>\n <span>{{ record.Name }}</span>\n </li>\n </ol>\n </nav>\n\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"test-icon\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas fa-flask\"></i>\n </div>\n <div class=\"test-info\">\n <h1>\n {{ record.Name }}\n @if (isDirty) {\n <span class=\"dirty-indicator\" title=\"You have unsaved changes\" aria-label=\"Unsaved changes\">\u25CF</span>\n }\n </h1>\n <div class=\"test-meta\">\n <span class=\"status-badge\" [ngClass]=\"getStatusClass()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n {{ record.Status }}\n </span>\n @if (record.Type) {\n <span class=\"test-type\">\n <i class=\"fas fa-tag\"></i>\n {{ record.Type }}\n </span>\n }\n @if (isDirty) {\n <span class=\"unsaved-pill\" title=\"You have unsaved changes\">\n <i class=\"fas fa-circle\"></i> Unsaved\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <app-evaluation-mode-toggle></app-evaluation-mode-toggle>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test\n </button>\n <button mjButton (click)=\"refresh()\" [disabled]=\"isRefreshing\">\n <i class=\"fas\" [ngClass]=\"isRefreshing ? 'fa-sync fa-spin' : 'fa-sync'\"></i>\n {{ isRefreshing ? 'Refreshing...' : 'Refresh' }}\n </button>\n </div>\n </div>\n\n <!-- Test Description -->\n @if (record.Description) {\n <div class=\"test-description\">\n <p>{{ record.Description }}</p>\n </div>\n }\n\n <!-- Metrics Bar -->\n @if (testRunsLoaded && testRuns.length > 0) {\n <div class=\"metrics-bar\">\n <div class=\"metric-card\">\n <div class=\"metric-label\">Total Runs</div>\n <div class=\"metric-value\">{{ testRuns.length }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Pass Rate</div>\n <div class=\"metric-value\">{{ getPassRate().toFixed(1) }}%</div>\n <div class=\"metric-progress\">\n <div class=\"metric-progress-fill\" [style.width.%]=\"getPassRate()\"></div>\n </div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Cost</div>\n <div class=\"metric-value\">{{ formatCost(getAverageCost()) }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Duration</div>\n <div class=\"metric-value\">{{ formatDuration(getAverageDuration()) }}</div>\n </div>\n </div>\n }\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs-container\">\n <div class=\"tabs\" role=\"tablist\">\n <button class=\"tab\"\n [class.active]=\"activeTab === 'overview'\"\n (click)=\"changeTab('overview')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'overview'\">\n <i class=\"fas fa-th-large\"></i>\n <span>Overview</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'config'\"\n (click)=\"changeTab('config')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'config'\">\n <i class=\"fas fa-sliders-h\"></i>\n <span>Configuration</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'runs'\"\n (click)=\"changeTab('runs')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'runs'\">\n <i class=\"fas fa-history\"></i>\n <span>Runs</span>\n @if (testRunsLoaded) {\n <span class=\"tab-badge\">{{ testRuns.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'suites'\"\n (click)=\"changeTab('suites')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'suites'\">\n <i class=\"fas fa-layer-group\"></i>\n <span>Test Suites</span>\n @if (suiteTestsLoaded) {\n <span class=\"tab-badge\">{{ suiteTests.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'analytics'\"\n (click)=\"changeTab('analytics')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'analytics'\">\n <i class=\"fas fa-chart-line\"></i>\n <span>Analytics</span>\n </button>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\" [class.has-savebar]=\"isDirty\">\n <!-- Overview Tab -->\n @if (activeTab === 'overview') {\n <div class=\"overview-tab\">\n <!-- Basic Information -->\n <div class=\"info-section\">\n <h3><i class=\"fas fa-info-circle\"></i> Test Information</h3>\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <div class=\"info-label\">Name</div>\n <div class=\"info-value\">{{ record.Name }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Type</div>\n <div class=\"info-value\">{{ record.Type || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Status</div>\n <div class=\"info-value\">\n <span class=\"status-badge-inline\" [ngClass]=\"getStatusClass()\">{{ record.Status }}</span>\n </div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Priority</div>\n <div class=\"info-value\">{{ record.Priority || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Duration</div>\n <div class=\"info-value\">{{ record.EstimatedDurationSeconds ? formatDuration(record.EstimatedDurationSeconds) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Cost</div>\n <div class=\"info-value\">{{ record.EstimatedCostUSD ? formatCost(record.EstimatedCostUSD) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Repeat Count</div>\n <div class=\"info-value\">{{ record.RepeatCount || 1 }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Max Execution Time</div>\n <div class=\"info-value\">{{ formatTimeout(record.MaxExecutionTimeMS) }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Created</div>\n <div class=\"info-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Updated</div>\n <div class=\"info-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n </div>\n </div>\n <!-- JSON Data Views -->\n <div class=\"json-section\">\n <h3><i class=\"fas fa-code\"></i> Test Definition</h3>\n <div class=\"json-tabs\">\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'input'\"\n (click)=\"setJsonView('input')\">\n <i class=\"fas fa-sign-in-alt\"></i>\n Input Definition\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'expected'\"\n (click)=\"setJsonView('expected')\">\n <i class=\"fas fa-check-double\"></i>\n Expected Outcomes\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'config'\"\n (click)=\"setJsonView('config')\">\n <i class=\"fas fa-cog\"></i>\n Configuration\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'tags'\"\n (click)=\"setJsonView('tags')\">\n <i class=\"fas fa-tags\"></i>\n Tags\n </button>\n </div>\n <div class=\"code-editor-container\">\n <mj-code-editor\n [value]=\"getJsonData()\"\n language=\"json\"\n [readonly]=\"true\"\n [toolbar]=\"jsonToolbar\"\n [lineWrapping]=\"true\">\n </mj-code-editor>\n </div>\n </div>\n </div>\n }\n\n <!-- Configuration Tab -->\n @if (activeTab === 'config') {\n <div class=\"config-tab\">\n <!-- Details -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-pen-to-square\"></i> Details</h3>\n <p class=\"edit-section-sub\">Edit any field \u2014 changes are saved with the bar at the bottom.</p>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-name\">Name <span class=\"required\">*</span></label>\n <input\n id=\"test-name\"\n type=\"text\"\n class=\"config-input\"\n placeholder=\"e.g., Agent Response Quality Test\"\n [(ngModel)]=\"record.Name\"\n />\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-description\">Description</label>\n <textarea\n id=\"test-description\"\n class=\"config-input config-textarea\"\n rows=\"3\"\n placeholder=\"What does this test evaluate?\"\n [ngModel]=\"record.Description\"\n (ngModelChange)=\"record.Description = $event || null\"\n ></textarea>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-status\">Status</label>\n <div class=\"select-wrapper\">\n <select\n id=\"test-status\"\n class=\"config-input\"\n [(ngModel)]=\"record.Status\"\n >\n @for (opt of statusOptions; track opt) {\n <option [ngValue]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-rubric\">Rubric</label>\n <select\n id=\"test-rubric\"\n class=\"config-input\"\n [ngModel]=\"record.RubricID\"\n (ngModelChange)=\"record.RubricID = $event || null\"\n >\n <option [ngValue]=\"null\">\u2014 None \u2014</option>\n @for (rubric of RubricOptions; track rubric.id) {\n <option [ngValue]=\"rubric.id\">{{ rubric.name }}</option>\n }\n </select>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-type\">Test Type</label>\n <select\n id=\"test-type\"\n class=\"config-input\"\n [(ngModel)]=\"record.TypeID\"\n >\n @for (t of testTypeOptions; track t.ID) {\n <option [ngValue]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-tags\">Tags</label>\n <div class=\"tag-editor\" (click)=\"tagInput.focus()\">\n @for (tag of tags; track tag) {\n <span class=\"tag-chip-editable\">\n {{ tag }}\n <button type=\"button\" class=\"tag-remove\" (click)=\"removeTag(tag); $event.stopPropagation()\" [attr.aria-label]=\"'Remove tag ' + tag\">\n <i class=\"fas fa-times\"></i>\n </button>\n </span>\n }\n <input\n #tagInput\n id=\"test-tags\"\n type=\"text\"\n class=\"tag-input-inline\"\n [placeholder]=\"tags.length === 0 ? 'Add tags, press Enter or comma...' : ''\"\n [(ngModel)]=\"tagDraft\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTagFromDraft()\"\n />\n </div>\n <span class=\"config-hint\">Press Enter or comma to add a tag. Backspace on empty input removes the last tag.</span>\n </div>\n </div>\n </section>\n\n <!-- Execution Settings -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-cogs\"></i> Execution Settings</h3>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field\">\n <label for=\"test-priority\">Priority</label>\n <input\n id=\"test-priority\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0 (lower runs first)\"\n [ngModel]=\"record.Priority\"\n (ngModelChange)=\"record.Priority = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Lower numbers run first.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-repeat\">Repeat Count</label>\n <input\n id=\"test-repeat\"\n type=\"number\"\n class=\"config-input\"\n min=\"1\"\n placeholder=\"1\"\n [ngModel]=\"record.RepeatCount\"\n (ngModelChange)=\"record.RepeatCount = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Number of times to repeat for statistical analysis.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-duration\">Estimated Duration (seconds)</label>\n <input\n id=\"test-duration\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0\"\n [ngModel]=\"record.EstimatedDurationSeconds\"\n (ngModelChange)=\"record.EstimatedDurationSeconds = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field\">\n <label for=\"test-cost\">Estimated Cost (USD)</label>\n <input\n id=\"test-cost\"\n type=\"number\"\n step=\"0.000001\"\n class=\"config-input\"\n placeholder=\"0.00\"\n [ngModel]=\"record.EstimatedCostUSD\"\n (ngModelChange)=\"record.EstimatedCostUSD = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-timeout\">Max Execution Time (ms)</label>\n <input\n id=\"test-timeout\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"Default: 300000 (5 min)\"\n [ngModel]=\"record.MaxExecutionTimeMS\"\n (ngModelChange)=\"record.MaxExecutionTimeMS = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Leave empty for the default 5 minute timeout. Currently: {{ formatTimeout(record.MaxExecutionTimeMS) }}</span>\n </div>\n </div>\n </section>\n\n <!-- JSON editors (preserved from original layout) -->\n <div class=\"config-section\">\n <h3><i class=\"fas fa-sign-in-alt\"></i> Input Definition (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.InputDefinition || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.InputDefinition = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-check-double\"></i> Expected Outcomes (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.ExpectedOutcomes || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.ExpectedOutcomes = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-cog\"></i> Configuration (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.Configuration || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.Configuration = $event\">\n </mj-code-editor>\n </div>\n </div>\n\n <!-- Metadata (read-only) -->\n <section class=\"meta-section\">\n <div class=\"meta-grid\">\n <div class=\"meta-item\">\n <div class=\"meta-label\">Created</div>\n <div class=\"meta-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Last updated</div>\n <div class=\"meta-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Test ID</div>\n <div class=\"meta-value meta-mono\">{{ record.ID }}</div>\n </div>\n </div>\n </section>\n </div>\n }\n\n <!-- Test Runs Tab -->\n @if (activeTab === 'runs') {\n <div class=\"runs-tab\">\n <!-- Loading State -->\n @if (loadingRuns) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3,4,5]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Runs List -->\n @if (!loadingRuns && testRuns.length > 0) {\n <div class=\"runs-list\">\n @for (run of testRuns; track run) {\n <div class=\"run-item\" (click)=\"openTestRun(run.ID)\">\n <div class=\"run-icon\" [style.background-color]=\"getRunStatusColor(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-stopwatch]=\"run.Status === 'Timeout'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n </div>\n <div class=\"run-content\">\n <div class=\"run-header\">\n <span class=\"run-id\">Run #{{ run.ID.substring(0, 8) }}</span>\n <span class=\"run-status\" [style.color]=\"getRunStatusColor(run.Status)\">{{ run.Status }}</span>\n </div>\n <div class=\"run-meta\">\n <span><i class=\"fas fa-calendar\"></i> {{ getRelativeTime(run.StartedAt) }}</span>\n @if (run.DurationSeconds) {\n <span><i class=\"fas fa-clock\"></i> {{ formatDuration(run.DurationSeconds) }}</span>\n }\n @if (run.CostUSD) {\n <span><i class=\"fas fa-dollar-sign\"></i> {{ formatCost(run.CostUSD) }}</span>\n }\n @if (run.TargetLogEntityID && run.TargetLogID) {\n <mj-entity-link-pill\n [entityName]=\"run.TargetLogEntity\"\n [recordId]=\"run.TargetLogID\">\n </mj-entity-link-pill>\n }\n </div>\n <!-- Evaluation indicators -->\n <div class=\"run-eval-stack\">\n <!-- Status indicator -->\n @if (evalPreferences.showExecution) {\n <span class=\"eval-pill status-pill\"\n [ngClass]=\"'status-' + run.Status.toLowerCase()\"\n [title]=\"getStatusTooltip(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-hourglass-end]=\"run.Status === 'Timeout'\"\n [class.fa-forward]=\"run.Status === 'Skipped'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n <span>{{ run.Status }}</span>\n </span>\n }\n <!-- Human feedback indicator -->\n @if (evalPreferences.showHuman) {\n @if (!getFeedbackForRun(run.ID)?.Rating) {\n <span class=\"eval-pill human-pill no-feedback\"\n title=\"Human Review: No rating submitted yet\">\n <i class=\"fas fa-user-slash\"></i>\n </span>\n }\n @if (getFeedbackForRun(run.ID)?.Rating; as rating) {\n <span class=\"eval-pill human-pill has-feedback\"\n [class.rating-low]=\"rating <= 4\"\n [class.rating-medium]=\"rating >= 5 && rating <= 6\"\n [class.rating-good]=\"rating >= 7 && rating <= 8\"\n [class.rating-excellent]=\"rating >= 9\"\n [title]=\"getHumanTooltip(rating, getFeedbackForRun(run.ID)?.CorrectionSummary || getFeedbackForRun(run.ID)?.Comments || null)\">\n <i class=\"fas fa-user\"></i>\n <span>{{ rating }}</span>\n </span>\n }\n }\n <!-- Auto score indicator -->\n @if (evalPreferences.showAuto) {\n @if (run.Score == null) {\n <span class=\"eval-pill auto-pill no-score\"\n title=\"Auto Score: No automated score available\">\n <i class=\"fas fa-robot\"></i>\n </span>\n }\n @if (run.Score != null) {\n <span class=\"eval-pill auto-pill has-score\"\n [class.score-low]=\"run.Score < 0.5\"\n [class.score-medium]=\"run.Score >= 0.5 && run.Score < 0.7\"\n [class.score-good]=\"run.Score >= 0.7 && run.Score < 0.85\"\n [class.score-excellent]=\"run.Score >= 0.85\"\n [title]=\"'Auto Score: ' + (run.Score * 100).toFixed(0) + '% automated evaluation'\">\n <i class=\"fas fa-robot\"></i>\n <span>{{ (run.Score * 100).toFixed(0) }}%</span>\n </span>\n }\n }\n </div>\n @if (getRunTags(run).length > 0) {\n <div class=\"run-tags\">\n @for (tag of getRunTags(run).slice(0, 3); track tag) {\n <span class=\"run-tag\">{{ tag }}</span>\n }\n @if (getRunTags(run).length > 3) {\n <span class=\"run-tag-more\">+{{ getRunTags(run).length - 3 }}</span>\n }\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (testRunsLoaded && !loadingRuns && testRuns.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-circle-play\"\n Title=\"No Test Runs Yet\"\n Message=\"Run this test to see execution history and results here.\"\n ActionText=\"Run Test Now\"\n ActionIcon=\"fa-solid fa-play\"\n (Action)=\"runTest()\" />\n }\n </div>\n }\n\n <!-- Test Suites Tab -->\n @if (activeTab === 'suites') {\n <div class=\"suites-tab\">\n <!-- Loading State -->\n @if (loadingSuites) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Suites List -->\n @if (!loadingSuites && suiteTests.length > 0) {\n <div class=\"suites-list\">\n @for (suiteTest of suiteTests; track suiteTest) {\n <div class=\"suite-item\" (click)=\"openTestSuite(suiteTest.SuiteID)\">\n <div class=\"suite-icon\">\n <i class=\"fas fa-layer-group\"></i>\n </div>\n <div class=\"suite-content\">\n <div class=\"suite-name\">{{ suiteTest.Suite }}</div>\n <div class=\"suite-meta\">\n <span><i class=\"fas fa-sort-numeric-up\"></i> Sequence: {{ suiteTest.Sequence }}</span>\n @if (suiteTest.Status) {\n <span><i class=\"fas fa-info-circle\"></i> {{ suiteTest.Status }}</span>\n }\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (suiteTestsLoaded && !loadingSuites && suiteTests.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-folder-open\"\n Title=\"Not Part of Any Suite\"\n Message=\"This test is not included in any test suites. Add it to a suite to run it with other tests.\" />\n }\n </div>\n }\n\n <!-- Analytics Tab -->\n @if (activeTab === 'analytics') {\n <div class=\"history-tab\">\n <!-- Loading State -->\n @if (loadingHistory) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading history...\"></mj-loading>\n </div>\n }\n <!-- History Content -->\n @if (!loadingHistory && historyLoaded) {\n <div class=\"history-content\">\n <!-- Filters -->\n <div class=\"history-filters\">\n <div class=\"time-range-filters\">\n <span class=\"filter-label\">Time Range:</span>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '7d'\"\n (click)=\"setHistoryTimeRange('7d')\">7 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '30d'\"\n (click)=\"setHistoryTimeRange('30d')\">30 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '90d'\"\n (click)=\"setHistoryTimeRange('90d')\">90 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === 'all'\"\n (click)=\"setHistoryTimeRange('all')\">All Time</button>\n </div>\n <div class=\"history-actions\">\n <button mjButton (click)=\"exportHistoryToCSV()\" [disabled]=\"historyData.length === 0\">\n <i class=\"fas fa-download\"></i> Export CSV\n </button>\n </div>\n </div>\n <!-- KPI Cards -->\n @if (historyData.length > 0) {\n <div class=\"history-kpi-cards\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-play-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ getTotalRuns() }}</div>\n <div class=\"kpi-label\">Total Runs</div>\n </div>\n </div>\n @if (evalPreferences.showExecution) {\n <div class=\"kpi-card\">\n <div class=\"kpi-icon pass-rate\">\n <i class=\"fas fa-percentage\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">\n {{ getOverallPassRate().toFixed(1) }}%\n <i class=\"fas trend-icon\"\n [class.fa-arrow-up]=\"getPassRateTrend() === 'up'\"\n [class.fa-arrow-down]=\"getPassRateTrend() === 'down'\"\n [class.fa-minus]=\"getPassRateTrend() === 'stable'\"\n [class.trend-up]=\"getPassRateTrend() === 'up'\"\n [class.trend-down]=\"getPassRateTrend() === 'down'\"></i>\n </div>\n <div class=\"kpi-label\">Pass Rate</div>\n </div>\n </div>\n }\n @if (evalPreferences.showAuto) {\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-star\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ (getOverallAvgScore() * 100).toFixed(1) }}%</div>\n <div class=\"kpi-label\">Avg Score</div>\n </div>\n </div>\n }\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-clock\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ formatDuration(getOverallAvgDuration()) }}</div>\n <div class=\"kpi-label\">Avg Duration</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-dollar-sign\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ formatCost(getOverallAvgCost()) }}</div>\n <div class=\"kpi-label\">Avg Cost</div>\n </div>\n </div>\n </div>\n }\n <!-- Daily History Table -->\n @if (historyData.length > 0) {\n <div class=\"history-section\">\n <h3><i class=\"fas fa-calendar-alt\"></i> Daily Performance</h3>\n <div class=\"history-table-container\">\n <table class=\"history-table\">\n <thead>\n <tr>\n <th>Date</th>\n <th>Runs</th>\n @if (evalPreferences.showExecution) {\n <th>Passed</th>\n }\n @if (evalPreferences.showExecution) {\n <th>Failed</th>\n }\n @if (evalPreferences.showExecution) {\n <th>Pass Rate</th>\n }\n @if (evalPreferences.showAuto) {\n <th>Avg Score</th>\n }\n <th>Avg Duration</th>\n <th>Avg Cost</th>\n </tr>\n </thead>\n <tbody>\n @for (day of historyData; track day) {\n <tr>\n <td class=\"date-cell\">{{ day.date | date:'mediumDate' }}</td>\n <td class=\"runs-cell\">{{ day.runCount }}</td>\n @if (evalPreferences.showExecution) {\n <td class=\"passed-cell\">{{ day.passCount }}</td>\n }\n @if (evalPreferences.showExecution) {\n <td class=\"failed-cell\">{{ day.failCount }}</td>\n }\n @if (evalPreferences.showExecution) {\n <td class=\"pass-rate-cell\">\n <div class=\"pass-rate-bar\">\n <div class=\"pass-rate-fill\" [style.width.%]=\"day.passRate\"></div>\n <span class=\"pass-rate-text\">{{ day.passRate.toFixed(1) }}%</span>\n </div>\n </td>\n }\n @if (evalPreferences.showAuto) {\n <td class=\"score-cell\">{{ (day.avgScore * 100).toFixed(1) }}%</td>\n }\n <td class=\"duration-cell\">{{ formatDuration(day.avgDuration) }}</td>\n <td class=\"cost-cell\">{{ formatCost(day.avgCost) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n <!-- Suite Performance -->\n @if (suitePerformance.length > 0) {\n <div class=\"history-section\">\n <h3><i class=\"fas fa-layer-group\"></i> Performance by Suite</h3>\n <div class=\"suite-performance-list\">\n @for (suite of suitePerformance; track suite) {\n <div class=\"suite-perf-card\" (click)=\"openSuiteFromHistory(suite.suiteId)\">\n <div class=\"suite-perf-header\">\n <div class=\"suite-perf-name\">{{ suite.suiteName }}</div>\n @if (suite.tags.length > 0) {\n <div class=\"suite-perf-tags\">\n @for (tag of suite.tags.slice(0, 3); track tag) {\n <span class=\"tag-mini\">{{ tag }}</span>\n }\n @if (suite.tags.length > 3) {\n <span class=\"tag-more\">+{{ suite.tags.length - 3 }}</span>\n }\n </div>\n }\n </div>\n <div class=\"suite-perf-stats\">\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ suite.totalRuns }}</span>\n <span class=\"stat-label\">Runs</span>\n </div>\n @if (evalPreferences.showExecution) {\n <div class=\"suite-stat\">\n <span class=\"stat-value pass-rate\" [class.high]=\"suite.passRate >= 80\" [class.low]=\"suite.passRate < 50\">\n {{ suite.passRate.toFixed(1) }}%\n </span>\n <span class=\"stat-label\">Pass Rate</span>\n </div>\n }\n @if (evalPreferences.showAuto) {\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ (suite.avgScore * 100).toFixed(1) }}%</span>\n <span class=\"stat-label\">Avg Score</span>\n </div>\n }\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ formatDuration(suite.avgDuration) }}</span>\n <span class=\"stat-label\">Avg Duration</span>\n </div>\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ formatCost(suite.avgCost) }}</span>\n <span class=\"stat-label\">Avg Cost</span>\n </div>\n @if (suite.lastRun) {\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ getRelativeTime(suite.lastRun) }}</span>\n <span class=\"stat-label\">Last Run</span>\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right suite-perf-arrow\"></i>\n </div>\n }\n </div>\n </div>\n }\n <!-- Empty State -->\n @if (historyData.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-chart-line\"\n Title=\"No History Available\"\n Message=\"Run this test to start building history and analytics data.\"\n ActionText=\"Run Test Now\"\n ActionIcon=\"fa-solid fa-play\"\n (Action)=\"runTest()\" />\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Keyboard Shortcuts Toggle Button -->\n <button class=\"shortcuts-toggle\" (click)=\"toggleShortcuts()\" [title]=\"showShortcuts ? 'Hide keyboard shortcuts' : 'Show keyboard shortcuts'\">\n <i class=\"fas fa-keyboard\"></i>\n </button>\n\n <!-- Keyboard Shortcuts Hint (Desktop Only) -->\n @if (showShortcuts) {\n <div class=\"keyboard-shortcuts\">\n <div class=\"shortcuts-header\">\n <i class=\"fas fa-keyboard\"></i>\n Shortcuts\n <button class=\"shortcuts-close\" (click)=\"toggleShortcuts()\" title=\"Hide shortcuts\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n <div class=\"shortcut-list\">\n <div class=\"shortcut-item\">\n <span>Save changes</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>S</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Refresh</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>R</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Run Test</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>Enter</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Switch Tabs</span>\n <span class=\"shortcut-keys\"><kbd>1</kbd>-<kbd>5</kbd></span>\n </div>\n </div>\n </div>\n }\n\n <!-- Slide Panel for Test Execution -->\n @if (testingDialogService.IsPanelOpen) {\n <mj-slide-panel\n Mode=\"slide\"\n [Title]=\"testingDialogService.PanelOptions?.testId ? 'Test Execution' : 'Run Test'\"\n [Resizable]=\"true\"\n (Closed)=\"OnPanelClosed()\">\n <app-test-run-dialog\n [PanelMode]=\"true\"\n [selectedTestId]=\"testingDialogService.PanelOptions?.testId ?? null\"\n [selectedSuiteId]=\"testingDialogService.PanelOptions?.suiteId ?? null\"\n [runMode]=\"testingDialogService.PanelOptions?.mode ?? 'test'\"\n (PanelClose)=\"OnPanelClosed()\">\n </app-test-run-dialog>\n </mj-slide-panel>\n }\n\n <!-- Sticky Save Bar \u2014 always in the DOM so CSS transitions can fire reliably.\n Visibility is controlled by the .save-bar--visible class, driven by isDirty. -->\n <div\n class=\"save-bar\"\n [class.save-bar--visible]=\"isDirty\"\n [attr.aria-hidden]=\"!isDirty\"\n role=\"region\"\n aria-label=\"Unsaved changes\"\n >\n <div class=\"save-bar-message\">\n <span class=\"save-bar-dot\" aria-hidden=\"true\">\u25CF</span>\n <span class=\"save-bar-text\">\n <strong>Unsaved changes</strong>\n <span class=\"save-bar-fields\">\n @if (dirtyFieldNames.length === 1) {\n {{ dirtyFieldNames[0] }} edited\n } @else if (dirtyFieldNames.length > 1) {\n {{ dirtyFieldNames.length }} fields edited\n }\n </span>\n </span>\n </div>\n <div class=\"save-bar-actions\">\n <button\n type=\"button\"\n class=\"save-bar-btn save-bar-btn--primary\"\n (click)=\"saveChanges()\"\n [disabled]=\"isSaving || !isDirty\"\n [attr.tabindex]=\"isDirty ? 0 : -1\"\n title=\"Save changes (\u2318S)\"\n >\n @if (isSaving) {\n <i class=\"fas fa-spinner fa-spin\"></i> Saving\u2026\n } @else {\n <i class=\"fas fa-check\"></i> Save changes\n <span class=\"save-bar-kbd\"><kbd>\u2318</kbd><kbd>S</kbd></span>\n }\n </button>\n <button\n type=\"button\"\n class=\"save-bar-btn save-bar-btn--ghost\"\n (click)=\"discardChanges()\"\n [disabled]=\"isSaving || !isDirty\"\n [attr.tabindex]=\"isDirty ? 0 : -1\"\n title=\"Discard changes\"\n >\n <i class=\"fas fa-undo\"></i> Discard\n </button>\n </div>\n </div>\n</div>\n", styles: ["/* ===========================\n Test Form - World-Class UX\n Premium Test Definition Styles\n =========================== */\n\n/* CSS Custom Properties for Theming - using :host for Angular encapsulation */\n:host {\n --test-primary: var(--mj-brand-primary);\n --test-primary-light: var(--mj-brand-primary);\n --test-primary-dark: var(--mj-brand-primary-hover);\n --test-success: var(--mj-status-success);\n --test-success-light: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n --test-error: var(--mj-status-error);\n --test-error-light: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n --test-warning: var(--mj-status-warning);\n --test-warning-light: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n --test-disabled: var(--mj-text-muted);\n --test-bg: var(--mj-bg-surface-card);\n --test-surface: var(--mj-bg-surface);\n --test-border: var(--mj-border-default);\n --test-text: var(--mj-text-primary);\n --test-text-secondary: var(--mj-text-muted);\n --test-text-muted: var(--mj-text-disabled);\n --test-radius-sm: 6px;\n --test-radius-md: 10px;\n --test-radius-lg: 16px;\n --test-shadow-sm: var(--mj-shadow-sm);\n --test-shadow-md: var(--mj-shadow-md);\n --test-shadow-lg: var(--mj-shadow-lg);\n --test-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: block;\n height: 100%;\n}\n\n/* Breadcrumb */\n.breadcrumb {\n margin-bottom: 16px;\n}\n\n.breadcrumb ol {\n display: flex;\n align-items: center;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n font-size: 13px;\n}\n\n.breadcrumb li {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.breadcrumb a {\n color: var(--test-primary);\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n border-radius: 6px;\n transition: background 0.15s;\n}\n\n.breadcrumb a:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n text-decoration: none;\n}\n\n.breadcrumb .separator {\n font-size: 10px;\n color: var(--test-text-muted);\n margin: 0 4px;\n}\n\n.breadcrumb .current {\n color: var(--test-text-secondary);\n font-weight: 500;\n}\n\n.breadcrumb-text {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Base Container */\n.test-form {\n position: relative;\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--test-bg);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* ===========================\n Header Section\n =========================== */\n.test-header {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n padding: 20px;\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 16px;\n gap: 16px;\n}\n\n.header-left {\n display: flex;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Test Icon */\n.test-icon {\n width: 56px;\n height: 56px;\n border-radius: var(--test-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-inverse);\n font-size: 24px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-md);\n transition: var(--test-transition);\n}\n\n.test-icon:hover {\n transform: scale(1.05);\n}\n\n/* Test Info */\n.test-info {\n flex: 1;\n min-width: 0;\n}\n\n.test-info h1 {\n margin: 0 0 8px 0;\n font-size: clamp(18px, 4vw, 24px);\n font-weight: 700;\n color: var(--test-text);\n line-height: 1.2;\n word-wrap: break-word;\n}\n\n.test-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* Status Badge */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border-radius: 20px;\n color: var(--mj-text-inverse);\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.status-badge.status-active { background: var(--mj-status-success); }\n.status-badge.status-disabled { background: var(--mj-text-secondary); }\n.status-badge.status-pending { background: var(--mj-status-warning); }\n\n.status-badge-inline {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border-radius: 10px;\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n}\n\n.status-badge-inline.status-active { background: var(--test-success); }\n.status-badge-inline.status-disabled { background: var(--test-disabled); }\n.status-badge-inline.status-pending { background: var(--test-warning); }\n\n.test-type {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--test-text-secondary);\n padding: 4px 10px;\n background: var(--test-bg);\n border-radius: var(--test-radius-sm);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.header-actions button {\n white-space: nowrap;\n}\n\n/* Test Description */\n.test-description {\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--test-radius-md);\n margin-bottom: 16px;\n border: 1px solid var(--test-border);\n}\n\n.test-description p {\n margin: 0;\n color: var(--test-text-secondary);\n line-height: 1.6;\n font-size: 14px;\n}\n\n/* ===========================\n Metrics Bar\n =========================== */\n.metrics-bar {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 12px;\n}\n\n.metric-card {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n padding: 14px;\n text-align: center;\n transition: var(--test-transition);\n}\n\n.metric-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.metric-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n margin-bottom: 6px;\n}\n\n.metric-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n/* Progress bar in metric card */\n.metric-progress {\n margin-top: 8px;\n height: 4px;\n background: var(--test-border);\n border-radius: 2px;\n overflow: hidden;\n}\n\n.metric-progress-fill {\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 2px;\n transition: width 0.5s ease-out;\n}\n\n/* ===========================\n Tabs Navigation\n =========================== */\n.tabs-container {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.tabs {\n display: flex;\n padding: 0 20px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.tabs::-webkit-scrollbar {\n display: none;\n}\n\n.tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 18px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: var(--test-text-secondary);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--test-transition);\n white-space: nowrap;\n}\n\n.tab:hover {\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.tab.active {\n color: var(--test-primary);\n border-bottom-color: var(--test-primary);\n font-weight: 600;\n}\n\n.tab i {\n font-size: 15px;\n}\n\n.tab-badge {\n background: var(--test-border);\n color: var(--test-text-secondary);\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n transition: var(--test-transition);\n}\n\n.tab.active .tab-badge {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--test-primary);\n}\n\n.tab-shortcut {\n font-size: 10px;\n color: var(--test-text-muted);\n background: var(--test-bg);\n padding: 2px 6px;\n border-radius: 4px;\n font-weight: 600;\n margin-left: 4px;\n}\n\n/* ===========================\n Tab Content Area\n =========================== */\n.tab-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n/* ===========================\n Overview Tab\n =========================== */\n.overview-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: fadeIn 0.3s ease-out;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* Info Section */\n.info-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.info-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.info-section h3 i {\n color: var(--test-primary);\n}\n\n.info-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n}\n\n.info-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.info-label {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.info-value {\n font-size: 14px;\n color: var(--test-text);\n word-wrap: break-word;\n font-weight: 500;\n}\n\n/* JSON Section */\n.json-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.json-section h3 {\n margin: 0 0 16px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.json-section h3 i {\n color: var(--test-primary);\n}\n\n.json-tabs {\n display: flex;\n gap: 4px;\n margin-bottom: 16px;\n background: var(--test-bg);\n border-radius: var(--test-radius-md);\n padding: 4px;\n flex-wrap: wrap;\n}\n\n.json-tab {\n flex: 1;\n min-width: 100px;\n padding: 10px 14px;\n border: none;\n background: transparent;\n color: var(--test-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n border-radius: var(--test-radius-sm);\n transition: var(--test-transition);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n}\n\n.json-tab:hover {\n color: var(--test-text);\n background: var(--mj-bg-overlay);\n}\n\n.json-tab.active {\n background: var(--test-surface);\n color: var(--test-primary);\n font-weight: 600;\n box-shadow: var(--test-shadow-sm);\n}\n\n.json-tab i {\n font-size: 12px;\n}\n\n.code-editor-container {\n border-radius: var(--test-radius-md);\n overflow: hidden;\n border: 1px solid var(--test-border);\n min-height: 200px;\n max-height: 400px;\n}\n\n/* ===========================\n Configuration Tab\n =========================== */\n.config-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: fadeIn 0.3s ease-out;\n}\n\n.config-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.config-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.config-section h3 i {\n color: var(--test-primary);\n}\n\n.config-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 20px;\n}\n\n.config-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.config-item.full-width {\n grid-column: 1 / -1;\n}\n\n.config-item label {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.config-input {\n padding: 10px 14px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n font-size: 14px;\n transition: var(--test-transition);\n background: var(--test-surface);\n}\n\n.config-input:focus {\n outline: none;\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.config-input::placeholder {\n color: var(--test-text-muted);\n}\n\n.config-hint {\n font-size: 11px;\n color: var(--test-text-muted);\n margin-top: 4px;\n}\n\n.config-editor-container {\n border-radius: var(--test-radius-md);\n overflow: hidden;\n border: 1px solid var(--test-border);\n min-height: 200px;\n}\n\n.config-editor-container.small {\n min-height: 100px;\n max-height: 150px;\n}\n\n/* ===========================\n Runs Tab\n =========================== */\n.runs-tab,\n.suites-tab {\n animation: fadeIn 0.3s ease-out;\n}\n\n/* Loading States & Skeletons */\n.loading-state {\n padding: 0;\n}\n\n.skeleton-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.skeleton-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n border: 1px solid var(--test-border);\n}\n\n.skeleton-icon {\n width: 44px;\n height: 44px;\n border-radius: var(--test-radius-md);\n background: linear-gradient(90deg, var(--mj-border-default) 25%, var(--mj-bg-surface-sunken) 50%, var(--mj-border-default) 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n flex-shrink: 0;\n}\n\n.skeleton-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.skeleton-line {\n height: 14px;\n border-radius: 4px;\n background: linear-gradient(90deg, var(--mj-border-default) 25%, var(--mj-bg-surface-sunken) 50%, var(--mj-border-default) 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n}\n\n.skeleton-line.wide { width: 70%; }\n.skeleton-line.narrow { width: 40%; }\n\n@keyframes shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Runs List */\n.runs-list,\n.suites-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.run-item,\n.suite-item {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.run-item:hover,\n.suite-item:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n box-shadow: var(--test-shadow-sm);\n}\n\n.run-icon,\n.suite-icon {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--test-radius-md);\n color: var(--mj-text-inverse);\n font-size: 18px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-sm);\n}\n\n.suite-icon {\n background: var(--mj-status-warning);\n}\n\n.run-content,\n.suite-content {\n flex: 1;\n min-width: 0;\n}\n\n.run-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-id {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.run-status {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.suite-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 4px;\n}\n\n.run-meta,\n.suite-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--test-text-secondary);\n flex-wrap: wrap;\n}\n\n.run-meta span,\n.suite-meta span {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-meta span i,\n.suite-meta span i {\n color: var(--test-text-muted);\n font-size: 11px;\n}\n\n.run-item > i.fa-chevron-right,\n.suite-item > i.fa-chevron-right {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.run-item:hover > i.fa-chevron-right,\n.suite-item:hover > i.fa-chevron-right {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n/* Run Evaluation Stack */\n.run-eval-stack {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n/* Evaluation Pills */\n.eval-pill {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n transition: var(--test-transition);\n}\n\n.eval-pill i {\n font-size: 10px;\n}\n\n/* Status pill colors */\n.eval-pill.status-pill.status-passed {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.status-pill.status-failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.status-pill.status-error {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.status-pill.status-timeout {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.status-pill.status-skipped,\n.eval-pill.status-pill.status-pending {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.eval-pill.status-pill.status-running {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n/* Human feedback pills */\n.eval-pill.human-pill.no-feedback {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n padding: 4px 8px;\n}\n\n.eval-pill.human-pill.has-feedback.rating-low {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.human-pill.has-feedback.rating-medium {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.human-pill.has-feedback.rating-good {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.human-pill.has-feedback.rating-excellent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n/* Auto score pills */\n.eval-pill.auto-pill.no-score {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n padding: 4px 8px;\n}\n\n.eval-pill.auto-pill.has-score.score-low {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.auto-pill.has-score.score-medium {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.auto-pill.has-score.score-good {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.auto-pill.has-score.score-excellent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n/* Run Tags */\n.run-tags {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n.run-tag {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n.run-tag-more {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: var(--test-border);\n color: var(--test-text-muted);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n/* ===========================\n Keyboard Shortcuts Popup\n =========================== */\n/* Keyboard shortcuts toggle button */\n.shortcuts-toggle {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n box-shadow: var(--test-shadow-md);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--test-text-secondary);\n font-size: 14px;\n z-index: 99;\n transition: var(--test-transition);\n opacity: 0.7;\n}\n\n.shortcuts-toggle:hover {\n opacity: 1;\n transform: scale(1.1);\n color: var(--test-primary);\n border-color: var(--test-primary);\n}\n\n.keyboard-shortcuts {\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n padding: 12px 16px;\n box-shadow: var(--test-shadow-lg);\n font-size: 12px;\n color: var(--test-text-secondary);\n z-index: 100;\n max-width: 260px;\n}\n\n.shortcuts-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 10px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--test-border);\n font-weight: 600;\n color: var(--test-text);\n}\n\n.shortcuts-close {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--test-text-muted);\n font-size: 12px;\n padding: 2px 4px;\n border-radius: 4px;\n transition: var(--test-transition);\n}\n\n.shortcuts-close:hover {\n color: var(--test-text);\n background: var(--test-border);\n}\n\n.shortcut-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.shortcut-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.shortcut-keys {\n display: flex;\n gap: 4px;\n}\n\n.shortcut-keys kbd {\n background: var(--test-bg);\n border: 1px solid var(--test-border);\n border-radius: 4px;\n padding: 2px 6px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 11px;\n color: var(--test-text);\n}\n\n/* ===========================\n Responsive Design - Tablet\n =========================== */\n@media (max-width: 1024px) {\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .config-grid {\n grid-template-columns: 1fr;\n }\n\n .keyboard-shortcuts, .shortcuts-toggle {\n display: none;\n }\n}\n\n/* ===========================\n Responsive Design - Mobile\n =========================== */\n@media (max-width: 768px) {\n .test-form {\n height: auto;\n min-height: 100%;\n }\n\n .test-header {\n padding: 16px;\n }\n\n .header-content {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-left {\n width: 100%;\n }\n\n .test-icon {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .test-info h1 {\n font-size: 18px;\n }\n\n .test-meta {\n gap: 8px;\n }\n\n .status-badge {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .header-actions {\n width: 100%;\n justify-content: stretch;\n }\n\n .header-actions button {\n flex: 1;\n }\n\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n gap: 10px;\n }\n\n .metric-card {\n padding: 12px;\n }\n\n .metric-value {\n font-size: 16px;\n }\n\n .tabs {\n padding: 0 12px;\n }\n\n .tab {\n padding: 12px 14px;\n font-size: 13px;\n gap: 6px;\n }\n\n .tab i {\n font-size: 14px;\n }\n\n .tab-shortcut {\n display: none;\n }\n\n .tab-content {\n padding: 16px;\n }\n\n .info-section,\n .json-section,\n .config-section {\n padding: 18px;\n }\n\n .info-grid {\n grid-template-columns: 1fr;\n }\n\n .json-tabs {\n flex-direction: column;\n }\n\n .json-tab {\n min-width: 0;\n justify-content: flex-start;\n }\n\n .run-item,\n .suite-item {\n padding: 14px;\n }\n\n .run-icon,\n .suite-icon {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .run-meta,\n .suite-meta {\n flex-direction: column;\n gap: 4px;\n }\n\n}\n\n/* ===========================\n Responsive Design - Small Mobile\n =========================== */\n@media (max-width: 480px) {\n .test-header {\n padding: 12px;\n }\n\n .header-left {\n gap: 12px;\n }\n\n .test-icon {\n width: 40px;\n height: 40px;\n font-size: 18px;\n border-radius: 8px;\n }\n\n .test-info h1 {\n font-size: 16px;\n }\n\n .metrics-bar {\n grid-template-columns: 1fr 1fr;\n }\n\n .tabs {\n padding: 0 8px;\n }\n\n .tab {\n padding: 10px 12px;\n font-size: 12px;\n }\n\n .tab-badge {\n display: none;\n }\n\n .tab-content {\n padding: 12px;\n }\n\n .run-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n}\n\n/* ===========================\n Touch Device Optimizations\n =========================== */\n@media (hover: none) and (pointer: coarse) {\n .tab,\n .json-tab,\n .run-item,\n .suite-item {\n -webkit-tap-highlight-color: transparent;\n }\n\n .run-item:active,\n .suite-item:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n transform: scale(0.98);\n }\n\n .tab:active,\n .json-tab:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n /* Larger touch targets */\n .tab {\n min-height: 48px;\n }\n\n .run-item,\n .suite-item {\n min-height: 64px;\n }\n}\n\n/* ===========================\n Reduced Motion\n =========================== */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n .skeleton-icon,\n .skeleton-line {\n animation: none;\n background: var(--mj-border-default);\n }\n}\n\n/* ===========================\n History Tab\n =========================== */\n.history-tab {\n animation: fadeIn 0.3s ease-out;\n}\n\n.history-content {\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n/* History Filters */\n.history-filters {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n padding: 16px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n box-shadow: var(--test-shadow-sm);\n}\n\n.time-range-filters {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--test-text-secondary);\n margin-right: 4px;\n}\n\n.filter-btn {\n padding: 8px 16px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n background: var(--test-surface);\n color: var(--test-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.filter-btn:hover {\n border-color: var(--test-primary-light);\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.filter-btn.active {\n background: var(--test-primary);\n color: var(--mj-text-inverse);\n border-color: var(--test-primary);\n}\n\n.history-actions {\n display: flex;\n gap: 8px;\n}\n\n/* KPI Cards */\n.history-kpi-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 16px;\n}\n\n.kpi-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n box-shadow: var(--test-shadow-sm);\n transition: var(--test-transition);\n}\n\n.kpi-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.kpi-icon {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-brand-primary);\n border-radius: var(--test-radius-md);\n color: var(--mj-text-inverse);\n font-size: 20px;\n flex-shrink: 0;\n}\n\n.kpi-icon.pass-rate {\n background: var(--mj-status-success);\n}\n\n.kpi-content {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--test-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n}\n\n.trend-icon {\n font-size: 14px;\n}\n\n.trend-icon.trend-up {\n color: var(--test-success);\n}\n\n.trend-icon.trend-down {\n color: var(--test-error);\n}\n\n/* History Section */\n.history-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.history-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.history-section h3 i {\n color: var(--test-primary);\n}\n\n/* History Table */\n.history-table-container {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 14px;\n}\n\n.history-table th,\n.history-table td {\n padding: 12px 16px;\n text-align: left;\n border-bottom: 1px solid var(--test-border);\n}\n\n.history-table th {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n background: var(--test-bg);\n}\n\n.history-table tbody tr:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, transparent);\n}\n\n.date-cell {\n font-weight: 600;\n color: var(--test-text);\n}\n\n.passed-cell {\n color: var(--test-success);\n font-weight: 600;\n}\n\n.failed-cell {\n color: var(--test-error);\n font-weight: 600;\n}\n\n.pass-rate-cell {\n min-width: 120px;\n}\n\n.pass-rate-bar {\n position: relative;\n height: 24px;\n background: var(--test-bg);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.pass-rate-fill {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 12px;\n transition: width 0.5s ease-out;\n}\n\n.pass-rate-text {\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n font-size: 11px;\n font-weight: 700;\n color: var(--test-text);\n z-index: 1;\n}\n\n/* Suite Performance List */\n.suite-performance-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.suite-perf-card {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 18px;\n background: var(--test-bg);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.suite-perf-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n}\n\n.suite-perf-header {\n flex: 1;\n min-width: 0;\n}\n\n.suite-perf-name {\n font-size: 15px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 6px;\n}\n\n.suite-perf-tags {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.tag-mini {\n display: inline-flex;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.tag-more {\n display: inline-flex;\n padding: 2px 8px;\n background: var(--test-border);\n color: var(--test-text-muted);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.suite-perf-stats {\n display: flex;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.suite-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n}\n\n.suite-stat .stat-value {\n font-size: 16px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n.suite-stat .stat-value.pass-rate.high {\n color: var(--test-success);\n}\n\n.suite-stat .stat-value.pass-rate.low {\n color: var(--test-error);\n}\n\n.suite-stat .stat-label {\n font-size: 10px;\n color: var(--test-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.suite-perf-arrow {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.suite-perf-card:hover .suite-perf-arrow {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n/* ===========================\n Print Styles\n =========================== */\n@media print {\n .test-form {\n background: var(--mj-bg-surface);\n height: auto;\n }\n\n .header-actions,\n .tabs-container,\n .keyboard-shortcuts {\n display: none !important;\n }\n\n .tab-content {\n overflow: visible;\n padding: 0;\n }\n\n .info-section,\n .json-section,\n .config-section {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n}\n\n/* ===========================\n Editable Form Sections (Config tab)\n =========================== */\n\n.edit-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.edit-section-header {\n margin: 0 0 18px 0;\n}\n\n.edit-section-header h3 {\n margin: 0 0 4px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.edit-section-header h3 i {\n color: var(--test-primary);\n}\n\n.edit-section-sub {\n margin: 0;\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.edit-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 18px;\n}\n\n@media (max-width: 720px) {\n .edit-grid {\n grid-template-columns: 1fr;\n }\n}\n\n.edit-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.edit-field--full {\n grid-column: 1 / -1;\n}\n\n.edit-field label {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.edit-field .required {\n color: var(--mj-status-error);\n margin-left: 2px;\n}\n\n.config-textarea {\n resize: vertical;\n min-height: 72px;\n font-family: inherit;\n line-height: 1.5;\n}\n\n.select-wrapper {\n position: relative;\n}\n\n.select-wrapper select.config-input {\n padding-right: 36px;\n appearance: none;\n background-color: var(--test-surface);\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2364748b' d='M1.41 0L6 4.59 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 14px center;\n background-size: 10px 7px;\n}\n\n/* Tag editor (chips + inline input) */\n.tag-editor {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 10px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n background: var(--test-surface);\n transition: var(--test-transition);\n cursor: text;\n min-height: 42px;\n align-items: center;\n}\n\n.tag-editor:focus-within {\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.tag-chip-editable {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 4px 3px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n border-radius: 999px;\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n}\n\n.tag-chip-editable .tag-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: transparent;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-size: 10px;\n transition: background 0.15s;\n}\n\n.tag-chip-editable .tag-remove:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n color: var(--mj-brand-primary-hover);\n}\n\n.tag-input-inline {\n flex: 1;\n min-width: 140px;\n border: none;\n background: transparent;\n outline: none;\n font-size: 13px;\n color: var(--test-text);\n padding: 4px 2px;\n}\n\n.tag-input-inline::placeholder {\n color: var(--test-text-muted);\n}\n\n/* Read-only metadata block at bottom of Config tab */\n.meta-section {\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--test-radius-md);\n padding: 14px 18px;\n border: 1px solid var(--test-border);\n}\n\n.meta-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 14px;\n}\n\n.meta-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.meta-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.meta-value {\n font-size: 12px;\n color: var(--test-text-secondary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.meta-mono {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n font-size: 11px;\n}\n\n/* Dirty indicator next to the title */\n.dirty-indicator {\n display: inline-block;\n margin-left: 8px;\n font-size: 14px;\n color: var(--mj-status-warning);\n line-height: 1;\n animation: pulseDot 1.8s ease-in-out infinite;\n vertical-align: middle;\n}\n\n@keyframes pulseDot {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.85); }\n}\n\n.unsaved-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n border-radius: 999px;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.unsaved-pill i {\n font-size: 6px;\n animation: pulseDot 1.8s ease-in-out infinite;\n}\n\n/* Pad the bottom of the tab content when the save bar is visible\n so the bar doesn't cover the last form field. */\n.tab-content.has-savebar {\n padding-bottom: 84px;\n}\n\n/* ===========================\n Sticky Save Bar\n =========================== */\n\n.save-bar {\n position: absolute;\n left: 16px;\n right: 96px; /* leaves room for the bottom-right chat launcher */\n bottom: 16px;\n z-index: 50;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 12px 16px 12px 20px;\n background: var(--mj-bg-surface-elevated, var(--test-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--test-border));\n border-radius: 14px;\n box-shadow: 0 12px 32px color-mix(in srgb, var(--mj-status-warning) 10%, rgba(0, 0, 0, 0.18));\n backdrop-filter: blur(8px);\n /* Hidden / off-screen state by default. The .save-bar--visible class\n animates it up into view. Using `transition` (not `animation`)\n guarantees the change runs every time isDirty toggles. */\n opacity: 0;\n transform: translateY(calc(100% + 32px));\n pointer-events: none;\n transition:\n transform 420ms cubic-bezier(0.16, 1, 0.3, 1),\n opacity 260ms cubic-bezier(0.16, 1, 0.3, 1);\n will-change: transform, opacity;\n}\n\n.save-bar--visible {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .save-bar {\n transition: opacity 180ms ease-out;\n transform: none;\n }\n .save-bar--visible {\n transform: none;\n }\n}\n\n.save-bar-message {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.save-bar-dot {\n color: var(--mj-status-warning);\n font-size: 12px;\n line-height: 1;\n animation: pulseDot 1.8s ease-in-out infinite;\n}\n\n.save-bar-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.save-bar-text strong {\n font-size: 14px;\n color: var(--test-text);\n font-weight: 700;\n}\n\n.save-bar-fields {\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.save-bar-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.save-bar-btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 9px 16px;\n font-size: 13px;\n font-weight: 600;\n border-radius: 8px;\n border: 1px solid transparent;\n cursor: pointer;\n transition: var(--test-transition);\n font-family: inherit;\n}\n\n.save-bar-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.save-bar-btn--primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, white);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n}\n\n.save-bar-btn--primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n}\n\n.save-bar-btn--primary:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.save-bar-btn--ghost {\n background: transparent;\n color: var(--test-text-secondary);\n border-color: var(--test-border);\n}\n\n.save-bar-btn--ghost:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover, var(--mj-bg-surface-card));\n color: var(--test-text);\n border-color: var(--test-text-muted);\n}\n\n.save-bar-kbd {\n display: inline-flex;\n gap: 3px;\n margin-left: 6px;\n opacity: 0.85;\n}\n\n.save-bar-kbd kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 4px;\n font-size: 10px;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n background: color-mix(in srgb, white 18%, transparent);\n border: 1px solid color-mix(in srgb, white 35%, transparent);\n border-radius: 4px;\n color: inherit;\n}\n\n@media (max-width: 640px) {\n .save-bar {\n left: 8px;\n right: 8px;\n bottom: 88px; /* push above the chat launcher on small screens */\n flex-direction: column;\n align-items: stretch;\n padding: 12px;\n }\n .save-bar-actions {\n justify-content: space-between;\n }\n .save-bar-kbd {\n display: none;\n }\n}\n\n"] }]
|
|
2732
2774
|
}], null, { handleKeyboardShortcut: [{
|
|
2733
2775
|
type: HostListener,
|
|
2734
2776
|
args: ['document:keydown', ['$event']]
|
|
@@ -2736,5 +2778,5 @@ export { MJTestFormComponentExtended };
|
|
|
2736
2778
|
type: HostListener,
|
|
2737
2779
|
args: ['window:beforeunload', ['$event']]
|
|
2738
2780
|
}] }); })();
|
|
2739
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTestFormComponentExtended, { className: "MJTestFormComponentExtended", filePath: "src/lib/custom/Tests/test-form.component.ts", lineNumber:
|
|
2781
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTestFormComponentExtended, { className: "MJTestFormComponentExtended", filePath: "src/lib/custom/Tests/test-form.component.ts", lineNumber: 64 }); })();
|
|
2740
2782
|
//# sourceMappingURL=test-form.component.js.map
|