@memberjunction/ng-core-entity-forms 2.128.0 → 2.130.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.d.ts.map +1 -1
  2. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.js +3 -9
  3. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.js.map +1 -1
  4. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.d.ts.map +1 -1
  5. package/dist/lib/custom/AIAgents/add-action-dialog.component.d.ts +1 -1
  6. package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.d.ts +2 -1
  7. package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.d.ts.map +1 -1
  8. package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.js +3 -3
  9. package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.js.map +1 -1
  10. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts +2 -1
  11. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
  12. package/dist/lib/custom/AIAgents/ai-agent-form.component.js +1 -1
  13. package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
  14. package/dist/lib/custom/AIAgents/ai-agent-management.service.d.ts +2 -1
  15. package/dist/lib/custom/AIAgents/ai-agent-management.service.d.ts.map +1 -1
  16. package/dist/lib/custom/AIAgents/ai-agent-management.service.js.map +1 -1
  17. package/dist/lib/custom/AIAgents/create-prompt-dialog.component.d.ts +2 -1
  18. package/dist/lib/custom/AIAgents/create-prompt-dialog.component.d.ts.map +1 -1
  19. package/dist/lib/custom/AIAgents/create-prompt-dialog.component.js +1 -1
  20. package/dist/lib/custom/AIAgents/create-prompt-dialog.component.js.map +1 -1
  21. package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.d.ts +2 -1
  22. package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.d.ts.map +1 -1
  23. package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js.map +1 -1
  24. package/dist/lib/custom/AIAgents/new-agent-dialog.component.d.ts +2 -1
  25. package/dist/lib/custom/AIAgents/new-agent-dialog.component.d.ts.map +1 -1
  26. package/dist/lib/custom/AIAgents/new-agent-dialog.component.js +1 -1
  27. package/dist/lib/custom/AIAgents/new-agent-dialog.component.js.map +1 -1
  28. package/dist/lib/custom/AIAgents/new-agent-dialog.service.d.ts +1 -1
  29. package/dist/lib/custom/AIAgents/new-agent-dialog.service.d.ts.map +1 -1
  30. package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.d.ts +1 -1
  31. package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.d.ts.map +1 -1
  32. package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.d.ts +2 -1
  33. package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.d.ts.map +1 -1
  34. package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.js +1 -1
  35. package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.js.map +1 -1
  36. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.d.ts +2 -1
  37. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.d.ts.map +1 -1
  38. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js +1 -1
  39. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js.map +1 -1
  40. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts +2 -1
  41. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts.map +1 -1
  42. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +1 -1
  43. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
  44. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts +2 -1
  45. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts.map +1 -1
  46. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +1 -1
  47. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
  48. package/dist/lib/custom/Entities/entity-form.component.d.ts +200 -0
  49. package/dist/lib/custom/Entities/entity-form.component.d.ts.map +1 -0
  50. package/dist/lib/custom/Entities/entity-form.component.js +2543 -0
  51. package/dist/lib/custom/Entities/entity-form.component.js.map +1 -0
  52. package/dist/lib/custom/Templates/templates-form.component.js +3 -3
  53. package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
  54. package/dist/lib/custom/Tests/entity-link-pill.component.d.ts +44 -0
  55. package/dist/lib/custom/Tests/entity-link-pill.component.d.ts.map +1 -0
  56. package/dist/lib/custom/Tests/entity-link-pill.component.js +124 -0
  57. package/dist/lib/custom/Tests/entity-link-pill.component.js.map +1 -0
  58. package/dist/lib/custom/Tests/test-form.component.d.ts +94 -8
  59. package/dist/lib/custom/Tests/test-form.component.d.ts.map +1 -1
  60. package/dist/lib/custom/Tests/test-form.component.js +1527 -276
  61. package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
  62. package/dist/lib/custom/Tests/test-run-form.component.d.ts +48 -8
  63. package/dist/lib/custom/Tests/test-run-form.component.d.ts.map +1 -1
  64. package/dist/lib/custom/Tests/test-run-form.component.js +1078 -426
  65. package/dist/lib/custom/Tests/test-run-form.component.js.map +1 -1
  66. package/dist/lib/custom/Tests/test-suite-form.component.d.ts +227 -5
  67. package/dist/lib/custom/Tests/test-suite-form.component.d.ts.map +1 -1
  68. package/dist/lib/custom/Tests/test-suite-form.component.js +3307 -200
  69. package/dist/lib/custom/Tests/test-suite-form.component.js.map +1 -1
  70. package/dist/lib/custom/Tests/test-suite-run-form.component.d.ts +86 -2
  71. package/dist/lib/custom/Tests/test-suite-run-form.component.d.ts.map +1 -1
  72. package/dist/lib/custom/Tests/test-suite-run-form.component.js +1975 -262
  73. package/dist/lib/custom/Tests/test-suite-run-form.component.js.map +1 -1
  74. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts +10 -3
  75. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts.map +1 -1
  76. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +275 -244
  77. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
  78. package/dist/lib/custom/custom-forms.module.d.ts +28 -25
  79. package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
  80. package/dist/lib/custom/custom-forms.module.js +25 -11
  81. package/dist/lib/custom/custom-forms.module.js.map +1 -1
  82. package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.d.ts.map +1 -1
  83. package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.js +154 -122
  84. package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.js.map +1 -1
  85. package/dist/lib/generated/Entities/AIAgentExample/aiagentexample.form.component.d.ts.map +1 -1
  86. package/dist/lib/generated/Entities/AIAgentExample/aiagentexample.form.component.js +2 -12
  87. package/dist/lib/generated/Entities/AIAgentExample/aiagentexample.form.component.js.map +1 -1
  88. package/dist/lib/generated/Entities/AIAgentModality/aiagentmodality.form.component.d.ts +11 -0
  89. package/dist/lib/generated/Entities/AIAgentModality/aiagentmodality.form.component.d.ts.map +1 -0
  90. package/dist/lib/generated/Entities/AIAgentModality/aiagentmodality.form.component.js +75 -0
  91. package/dist/lib/generated/Entities/AIAgentModality/aiagentmodality.form.component.js.map +1 -0
  92. package/dist/lib/generated/Entities/AIAgentNote/aiagentnote.form.component.d.ts.map +1 -1
  93. package/dist/lib/generated/Entities/AIAgentNote/aiagentnote.form.component.js +2 -12
  94. package/dist/lib/generated/Entities/AIAgentNote/aiagentnote.form.component.js.map +1 -1
  95. package/dist/lib/generated/Entities/AIAgentRunStep/aiagentrunstep.form.component.d.ts.map +1 -1
  96. package/dist/lib/generated/Entities/AIAgentRunStep/aiagentrunstep.form.component.js +6 -16
  97. package/dist/lib/generated/Entities/AIAgentRunStep/aiagentrunstep.form.component.js.map +1 -1
  98. package/dist/lib/generated/Entities/AIArchitecture/aiarchitecture.form.component.d.ts +11 -0
  99. package/dist/lib/generated/Entities/AIArchitecture/aiarchitecture.form.component.d.ts.map +1 -0
  100. package/dist/lib/generated/Entities/AIArchitecture/aiarchitecture.form.component.js +121 -0
  101. package/dist/lib/generated/Entities/AIArchitecture/aiarchitecture.form.component.js.map +1 -0
  102. package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.d.ts.map +1 -1
  103. package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.js +77 -41
  104. package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.js.map +1 -1
  105. package/dist/lib/generated/Entities/AICredentialBinding/aicredentialbinding.form.component.d.ts +11 -0
  106. package/dist/lib/generated/Entities/AICredentialBinding/aicredentialbinding.form.component.d.ts.map +1 -0
  107. package/dist/lib/generated/Entities/AICredentialBinding/aicredentialbinding.form.component.js +69 -0
  108. package/dist/lib/generated/Entities/AICredentialBinding/aicredentialbinding.form.component.js.map +1 -0
  109. package/dist/lib/generated/Entities/AIModality/aimodality.form.component.d.ts +11 -0
  110. package/dist/lib/generated/Entities/AIModality/aimodality.form.component.d.ts.map +1 -0
  111. package/dist/lib/generated/Entities/AIModality/aimodality.form.component.js +167 -0
  112. package/dist/lib/generated/Entities/AIModality/aimodality.form.component.js.map +1 -0
  113. package/dist/lib/generated/Entities/AIModel/aimodel.form.component.d.ts.map +1 -1
  114. package/dist/lib/generated/Entities/AIModel/aimodel.form.component.js +160 -102
  115. package/dist/lib/generated/Entities/AIModel/aimodel.form.component.js.map +1 -1
  116. package/dist/lib/generated/Entities/AIModelArchitecture/aimodelarchitecture.form.component.d.ts +11 -0
  117. package/dist/lib/generated/Entities/AIModelArchitecture/aimodelarchitecture.form.component.d.ts.map +1 -0
  118. package/dist/lib/generated/Entities/AIModelArchitecture/aimodelarchitecture.form.component.js +73 -0
  119. package/dist/lib/generated/Entities/AIModelArchitecture/aimodelarchitecture.form.component.js.map +1 -0
  120. package/dist/lib/generated/Entities/AIModelModality/aimodelmodality.form.component.d.ts +11 -0
  121. package/dist/lib/generated/Entities/AIModelModality/aimodelmodality.form.component.d.ts.map +1 -0
  122. package/dist/lib/generated/Entities/AIModelModality/aimodelmodality.form.component.js +89 -0
  123. package/dist/lib/generated/Entities/AIModelModality/aimodelmodality.form.component.js.map +1 -0
  124. package/dist/lib/generated/Entities/AIModelType/aimodeltype.form.component.d.ts.map +1 -1
  125. package/dist/lib/generated/Entities/AIModelType/aimodeltype.form.component.js +27 -13
  126. package/dist/lib/generated/Entities/AIModelType/aimodeltype.form.component.js.map +1 -1
  127. package/dist/lib/generated/Entities/AIModelVendor/aimodelvendor.form.component.d.ts.map +1 -1
  128. package/dist/lib/generated/Entities/AIModelVendor/aimodelvendor.form.component.js +27 -7
  129. package/dist/lib/generated/Entities/AIModelVendor/aimodelvendor.form.component.js.map +1 -1
  130. package/dist/lib/generated/Entities/AIPromptModel/aipromptmodel.form.component.d.ts.map +1 -1
  131. package/dist/lib/generated/Entities/AIPromptModel/aipromptmodel.form.component.js +27 -7
  132. package/dist/lib/generated/Entities/AIPromptModel/aipromptmodel.form.component.js.map +1 -1
  133. package/dist/lib/generated/Entities/AIPromptRun/aipromptrun.form.component.js +34 -32
  134. package/dist/lib/generated/Entities/AIPromptRun/aipromptrun.form.component.js.map +1 -1
  135. package/dist/lib/generated/Entities/AIResultCache/airesultcache.form.component.d.ts.map +1 -1
  136. package/dist/lib/generated/Entities/AIResultCache/airesultcache.form.component.js +3 -11
  137. package/dist/lib/generated/Entities/AIResultCache/airesultcache.form.component.js.map +1 -1
  138. package/dist/lib/generated/Entities/AIVendor/aivendor.form.component.d.ts.map +1 -1
  139. package/dist/lib/generated/Entities/AIVendor/aivendor.form.component.js +69 -41
  140. package/dist/lib/generated/Entities/AIVendor/aivendor.form.component.js.map +1 -1
  141. package/dist/lib/generated/Entities/CompanyIntegrationRunAPILog/companyintegrationrunapilog.form.component.js +2 -2
  142. package/dist/lib/generated/Entities/CompanyIntegrationRunAPILog/companyintegrationrunapilog.form.component.js.map +1 -1
  143. package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.d.ts.map +1 -1
  144. package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.js +84 -56
  145. package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.js.map +1 -1
  146. package/dist/lib/generated/Entities/ConversationDetailArtifact/conversationdetailartifact.form.component.d.ts.map +1 -1
  147. package/dist/lib/generated/Entities/ConversationDetailArtifact/conversationdetailartifact.form.component.js +3 -11
  148. package/dist/lib/generated/Entities/ConversationDetailArtifact/conversationdetailartifact.form.component.js.map +1 -1
  149. package/dist/lib/generated/Entities/ConversationDetailAttachment/conversationdetailattachment.form.component.d.ts +11 -0
  150. package/dist/lib/generated/Entities/ConversationDetailAttachment/conversationdetailattachment.form.component.d.ts.map +1 -0
  151. package/dist/lib/generated/Entities/ConversationDetailAttachment/conversationdetailattachment.form.component.js +95 -0
  152. package/dist/lib/generated/Entities/ConversationDetailAttachment/conversationdetailattachment.form.component.js.map +1 -0
  153. package/dist/lib/generated/Entities/ConversationDetailRating/conversationdetailrating.form.component.d.ts.map +1 -1
  154. package/dist/lib/generated/Entities/ConversationDetailRating/conversationdetailrating.form.component.js +3 -11
  155. package/dist/lib/generated/Entities/ConversationDetailRating/conversationdetailrating.form.component.js.map +1 -1
  156. package/dist/lib/generated/Entities/Credential/credential.form.component.d.ts +11 -0
  157. package/dist/lib/generated/Entities/Credential/credential.form.component.d.ts.map +1 -0
  158. package/dist/lib/generated/Entities/Credential/credential.form.component.js +111 -0
  159. package/dist/lib/generated/Entities/Credential/credential.form.component.js.map +1 -0
  160. package/dist/lib/generated/Entities/CredentialCategory/credentialcategory.form.component.d.ts +11 -0
  161. package/dist/lib/generated/Entities/CredentialCategory/credentialcategory.form.component.d.ts.map +1 -0
  162. package/dist/lib/generated/Entities/CredentialCategory/credentialcategory.form.component.js +109 -0
  163. package/dist/lib/generated/Entities/CredentialCategory/credentialcategory.form.component.js.map +1 -0
  164. package/dist/lib/generated/Entities/CredentialType/credentialtype.form.component.d.ts +11 -0
  165. package/dist/lib/generated/Entities/CredentialType/credentialtype.form.component.d.ts.map +1 -0
  166. package/dist/lib/generated/Entities/CredentialType/credentialtype.form.component.js +109 -0
  167. package/dist/lib/generated/Entities/CredentialType/credentialtype.form.component.js.map +1 -0
  168. package/dist/lib/generated/Entities/DataContextItem/datacontextitem.form.component.js +2 -2
  169. package/dist/lib/generated/Entities/DuplicateRunDetail/duplicaterundetail.form.component.d.ts.map +1 -1
  170. package/dist/lib/generated/Entities/DuplicateRunDetail/duplicaterundetail.form.component.js +8 -16
  171. package/dist/lib/generated/Entities/DuplicateRunDetail/duplicaterundetail.form.component.js.map +1 -1
  172. package/dist/lib/generated/Entities/EmployeeCompanyIntegration/employeecompanyintegration.form.component.d.ts.map +1 -1
  173. package/dist/lib/generated/Entities/EmployeeCompanyIntegration/employeecompanyintegration.form.component.js +3 -11
  174. package/dist/lib/generated/Entities/EmployeeCompanyIntegration/employeecompanyintegration.form.component.js.map +1 -1
  175. package/dist/lib/generated/Entities/EmployeeRole/employeerole.form.component.d.ts.map +1 -1
  176. package/dist/lib/generated/Entities/EmployeeRole/employeerole.form.component.js +4 -12
  177. package/dist/lib/generated/Entities/EmployeeRole/employeerole.form.component.js.map +1 -1
  178. package/dist/lib/generated/Entities/EmployeeSkill/employeeskill.form.component.d.ts.map +1 -1
  179. package/dist/lib/generated/Entities/EmployeeSkill/employeeskill.form.component.js +3 -11
  180. package/dist/lib/generated/Entities/EmployeeSkill/employeeskill.form.component.js.map +1 -1
  181. package/dist/lib/generated/Entities/EncryptionAlgorithm/encryptionalgorithm.form.component.d.ts +11 -0
  182. package/dist/lib/generated/Entities/EncryptionAlgorithm/encryptionalgorithm.form.component.d.ts.map +1 -0
  183. package/dist/lib/generated/Entities/EncryptionAlgorithm/encryptionalgorithm.form.component.js +81 -0
  184. package/dist/lib/generated/Entities/EncryptionAlgorithm/encryptionalgorithm.form.component.js.map +1 -0
  185. package/dist/lib/generated/Entities/EncryptionKey/encryptionkey.form.component.d.ts +11 -0
  186. package/dist/lib/generated/Entities/EncryptionKey/encryptionkey.form.component.d.ts.map +1 -0
  187. package/dist/lib/generated/Entities/EncryptionKey/encryptionkey.form.component.js +93 -0
  188. package/dist/lib/generated/Entities/EncryptionKey/encryptionkey.form.component.js.map +1 -0
  189. package/dist/lib/generated/Entities/EncryptionKeySource/encryptionkeysource.form.component.d.ts +11 -0
  190. package/dist/lib/generated/Entities/EncryptionKeySource/encryptionkeysource.form.component.d.ts.map +1 -0
  191. package/dist/lib/generated/Entities/EncryptionKeySource/encryptionkeysource.form.component.js +81 -0
  192. package/dist/lib/generated/Entities/EncryptionKeySource/encryptionkeysource.form.component.js.map +1 -0
  193. package/dist/lib/generated/Entities/Entity/entity.form.component.d.ts.map +1 -1
  194. package/dist/lib/generated/Entities/Entity/entity.form.component.js +61 -43
  195. package/dist/lib/generated/Entities/Entity/entity.form.component.js.map +1 -1
  196. package/dist/lib/generated/Entities/EntityActionFilter/entityactionfilter.form.component.d.ts.map +1 -1
  197. package/dist/lib/generated/Entities/EntityActionFilter/entityactionfilter.form.component.js +2 -12
  198. package/dist/lib/generated/Entities/EntityActionFilter/entityactionfilter.form.component.js.map +1 -1
  199. package/dist/lib/generated/Entities/EntityActionInvocation/entityactioninvocation.form.component.d.ts.map +1 -1
  200. package/dist/lib/generated/Entities/EntityActionInvocation/entityactioninvocation.form.component.js +3 -11
  201. package/dist/lib/generated/Entities/EntityActionInvocation/entityactioninvocation.form.component.js.map +1 -1
  202. package/dist/lib/generated/Entities/EntityActionParam/entityactionparam.form.component.d.ts.map +1 -1
  203. package/dist/lib/generated/Entities/EntityActionParam/entityactionparam.form.component.js +3 -11
  204. package/dist/lib/generated/Entities/EntityActionParam/entityactionparam.form.component.js.map +1 -1
  205. package/dist/lib/generated/Entities/EntityCommunicationField/entitycommunicationfield.form.component.d.ts.map +1 -1
  206. package/dist/lib/generated/Entities/EntityCommunicationField/entitycommunicationfield.form.component.js +3 -11
  207. package/dist/lib/generated/Entities/EntityCommunicationField/entitycommunicationfield.form.component.js.map +1 -1
  208. package/dist/lib/generated/Entities/EntityField/entityfield.form.component.d.ts.map +1 -1
  209. package/dist/lib/generated/Entities/EntityField/entityfield.form.component.js +22 -8
  210. package/dist/lib/generated/Entities/EntityField/entityfield.form.component.js.map +1 -1
  211. package/dist/lib/generated/Entities/ErrorLog/errorlog.form.component.d.ts.map +1 -1
  212. package/dist/lib/generated/Entities/ErrorLog/errorlog.form.component.js +2 -12
  213. package/dist/lib/generated/Entities/ErrorLog/errorlog.form.component.js.map +1 -1
  214. package/dist/lib/generated/Entities/File/file.form.component.d.ts.map +1 -1
  215. package/dist/lib/generated/Entities/File/file.form.component.js +22 -4
  216. package/dist/lib/generated/Entities/File/file.form.component.js.map +1 -1
  217. package/dist/lib/generated/Entities/FileStorageProvider/filestorageprovider.form.component.d.ts.map +1 -1
  218. package/dist/lib/generated/Entities/FileStorageProvider/filestorageprovider.form.component.js +40 -4
  219. package/dist/lib/generated/Entities/FileStorageProvider/filestorageprovider.form.component.js.map +1 -1
  220. package/dist/lib/generated/Entities/Query/query.form.component.js +34 -32
  221. package/dist/lib/generated/Entities/Query/query.form.component.js.map +1 -1
  222. package/dist/lib/generated/Entities/Recommendation/recommendation.form.component.d.ts.map +1 -1
  223. package/dist/lib/generated/Entities/Recommendation/recommendation.form.component.js +8 -16
  224. package/dist/lib/generated/Entities/Recommendation/recommendation.form.component.js.map +1 -1
  225. package/dist/lib/generated/Entities/RecommendationItem/recommendationitem.form.component.d.ts.map +1 -1
  226. package/dist/lib/generated/Entities/RecommendationItem/recommendationitem.form.component.js +3 -11
  227. package/dist/lib/generated/Entities/RecommendationItem/recommendationitem.form.component.js.map +1 -1
  228. package/dist/lib/generated/Entities/RecordChange/recordchange.form.component.d.ts.map +1 -1
  229. package/dist/lib/generated/Entities/RecordChange/recordchange.form.component.js +3 -11
  230. package/dist/lib/generated/Entities/RecordChange/recordchange.form.component.js.map +1 -1
  231. package/dist/lib/generated/Entities/RecordMergeDeletionLog/recordmergedeletionlog.form.component.d.ts.map +1 -1
  232. package/dist/lib/generated/Entities/RecordMergeDeletionLog/recordmergedeletionlog.form.component.js +3 -11
  233. package/dist/lib/generated/Entities/RecordMergeDeletionLog/recordmergedeletionlog.form.component.js.map +1 -1
  234. package/dist/lib/generated/Entities/Report/report.form.component.d.ts.map +1 -1
  235. package/dist/lib/generated/Entities/Report/report.form.component.js +17 -25
  236. package/dist/lib/generated/Entities/Report/report.form.component.js.map +1 -1
  237. package/dist/lib/generated/Entities/Task/task.form.component.d.ts.map +1 -1
  238. package/dist/lib/generated/Entities/Task/task.form.component.js +17 -25
  239. package/dist/lib/generated/Entities/Task/task.form.component.js.map +1 -1
  240. package/dist/lib/generated/Entities/TemplateParam/templateparam.form.component.d.ts.map +1 -1
  241. package/dist/lib/generated/Entities/TemplateParam/templateparam.form.component.js +3 -11
  242. package/dist/lib/generated/Entities/TemplateParam/templateparam.form.component.js.map +1 -1
  243. package/dist/lib/generated/Entities/Test/test.form.component.js +17 -15
  244. package/dist/lib/generated/Entities/Test/test.form.component.js.map +1 -1
  245. package/dist/lib/generated/Entities/TestRun/testrun.form.component.d.ts.map +1 -1
  246. package/dist/lib/generated/Entities/TestRun/testrun.form.component.js +72 -28
  247. package/dist/lib/generated/Entities/TestRun/testrun.form.component.js.map +1 -1
  248. package/dist/lib/generated/Entities/TestRunFeedback/testrunfeedback.form.component.d.ts.map +1 -1
  249. package/dist/lib/generated/Entities/TestRunFeedback/testrunfeedback.form.component.js +18 -4
  250. package/dist/lib/generated/Entities/TestRunFeedback/testrunfeedback.form.component.js.map +1 -1
  251. package/dist/lib/generated/Entities/TestSuite/testsuite.form.component.d.ts.map +1 -1
  252. package/dist/lib/generated/Entities/TestSuite/testsuite.form.component.js +39 -19
  253. package/dist/lib/generated/Entities/TestSuite/testsuite.form.component.js.map +1 -1
  254. package/dist/lib/generated/Entities/TestSuiteRun/testsuiterun.form.component.d.ts.map +1 -1
  255. package/dist/lib/generated/Entities/TestSuiteRun/testsuiterun.form.component.js +57 -9
  256. package/dist/lib/generated/Entities/TestSuiteRun/testsuiterun.form.component.js.map +1 -1
  257. package/dist/lib/generated/Entities/User/user.form.component.js +2 -2
  258. package/dist/lib/generated/Entities/UserRecordLog/userrecordlog.form.component.js +2 -2
  259. package/dist/lib/generated/Entities/UserRecordLog/userrecordlog.form.component.js.map +1 -1
  260. package/dist/lib/generated/generated-forms.module.d.ts +145 -127
  261. package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
  262. package/dist/lib/generated/generated-forms.module.js +226 -117
  263. package/dist/lib/generated/generated-forms.module.js.map +1 -1
  264. package/package.json +28 -25
  265. package/dist/lib/custom/Entities/entities-form.component.d.ts +0 -10
  266. package/dist/lib/custom/Entities/entities-form.component.d.ts.map +0 -1
  267. package/dist/lib/custom/Entities/entities-form.component.js +0 -198
  268. package/dist/lib/custom/Entities/entities-form.component.js.map +0 -1
@@ -4,13 +4,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { Component, ChangeDetectionStrategy } from '@angular/core';
7
+ import { Component, ChangeDetectionStrategy, HostListener } from '@angular/core';
8
8
  import { Subject } from 'rxjs';
9
- import { CompositeKey, RunView } from '@memberjunction/core';
9
+ import { takeUntil } from 'rxjs/operators';
10
+ import { CompositeKey, Metadata, RunView } from '@memberjunction/core';
11
+ import { UserInfoEngine } from '@memberjunction/core-entities';
10
12
  import { BaseFormComponent } from '@memberjunction/ng-base-forms';
11
13
  import { RegisterClass } from '@memberjunction/global';
12
14
  import { SharedService } from '@memberjunction/ng-shared';
13
15
  import { TestFormComponent } from '../../generated/Entities/Test/test.form.component';
16
+ import { TagsHelper } from '@memberjunction/ng-testing';
17
+ import { createCopyOnlyToolbar } from '@memberjunction/ng-code-editor';
14
18
  import * as i0 from "@angular/core";
15
19
  import * as i1 from "@memberjunction/ng-shared";
16
20
  import * as i2 from "@angular/router";
@@ -19,8 +23,23 @@ import * as i4 from "@angular/common";
19
23
  import * as i5 from "@angular/forms";
20
24
  import * as i6 from "@progress/kendo-angular-dialog";
21
25
  import * as i7 from "@progress/kendo-angular-buttons";
22
- function TestFormComponentExtended_div_20_Template(rf, ctx) { if (rf & 1) {
23
- i0.ɵɵelementStart(0, "div", 29)(1, "p");
26
+ import * as i8 from "@memberjunction/ng-code-editor";
27
+ import * as i9 from "@memberjunction/ng-shared-generic";
28
+ import * as i10 from "./entity-link-pill.component";
29
+ const _c0 = () => [1, 2, 3, 4, 5];
30
+ const _c1 = () => [1, 2, 3];
31
+ function TestFormComponentExtended_span_13_Template(rf, ctx) { if (rf & 1) {
32
+ i0.ɵɵelementStart(0, "span", 35);
33
+ i0.ɵɵelement(1, "i", 36);
34
+ i0.ɵɵtext(2);
35
+ i0.ɵɵelementEnd();
36
+ } if (rf & 2) {
37
+ const ctx_r0 = i0.ɵɵnextContext();
38
+ i0.ɵɵadvance(2);
39
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.record.Type, " ");
40
+ } }
41
+ function TestFormComponentExtended_div_22_Template(rf, ctx) { if (rf & 1) {
42
+ i0.ɵɵelementStart(0, "div", 37)(1, "p");
24
43
  i0.ɵɵtext(2);
25
44
  i0.ɵɵelementEnd()();
26
45
  } if (rf & 2) {
@@ -28,30 +47,33 @@ function TestFormComponentExtended_div_20_Template(rf, ctx) { if (rf & 1) {
28
47
  i0.ɵɵadvance(2);
29
48
  i0.ɵɵtextInterpolate(ctx_r0.record.Description);
30
49
  } }
31
- function TestFormComponentExtended_div_21_Template(rf, ctx) { if (rf & 1) {
32
- i0.ɵɵelementStart(0, "div", 30)(1, "div", 31)(2, "div", 32);
50
+ function TestFormComponentExtended_div_23_Template(rf, ctx) { if (rf & 1) {
51
+ i0.ɵɵelementStart(0, "div", 38)(1, "div", 39)(2, "div", 40);
33
52
  i0.ɵɵtext(3, "Total Runs");
34
53
  i0.ɵɵelementEnd();
35
- i0.ɵɵelementStart(4, "div", 33);
54
+ i0.ɵɵelementStart(4, "div", 41);
36
55
  i0.ɵɵtext(5);
37
56
  i0.ɵɵelementEnd()();
38
- i0.ɵɵelementStart(6, "div", 31)(7, "div", 32);
57
+ i0.ɵɵelementStart(6, "div", 39)(7, "div", 40);
39
58
  i0.ɵɵtext(8, "Pass Rate");
40
59
  i0.ɵɵelementEnd();
41
- i0.ɵɵelementStart(9, "div", 33);
60
+ i0.ɵɵelementStart(9, "div", 41);
42
61
  i0.ɵɵtext(10);
62
+ i0.ɵɵelementEnd();
63
+ i0.ɵɵelementStart(11, "div", 42);
64
+ i0.ɵɵelement(12, "div", 43);
43
65
  i0.ɵɵelementEnd()();
44
- i0.ɵɵelementStart(11, "div", 31)(12, "div", 32);
45
- i0.ɵɵtext(13, "Avg Cost");
66
+ i0.ɵɵelementStart(13, "div", 39)(14, "div", 40);
67
+ i0.ɵɵtext(15, "Avg Cost");
46
68
  i0.ɵɵelementEnd();
47
- i0.ɵɵelementStart(14, "div", 33);
48
- i0.ɵɵtext(15);
69
+ i0.ɵɵelementStart(16, "div", 41);
70
+ i0.ɵɵtext(17);
49
71
  i0.ɵɵelementEnd()();
50
- i0.ɵɵelementStart(16, "div", 31)(17, "div", 32);
51
- i0.ɵɵtext(18, "Avg Duration");
72
+ i0.ɵɵelementStart(18, "div", 39)(19, "div", 40);
73
+ i0.ɵɵtext(20, "Avg Duration");
52
74
  i0.ɵɵelementEnd();
53
- i0.ɵɵelementStart(19, "div", 33);
54
- i0.ɵɵtext(20);
75
+ i0.ɵɵelementStart(21, "div", 41);
76
+ i0.ɵɵtext(22);
55
77
  i0.ɵɵelementEnd()()();
56
78
  } if (rf & 2) {
57
79
  const ctx_r0 = i0.ɵɵnextContext();
@@ -59,13 +81,15 @@ function TestFormComponentExtended_div_21_Template(rf, ctx) { if (rf & 1) {
59
81
  i0.ɵɵtextInterpolate(ctx_r0.testRuns.length);
60
82
  i0.ɵɵadvance(5);
61
83
  i0.ɵɵtextInterpolate1("", ctx_r0.getPassRate().toFixed(1), "%");
84
+ i0.ɵɵadvance(2);
85
+ i0.ɵɵstyleProp("width", ctx_r0.getPassRate(), "%");
62
86
  i0.ɵɵadvance(5);
63
87
  i0.ɵɵtextInterpolate(ctx_r0.formatCost(ctx_r0.getAverageCost()));
64
88
  i0.ɵɵadvance(5);
65
89
  i0.ɵɵtextInterpolate(ctx_r0.formatDuration(ctx_r0.getAverageDuration()));
66
90
  } }
67
- function TestFormComponentExtended_span_36_Template(rf, ctx) { if (rf & 1) {
68
- i0.ɵɵelementStart(0, "span", 34);
91
+ function TestFormComponentExtended_span_38_Template(rf, ctx) { if (rf & 1) {
92
+ i0.ɵɵelementStart(0, "span", 44);
69
93
  i0.ɵɵtext(1);
70
94
  i0.ɵɵelementEnd();
71
95
  } if (rf & 2) {
@@ -73,8 +97,8 @@ function TestFormComponentExtended_span_36_Template(rf, ctx) { if (rf & 1) {
73
97
  i0.ɵɵadvance();
74
98
  i0.ɵɵtextInterpolate(ctx_r0.testRuns.length);
75
99
  } }
76
- function TestFormComponentExtended_span_41_Template(rf, ctx) { if (rf & 1) {
77
- i0.ɵɵelementStart(0, "span", 34);
100
+ function TestFormComponentExtended_span_43_Template(rf, ctx) { if (rf & 1) {
101
+ i0.ɵɵelementStart(0, "span", 44);
78
102
  i0.ɵɵtext(1);
79
103
  i0.ɵɵelementEnd();
80
104
  } if (rf & 2) {
@@ -82,90 +106,110 @@ function TestFormComponentExtended_span_41_Template(rf, ctx) { if (rf & 1) {
82
106
  i0.ɵɵadvance();
83
107
  i0.ɵɵtextInterpolate(ctx_r0.suiteTests.length);
84
108
  } }
85
- function TestFormComponentExtended_div_43_Template(rf, ctx) { if (rf & 1) {
109
+ function TestFormComponentExtended_div_49_Template(rf, ctx) { if (rf & 1) {
86
110
  const _r2 = i0.ɵɵgetCurrentView();
87
- i0.ɵɵelementStart(0, "div", 35)(1, "div", 36)(2, "h3");
88
- i0.ɵɵtext(3, "Test Information");
111
+ i0.ɵɵelementStart(0, "div", 45)(1, "div", 46)(2, "h3");
112
+ i0.ɵɵelement(3, "i", 47);
113
+ i0.ɵɵtext(4, " Test Information");
89
114
  i0.ɵɵelementEnd();
90
- i0.ɵɵelementStart(4, "div", 37)(5, "div", 38)(6, "div", 39);
91
- i0.ɵɵtext(7, "Name");
115
+ i0.ɵɵelementStart(5, "div", 48)(6, "div", 49)(7, "div", 50);
116
+ i0.ɵɵtext(8, "Name");
92
117
  i0.ɵɵelementEnd();
93
- i0.ɵɵelementStart(8, "div", 40);
94
- i0.ɵɵtext(9);
118
+ i0.ɵɵelementStart(9, "div", 51);
119
+ i0.ɵɵtext(10);
95
120
  i0.ɵɵelementEnd()();
96
- i0.ɵɵelementStart(10, "div", 38)(11, "div", 39);
97
- i0.ɵɵtext(12, "Type");
121
+ i0.ɵɵelementStart(11, "div", 49)(12, "div", 50);
122
+ i0.ɵɵtext(13, "Type");
98
123
  i0.ɵɵelementEnd();
99
- i0.ɵɵelementStart(13, "div", 40);
100
- i0.ɵɵtext(14);
124
+ i0.ɵɵelementStart(14, "div", 51);
125
+ i0.ɵɵtext(15);
101
126
  i0.ɵɵelementEnd()();
102
- i0.ɵɵelementStart(15, "div", 38)(16, "div", 39);
103
- i0.ɵɵtext(17, "Status");
127
+ i0.ɵɵelementStart(16, "div", 49)(17, "div", 50);
128
+ i0.ɵɵtext(18, "Status");
104
129
  i0.ɵɵelementEnd();
105
- i0.ɵɵelementStart(18, "div", 40);
106
- i0.ɵɵtext(19);
130
+ i0.ɵɵelementStart(19, "div", 51)(20, "span", 52);
131
+ i0.ɵɵtext(21);
132
+ i0.ɵɵelementEnd()()();
133
+ i0.ɵɵelementStart(22, "div", 49)(23, "div", 50);
134
+ i0.ɵɵtext(24, "Priority");
135
+ i0.ɵɵelementEnd();
136
+ i0.ɵɵelementStart(25, "div", 51);
137
+ i0.ɵɵtext(26);
107
138
  i0.ɵɵelementEnd()();
108
- i0.ɵɵelementStart(20, "div", 38)(21, "div", 39);
109
- i0.ɵɵtext(22, "Priority");
139
+ i0.ɵɵelementStart(27, "div", 49)(28, "div", 50);
140
+ i0.ɵɵtext(29, "Estimated Duration");
110
141
  i0.ɵɵelementEnd();
111
- i0.ɵɵelementStart(23, "div", 40);
112
- i0.ɵɵtext(24);
142
+ i0.ɵɵelementStart(30, "div", 51);
143
+ i0.ɵɵtext(31);
144
+ i0.ɵɵelementEnd()();
145
+ i0.ɵɵelementStart(32, "div", 49)(33, "div", 50);
146
+ i0.ɵɵtext(34, "Estimated Cost");
147
+ i0.ɵɵelementEnd();
148
+ i0.ɵɵelementStart(35, "div", 51);
149
+ i0.ɵɵtext(36);
113
150
  i0.ɵɵelementEnd()();
114
- i0.ɵɵelementStart(25, "div", 38)(26, "div", 39);
115
- i0.ɵɵtext(27, "Estimated Duration");
151
+ i0.ɵɵelementStart(37, "div", 49)(38, "div", 50);
152
+ i0.ɵɵtext(39, "Repeat Count");
116
153
  i0.ɵɵelementEnd();
117
- i0.ɵɵelementStart(28, "div", 40);
118
- i0.ɵɵtext(29);
154
+ i0.ɵɵelementStart(40, "div", 51);
155
+ i0.ɵɵtext(41);
119
156
  i0.ɵɵelementEnd()();
120
- i0.ɵɵelementStart(30, "div", 38)(31, "div", 39);
121
- i0.ɵɵtext(32, "Estimated Cost");
157
+ i0.ɵɵelementStart(42, "div", 49)(43, "div", 50);
158
+ i0.ɵɵtext(44, "Max Execution Time");
122
159
  i0.ɵɵelementEnd();
123
- i0.ɵɵelementStart(33, "div", 40);
124
- i0.ɵɵtext(34);
160
+ i0.ɵɵelementStart(45, "div", 51);
161
+ i0.ɵɵtext(46);
125
162
  i0.ɵɵelementEnd()();
126
- i0.ɵɵelementStart(35, "div", 38)(36, "div", 39);
127
- i0.ɵɵtext(37, "Repeat Count");
163
+ i0.ɵɵelementStart(47, "div", 49)(48, "div", 50);
164
+ i0.ɵɵtext(49, "Created");
128
165
  i0.ɵɵelementEnd();
129
- i0.ɵɵelementStart(38, "div", 40);
130
- i0.ɵɵtext(39);
166
+ i0.ɵɵelementStart(50, "div", 51);
167
+ i0.ɵɵtext(51);
168
+ i0.ɵɵpipe(52, "date");
131
169
  i0.ɵɵelementEnd()();
132
- i0.ɵɵelementStart(40, "div", 38)(41, "div", 39);
133
- i0.ɵɵtext(42, "Created");
170
+ i0.ɵɵelementStart(53, "div", 49)(54, "div", 50);
171
+ i0.ɵɵtext(55, "Updated");
134
172
  i0.ɵɵelementEnd();
135
- i0.ɵɵelementStart(43, "div", 40);
136
- i0.ɵɵtext(44);
137
- i0.ɵɵpipe(45, "date");
173
+ i0.ɵɵelementStart(56, "div", 51);
174
+ i0.ɵɵtext(57);
175
+ i0.ɵɵpipe(58, "date");
138
176
  i0.ɵɵelementEnd()()()();
139
- i0.ɵɵelementStart(46, "div", 41)(47, "h3");
140
- i0.ɵɵtext(48, "Test Definition");
177
+ i0.ɵɵelementStart(59, "div", 53)(60, "h3");
178
+ i0.ɵɵelement(61, "i", 54);
179
+ i0.ɵɵtext(62, " Test Definition");
141
180
  i0.ɵɵelementEnd();
142
- i0.ɵɵelementStart(49, "div", 42)(50, "button", 43);
143
- i0.ɵɵlistener("click", function TestFormComponentExtended_div_43_Template_button_click_50_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("input")); });
144
- i0.ɵɵtext(51, " Input Definition ");
181
+ i0.ɵɵelementStart(63, "div", 55)(64, "button", 56);
182
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_49_Template_button_click_64_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("input")); });
183
+ i0.ɵɵelement(65, "i", 57);
184
+ i0.ɵɵtext(66, " Input Definition ");
145
185
  i0.ɵɵelementEnd();
146
- i0.ɵɵelementStart(52, "button", 43);
147
- i0.ɵɵlistener("click", function TestFormComponentExtended_div_43_Template_button_click_52_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("expected")); });
148
- i0.ɵɵtext(53, " Expected Outcomes ");
186
+ i0.ɵɵelementStart(67, "button", 56);
187
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_49_Template_button_click_67_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("expected")); });
188
+ i0.ɵɵelement(68, "i", 58);
189
+ i0.ɵɵtext(69, " Expected Outcomes ");
149
190
  i0.ɵɵelementEnd();
150
- i0.ɵɵelementStart(54, "button", 43);
151
- i0.ɵɵlistener("click", function TestFormComponentExtended_div_43_Template_button_click_54_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("config")); });
152
- i0.ɵɵtext(55, " Configuration ");
191
+ i0.ɵɵelementStart(70, "button", 56);
192
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_49_Template_button_click_70_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("config")); });
193
+ i0.ɵɵelement(71, "i", 59);
194
+ i0.ɵɵtext(72, " Configuration ");
153
195
  i0.ɵɵelementEnd();
154
- i0.ɵɵelementStart(56, "button", 43);
155
- i0.ɵɵlistener("click", function TestFormComponentExtended_div_43_Template_button_click_56_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("tags")); });
156
- i0.ɵɵtext(57, " Tags ");
196
+ i0.ɵɵelementStart(73, "button", 56);
197
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_49_Template_button_click_73_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("tags")); });
198
+ i0.ɵɵelement(74, "i", 60);
199
+ i0.ɵɵtext(75, " Tags ");
157
200
  i0.ɵɵelementEnd()();
158
- i0.ɵɵelementStart(58, "div", 44)(59, "pre");
159
- i0.ɵɵtext(60);
160
- i0.ɵɵpipe(61, "json");
161
- i0.ɵɵelementEnd()()()();
201
+ i0.ɵɵelementStart(76, "div", 61);
202
+ i0.ɵɵelement(77, "mj-code-editor", 62);
203
+ i0.ɵɵelementEnd()()();
162
204
  } if (rf & 2) {
163
205
  const ctx_r0 = i0.ɵɵnextContext();
164
- i0.ɵɵadvance(9);
206
+ i0.ɵɵadvance(10);
165
207
  i0.ɵɵtextInterpolate(ctx_r0.record.Name);
166
208
  i0.ɵɵadvance(5);
167
- i0.ɵɵtextInterpolate(ctx_r0.record.Type);
209
+ i0.ɵɵtextInterpolate(ctx_r0.record.Type || "N/A");
168
210
  i0.ɵɵadvance(5);
211
+ i0.ɵɵproperty("ngClass", ctx_r0.getStatusClass());
212
+ i0.ɵɵadvance();
169
213
  i0.ɵɵtextInterpolate(ctx_r0.record.Status);
170
214
  i0.ɵɵadvance(5);
171
215
  i0.ɵɵtextInterpolate(ctx_r0.record.Priority || "N/A");
@@ -176,74 +220,92 @@ function TestFormComponentExtended_div_43_Template(rf, ctx) { if (rf & 1) {
176
220
  i0.ɵɵadvance(5);
177
221
  i0.ɵɵtextInterpolate(ctx_r0.record.RepeatCount || 1);
178
222
  i0.ɵɵadvance(5);
179
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(45, 17, ctx_r0.record.__mj_CreatedAt, "medium"));
223
+ i0.ɵɵtextInterpolate(ctx_r0.formatTimeout(ctx_r0.record.MaxExecutionTimeMS));
224
+ i0.ɵɵadvance(5);
225
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(52, 23, ctx_r0.record.__mj_CreatedAt, "medium"));
180
226
  i0.ɵɵadvance(6);
227
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(58, 26, ctx_r0.record.__mj_UpdatedAt, "medium"));
228
+ i0.ɵɵadvance(7);
181
229
  i0.ɵɵclassProp("active", ctx_r0.activeJsonView === "input");
182
- i0.ɵɵadvance(2);
230
+ i0.ɵɵadvance(3);
183
231
  i0.ɵɵclassProp("active", ctx_r0.activeJsonView === "expected");
184
- i0.ɵɵadvance(2);
232
+ i0.ɵɵadvance(3);
185
233
  i0.ɵɵclassProp("active", ctx_r0.activeJsonView === "config");
186
- i0.ɵɵadvance(2);
234
+ i0.ɵɵadvance(3);
187
235
  i0.ɵɵclassProp("active", ctx_r0.activeJsonView === "tags");
188
236
  i0.ɵɵadvance(4);
189
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(61, 20, ctx_r0.getJsonData()));
237
+ i0.ɵɵproperty("value", ctx_r0.getJsonData())("readonly", true)("toolbar", ctx_r0.jsonToolbar)("lineWrapping", true);
190
238
  } }
191
- function TestFormComponentExtended_div_44_Template(rf, ctx) { if (rf & 1) {
239
+ function TestFormComponentExtended_div_50_Template(rf, ctx) { if (rf & 1) {
192
240
  const _r3 = i0.ɵɵgetCurrentView();
193
- i0.ɵɵelementStart(0, "div", 45)(1, "div", 46)(2, "h3");
194
- i0.ɵɵtext(3, "Execution Settings");
241
+ i0.ɵɵelementStart(0, "div", 63)(1, "div", 64)(2, "h3");
242
+ i0.ɵɵelement(3, "i", 65);
243
+ i0.ɵɵtext(4, " Execution Settings");
195
244
  i0.ɵɵelementEnd();
196
- i0.ɵɵelementStart(4, "div", 47)(5, "div", 48)(6, "label");
197
- i0.ɵɵtext(7, "Priority");
245
+ i0.ɵɵelementStart(5, "div", 66)(6, "div", 67)(7, "label");
246
+ i0.ɵɵtext(8, "Priority");
198
247
  i0.ɵɵelementEnd();
199
- i0.ɵɵelementStart(8, "input", 49);
200
- i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_44_Template_input_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.Priority, $event) || (ctx_r0.record.Priority = $event); return i0.ɵɵresetView($event); });
248
+ i0.ɵɵelementStart(9, "input", 68);
249
+ i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_50_Template_input_ngModelChange_9_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.Priority, $event) || (ctx_r0.record.Priority = $event); return i0.ɵɵresetView($event); });
201
250
  i0.ɵɵelementEnd()();
202
- i0.ɵɵelementStart(9, "div", 48)(10, "label");
203
- i0.ɵɵtext(11, "Repeat Count");
251
+ i0.ɵɵelementStart(10, "div", 67)(11, "label");
252
+ i0.ɵɵtext(12, "Repeat Count");
204
253
  i0.ɵɵelementEnd();
205
- i0.ɵɵelementStart(12, "input", 49);
206
- i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_44_Template_input_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.RepeatCount, $event) || (ctx_r0.record.RepeatCount = $event); return i0.ɵɵresetView($event); });
254
+ i0.ɵɵelementStart(13, "input", 69);
255
+ i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_50_Template_input_ngModelChange_13_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.RepeatCount, $event) || (ctx_r0.record.RepeatCount = $event); return i0.ɵɵresetView($event); });
207
256
  i0.ɵɵelementEnd()();
208
- i0.ɵɵelementStart(13, "div", 48)(14, "label");
209
- i0.ɵɵtext(15, "Estimated Duration (seconds)");
257
+ i0.ɵɵelementStart(14, "div", 67)(15, "label");
258
+ i0.ɵɵtext(16, "Estimated Duration (seconds)");
210
259
  i0.ɵɵelementEnd();
211
- i0.ɵɵelementStart(16, "input", 49);
212
- i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_44_Template_input_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.EstimatedDurationSeconds, $event) || (ctx_r0.record.EstimatedDurationSeconds = $event); return i0.ɵɵresetView($event); });
260
+ i0.ɵɵelementStart(17, "input", 70);
261
+ i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_50_Template_input_ngModelChange_17_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.EstimatedDurationSeconds, $event) || (ctx_r0.record.EstimatedDurationSeconds = $event); return i0.ɵɵresetView($event); });
213
262
  i0.ɵɵelementEnd()();
214
- i0.ɵɵelementStart(17, "div", 48)(18, "label");
215
- i0.ɵɵtext(19, "Estimated Cost (USD)");
216
- i0.ɵɵelementEnd();
217
- i0.ɵɵelementStart(20, "input", 50);
218
- i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_44_Template_input_ngModelChange_20_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.EstimatedCostUSD, $event) || (ctx_r0.record.EstimatedCostUSD = $event); return i0.ɵɵresetView($event); });
219
- i0.ɵɵelementEnd()()()();
220
- i0.ɵɵelementStart(21, "div", 46)(22, "h3");
221
- i0.ɵɵtext(23, "Input Definition (JSON)");
263
+ i0.ɵɵelementStart(18, "div", 67)(19, "label");
264
+ i0.ɵɵtext(20, "Estimated Cost (USD)");
222
265
  i0.ɵɵelementEnd();
223
- i0.ɵɵelementStart(24, "textarea", 51);
224
- i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_44_Template_textarea_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.InputDefinition, $event) || (ctx_r0.record.InputDefinition = $event); return i0.ɵɵresetView($event); });
266
+ i0.ɵɵelementStart(21, "input", 71);
267
+ i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_50_Template_input_ngModelChange_21_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.EstimatedCostUSD, $event) || (ctx_r0.record.EstimatedCostUSD = $event); return i0.ɵɵresetView($event); });
225
268
  i0.ɵɵelementEnd()();
226
- i0.ɵɵelementStart(25, "div", 46)(26, "h3");
227
- i0.ɵɵtext(27, "Expected Outcomes (JSON)");
269
+ i0.ɵɵelementStart(22, "div", 72)(23, "label");
270
+ i0.ɵɵtext(24, "Max Execution Time (ms)");
228
271
  i0.ɵɵelementEnd();
229
- i0.ɵɵelementStart(28, "textarea", 51);
230
- i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_44_Template_textarea_ngModelChange_28_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.ExpectedOutcomes, $event) || (ctx_r0.record.ExpectedOutcomes = $event); return i0.ɵɵresetView($event); });
231
- i0.ɵɵelementEnd()();
232
- i0.ɵɵelementStart(29, "div", 46)(30, "h3");
233
- i0.ɵɵtext(31, "Configuration (JSON)");
272
+ i0.ɵɵelementStart(25, "input", 73);
273
+ i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_50_Template_input_ngModelChange_25_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.MaxExecutionTimeMS, $event) || (ctx_r0.record.MaxExecutionTimeMS = $event); return i0.ɵɵresetView($event); });
234
274
  i0.ɵɵelementEnd();
235
- i0.ɵɵelementStart(32, "textarea", 51);
236
- i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_44_Template_textarea_ngModelChange_32_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.Configuration, $event) || (ctx_r0.record.Configuration = $event); return i0.ɵɵresetView($event); });
237
- i0.ɵɵelementEnd()();
238
- i0.ɵɵelementStart(33, "div", 46)(34, "h3");
239
- i0.ɵɵtext(35, "Tags (JSON Array)");
275
+ i0.ɵɵelementStart(26, "span", 74);
276
+ i0.ɵɵtext(27, "Leave empty for default 5 minute timeout");
277
+ i0.ɵɵelementEnd()()()();
278
+ i0.ɵɵelementStart(28, "div", 64)(29, "h3");
279
+ i0.ɵɵelement(30, "i", 57);
280
+ i0.ɵɵtext(31, " Input Definition (JSON)");
281
+ i0.ɵɵelementEnd();
282
+ i0.ɵɵelementStart(32, "div", 75)(33, "mj-code-editor", 76);
283
+ i0.ɵɵlistener("change", function TestFormComponentExtended_div_50_Template_mj_code_editor_change_33_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.InputDefinition = $event); });
284
+ i0.ɵɵelementEnd()()();
285
+ i0.ɵɵelementStart(34, "div", 64)(35, "h3");
286
+ i0.ɵɵelement(36, "i", 58);
287
+ i0.ɵɵtext(37, " Expected Outcomes (JSON)");
240
288
  i0.ɵɵelementEnd();
241
- i0.ɵɵelementStart(36, "textarea", 52);
242
- i0.ɵɵtwoWayListener("ngModelChange", function TestFormComponentExtended_div_44_Template_textarea_ngModelChange_36_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.Tags, $event) || (ctx_r0.record.Tags = $event); return i0.ɵɵresetView($event); });
289
+ i0.ɵɵelementStart(38, "div", 75)(39, "mj-code-editor", 76);
290
+ i0.ɵɵlistener("change", function TestFormComponentExtended_div_50_Template_mj_code_editor_change_39_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.ExpectedOutcomes = $event); });
243
291
  i0.ɵɵelementEnd()()();
292
+ i0.ɵɵelementStart(40, "div", 64)(41, "h3");
293
+ i0.ɵɵelement(42, "i", 59);
294
+ i0.ɵɵtext(43, " Configuration (JSON)");
295
+ i0.ɵɵelementEnd();
296
+ i0.ɵɵelementStart(44, "div", 75)(45, "mj-code-editor", 76);
297
+ i0.ɵɵlistener("change", function TestFormComponentExtended_div_50_Template_mj_code_editor_change_45_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Configuration = $event); });
298
+ i0.ɵɵelementEnd()()();
299
+ i0.ɵɵelementStart(46, "div", 64)(47, "h3");
300
+ i0.ɵɵelement(48, "i", 60);
301
+ i0.ɵɵtext(49, " Tags (JSON Array)");
302
+ i0.ɵɵelementEnd();
303
+ i0.ɵɵelementStart(50, "div", 77)(51, "mj-code-editor", 76);
304
+ i0.ɵɵlistener("change", function TestFormComponentExtended_div_50_Template_mj_code_editor_change_51_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Tags = $event); });
305
+ i0.ɵɵelementEnd()()()();
244
306
  } if (rf & 2) {
245
307
  const ctx_r0 = i0.ɵɵnextContext();
246
- i0.ɵɵadvance(8);
308
+ i0.ɵɵadvance(9);
247
309
  i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.Priority);
248
310
  i0.ɵɵadvance(4);
249
311
  i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.RepeatCount);
@@ -252,186 +314,863 @@ function TestFormComponentExtended_div_44_Template(rf, ctx) { if (rf & 1) {
252
314
  i0.ɵɵadvance(4);
253
315
  i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.EstimatedCostUSD);
254
316
  i0.ɵɵadvance(4);
255
- i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.InputDefinition);
256
- i0.ɵɵadvance(4);
257
- i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.ExpectedOutcomes);
258
- i0.ɵɵadvance(4);
259
- i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.Configuration);
260
- i0.ɵɵadvance(4);
261
- i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.Tags);
317
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.MaxExecutionTimeMS);
318
+ i0.ɵɵadvance(8);
319
+ i0.ɵɵproperty("value", ctx_r0.record.InputDefinition || "")("readonly", false)("lineWrapping", true);
320
+ i0.ɵɵadvance(6);
321
+ i0.ɵɵproperty("value", ctx_r0.record.ExpectedOutcomes || "")("readonly", false)("lineWrapping", true);
322
+ i0.ɵɵadvance(6);
323
+ i0.ɵɵproperty("value", ctx_r0.record.Configuration || "")("readonly", false)("lineWrapping", true);
324
+ i0.ɵɵadvance(6);
325
+ i0.ɵɵproperty("value", ctx_r0.record.Tags || "[]")("readonly", false)("lineWrapping", true);
326
+ } }
327
+ function TestFormComponentExtended_div_51_div_1_div_2_Template(rf, ctx) { if (rf & 1) {
328
+ i0.ɵɵelementStart(0, "div", 85);
329
+ i0.ɵɵelement(1, "div", 86);
330
+ i0.ɵɵelementStart(2, "div", 87);
331
+ i0.ɵɵelement(3, "div", 88)(4, "div", 89);
332
+ i0.ɵɵelementEnd()();
262
333
  } }
263
- function TestFormComponentExtended_div_45_div_1_div_1_span_13_Template(rf, ctx) { if (rf & 1) {
334
+ function TestFormComponentExtended_div_51_div_1_Template(rf, ctx) { if (rf & 1) {
335
+ i0.ɵɵelementStart(0, "div", 82)(1, "div", 83);
336
+ i0.ɵɵtemplate(2, TestFormComponentExtended_div_51_div_1_div_2_Template, 5, 0, "div", 84);
337
+ i0.ɵɵelementEnd()();
338
+ } if (rf & 2) {
339
+ i0.ɵɵadvance(2);
340
+ i0.ɵɵproperty("ngForOf", i0.ɵɵpureFunction0(1, _c0));
341
+ } }
342
+ function TestFormComponentExtended_div_51_div_2_div_1_span_13_Template(rf, ctx) { if (rf & 1) {
264
343
  i0.ɵɵelementStart(0, "span");
265
- i0.ɵɵtext(1);
344
+ i0.ɵɵelement(1, "i", 107);
345
+ i0.ɵɵtext(2);
266
346
  i0.ɵɵelementEnd();
267
347
  } if (rf & 2) {
268
348
  const run_r5 = i0.ɵɵnextContext().$implicit;
269
349
  const ctx_r0 = i0.ɵɵnextContext(3);
270
- i0.ɵɵadvance();
271
- i0.ɵɵtextInterpolate(ctx_r0.formatDuration(run_r5.DurationSeconds));
350
+ i0.ɵɵadvance(2);
351
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatDuration(run_r5.DurationSeconds), "");
272
352
  } }
273
- function TestFormComponentExtended_div_45_div_1_div_1_span_14_Template(rf, ctx) { if (rf & 1) {
353
+ function TestFormComponentExtended_div_51_div_2_div_1_span_14_Template(rf, ctx) { if (rf & 1) {
274
354
  i0.ɵɵelementStart(0, "span");
275
- i0.ɵɵtext(1);
355
+ i0.ɵɵelement(1, "i", 108);
356
+ i0.ɵɵtext(2);
276
357
  i0.ɵɵelementEnd();
277
358
  } if (rf & 2) {
278
359
  const run_r5 = i0.ɵɵnextContext().$implicit;
279
360
  const ctx_r0 = i0.ɵɵnextContext(3);
361
+ i0.ɵɵadvance(2);
362
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatCost(run_r5.CostUSD), "");
363
+ } }
364
+ function TestFormComponentExtended_div_51_div_2_div_1_mj_entity_link_pill_15_Template(rf, ctx) { if (rf & 1) {
365
+ i0.ɵɵelement(0, "mj-entity-link-pill", 109);
366
+ } if (rf & 2) {
367
+ const run_r5 = i0.ɵɵnextContext().$implicit;
368
+ i0.ɵɵproperty("entityName", run_r5.TargetLogEntity)("recordId", run_r5.TargetLogID);
369
+ } }
370
+ function TestFormComponentExtended_div_51_div_2_div_1_span_17_Template(rf, ctx) { if (rf & 1) {
371
+ i0.ɵɵelementStart(0, "span", 110);
372
+ i0.ɵɵelement(1, "i", 94);
373
+ i0.ɵɵelementStart(2, "span");
374
+ i0.ɵɵtext(3);
375
+ i0.ɵɵelementEnd()();
376
+ } if (rf & 2) {
377
+ const run_r5 = i0.ɵɵnextContext().$implicit;
378
+ const ctx_r0 = i0.ɵɵnextContext(3);
379
+ i0.ɵɵproperty("ngClass", "status-" + run_r5.Status.toLowerCase())("title", ctx_r0.getStatusTooltip(run_r5.Status));
280
380
  i0.ɵɵadvance();
281
- i0.ɵɵtextInterpolate(ctx_r0.formatCost(run_r5.CostUSD));
381
+ i0.ɵɵclassProp("fa-check", run_r5.Status === "Passed")("fa-times", run_r5.Status === "Failed")("fa-exclamation", run_r5.Status === "Error")("fa-hourglass-end", run_r5.Status === "Timeout")("fa-forward", run_r5.Status === "Skipped")("fa-spinner", run_r5.Status === "Running")("fa-clock", run_r5.Status === "Pending");
382
+ i0.ɵɵadvance(2);
383
+ i0.ɵɵtextInterpolate(run_r5.Status);
282
384
  } }
283
- function TestFormComponentExtended_div_45_div_1_div_1_span_15_Template(rf, ctx) { if (rf & 1) {
284
- i0.ɵɵelementStart(0, "span");
385
+ function TestFormComponentExtended_div_51_div_2_div_1_ng_container_18_span_1_Template(rf, ctx) { if (rf & 1) {
386
+ i0.ɵɵelementStart(0, "span", 113);
387
+ i0.ɵɵelement(1, "i", 114);
388
+ i0.ɵɵelementEnd();
389
+ } }
390
+ function TestFormComponentExtended_div_51_div_2_div_1_ng_container_18_span_2_Template(rf, ctx) { if (rf & 1) {
391
+ i0.ɵɵelementStart(0, "span", 115);
392
+ i0.ɵɵelement(1, "i", 116);
393
+ i0.ɵɵelementStart(2, "span");
394
+ i0.ɵɵtext(3);
395
+ i0.ɵɵelementEnd()();
396
+ } if (rf & 2) {
397
+ let tmp_11_0;
398
+ const rating_r6 = ctx.ngIf;
399
+ const run_r5 = i0.ɵɵnextContext(2).$implicit;
400
+ const ctx_r0 = i0.ɵɵnextContext(3);
401
+ i0.ɵɵclassProp("rating-low", rating_r6 <= 4)("rating-medium", rating_r6 >= 5 && rating_r6 <= 6)("rating-good", rating_r6 >= 7 && rating_r6 <= 8)("rating-excellent", rating_r6 >= 9);
402
+ i0.ɵɵproperty("title", ctx_r0.getHumanTooltip(rating_r6, ((tmp_11_0 = ctx_r0.getFeedbackForRun(run_r5.ID)) == null ? null : tmp_11_0.CorrectionSummary) || ((tmp_11_0 = ctx_r0.getFeedbackForRun(run_r5.ID)) == null ? null : tmp_11_0.Comments) || null));
403
+ i0.ɵɵadvance(3);
404
+ i0.ɵɵtextInterpolate(rating_r6);
405
+ } }
406
+ function TestFormComponentExtended_div_51_div_2_div_1_ng_container_18_Template(rf, ctx) { if (rf & 1) {
407
+ i0.ɵɵelementContainerStart(0);
408
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_51_div_2_div_1_ng_container_18_span_1_Template, 2, 0, "span", 111)(2, TestFormComponentExtended_div_51_div_2_div_1_ng_container_18_span_2_Template, 4, 10, "span", 112);
409
+ i0.ɵɵelementContainerEnd();
410
+ } if (rf & 2) {
411
+ let tmp_5_0;
412
+ let tmp_6_0;
413
+ const run_r5 = i0.ɵɵnextContext().$implicit;
414
+ const ctx_r0 = i0.ɵɵnextContext(3);
415
+ i0.ɵɵadvance();
416
+ i0.ɵɵproperty("ngIf", !((tmp_5_0 = ctx_r0.getFeedbackForRun(run_r5.ID)) == null ? null : tmp_5_0.Rating));
417
+ i0.ɵɵadvance();
418
+ i0.ɵɵproperty("ngIf", (tmp_6_0 = ctx_r0.getFeedbackForRun(run_r5.ID)) == null ? null : tmp_6_0.Rating);
419
+ } }
420
+ function TestFormComponentExtended_div_51_div_2_div_1_ng_container_19_span_1_Template(rf, ctx) { if (rf & 1) {
421
+ i0.ɵɵelementStart(0, "span", 119);
422
+ i0.ɵɵelement(1, "i", 120);
423
+ i0.ɵɵelementEnd();
424
+ } }
425
+ function TestFormComponentExtended_div_51_div_2_div_1_ng_container_19_span_2_Template(rf, ctx) { if (rf & 1) {
426
+ i0.ɵɵelementStart(0, "span", 121);
427
+ i0.ɵɵelement(1, "i", 120);
428
+ i0.ɵɵelementStart(2, "span");
429
+ i0.ɵɵtext(3);
430
+ i0.ɵɵelementEnd()();
431
+ } if (rf & 2) {
432
+ const run_r5 = i0.ɵɵnextContext(2).$implicit;
433
+ i0.ɵɵclassProp("score-low", run_r5.Score < 0.5)("score-medium", run_r5.Score >= 0.5 && run_r5.Score < 0.7)("score-good", run_r5.Score >= 0.7 && run_r5.Score < 0.85)("score-excellent", run_r5.Score >= 0.85);
434
+ i0.ɵɵproperty("title", "Auto Score: " + (run_r5.Score * 100).toFixed(0) + "% automated evaluation");
435
+ i0.ɵɵadvance(3);
436
+ i0.ɵɵtextInterpolate1("", (run_r5.Score * 100).toFixed(0), "%");
437
+ } }
438
+ function TestFormComponentExtended_div_51_div_2_div_1_ng_container_19_Template(rf, ctx) { if (rf & 1) {
439
+ i0.ɵɵelementContainerStart(0);
440
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_51_div_2_div_1_ng_container_19_span_1_Template, 2, 0, "span", 117)(2, TestFormComponentExtended_div_51_div_2_div_1_ng_container_19_span_2_Template, 4, 10, "span", 118);
441
+ i0.ɵɵelementContainerEnd();
442
+ } if (rf & 2) {
443
+ const run_r5 = i0.ɵɵnextContext().$implicit;
444
+ i0.ɵɵadvance();
445
+ i0.ɵɵproperty("ngIf", run_r5.Score == null);
446
+ i0.ɵɵadvance();
447
+ i0.ɵɵproperty("ngIf", run_r5.Score != null);
448
+ } }
449
+ function TestFormComponentExtended_div_51_div_2_div_1_div_20_span_1_Template(rf, ctx) { if (rf & 1) {
450
+ i0.ɵɵelementStart(0, "span", 125);
285
451
  i0.ɵɵtext(1);
286
452
  i0.ɵɵelementEnd();
453
+ } if (rf & 2) {
454
+ const tag_r7 = ctx.$implicit;
455
+ i0.ɵɵadvance();
456
+ i0.ɵɵtextInterpolate(tag_r7);
457
+ } }
458
+ function TestFormComponentExtended_div_51_div_2_div_1_div_20_span_2_Template(rf, ctx) { if (rf & 1) {
459
+ i0.ɵɵelementStart(0, "span", 126);
460
+ i0.ɵɵtext(1);
461
+ i0.ɵɵelementEnd();
462
+ } if (rf & 2) {
463
+ const run_r5 = i0.ɵɵnextContext(2).$implicit;
464
+ const ctx_r0 = i0.ɵɵnextContext(3);
465
+ i0.ɵɵadvance();
466
+ i0.ɵɵtextInterpolate1("+", ctx_r0.getRunTags(run_r5).length - 3, "");
467
+ } }
468
+ function TestFormComponentExtended_div_51_div_2_div_1_div_20_Template(rf, ctx) { if (rf & 1) {
469
+ i0.ɵɵelementStart(0, "div", 122);
470
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_51_div_2_div_1_div_20_span_1_Template, 2, 1, "span", 123)(2, TestFormComponentExtended_div_51_div_2_div_1_div_20_span_2_Template, 2, 1, "span", 124);
471
+ i0.ɵɵelementEnd();
287
472
  } if (rf & 2) {
288
473
  const run_r5 = i0.ɵɵnextContext().$implicit;
474
+ const ctx_r0 = i0.ɵɵnextContext(3);
475
+ i0.ɵɵadvance();
476
+ i0.ɵɵproperty("ngForOf", ctx_r0.getRunTags(run_r5).slice(0, 3));
289
477
  i0.ɵɵadvance();
290
- i0.ɵɵtextInterpolate1("Score: ", run_r5.Score.toFixed(4), "");
478
+ i0.ɵɵproperty("ngIf", ctx_r0.getRunTags(run_r5).length > 3);
291
479
  } }
292
- function TestFormComponentExtended_div_45_div_1_div_1_Template(rf, ctx) { if (rf & 1) {
480
+ function TestFormComponentExtended_div_51_div_2_div_1_Template(rf, ctx) { if (rf & 1) {
293
481
  const _r4 = i0.ɵɵgetCurrentView();
294
- i0.ɵɵelementStart(0, "div", 58);
295
- i0.ɵɵlistener("click", function TestFormComponentExtended_div_45_div_1_div_1_Template_div_click_0_listener() { const run_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestRun(run_r5.ID)); });
296
- i0.ɵɵelementStart(1, "div", 59);
297
- i0.ɵɵelement(2, "i", 60);
482
+ i0.ɵɵelementStart(0, "div", 92);
483
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_51_div_2_div_1_Template_div_click_0_listener() { const run_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestRun(run_r5.ID)); });
484
+ i0.ɵɵelementStart(1, "div", 93);
485
+ i0.ɵɵelement(2, "i", 94);
298
486
  i0.ɵɵelementEnd();
299
- i0.ɵɵelementStart(3, "div", 61)(4, "div", 62)(5, "span", 63);
487
+ i0.ɵɵelementStart(3, "div", 95)(4, "div", 96)(5, "span", 97);
300
488
  i0.ɵɵtext(6);
301
489
  i0.ɵɵelementEnd();
302
- i0.ɵɵelementStart(7, "span", 64);
490
+ i0.ɵɵelementStart(7, "span", 98);
303
491
  i0.ɵɵtext(8);
304
492
  i0.ɵɵelementEnd()();
305
- i0.ɵɵelementStart(9, "div", 65)(10, "span");
306
- i0.ɵɵtext(11);
307
- i0.ɵɵpipe(12, "date");
493
+ i0.ɵɵelementStart(9, "div", 99)(10, "span");
494
+ i0.ɵɵelement(11, "i", 100);
495
+ i0.ɵɵtext(12);
308
496
  i0.ɵɵelementEnd();
309
- i0.ɵɵtemplate(13, TestFormComponentExtended_div_45_div_1_div_1_span_13_Template, 2, 1, "span", 66)(14, TestFormComponentExtended_div_45_div_1_div_1_span_14_Template, 2, 1, "span", 66)(15, TestFormComponentExtended_div_45_div_1_div_1_span_15_Template, 2, 1, "span", 66);
310
- i0.ɵɵelementEnd()();
311
- i0.ɵɵelement(16, "i", 67);
497
+ i0.ɵɵtemplate(13, TestFormComponentExtended_div_51_div_2_div_1_span_13_Template, 3, 1, "span", 101)(14, TestFormComponentExtended_div_51_div_2_div_1_span_14_Template, 3, 1, "span", 101)(15, TestFormComponentExtended_div_51_div_2_div_1_mj_entity_link_pill_15_Template, 1, 2, "mj-entity-link-pill", 102);
498
+ i0.ɵɵelementEnd();
499
+ i0.ɵɵelementStart(16, "div", 103);
500
+ i0.ɵɵtemplate(17, TestFormComponentExtended_div_51_div_2_div_1_span_17_Template, 4, 17, "span", 104)(18, TestFormComponentExtended_div_51_div_2_div_1_ng_container_18_Template, 3, 2, "ng-container", 101)(19, TestFormComponentExtended_div_51_div_2_div_1_ng_container_19_Template, 3, 2, "ng-container", 101);
501
+ i0.ɵɵelementEnd();
502
+ i0.ɵɵtemplate(20, TestFormComponentExtended_div_51_div_2_div_1_div_20_Template, 3, 2, "div", 105);
503
+ i0.ɵɵelementEnd();
504
+ i0.ɵɵelement(21, "i", 106);
312
505
  i0.ɵɵelementEnd();
313
506
  } if (rf & 2) {
314
507
  const run_r5 = ctx.$implicit;
508
+ const ctx_r0 = i0.ɵɵnextContext(3);
315
509
  i0.ɵɵadvance();
316
- i0.ɵɵstyleProp("background-color", run_r5.Status === "Passed" ? "#4caf50" : run_r5.Status === "Failed" ? "#f44336" : "#ff9800");
510
+ i0.ɵɵstyleProp("background-color", ctx_r0.getRunStatusColor(run_r5.Status));
317
511
  i0.ɵɵadvance();
318
- i0.ɵɵclassProp("fa-check", run_r5.Status === "Passed")("fa-times", run_r5.Status === "Failed")("fa-exclamation", run_r5.Status === "Error");
512
+ i0.ɵɵclassProp("fa-check", run_r5.Status === "Passed")("fa-times", run_r5.Status === "Failed")("fa-exclamation", run_r5.Status === "Error")("fa-stopwatch", run_r5.Status === "Timeout")("fa-spinner", run_r5.Status === "Running")("fa-clock", run_r5.Status === "Pending");
319
513
  i0.ɵɵadvance(4);
320
514
  i0.ɵɵtextInterpolate1("Run #", run_r5.ID.substring(0, 8), "");
321
515
  i0.ɵɵadvance();
322
- i0.ɵɵstyleProp("color", run_r5.Status === "Passed" ? "#4caf50" : run_r5.Status === "Failed" ? "#f44336" : "#ff9800");
516
+ i0.ɵɵstyleProp("color", ctx_r0.getRunStatusColor(run_r5.Status));
323
517
  i0.ɵɵadvance();
324
518
  i0.ɵɵtextInterpolate(run_r5.Status);
325
- i0.ɵɵadvance(3);
326
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(12, 16, run_r5.StartedAt, "short"));
327
- i0.ɵɵadvance(2);
519
+ i0.ɵɵadvance(4);
520
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.getRelativeTime(run_r5.StartedAt), "");
521
+ i0.ɵɵadvance();
328
522
  i0.ɵɵproperty("ngIf", run_r5.DurationSeconds);
329
523
  i0.ɵɵadvance();
330
524
  i0.ɵɵproperty("ngIf", run_r5.CostUSD);
331
525
  i0.ɵɵadvance();
332
- i0.ɵɵproperty("ngIf", run_r5.Score != null);
526
+ i0.ɵɵproperty("ngIf", run_r5.TargetLogEntityID && run_r5.TargetLogID);
527
+ i0.ɵɵadvance(2);
528
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
529
+ i0.ɵɵadvance();
530
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showHuman);
531
+ i0.ɵɵadvance();
532
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showAuto);
533
+ i0.ɵɵadvance();
534
+ i0.ɵɵproperty("ngIf", ctx_r0.getRunTags(run_r5).length > 0);
333
535
  } }
334
- function TestFormComponentExtended_div_45_div_1_Template(rf, ctx) { if (rf & 1) {
335
- i0.ɵɵelementStart(0, "div", 56);
336
- i0.ɵɵtemplate(1, TestFormComponentExtended_div_45_div_1_div_1_Template, 17, 19, "div", 57);
536
+ function TestFormComponentExtended_div_51_div_2_Template(rf, ctx) { if (rf & 1) {
537
+ i0.ɵɵelementStart(0, "div", 90);
538
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_51_div_2_div_1_Template, 22, 26, "div", 91);
337
539
  i0.ɵɵelementEnd();
338
540
  } if (rf & 2) {
339
541
  const ctx_r0 = i0.ɵɵnextContext(2);
340
542
  i0.ɵɵadvance();
341
543
  i0.ɵɵproperty("ngForOf", ctx_r0.testRuns);
342
544
  } }
343
- function TestFormComponentExtended_div_45_div_2_Template(rf, ctx) { if (rf & 1) {
344
- i0.ɵɵelementStart(0, "div", 68);
345
- i0.ɵɵelement(1, "i", 69);
346
- i0.ɵɵelementStart(2, "p");
347
- i0.ɵɵtext(3, "No test runs found for this test");
545
+ function TestFormComponentExtended_div_51_div_3_Template(rf, ctx) { if (rf & 1) {
546
+ const _r8 = i0.ɵɵgetCurrentView();
547
+ i0.ɵɵelementStart(0, "div", 127)(1, "div", 128);
548
+ i0.ɵɵelement(2, "i", 129);
549
+ i0.ɵɵelementEnd();
550
+ i0.ɵɵelementStart(3, "h4");
551
+ i0.ɵɵtext(4, "No Test Runs Yet");
552
+ i0.ɵɵelementEnd();
553
+ i0.ɵɵelementStart(5, "p");
554
+ i0.ɵɵtext(6, "Run this test to see execution history and results here.");
555
+ i0.ɵɵelementEnd();
556
+ i0.ɵɵelementStart(7, "button", 12);
557
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_51_div_3_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r8); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.runTest()); });
558
+ i0.ɵɵelement(8, "i", 13);
559
+ i0.ɵɵtext(9, " Run Test Now ");
348
560
  i0.ɵɵelementEnd()();
349
561
  } }
350
- function TestFormComponentExtended_div_45_Template(rf, ctx) { if (rf & 1) {
351
- i0.ɵɵelementStart(0, "div", 53);
352
- i0.ɵɵtemplate(1, TestFormComponentExtended_div_45_div_1_Template, 2, 1, "div", 54)(2, TestFormComponentExtended_div_45_div_2_Template, 4, 0, "div", 55);
562
+ function TestFormComponentExtended_div_51_Template(rf, ctx) { if (rf & 1) {
563
+ i0.ɵɵelementStart(0, "div", 78);
564
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_51_div_1_Template, 3, 2, "div", 79)(2, TestFormComponentExtended_div_51_div_2_Template, 2, 1, "div", 80)(3, TestFormComponentExtended_div_51_div_3_Template, 10, 0, "div", 81);
353
565
  i0.ɵɵelementEnd();
354
566
  } if (rf & 2) {
355
567
  const ctx_r0 = i0.ɵɵnextContext();
356
568
  i0.ɵɵadvance();
357
- i0.ɵɵproperty("ngIf", ctx_r0.testRuns.length > 0);
569
+ i0.ɵɵproperty("ngIf", ctx_r0.loadingRuns);
570
+ i0.ɵɵadvance();
571
+ i0.ɵɵproperty("ngIf", !ctx_r0.loadingRuns && ctx_r0.testRuns.length > 0);
358
572
  i0.ɵɵadvance();
359
- i0.ɵɵproperty("ngIf", ctx_r0.testRunsLoaded && ctx_r0.testRuns.length === 0);
573
+ i0.ɵɵproperty("ngIf", ctx_r0.testRunsLoaded && !ctx_r0.loadingRuns && ctx_r0.testRuns.length === 0);
574
+ } }
575
+ function TestFormComponentExtended_div_52_div_1_div_2_Template(rf, ctx) { if (rf & 1) {
576
+ i0.ɵɵelementStart(0, "div", 85);
577
+ i0.ɵɵelement(1, "div", 86);
578
+ i0.ɵɵelementStart(2, "div", 87);
579
+ i0.ɵɵelement(3, "div", 88)(4, "div", 89);
580
+ i0.ɵɵelementEnd()();
581
+ } }
582
+ function TestFormComponentExtended_div_52_div_1_Template(rf, ctx) { if (rf & 1) {
583
+ i0.ɵɵelementStart(0, "div", 82)(1, "div", 83);
584
+ i0.ɵɵtemplate(2, TestFormComponentExtended_div_52_div_1_div_2_Template, 5, 0, "div", 84);
585
+ i0.ɵɵelementEnd()();
586
+ } if (rf & 2) {
587
+ i0.ɵɵadvance(2);
588
+ i0.ɵɵproperty("ngForOf", i0.ɵɵpureFunction0(1, _c1));
360
589
  } }
361
- function TestFormComponentExtended_div_46_div_1_div_1_Template(rf, ctx) { if (rf & 1) {
362
- const _r6 = i0.ɵɵgetCurrentView();
363
- i0.ɵɵelementStart(0, "div", 74);
364
- i0.ɵɵlistener("click", function TestFormComponentExtended_div_46_div_1_div_1_Template_div_click_0_listener() { const suiteTest_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestSuite(suiteTest_r7.SuiteID)); });
365
- i0.ɵɵelementStart(1, "div", 75);
366
- i0.ɵɵelement(2, "i", 76);
590
+ function TestFormComponentExtended_div_52_div_2_div_1_span_10_Template(rf, ctx) { if (rf & 1) {
591
+ i0.ɵɵelementStart(0, "span");
592
+ i0.ɵɵelement(1, "i", 47);
593
+ i0.ɵɵtext(2);
594
+ i0.ɵɵelementEnd();
595
+ } if (rf & 2) {
596
+ const suiteTest_r10 = i0.ɵɵnextContext().$implicit;
597
+ i0.ɵɵadvance(2);
598
+ i0.ɵɵtextInterpolate1(" ", suiteTest_r10.Status, "");
599
+ } }
600
+ function TestFormComponentExtended_div_52_div_2_div_1_Template(rf, ctx) { if (rf & 1) {
601
+ const _r9 = i0.ɵɵgetCurrentView();
602
+ i0.ɵɵelementStart(0, "div", 134);
603
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_52_div_2_div_1_Template_div_click_0_listener() { const suiteTest_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestSuite(suiteTest_r10.SuiteID)); });
604
+ i0.ɵɵelementStart(1, "div", 135);
605
+ i0.ɵɵelement(2, "i", 24);
367
606
  i0.ɵɵelementEnd();
368
- i0.ɵɵelementStart(3, "div", 77)(4, "div", 78);
607
+ i0.ɵɵelementStart(3, "div", 136)(4, "div", 137);
369
608
  i0.ɵɵtext(5);
370
609
  i0.ɵɵelementEnd();
371
- i0.ɵɵelementStart(6, "div", 79)(7, "span");
372
- i0.ɵɵtext(8);
373
- i0.ɵɵelementEnd()()();
374
- i0.ɵɵelement(9, "i", 67);
610
+ i0.ɵɵelementStart(6, "div", 138)(7, "span");
611
+ i0.ɵɵelement(8, "i", 139);
612
+ i0.ɵɵtext(9);
613
+ i0.ɵɵelementEnd();
614
+ i0.ɵɵtemplate(10, TestFormComponentExtended_div_52_div_2_div_1_span_10_Template, 3, 1, "span", 101);
615
+ i0.ɵɵelementEnd()();
616
+ i0.ɵɵelement(11, "i", 106);
375
617
  i0.ɵɵelementEnd();
376
618
  } if (rf & 2) {
377
- const suiteTest_r7 = ctx.$implicit;
619
+ const suiteTest_r10 = ctx.$implicit;
378
620
  i0.ɵɵadvance(5);
379
- i0.ɵɵtextInterpolate(suiteTest_r7.Suite);
380
- i0.ɵɵadvance(3);
381
- i0.ɵɵtextInterpolate1("Sequence: ", suiteTest_r7.Sequence, "");
621
+ i0.ɵɵtextInterpolate(suiteTest_r10.Suite);
622
+ i0.ɵɵadvance(4);
623
+ i0.ɵɵtextInterpolate1(" Sequence: ", suiteTest_r10.Sequence, "");
624
+ i0.ɵɵadvance();
625
+ i0.ɵɵproperty("ngIf", suiteTest_r10.Status);
382
626
  } }
383
- function TestFormComponentExtended_div_46_div_1_Template(rf, ctx) { if (rf & 1) {
384
- i0.ɵɵelementStart(0, "div", 72);
385
- i0.ɵɵtemplate(1, TestFormComponentExtended_div_46_div_1_div_1_Template, 10, 2, "div", 73);
627
+ function TestFormComponentExtended_div_52_div_2_Template(rf, ctx) { if (rf & 1) {
628
+ i0.ɵɵelementStart(0, "div", 132);
629
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_52_div_2_div_1_Template, 12, 3, "div", 133);
386
630
  i0.ɵɵelementEnd();
387
631
  } if (rf & 2) {
388
632
  const ctx_r0 = i0.ɵɵnextContext(2);
389
633
  i0.ɵɵadvance();
390
634
  i0.ɵɵproperty("ngForOf", ctx_r0.suiteTests);
391
635
  } }
392
- function TestFormComponentExtended_div_46_div_2_Template(rf, ctx) { if (rf & 1) {
393
- i0.ɵɵelementStart(0, "div", 68);
394
- i0.ɵɵelement(1, "i", 69);
395
- i0.ɵɵelementStart(2, "p");
396
- i0.ɵɵtext(3, "This test is not part of any test suite");
636
+ function TestFormComponentExtended_div_52_div_3_Template(rf, ctx) { if (rf & 1) {
637
+ i0.ɵɵelementStart(0, "div", 127)(1, "div", 128);
638
+ i0.ɵɵelement(2, "i", 140);
639
+ i0.ɵɵelementEnd();
640
+ i0.ɵɵelementStart(3, "h4");
641
+ i0.ɵɵtext(4, "Not Part of Any Suite");
642
+ i0.ɵɵelementEnd();
643
+ i0.ɵɵelementStart(5, "p");
644
+ i0.ɵɵtext(6, "This test is not included in any test suites. Add it to a suite to run it with other tests.");
645
+ i0.ɵɵelementEnd()();
646
+ } }
647
+ function TestFormComponentExtended_div_52_Template(rf, ctx) { if (rf & 1) {
648
+ i0.ɵɵelementStart(0, "div", 130);
649
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_52_div_1_Template, 3, 2, "div", 79)(2, TestFormComponentExtended_div_52_div_2_Template, 2, 1, "div", 131)(3, TestFormComponentExtended_div_52_div_3_Template, 7, 0, "div", 81);
650
+ i0.ɵɵelementEnd();
651
+ } if (rf & 2) {
652
+ const ctx_r0 = i0.ɵɵnextContext();
653
+ i0.ɵɵadvance();
654
+ i0.ɵɵproperty("ngIf", ctx_r0.loadingSuites);
655
+ i0.ɵɵadvance();
656
+ i0.ɵɵproperty("ngIf", !ctx_r0.loadingSuites && ctx_r0.suiteTests.length > 0);
657
+ i0.ɵɵadvance();
658
+ i0.ɵɵproperty("ngIf", ctx_r0.suiteTestsLoaded && !ctx_r0.loadingSuites && ctx_r0.suiteTests.length === 0);
659
+ } }
660
+ function TestFormComponentExtended_div_53_div_1_Template(rf, ctx) { if (rf & 1) {
661
+ i0.ɵɵelementStart(0, "div", 82);
662
+ i0.ɵɵelement(1, "mj-loading", 143);
663
+ i0.ɵɵelementEnd();
664
+ } }
665
+ function TestFormComponentExtended_div_53_div_2_div_17_div_9_Template(rf, ctx) { if (rf & 1) {
666
+ i0.ɵɵelementStart(0, "div", 154)(1, "div", 160);
667
+ i0.ɵɵelement(2, "i", 161);
668
+ i0.ɵɵelementEnd();
669
+ i0.ɵɵelementStart(3, "div", 156)(4, "div", 157);
670
+ i0.ɵɵtext(5);
671
+ i0.ɵɵelement(6, "i", 162);
672
+ i0.ɵɵelementEnd();
673
+ i0.ɵɵelementStart(7, "div", 158);
674
+ i0.ɵɵtext(8, "Pass Rate");
675
+ i0.ɵɵelementEnd()()();
676
+ } if (rf & 2) {
677
+ const ctx_r0 = i0.ɵɵnextContext(4);
678
+ i0.ɵɵadvance(5);
679
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.getOverallPassRate().toFixed(1), "% ");
680
+ i0.ɵɵadvance();
681
+ 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");
682
+ } }
683
+ function TestFormComponentExtended_div_53_div_2_div_17_div_10_Template(rf, ctx) { if (rf & 1) {
684
+ i0.ɵɵelementStart(0, "div", 154)(1, "div", 155);
685
+ i0.ɵɵelement(2, "i", 163);
686
+ i0.ɵɵelementEnd();
687
+ i0.ɵɵelementStart(3, "div", 156)(4, "div", 157);
688
+ i0.ɵɵtext(5);
689
+ i0.ɵɵelementEnd();
690
+ i0.ɵɵelementStart(6, "div", 158);
691
+ i0.ɵɵtext(7, "Avg Score");
692
+ i0.ɵɵelementEnd()()();
693
+ } if (rf & 2) {
694
+ const ctx_r0 = i0.ɵɵnextContext(4);
695
+ i0.ɵɵadvance(5);
696
+ i0.ɵɵtextInterpolate1("", (ctx_r0.getOverallAvgScore() * 100).toFixed(1), "%");
697
+ } }
698
+ function TestFormComponentExtended_div_53_div_2_div_17_Template(rf, ctx) { if (rf & 1) {
699
+ i0.ɵɵelementStart(0, "div", 153)(1, "div", 154)(2, "div", 155);
700
+ i0.ɵɵelement(3, "i", 129);
701
+ i0.ɵɵelementEnd();
702
+ i0.ɵɵelementStart(4, "div", 156)(5, "div", 157);
703
+ i0.ɵɵtext(6);
704
+ i0.ɵɵelementEnd();
705
+ i0.ɵɵelementStart(7, "div", 158);
706
+ i0.ɵɵtext(8, "Total Runs");
707
+ i0.ɵɵelementEnd()()();
708
+ i0.ɵɵtemplate(9, TestFormComponentExtended_div_53_div_2_div_17_div_9_Template, 9, 11, "div", 159)(10, TestFormComponentExtended_div_53_div_2_div_17_div_10_Template, 8, 1, "div", 159);
709
+ i0.ɵɵelementStart(11, "div", 154)(12, "div", 155);
710
+ i0.ɵɵelement(13, "i", 107);
711
+ i0.ɵɵelementEnd();
712
+ i0.ɵɵelementStart(14, "div", 156)(15, "div", 157);
713
+ i0.ɵɵtext(16);
714
+ i0.ɵɵelementEnd();
715
+ i0.ɵɵelementStart(17, "div", 158);
716
+ i0.ɵɵtext(18, "Avg Duration");
717
+ i0.ɵɵelementEnd()()();
718
+ i0.ɵɵelementStart(19, "div", 154)(20, "div", 155);
719
+ i0.ɵɵelement(21, "i", 108);
720
+ i0.ɵɵelementEnd();
721
+ i0.ɵɵelementStart(22, "div", 156)(23, "div", 157);
722
+ i0.ɵɵtext(24);
723
+ i0.ɵɵelementEnd();
724
+ i0.ɵɵelementStart(25, "div", 158);
725
+ i0.ɵɵtext(26, "Avg Cost");
726
+ i0.ɵɵelementEnd()()()();
727
+ } if (rf & 2) {
728
+ const ctx_r0 = i0.ɵɵnextContext(3);
729
+ i0.ɵɵadvance(6);
730
+ i0.ɵɵtextInterpolate(ctx_r0.getTotalRuns());
731
+ i0.ɵɵadvance(3);
732
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
733
+ i0.ɵɵadvance();
734
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showAuto);
735
+ i0.ɵɵadvance(6);
736
+ i0.ɵɵtextInterpolate(ctx_r0.formatDuration(ctx_r0.getOverallAvgDuration()));
737
+ i0.ɵɵadvance(8);
738
+ i0.ɵɵtextInterpolate(ctx_r0.formatCost(ctx_r0.getOverallAvgCost()));
739
+ } }
740
+ function TestFormComponentExtended_div_53_div_2_div_18_th_12_Template(rf, ctx) { if (rf & 1) {
741
+ i0.ɵɵelementStart(0, "th");
742
+ i0.ɵɵtext(1, "Passed");
743
+ i0.ɵɵelementEnd();
744
+ } }
745
+ function TestFormComponentExtended_div_53_div_2_div_18_th_13_Template(rf, ctx) { if (rf & 1) {
746
+ i0.ɵɵelementStart(0, "th");
747
+ i0.ɵɵtext(1, "Failed");
748
+ i0.ɵɵelementEnd();
749
+ } }
750
+ function TestFormComponentExtended_div_53_div_2_div_18_th_14_Template(rf, ctx) { if (rf & 1) {
751
+ i0.ɵɵelementStart(0, "th");
752
+ i0.ɵɵtext(1, "Pass Rate");
753
+ i0.ɵɵelementEnd();
754
+ } }
755
+ function TestFormComponentExtended_div_53_div_2_div_18_th_15_Template(rf, ctx) { if (rf & 1) {
756
+ i0.ɵɵelementStart(0, "th");
757
+ i0.ɵɵtext(1, "Avg Score");
758
+ i0.ɵɵelementEnd();
759
+ } }
760
+ function TestFormComponentExtended_div_53_div_2_div_18_tr_21_td_6_Template(rf, ctx) { if (rf & 1) {
761
+ i0.ɵɵelementStart(0, "td", 177);
762
+ i0.ɵɵtext(1);
763
+ i0.ɵɵelementEnd();
764
+ } if (rf & 2) {
765
+ const day_r12 = i0.ɵɵnextContext().$implicit;
766
+ i0.ɵɵadvance();
767
+ i0.ɵɵtextInterpolate(day_r12.passCount);
768
+ } }
769
+ function TestFormComponentExtended_div_53_div_2_div_18_tr_21_td_7_Template(rf, ctx) { if (rf & 1) {
770
+ i0.ɵɵelementStart(0, "td", 178);
771
+ i0.ɵɵtext(1);
772
+ i0.ɵɵelementEnd();
773
+ } if (rf & 2) {
774
+ const day_r12 = i0.ɵɵnextContext().$implicit;
775
+ i0.ɵɵadvance();
776
+ i0.ɵɵtextInterpolate(day_r12.failCount);
777
+ } }
778
+ function TestFormComponentExtended_div_53_div_2_div_18_tr_21_td_8_Template(rf, ctx) { if (rf & 1) {
779
+ i0.ɵɵelementStart(0, "td", 179)(1, "div", 180);
780
+ i0.ɵɵelement(2, "div", 181);
781
+ i0.ɵɵelementStart(3, "span", 182);
782
+ i0.ɵɵtext(4);
783
+ i0.ɵɵelementEnd()()();
784
+ } if (rf & 2) {
785
+ const day_r12 = i0.ɵɵnextContext().$implicit;
786
+ i0.ɵɵadvance(2);
787
+ i0.ɵɵstyleProp("width", day_r12.passRate, "%");
788
+ i0.ɵɵadvance(2);
789
+ i0.ɵɵtextInterpolate1("", day_r12.passRate.toFixed(1), "%");
790
+ } }
791
+ function TestFormComponentExtended_div_53_div_2_div_18_tr_21_td_9_Template(rf, ctx) { if (rf & 1) {
792
+ i0.ɵɵelementStart(0, "td", 183);
793
+ i0.ɵɵtext(1);
794
+ i0.ɵɵelementEnd();
795
+ } if (rf & 2) {
796
+ const day_r12 = i0.ɵɵnextContext().$implicit;
797
+ i0.ɵɵadvance();
798
+ i0.ɵɵtextInterpolate1("", (day_r12.avgScore * 100).toFixed(1), "%");
799
+ } }
800
+ function TestFormComponentExtended_div_53_div_2_div_18_tr_21_Template(rf, ctx) { if (rf & 1) {
801
+ i0.ɵɵelementStart(0, "tr")(1, "td", 169);
802
+ i0.ɵɵtext(2);
803
+ i0.ɵɵpipe(3, "date");
804
+ i0.ɵɵelementEnd();
805
+ i0.ɵɵelementStart(4, "td", 170);
806
+ i0.ɵɵtext(5);
807
+ i0.ɵɵelementEnd();
808
+ i0.ɵɵtemplate(6, TestFormComponentExtended_div_53_div_2_div_18_tr_21_td_6_Template, 2, 1, "td", 171)(7, TestFormComponentExtended_div_53_div_2_div_18_tr_21_td_7_Template, 2, 1, "td", 172)(8, TestFormComponentExtended_div_53_div_2_div_18_tr_21_td_8_Template, 5, 3, "td", 173)(9, TestFormComponentExtended_div_53_div_2_div_18_tr_21_td_9_Template, 2, 1, "td", 174);
809
+ i0.ɵɵelementStart(10, "td", 175);
810
+ i0.ɵɵtext(11);
811
+ i0.ɵɵelementEnd();
812
+ i0.ɵɵelementStart(12, "td", 176);
813
+ i0.ɵɵtext(13);
814
+ i0.ɵɵelementEnd()();
815
+ } if (rf & 2) {
816
+ const day_r12 = ctx.$implicit;
817
+ const ctx_r0 = i0.ɵɵnextContext(4);
818
+ i0.ɵɵadvance(2);
819
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 8, day_r12.date, "mediumDate"));
820
+ i0.ɵɵadvance(3);
821
+ i0.ɵɵtextInterpolate(day_r12.runCount);
822
+ i0.ɵɵadvance();
823
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
824
+ i0.ɵɵadvance();
825
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
826
+ i0.ɵɵadvance();
827
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
828
+ i0.ɵɵadvance();
829
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showAuto);
830
+ i0.ɵɵadvance(2);
831
+ i0.ɵɵtextInterpolate(ctx_r0.formatDuration(day_r12.avgDuration));
832
+ i0.ɵɵadvance(2);
833
+ i0.ɵɵtextInterpolate(ctx_r0.formatCost(day_r12.avgCost));
834
+ } }
835
+ function TestFormComponentExtended_div_53_div_2_div_18_Template(rf, ctx) { if (rf & 1) {
836
+ i0.ɵɵelementStart(0, "div", 164)(1, "h3");
837
+ i0.ɵɵelement(2, "i", 165);
838
+ i0.ɵɵtext(3, " Daily Performance");
839
+ i0.ɵɵelementEnd();
840
+ i0.ɵɵelementStart(4, "div", 166)(5, "table", 167)(6, "thead")(7, "tr")(8, "th");
841
+ i0.ɵɵtext(9, "Date");
842
+ i0.ɵɵelementEnd();
843
+ i0.ɵɵelementStart(10, "th");
844
+ i0.ɵɵtext(11, "Runs");
845
+ i0.ɵɵelementEnd();
846
+ i0.ɵɵtemplate(12, TestFormComponentExtended_div_53_div_2_div_18_th_12_Template, 2, 0, "th", 101)(13, TestFormComponentExtended_div_53_div_2_div_18_th_13_Template, 2, 0, "th", 101)(14, TestFormComponentExtended_div_53_div_2_div_18_th_14_Template, 2, 0, "th", 101)(15, TestFormComponentExtended_div_53_div_2_div_18_th_15_Template, 2, 0, "th", 101);
847
+ i0.ɵɵelementStart(16, "th");
848
+ i0.ɵɵtext(17, "Avg Duration");
849
+ i0.ɵɵelementEnd();
850
+ i0.ɵɵelementStart(18, "th");
851
+ i0.ɵɵtext(19, "Avg Cost");
852
+ i0.ɵɵelementEnd()()();
853
+ i0.ɵɵelementStart(20, "tbody");
854
+ i0.ɵɵtemplate(21, TestFormComponentExtended_div_53_div_2_div_18_tr_21_Template, 14, 11, "tr", 168);
855
+ i0.ɵɵelementEnd()()()();
856
+ } if (rf & 2) {
857
+ const ctx_r0 = i0.ɵɵnextContext(3);
858
+ i0.ɵɵadvance(12);
859
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
860
+ i0.ɵɵadvance();
861
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
862
+ i0.ɵɵadvance();
863
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
864
+ i0.ɵɵadvance();
865
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showAuto);
866
+ i0.ɵɵadvance(6);
867
+ i0.ɵɵproperty("ngForOf", ctx_r0.historyData);
868
+ } }
869
+ function TestFormComponentExtended_div_53_div_2_div_19_div_5_div_4_span_1_Template(rf, ctx) { if (rf & 1) {
870
+ i0.ɵɵelementStart(0, "span", 199);
871
+ i0.ɵɵtext(1);
872
+ i0.ɵɵelementEnd();
873
+ } if (rf & 2) {
874
+ const tag_r15 = ctx.$implicit;
875
+ i0.ɵɵadvance();
876
+ i0.ɵɵtextInterpolate(tag_r15);
877
+ } }
878
+ function TestFormComponentExtended_div_53_div_2_div_19_div_5_div_4_span_2_Template(rf, ctx) { if (rf & 1) {
879
+ i0.ɵɵelementStart(0, "span", 200);
880
+ i0.ɵɵtext(1);
881
+ i0.ɵɵelementEnd();
882
+ } if (rf & 2) {
883
+ const suite_r14 = i0.ɵɵnextContext(2).$implicit;
884
+ i0.ɵɵadvance();
885
+ i0.ɵɵtextInterpolate1("+", suite_r14.tags.length - 3, "");
886
+ } }
887
+ function TestFormComponentExtended_div_53_div_2_div_19_div_5_div_4_Template(rf, ctx) { if (rf & 1) {
888
+ i0.ɵɵelementStart(0, "div", 196);
889
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_53_div_2_div_19_div_5_div_4_span_1_Template, 2, 1, "span", 197)(2, TestFormComponentExtended_div_53_div_2_div_19_div_5_div_4_span_2_Template, 2, 1, "span", 198);
890
+ i0.ɵɵelementEnd();
891
+ } if (rf & 2) {
892
+ const suite_r14 = i0.ɵɵnextContext().$implicit;
893
+ i0.ɵɵadvance();
894
+ i0.ɵɵproperty("ngForOf", suite_r14.tags.slice(0, 3));
895
+ i0.ɵɵadvance();
896
+ i0.ɵɵproperty("ngIf", suite_r14.tags.length > 3);
897
+ } }
898
+ function TestFormComponentExtended_div_53_div_2_div_19_div_5_div_11_Template(rf, ctx) { if (rf & 1) {
899
+ i0.ɵɵelementStart(0, "div", 191)(1, "span", 201);
900
+ i0.ɵɵtext(2);
901
+ i0.ɵɵelementEnd();
902
+ i0.ɵɵelementStart(3, "span", 193);
903
+ i0.ɵɵtext(4, "Pass Rate");
904
+ i0.ɵɵelementEnd()();
905
+ } if (rf & 2) {
906
+ const suite_r14 = i0.ɵɵnextContext().$implicit;
907
+ i0.ɵɵadvance();
908
+ i0.ɵɵclassProp("high", suite_r14.passRate >= 80)("low", suite_r14.passRate < 50);
909
+ i0.ɵɵadvance();
910
+ i0.ɵɵtextInterpolate1(" ", suite_r14.passRate.toFixed(1), "% ");
911
+ } }
912
+ function TestFormComponentExtended_div_53_div_2_div_19_div_5_div_12_Template(rf, ctx) { if (rf & 1) {
913
+ i0.ɵɵelementStart(0, "div", 191)(1, "span", 192);
914
+ i0.ɵɵtext(2);
915
+ i0.ɵɵelementEnd();
916
+ i0.ɵɵelementStart(3, "span", 193);
917
+ i0.ɵɵtext(4, "Avg Score");
918
+ i0.ɵɵelementEnd()();
919
+ } if (rf & 2) {
920
+ const suite_r14 = i0.ɵɵnextContext().$implicit;
921
+ i0.ɵɵadvance(2);
922
+ i0.ɵɵtextInterpolate1("", (suite_r14.avgScore * 100).toFixed(1), "%");
923
+ } }
924
+ function TestFormComponentExtended_div_53_div_2_div_19_div_5_div_23_Template(rf, ctx) { if (rf & 1) {
925
+ i0.ɵɵelementStart(0, "div", 191)(1, "span", 192);
926
+ i0.ɵɵtext(2);
927
+ i0.ɵɵelementEnd();
928
+ i0.ɵɵelementStart(3, "span", 193);
929
+ i0.ɵɵtext(4, "Last Run");
930
+ i0.ɵɵelementEnd()();
931
+ } if (rf & 2) {
932
+ const suite_r14 = i0.ɵɵnextContext().$implicit;
933
+ const ctx_r0 = i0.ɵɵnextContext(4);
934
+ i0.ɵɵadvance(2);
935
+ i0.ɵɵtextInterpolate(ctx_r0.getRelativeTime(suite_r14.lastRun));
936
+ } }
937
+ function TestFormComponentExtended_div_53_div_2_div_19_div_5_Template(rf, ctx) { if (rf & 1) {
938
+ const _r13 = i0.ɵɵgetCurrentView();
939
+ i0.ɵɵelementStart(0, "div", 186);
940
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_53_div_2_div_19_div_5_Template_div_click_0_listener() { const suite_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.openSuiteFromHistory(suite_r14.suiteId)); });
941
+ i0.ɵɵelementStart(1, "div", 187)(2, "div", 188);
942
+ i0.ɵɵtext(3);
943
+ i0.ɵɵelementEnd();
944
+ i0.ɵɵtemplate(4, TestFormComponentExtended_div_53_div_2_div_19_div_5_div_4_Template, 3, 2, "div", 189);
945
+ i0.ɵɵelementEnd();
946
+ i0.ɵɵelementStart(5, "div", 190)(6, "div", 191)(7, "span", 192);
947
+ i0.ɵɵtext(8);
948
+ i0.ɵɵelementEnd();
949
+ i0.ɵɵelementStart(9, "span", 193);
950
+ i0.ɵɵtext(10, "Runs");
951
+ i0.ɵɵelementEnd()();
952
+ i0.ɵɵtemplate(11, TestFormComponentExtended_div_53_div_2_div_19_div_5_div_11_Template, 5, 5, "div", 194)(12, TestFormComponentExtended_div_53_div_2_div_19_div_5_div_12_Template, 5, 1, "div", 194);
953
+ i0.ɵɵelementStart(13, "div", 191)(14, "span", 192);
954
+ i0.ɵɵtext(15);
955
+ i0.ɵɵelementEnd();
956
+ i0.ɵɵelementStart(16, "span", 193);
957
+ i0.ɵɵtext(17, "Avg Duration");
958
+ i0.ɵɵelementEnd()();
959
+ i0.ɵɵelementStart(18, "div", 191)(19, "span", 192);
960
+ i0.ɵɵtext(20);
961
+ i0.ɵɵelementEnd();
962
+ i0.ɵɵelementStart(21, "span", 193);
963
+ i0.ɵɵtext(22, "Avg Cost");
964
+ i0.ɵɵelementEnd()();
965
+ i0.ɵɵtemplate(23, TestFormComponentExtended_div_53_div_2_div_19_div_5_div_23_Template, 5, 1, "div", 194);
966
+ i0.ɵɵelementEnd();
967
+ i0.ɵɵelement(24, "i", 195);
968
+ i0.ɵɵelementEnd();
969
+ } if (rf & 2) {
970
+ const suite_r14 = ctx.$implicit;
971
+ const ctx_r0 = i0.ɵɵnextContext(4);
972
+ i0.ɵɵadvance(3);
973
+ i0.ɵɵtextInterpolate(suite_r14.suiteName);
974
+ i0.ɵɵadvance();
975
+ i0.ɵɵproperty("ngIf", suite_r14.tags.length > 0);
976
+ i0.ɵɵadvance(4);
977
+ i0.ɵɵtextInterpolate(suite_r14.totalRuns);
978
+ i0.ɵɵadvance(3);
979
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showExecution);
980
+ i0.ɵɵadvance();
981
+ i0.ɵɵproperty("ngIf", ctx_r0.evalPreferences.showAuto);
982
+ i0.ɵɵadvance(3);
983
+ i0.ɵɵtextInterpolate(ctx_r0.formatDuration(suite_r14.avgDuration));
984
+ i0.ɵɵadvance(5);
985
+ i0.ɵɵtextInterpolate(ctx_r0.formatCost(suite_r14.avgCost));
986
+ i0.ɵɵadvance(3);
987
+ i0.ɵɵproperty("ngIf", suite_r14.lastRun);
988
+ } }
989
+ function TestFormComponentExtended_div_53_div_2_div_19_Template(rf, ctx) { if (rf & 1) {
990
+ i0.ɵɵelementStart(0, "div", 164)(1, "h3");
991
+ i0.ɵɵelement(2, "i", 24);
992
+ i0.ɵɵtext(3, " Performance by Suite");
993
+ i0.ɵɵelementEnd();
994
+ i0.ɵɵelementStart(4, "div", 184);
995
+ i0.ɵɵtemplate(5, TestFormComponentExtended_div_53_div_2_div_19_div_5_Template, 25, 8, "div", 185);
397
996
  i0.ɵɵelementEnd()();
997
+ } if (rf & 2) {
998
+ const ctx_r0 = i0.ɵɵnextContext(3);
999
+ i0.ɵɵadvance(5);
1000
+ i0.ɵɵproperty("ngForOf", ctx_r0.suitePerformance);
398
1001
  } }
399
- function TestFormComponentExtended_div_46_Template(rf, ctx) { if (rf & 1) {
400
- i0.ɵɵelementStart(0, "div", 70);
401
- i0.ɵɵtemplate(1, TestFormComponentExtended_div_46_div_1_Template, 2, 1, "div", 71)(2, TestFormComponentExtended_div_46_div_2_Template, 4, 0, "div", 55);
1002
+ function TestFormComponentExtended_div_53_div_2_div_20_Template(rf, ctx) { if (rf & 1) {
1003
+ const _r16 = i0.ɵɵgetCurrentView();
1004
+ i0.ɵɵelementStart(0, "div", 127)(1, "div", 128);
1005
+ i0.ɵɵelement(2, "i", 25);
1006
+ i0.ɵɵelementEnd();
1007
+ i0.ɵɵelementStart(3, "h4");
1008
+ i0.ɵɵtext(4, "No History Available");
1009
+ i0.ɵɵelementEnd();
1010
+ i0.ɵɵelementStart(5, "p");
1011
+ i0.ɵɵtext(6, "Run this test to start building history and analytics data.");
1012
+ i0.ɵɵelementEnd();
1013
+ i0.ɵɵelementStart(7, "button", 12);
1014
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_53_div_2_div_20_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.runTest()); });
1015
+ i0.ɵɵelement(8, "i", 13);
1016
+ i0.ɵɵtext(9, " Run Test Now ");
1017
+ i0.ɵɵelementEnd()();
1018
+ } }
1019
+ function TestFormComponentExtended_div_53_div_2_Template(rf, ctx) { if (rf & 1) {
1020
+ const _r11 = i0.ɵɵgetCurrentView();
1021
+ i0.ɵɵelementStart(0, "div", 144)(1, "div", 145)(2, "div", 146)(3, "span", 147);
1022
+ i0.ɵɵtext(4, "Time Range:");
1023
+ i0.ɵɵelementEnd();
1024
+ i0.ɵɵelementStart(5, "button", 148);
1025
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_53_div_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("7d")); });
1026
+ i0.ɵɵtext(6, "7 Days");
1027
+ i0.ɵɵelementEnd();
1028
+ i0.ɵɵelementStart(7, "button", 148);
1029
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_53_div_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("30d")); });
1030
+ i0.ɵɵtext(8, "30 Days");
1031
+ i0.ɵɵelementEnd();
1032
+ i0.ɵɵelementStart(9, "button", 148);
1033
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_53_div_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("90d")); });
1034
+ i0.ɵɵtext(10, "90 Days");
1035
+ i0.ɵɵelementEnd();
1036
+ i0.ɵɵelementStart(11, "button", 148);
1037
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_53_div_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("all")); });
1038
+ i0.ɵɵtext(12, "All Time");
1039
+ i0.ɵɵelementEnd()();
1040
+ i0.ɵɵelementStart(13, "div", 149)(14, "button", 14);
1041
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_53_div_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.exportHistoryToCSV()); });
1042
+ i0.ɵɵelement(15, "i", 150);
1043
+ i0.ɵɵtext(16, " Export CSV ");
1044
+ i0.ɵɵelementEnd()()();
1045
+ i0.ɵɵtemplate(17, TestFormComponentExtended_div_53_div_2_div_17_Template, 27, 5, "div", 151)(18, TestFormComponentExtended_div_53_div_2_div_18_Template, 22, 5, "div", 152)(19, TestFormComponentExtended_div_53_div_2_div_19_Template, 6, 1, "div", 152)(20, TestFormComponentExtended_div_53_div_2_div_20_Template, 10, 0, "div", 81);
1046
+ i0.ɵɵelementEnd();
1047
+ } if (rf & 2) {
1048
+ const ctx_r0 = i0.ɵɵnextContext(2);
1049
+ i0.ɵɵadvance(5);
1050
+ i0.ɵɵclassProp("active", ctx_r0.historyTimeRange === "7d");
1051
+ i0.ɵɵadvance(2);
1052
+ i0.ɵɵclassProp("active", ctx_r0.historyTimeRange === "30d");
1053
+ i0.ɵɵadvance(2);
1054
+ i0.ɵɵclassProp("active", ctx_r0.historyTimeRange === "90d");
1055
+ i0.ɵɵadvance(2);
1056
+ i0.ɵɵclassProp("active", ctx_r0.historyTimeRange === "all");
1057
+ i0.ɵɵadvance(3);
1058
+ i0.ɵɵproperty("disabled", ctx_r0.historyData.length === 0);
1059
+ i0.ɵɵadvance(3);
1060
+ i0.ɵɵproperty("ngIf", ctx_r0.historyData.length > 0);
1061
+ i0.ɵɵadvance();
1062
+ i0.ɵɵproperty("ngIf", ctx_r0.historyData.length > 0);
1063
+ i0.ɵɵadvance();
1064
+ i0.ɵɵproperty("ngIf", ctx_r0.suitePerformance.length > 0);
1065
+ i0.ɵɵadvance();
1066
+ i0.ɵɵproperty("ngIf", ctx_r0.historyData.length === 0);
1067
+ } }
1068
+ function TestFormComponentExtended_div_53_Template(rf, ctx) { if (rf & 1) {
1069
+ i0.ɵɵelementStart(0, "div", 141);
1070
+ i0.ɵɵtemplate(1, TestFormComponentExtended_div_53_div_1_Template, 2, 0, "div", 79)(2, TestFormComponentExtended_div_53_div_2_Template, 21, 13, "div", 142);
402
1071
  i0.ɵɵelementEnd();
403
1072
  } if (rf & 2) {
404
1073
  const ctx_r0 = i0.ɵɵnextContext();
405
1074
  i0.ɵɵadvance();
406
- i0.ɵɵproperty("ngIf", ctx_r0.suiteTests.length > 0);
1075
+ i0.ɵɵproperty("ngIf", ctx_r0.loadingHistory);
407
1076
  i0.ɵɵadvance();
408
- i0.ɵɵproperty("ngIf", ctx_r0.suiteTestsLoaded && ctx_r0.suiteTests.length === 0);
1077
+ i0.ɵɵproperty("ngIf", !ctx_r0.loadingHistory && ctx_r0.historyLoaded);
1078
+ } }
1079
+ function TestFormComponentExtended_div_56_Template(rf, ctx) { if (rf & 1) {
1080
+ const _r17 = i0.ɵɵgetCurrentView();
1081
+ i0.ɵɵelementStart(0, "div", 202)(1, "div", 203);
1082
+ i0.ɵɵelement(2, "i", 33);
1083
+ i0.ɵɵtext(3, " Shortcuts ");
1084
+ i0.ɵɵelementStart(4, "button", 204);
1085
+ i0.ɵɵlistener("click", function TestFormComponentExtended_div_56_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.toggleShortcuts()); });
1086
+ i0.ɵɵelement(5, "i", 205);
1087
+ i0.ɵɵelementEnd()();
1088
+ i0.ɵɵelementStart(6, "div", 206)(7, "div", 207)(8, "span");
1089
+ i0.ɵɵtext(9, "Refresh");
1090
+ i0.ɵɵelementEnd();
1091
+ i0.ɵɵelementStart(10, "span", 208)(11, "kbd");
1092
+ i0.ɵɵtext(12, "Cmd");
1093
+ i0.ɵɵelementEnd();
1094
+ i0.ɵɵelementStart(13, "kbd");
1095
+ i0.ɵɵtext(14, "R");
1096
+ i0.ɵɵelementEnd()()();
1097
+ i0.ɵɵelementStart(15, "div", 207)(16, "span");
1098
+ i0.ɵɵtext(17, "Run Test");
1099
+ i0.ɵɵelementEnd();
1100
+ i0.ɵɵelementStart(18, "span", 208)(19, "kbd");
1101
+ i0.ɵɵtext(20, "Cmd");
1102
+ i0.ɵɵelementEnd();
1103
+ i0.ɵɵelementStart(21, "kbd");
1104
+ i0.ɵɵtext(22, "Enter");
1105
+ i0.ɵɵelementEnd()()();
1106
+ i0.ɵɵelementStart(23, "div", 207)(24, "span");
1107
+ i0.ɵɵtext(25, "Switch Tabs");
1108
+ i0.ɵɵelementEnd();
1109
+ i0.ɵɵelementStart(26, "span", 208)(27, "kbd");
1110
+ i0.ɵɵtext(28, "1");
1111
+ i0.ɵɵelementEnd();
1112
+ i0.ɵɵtext(29, "-");
1113
+ i0.ɵɵelementStart(30, "kbd");
1114
+ i0.ɵɵtext(31, "5");
1115
+ i0.ɵɵelementEnd()()()()();
409
1116
  } }
1117
+ /** Settings key for keyboard shortcuts visibility */
1118
+ const SHORTCUTS_SETTINGS_KEY = '__mj.Testing.ShowKeyboardShortcuts';
410
1119
  let TestFormComponentExtended = class TestFormComponentExtended extends TestFormComponent {
411
- constructor(elementRef, sharedService, router, route, cdr, testingDialogService) {
1120
+ constructor(elementRef, sharedService, router, route, cdr, testingDialogService, evalPrefsService) {
412
1121
  super(elementRef, sharedService, router, route, cdr);
413
1122
  this.router = router;
414
1123
  this.cdr = cdr;
415
1124
  this.testingDialogService = testingDialogService;
1125
+ this.evalPrefsService = evalPrefsService;
416
1126
  this.destroy$ = new Subject();
417
1127
  // UI state
418
1128
  this.activeTab = 'overview';
419
1129
  this.loading = false;
1130
+ this.loadingRuns = false;
1131
+ this.loadingSuites = false;
420
1132
  this.error = null;
421
1133
  this.testRunsLoaded = false;
422
1134
  this.suiteTestsLoaded = false;
1135
+ this.isRefreshing = false;
423
1136
  // Related data
424
1137
  this.testRuns = [];
425
1138
  this.suiteTests = [];
1139
+ // Human feedback map: testRunId -> feedback entity
1140
+ this.feedbackMap = new Map();
1141
+ // History tab data
1142
+ this.historyLoaded = false;
1143
+ this.loadingHistory = false;
1144
+ this.historyTimeRange = '30d';
1145
+ this.historyData = [];
1146
+ this.suitePerformance = [];
1147
+ this.uniqueTags = [];
1148
+ this.selectedTagFilter = null;
426
1149
  // Parsed JSON fields
427
1150
  this.parsedData = {};
428
1151
  // Active JSON view
429
1152
  this.activeJsonView = 'input';
1153
+ // Code editor configuration
1154
+ this.jsonToolbar = createCopyOnlyToolbar();
1155
+ // Keyboard shortcuts
1156
+ this.keyboardShortcutsEnabled = true;
1157
+ this.showShortcuts = false; // Hidden by default
1158
+ this.shortcutsSettingEntity = null;
1159
+ this.metadata = new Metadata();
1160
+ // Evaluation preferences
1161
+ this.evalPreferences = { showExecution: true, showHuman: true, showAuto: false };
430
1162
  }
431
1163
  async ngOnInit() {
432
1164
  await super.ngOnInit();
1165
+ this.loadShortcutsSetting();
1166
+ // Subscribe to evaluation preferences
1167
+ this.evalPrefsService.preferences$
1168
+ .pipe(takeUntil(this.destroy$))
1169
+ .subscribe(prefs => {
1170
+ this.evalPreferences = prefs;
1171
+ this.cdr.markForCheck();
1172
+ });
433
1173
  if (this.record && this.record.ID) {
434
- await this.loadRelatedData();
435
1174
  this.parseJsonFields();
436
1175
  }
437
1176
  }
@@ -439,23 +1178,48 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
439
1178
  this.destroy$.next();
440
1179
  this.destroy$.complete();
441
1180
  }
442
- async loadRelatedData() {
443
- this.loading = true;
444
- try {
445
- this.cdr.markForCheck();
1181
+ // Keyboard shortcuts
1182
+ handleKeyboardShortcut(event) {
1183
+ if (!this.keyboardShortcutsEnabled)
1184
+ return;
1185
+ // Cmd/Ctrl + R: Refresh
1186
+ if ((event.metaKey || event.ctrlKey) && event.key === 'r' && !event.shiftKey) {
1187
+ event.preventDefault();
1188
+ this.refresh();
1189
+ return;
446
1190
  }
447
- catch (error) {
448
- console.error('Error loading related data:', error);
449
- this.error = 'Failed to load related data';
1191
+ // Cmd/Ctrl + Enter: Run test
1192
+ if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
1193
+ event.preventDefault();
1194
+ this.runTest();
1195
+ return;
450
1196
  }
451
- finally {
452
- this.loading = false;
453
- this.cdr.markForCheck();
1197
+ // Number keys for tabs (1-5)
1198
+ if (!event.metaKey && !event.ctrlKey && !event.altKey) {
1199
+ switch (event.key) {
1200
+ case '1':
1201
+ this.changeTab('overview');
1202
+ break;
1203
+ case '2':
1204
+ this.changeTab('config');
1205
+ break;
1206
+ case '3':
1207
+ this.changeTab('runs');
1208
+ break;
1209
+ case '4':
1210
+ this.changeTab('suites');
1211
+ break;
1212
+ case '5':
1213
+ this.changeTab('analytics');
1214
+ break;
1215
+ }
454
1216
  }
455
1217
  }
456
1218
  async loadTestRuns() {
457
1219
  if (this.testRunsLoaded)
458
1220
  return;
1221
+ this.loadingRuns = true;
1222
+ this.cdr.markForCheck();
459
1223
  try {
460
1224
  const rv = new RunView();
461
1225
  const result = await rv.RunView({
@@ -467,17 +1231,87 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
467
1231
  });
468
1232
  if (result.Success) {
469
1233
  this.testRuns = result.Results || [];
1234
+ // Load feedbacks for all test runs
1235
+ if (this.testRuns.length > 0) {
1236
+ await this.loadFeedbacksForTestRuns(this.testRuns.map(r => r.ID));
1237
+ }
470
1238
  }
471
1239
  this.testRunsLoaded = true;
472
- this.cdr.markForCheck();
473
1240
  }
474
1241
  catch (error) {
475
1242
  console.error('Error loading test runs:', error);
1243
+ SharedService.Instance.CreateSimpleNotification('Failed to load test runs', 'error', 3000);
476
1244
  }
1245
+ finally {
1246
+ this.loadingRuns = false;
1247
+ this.cdr.markForCheck();
1248
+ }
1249
+ }
1250
+ /**
1251
+ * Load feedbacks for a batch of test run IDs
1252
+ */
1253
+ async loadFeedbacksForTestRuns(testRunIds) {
1254
+ if (testRunIds.length === 0)
1255
+ return;
1256
+ try {
1257
+ const rv = new RunView();
1258
+ const chunkSize = 50;
1259
+ for (let i = 0; i < testRunIds.length; i += chunkSize) {
1260
+ const chunk = testRunIds.slice(i, i + chunkSize);
1261
+ const inClause = chunk.map(id => `'${id}'`).join(',');
1262
+ const result = await rv.RunView({
1263
+ EntityName: 'MJ: Test Run Feedbacks',
1264
+ ExtraFilter: `TestRunID IN (${inClause})`,
1265
+ ResultType: 'entity_object'
1266
+ });
1267
+ if (result.Success && result.Results) {
1268
+ for (const feedback of result.Results) {
1269
+ this.feedbackMap.set(feedback.TestRunID, feedback);
1270
+ }
1271
+ }
1272
+ }
1273
+ }
1274
+ catch (error) {
1275
+ console.warn('Failed to load feedbacks:', error);
1276
+ }
1277
+ }
1278
+ /**
1279
+ * Get feedback for a specific test run
1280
+ */
1281
+ getFeedbackForRun(testRunId) {
1282
+ return this.feedbackMap.get(testRunId);
1283
+ }
1284
+ /**
1285
+ * Get tooltip for status indicator
1286
+ */
1287
+ getStatusTooltip(status) {
1288
+ switch (status) {
1289
+ case 'Passed': return 'Status: Passed - Test completed without error';
1290
+ case 'Failed': return 'Status: Failed - Test assertions did not pass';
1291
+ case 'Error': return 'Status: Error - Test encountered an exception';
1292
+ case 'Timeout': return 'Status: Timeout - Test exceeded time limit';
1293
+ case 'Skipped': return 'Status: Skipped - Test was not executed';
1294
+ case 'Running': return 'Status: Running - Test is currently executing';
1295
+ case 'Pending': return 'Status: Pending - Test waiting to run';
1296
+ default: return `Status: ${status}`;
1297
+ }
1298
+ }
1299
+ /**
1300
+ * Get tooltip for human review with rating and optional comments
1301
+ */
1302
+ getHumanTooltip(rating, comments) {
1303
+ let tooltip = `Human Review: ${rating}/10 rating`;
1304
+ if (comments) {
1305
+ const truncated = comments.length > 200 ? comments.substring(0, 200) + '...' : comments;
1306
+ tooltip += `\n\n"${truncated}"`;
1307
+ }
1308
+ return tooltip;
477
1309
  }
478
1310
  async loadSuiteTests() {
479
1311
  if (this.suiteTestsLoaded)
480
1312
  return;
1313
+ this.loadingSuites = true;
1314
+ this.cdr.markForCheck();
481
1315
  try {
482
1316
  const rv = new RunView();
483
1317
  const result = await rv.RunView({
@@ -490,10 +1324,14 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
490
1324
  this.suiteTests = result.Results || [];
491
1325
  }
492
1326
  this.suiteTestsLoaded = true;
493
- this.cdr.markForCheck();
494
1327
  }
495
1328
  catch (error) {
496
1329
  console.error('Error loading suite tests:', error);
1330
+ SharedService.Instance.CreateSimpleNotification('Failed to load test suites', 'error', 3000);
1331
+ }
1332
+ finally {
1333
+ this.loadingSuites = false;
1334
+ this.cdr.markForCheck();
497
1335
  }
498
1336
  }
499
1337
  parseJsonFields() {
@@ -524,6 +1362,9 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
524
1362
  if (tab === 'suites' && !this.suiteTestsLoaded) {
525
1363
  this.loadSuiteTests();
526
1364
  }
1365
+ if (tab === 'analytics' && !this.historyLoaded) {
1366
+ this.loadHistory();
1367
+ }
527
1368
  this.cdr.markForCheck();
528
1369
  }
529
1370
  setJsonView(view) {
@@ -532,10 +1373,10 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
532
1373
  }
533
1374
  getStatusColor() {
534
1375
  switch (this.record.Status) {
535
- case 'Active': return '#4caf50';
536
- case 'Disabled': return '#9e9e9e';
537
- case 'Pending': return '#ffc107';
538
- default: return '#999';
1376
+ case 'Active': return '#10b981';
1377
+ case 'Disabled': return '#6b7280';
1378
+ case 'Pending': return '#f59e0b';
1379
+ default: return '#9ca3af';
539
1380
  }
540
1381
  }
541
1382
  getStatusIcon() {
@@ -546,6 +1387,20 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
546
1387
  default: return 'fa-circle-question';
547
1388
  }
548
1389
  }
1390
+ getStatusClass() {
1391
+ return `status-${this.record.Status?.toLowerCase() || 'unknown'}`;
1392
+ }
1393
+ getRunStatusColor(status) {
1394
+ switch (status) {
1395
+ case 'Passed': return '#10b981';
1396
+ case 'Failed': return '#ef4444';
1397
+ case 'Error': return '#f59e0b';
1398
+ case 'Timeout': return '#f97316';
1399
+ case 'Running': return '#3b82f6';
1400
+ case 'Pending': return '#8b5cf6';
1401
+ default: return '#6b7280';
1402
+ }
1403
+ }
549
1404
  getPassRate() {
550
1405
  if (this.testRuns.length === 0)
551
1406
  return 0;
@@ -579,9 +1434,28 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
579
1434
  formatCost(cost) {
580
1435
  return `$${cost.toFixed(6)}`;
581
1436
  }
1437
+ formatTimeout(ms) {
1438
+ if (ms === null || ms === undefined)
1439
+ return 'Default (5 min)';
1440
+ if (ms < 1000)
1441
+ return `${ms}ms`;
1442
+ if (ms < 60000)
1443
+ return `${(ms / 1000).toFixed(1)}s`;
1444
+ if (ms < 3600000) {
1445
+ const mins = Math.floor(ms / 60000);
1446
+ const secs = Math.floor((ms % 60000) / 1000);
1447
+ return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`;
1448
+ }
1449
+ const hours = Math.floor(ms / 3600000);
1450
+ const mins = Math.floor((ms % 3600000) / 60000);
1451
+ return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
1452
+ }
582
1453
  openTestRun(runId) {
583
1454
  SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(runId));
584
1455
  }
1456
+ getRunTags(run) {
1457
+ return TagsHelper.parseTags(run.Tags);
1458
+ }
585
1459
  openTestSuite(suiteId) {
586
1460
  SharedService.Instance.OpenEntityRecord('MJ: Test Suites', CompositeKey.FromID(suiteId));
587
1461
  }
@@ -591,28 +1465,368 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
591
1465
  }
592
1466
  }
593
1467
  async refresh() {
594
- await this.loadRelatedData();
595
- if (this.testRunsLoaded) {
596
- this.testRunsLoaded = false;
597
- await this.loadTestRuns();
1468
+ this.isRefreshing = true;
1469
+ this.cdr.markForCheck();
1470
+ try {
1471
+ await this.record.Load(this.record.ID);
1472
+ this.parseJsonFields();
1473
+ // Reset lazy-loaded data to force reload
1474
+ if (this.testRunsLoaded) {
1475
+ this.testRunsLoaded = false;
1476
+ this.testRuns = [];
1477
+ await this.loadTestRuns();
1478
+ }
1479
+ if (this.suiteTestsLoaded) {
1480
+ this.suiteTestsLoaded = false;
1481
+ this.suiteTests = [];
1482
+ await this.loadSuiteTests();
1483
+ }
1484
+ SharedService.Instance.CreateSimpleNotification('Refreshed successfully', 'success', 2000);
598
1485
  }
599
- if (this.suiteTestsLoaded) {
600
- this.suiteTestsLoaded = false;
601
- await this.loadSuiteTests();
1486
+ catch {
1487
+ SharedService.Instance.CreateSimpleNotification('Failed to refresh', 'error', 3000);
1488
+ }
1489
+ finally {
1490
+ this.isRefreshing = false;
1491
+ this.cdr.markForCheck();
602
1492
  }
603
- this.cdr.markForCheck();
604
1493
  }
605
1494
  getJsonData() {
1495
+ let data;
606
1496
  switch (this.activeJsonView) {
607
- case 'input': return this.parsedData.inputDefinition;
608
- case 'expected': return this.parsedData.expectedOutcomes;
609
- case 'config': return this.parsedData.configuration;
610
- case 'tags': return this.parsedData.tags;
611
- default: return null;
1497
+ case 'input':
1498
+ data = this.parsedData.inputDefinition;
1499
+ break;
1500
+ case 'expected':
1501
+ data = this.parsedData.expectedOutcomes;
1502
+ break;
1503
+ case 'config':
1504
+ data = this.parsedData.configuration;
1505
+ break;
1506
+ case 'tags':
1507
+ data = this.parsedData.tags;
1508
+ break;
1509
+ }
1510
+ return data ? JSON.stringify(data, null, 2) : '// No data available';
1511
+ }
1512
+ getRelativeTime(date) {
1513
+ if (!date)
1514
+ return 'N/A';
1515
+ const d = new Date(date);
1516
+ const now = new Date();
1517
+ const diffMs = now.getTime() - d.getTime();
1518
+ const diffMins = Math.floor(diffMs / 60000);
1519
+ const diffHours = Math.floor(diffMs / 3600000);
1520
+ const diffDays = Math.floor(diffMs / 86400000);
1521
+ if (diffMins < 1)
1522
+ return 'Just now';
1523
+ if (diffMins < 60)
1524
+ return `${diffMins}m ago`;
1525
+ if (diffHours < 24)
1526
+ return `${diffHours}h ago`;
1527
+ if (diffDays < 7)
1528
+ return `${diffDays}d ago`;
1529
+ return d.toLocaleDateString();
1530
+ }
1531
+ // ===========================
1532
+ // History Tab Methods
1533
+ // ===========================
1534
+ async loadHistory() {
1535
+ if (this.historyLoaded)
1536
+ return;
1537
+ this.loadingHistory = true;
1538
+ this.cdr.markForCheck();
1539
+ try {
1540
+ // Load all test runs for this test
1541
+ const rv = new RunView();
1542
+ const runsResult = await rv.RunView({
1543
+ EntityName: 'MJ: Test Runs',
1544
+ ExtraFilter: `TestID='${this.record.ID}'`,
1545
+ OrderBy: 'StartedAt DESC',
1546
+ ResultType: 'entity_object'
1547
+ });
1548
+ if (runsResult.Success && runsResult.Results) {
1549
+ const allRuns = runsResult.Results;
1550
+ // Extract unique tags from all runs
1551
+ this.uniqueTags = TagsHelper.getUniqueTags(allRuns.map(r => r.Tags));
1552
+ // Build history data (aggregated by date)
1553
+ this.historyData = this.buildHistoryData(allRuns);
1554
+ // Build suite performance data
1555
+ await this.buildSuitePerformance(allRuns);
1556
+ }
1557
+ this.historyLoaded = true;
1558
+ }
1559
+ catch (error) {
1560
+ console.error('Error loading history:', error);
1561
+ SharedService.Instance.CreateSimpleNotification('Failed to load history', 'error', 3000);
1562
+ }
1563
+ finally {
1564
+ this.loadingHistory = false;
1565
+ this.cdr.markForCheck();
1566
+ }
1567
+ }
1568
+ buildHistoryData(runs) {
1569
+ // Filter by time range
1570
+ const filteredRuns = this.filterRunsByTimeRange(runs);
1571
+ // Group by date
1572
+ const dateMap = new Map();
1573
+ for (const run of filteredRuns) {
1574
+ if (run.StartedAt) {
1575
+ const dateKey = new Date(run.StartedAt).toISOString().split('T')[0];
1576
+ if (!dateMap.has(dateKey)) {
1577
+ dateMap.set(dateKey, []);
1578
+ }
1579
+ dateMap.get(dateKey).push(run);
1580
+ }
1581
+ }
1582
+ // Convert to data points
1583
+ const dataPoints = [];
1584
+ for (const [dateKey, dateRuns] of dateMap) {
1585
+ const passCount = dateRuns.filter(r => r.Status === 'Passed').length;
1586
+ const failCount = dateRuns.filter(r => r.Status === 'Failed' || r.Status === 'Error').length;
1587
+ const scores = dateRuns.filter(r => r.Score != null).map(r => r.Score);
1588
+ const durations = dateRuns.filter(r => r.DurationSeconds != null).map(r => r.DurationSeconds);
1589
+ const costs = dateRuns.filter(r => r.CostUSD != null).map(r => r.CostUSD);
1590
+ dataPoints.push({
1591
+ date: new Date(dateKey),
1592
+ passRate: dateRuns.length > 0 ? (passCount / dateRuns.length) * 100 : 0,
1593
+ avgScore: scores.length > 0 ? scores.reduce((a, b) => a + b, 0) / scores.length : 0,
1594
+ avgDuration: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0,
1595
+ avgCost: costs.length > 0 ? costs.reduce((a, b) => a + b, 0) / costs.length : 0,
1596
+ runCount: dateRuns.length,
1597
+ passCount,
1598
+ failCount
1599
+ });
1600
+ }
1601
+ // Sort by date descending
1602
+ return dataPoints.sort((a, b) => b.date.getTime() - a.date.getTime());
1603
+ }
1604
+ filterRunsByTimeRange(runs) {
1605
+ if (this.historyTimeRange === 'all')
1606
+ return runs;
1607
+ const now = new Date();
1608
+ let cutoff;
1609
+ switch (this.historyTimeRange) {
1610
+ case '7d':
1611
+ cutoff = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
1612
+ break;
1613
+ case '30d':
1614
+ cutoff = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
1615
+ break;
1616
+ case '90d':
1617
+ cutoff = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);
1618
+ break;
1619
+ default:
1620
+ return runs;
1621
+ }
1622
+ return runs.filter(r => r.StartedAt && new Date(r.StartedAt) >= cutoff);
1623
+ }
1624
+ async buildSuitePerformance(runs) {
1625
+ // Group runs by suite
1626
+ const suiteMap = new Map();
1627
+ for (const run of runs) {
1628
+ if (run.TestSuiteRunID) {
1629
+ if (!suiteMap.has(run.TestSuiteRunID)) {
1630
+ suiteMap.set(run.TestSuiteRunID, []);
1631
+ }
1632
+ suiteMap.get(run.TestSuiteRunID).push(run);
1633
+ }
1634
+ }
1635
+ // Load suite run info for each unique suite run
1636
+ if (suiteMap.size > 0) {
1637
+ const suiteRunIds = Array.from(suiteMap.keys()).map(id => `'${id}'`).join(',');
1638
+ const rv = new RunView();
1639
+ const suiteRunsResult = await rv.RunView({
1640
+ EntityName: 'MJ: Test Suite Runs',
1641
+ ExtraFilter: `ID IN (${suiteRunIds})`,
1642
+ ResultType: 'entity_object'
1643
+ });
1644
+ if (suiteRunsResult.Success && suiteRunsResult.Results) {
1645
+ // Group by suite ID
1646
+ const suiteIdMap = new Map();
1647
+ for (const suiteRun of suiteRunsResult.Results) {
1648
+ const suiteId = suiteRun.SuiteID;
1649
+ if (!suiteIdMap.has(suiteId)) {
1650
+ suiteIdMap.set(suiteId, { runs: [], suiteRuns: [] });
1651
+ }
1652
+ suiteIdMap.get(suiteId).suiteRuns.push(suiteRun);
1653
+ const testRuns = suiteMap.get(suiteRun.ID) || [];
1654
+ suiteIdMap.get(suiteId).runs.push(...testRuns);
1655
+ }
1656
+ // Build performance data for each suite
1657
+ this.suitePerformance = [];
1658
+ for (const [suiteId, data] of suiteIdMap) {
1659
+ const suiteName = data.suiteRuns[0]?.Suite || 'Unknown Suite';
1660
+ const totalRuns = data.runs.length;
1661
+ const passedRuns = data.runs.filter(r => r.Status === 'Passed').length;
1662
+ const failedRuns = data.runs.filter(r => r.Status === 'Failed' || r.Status === 'Error').length;
1663
+ const scores = data.runs.filter(r => r.Score != null).map(r => r.Score);
1664
+ const durations = data.runs.filter(r => r.DurationSeconds != null).map(r => r.DurationSeconds);
1665
+ const costs = data.runs.filter(r => r.CostUSD != null).map(r => r.CostUSD);
1666
+ // Collect all tags from suite runs
1667
+ const allTags = TagsHelper.getUniqueTags(data.suiteRuns.map(sr => sr.Tags));
1668
+ // Find most recent run
1669
+ const lastRun = data.runs
1670
+ .filter(r => r.StartedAt)
1671
+ .sort((a, b) => new Date(b.StartedAt).getTime() - new Date(a.StartedAt).getTime())[0];
1672
+ this.suitePerformance.push({
1673
+ suiteId,
1674
+ suiteName,
1675
+ totalRuns,
1676
+ passedRuns,
1677
+ failedRuns,
1678
+ passRate: totalRuns > 0 ? (passedRuns / totalRuns) * 100 : 0,
1679
+ avgScore: scores.length > 0 ? scores.reduce((a, b) => a + b, 0) / scores.length : 0,
1680
+ avgDuration: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0,
1681
+ avgCost: costs.length > 0 ? costs.reduce((a, b) => a + b, 0) / costs.length : 0,
1682
+ lastRun: lastRun?.StartedAt ? new Date(lastRun.StartedAt) : null,
1683
+ tags: allTags
1684
+ });
1685
+ }
1686
+ // Sort by total runs descending
1687
+ this.suitePerformance.sort((a, b) => b.totalRuns - a.totalRuns);
1688
+ }
612
1689
  }
613
1690
  }
614
- static { this.ɵfac = function TestFormComponentExtended_Factory(t) { return new (t || TestFormComponentExtended)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i1.SharedService), i0.ɵɵdirectiveInject(i2.Router), i0.ɵɵdirectiveInject(i2.ActivatedRoute), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i3.TestingDialogService)); }; }
615
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TestFormComponentExtended, selectors: [["mj-test-form"]], features: [i0.ɵɵInheritDefinitionFeature], decls: 47, vars: 24, consts: [["kendoDialogContainer", "", 1, "test-form"], [1, "test-header"], [1, "header-content"], [1, "header-left"], [1, "test-icon"], [1, "fas", "fa-flask"], [1, "test-info"], [1, "test-meta"], [1, "status-badge"], [1, "fas", 3, "ngClass"], [1, "test-type"], [1, "header-actions"], ["kendoButton", "", "icon", "play", 3, "click"], ["kendoButton", "", "icon", "sync", 3, "click"], ["class", "test-description", 4, "ngIf"], ["class", "metrics-bar", 4, "ngIf"], [1, "tabs-container"], [1, "tabs"], [1, "tab", 3, "click"], [1, "fas", "fa-th-large"], [1, "fas", "fa-sliders-h"], [1, "fas", "fa-list"], ["class", "tab-badge", 4, "ngIf"], [1, "fas", "fa-layer-group"], [1, "tab-content"], ["class", "overview-tab", 4, "ngIf"], ["class", "config-tab", 4, "ngIf"], ["class", "runs-tab", 4, "ngIf"], ["class", "suites-tab", 4, "ngIf"], [1, "test-description"], [1, "metrics-bar"], [1, "metric-card"], [1, "metric-label"], [1, "metric-value"], [1, "tab-badge"], [1, "overview-tab"], [1, "info-section"], [1, "info-grid"], [1, "info-item"], [1, "info-label"], [1, "info-value"], [1, "json-section"], [1, "json-tabs"], [1, "json-tab", 3, "click"], [1, "json-content"], [1, "config-tab"], [1, "config-section"], [1, "config-grid"], [1, "config-item"], ["type", "number", 1, "config-input", 3, "ngModelChange", "ngModel"], ["type", "number", "step", "0.000001", 1, "config-input", 3, "ngModelChange", "ngModel"], ["rows", "10", 1, "json-editor", 3, "ngModelChange", "ngModel"], ["rows", "5", 1, "json-editor", 3, "ngModelChange", "ngModel"], [1, "runs-tab"], ["class", "runs-list", 4, "ngIf"], ["class", "no-data", 4, "ngIf"], [1, "runs-list"], ["class", "run-item", 3, "click", 4, "ngFor", "ngForOf"], [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"], [4, "ngIf"], [1, "fas", "fa-chevron-right"], [1, "no-data"], [1, "fas", "fa-inbox"], [1, "suites-tab"], ["class", "suites-list", 4, "ngIf"], [1, "suites-list"], ["class", "suite-item", 3, "click", 4, "ngFor", "ngForOf"], [1, "suite-item", 3, "click"], [1, "suite-icon"], [1, "fas", "fa-folder"], [1, "suite-content"], [1, "suite-name"], [1, "suite-meta"]], template: function TestFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
1691
+ setHistoryTimeRange(range) {
1692
+ this.historyTimeRange = range;
1693
+ this.historyLoaded = false;
1694
+ this.loadHistory();
1695
+ }
1696
+ setTagFilter(tag) {
1697
+ this.selectedTagFilter = tag;
1698
+ this.cdr.markForCheck();
1699
+ }
1700
+ getFilteredHistoryData() {
1701
+ return this.historyData;
1702
+ }
1703
+ getOverallPassRate() {
1704
+ if (this.historyData.length === 0)
1705
+ return 0;
1706
+ const totalRuns = this.historyData.reduce((sum, d) => sum + d.runCount, 0);
1707
+ const totalPassed = this.historyData.reduce((sum, d) => sum + d.passCount, 0);
1708
+ return totalRuns > 0 ? (totalPassed / totalRuns) * 100 : 0;
1709
+ }
1710
+ getOverallAvgScore() {
1711
+ if (this.historyData.length === 0)
1712
+ return 0;
1713
+ const scores = this.historyData.filter(d => d.avgScore > 0).map(d => d.avgScore);
1714
+ return scores.length > 0 ? scores.reduce((a, b) => a + b, 0) / scores.length : 0;
1715
+ }
1716
+ getOverallAvgDuration() {
1717
+ if (this.historyData.length === 0)
1718
+ return 0;
1719
+ const durations = this.historyData.filter(d => d.avgDuration > 0).map(d => d.avgDuration);
1720
+ return durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0;
1721
+ }
1722
+ getOverallAvgCost() {
1723
+ if (this.historyData.length === 0)
1724
+ return 0;
1725
+ const costs = this.historyData.filter(d => d.avgCost > 0).map(d => d.avgCost);
1726
+ return costs.length > 0 ? costs.reduce((a, b) => a + b, 0) / costs.length : 0;
1727
+ }
1728
+ getTotalRuns() {
1729
+ return this.historyData.reduce((sum, d) => sum + d.runCount, 0);
1730
+ }
1731
+ getPassRateTrend() {
1732
+ if (this.historyData.length < 2)
1733
+ return 'stable';
1734
+ // Compare recent half to older half
1735
+ const mid = Math.floor(this.historyData.length / 2);
1736
+ const recentData = this.historyData.slice(0, mid);
1737
+ const olderData = this.historyData.slice(mid);
1738
+ const recentRate = recentData.reduce((sum, d) => sum + d.passRate, 0) / recentData.length;
1739
+ const olderRate = olderData.reduce((sum, d) => sum + d.passRate, 0) / olderData.length;
1740
+ const diff = recentRate - olderRate;
1741
+ if (diff > 5)
1742
+ return 'up';
1743
+ if (diff < -5)
1744
+ return 'down';
1745
+ return 'stable';
1746
+ }
1747
+ exportHistoryToCSV() {
1748
+ const headers = ['Date', 'Run Count', 'Passed', 'Failed', 'Pass Rate (%)', 'Avg Score', 'Avg Duration (s)', 'Avg Cost (USD)'];
1749
+ const rows = this.historyData.map(d => [
1750
+ d.date.toISOString().split('T')[0],
1751
+ d.runCount.toString(),
1752
+ d.passCount.toString(),
1753
+ d.failCount.toString(),
1754
+ d.passRate.toFixed(1),
1755
+ d.avgScore.toFixed(4),
1756
+ d.avgDuration.toFixed(2),
1757
+ d.avgCost.toFixed(6)
1758
+ ]);
1759
+ const csvContent = [headers, ...rows]
1760
+ .map(row => row.map(cell => `"${cell}"`).join(','))
1761
+ .join('\n');
1762
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
1763
+ const link = document.createElement('a');
1764
+ link.href = URL.createObjectURL(blob);
1765
+ link.download = `test-${this.record.ID.substring(0, 8)}-history.csv`;
1766
+ link.click();
1767
+ URL.revokeObjectURL(link.href);
1768
+ SharedService.Instance.CreateSimpleNotification('Export complete', 'success', 2000);
1769
+ }
1770
+ openSuiteFromHistory(suiteId) {
1771
+ SharedService.Instance.OpenEntityRecord('MJ: Test Suites', CompositeKey.FromID(suiteId));
1772
+ }
1773
+ // ===========================
1774
+ // Keyboard Shortcuts Settings
1775
+ // ===========================
1776
+ /**
1777
+ * Load keyboard shortcuts visibility setting from user settings
1778
+ */
1779
+ loadShortcutsSetting() {
1780
+ try {
1781
+ const engine = UserInfoEngine.Instance;
1782
+ const setting = engine.UserSettings.find(s => s.Setting === SHORTCUTS_SETTINGS_KEY);
1783
+ if (setting) {
1784
+ this.shortcutsSettingEntity = setting;
1785
+ this.showShortcuts = setting.Value === 'true';
1786
+ }
1787
+ else {
1788
+ // Default to hidden
1789
+ this.showShortcuts = false;
1790
+ }
1791
+ this.cdr.markForCheck();
1792
+ }
1793
+ catch (error) {
1794
+ console.warn('Failed to load shortcuts setting:', error);
1795
+ }
1796
+ }
1797
+ /**
1798
+ * Toggle keyboard shortcuts visibility and save preference
1799
+ */
1800
+ async toggleShortcuts() {
1801
+ this.showShortcuts = !this.showShortcuts;
1802
+ this.cdr.markForCheck();
1803
+ try {
1804
+ const userId = this.metadata.CurrentUser?.ID;
1805
+ if (!userId)
1806
+ return;
1807
+ if (!this.shortcutsSettingEntity) {
1808
+ const engine = UserInfoEngine.Instance;
1809
+ const setting = engine.UserSettings.find(s => s.Setting === SHORTCUTS_SETTINGS_KEY);
1810
+ if (setting) {
1811
+ this.shortcutsSettingEntity = setting;
1812
+ }
1813
+ else {
1814
+ this.shortcutsSettingEntity = await this.metadata.GetEntityObject('MJ: User Settings');
1815
+ this.shortcutsSettingEntity.UserID = userId;
1816
+ this.shortcutsSettingEntity.Setting = SHORTCUTS_SETTINGS_KEY;
1817
+ }
1818
+ }
1819
+ this.shortcutsSettingEntity.Value = this.showShortcuts ? 'true' : 'false';
1820
+ await this.shortcutsSettingEntity.Save();
1821
+ }
1822
+ catch (error) {
1823
+ console.warn('Failed to save shortcuts setting:', error);
1824
+ }
1825
+ }
1826
+ static { this.ɵfac = function TestFormComponentExtended_Factory(t) { return new (t || TestFormComponentExtended)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i1.SharedService), i0.ɵɵdirectiveInject(i2.Router), i0.ɵɵdirectiveInject(i2.ActivatedRoute), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i3.TestingDialogService), i0.ɵɵdirectiveInject(i3.EvaluationPreferencesService)); }; }
1827
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TestFormComponentExtended, selectors: [["mj-test-form"]], hostBindings: function TestFormComponentExtended_HostBindings(rf, ctx) { if (rf & 1) {
1828
+ i0.ɵɵlistener("keydown", function TestFormComponentExtended_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, false, i0.ɵɵresolveDocument);
1829
+ } }, features: [i0.ɵɵInheritDefinitionFeature], decls: 57, vars: 36, consts: [["kendoDialogContainer", "", 1, "test-form"], [1, "test-header"], [1, "header-content"], [1, "header-left"], [1, "test-icon"], [1, "fas", "fa-flask"], [1, "test-info"], [1, "test-meta"], [1, "status-badge", 3, "ngClass"], [1, "fas", 3, "ngClass"], ["class", "test-type", 4, "ngIf"], [1, "header-actions"], ["kendoButton", "", "themeColor", "primary", 3, "click"], [1, "fas", "fa-play"], ["kendoButton", "", 3, "click", "disabled"], ["class", "test-description", 4, "ngIf"], ["class", "metrics-bar", 4, "ngIf"], [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"], ["class", "tab-badge", 4, "ngIf"], [1, "fas", "fa-layer-group"], [1, "fas", "fa-chart-line"], [1, "tab-content"], ["class", "overview-tab", 4, "ngIf"], ["class", "config-tab", 4, "ngIf"], ["class", "runs-tab", 4, "ngIf"], ["class", "suites-tab", 4, "ngIf"], ["class", "history-tab", 4, "ngIf"], [1, "shortcuts-toggle", 3, "click", "title"], [1, "fas", "fa-keyboard"], ["class", "keyboard-shortcuts", 4, "ngIf"], [1, "test-type"], [1, "fas", "fa-tag"], [1, "test-description"], [1, "metrics-bar"], [1, "metric-card"], [1, "metric-label"], [1, "metric-value"], [1, "metric-progress"], [1, "metric-progress-fill"], [1, "tab-badge"], [1, "overview-tab"], [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, "config-tab"], [1, "config-section"], [1, "fas", "fa-cogs"], [1, "config-grid"], [1, "config-item"], ["type", "number", "placeholder", "Lower = Higher Priority", 1, "config-input", 3, "ngModelChange", "ngModel"], ["type", "number", "min", "1", 1, "config-input", 3, "ngModelChange", "ngModel"], ["type", "number", 1, "config-input", 3, "ngModelChange", "ngModel"], ["type", "number", "step", "0.000001", 1, "config-input", 3, "ngModelChange", "ngModel"], [1, "config-item", "full-width"], ["type", "number", "placeholder", "Default: 300000 (5 min)", 1, "config-input", 3, "ngModelChange", "ngModel"], [1, "config-hint"], [1, "config-editor-container"], ["language", "json", 3, "change", "value", "readonly", "lineWrapping"], [1, "config-editor-container", "small"], [1, "runs-tab"], ["class", "loading-state", 4, "ngIf"], ["class", "runs-list", 4, "ngIf"], ["class", "empty-state", 4, "ngIf"], [1, "loading-state"], [1, "skeleton-list"], ["class", "skeleton-card", 4, "ngFor", "ngForOf"], [1, "skeleton-card"], [1, "skeleton-icon"], [1, "skeleton-content"], [1, "skeleton-line", "wide"], [1, "skeleton-line", "narrow"], [1, "runs-list"], ["class", "run-item", 3, "click", 4, "ngFor", "ngForOf"], [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"], [4, "ngIf"], [3, "entityName", "recordId", 4, "ngIf"], [1, "run-eval-stack"], ["class", "eval-pill status-pill", 3, "ngClass", "title", 4, "ngIf"], ["class", "run-tags", 4, "ngIf"], [1, "fas", "fa-chevron-right"], [1, "fas", "fa-clock"], [1, "fas", "fa-dollar-sign"], [3, "entityName", "recordId"], [1, "eval-pill", "status-pill", 3, "ngClass", "title"], ["class", "eval-pill human-pill no-feedback", "title", "Human Review: No rating submitted yet", 4, "ngIf"], ["class", "eval-pill human-pill has-feedback", 3, "rating-low", "rating-medium", "rating-good", "rating-excellent", "title", 4, "ngIf"], ["title", "Human Review: No rating submitted yet", 1, "eval-pill", "human-pill", "no-feedback"], [1, "fas", "fa-user-slash"], [1, "eval-pill", "human-pill", "has-feedback", 3, "title"], [1, "fas", "fa-user"], ["class", "eval-pill auto-pill no-score", "title", "Auto Score: No automated score available", 4, "ngIf"], ["class", "eval-pill auto-pill has-score", 3, "score-low", "score-medium", "score-good", "score-excellent", "title", 4, "ngIf"], ["title", "Auto Score: No automated score available", 1, "eval-pill", "auto-pill", "no-score"], [1, "fas", "fa-robot"], [1, "eval-pill", "auto-pill", "has-score", 3, "title"], [1, "run-tags"], ["class", "run-tag", 4, "ngFor", "ngForOf"], ["class", "run-tag-more", 4, "ngIf"], [1, "run-tag"], [1, "run-tag-more"], [1, "empty-state"], [1, "empty-icon"], [1, "fas", "fa-play-circle"], [1, "suites-tab"], ["class", "suites-list", 4, "ngIf"], [1, "suites-list"], ["class", "suite-item", 3, "click", 4, "ngFor", "ngForOf"], [1, "suite-item", 3, "click"], [1, "suite-icon"], [1, "suite-content"], [1, "suite-name"], [1, "suite-meta"], [1, "fas", "fa-sort-numeric-up"], [1, "fas", "fa-folder-open"], [1, "history-tab"], ["class", "history-content", 4, "ngIf"], ["text", "Loading history..."], [1, "history-content"], [1, "history-filters"], [1, "time-range-filters"], [1, "filter-label"], [1, "filter-btn", 3, "click"], [1, "history-actions"], [1, "fas", "fa-download"], ["class", "history-kpi-cards", 4, "ngIf"], ["class", "history-section", 4, "ngIf"], [1, "history-kpi-cards"], [1, "kpi-card"], [1, "kpi-icon"], [1, "kpi-content"], [1, "kpi-value"], [1, "kpi-label"], ["class", "kpi-card", 4, "ngIf"], [1, "kpi-icon", "pass-rate"], [1, "fas", "fa-percentage"], [1, "fas", "trend-icon"], [1, "fas", "fa-star"], [1, "history-section"], [1, "fas", "fa-calendar-alt"], [1, "history-table-container"], [1, "history-table"], [4, "ngFor", "ngForOf"], [1, "date-cell"], [1, "runs-cell"], ["class", "passed-cell", 4, "ngIf"], ["class", "failed-cell", 4, "ngIf"], ["class", "pass-rate-cell", 4, "ngIf"], ["class", "score-cell", 4, "ngIf"], [1, "duration-cell"], [1, "cost-cell"], [1, "passed-cell"], [1, "failed-cell"], [1, "pass-rate-cell"], [1, "pass-rate-bar"], [1, "pass-rate-fill"], [1, "pass-rate-text"], [1, "score-cell"], [1, "suite-performance-list"], ["class", "suite-perf-card", 3, "click", 4, "ngFor", "ngForOf"], [1, "suite-perf-card", 3, "click"], [1, "suite-perf-header"], [1, "suite-perf-name"], ["class", "suite-perf-tags", 4, "ngIf"], [1, "suite-perf-stats"], [1, "suite-stat"], [1, "stat-value"], [1, "stat-label"], ["class", "suite-stat", 4, "ngIf"], [1, "fas", "fa-chevron-right", "suite-perf-arrow"], [1, "suite-perf-tags"], ["class", "tag-mini", 4, "ngFor", "ngForOf"], ["class", "tag-more", 4, "ngIf"], [1, "tag-mini"], [1, "tag-more"], [1, "stat-value", "pass-rate"], [1, "keyboard-shortcuts"], [1, "shortcuts-header"], ["title", "Hide shortcuts", 1, "shortcuts-close", 3, "click"], [1, "fas", "fa-times"], [1, "shortcut-list"], [1, "shortcut-item"], [1, "shortcut-keys"]], template: function TestFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
616
1830
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div", 3)(4, "div", 4);
617
1831
  i0.ɵɵelement(5, "i", 5);
618
1832
  i0.ɵɵelementEnd();
@@ -623,80 +1837,108 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
623
1837
  i0.ɵɵelement(11, "i", 9);
624
1838
  i0.ɵɵtext(12);
625
1839
  i0.ɵɵelementEnd();
626
- i0.ɵɵelementStart(13, "span", 10);
627
- i0.ɵɵtext(14);
628
- i0.ɵɵelementEnd()()()();
629
- i0.ɵɵelementStart(15, "div", 11)(16, "button", 12);
1840
+ i0.ɵɵtemplate(13, TestFormComponentExtended_span_13_Template, 3, 1, "span", 10);
1841
+ i0.ɵɵelementEnd()()();
1842
+ i0.ɵɵelementStart(14, "div", 11);
1843
+ i0.ɵɵelement(15, "app-evaluation-mode-toggle");
1844
+ i0.ɵɵelementStart(16, "button", 12);
630
1845
  i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_16_listener() { return ctx.runTest(); });
631
- i0.ɵɵtext(17, " Run Test ");
1846
+ i0.ɵɵelement(17, "i", 13);
1847
+ i0.ɵɵtext(18, " Run Test ");
632
1848
  i0.ɵɵelementEnd();
633
- i0.ɵɵelementStart(18, "button", 13);
634
- i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_18_listener() { return ctx.refresh(); });
635
- i0.ɵɵtext(19, " Refresh ");
1849
+ i0.ɵɵelementStart(19, "button", 14);
1850
+ i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_19_listener() { return ctx.refresh(); });
1851
+ i0.ɵɵelement(20, "i", 9);
1852
+ i0.ɵɵtext(21);
636
1853
  i0.ɵɵelementEnd()()();
637
- i0.ɵɵtemplate(20, TestFormComponentExtended_div_20_Template, 3, 1, "div", 14)(21, TestFormComponentExtended_div_21_Template, 21, 4, "div", 15);
1854
+ i0.ɵɵtemplate(22, TestFormComponentExtended_div_22_Template, 3, 1, "div", 15)(23, TestFormComponentExtended_div_23_Template, 23, 6, "div", 16);
638
1855
  i0.ɵɵelementEnd();
639
- i0.ɵɵelementStart(22, "div", 16)(23, "div", 17)(24, "button", 18);
640
- i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_24_listener() { return ctx.changeTab("overview"); });
641
- i0.ɵɵelement(25, "i", 19);
642
- i0.ɵɵelementStart(26, "span");
643
- i0.ɵɵtext(27, "Overview");
1856
+ i0.ɵɵelementStart(24, "div", 17)(25, "div", 18)(26, "button", 19);
1857
+ i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_26_listener() { return ctx.changeTab("overview"); });
1858
+ i0.ɵɵelement(27, "i", 20);
1859
+ i0.ɵɵelementStart(28, "span");
1860
+ i0.ɵɵtext(29, "Overview");
644
1861
  i0.ɵɵelementEnd()();
645
- i0.ɵɵelementStart(28, "button", 18);
646
- i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_28_listener() { return ctx.changeTab("config"); });
647
- i0.ɵɵelement(29, "i", 20);
648
- i0.ɵɵelementStart(30, "span");
649
- i0.ɵɵtext(31, "Configuration");
1862
+ i0.ɵɵelementStart(30, "button", 19);
1863
+ i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_30_listener() { return ctx.changeTab("config"); });
1864
+ i0.ɵɵelement(31, "i", 21);
1865
+ i0.ɵɵelementStart(32, "span");
1866
+ i0.ɵɵtext(33, "Configuration");
650
1867
  i0.ɵɵelementEnd()();
651
- i0.ɵɵelementStart(32, "button", 18);
652
- i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_32_listener() { return ctx.changeTab("runs"); });
653
- i0.ɵɵelement(33, "i", 21);
654
- i0.ɵɵelementStart(34, "span");
655
- i0.ɵɵtext(35, "Test Runs");
1868
+ i0.ɵɵelementStart(34, "button", 19);
1869
+ i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_34_listener() { return ctx.changeTab("runs"); });
1870
+ i0.ɵɵelement(35, "i", 22);
1871
+ i0.ɵɵelementStart(36, "span");
1872
+ i0.ɵɵtext(37, "Runs");
656
1873
  i0.ɵɵelementEnd();
657
- i0.ɵɵtemplate(36, TestFormComponentExtended_span_36_Template, 2, 1, "span", 22);
1874
+ i0.ɵɵtemplate(38, TestFormComponentExtended_span_38_Template, 2, 1, "span", 23);
658
1875
  i0.ɵɵelementEnd();
659
- i0.ɵɵelementStart(37, "button", 18);
660
- i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_37_listener() { return ctx.changeTab("suites"); });
661
- i0.ɵɵelement(38, "i", 23);
662
- i0.ɵɵelementStart(39, "span");
663
- i0.ɵɵtext(40, "Test Suites");
1876
+ i0.ɵɵelementStart(39, "button", 19);
1877
+ i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_39_listener() { return ctx.changeTab("suites"); });
1878
+ i0.ɵɵelement(40, "i", 24);
1879
+ i0.ɵɵelementStart(41, "span");
1880
+ i0.ɵɵtext(42, "Test Suites");
1881
+ i0.ɵɵelementEnd();
1882
+ i0.ɵɵtemplate(43, TestFormComponentExtended_span_43_Template, 2, 1, "span", 23);
1883
+ i0.ɵɵelementEnd();
1884
+ i0.ɵɵelementStart(44, "button", 19);
1885
+ i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_44_listener() { return ctx.changeTab("analytics"); });
1886
+ i0.ɵɵelement(45, "i", 25);
1887
+ i0.ɵɵelementStart(46, "span");
1888
+ i0.ɵɵtext(47, "Analytics");
1889
+ i0.ɵɵelementEnd()()()();
1890
+ i0.ɵɵelementStart(48, "div", 26);
1891
+ i0.ɵɵtemplate(49, TestFormComponentExtended_div_49_Template, 78, 29, "div", 27)(50, TestFormComponentExtended_div_50_Template, 52, 17, "div", 28)(51, TestFormComponentExtended_div_51_Template, 4, 3, "div", 29)(52, TestFormComponentExtended_div_52_Template, 4, 3, "div", 30)(53, TestFormComponentExtended_div_53_Template, 3, 2, "div", 31);
1892
+ i0.ɵɵelementEnd();
1893
+ i0.ɵɵelementStart(54, "button", 32);
1894
+ i0.ɵɵlistener("click", function TestFormComponentExtended_Template_button_click_54_listener() { return ctx.toggleShortcuts(); });
1895
+ i0.ɵɵelement(55, "i", 33);
1896
+ i0.ɵɵelementEnd();
1897
+ i0.ɵɵtemplate(56, TestFormComponentExtended_div_56_Template, 32, 0, "div", 34);
664
1898
  i0.ɵɵelementEnd();
665
- i0.ɵɵtemplate(41, TestFormComponentExtended_span_41_Template, 2, 1, "span", 22);
666
- i0.ɵɵelementEnd()()();
667
- i0.ɵɵelementStart(42, "div", 24);
668
- i0.ɵɵtemplate(43, TestFormComponentExtended_div_43_Template, 62, 22, "div", 25)(44, TestFormComponentExtended_div_44_Template, 37, 8, "div", 26)(45, TestFormComponentExtended_div_45_Template, 3, 2, "div", 27)(46, TestFormComponentExtended_div_46_Template, 3, 2, "div", 28);
669
- i0.ɵɵelementEnd()();
670
1899
  } if (rf & 2) {
671
1900
  i0.ɵɵadvance(4);
672
1901
  i0.ɵɵstyleProp("background-color", ctx.getStatusColor());
673
1902
  i0.ɵɵadvance(4);
674
1903
  i0.ɵɵtextInterpolate(ctx.record.Name);
675
1904
  i0.ɵɵadvance(2);
676
- i0.ɵɵstyleProp("background-color", ctx.getStatusColor());
1905
+ i0.ɵɵproperty("ngClass", ctx.getStatusClass());
677
1906
  i0.ɵɵadvance();
678
1907
  i0.ɵɵproperty("ngClass", ctx.getStatusIcon());
679
1908
  i0.ɵɵadvance();
680
1909
  i0.ɵɵtextInterpolate1(" ", ctx.record.Status, " ");
681
- i0.ɵɵadvance(2);
682
- i0.ɵɵtextInterpolate(ctx.record.Type);
1910
+ i0.ɵɵadvance();
1911
+ i0.ɵɵproperty("ngIf", ctx.record.Type);
683
1912
  i0.ɵɵadvance(6);
1913
+ i0.ɵɵproperty("disabled", ctx.isRefreshing);
1914
+ i0.ɵɵadvance();
1915
+ i0.ɵɵproperty("ngClass", ctx.isRefreshing ? "fa-sync fa-spin" : "fa-sync");
1916
+ i0.ɵɵadvance();
1917
+ i0.ɵɵtextInterpolate1(" ", ctx.isRefreshing ? "Refreshing..." : "Refresh", " ");
1918
+ i0.ɵɵadvance();
684
1919
  i0.ɵɵproperty("ngIf", ctx.record.Description);
685
1920
  i0.ɵɵadvance();
686
1921
  i0.ɵɵproperty("ngIf", ctx.testRunsLoaded && ctx.testRuns.length > 0);
687
1922
  i0.ɵɵadvance(3);
688
1923
  i0.ɵɵclassProp("active", ctx.activeTab === "overview");
1924
+ i0.ɵɵattribute("aria-selected", ctx.activeTab === "overview");
689
1925
  i0.ɵɵadvance(4);
690
1926
  i0.ɵɵclassProp("active", ctx.activeTab === "config");
1927
+ i0.ɵɵattribute("aria-selected", ctx.activeTab === "config");
691
1928
  i0.ɵɵadvance(4);
692
1929
  i0.ɵɵclassProp("active", ctx.activeTab === "runs");
1930
+ i0.ɵɵattribute("aria-selected", ctx.activeTab === "runs");
693
1931
  i0.ɵɵadvance(4);
694
1932
  i0.ɵɵproperty("ngIf", ctx.testRunsLoaded);
695
1933
  i0.ɵɵadvance();
696
1934
  i0.ɵɵclassProp("active", ctx.activeTab === "suites");
1935
+ i0.ɵɵattribute("aria-selected", ctx.activeTab === "suites");
697
1936
  i0.ɵɵadvance(4);
698
1937
  i0.ɵɵproperty("ngIf", ctx.suiteTestsLoaded);
699
- i0.ɵɵadvance(2);
1938
+ i0.ɵɵadvance();
1939
+ i0.ɵɵclassProp("active", ctx.activeTab === "analytics");
1940
+ i0.ɵɵattribute("aria-selected", ctx.activeTab === "analytics");
1941
+ i0.ɵɵadvance(5);
700
1942
  i0.ɵɵproperty("ngIf", ctx.activeTab === "overview");
701
1943
  i0.ɵɵadvance();
702
1944
  i0.ɵɵproperty("ngIf", ctx.activeTab === "config");
@@ -704,7 +1946,13 @@ let TestFormComponentExtended = class TestFormComponentExtended extends TestForm
704
1946
  i0.ɵɵproperty("ngIf", ctx.activeTab === "runs");
705
1947
  i0.ɵɵadvance();
706
1948
  i0.ɵɵproperty("ngIf", ctx.activeTab === "suites");
707
- } }, dependencies: [i4.NgClass, i4.NgForOf, i4.NgIf, i5.DefaultValueAccessor, i5.NumberValueAccessor, i5.NgControlStatus, i5.NgModel, i6.DialogContainerDirective, i7.ButtonComponent, i4.JsonPipe, i4.DatePipe], styles: [".test-form[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8f9fa;\n}\n\n\n\n.test-header[_ngcontent-%COMP%] {\n background: white;\n border-bottom: 1px solid #e0e0e0;\n padding: 20px;\n}\n\n.header-content[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 16px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.test-icon[_ngcontent-%COMP%] {\n width: 56px;\n height: 56px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 24px;\n}\n\n.test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 24px;\n font-weight: 600;\n color: #333;\n}\n\n.test-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 12px;\n color: white;\n font-size: 12px;\n font-weight: 600;\n}\n\n.test-type[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #666;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.test-description[_ngcontent-%COMP%] {\n padding: 16px;\n background: #f8f9fa;\n border-radius: 8px;\n margin-bottom: 16px;\n}\n\n.test-description[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n color: #666;\n line-height: 1.5;\n}\n\n.metrics-bar[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n}\n\n.metric-card[_ngcontent-%COMP%] {\n background: #f5f7fa;\n border-radius: 8px;\n padding: 12px;\n text-align: center;\n}\n\n.metric-label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #999;\n margin-bottom: 4px;\n}\n\n.metric-value[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 600;\n color: #333;\n}\n\n\n\n.tabs-container[_ngcontent-%COMP%] {\n background: white;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.tabs[_ngcontent-%COMP%] {\n display: flex;\n padding: 0 20px;\n overflow-x: auto;\n}\n\n.tab[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px 20px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: #666;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.tab[_ngcontent-%COMP%]:hover {\n color: #2196f3;\n background: rgba(33, 150, 243, 0.05);\n}\n\n.tab.active[_ngcontent-%COMP%] {\n color: #2196f3;\n border-bottom-color: #2196f3;\n}\n\n.tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.tab-badge[_ngcontent-%COMP%] {\n background: #e0e0e0;\n color: #666;\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.tab.active[_ngcontent-%COMP%] .tab-badge[_ngcontent-%COMP%] {\n background: #e3f2fd;\n color: #2196f3;\n}\n\n\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n\n\n.overview-tab[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.info-section[_ngcontent-%COMP%], \n.json-section[_ngcontent-%COMP%], \n.config-section[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n padding: 20px;\n}\n\n.info-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%], \n.json-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%], \n.config-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 18px;\n font-weight: 600;\n color: #333;\n}\n\n.info-grid[_ngcontent-%COMP%], \n.config-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px;\n}\n\n.info-item[_ngcontent-%COMP%], \n.config-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.info-label[_ngcontent-%COMP%], \n.config-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #999;\n}\n\n.info-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #333;\n word-wrap: break-word;\n}\n\n.config-input[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n}\n\n.config-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.json-tabs[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n border-bottom: 2px solid #e0e0e0;\n}\n\n.json-tab[_ngcontent-%COMP%] {\n padding: 10px 20px;\n border: none;\n background: transparent;\n color: #666;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n border-bottom: 3px solid transparent;\n margin-bottom: -2px;\n transition: all 0.2s ease;\n}\n\n.json-tab[_ngcontent-%COMP%]:hover {\n color: #2196f3;\n}\n\n.json-tab.active[_ngcontent-%COMP%] {\n color: #2196f3;\n border-bottom-color: #2196f3;\n}\n\n.json-content[_ngcontent-%COMP%] {\n background: #1e1e1e;\n border-radius: 8px;\n padding: 16px;\n max-height: 400px;\n overflow-y: auto;\n}\n\n.json-content[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] {\n margin: 0;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n line-height: 1.5;\n color: #e0e0e0;\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n\n.json-editor[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n resize: vertical;\n}\n\n.json-editor[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n\n\n.runs-list[_ngcontent-%COMP%], \n.suites-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.run-item[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n background: white;\n border: 2px solid transparent;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.run-item[_ngcontent-%COMP%]:hover, \n.suite-item[_ngcontent-%COMP%]:hover {\n background: #e3f2fd;\n border-color: #90caf9;\n}\n\n.run-icon[_ngcontent-%COMP%], \n.suite-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n color: white;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.suite-icon[_ngcontent-%COMP%] {\n background: #ff9800;\n}\n\n.run-content[_ngcontent-%COMP%], \n.suite-content[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.run-header[_ngcontent-%COMP%], \n.suite-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: #333;\n margin-bottom: 4px;\n}\n\n.run-id[_ngcontent-%COMP%] {\n margin-right: 12px;\n}\n\n.run-status[_ngcontent-%COMP%] {\n font-weight: 700;\n}\n\n.run-meta[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n font-size: 12px;\n color: #666;\n}\n\n.run-item[_ngcontent-%COMP%] > i[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n color: #999;\n font-size: 14px;\n}\n\n\n\n.no-data[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: #999;\n text-align: center;\n background: white;\n border-radius: 12px;\n}\n\n.no-data[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.no-data[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\n@media (max-width: 1200px) {\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid[_ngcontent-%COMP%], \n .config-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 768px) {\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .header-content[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n\n .tabs[_ngcontent-%COMP%] {\n overflow-x: auto;\n }\n}"], changeDetection: 0 }); }
1949
+ i0.ɵɵadvance();
1950
+ i0.ɵɵproperty("ngIf", ctx.activeTab === "analytics");
1951
+ i0.ɵɵadvance();
1952
+ i0.ɵɵproperty("title", ctx.showShortcuts ? "Hide keyboard shortcuts" : "Show keyboard shortcuts");
1953
+ i0.ɵɵadvance(2);
1954
+ i0.ɵɵproperty("ngIf", ctx.showShortcuts);
1955
+ } }, dependencies: [i4.NgClass, i4.NgForOf, i4.NgIf, i5.DefaultValueAccessor, i5.NumberValueAccessor, i5.NgControlStatus, i5.MinValidator, i5.NgModel, i6.DialogContainerDirective, i7.ButtonComponent, i8.CodeEditorComponent, i3.EvaluationModeToggleComponent, i9.LoadingComponent, i10.EntityLinkPillComponent, i4.DatePipe], styles: ["\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n --test-primary: #2563eb;\n --test-primary-light: #3b82f6;\n --test-primary-dark: #1d4ed8;\n --test-success: #10b981;\n --test-success-light: #d1fae5;\n --test-error: #ef4444;\n --test-error-light: #fee2e2;\n --test-warning: #f59e0b;\n --test-warning-light: #fef3c7;\n --test-disabled: #6b7280;\n --test-bg: #f8fafc;\n --test-surface: #ffffff;\n --test-border: #e2e8f0;\n --test-text: #1e293b;\n --test-text-secondary: #64748b;\n --test-text-muted: #94a3b8;\n --test-radius-sm: 6px;\n --test-radius-md: 10px;\n --test-radius-lg: 16px;\n --test-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);\n --test-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n --test-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n --test-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: block;\n height: 100%;\n}\n\n\n\n.test-form[_ngcontent-%COMP%] {\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\n\n\n.test-header[_ngcontent-%COMP%] {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n padding: 20px;\n}\n\n.header-content[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n\n\n.test-icon[_ngcontent-%COMP%] {\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: white;\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[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n\n.test-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border-radius: 20px;\n color: white;\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[_ngcontent-%COMP%] { background: linear-gradient(135deg, var(--test-success) 0%, #059669 100%); }\n.status-badge.status-disabled[_ngcontent-%COMP%] { background: linear-gradient(135deg, var(--test-disabled) 0%, #4b5563 100%); }\n.status-badge.status-pending[_ngcontent-%COMP%] { background: linear-gradient(135deg, var(--test-warning) 0%, #d97706 100%); }\n\n.status-badge-inline[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border-radius: 10px;\n color: white;\n font-size: 11px;\n font-weight: 600;\n}\n\n.status-badge-inline.status-active[_ngcontent-%COMP%] { background: var(--test-success); }\n.status-badge-inline.status-disabled[_ngcontent-%COMP%] { background: var(--test-disabled); }\n.status-badge-inline.status-pending[_ngcontent-%COMP%] { background: var(--test-warning); }\n\n.test-type[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.header-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n white-space: nowrap;\n}\n\n\n\n.test-description[_ngcontent-%COMP%] {\n padding: 16px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-radius: var(--test-radius-md);\n margin-bottom: 16px;\n border: 1px solid var(--test-border);\n}\n\n.test-description[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--test-text-secondary);\n line-height: 1.6;\n font-size: 14px;\n}\n\n\n\n\n\n.metrics-bar[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 12px;\n}\n\n.metric-card[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\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[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.metric-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n\n\n.metric-progress[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n height: 100%;\n background: linear-gradient(90deg, var(--test-success) 0%, #34d399 100%);\n border-radius: 2px;\n transition: width 0.5s ease-out;\n}\n\n\n\n\n\n.tabs-container[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]::-webkit-scrollbar {\n display: none;\n}\n\n.tab[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-primary);\n background: rgba(37, 99, 235, 0.05);\n}\n\n.tab.active[_ngcontent-%COMP%] {\n color: var(--test-primary);\n border-bottom-color: var(--test-primary);\n font-weight: 600;\n}\n\n.tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 15px;\n}\n\n.tab-badge[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .tab-badge[_ngcontent-%COMP%] {\n background: rgba(37, 99, 235, 0.15);\n color: var(--test-primary);\n}\n\n.tab-shortcut[_ngcontent-%COMP%] {\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\n\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n\n\n\n\n.overview-tab[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n.info-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.info-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n}\n\n.info-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.info-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--test-text);\n word-wrap: break-word;\n font-weight: 500;\n}\n\n\n\n.json-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.json-tabs[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-text);\n background: rgba(0, 0, 0, 0.05);\n}\n\n.json-tab.active[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.code-editor-container[_ngcontent-%COMP%] {\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\n\n\n.config-tab[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n.config-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.config-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 20px;\n}\n\n.config-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.config-item.full-width[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.config-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);\n}\n\n.config-input[_ngcontent-%COMP%]::placeholder {\n color: var(--test-text-muted);\n}\n\n.config-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--test-text-muted);\n margin-top: 4px;\n}\n\n.config-editor-container[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n min-height: 100px;\n max-height: 150px;\n}\n\n\n\n\n\n.runs-tab[_ngcontent-%COMP%], \n.suites-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n\n\n.loading-state[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n.skeleton-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.skeleton-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n border-radius: var(--test-radius-md);\n background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%);\n background-size: 200% 100%;\n animation: _ngcontent-%COMP%_shimmer 1.5s infinite;\n flex-shrink: 0;\n}\n\n.skeleton-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.skeleton-line[_ngcontent-%COMP%] {\n height: 14px;\n border-radius: 4px;\n background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%);\n background-size: 200% 100%;\n animation: _ngcontent-%COMP%_shimmer 1.5s infinite;\n}\n\n.skeleton-line.wide[_ngcontent-%COMP%] { width: 70%; }\n.skeleton-line.narrow[_ngcontent-%COMP%] { width: 40%; }\n\n@keyframes _ngcontent-%COMP%_shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n\n\n.runs-list[_ngcontent-%COMP%], \n.suites-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.run-item[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover, \n.suite-item[_ngcontent-%COMP%]:hover {\n background: rgba(37, 99, 235, 0.05);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n box-shadow: var(--test-shadow-sm);\n}\n\n.run-icon[_ngcontent-%COMP%], \n.suite-icon[_ngcontent-%COMP%] {\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: white;\n font-size: 18px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-sm);\n}\n\n.suite-icon[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\n}\n\n.run-content[_ngcontent-%COMP%], \n.suite-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.run-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-id[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.run-status[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.suite-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 4px;\n}\n\n.run-meta[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] span[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 11px;\n}\n\n.run-item[_ngcontent-%COMP%] > i.fa-chevron-right[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%] > i.fa-chevron-right[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.run-item[_ngcontent-%COMP%]:hover > i.fa-chevron-right[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%]:hover > i.fa-chevron-right[_ngcontent-%COMP%] {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n\n\n.run-eval-stack[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n\n\n.eval-pill[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n\n.eval-pill.status-pill.status-passed[_ngcontent-%COMP%] {\n background: #dcfce7;\n color: #16a34a;\n}\n\n.eval-pill.status-pill.status-failed[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #dc2626;\n}\n\n.eval-pill.status-pill.status-error[_ngcontent-%COMP%] {\n background: #fef3c7;\n color: #d97706;\n}\n\n.eval-pill.status-pill.status-timeout[_ngcontent-%COMP%] {\n background: #fef3c7;\n color: #d97706;\n}\n\n.eval-pill.status-pill.status-skipped[_ngcontent-%COMP%], \n.eval-pill.status-pill.status-pending[_ngcontent-%COMP%] {\n background: #f1f5f9;\n color: #64748b;\n}\n\n.eval-pill.status-pill.status-running[_ngcontent-%COMP%] {\n background: #dbeafe;\n color: #2563eb;\n}\n\n\n\n.eval-pill.human-pill.no-feedback[_ngcontent-%COMP%] {\n background: #f1f5f9;\n color: #94a3b8;\n padding: 4px 8px;\n}\n\n.eval-pill.human-pill.has-feedback.rating-low[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #dc2626;\n}\n\n.eval-pill.human-pill.has-feedback.rating-medium[_ngcontent-%COMP%] {\n background: #fef3c7;\n color: #d97706;\n}\n\n.eval-pill.human-pill.has-feedback.rating-good[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #059669;\n}\n\n.eval-pill.human-pill.has-feedback.rating-excellent[_ngcontent-%COMP%] {\n background: #dcfce7;\n color: #16a34a;\n}\n\n\n\n.eval-pill.auto-pill.no-score[_ngcontent-%COMP%] {\n background: #f1f5f9;\n color: #94a3b8;\n padding: 4px 8px;\n}\n\n.eval-pill.auto-pill.has-score.score-low[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #dc2626;\n}\n\n.eval-pill.auto-pill.has-score.score-medium[_ngcontent-%COMP%] {\n background: #fef3c7;\n color: #d97706;\n}\n\n.eval-pill.auto-pill.has-score.score-good[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #059669;\n}\n\n.eval-pill.auto-pill.has-score.score-excellent[_ngcontent-%COMP%] {\n background: #dcfce7;\n color: #16a34a;\n}\n\n\n\n.run-tags[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n.run-tag[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: rgba(37, 99, 235, 0.1);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n.run-tag-more[_ngcontent-%COMP%] {\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\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--test-bg);\n border-radius: 50%;\n margin-bottom: 20px;\n}\n\n.empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 36px;\n color: var(--test-text-muted);\n}\n\n.empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 20px 0;\n font-size: 14px;\n color: var(--test-text-secondary);\n max-width: 300px;\n}\n\n\n\n.no-data[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--test-text-muted);\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.no-data[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.no-data[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\n\n\n\n\n.shortcuts-toggle[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-text);\n background: var(--test-border);\n}\n\n.shortcut-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.shortcut-item[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.shortcut-keys[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.shortcut-keys[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\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\n\n\n@media (max-width: 1024px) {\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .config-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .keyboard-shortcuts[_ngcontent-%COMP%], .shortcuts-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n@media (max-width: 768px) {\n .test-form[_ngcontent-%COMP%] {\n height: auto;\n min-height: 100%;\n }\n\n .test-header[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .header-content[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-left[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .test-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .test-meta[_ngcontent-%COMP%] {\n gap: 8px;\n }\n\n .status-badge[_ngcontent-%COMP%] {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .header-actions[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: stretch;\n }\n\n .header-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 10px;\n }\n\n .metric-card[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .metric-value[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .tabs[_ngcontent-%COMP%] {\n padding: 0 12px;\n }\n\n .tab[_ngcontent-%COMP%] {\n padding: 12px 14px;\n font-size: 13px;\n gap: 6px;\n }\n\n .tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n\n .tab-shortcut[_ngcontent-%COMP%] {\n display: none;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .info-section[_ngcontent-%COMP%], \n .json-section[_ngcontent-%COMP%], \n .config-section[_ngcontent-%COMP%] {\n padding: 18px;\n }\n\n .info-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .json-tabs[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .json-tab[_ngcontent-%COMP%] {\n min-width: 0;\n justify-content: flex-start;\n }\n\n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n padding: 14px;\n }\n\n .run-icon[_ngcontent-%COMP%], \n .suite-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .run-meta[_ngcontent-%COMP%], \n .suite-meta[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 4px;\n }\n\n .empty-state[_ngcontent-%COMP%] {\n padding: 40px 20px;\n }\n\n .empty-icon[_ngcontent-%COMP%] {\n width: 64px;\n height: 64px;\n }\n\n .empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n }\n}\n\n\n\n\n\n@media (max-width: 480px) {\n .test-header[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .header-left[_ngcontent-%COMP%] {\n gap: 12px;\n }\n\n .test-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 18px;\n border-radius: 8px;\n }\n\n .test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 1fr;\n }\n\n .tabs[_ngcontent-%COMP%] {\n padding: 0 8px;\n }\n\n .tab[_ngcontent-%COMP%] {\n padding: 10px 12px;\n font-size: 12px;\n }\n\n .tab-badge[_ngcontent-%COMP%] {\n display: none;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .run-header[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n}\n\n\n\n\n\n@media (hover: none) and (pointer: coarse) {\n .tab[_ngcontent-%COMP%], \n .json-tab[_ngcontent-%COMP%], \n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n -webkit-tap-highlight-color: transparent;\n }\n\n .run-item[_ngcontent-%COMP%]:active, \n .suite-item[_ngcontent-%COMP%]:active {\n background: rgba(37, 99, 235, 0.1);\n transform: scale(0.98);\n }\n\n .tab[_ngcontent-%COMP%]:active, \n .json-tab[_ngcontent-%COMP%]:active {\n background: rgba(37, 99, 235, 0.1);\n }\n\n \n\n .tab[_ngcontent-%COMP%] {\n min-height: 48px;\n }\n\n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n min-height: 64px;\n }\n}\n\n\n\n\n\n@media (prefers-reduced-motion: reduce) {\n *[_ngcontent-%COMP%], \n *[_ngcontent-%COMP%]::before, \n *[_ngcontent-%COMP%]::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n .skeleton-icon[_ngcontent-%COMP%], \n .skeleton-line[_ngcontent-%COMP%] {\n animation: none;\n background: #e2e8f0;\n }\n}\n\n\n\n\n\n.history-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n.history-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n\n\n.history-filters[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--test-text-secondary);\n margin-right: 4px;\n}\n\n.filter-btn[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n border-color: var(--test-primary-light);\n color: var(--test-primary);\n background: rgba(37, 99, 235, 0.05);\n}\n\n.filter-btn.active[_ngcontent-%COMP%] {\n background: var(--test-primary);\n color: white;\n border-color: var(--test-primary);\n}\n\n.history-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n\n\n.history-kpi-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 16px;\n}\n\n.kpi-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.kpi-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, var(--test-primary) 0%, var(--test-primary-dark) 100%);\n border-radius: var(--test-radius-md);\n color: white;\n font-size: 20px;\n flex-shrink: 0;\n}\n\n.kpi-icon.pass-rate[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--test-success) 0%, #059669 100%);\n}\n\n.kpi-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.trend-icon.trend-up[_ngcontent-%COMP%] {\n color: var(--test-success);\n}\n\n.trend-icon.trend-down[_ngcontent-%COMP%] {\n color: var(--test-error);\n}\n\n\n\n.history-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n\n\n.history-table-container[_ngcontent-%COMP%] {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.history-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: 14px;\n}\n\n.history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%], \n.history-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 12px 16px;\n text-align: left;\n border-bottom: 1px solid var(--test-border);\n}\n\n.history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background: rgba(37, 99, 235, 0.03);\n}\n\n.date-cell[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--test-text);\n}\n\n.passed-cell[_ngcontent-%COMP%] {\n color: var(--test-success);\n font-weight: 600;\n}\n\n.failed-cell[_ngcontent-%COMP%] {\n color: var(--test-error);\n font-weight: 600;\n}\n\n.pass-rate-cell[_ngcontent-%COMP%] {\n min-width: 120px;\n}\n\n.pass-rate-bar[_ngcontent-%COMP%] {\n position: relative;\n height: 24px;\n background: var(--test-bg);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.pass-rate-fill[_ngcontent-%COMP%] {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n background: linear-gradient(90deg, var(--test-success) 0%, #34d399 100%);\n border-radius: 12px;\n transition: width 0.5s ease-out;\n}\n\n.pass-rate-text[_ngcontent-%COMP%] {\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\n\n.suite-performance-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.suite-perf-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n background: rgba(37, 99, 235, 0.05);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n}\n\n.suite-perf-header[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.suite-perf-name[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 6px;\n}\n\n.suite-perf-tags[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.tag-mini[_ngcontent-%COMP%] {\n display: inline-flex;\n padding: 2px 8px;\n background: rgba(37, 99, 235, 0.1);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.tag-more[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.suite-stat[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value.pass-rate.high[_ngcontent-%COMP%] {\n color: var(--test-success);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value.pass-rate.low[_ngcontent-%COMP%] {\n color: var(--test-error);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.suite-perf-card[_ngcontent-%COMP%]:hover .suite-perf-arrow[_ngcontent-%COMP%] {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n\n\n\n\n@media print {\n .test-form[_ngcontent-%COMP%] {\n background: white;\n height: auto;\n }\n\n .header-actions[_ngcontent-%COMP%], \n .tabs-container[_ngcontent-%COMP%], \n .keyboard-shortcuts[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n overflow: visible;\n padding: 0;\n }\n\n .info-section[_ngcontent-%COMP%], \n .json-section[_ngcontent-%COMP%], \n .config-section[_ngcontent-%COMP%], \n .empty-state[_ngcontent-%COMP%] {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid #ddd;\n }\n}"], changeDetection: 0 }); }
708
1956
  };
709
1957
  TestFormComponentExtended = __decorate([
710
1958
  RegisterClass(BaseFormComponent, 'MJ: Tests')
@@ -712,9 +1960,12 @@ TestFormComponentExtended = __decorate([
712
1960
  export { TestFormComponentExtended };
713
1961
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TestFormComponentExtended, [{
714
1962
  type: Component,
715
- args: [{ selector: 'mj-test-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-form\" kendoDialogContainer>\n <!-- Header Section -->\n <div class=\"test-header\">\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>{{ record.Name }}</h1>\n <div class=\"test-meta\">\n <span class=\"status-badge\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n {{ record.Status }}\n </span>\n <span class=\"test-type\">{{ record.Type }}</span>\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <button kendoButton (click)=\"runTest()\" icon=\"play\">\n Run Test\n </button>\n <button kendoButton (click)=\"refresh()\" icon=\"sync\">\n Refresh\n </button>\n </div>\n </div>\n\n <!-- Test Description -->\n <div class=\"test-description\" *ngIf=\"record.Description\">\n <p>{{ record.Description }}</p>\n </div>\n\n <!-- Metrics Bar -->\n <div class=\"metrics-bar\" *ngIf=\"testRunsLoaded && testRuns.length > 0\">\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>\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 </div>\n\n <!-- Tabs -->\n <div class=\"tabs-container\">\n <div class=\"tabs\">\n <button class=\"tab\" [class.active]=\"activeTab === 'overview'\" (click)=\"changeTab('overview')\">\n <i class=\"fas fa-th-large\"></i>\n <span>Overview</span>\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'config'\" (click)=\"changeTab('config')\">\n <i class=\"fas fa-sliders-h\"></i>\n <span>Configuration</span>\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'runs'\" (click)=\"changeTab('runs')\">\n <i class=\"fas fa-list\"></i>\n <span>Test Runs</span>\n <span class=\"tab-badge\" *ngIf=\"testRunsLoaded\">{{ testRuns.length }}</span>\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'suites'\" (click)=\"changeTab('suites')\">\n <i class=\"fas fa-layer-group\"></i>\n <span>Test Suites</span>\n <span class=\"tab-badge\" *ngIf=\"suiteTestsLoaded\">{{ suiteTests.length }}</span>\n </button>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\">\n <!-- Overview Tab -->\n <div class=\"overview-tab\" *ngIf=\"activeTab === 'overview'\">\n <!-- Basic Information -->\n <div class=\"info-section\">\n <h3>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 }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Status</div>\n <div class=\"info-value\">{{ record.Status }}</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\">Created</div>\n <div class=\"info-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n </div>\n </div>\n\n <!-- JSON Data Views -->\n <div class=\"json-section\">\n <h3>Test Definition</h3>\n <div class=\"json-tabs\">\n <button class=\"json-tab\" [class.active]=\"activeJsonView === 'input'\" (click)=\"setJsonView('input')\">\n Input Definition\n </button>\n <button class=\"json-tab\" [class.active]=\"activeJsonView === 'expected'\" (click)=\"setJsonView('expected')\">\n Expected Outcomes\n </button>\n <button class=\"json-tab\" [class.active]=\"activeJsonView === 'config'\" (click)=\"setJsonView('config')\">\n Configuration\n </button>\n <button class=\"json-tab\" [class.active]=\"activeJsonView === 'tags'\" (click)=\"setJsonView('tags')\">\n Tags\n </button>\n </div>\n <div class=\"json-content\">\n <pre>{{ getJsonData() | json }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Configuration Tab -->\n <div class=\"config-tab\" *ngIf=\"activeTab === 'config'\">\n <div class=\"config-section\">\n <h3>Execution Settings</h3>\n <div class=\"config-grid\">\n <div class=\"config-item\">\n <label>Priority</label>\n <input type=\"number\" [(ngModel)]=\"record.Priority\" class=\"config-input\" />\n </div>\n <div class=\"config-item\">\n <label>Repeat Count</label>\n <input type=\"number\" [(ngModel)]=\"record.RepeatCount\" class=\"config-input\" />\n </div>\n <div class=\"config-item\">\n <label>Estimated Duration (seconds)</label>\n <input type=\"number\" [(ngModel)]=\"record.EstimatedDurationSeconds\" class=\"config-input\" />\n </div>\n <div class=\"config-item\">\n <label>Estimated Cost (USD)</label>\n <input type=\"number\" step=\"0.000001\" [(ngModel)]=\"record.EstimatedCostUSD\" class=\"config-input\" />\n </div>\n </div>\n </div>\n\n <div class=\"config-section\">\n <h3>Input Definition (JSON)</h3>\n <textarea class=\"json-editor\" [(ngModel)]=\"record.InputDefinition\" rows=\"10\"></textarea>\n </div>\n\n <div class=\"config-section\">\n <h3>Expected Outcomes (JSON)</h3>\n <textarea class=\"json-editor\" [(ngModel)]=\"record.ExpectedOutcomes\" rows=\"10\"></textarea>\n </div>\n\n <div class=\"config-section\">\n <h3>Configuration (JSON)</h3>\n <textarea class=\"json-editor\" [(ngModel)]=\"record.Configuration\" rows=\"10\"></textarea>\n </div>\n\n <div class=\"config-section\">\n <h3>Tags (JSON Array)</h3>\n <textarea class=\"json-editor\" [(ngModel)]=\"record.Tags\" rows=\"5\"></textarea>\n </div>\n </div>\n\n <!-- Test Runs Tab -->\n <div class=\"runs-tab\" *ngIf=\"activeTab === 'runs'\">\n <div class=\"runs-list\" *ngIf=\"testRuns.length > 0\">\n <div class=\"run-item\" *ngFor=\"let run of testRuns\" (click)=\"openTestRun(run.ID)\">\n <div class=\"run-icon\" [style.background-color]=\"run.Status === 'Passed' ? '#4caf50' : run.Status === 'Failed' ? '#f44336' : '#ff9800'\">\n <i class=\"fas\" [class.fa-check]=\"run.Status === 'Passed'\" [class.fa-times]=\"run.Status === 'Failed'\" [class.fa-exclamation]=\"run.Status === 'Error'\"></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]=\"run.Status === 'Passed' ? '#4caf50' : run.Status === 'Failed' ? '#f44336' : '#ff9800'\">{{ run.Status }}</span>\n </div>\n <div class=\"run-meta\">\n <span>{{ run.StartedAt | date:'short' }}</span>\n <span *ngIf=\"run.DurationSeconds\">{{ formatDuration(run.DurationSeconds) }}</span>\n <span *ngIf=\"run.CostUSD\">{{ formatCost(run.CostUSD) }}</span>\n <span *ngIf=\"run.Score != null\">Score: {{ run.Score.toFixed(4) }}</span>\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n </div>\n\n <div class=\"no-data\" *ngIf=\"testRunsLoaded && testRuns.length === 0\">\n <i class=\"fas fa-inbox\"></i>\n <p>No test runs found for this test</p>\n </div>\n </div>\n\n <!-- Test Suites Tab -->\n <div class=\"suites-tab\" *ngIf=\"activeTab === 'suites'\">\n <div class=\"suites-list\" *ngIf=\"suiteTests.length > 0\">\n <div class=\"suite-item\" *ngFor=\"let suiteTest of suiteTests\" (click)=\"openTestSuite(suiteTest.SuiteID)\">\n <div class=\"suite-icon\">\n <i class=\"fas fa-folder\"></i>\n </div>\n <div class=\"suite-content\">\n <div class=\"suite-name\">{{ suiteTest.Suite }}</div>\n <div class=\"suite-meta\">\n <span>Sequence: {{ suiteTest.Sequence }}</span>\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n </div>\n\n <div class=\"no-data\" *ngIf=\"suiteTestsLoaded && suiteTests.length === 0\">\n <i class=\"fas fa-inbox\"></i>\n <p>This test is not part of any test suite</p>\n </div>\n </div>\n </div>\n</div>\n", styles: [".test-form {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8f9fa;\n}\n\n/* Header */\n.test-header {\n background: white;\n border-bottom: 1px solid #e0e0e0;\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}\n\n.header-left {\n display: flex;\n gap: 16px;\n}\n\n.test-icon {\n width: 56px;\n height: 56px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 24px;\n}\n\n.test-info h1 {\n margin: 0 0 8px 0;\n font-size: 24px;\n font-weight: 600;\n color: #333;\n}\n\n.test-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 12px;\n color: white;\n font-size: 12px;\n font-weight: 600;\n}\n\n.test-type {\n font-size: 14px;\n color: #666;\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n}\n\n.test-description {\n padding: 16px;\n background: #f8f9fa;\n border-radius: 8px;\n margin-bottom: 16px;\n}\n\n.test-description p {\n margin: 0;\n color: #666;\n line-height: 1.5;\n}\n\n.metrics-bar {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n}\n\n.metric-card {\n background: #f5f7fa;\n border-radius: 8px;\n padding: 12px;\n text-align: center;\n}\n\n.metric-label {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #999;\n margin-bottom: 4px;\n}\n\n.metric-value {\n font-size: 16px;\n font-weight: 600;\n color: #333;\n}\n\n/* Tabs */\n.tabs-container {\n background: white;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.tabs {\n display: flex;\n padding: 0 20px;\n overflow-x: auto;\n}\n\n.tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px 20px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: #666;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.tab:hover {\n color: #2196f3;\n background: rgba(33, 150, 243, 0.05);\n}\n\n.tab.active {\n color: #2196f3;\n border-bottom-color: #2196f3;\n}\n\n.tab i {\n font-size: 16px;\n}\n\n.tab-badge {\n background: #e0e0e0;\n color: #666;\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.tab.active .tab-badge {\n background: #e3f2fd;\n color: #2196f3;\n}\n\n/* Tab Content */\n.tab-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n/* Overview Tab */\n.overview-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.info-section,\n.json-section,\n.config-section {\n background: white;\n border-radius: 12px;\n padding: 20px;\n}\n\n.info-section h3,\n.json-section h3,\n.config-section h3 {\n margin: 0 0 16px 0;\n font-size: 18px;\n font-weight: 600;\n color: #333;\n}\n\n.info-grid,\n.config-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px;\n}\n\n.info-item,\n.config-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.info-label,\n.config-item label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #999;\n}\n\n.info-value {\n font-size: 14px;\n color: #333;\n word-wrap: break-word;\n}\n\n.config-input {\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n}\n\n.config-input:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.json-tabs {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n border-bottom: 2px solid #e0e0e0;\n}\n\n.json-tab {\n padding: 10px 20px;\n border: none;\n background: transparent;\n color: #666;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n border-bottom: 3px solid transparent;\n margin-bottom: -2px;\n transition: all 0.2s ease;\n}\n\n.json-tab:hover {\n color: #2196f3;\n}\n\n.json-tab.active {\n color: #2196f3;\n border-bottom-color: #2196f3;\n}\n\n.json-content {\n background: #1e1e1e;\n border-radius: 8px;\n padding: 16px;\n max-height: 400px;\n overflow-y: auto;\n}\n\n.json-content pre {\n margin: 0;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n line-height: 1.5;\n color: #e0e0e0;\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n\n.json-editor {\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n resize: vertical;\n}\n\n.json-editor:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n/* Runs Tab */\n.runs-list,\n.suites-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.run-item,\n.suite-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n background: white;\n border: 2px solid transparent;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.run-item:hover,\n.suite-item:hover {\n background: #e3f2fd;\n border-color: #90caf9;\n}\n\n.run-icon,\n.suite-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n color: white;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.suite-icon {\n background: #ff9800;\n}\n\n.run-content,\n.suite-content {\n flex: 1;\n}\n\n.run-header,\n.suite-name {\n font-size: 14px;\n font-weight: 600;\n color: #333;\n margin-bottom: 4px;\n}\n\n.run-id {\n margin-right: 12px;\n}\n\n.run-status {\n font-weight: 700;\n}\n\n.run-meta,\n.suite-meta {\n display: flex;\n gap: 12px;\n font-size: 12px;\n color: #666;\n}\n\n.run-item > i,\n.suite-item > i {\n color: #999;\n font-size: 14px;\n}\n\n/* No Data State */\n.no-data {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: #999;\n text-align: center;\n background: white;\n border-radius: 12px;\n}\n\n.no-data i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.no-data p {\n margin: 0;\n font-size: 14px;\n}\n\n/* Responsive */\n@media (max-width: 1200px) {\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid,\n .config-grid {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 768px) {\n .metrics-bar {\n grid-template-columns: 1fr;\n }\n\n .header-content {\n flex-direction: column;\n gap: 16px;\n }\n\n .tabs {\n overflow-x: auto;\n }\n}\n"] }]
716
- }], () => [{ type: i0.ElementRef }, { type: i1.SharedService }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i3.TestingDialogService }], null); })();
717
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TestFormComponentExtended, { className: "TestFormComponentExtended", filePath: "src/lib/custom/Tests/test-form.component.ts", lineNumber: 27 }); })();
1963
+ args: [{ selector: 'mj-test-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-form\" kendoDialogContainer>\n <!-- Header Section -->\n <div class=\"test-header\">\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>{{ record.Name }}</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 <span class=\"test-type\" *ngIf=\"record.Type\">\n <i class=\"fas fa-tag\"></i>\n {{ record.Type }}\n </span>\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <app-evaluation-mode-toggle></app-evaluation-mode-toggle>\n <button kendoButton (click)=\"runTest()\" themeColor=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test\n </button>\n <button kendoButton (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 <div class=\"test-description\" *ngIf=\"record.Description\">\n <p>{{ record.Description }}</p>\n </div>\n\n <!-- Metrics Bar -->\n <div class=\"metrics-bar\" *ngIf=\"testRunsLoaded && testRuns.length > 0\">\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 </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 <span class=\"tab-badge\" *ngIf=\"testRunsLoaded\">{{ testRuns.length }}</span>\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 <span class=\"tab-badge\" *ngIf=\"suiteTestsLoaded\">{{ suiteTests.length }}</span>\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\">\n <!-- Overview Tab -->\n <div class=\"overview-tab\" *ngIf=\"activeTab === 'overview'\">\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\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 <!-- Configuration Tab -->\n <div class=\"config-tab\" *ngIf=\"activeTab === 'config'\">\n <div class=\"config-section\">\n <h3><i class=\"fas fa-cogs\"></i> Execution Settings</h3>\n <div class=\"config-grid\">\n <div class=\"config-item\">\n <label>Priority</label>\n <input type=\"number\" [(ngModel)]=\"record.Priority\" class=\"config-input\" placeholder=\"Lower = Higher Priority\" />\n </div>\n <div class=\"config-item\">\n <label>Repeat Count</label>\n <input type=\"number\" [(ngModel)]=\"record.RepeatCount\" class=\"config-input\" min=\"1\" />\n </div>\n <div class=\"config-item\">\n <label>Estimated Duration (seconds)</label>\n <input type=\"number\" [(ngModel)]=\"record.EstimatedDurationSeconds\" class=\"config-input\" />\n </div>\n <div class=\"config-item\">\n <label>Estimated Cost (USD)</label>\n <input type=\"number\" step=\"0.000001\" [(ngModel)]=\"record.EstimatedCostUSD\" class=\"config-input\" />\n </div>\n <div class=\"config-item full-width\">\n <label>Max Execution Time (ms)</label>\n <input type=\"number\" [(ngModel)]=\"record.MaxExecutionTimeMS\" class=\"config-input\" placeholder=\"Default: 300000 (5 min)\" />\n <span class=\"config-hint\">Leave empty for default 5 minute timeout</span>\n </div>\n </div>\n </div>\n\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\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\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 <div class=\"config-section\">\n <h3><i class=\"fas fa-tags\"></i> Tags (JSON Array)</h3>\n <div class=\"config-editor-container small\">\n <mj-code-editor\n [value]=\"record.Tags || '[]'\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.Tags = $event\">\n </mj-code-editor>\n </div>\n </div>\n </div>\n\n <!-- Test Runs Tab -->\n <div class=\"runs-tab\" *ngIf=\"activeTab === 'runs'\">\n <!-- Loading State -->\n <div class=\"loading-state\" *ngIf=\"loadingRuns\">\n <div class=\"skeleton-list\">\n <div class=\"skeleton-card\" *ngFor=\"let i of [1,2,3,4,5]\">\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 </div>\n </div>\n\n <!-- Runs List -->\n <div class=\"runs-list\" *ngIf=\"!loadingRuns && testRuns.length > 0\">\n <div class=\"run-item\" *ngFor=\"let run of testRuns\" (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 <span *ngIf=\"run.DurationSeconds\"><i class=\"fas fa-clock\"></i> {{ formatDuration(run.DurationSeconds) }}</span>\n <span *ngIf=\"run.CostUSD\"><i class=\"fas fa-dollar-sign\"></i> {{ formatCost(run.CostUSD) }}</span>\n <mj-entity-link-pill\n *ngIf=\"run.TargetLogEntityID && run.TargetLogID\"\n [entityName]=\"run.TargetLogEntity\"\n [recordId]=\"run.TargetLogID\">\n </mj-entity-link-pill>\n </div>\n <!-- Evaluation indicators -->\n <div class=\"run-eval-stack\">\n <!-- Status indicator -->\n <span class=\"eval-pill status-pill\" *ngIf=\"evalPreferences.showExecution\"\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 <!-- Human feedback indicator -->\n <ng-container *ngIf=\"evalPreferences.showHuman\">\n <span class=\"eval-pill human-pill no-feedback\" *ngIf=\"!getFeedbackForRun(run.ID)?.Rating\"\n title=\"Human Review: No rating submitted yet\">\n <i class=\"fas fa-user-slash\"></i>\n </span>\n <span class=\"eval-pill human-pill has-feedback\" *ngIf=\"getFeedbackForRun(run.ID)?.Rating as rating\"\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 </ng-container>\n <!-- Auto score indicator -->\n <ng-container *ngIf=\"evalPreferences.showAuto\">\n <span class=\"eval-pill auto-pill no-score\" *ngIf=\"run.Score == null\"\n title=\"Auto Score: No automated score available\">\n <i class=\"fas fa-robot\"></i>\n </span>\n <span class=\"eval-pill auto-pill has-score\" *ngIf=\"run.Score != null\"\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 </ng-container>\n </div>\n <div class=\"run-tags\" *ngIf=\"getRunTags(run).length > 0\">\n <span class=\"run-tag\" *ngFor=\"let tag of getRunTags(run).slice(0, 3)\">{{ tag }}</span>\n <span class=\"run-tag-more\" *ngIf=\"getRunTags(run).length > 3\">+{{ getRunTags(run).length - 3 }}</span>\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n </div>\n\n <!-- Empty State -->\n <div class=\"empty-state\" *ngIf=\"testRunsLoaded && !loadingRuns && testRuns.length === 0\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-play-circle\"></i>\n </div>\n <h4>No Test Runs Yet</h4>\n <p>Run this test to see execution history and results here.</p>\n <button kendoButton (click)=\"runTest()\" themeColor=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test Now\n </button>\n </div>\n </div>\n\n <!-- Test Suites Tab -->\n <div class=\"suites-tab\" *ngIf=\"activeTab === 'suites'\">\n <!-- Loading State -->\n <div class=\"loading-state\" *ngIf=\"loadingSuites\">\n <div class=\"skeleton-list\">\n <div class=\"skeleton-card\" *ngFor=\"let i of [1,2,3]\">\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 </div>\n </div>\n\n <!-- Suites List -->\n <div class=\"suites-list\" *ngIf=\"!loadingSuites && suiteTests.length > 0\">\n <div class=\"suite-item\" *ngFor=\"let suiteTest of suiteTests\" (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 <span *ngIf=\"suiteTest.Status\"><i class=\"fas fa-info-circle\"></i> {{ suiteTest.Status }}</span>\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n </div>\n\n <!-- Empty State -->\n <div class=\"empty-state\" *ngIf=\"suiteTestsLoaded && !loadingSuites && suiteTests.length === 0\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-folder-open\"></i>\n </div>\n <h4>Not Part of Any Suite</h4>\n <p>This test is not included in any test suites. Add it to a suite to run it with other tests.</p>\n </div>\n </div>\n\n <!-- Analytics Tab -->\n <div class=\"history-tab\" *ngIf=\"activeTab === 'analytics'\">\n <!-- Loading State -->\n <div class=\"loading-state\" *ngIf=\"loadingHistory\">\n <mj-loading text=\"Loading history...\"></mj-loading>\n </div>\n\n <!-- History Content -->\n <div class=\"history-content\" *ngIf=\"!loadingHistory && historyLoaded\">\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 kendoButton (click)=\"exportHistoryToCSV()\" [disabled]=\"historyData.length === 0\">\n <i class=\"fas fa-download\"></i> Export CSV\n </button>\n </div>\n </div>\n\n <!-- KPI Cards -->\n <div class=\"history-kpi-cards\" *ngIf=\"historyData.length > 0\">\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 <div class=\"kpi-card\" *ngIf=\"evalPreferences.showExecution\">\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 <div class=\"kpi-card\" *ngIf=\"evalPreferences.showAuto\">\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 <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 <div class=\"history-section\" *ngIf=\"historyData.length > 0\">\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 <th *ngIf=\"evalPreferences.showExecution\">Passed</th>\n <th *ngIf=\"evalPreferences.showExecution\">Failed</th>\n <th *ngIf=\"evalPreferences.showExecution\">Pass Rate</th>\n <th *ngIf=\"evalPreferences.showAuto\">Avg Score</th>\n <th>Avg Duration</th>\n <th>Avg Cost</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let day of historyData\">\n <td class=\"date-cell\">{{ day.date | date:'mediumDate' }}</td>\n <td class=\"runs-cell\">{{ day.runCount }}</td>\n <td class=\"passed-cell\" *ngIf=\"evalPreferences.showExecution\">{{ day.passCount }}</td>\n <td class=\"failed-cell\" *ngIf=\"evalPreferences.showExecution\">{{ day.failCount }}</td>\n <td class=\"pass-rate-cell\" *ngIf=\"evalPreferences.showExecution\">\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 <td class=\"score-cell\" *ngIf=\"evalPreferences.showAuto\">{{ (day.avgScore * 100).toFixed(1) }}%</td>\n <td class=\"duration-cell\">{{ formatDuration(day.avgDuration) }}</td>\n <td class=\"cost-cell\">{{ formatCost(day.avgCost) }}</td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n\n <!-- Suite Performance -->\n <div class=\"history-section\" *ngIf=\"suitePerformance.length > 0\">\n <h3><i class=\"fas fa-layer-group\"></i> Performance by Suite</h3>\n <div class=\"suite-performance-list\">\n <div class=\"suite-perf-card\" *ngFor=\"let suite of suitePerformance\" (click)=\"openSuiteFromHistory(suite.suiteId)\">\n <div class=\"suite-perf-header\">\n <div class=\"suite-perf-name\">{{ suite.suiteName }}</div>\n <div class=\"suite-perf-tags\" *ngIf=\"suite.tags.length > 0\">\n <span class=\"tag-mini\" *ngFor=\"let tag of suite.tags.slice(0, 3)\">{{ tag }}</span>\n <span class=\"tag-more\" *ngIf=\"suite.tags.length > 3\">+{{ suite.tags.length - 3 }}</span>\n </div>\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 <div class=\"suite-stat\" *ngIf=\"evalPreferences.showExecution\">\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 <div class=\"suite-stat\" *ngIf=\"evalPreferences.showAuto\">\n <span class=\"stat-value\">{{ (suite.avgScore * 100).toFixed(1) }}%</span>\n <span class=\"stat-label\">Avg Score</span>\n </div>\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 <div class=\"suite-stat\" *ngIf=\"suite.lastRun\">\n <span class=\"stat-value\">{{ getRelativeTime(suite.lastRun) }}</span>\n <span class=\"stat-label\">Last Run</span>\n </div>\n </div>\n <i class=\"fas fa-chevron-right suite-perf-arrow\"></i>\n </div>\n </div>\n </div>\n\n <!-- Empty State -->\n <div class=\"empty-state\" *ngIf=\"historyData.length === 0\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-chart-line\"></i>\n </div>\n <h4>No History Available</h4>\n <p>Run this test to start building history and analytics data.</p>\n <button kendoButton (click)=\"runTest()\" themeColor=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test Now\n </button>\n </div>\n </div>\n </div>\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 <div class=\"keyboard-shortcuts\" *ngIf=\"showShortcuts\">\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>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</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: #2563eb;\n --test-primary-light: #3b82f6;\n --test-primary-dark: #1d4ed8;\n --test-success: #10b981;\n --test-success-light: #d1fae5;\n --test-error: #ef4444;\n --test-error-light: #fee2e2;\n --test-warning: #f59e0b;\n --test-warning-light: #fef3c7;\n --test-disabled: #6b7280;\n --test-bg: #f8fafc;\n --test-surface: #ffffff;\n --test-border: #e2e8f0;\n --test-text: #1e293b;\n --test-text-secondary: #64748b;\n --test-text-muted: #94a3b8;\n --test-radius-sm: 6px;\n --test-radius-md: 10px;\n --test-radius-lg: 16px;\n --test-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);\n --test-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n --test-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n --test-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: block;\n height: 100%;\n}\n\n/* Base Container */\n.test-form {\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: white;\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: white;\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: linear-gradient(135deg, var(--test-success) 0%, #059669 100%); }\n.status-badge.status-disabled { background: linear-gradient(135deg, var(--test-disabled) 0%, #4b5563 100%); }\n.status-badge.status-pending { background: linear-gradient(135deg, var(--test-warning) 0%, #d97706 100%); }\n\n.status-badge-inline {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border-radius: 10px;\n color: white;\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: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\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: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\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: linear-gradient(90deg, var(--test-success) 0%, #34d399 100%);\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: rgba(37, 99, 235, 0.05);\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: rgba(37, 99, 235, 0.15);\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: rgba(0, 0, 0, 0.05);\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 rgba(37, 99, 235, 0.1);\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, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 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, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 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: rgba(37, 99, 235, 0.05);\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: white;\n font-size: 18px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-sm);\n}\n\n.suite-icon {\n background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);\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: #dcfce7;\n color: #16a34a;\n}\n\n.eval-pill.status-pill.status-failed {\n background: #fee2e2;\n color: #dc2626;\n}\n\n.eval-pill.status-pill.status-error {\n background: #fef3c7;\n color: #d97706;\n}\n\n.eval-pill.status-pill.status-timeout {\n background: #fef3c7;\n color: #d97706;\n}\n\n.eval-pill.status-pill.status-skipped,\n.eval-pill.status-pill.status-pending {\n background: #f1f5f9;\n color: #64748b;\n}\n\n.eval-pill.status-pill.status-running {\n background: #dbeafe;\n color: #2563eb;\n}\n\n/* Human feedback pills */\n.eval-pill.human-pill.no-feedback {\n background: #f1f5f9;\n color: #94a3b8;\n padding: 4px 8px;\n}\n\n.eval-pill.human-pill.has-feedback.rating-low {\n background: #fee2e2;\n color: #dc2626;\n}\n\n.eval-pill.human-pill.has-feedback.rating-medium {\n background: #fef3c7;\n color: #d97706;\n}\n\n.eval-pill.human-pill.has-feedback.rating-good {\n background: #d1fae5;\n color: #059669;\n}\n\n.eval-pill.human-pill.has-feedback.rating-excellent {\n background: #dcfce7;\n color: #16a34a;\n}\n\n/* Auto score pills */\n.eval-pill.auto-pill.no-score {\n background: #f1f5f9;\n color: #94a3b8;\n padding: 4px 8px;\n}\n\n.eval-pill.auto-pill.has-score.score-low {\n background: #fee2e2;\n color: #dc2626;\n}\n\n.eval-pill.auto-pill.has-score.score-medium {\n background: #fef3c7;\n color: #d97706;\n}\n\n.eval-pill.auto-pill.has-score.score-good {\n background: #d1fae5;\n color: #059669;\n}\n\n.eval-pill.auto-pill.has-score.score-excellent {\n background: #dcfce7;\n color: #16a34a;\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: rgba(37, 99, 235, 0.1);\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 Empty States\n =========================== */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.empty-icon {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--test-bg);\n border-radius: 50%;\n margin-bottom: 20px;\n}\n\n.empty-icon i {\n font-size: 36px;\n color: var(--test-text-muted);\n}\n\n.empty-state h4 {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.empty-state p {\n margin: 0 0 20px 0;\n font-size: 14px;\n color: var(--test-text-secondary);\n max-width: 300px;\n}\n\n/* Legacy no-data for backwards compatibility */\n.no-data {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--test-text-muted);\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.no-data i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.no-data p {\n margin: 0;\n font-size: 14px;\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 .empty-state {\n padding: 40px 20px;\n }\n\n .empty-icon {\n width: 64px;\n height: 64px;\n }\n\n .empty-icon i {\n font-size: 28px;\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: rgba(37, 99, 235, 0.1);\n transform: scale(0.98);\n }\n\n .tab:active,\n .json-tab:active {\n background: rgba(37, 99, 235, 0.1);\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: #e2e8f0;\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: rgba(37, 99, 235, 0.05);\n}\n\n.filter-btn.active {\n background: var(--test-primary);\n color: white;\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: linear-gradient(135deg, var(--test-primary) 0%, var(--test-primary-dark) 100%);\n border-radius: var(--test-radius-md);\n color: white;\n font-size: 20px;\n flex-shrink: 0;\n}\n\n.kpi-icon.pass-rate {\n background: linear-gradient(135deg, var(--test-success) 0%, #059669 100%);\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: rgba(37, 99, 235, 0.03);\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: linear-gradient(90deg, var(--test-success) 0%, #34d399 100%);\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: rgba(37, 99, 235, 0.05);\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: rgba(37, 99, 235, 0.1);\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: white;\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 .empty-state {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid #ddd;\n }\n}\n"] }]
1964
+ }], () => [{ type: i0.ElementRef }, { type: i1.SharedService }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i3.TestingDialogService }, { type: i3.EvaluationPreferencesService }], { handleKeyboardShortcut: [{
1965
+ type: HostListener,
1966
+ args: ['document:keydown', ['$event']]
1967
+ }] }); })();
1968
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TestFormComponentExtended, { className: "TestFormComponentExtended", filePath: "src/lib/custom/Tests/test-form.component.ts", lineNumber: 61 }); })();
718
1969
  export function LoadTestFormComponentExtended() {
719
1970
  // Prevents tree-shaking
720
1971
  }