@memberjunction/ng-dashboards 5.38.0 → 5.40.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 (321) hide show
  1. package/README.md +14 -7
  2. package/dist/AI/components/agents/agent-configuration.component.js +199 -198
  3. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  4. package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts.map +1 -1
  5. package/dist/AI/components/analytics/ai-analytics-resource.component.js +20 -17
  6. package/dist/AI/components/analytics/ai-analytics-resource.component.js.map +1 -1
  7. package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts +15 -0
  8. package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts.map +1 -1
  9. package/dist/AI/components/analytics/cost-budget/cost-budget.component.js +166 -58
  10. package/dist/AI/components/analytics/cost-budget/cost-budget.component.js.map +1 -1
  11. package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts.map +1 -1
  12. package/dist/AI/components/analytics/executive-summary/executive-summary.component.js +2 -1
  13. package/dist/AI/components/analytics/executive-summary/executive-summary.component.js.map +1 -1
  14. package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts +1 -0
  15. package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts.map +1 -1
  16. package/dist/AI/components/analytics/model-performance/model-performance.component.js +55 -36
  17. package/dist/AI/components/analytics/model-performance/model-performance.component.js.map +1 -1
  18. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts +9 -1
  19. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts.map +1 -1
  20. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js +158 -117
  21. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js.map +1 -1
  22. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts +1 -0
  23. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts.map +1 -1
  24. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js +22 -8
  25. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js.map +1 -1
  26. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +217 -860
  27. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  28. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +1717 -7802
  29. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  30. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts +56 -0
  31. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts.map +1 -0
  32. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js +423 -0
  33. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js.map +1 -0
  34. package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts +70 -0
  35. package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts.map +1 -0
  36. package/dist/AI/components/autotagging/components/classify-item-grid.component.js +308 -0
  37. package/dist/AI/components/autotagging/components/classify-item-grid.component.js.map +1 -0
  38. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts +29 -0
  39. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts.map +1 -0
  40. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js +186 -0
  41. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js.map +1 -0
  42. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts +69 -0
  43. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts.map +1 -0
  44. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js +278 -0
  45. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js.map +1 -0
  46. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts +73 -0
  47. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts.map +1 -0
  48. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js +393 -0
  49. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js.map +1 -0
  50. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts +122 -0
  51. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts.map +1 -0
  52. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js +908 -0
  53. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js.map +1 -0
  54. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts +87 -0
  55. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts.map +1 -0
  56. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js +475 -0
  57. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js.map +1 -0
  58. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts +29 -0
  59. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts.map +1 -0
  60. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js +208 -0
  61. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js.map +1 -0
  62. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts +21 -0
  63. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts.map +1 -0
  64. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js +70 -0
  65. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js.map +1 -0
  66. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +333 -0
  67. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -0
  68. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +2125 -0
  69. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -0
  70. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts +61 -0
  71. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts.map +1 -0
  72. package/dist/AI/components/autotagging/shared/classify.dryrun.js +78 -0
  73. package/dist/AI/components/autotagging/shared/classify.dryrun.js.map +1 -0
  74. package/dist/AI/components/autotagging/shared/classify.format.d.ts +58 -0
  75. package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -0
  76. package/dist/AI/components/autotagging/shared/classify.format.js +260 -0
  77. package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -0
  78. package/dist/AI/components/autotagging/shared/classify.types.d.ts +319 -0
  79. package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -0
  80. package/dist/AI/components/autotagging/shared/classify.types.js +6 -0
  81. package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -0
  82. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts +103 -0
  83. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts.map +1 -0
  84. package/dist/AI/components/autotagging/tabs/health-tab.component.js +571 -0
  85. package/dist/AI/components/autotagging/tabs/health-tab.component.js.map +1 -0
  86. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +77 -0
  87. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -0
  88. package/dist/AI/components/autotagging/tabs/history-tab.component.js +519 -0
  89. package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -0
  90. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts +107 -0
  91. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts.map +1 -0
  92. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js +719 -0
  93. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js.map +1 -0
  94. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +131 -0
  95. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -0
  96. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +813 -0
  97. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -0
  98. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +177 -0
  99. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -0
  100. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1465 -0
  101. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -0
  102. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +78 -0
  103. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -0
  104. package/dist/AI/components/autotagging/tabs/tags-tab.component.js +492 -0
  105. package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -0
  106. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts +397 -0
  107. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts.map +1 -0
  108. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js +3490 -0
  109. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js.map +1 -0
  110. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +56 -0
  111. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -0
  112. package/dist/AI/components/autotagging/tabs/types-tab.component.js +271 -0
  113. package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -0
  114. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +3 -0
  115. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  116. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +306 -290
  117. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  118. package/dist/AI/components/execution-monitoring.component.js +1 -1
  119. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  120. package/dist/AI/components/models/model-management.component.js +209 -208
  121. package/dist/AI/components/models/model-management.component.js.map +1 -1
  122. package/dist/AI/components/prompts/prompt-management.component.js +130 -128
  123. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  124. package/dist/AI/components/requests/agent-requests-resource.component.js +61 -61
  125. package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
  126. package/dist/AI/components/system/system-configuration.component.js +17 -17
  127. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  128. package/dist/AI/components/tags/tags-resource.component.d.ts +1 -0
  129. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  130. package/dist/AI/components/tags/tags-resource.component.js +578 -538
  131. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  132. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +3 -0
  133. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  134. package/dist/AI/components/vectors/vector-management-resource.component.js +331 -303
  135. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  136. package/dist/AI/services/ai-instrumentation.service.d.ts +5 -0
  137. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  138. package/dist/AI/services/ai-instrumentation.service.js +14 -2
  139. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  140. package/dist/AI/services/cache-metrics.d.ts +50 -0
  141. package/dist/AI/services/cache-metrics.d.ts.map +1 -0
  142. package/dist/AI/services/cache-metrics.js +43 -0
  143. package/dist/AI/services/cache-metrics.js.map +1 -0
  144. package/dist/APIKeys/api-applications-panel.component.js +2 -2
  145. package/dist/APIKeys/api-key-create-dialog.component.js +2 -2
  146. package/dist/APIKeys/api-key-edit-panel.component.js +2 -2
  147. package/dist/APIKeys/api-keys-resource.component.js +132 -131
  148. package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
  149. package/dist/Actions/components/actions-overview.component.js +141 -141
  150. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  151. package/dist/Actions/components/execution-monitoring.component.js +15 -15
  152. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  153. package/dist/Actions/components/explorer/action-explorer.component.d.ts +0 -5
  154. package/dist/Actions/components/explorer/action-explorer.component.d.ts.map +1 -1
  155. package/dist/Actions/components/explorer/action-explorer.component.js +139 -212
  156. package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
  157. package/dist/Admin/admin-data-schema.component.js +2 -2
  158. package/dist/Admin/admin-data-schema.component.js.map +1 -1
  159. package/dist/Admin/admin-dev-tools-resource.component.js +2 -2
  160. package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
  161. package/dist/Admin/admin-identity-access.component.js +2 -2
  162. package/dist/Admin/admin-identity-access.component.js.map +1 -1
  163. package/dist/Admin/admin-monitoring.component.js +2 -2
  164. package/dist/Admin/admin-monitoring.component.js.map +1 -1
  165. package/dist/ApplicationRoles/application-roles-resource.component.js +54 -49
  166. package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
  167. package/dist/Communication/communication-logs-resource.component.d.ts +6 -0
  168. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  169. package/dist/Communication/communication-logs-resource.component.js +72 -50
  170. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  171. package/dist/Communication/communication-monitor-resource.component.js +103 -102
  172. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  173. package/dist/Communication/communication-providers-resource.component.js +52 -51
  174. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  175. package/dist/Communication/communication-runs-resource.component.js +39 -38
  176. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  177. package/dist/Communication/communication-templates-resource.component.d.ts +6 -0
  178. package/dist/Communication/communication-templates-resource.component.d.ts.map +1 -1
  179. package/dist/Communication/communication-templates-resource.component.js +92 -89
  180. package/dist/Communication/communication-templates-resource.component.js.map +1 -1
  181. package/dist/Credentials/components/credentials-audit-resource.component.js +136 -135
  182. package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
  183. package/dist/Credentials/components/credentials-categories-resource.component.js +155 -152
  184. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  185. package/dist/Credentials/components/credentials-list-resource.component.js +119 -118
  186. package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
  187. package/dist/Credentials/components/credentials-overview-resource.component.js +129 -128
  188. package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
  189. package/dist/Credentials/components/credentials-types-resource.component.js +107 -106
  190. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  191. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +31 -340
  192. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  193. package/dist/DataExplorer/data-explorer-dashboard.component.js +468 -1958
  194. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  195. package/dist/DataExplorer/data-explorer-resource.component.d.ts.map +1 -1
  196. package/dist/DataExplorer/data-explorer-resource.component.js +10 -0
  197. package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
  198. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +1 -1
  199. package/dist/DatabaseDesigner/components/entity-list.component.js +115 -114
  200. package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -1
  201. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +5 -6
  202. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -1
  203. package/dist/DatabaseDesigner/database-designer-dashboards.module.js +4 -5
  204. package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -1
  205. package/dist/DevTools/app-state-inspector.component.js +18 -17
  206. package/dist/DevTools/app-state-inspector.component.js.map +1 -1
  207. package/dist/DevTools/class-registry.component.js +88 -85
  208. package/dist/DevTools/class-registry.component.js.map +1 -1
  209. package/dist/DevTools/event-monitor.component.js +155 -150
  210. package/dist/DevTools/event-monitor.component.js.map +1 -1
  211. package/dist/DevTools/graphql-console.component.js +245 -243
  212. package/dist/DevTools/graphql-console.component.js.map +1 -1
  213. package/dist/DevTools/layout-inspector.component.js +18 -17
  214. package/dist/DevTools/layout-inspector.component.js.map +1 -1
  215. package/dist/EntityAdmin/entity-admin-dashboard.component.js +20 -19
  216. package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
  217. package/dist/Home/home-dashboard.component.js +2 -2
  218. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
  219. package/dist/Integration/components/activity/activity.component.js +236 -229
  220. package/dist/Integration/components/activity/activity.component.js.map +1 -1
  221. package/dist/Integration/components/connections/connections.component.js +390 -389
  222. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  223. package/dist/Integration/components/overview/overview.component.js +2 -2
  224. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -1
  225. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +14 -11
  226. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
  227. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +27 -2
  228. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
  229. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +244 -119
  230. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
  231. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +293 -291
  232. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  233. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +62 -61
  234. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
  235. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts +65 -0
  236. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts.map +1 -0
  237. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js +176 -0
  238. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js.map +1 -0
  239. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts +81 -0
  240. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts.map +1 -0
  241. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js +308 -0
  242. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js.map +1 -0
  243. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts +85 -0
  244. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts.map +1 -0
  245. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js +362 -0
  246. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js.map +1 -0
  247. package/dist/KnowledgeHub/index.d.ts +3 -0
  248. package/dist/KnowledgeHub/index.d.ts.map +1 -1
  249. package/dist/KnowledgeHub/index.js +3 -0
  250. package/dist/KnowledgeHub/index.js.map +1 -1
  251. package/dist/Lists/components/lists-browse-resource.component.d.ts +6 -2
  252. package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
  253. package/dist/Lists/components/lists-browse-resource.component.js +525 -566
  254. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  255. package/dist/Lists/components/lists-categories-resource.component.js +135 -134
  256. package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
  257. package/dist/Lists/components/lists-my-lists-resource.component.js +199 -198
  258. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  259. package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
  260. package/dist/MCP/mcp-dashboard.component.js +443 -438
  261. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  262. package/dist/QueryBrowser/query-browser-resource.component.js +1 -1
  263. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  264. package/dist/Scheduling/components/scheduling-activity.component.d.ts.map +1 -1
  265. package/dist/Scheduling/components/scheduling-activity.component.js +146 -147
  266. package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
  267. package/dist/Scheduling/components/scheduling-jobs.component.js +76 -75
  268. package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
  269. package/dist/Scheduling/components/scheduling-overview.component.js +97 -96
  270. package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
  271. package/dist/Scheduling/scheduling-dashboard.component.js +24 -22
  272. package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
  273. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts +2 -0
  274. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts.map +1 -1
  275. package/dist/Scheduling/services/scheduling-instrumentation.service.js +1 -0
  276. package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
  277. package/dist/Testing/components/testing-dashboard-tab-resource.component.js +1 -1
  278. package/dist/Testing/components/testing-explorer.component.d.ts +14 -4
  279. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  280. package/dist/Testing/components/testing-explorer.component.js +436 -427
  281. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  282. package/dist/Testing/components/testing-runs-resource.component.js +1 -1
  283. package/dist/Testing/components/testing-runs.component.js +116 -115
  284. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  285. package/dist/Testing/testing-dashboard.component.js +6 -7
  286. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  287. package/dist/VersionHistory/components/labels-resource.component.js +173 -172
  288. package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
  289. package/dist/VersionHistory/components/restore-resource.component.d.ts +6 -0
  290. package/dist/VersionHistory/components/restore-resource.component.d.ts.map +1 -1
  291. package/dist/VersionHistory/components/restore-resource.component.js +116 -92
  292. package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
  293. package/dist/ai-dashboards.module.d.ts +57 -35
  294. package/dist/ai-dashboards.module.d.ts.map +1 -1
  295. package/dist/ai-dashboards.module.js +80 -1
  296. package/dist/ai-dashboards.module.js.map +1 -1
  297. package/dist/communication-dashboards.module.d.ts +1 -1
  298. package/dist/communication-dashboards.module.d.ts.map +1 -1
  299. package/dist/communication-dashboards.module.js +7 -1
  300. package/dist/communication-dashboards.module.js.map +1 -1
  301. package/dist/data-explorer-dashboards.module.d.ts +12 -14
  302. package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
  303. package/dist/data-explorer-dashboards.module.js +5 -14
  304. package/dist/data-explorer-dashboards.module.js.map +1 -1
  305. package/dist/public-api.d.ts +3 -0
  306. package/dist/public-api.d.ts.map +1 -1
  307. package/dist/public-api.js +3 -0
  308. package/dist/public-api.js.map +1 -1
  309. package/dist/testing-dashboards.module.d.ts +4 -5
  310. package/dist/testing-dashboards.module.d.ts.map +1 -1
  311. package/dist/testing-dashboards.module.js +7 -5
  312. package/dist/testing-dashboards.module.js.map +1 -1
  313. package/package.json +57 -54
  314. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts +0 -79
  315. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts.map +0 -1
  316. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +0 -195
  317. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js.map +0 -1
  318. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts +0 -226
  319. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +0 -1
  320. package/dist/DataExplorer/components/view-selector/view-selector.component.js +0 -861
  321. package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +0 -1
@@ -0,0 +1,2125 @@
1
+ /**
2
+ * @fileoverview Classify · Source + Content Type CRUD slide-in form dialog.
3
+ *
4
+ * Owns the entire add/edit slide-in form for BOTH content sources and content
5
+ * types (the form renders one or the other depending on `FormMode`). Extracted
6
+ * from the host monolith: the dialog owns ALL form state, the dropdown option
7
+ * getters, the dynamic source-type field logic, and the open / populate / save /
8
+ * close lifecycle. It reads cached reference metadata directly from
9
+ * `KnowledgeHubMetadataEngine.Instance` / `AIEngineBase.Instance` (same as the
10
+ * host did) and persists via the threaded provider.
11
+ *
12
+ * Contract with the host (data orchestrator):
13
+ * - The host calls the public `OpenAddSource()` / `OpenEditSource(card)` /
14
+ * `OpenAddType()` / `OpenEditType(card)` methods via `@ViewChild` in response
15
+ * to the Sources/Types tabs' add/edit events.
16
+ * - After a successful save the dialog closes itself and emits `(Saved)` with
17
+ * `{ kind: 'source' | 'type' }` so the host reloads the right shared data.
18
+ * - When a source save is blocked because no content type exists, it emits
19
+ * `(ContentTypeMissing)` so the host shows its no-content-type warning.
20
+ * - "Open advanced settings" navigates to the full entity form via the host's
21
+ * NavigationService through the `(NavigateToRecordRequested)` output.
22
+ */
23
+ import { Component, ChangeDetectorRef, EventEmitter, Output, inject, NgZone } from '@angular/core';
24
+ import { CompositeKey, RunView } from '@memberjunction/core';
25
+ import { KnowledgeHubMetadataEngine, ApplicationSettingEngine, UserInfoEngine } from '@memberjunction/core-entities';
26
+ import { UUIDsEqual } from '@memberjunction/global';
27
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
28
+ import { MJNotificationService } from '@memberjunction/ng-notifications';
29
+ import { AIEngineBase } from '@memberjunction/ai-engine-base';
30
+ import { TagEngineBase } from '@memberjunction/tag-engine-base';
31
+ import * as i0 from "@angular/core";
32
+ import * as i1 from "@angular/forms";
33
+ import * as i2 from "@memberjunction/ng-trees";
34
+ import * as i3 from "@memberjunction/ng-ui-components";
35
+ import * as i4 from "@angular/common";
36
+ const _c0 = () => [];
37
+ const _forTrack0 = ($index, $item) => $item.ID;
38
+ const _forTrack1 = ($index, $item) => $item.Key;
39
+ const _forTrack2 = ($index, $item) => $item.value;
40
+ const _forTrack3 = ($index, $item) => $item.Value;
41
+ const _forTrack4 = ($index, $item) => $item.Name;
42
+ const _forTrack5 = ($index, $item) => $item.label;
43
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
44
+ i0.ɵɵtext(0, " Add Content Source ");
45
+ } }
46
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_6_Template(rf, ctx) { if (rf & 1) {
47
+ i0.ɵɵtext(0, " Edit Content Source ");
48
+ } }
49
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_7_Template(rf, ctx) { if (rf & 1) {
50
+ i0.ɵɵtext(0, " Add Content Type ");
51
+ } }
52
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
53
+ i0.ɵɵtext(0, " Edit Content Type ");
54
+ } }
55
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_15_Template(rf, ctx) { if (rf & 1) {
56
+ i0.ɵɵelementStart(0, "option", 15);
57
+ i0.ɵɵtext(1);
58
+ i0.ɵɵelementEnd();
59
+ } if (rf & 2) {
60
+ const opt_r4 = ctx.$implicit;
61
+ i0.ɵɵproperty("value", opt_r4.ID);
62
+ i0.ɵɵadvance();
63
+ i0.ɵɵtextInterpolate(opt_r4.Name);
64
+ } }
65
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_For_7_Template(rf, ctx) { if (rf & 1) {
66
+ i0.ɵɵelementStart(0, "option", 15);
67
+ i0.ɵɵtext(1);
68
+ i0.ɵɵelementEnd();
69
+ } if (rf & 2) {
70
+ const opt_r6 = ctx.$implicit;
71
+ i0.ɵɵproperty("value", opt_r6.ID);
72
+ i0.ɵɵadvance();
73
+ i0.ɵɵtextInterpolate(opt_r6.Name);
74
+ } }
75
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_For_15_Template(rf, ctx) { if (rf & 1) {
76
+ i0.ɵɵelementStart(0, "option", 15);
77
+ i0.ɵɵtext(1);
78
+ i0.ɵɵelementEnd();
79
+ } if (rf & 2) {
80
+ const opt_r7 = ctx.$implicit;
81
+ i0.ɵɵproperty("value", opt_r7.ID);
82
+ i0.ɵɵadvance();
83
+ i0.ɵɵtextInterpolate(opt_r7.Name);
84
+ } }
85
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_Template(rf, ctx) { if (rf & 1) {
86
+ const _r5 = i0.ɵɵgetCurrentView();
87
+ i0.ɵɵelementStart(0, "div", 10)(1, "label", 11);
88
+ i0.ɵɵtext(2, "Content Type");
89
+ i0.ɵɵelementEnd();
90
+ i0.ɵɵelementStart(3, "select", 13);
91
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_Template_select_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormContentTypeID, $event) || (ctx_r1.FormContentTypeID = $event); return i0.ɵɵresetView($event); });
92
+ i0.ɵɵelementStart(4, "option", 14);
93
+ i0.ɵɵtext(5, "Select content type...");
94
+ i0.ɵɵelementEnd();
95
+ i0.ɵɵrepeaterCreate(6, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_For_7_Template, 2, 2, "option", 15, _forTrack0);
96
+ i0.ɵɵelementEnd()();
97
+ i0.ɵɵelementStart(8, "div", 10)(9, "label", 11);
98
+ i0.ɵɵtext(10, "File Type");
99
+ i0.ɵɵelementEnd();
100
+ i0.ɵɵelementStart(11, "select", 13);
101
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_Template_select_ngModelChange_11_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormFileTypeID, $event) || (ctx_r1.FormFileTypeID = $event); return i0.ɵɵresetView($event); });
102
+ i0.ɵɵelementStart(12, "option", 14);
103
+ i0.ɵɵtext(13, "Select file type...");
104
+ i0.ɵɵelementEnd();
105
+ i0.ɵɵrepeaterCreate(14, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_For_15_Template, 2, 2, "option", 15, _forTrack0);
106
+ i0.ɵɵelementEnd()();
107
+ } if (rf & 2) {
108
+ const ctx_r1 = i0.ɵɵnextContext(3);
109
+ i0.ɵɵadvance(3);
110
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormContentTypeID);
111
+ i0.ɵɵadvance(3);
112
+ i0.ɵɵrepeater(ctx_r1.ContentTypeOptions);
113
+ i0.ɵɵadvance(5);
114
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormFileTypeID);
115
+ i0.ɵɵadvance(3);
116
+ i0.ɵɵrepeater(ctx_r1.FileTypeOptions);
117
+ } }
118
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Conditional_3_Template(rf, ctx) { if (rf & 1) {
119
+ i0.ɵɵelementStart(0, "span", 51);
120
+ i0.ɵɵtext(1, "*");
121
+ i0.ɵɵelementEnd();
122
+ } }
123
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_4_Template(rf, ctx) { if (rf & 1) {
124
+ const _r8 = i0.ɵɵgetCurrentView();
125
+ i0.ɵɵelementStart(0, "input", 56);
126
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_4_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r8); const field_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceSpecificConfig[field_r9.Key], $event) || (ctx_r1.FormSourceSpecificConfig[field_r9.Key] = $event); return i0.ɵɵresetView($event); });
127
+ i0.ɵɵelementEnd();
128
+ } if (rf & 2) {
129
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
130
+ const ctx_r1 = i0.ɵɵnextContext(3);
131
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
132
+ i0.ɵɵproperty("placeholder", field_r9.Description || "https://...");
133
+ } }
134
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_5_Template(rf, ctx) { if (rf & 1) {
135
+ const _r10 = i0.ɵɵgetCurrentView();
136
+ i0.ɵɵelementStart(0, "input", 57);
137
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_5_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r10); const field_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceSpecificConfig[field_r9.Key], $event) || (ctx_r1.FormSourceSpecificConfig[field_r9.Key] = $event); return i0.ɵɵresetView($event); });
138
+ i0.ɵɵelementEnd();
139
+ } if (rf & 2) {
140
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
141
+ const ctx_r1 = i0.ɵɵnextContext(3);
142
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
143
+ i0.ɵɵproperty("placeholder", field_r9.Description || "/path/to/...");
144
+ } }
145
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_6_Template(rf, ctx) { if (rf & 1) {
146
+ const _r11 = i0.ɵɵgetCurrentView();
147
+ i0.ɵɵelementStart(0, "input", 58);
148
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_6_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r11); const field_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceSpecificConfig[field_r9.Key], $event) || (ctx_r1.FormSourceSpecificConfig[field_r9.Key] = $event); return i0.ɵɵresetView($event); });
149
+ i0.ɵɵelementEnd();
150
+ } if (rf & 2) {
151
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
152
+ const ctx_r1 = i0.ɵɵnextContext(3);
153
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
154
+ i0.ɵɵproperty("placeholder", field_r9.Description || "")("value", field_r9.DefaultValue || "");
155
+ } }
156
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_For_4_Template(rf, ctx) { if (rf & 1) {
157
+ i0.ɵɵelementStart(0, "option", 15);
158
+ i0.ɵɵtext(1);
159
+ i0.ɵɵelementEnd();
160
+ } if (rf & 2) {
161
+ const opt_r13 = ctx.$implicit;
162
+ i0.ɵɵproperty("value", opt_r13.ID);
163
+ i0.ɵɵadvance();
164
+ i0.ɵɵtextInterpolate(opt_r13.Name);
165
+ } }
166
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_Template(rf, ctx) { if (rf & 1) {
167
+ const _r12 = i0.ɵɵgetCurrentView();
168
+ i0.ɵɵelementStart(0, "select", 13);
169
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_Template_select_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r12); const field_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceSpecificConfig[field_r9.Key], $event) || (ctx_r1.FormSourceSpecificConfig[field_r9.Key] = $event); return i0.ɵɵresetView($event); });
170
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_Template_select_ngModelChange_0_listener() { i0.ɵɵrestoreView(_r12); const field_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnSourceFieldChanged(field_r9.Key)); });
171
+ i0.ɵɵelementStart(1, "option", 14);
172
+ i0.ɵɵtext(2, "Select entity...");
173
+ i0.ɵɵelementEnd();
174
+ i0.ɵɵrepeaterCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_For_4_Template, 2, 2, "option", 15, _forTrack0);
175
+ i0.ɵɵelementEnd();
176
+ } if (rf & 2) {
177
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
178
+ const ctx_r1 = i0.ɵɵnextContext(3);
179
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
180
+ i0.ɵɵadvance(3);
181
+ i0.ɵɵrepeater(ctx_r1.EntitiesWithDocuments);
182
+ } }
183
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_For_2_Template(rf, ctx) { if (rf & 1) {
184
+ i0.ɵɵelementStart(0, "option", 15);
185
+ i0.ɵɵtext(1);
186
+ i0.ɵɵelementEnd();
187
+ } if (rf & 2) {
188
+ const opt_r15 = ctx.$implicit;
189
+ i0.ɵɵproperty("value", opt_r15.ID);
190
+ i0.ɵɵadvance();
191
+ i0.ɵɵtextInterpolate(opt_r15.Name);
192
+ } }
193
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_Template(rf, ctx) { if (rf & 1) {
194
+ const _r14 = i0.ɵɵgetCurrentView();
195
+ i0.ɵɵelementStart(0, "select", 13);
196
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_Template_select_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r14); const field_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceSpecificConfig[field_r9.Key], $event) || (ctx_r1.FormSourceSpecificConfig[field_r9.Key] = $event); return i0.ɵɵresetView($event); });
197
+ i0.ɵɵrepeaterCreate(1, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_For_2_Template, 2, 2, "option", 15, _forTrack0);
198
+ i0.ɵɵelementEnd();
199
+ } if (rf & 2) {
200
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
201
+ const ctx_r1 = i0.ɵɵnextContext(3);
202
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
203
+ i0.ɵɵadvance();
204
+ i0.ɵɵrepeater(ctx_r1.GetDependentOptions(field_r9));
205
+ } }
206
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_9_For_4_Template(rf, ctx) { if (rf & 1) {
207
+ i0.ɵɵelementStart(0, "option", 15);
208
+ i0.ɵɵtext(1);
209
+ i0.ɵɵelementEnd();
210
+ } if (rf & 2) {
211
+ const opt_r17 = ctx.$implicit;
212
+ i0.ɵɵproperty("value", opt_r17);
213
+ i0.ɵɵadvance();
214
+ i0.ɵɵtextInterpolate(opt_r17);
215
+ } }
216
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_9_Template(rf, ctx) { if (rf & 1) {
217
+ const _r16 = i0.ɵɵgetCurrentView();
218
+ i0.ɵɵelementStart(0, "select", 13);
219
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_9_Template_select_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r16); const field_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceSpecificConfig[field_r9.Key], $event) || (ctx_r1.FormSourceSpecificConfig[field_r9.Key] = $event); return i0.ɵɵresetView($event); });
220
+ i0.ɵɵelementStart(1, "option", 14);
221
+ i0.ɵɵtext(2, "Select provider...");
222
+ i0.ɵɵelementEnd();
223
+ i0.ɵɵrepeaterCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_9_For_4_Template, 2, 2, "option", 15, i0.ɵɵrepeaterTrackByIdentity);
224
+ i0.ɵɵelementEnd();
225
+ } if (rf & 2) {
226
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
227
+ const ctx_r1 = i0.ɵɵnextContext(3);
228
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
229
+ i0.ɵɵadvance(3);
230
+ i0.ɵɵrepeater(ctx_r1.StorageProviderOptions);
231
+ } }
232
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_For_4_Template(rf, ctx) { if (rf & 1) {
233
+ i0.ɵɵelementStart(0, "option", 15);
234
+ i0.ɵɵtext(1);
235
+ i0.ɵɵelementEnd();
236
+ } if (rf & 2) {
237
+ const opt_r19 = ctx.$implicit;
238
+ i0.ɵɵproperty("value", opt_r19.Value);
239
+ i0.ɵɵadvance();
240
+ i0.ɵɵtextInterpolate(opt_r19.Label);
241
+ } }
242
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_Template(rf, ctx) { if (rf & 1) {
243
+ const _r18 = i0.ɵɵgetCurrentView();
244
+ i0.ɵɵelementStart(0, "select", 13);
245
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_Template_select_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r18); const field_r9 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceSpecificConfig[field_r9.Key], $event) || (ctx_r1.FormSourceSpecificConfig[field_r9.Key] = $event); return i0.ɵɵresetView($event); });
246
+ i0.ɵɵelementStart(1, "option", 14);
247
+ i0.ɵɵtext(2, "Select...");
248
+ i0.ɵɵelementEnd();
249
+ i0.ɵɵrepeaterCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_For_4_Template, 2, 2, "option", 15, _forTrack3);
250
+ i0.ɵɵelementEnd();
251
+ } if (rf & 2) {
252
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
253
+ const ctx_r1 = i0.ɵɵnextContext(3);
254
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
255
+ i0.ɵɵadvance(3);
256
+ i0.ɵɵrepeater(field_r9.Options || i0.ɵɵpureFunction0(1, _c0));
257
+ } }
258
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Conditional_11_Template(rf, ctx) { if (rf & 1) {
259
+ i0.ɵɵelementStart(0, "span", 19);
260
+ i0.ɵɵtext(1);
261
+ i0.ɵɵelementEnd();
262
+ } if (rf & 2) {
263
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
264
+ i0.ɵɵadvance();
265
+ i0.ɵɵtextInterpolate(field_r9.Description);
266
+ } }
267
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
268
+ i0.ɵɵelementStart(0, "div", 10)(1, "label", 11);
269
+ i0.ɵɵtext(2);
270
+ i0.ɵɵconditionalCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Conditional_3_Template, 2, 0, "span", 51);
271
+ i0.ɵɵelementEnd();
272
+ i0.ɵɵconditionalCreate(4, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_4_Template, 1, 2, "input", 52)(5, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_5_Template, 1, 2, "input", 53)(6, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_6_Template, 1, 3, "input", 54)(7, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_Template, 5, 1, "select", 55)(8, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_Template, 3, 1, "select", 55)(9, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_9_Template, 5, 1, "select", 55)(10, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_Template, 5, 2, "select", 55);
273
+ i0.ɵɵconditionalCreate(11, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Conditional_11_Template, 2, 1, "span", 19);
274
+ i0.ɵɵelementEnd();
275
+ } if (rf & 2) {
276
+ let tmp_16_0;
277
+ const field_r9 = i0.ɵɵnextContext(2).$implicit;
278
+ i0.ɵɵadvance(2);
279
+ i0.ɵɵtextInterpolate1("", field_r9.Label, " ");
280
+ i0.ɵɵadvance();
281
+ i0.ɵɵconditional(field_r9.Required ? 3 : -1);
282
+ i0.ɵɵadvance();
283
+ i0.ɵɵconditional((tmp_16_0 = field_r9.Type) === "url" ? 4 : tmp_16_0 === "path" ? 5 : tmp_16_0 === "text" ? 6 : tmp_16_0 === "entity-picker" ? 7 : tmp_16_0 === "entity-doc-picker" ? 8 : tmp_16_0 === "storage-provider-picker" ? 9 : tmp_16_0 === "dropdown" ? 10 : -1);
284
+ i0.ɵɵadvance(7);
285
+ i0.ɵɵconditional(field_r9.Description ? 11 : -1);
286
+ } }
287
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Template(rf, ctx) { if (rf & 1) {
288
+ i0.ɵɵconditionalCreate(0, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Template, 12, 4, "div", 10);
289
+ } if (rf & 2) {
290
+ const field_r9 = i0.ɵɵnextContext().$implicit;
291
+ const ctx_r1 = i0.ɵɵnextContext(3);
292
+ i0.ɵɵconditional(!field_r9.ShowOnlyIfMultiple || ctx_r1.GetDependentOptions(field_r9).length > 1 ? 0 : -1);
293
+ } }
294
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Template(rf, ctx) { if (rf & 1) {
295
+ i0.ɵɵconditionalCreate(0, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Template, 1, 1);
296
+ } if (rf & 2) {
297
+ const field_r9 = ctx.$implicit;
298
+ const ctx_r1 = i0.ɵɵnextContext(3);
299
+ i0.ɵɵconditional(!field_r9.DependsOnField || ctx_r1.FormSourceSpecificConfig[field_r9.DependsOnField] ? 0 : -1);
300
+ } }
301
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_7_Template(rf, ctx) { if (rf & 1) {
302
+ const _r20 = i0.ɵɵgetCurrentView();
303
+ i0.ɵɵelementStart(0, "button", 64);
304
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_7_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OpenInlineEntityDocForm()); });
305
+ i0.ɵɵelement(1, "i", 65);
306
+ i0.ɵɵtext(2, " Create Entity Document ");
307
+ i0.ɵɵelementEnd();
308
+ } }
309
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_For_10_Template(rf, ctx) { if (rf & 1) {
310
+ const _r22 = i0.ɵɵgetCurrentView();
311
+ i0.ɵɵelementStart(0, "label", 68)(1, "input", 71);
312
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_For_10_Template_input_ngModelChange_1_listener($event) { const f_r23 = i0.ɵɵrestoreView(_r22).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); i0.ɵɵtwoWayBindingSet(ctx_r1.NewEntityDocSelectedFields[f_r23.Name], $event) || (ctx_r1.NewEntityDocSelectedFields[f_r23.Name] = $event); return i0.ɵɵresetView($event); });
313
+ i0.ɵɵelementEnd();
314
+ i0.ɵɵelementStart(2, "span");
315
+ i0.ɵɵtext(3);
316
+ i0.ɵɵelementEnd()();
317
+ } if (rf & 2) {
318
+ const f_r23 = ctx.$implicit;
319
+ const ctx_r1 = i0.ɵɵnextContext(5);
320
+ i0.ɵɵadvance();
321
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.NewEntityDocSelectedFields[f_r23.Name]);
322
+ i0.ɵɵadvance(2);
323
+ i0.ɵɵtextInterpolate(f_r23.DisplayName);
324
+ } }
325
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Conditional_13_Template(rf, ctx) { if (rf & 1) {
326
+ i0.ɵɵelement(0, "i", 72);
327
+ i0.ɵɵtext(1, " Creating\u2026 ");
328
+ } }
329
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Conditional_14_Template(rf, ctx) { if (rf & 1) {
330
+ i0.ɵɵelement(0, "i", 73);
331
+ i0.ɵɵtext(1, " Create ");
332
+ } }
333
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Template(rf, ctx) { if (rf & 1) {
334
+ const _r21 = i0.ɵɵgetCurrentView();
335
+ i0.ɵɵelementStart(0, "div", 63)(1, "div", 10)(2, "label", 11);
336
+ i0.ɵɵtext(3, "Document name");
337
+ i0.ɵɵelementEnd();
338
+ i0.ɵɵelementStart(4, "input", 66);
339
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r1.NewEntityDocName, $event) || (ctx_r1.NewEntityDocName = $event); return i0.ɵɵresetView($event); });
340
+ i0.ɵɵelementEnd()();
341
+ i0.ɵɵelementStart(5, "div", 10)(6, "label", 11);
342
+ i0.ɵɵtext(7);
343
+ i0.ɵɵelementEnd();
344
+ i0.ɵɵelementStart(8, "div", 67);
345
+ i0.ɵɵrepeaterCreate(9, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_For_10_Template, 4, 2, "label", 68, _forTrack4);
346
+ i0.ɵɵelementEnd()();
347
+ i0.ɵɵelementStart(11, "div", 47)(12, "button", 69);
348
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.CreateInlineEntityDocument()); });
349
+ i0.ɵɵconditionalCreate(13, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Conditional_13_Template, 2, 0)(14, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Conditional_14_Template, 2, 0);
350
+ i0.ɵɵelementEnd();
351
+ i0.ɵɵelementStart(15, "button", 70);
352
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.CancelInlineEntityDocForm()); });
353
+ i0.ɵɵtext(16, "Cancel");
354
+ i0.ɵɵelementEnd()()();
355
+ } if (rf & 2) {
356
+ const ctx_r1 = i0.ɵɵnextContext(4);
357
+ i0.ɵɵadvance(4);
358
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.NewEntityDocName);
359
+ i0.ɵɵadvance(3);
360
+ i0.ɵɵtextInterpolate1("Fields to include (", ctx_r1.SelectedEntityDocFieldCount, " selected)");
361
+ i0.ɵɵadvance(2);
362
+ i0.ɵɵrepeater(ctx_r1.SelectedEntityFields);
363
+ i0.ɵɵadvance(3);
364
+ i0.ɵɵproperty("disabled", ctx_r1.EntityDocSaving);
365
+ i0.ɵɵadvance();
366
+ i0.ɵɵconditional(ctx_r1.EntityDocSaving ? 13 : 14);
367
+ } }
368
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Template(rf, ctx) { if (rf & 1) {
369
+ i0.ɵɵelementStart(0, "div", 59)(1, "div", 60);
370
+ i0.ɵɵelement(2, "i", 61);
371
+ i0.ɵɵelementStart(3, "span")(4, "strong");
372
+ i0.ɵɵtext(5);
373
+ i0.ɵɵelementEnd();
374
+ i0.ɵɵtext(6, " has no Entity Document. One is required to classify its records.");
375
+ i0.ɵɵelementEnd()();
376
+ i0.ɵɵconditionalCreate(7, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_7_Template, 3, 0, "button", 62);
377
+ i0.ɵɵelementEnd();
378
+ i0.ɵɵconditionalCreate(8, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Conditional_8_Template, 17, 4, "div", 63);
379
+ } if (rf & 2) {
380
+ const ctx_r1 = i0.ɵɵnextContext(3);
381
+ i0.ɵɵadvance(5);
382
+ i0.ɵɵtextInterpolate(ctx_r1.SelectedEntityName);
383
+ i0.ɵɵadvance(2);
384
+ i0.ɵɵconditional(!ctx_r1.ShowInlineEntityDocForm ? 7 : -1);
385
+ i0.ɵɵadvance();
386
+ i0.ɵɵconditional(ctx_r1.ShowInlineEntityDocForm ? 8 : -1);
387
+ } }
388
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_37_Template(rf, ctx) { if (rf & 1) {
389
+ i0.ɵɵelementStart(0, "option", 15);
390
+ i0.ɵɵtext(1);
391
+ i0.ɵɵelementEnd();
392
+ } if (rf & 2) {
393
+ const opt_r24 = ctx.$implicit;
394
+ i0.ɵɵproperty("value", opt_r24.ID);
395
+ i0.ɵɵadvance();
396
+ i0.ɵɵtextInterpolate(opt_r24.Name);
397
+ } }
398
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_53_Template(rf, ctx) { if (rf & 1) {
399
+ const _r25 = i0.ɵɵgetCurrentView();
400
+ i0.ɵɵelementStart(0, "div", 74);
401
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_53_Template_div_click_0_listener() { const m_r26 = i0.ɵɵrestoreView(_r25).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SetMode(m_r26.value)); });
402
+ i0.ɵɵelement(1, "i");
403
+ i0.ɵɵelementStart(2, "div", 75);
404
+ i0.ɵɵtext(3);
405
+ i0.ɵɵelementEnd();
406
+ i0.ɵɵelementStart(4, "div", 76);
407
+ i0.ɵɵtext(5);
408
+ i0.ɵɵelementEnd()();
409
+ } if (rf & 2) {
410
+ const m_r26 = ctx.$implicit;
411
+ const ctx_r1 = i0.ɵɵnextContext(3);
412
+ i0.ɵɵclassProp("selected", ctx_r1.CurrentMode === m_r26.value);
413
+ i0.ɵɵadvance();
414
+ i0.ɵɵclassMap(i0.ɵɵinterpolate1("fa-solid ", m_r26.icon, " cls-mode-ic"));
415
+ i0.ɵɵadvance(2);
416
+ i0.ɵɵtextInterpolate(m_r26.label);
417
+ i0.ɵɵadvance(2);
418
+ i0.ɵɵtextInterpolate(m_r26.bestFor);
419
+ } }
420
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_61_Template(rf, ctx) { if (rf & 1) {
421
+ i0.ɵɵelementStart(0, "option", 15);
422
+ i0.ɵɵtext(1);
423
+ i0.ɵɵelementEnd();
424
+ } if (rf & 2) {
425
+ const opt_r27 = ctx.$implicit;
426
+ i0.ɵɵproperty("value", opt_r27.ID);
427
+ i0.ɵɵadvance();
428
+ i0.ɵɵtextInterpolate(opt_r27.Name);
429
+ } }
430
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_84_Template(rf, ctx) { if (rf & 1) {
431
+ i0.ɵɵelementStart(0, "div", 32);
432
+ i0.ɵɵelement(1, "i", 77);
433
+ i0.ɵɵtext(2);
434
+ i0.ɵɵelementEnd();
435
+ } if (rf & 2) {
436
+ const ctx_r1 = i0.ɵɵnextContext(3);
437
+ i0.ɵɵadvance(2);
438
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.ThresholdValidationMessage);
439
+ } }
440
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_85_Template(rf, ctx) { if (rf & 1) {
441
+ i0.ɵɵelementStart(0, "div", 33)(1, "span", 78);
442
+ i0.ɵɵtext(2, "reject / new");
443
+ i0.ɵɵelementEnd();
444
+ i0.ɵɵelementStart(3, "span", 79);
445
+ i0.ɵɵtext(4, "review (inbox)");
446
+ i0.ɵɵelementEnd();
447
+ i0.ɵɵelementStart(5, "span", 80);
448
+ i0.ɵɵtext(6, "auto-apply");
449
+ i0.ɵɵelementEnd()();
450
+ } }
451
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_100_For_4_Template(rf, ctx) { if (rf & 1) {
452
+ i0.ɵɵelementStart(0, "div", 82)(1, "span", 83);
453
+ i0.ɵɵtext(2);
454
+ i0.ɵɵelementEnd();
455
+ i0.ɵɵelementStart(3, "span", 84);
456
+ i0.ɵɵtext(4);
457
+ i0.ɵɵelementStart(5, "span", 85);
458
+ i0.ɵɵtext(6);
459
+ i0.ɵɵelementEnd()()();
460
+ } if (rf & 2) {
461
+ const row_r28 = ctx.$implicit;
462
+ i0.ɵɵadvance(2);
463
+ i0.ɵɵtextInterpolate(row_r28.label);
464
+ i0.ɵɵadvance(2);
465
+ i0.ɵɵtextInterpolate1("", row_r28.value, " ");
466
+ i0.ɵɵadvance();
467
+ i0.ɵɵclassProp("override", row_r28.origin === "source override");
468
+ i0.ɵɵadvance();
469
+ i0.ɵɵtextInterpolate(row_r28.origin);
470
+ } }
471
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_100_Template(rf, ctx) { if (rf & 1) {
472
+ i0.ɵɵelementStart(0, "div", 39)(1, "h5", 81);
473
+ i0.ɵɵtext(2, "Effective values");
474
+ i0.ɵɵelementEnd();
475
+ i0.ɵɵrepeaterCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_100_For_4_Template, 7, 5, "div", 82, _forTrack5);
476
+ i0.ɵɵelementEnd();
477
+ } if (rf & 2) {
478
+ const ctx_r1 = i0.ɵɵnextContext(3);
479
+ i0.ɵɵadvance(3);
480
+ i0.ɵɵrepeater(ctx_r1.EffectiveValues);
481
+ } }
482
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_166_Template(rf, ctx) { if (rf & 1) {
483
+ const _r29 = i0.ɵɵgetCurrentView();
484
+ i0.ɵɵelementStart(0, "div", 16)(1, "div", 8);
485
+ i0.ɵɵelement(2, "i", 86);
486
+ i0.ɵɵtext(3, " Crawl settings");
487
+ i0.ɵɵelementEnd();
488
+ i0.ɵɵelementStart(4, "div", 10)(5, "label", 11);
489
+ i0.ɵɵtext(6, "Crawl depth");
490
+ i0.ɵɵelementEnd();
491
+ i0.ɵɵelementStart(7, "input", 87);
492
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_166_Template_input_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormMaxDepth, $event) || (ctx_r1.FormMaxDepth = $event); return i0.ɵɵresetView($event); });
493
+ i0.ɵɵelementEnd();
494
+ i0.ɵɵelementStart(8, "span", 19);
495
+ i0.ɵɵtext(9, " Recursion ceiling for in-domain links. ");
496
+ i0.ɵɵelementStart(10, "code");
497
+ i0.ɵɵtext(11, "0");
498
+ i0.ɵɵelementEnd();
499
+ i0.ɵɵtext(12, " = just the start URL. ");
500
+ i0.ɵɵelementStart(13, "code");
501
+ i0.ɵɵtext(14, "2");
502
+ i0.ɵɵelementEnd();
503
+ i0.ɵɵtext(15, " (default) = root + sections + content pages. ");
504
+ i0.ɵɵelementEnd()();
505
+ i0.ɵɵelementStart(16, "div", 10)(17, "label", 11)(18, "input", 71);
506
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_166_Template_input_ngModelChange_18_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormCrawlSitesInLowerLevelDomain, $event) || (ctx_r1.FormCrawlSitesInLowerLevelDomain = $event); return i0.ɵɵresetView($event); });
507
+ i0.ɵɵelementEnd();
508
+ i0.ɵɵtext(19, " Crawl sites in lower-level domain ");
509
+ i0.ɵɵelementEnd();
510
+ i0.ɵɵelementStart(20, "span", 19);
511
+ i0.ɵɵtext(21, "When on (default), the depth-aware recursive crawler runs. Turn off to crawl only the seed page.");
512
+ i0.ɵɵelementEnd()();
513
+ i0.ɵɵelementStart(22, "div", 10)(23, "label", 11)(24, "input", 71);
514
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_166_Template_input_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormCrawlOtherSitesInTopLevelDomain, $event) || (ctx_r1.FormCrawlOtherSitesInTopLevelDomain = $event); return i0.ɵɵresetView($event); });
515
+ i0.ɵɵelementEnd();
516
+ i0.ɵɵtext(25, " Crawl other sites in top-level domain ");
517
+ i0.ɵɵelementEnd();
518
+ i0.ɵɵelementStart(26, "span", 19);
519
+ i0.ɵɵtext(27, "When on, also adds sibling-path URLs found on the seed page. Off by default to avoid accidental fan-out.");
520
+ i0.ɵɵelementEnd()()();
521
+ } if (rf & 2) {
522
+ const ctx_r1 = i0.ɵɵnextContext(3);
523
+ i0.ɵɵadvance(7);
524
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormMaxDepth);
525
+ i0.ɵɵadvance(11);
526
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormCrawlSitesInLowerLevelDomain);
527
+ i0.ɵɵadvance(6);
528
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormCrawlOtherSitesInTopLevelDomain);
529
+ } }
530
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_169_Template(rf, ctx) { if (rf & 1) {
531
+ i0.ɵɵelement(0, "i", 72);
532
+ i0.ɵɵtext(1, " Saving... ");
533
+ } }
534
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_170_Template(rf, ctx) { if (rf & 1) {
535
+ i0.ɵɵelement(0, "i", 73);
536
+ i0.ɵɵtext(1, " Save ");
537
+ } }
538
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_173_Template(rf, ctx) { if (rf & 1) {
539
+ const _r30 = i0.ɵɵgetCurrentView();
540
+ i0.ɵɵelementStart(0, "div", 50)(1, "a", 88);
541
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_173_Template_a_click_1_listener() { i0.ɵɵrestoreView(_r30); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OpenAdvancedSourceSettings()); });
542
+ i0.ɵɵelement(2, "i", 89);
543
+ i0.ɵɵtext(3, " Open advanced settings \u2014 URL pattern, root URL, & full entity form ");
544
+ i0.ɵɵelementEnd();
545
+ i0.ɵɵelementStart(4, "span", 19);
546
+ i0.ɵɵtext(5, "The key classifier knobs (taxonomy mode, thresholds, tag root, budgets) are now editable inline above.");
547
+ i0.ɵɵelementEnd()();
548
+ } }
549
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template(rf, ctx) { if (rf & 1) {
550
+ const _r3 = i0.ɵɵgetCurrentView();
551
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 8);
552
+ i0.ɵɵelement(2, "i", 9);
553
+ i0.ɵɵtext(3, " Source");
554
+ i0.ɵɵelementEnd();
555
+ i0.ɵɵelementStart(4, "div", 10)(5, "label", 11);
556
+ i0.ɵɵtext(6, "Name");
557
+ i0.ɵɵelementEnd();
558
+ i0.ɵɵelementStart(7, "input", 12);
559
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceName, $event) || (ctx_r1.FormSourceName = $event); return i0.ɵɵresetView($event); });
560
+ i0.ɵɵelementEnd()();
561
+ i0.ɵɵelementStart(8, "div", 10)(9, "label", 11);
562
+ i0.ɵɵtext(10, "Source Type");
563
+ i0.ɵɵelementEnd();
564
+ i0.ɵɵelementStart(11, "select", 13);
565
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_select_ngModelChange_11_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceTypeID, $event) || (ctx_r1.FormSourceTypeID = $event); return i0.ɵɵresetView($event); });
566
+ i0.ɵɵelementStart(12, "option", 14);
567
+ i0.ɵɵtext(13, "Select source type...");
568
+ i0.ɵɵelementEnd();
569
+ i0.ɵɵrepeaterCreate(14, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_15_Template, 2, 2, "option", 15, _forTrack0);
570
+ i0.ɵɵelementEnd()();
571
+ i0.ɵɵconditionalCreate(16, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_Template, 16, 2);
572
+ i0.ɵɵrepeaterCreate(17, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Template, 1, 1, null, null, _forTrack1);
573
+ i0.ɵɵconditionalCreate(19, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_19_Template, 9, 3);
574
+ i0.ɵɵelementEnd();
575
+ i0.ɵɵelementStart(20, "div", 16)(21, "div", 8);
576
+ i0.ɵɵelement(22, "i", 17);
577
+ i0.ɵɵtext(23, " Embedding & Vectors");
578
+ i0.ɵɵelementEnd();
579
+ i0.ɵɵelementStart(24, "div", 10)(25, "label", 11);
580
+ i0.ɵɵtext(26, "Embedding Model Override");
581
+ i0.ɵɵelementEnd();
582
+ i0.ɵɵelementStart(27, "mj-tree-dropdown", 18);
583
+ i0.ɵɵlistener("ValueChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_mj_tree_dropdown_ValueChange_27_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.FormSourceEmbeddingModelID = ctx_r1.FromCompositeKey($event)); });
584
+ i0.ɵɵelementEnd();
585
+ i0.ɵɵelementStart(28, "span", 19);
586
+ i0.ɵɵtext(29, "Overrides Content Type default");
587
+ i0.ɵɵelementEnd()();
588
+ i0.ɵɵelementStart(30, "div", 10)(31, "label", 11);
589
+ i0.ɵɵtext(32, "Vector Index Override");
590
+ i0.ɵɵelementEnd();
591
+ i0.ɵɵelementStart(33, "select", 13);
592
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_select_ngModelChange_33_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormSourceVectorIndexID, $event) || (ctx_r1.FormSourceVectorIndexID = $event); return i0.ɵɵresetView($event); });
593
+ i0.ɵɵelementStart(34, "option", 14);
594
+ i0.ɵɵtext(35, "Use system default");
595
+ i0.ɵɵelementEnd();
596
+ i0.ɵɵrepeaterCreate(36, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_37_Template, 2, 2, "option", 15, _forTrack0);
597
+ i0.ɵɵelementEnd();
598
+ i0.ɵɵelementStart(38, "span", 19);
599
+ i0.ɵɵtext(39, "Overrides Content Type default");
600
+ i0.ɵɵelementEnd()()();
601
+ i0.ɵɵelementStart(40, "div", 16)(41, "div", 8);
602
+ i0.ɵɵelement(42, "i", 20);
603
+ i0.ɵɵtext(43, " Classification ");
604
+ i0.ɵɵelementStart(44, "button", 21);
605
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_button_click_44_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleEffectiveValues()); });
606
+ i0.ɵɵelement(45, "i", 22);
607
+ i0.ɵɵtext(46);
608
+ i0.ɵɵelementEnd()();
609
+ i0.ɵɵelementStart(47, "div", 23)(48, "div", 10)(49, "label", 11);
610
+ i0.ɵɵtext(50, "Taxonomy mode");
611
+ i0.ɵɵelementEnd();
612
+ i0.ɵɵelementStart(51, "div", 24);
613
+ i0.ɵɵrepeaterCreate(52, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_53_Template, 6, 7, "div", 25, _forTrack2);
614
+ i0.ɵɵelementEnd()();
615
+ i0.ɵɵelementStart(54, "div", 10)(55, "label", 11);
616
+ i0.ɵɵtext(56, "Tag root");
617
+ i0.ɵɵelementEnd();
618
+ i0.ɵɵelementStart(57, "select", 13);
619
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_select_ngModelChange_57_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.TagRootIDValue, $event) || (ctx_r1.TagRootIDValue = $event); return i0.ɵɵresetView($event); });
620
+ i0.ɵɵelementStart(58, "option", 14);
621
+ i0.ɵɵtext(59, "(none / whole taxonomy)");
622
+ i0.ɵɵelementEnd();
623
+ i0.ɵɵrepeaterCreate(60, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_61_Template, 2, 2, "option", 15, _forTrack0);
624
+ i0.ɵɵelementEnd();
625
+ i0.ɵɵelementStart(62, "span", 19);
626
+ i0.ɵɵtext(63, "Restricts the LLM's visible taxonomy + auto-grow target. Leave blank for the full taxonomy.");
627
+ i0.ɵɵelementEnd()();
628
+ i0.ɵɵelementStart(64, "div", 10)(65, "label", 11);
629
+ i0.ɵɵtext(66, "Confidence thresholds");
630
+ i0.ɵɵelementEnd();
631
+ i0.ɵɵelementStart(67, "div", 26)(68, "div", 27)(69, "div", 28)(70, "span", 29);
632
+ i0.ɵɵtext(71, "Match (auto-apply) ");
633
+ i0.ɵɵelementStart(72, "strong");
634
+ i0.ɵɵtext(73);
635
+ i0.ɵɵpipe(74, "number");
636
+ i0.ɵɵelementEnd()();
637
+ i0.ɵɵelementStart(75, "input", 30);
638
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_75_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MatchThresholdValue = $event); });
639
+ i0.ɵɵelementEnd()();
640
+ i0.ɵɵelementStart(76, "div", 28)(77, "span", 29);
641
+ i0.ɵɵtext(78, "Suggest (route to inbox) ");
642
+ i0.ɵɵelementStart(79, "strong");
643
+ i0.ɵɵtext(80);
644
+ i0.ɵɵpipe(81, "number");
645
+ i0.ɵɵelementEnd()();
646
+ i0.ɵɵelementStart(82, "input", 30);
647
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_82_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SuggestThresholdValue = $event); });
648
+ i0.ɵɵelementEnd()()();
649
+ i0.ɵɵelement(83, "div", 31);
650
+ i0.ɵɵconditionalCreate(84, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_84_Template, 3, 1, "div", 32)(85, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_85_Template, 7, 0, "div", 33);
651
+ i0.ɵɵelementEnd()();
652
+ i0.ɵɵelementStart(86, "div", 34)(87, "div", 35)(88, "span", 36);
653
+ i0.ɵɵtext(89, "Share full taxonomy with the LLM");
654
+ i0.ɵɵelementEnd();
655
+ i0.ɵɵelementStart(90, "span", 37);
656
+ i0.ɵɵtext(91, "When on, the LLM prompt includes the visible taxonomy. Larger taxonomies \u2192 higher token cost.");
657
+ i0.ɵɵelementEnd()();
658
+ i0.ɵɵelementStart(92, "mj-switch", 38);
659
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_mj_switch_ngModelChange_92_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.ShareTaxonomyValue, $event) || (ctx_r1.ShareTaxonomyValue = $event); return i0.ɵɵresetView($event); });
660
+ i0.ɵɵelementEnd()();
661
+ i0.ɵɵelementStart(93, "div", 34)(94, "div", 35)(95, "span", 36);
662
+ i0.ɵɵtext(96, "Vectorize new content");
663
+ i0.ɵɵelementEnd();
664
+ i0.ɵɵelementStart(97, "span", 37);
665
+ i0.ɵɵtext(98, "When off, this source skips vectorization (the classifier still runs).");
666
+ i0.ɵɵelementEnd()();
667
+ i0.ɵɵelementStart(99, "mj-switch", 38);
668
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_mj_switch_ngModelChange_99_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.EnableVectorizationValue, $event) || (ctx_r1.EnableVectorizationValue = $event); return i0.ɵɵresetView($event); });
669
+ i0.ɵɵelementEnd()()();
670
+ i0.ɵɵconditionalCreate(100, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_100_Template, 5, 0, "div", 39);
671
+ i0.ɵɵelementEnd();
672
+ i0.ɵɵelementStart(101, "div", 16)(102, "div", 8);
673
+ i0.ɵɵelement(103, "i", 40);
674
+ i0.ɵɵtext(104, " Domain context");
675
+ i0.ɵɵelementEnd();
676
+ i0.ɵɵelementStart(105, "div", 10)(106, "label", 11);
677
+ i0.ɵɵtext(107, "Source guidance");
678
+ i0.ɵɵelementEnd();
679
+ i0.ɵɵelementStart(108, "textarea", 41);
680
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_textarea_ngModelChange_108_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ClassificationContextValue = $event); });
681
+ i0.ɵɵelementEnd();
682
+ i0.ɵɵelementStart(109, "span", 19);
683
+ i0.ɵɵtext(110, "Injected into the autotagging prompt at the source scope.");
684
+ i0.ɵɵelementEnd()();
685
+ i0.ɵɵelementStart(111, "div", 34)(112, "div", 35)(113, "span", 36);
686
+ i0.ɵɵtext(114, "Substitutive mode");
687
+ i0.ɵɵelementEnd();
688
+ i0.ɵɵelementStart(115, "span", 37);
689
+ i0.ɵɵtext(116, "When on, this source's guidance ");
690
+ i0.ɵɵelementStart(117, "em");
691
+ i0.ɵɵtext(118, "replaces");
692
+ i0.ɵɵelementEnd();
693
+ i0.ɵɵtext(119, " the org/content-type context. When off (default), it's ");
694
+ i0.ɵɵelementStart(120, "em");
695
+ i0.ɵɵtext(121, "added");
696
+ i0.ɵɵelementEnd();
697
+ i0.ɵɵtext(122, " to them.");
698
+ i0.ɵɵelementEnd()();
699
+ i0.ɵɵelementStart(123, "mj-switch", 38);
700
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_mj_switch_ngModelChange_123_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.IsSubstitutiveMode, $event) || (ctx_r1.IsSubstitutiveMode = $event); return i0.ɵɵresetView($event); });
701
+ i0.ɵɵelementEnd()();
702
+ i0.ɵɵelementStart(124, "div", 10)(125, "label", 11);
703
+ i0.ɵɵtext(126, "Effective context preview");
704
+ i0.ɵɵelementEnd();
705
+ i0.ɵɵelementStart(127, "pre", 42);
706
+ i0.ɵɵtext(128);
707
+ i0.ɵɵelementEnd();
708
+ i0.ɵɵelementStart(129, "span", 19);
709
+ i0.ɵɵtext(130, "Org + source scopes shown. Content-type scope (if any) is also merged at run time.");
710
+ i0.ɵɵelementEnd()()();
711
+ i0.ɵɵelementStart(131, "div", 16)(132, "div", 8);
712
+ i0.ɵɵelement(133, "i", 43);
713
+ i0.ɵɵtext(134, " Run budgets");
714
+ i0.ɵɵelementEnd();
715
+ i0.ɵɵelementStart(135, "div", 10)(136, "label", 11);
716
+ i0.ɵɵtext(137, "Max items per run");
717
+ i0.ɵɵelementEnd();
718
+ i0.ɵɵelementStart(138, "input", 44);
719
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_138_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormMaxItemsPerRun, $event) || (ctx_r1.FormMaxItemsPerRun = $event); return i0.ɵɵresetView($event); });
720
+ i0.ɵɵelementEnd();
721
+ i0.ɵɵelementStart(139, "span", 19);
722
+ i0.ɵɵtext(140, " Caps the number of content items handed to the LLM. Skipped (unchanged) items don't count. Paused work resumes on the next run. ");
723
+ i0.ɵɵelementEnd()();
724
+ i0.ɵɵelementStart(141, "div", 45)(142, "div", 10)(143, "label", 11);
725
+ i0.ɵɵtext(144, "Max new tags / run");
726
+ i0.ɵɵelementEnd();
727
+ i0.ɵɵelementStart(145, "input", 44);
728
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_145_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MaxNewTagsPerRunValue = $event); });
729
+ i0.ɵɵelementEnd();
730
+ i0.ɵɵelementStart(146, "span", 19);
731
+ i0.ɵɵtext(147, "across all items");
732
+ i0.ɵɵelementEnd()();
733
+ i0.ɵɵelementStart(148, "div", 10)(149, "label", 11);
734
+ i0.ɵɵtext(150, "Max new tags / item");
735
+ i0.ɵɵelementEnd();
736
+ i0.ɵɵelementStart(151, "input", 44);
737
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_151_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MaxNewTagsPerItemValue = $event); });
738
+ i0.ɵɵelementEnd();
739
+ i0.ɵɵelementStart(152, "span", 19);
740
+ i0.ɵɵtext(153, "extras \u2192 suggestions");
741
+ i0.ɵɵelementEnd()();
742
+ i0.ɵɵelementStart(154, "div", 10)(155, "label", 11);
743
+ i0.ɵɵtext(156, "Max tokens / run");
744
+ i0.ɵɵelementEnd();
745
+ i0.ɵɵelementStart(157, "input", 44);
746
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_157_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MaxTokensPerRunValue = $event); });
747
+ i0.ɵɵelementEnd();
748
+ i0.ɵɵelementStart(158, "span", 19);
749
+ i0.ɵɵtext(159, "across all LLM calls");
750
+ i0.ɵɵelementEnd()();
751
+ i0.ɵɵelementStart(160, "div", 10)(161, "label", 11);
752
+ i0.ɵɵtext(162, "Max cost / run (USD)");
753
+ i0.ɵɵelementEnd();
754
+ i0.ɵɵelementStart(163, "input", 46);
755
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_163_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MaxCostPerRunValue = $event); });
756
+ i0.ɵɵelementEnd();
757
+ i0.ɵɵelementStart(164, "span", 19);
758
+ i0.ɵɵtext(165, "$ stops the run");
759
+ i0.ɵɵelementEnd()()()();
760
+ i0.ɵɵconditionalCreate(166, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_166_Template, 28, 3, "div", 16);
761
+ i0.ɵɵelementStart(167, "div", 47)(168, "button", 48);
762
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_button_click_168_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SaveSource()); });
763
+ i0.ɵɵconditionalCreate(169, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_169_Template, 2, 0)(170, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_170_Template, 2, 0);
764
+ i0.ɵɵelementEnd();
765
+ i0.ɵɵelementStart(171, "button", 49);
766
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_button_click_171_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.CloseForm()); });
767
+ i0.ɵɵtext(172, "Cancel");
768
+ i0.ɵɵelementEnd()();
769
+ i0.ɵɵconditionalCreate(173, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_173_Template, 6, 0, "div", 50);
770
+ } if (rf & 2) {
771
+ const ctx_r1 = i0.ɵɵnextContext(2);
772
+ i0.ɵɵadvance(7);
773
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceName);
774
+ i0.ɵɵadvance(4);
775
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceTypeID);
776
+ i0.ɵɵadvance(3);
777
+ i0.ɵɵrepeater(ctx_r1.SourceTypeOptions);
778
+ i0.ɵɵadvance(2);
779
+ i0.ɵɵconditional(ctx_r1.SelectedSourceTypeRequiresContentType ? 16 : -1);
780
+ i0.ɵɵadvance();
781
+ i0.ɵɵrepeater(ctx_r1.SelectedSourceTypeFields);
782
+ i0.ɵɵadvance(2);
783
+ i0.ɵɵconditional(ctx_r1.SelectedEntityHasNoDocument ? 19 : -1);
784
+ i0.ɵɵadvance(8);
785
+ i0.ɵɵproperty("BranchConfig", ctx_r1.EmbeddingVendorBranch)("LeafConfig", ctx_r1.EmbeddingModelsLeaf)("Clearable", true)("Value", ctx_r1.ToCompositeKey(ctx_r1.FormSourceEmbeddingModelID));
786
+ i0.ɵɵadvance(6);
787
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceVectorIndexID);
788
+ i0.ɵɵadvance(3);
789
+ i0.ɵɵrepeater(ctx_r1.VectorIndexOptions);
790
+ i0.ɵɵadvance(9);
791
+ i0.ɵɵclassProp("fa-eye", !ctx_r1.ShowEffectiveValues)("fa-eye-slash", ctx_r1.ShowEffectiveValues);
792
+ i0.ɵɵadvance();
793
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.ShowEffectiveValues ? "Hide effective values" : "Show effective values", " ");
794
+ i0.ɵɵadvance(6);
795
+ i0.ɵɵrepeater(ctx_r1.TaxonomyModes);
796
+ i0.ɵɵadvance(5);
797
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.TagRootIDValue);
798
+ i0.ɵɵadvance(3);
799
+ i0.ɵɵrepeater(ctx_r1.TagRootOptions);
800
+ i0.ɵɵadvance(13);
801
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(74, 35, ctx_r1.MatchThresholdValue, "1.2-2"));
802
+ i0.ɵɵadvance(2);
803
+ i0.ɵɵproperty("ngModel", ctx_r1.MatchThresholdValue);
804
+ i0.ɵɵadvance(5);
805
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(81, 38, ctx_r1.SuggestThresholdValue, "1.2-2"));
806
+ i0.ɵɵadvance(2);
807
+ i0.ɵɵproperty("ngModel", ctx_r1.SuggestThresholdValue);
808
+ i0.ɵɵadvance(2);
809
+ i0.ɵɵconditional(ctx_r1.ThresholdValidationMessage ? 84 : 85);
810
+ i0.ɵɵadvance(8);
811
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.ShareTaxonomyValue);
812
+ i0.ɵɵadvance(7);
813
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EnableVectorizationValue);
814
+ i0.ɵɵadvance();
815
+ i0.ɵɵconditional(ctx_r1.ShowEffectiveValues ? 100 : -1);
816
+ i0.ɵɵadvance(8);
817
+ i0.ɵɵproperty("ngModel", ctx_r1.ClassificationContextValue);
818
+ i0.ɵɵadvance(15);
819
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.IsSubstitutiveMode);
820
+ i0.ɵɵadvance(5);
821
+ i0.ɵɵtextInterpolate(ctx_r1.EffectiveContextPreview);
822
+ i0.ɵɵadvance(10);
823
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormMaxItemsPerRun);
824
+ i0.ɵɵadvance(7);
825
+ i0.ɵɵproperty("ngModel", ctx_r1.MaxNewTagsPerRunValue ?? "");
826
+ i0.ɵɵadvance(6);
827
+ i0.ɵɵproperty("ngModel", ctx_r1.MaxNewTagsPerItemValue ?? "");
828
+ i0.ɵɵadvance(6);
829
+ i0.ɵɵproperty("ngModel", ctx_r1.MaxTokensPerRunValue ?? "");
830
+ i0.ɵɵadvance(6);
831
+ i0.ɵɵproperty("ngModel", ctx_r1.MaxCostPerRunValue ?? "");
832
+ i0.ɵɵadvance(3);
833
+ i0.ɵɵconditional(ctx_r1.IsWebsiteSourceTypeSelected ? 166 : -1);
834
+ i0.ɵɵadvance(2);
835
+ i0.ɵɵproperty("disabled", ctx_r1.FormSaving);
836
+ i0.ɵɵadvance();
837
+ i0.ɵɵconditional(ctx_r1.FormSaving ? 169 : 170);
838
+ i0.ɵɵadvance(4);
839
+ i0.ɵɵconditional(ctx_r1.FormMode === "edit-source" && ctx_r1.EditingSourceID ? 173 : -1);
840
+ } }
841
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_For_32_Template(rf, ctx) { if (rf & 1) {
842
+ i0.ɵɵelementStart(0, "option", 15);
843
+ i0.ɵɵtext(1);
844
+ i0.ɵɵelementEnd();
845
+ } if (rf & 2) {
846
+ const opt_r32 = ctx.$implicit;
847
+ i0.ɵɵproperty("value", opt_r32.ID);
848
+ i0.ɵɵadvance();
849
+ i0.ɵɵtextInterpolate(opt_r32.Name);
850
+ } }
851
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Conditional_35_Template(rf, ctx) { if (rf & 1) {
852
+ i0.ɵɵelement(0, "i", 72);
853
+ i0.ɵɵtext(1, " Saving... ");
854
+ } }
855
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Conditional_36_Template(rf, ctx) { if (rf & 1) {
856
+ i0.ɵɵelement(0, "i", 73);
857
+ i0.ɵɵtext(1, " Save ");
858
+ } }
859
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template(rf, ctx) { if (rf & 1) {
860
+ const _r31 = i0.ɵɵgetCurrentView();
861
+ i0.ɵɵelementStart(0, "div", 10)(1, "label", 11);
862
+ i0.ɵɵtext(2, "Name");
863
+ i0.ɵɵelementEnd();
864
+ i0.ɵɵelementStart(3, "input", 90);
865
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeName, $event) || (ctx_r1.FormTypeName = $event); return i0.ɵɵresetView($event); });
866
+ i0.ɵɵelementEnd()();
867
+ i0.ɵɵelementStart(4, "div", 10)(5, "label", 11);
868
+ i0.ɵɵtext(6, "Description");
869
+ i0.ɵɵelementEnd();
870
+ i0.ɵɵelementStart(7, "textarea", 91);
871
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_textarea_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeDescription, $event) || (ctx_r1.FormTypeDescription = $event); return i0.ɵɵresetView($event); });
872
+ i0.ɵɵelementEnd()();
873
+ i0.ɵɵelementStart(8, "div", 10)(9, "label", 11);
874
+ i0.ɵɵtext(10, "AI Model (for tagging)");
875
+ i0.ɵɵelementEnd();
876
+ i0.ɵɵelementStart(11, "mj-tree-dropdown", 92);
877
+ i0.ɵɵlistener("ValueChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_mj_tree_dropdown_ValueChange_11_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.FormTypeAIModelID = ctx_r1.FromCompositeKey($event)); });
878
+ i0.ɵɵelementEnd()();
879
+ i0.ɵɵelementStart(12, "div", 93)(13, "div", 94)(14, "label", 11);
880
+ i0.ɵɵtext(15, "Min Tags");
881
+ i0.ɵɵelementEnd();
882
+ i0.ɵɵelementStart(16, "input", 95);
883
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_input_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeMinTags, $event) || (ctx_r1.FormTypeMinTags = $event); return i0.ɵɵresetView($event); });
884
+ i0.ɵɵelementEnd()();
885
+ i0.ɵɵelementStart(17, "div", 94)(18, "label", 11);
886
+ i0.ɵɵtext(19, "Max Tags");
887
+ i0.ɵɵelementEnd();
888
+ i0.ɵɵelementStart(20, "input", 96);
889
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_input_ngModelChange_20_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeMaxTags, $event) || (ctx_r1.FormTypeMaxTags = $event); return i0.ɵɵresetView($event); });
890
+ i0.ɵɵelementEnd()()();
891
+ i0.ɵɵelementStart(21, "div", 10)(22, "label", 11);
892
+ i0.ɵɵtext(23, "Embedding Model");
893
+ i0.ɵɵelementEnd();
894
+ i0.ɵɵelementStart(24, "mj-tree-dropdown", 18);
895
+ i0.ɵɵlistener("ValueChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_mj_tree_dropdown_ValueChange_24_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.FormTypeEmbeddingModelID = ctx_r1.FromCompositeKey($event)); });
896
+ i0.ɵɵelementEnd()();
897
+ i0.ɵɵelementStart(25, "div", 10)(26, "label", 11);
898
+ i0.ɵɵtext(27, "Vector Index");
899
+ i0.ɵɵelementEnd();
900
+ i0.ɵɵelementStart(28, "select", 13);
901
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_select_ngModelChange_28_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeVectorIndexID, $event) || (ctx_r1.FormTypeVectorIndexID = $event); return i0.ɵɵresetView($event); });
902
+ i0.ɵɵelementStart(29, "option", 14);
903
+ i0.ɵɵtext(30, "Use system default");
904
+ i0.ɵɵelementEnd();
905
+ i0.ɵɵrepeaterCreate(31, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_For_32_Template, 2, 2, "option", 15, _forTrack0);
906
+ i0.ɵɵelementEnd()();
907
+ i0.ɵɵelementStart(33, "div", 47)(34, "button", 48);
908
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_button_click_34_listener() { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SaveContentType()); });
909
+ i0.ɵɵconditionalCreate(35, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Conditional_35_Template, 2, 0)(36, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Conditional_36_Template, 2, 0);
910
+ i0.ɵɵelementEnd();
911
+ i0.ɵɵelementStart(37, "button", 49);
912
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_button_click_37_listener() { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.CloseForm()); });
913
+ i0.ɵɵtext(38, "Cancel");
914
+ i0.ɵɵelementEnd()();
915
+ } if (rf & 2) {
916
+ const ctx_r1 = i0.ɵɵnextContext(2);
917
+ i0.ɵɵadvance(3);
918
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeName);
919
+ i0.ɵɵadvance(4);
920
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeDescription);
921
+ i0.ɵɵadvance(4);
922
+ i0.ɵɵproperty("BranchConfig", ctx_r1.AIModelVendorBranch)("LeafConfig", ctx_r1.AllModelsLeaf)("Clearable", true)("Value", ctx_r1.ToCompositeKey(ctx_r1.FormTypeAIModelID));
923
+ i0.ɵɵadvance(5);
924
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeMinTags);
925
+ i0.ɵɵadvance(4);
926
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeMaxTags);
927
+ i0.ɵɵadvance(4);
928
+ i0.ɵɵproperty("BranchConfig", ctx_r1.EmbeddingVendorBranch)("LeafConfig", ctx_r1.EmbeddingModelsLeaf)("Clearable", true)("Value", ctx_r1.ToCompositeKey(ctx_r1.FormTypeEmbeddingModelID));
929
+ i0.ɵɵadvance(4);
930
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeVectorIndexID);
931
+ i0.ɵɵadvance(3);
932
+ i0.ɵɵrepeater(ctx_r1.VectorIndexOptions);
933
+ i0.ɵɵadvance(3);
934
+ i0.ɵɵproperty("disabled", ctx_r1.FormSaving);
935
+ i0.ɵɵadvance();
936
+ i0.ɵɵconditional(ctx_r1.FormSaving ? 35 : 36);
937
+ } }
938
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
939
+ const _r1 = i0.ɵɵgetCurrentView();
940
+ i0.ɵɵelementStart(0, "div", 0);
941
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseForm()); });
942
+ i0.ɵɵelementEnd();
943
+ i0.ɵɵelementStart(1, "div", 1)(2, "div", 2);
944
+ i0.ɵɵlistener("mousedown", function ClassifySourceTypeFormDialogComponent_Conditional_0_Template_div_mousedown_2_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.StartResize($event)); });
945
+ i0.ɵɵelementEnd();
946
+ i0.ɵɵelementStart(3, "div", 3)(4, "h3");
947
+ i0.ɵɵconditionalCreate(5, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_5_Template, 1, 0)(6, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_6_Template, 1, 0)(7, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_7_Template, 1, 0)(8, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_8_Template, 1, 0);
948
+ i0.ɵɵelementEnd();
949
+ i0.ɵɵelementStart(9, "button", 4);
950
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseForm()); });
951
+ i0.ɵɵelement(10, "i", 5);
952
+ i0.ɵɵelementEnd()();
953
+ i0.ɵɵelementStart(11, "div", 6);
954
+ i0.ɵɵconditionalCreate(12, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template, 174, 41);
955
+ i0.ɵɵconditionalCreate(13, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template, 39, 15);
956
+ i0.ɵɵelementEnd()();
957
+ } if (rf & 2) {
958
+ const ctx_r1 = i0.ɵɵnextContext();
959
+ i0.ɵɵadvance();
960
+ i0.ɵɵstyleProp("width", ctx_r1.PanelWidth, "px");
961
+ i0.ɵɵadvance(4);
962
+ i0.ɵɵconditional(ctx_r1.FormMode === "add-source" ? 5 : ctx_r1.FormMode === "edit-source" ? 6 : ctx_r1.FormMode === "add-type" ? 7 : ctx_r1.FormMode === "edit-type" ? 8 : -1);
963
+ i0.ɵɵadvance(7);
964
+ i0.ɵɵconditional(ctx_r1.FormMode === "add-source" || ctx_r1.FormMode === "edit-source" ? 12 : -1);
965
+ i0.ɵɵadvance();
966
+ i0.ɵɵconditional(ctx_r1.FormMode === "add-type" || ctx_r1.FormMode === "edit-type" ? 13 : -1);
967
+ } }
968
+ /**
969
+ * Application name used to resolve the Knowledge Hub Application ID for the
970
+ * org-level classification-context ApplicationSetting. Mirrors the server-side
971
+ * `KNOWLEDGE_HUB_APPLICATION_NAME` constant.
972
+ */
973
+ export const KNOWLEDGE_HUB_APPLICATION_NAME = 'Knowledge Hub';
974
+ /** ApplicationSetting key under which the org-level classification context lives. */
975
+ export const CLASSIFY_ORG_CONTEXT_SETTING_KEY = 'classify.org.context';
976
+ /** Default classifier knob values — mirrors the autotagger's runtime defaults + the reference panel. */
977
+ const DEFAULT_TAXONOMY_MODE = 'auto-grow';
978
+ const DEFAULT_MATCH_THRESHOLD = 0.85;
979
+ const SUGGEST_THRESHOLD_GAP = 0.05;
980
+ const DEFAULT_SHARE_TAXONOMY = true;
981
+ const DEFAULT_ENABLE_VECTORIZATION = true;
982
+ /** Slide-in panel width bounds + default. The source form is field-rich, so it
983
+ * defaults wider than the host's 420px shared default. */
984
+ const PANEL_WIDTH_DEFAULT = 640;
985
+ const PANEL_WIDTH_MIN = 420;
986
+ /** UserInfoEngine setting key for the remembered source-form panel width. */
987
+ const PANEL_WIDTH_SETTING_KEY = 'mj.classify.sourceForm.width';
988
+ export class ClassifySourceTypeFormDialogComponent extends BaseAngularComponent {
989
+ cdr = inject(ChangeDetectorRef);
990
+ zone = inject(NgZone);
991
+ // ── Resizable panel state ──
992
+ /** Current slide-in panel width (px). Bound to the panel via [style.width.px]. */
993
+ PanelWidth = PANEL_WIDTH_DEFAULT;
994
+ /** Whether the inline "Effective values" panel is shown in the Classification section. */
995
+ ShowEffectiveValues = false;
996
+ /** Active-drag bookkeeping for the left-edge resize handle. */
997
+ isResizing = false;
998
+ resizeMoveListener = null;
999
+ resizeUpListener = null;
1000
+ // ── Cross-tab / host intents ──
1001
+ /** Emitted after a successful save so the host reloads the relevant shared data. */
1002
+ Saved = new EventEmitter();
1003
+ /** Emitted when a source save is blocked because no content type exists. */
1004
+ ContentTypeMissing = new EventEmitter();
1005
+ /** Emitted when the user opts into the full entity form (advanced settings). */
1006
+ NavigateToRecordRequested = new EventEmitter();
1007
+ // ── Slide-in form state ──
1008
+ FormMode = 'none';
1009
+ FormSaving = false;
1010
+ // Source form fields
1011
+ FormSourceName = '';
1012
+ FormSourceTypeID = '';
1013
+ FormContentTypeID = '';
1014
+ FormFileTypeID = '';
1015
+ FormSourceURL = '';
1016
+ EditingSourceID = '';
1017
+ // Content Type form fields
1018
+ FormTypeName = '';
1019
+ FormTypeDescription = '';
1020
+ FormTypeAIModelID = '';
1021
+ FormTypeMinTags = 1;
1022
+ FormTypeMaxTags = 10;
1023
+ EditingTypeID = '';
1024
+ // Embedding model + vector index form fields (Content Type)
1025
+ FormTypeEmbeddingModelID = '';
1026
+ FormTypeVectorIndexID = '';
1027
+ // Entity source fields (shown when source type is "Entity")
1028
+ FormSourceEntityID = '';
1029
+ FormSourceEntityDocID = '';
1030
+ // ── Inline Entity Document creation ──────────────────────────────────────
1031
+ // When the selected Entity-type source's entity has no Entity Document, the
1032
+ // form shows a callout + an inline create sub-form so the operator doesn't
1033
+ // have to leave the wizard to set one up.
1034
+ /** Whether the inline "Create Entity Document" sub-form is expanded. */
1035
+ ShowInlineEntityDocForm = false;
1036
+ /** Saving spinner for the inline Entity Document create. */
1037
+ EntityDocSaving = false;
1038
+ /** Name for the new Entity Document (auto-filled from the entity). */
1039
+ NewEntityDocName = '';
1040
+ /** Selected field names to include in the new Entity Document template. */
1041
+ NewEntityDocSelectedFields = {};
1042
+ // Embedding model + vector index form fields (Content Source overrides)
1043
+ FormSourceEmbeddingModelID = '';
1044
+ FormSourceVectorIndexID = '';
1045
+ // Slide-in is the QUICK-EDIT surface for content sources. We only expose the
1046
+ // most-useful subset of the new knobs here; the full surface (other budgets,
1047
+ // URL pattern, root URL, taxonomy mode, thresholds, …) lives on the entity
1048
+ // form opened via the "Open Advanced settings →" link below.
1049
+ //
1050
+ // Decisions:
1051
+ // - MaxItemsPerRun: the single most-asked-for cap → always shown
1052
+ // - MaxDepth + the two crawl toggles: Website-only, the symptom that
1053
+ // started this whole work
1054
+ // - Everything else: too niche for the quick-edit surface
1055
+ FormMaxItemsPerRun = null;
1056
+ FormMaxDepth = null;
1057
+ FormCrawlSitesInLowerLevelDomain = true;
1058
+ FormCrawlOtherSitesInTopLevelDomain = false;
1059
+ // ── Classification (full config parity) ──────────────────────────────
1060
+ // The classifier knobs that used to require navigating out to the entity
1061
+ // form's "advanced settings" are now edited inline. They live on the typed
1062
+ // Configuration JSON (`MJContentSourceEntity_IContentSourceConfiguration`),
1063
+ // accessed via the `Config` getter / `setConfig` merge helper below.
1064
+ //
1065
+ // For EDIT we hydrate `workingConfig` from the loaded source's
1066
+ // ConfigurationObject; for ADD we start from {} and accumulate. On SAVE the
1067
+ // working config is merged into the entity's ConfigurationObject so we never
1068
+ // clobber Website / SourceSpecificConfiguration sub-objects.
1069
+ workingConfig = {};
1070
+ /** Selectable taxonomy-mode cards. Exactly the three modes the type allows — no 'hybrid'. */
1071
+ TaxonomyModes = [
1072
+ { value: 'constrained', label: 'Constrained', icon: 'fa-lock', bestFor: 'Curated, regulated taxonomies' },
1073
+ { value: 'auto-grow', label: 'Auto-Grow', icon: 'fa-seedling', bestFor: 'Bounded growth under a tag root' },
1074
+ { value: 'free-flow', label: 'Free-Flow', icon: 'fa-water', bestFor: 'Sandbox — anything goes' },
1075
+ ];
1076
+ /** Tags eligible to be the taxonomy root (loaded from TagEngineBase). */
1077
+ TagRootOptions = [];
1078
+ // ── Config accessor + merge helper (mirrors TagPipelineConfigurationPanel) ──
1079
+ /** The working classifier config — never null; defaults are applied by the typed getters below. */
1080
+ get Config() {
1081
+ return this.workingConfig;
1082
+ }
1083
+ /** Merge a partial patch into the working config (immutable spread, like the reference panel). */
1084
+ setConfig(patch) {
1085
+ this.workingConfig = { ...this.workingConfig, ...patch };
1086
+ }
1087
+ // Taxonomy mode
1088
+ get CurrentMode() {
1089
+ return this.Config.TagTaxonomyMode ?? DEFAULT_TAXONOMY_MODE;
1090
+ }
1091
+ SetMode(mode) {
1092
+ this.setConfig({ TagTaxonomyMode: mode });
1093
+ }
1094
+ // Thresholds — match auto-applies; suggest routes to inbox. When match moves
1095
+ // and suggest is unset/above it, default suggest to max(0, match - 0.05).
1096
+ get MatchThresholdValue() {
1097
+ return this.Config.TagMatchThreshold ?? DEFAULT_MATCH_THRESHOLD;
1098
+ }
1099
+ set MatchThresholdValue(v) {
1100
+ const clamped = Math.max(0, Math.min(1, Number(v) || 0));
1101
+ const cur = this.Config.SuggestThreshold;
1102
+ const patch = { TagMatchThreshold: clamped };
1103
+ if (cur == null || cur >= clamped) {
1104
+ patch.SuggestThreshold = Math.max(0, clamped - SUGGEST_THRESHOLD_GAP);
1105
+ }
1106
+ this.setConfig(patch);
1107
+ }
1108
+ get SuggestThresholdValue() {
1109
+ return this.Config.SuggestThreshold ?? Math.max(0, this.MatchThresholdValue - SUGGEST_THRESHOLD_GAP);
1110
+ }
1111
+ set SuggestThresholdValue(v) {
1112
+ const clamped = Math.max(0, Math.min(this.MatchThresholdValue, Number(v) || 0));
1113
+ this.setConfig({ SuggestThreshold: clamped });
1114
+ }
1115
+ get ThresholdValidationMessage() {
1116
+ const m = this.Config.TagMatchThreshold;
1117
+ const s = this.Config.SuggestThreshold;
1118
+ if (m != null && s != null && s >= m) {
1119
+ return 'Suggest threshold must be lower than the match threshold.';
1120
+ }
1121
+ return null;
1122
+ }
1123
+ // Tag root + toggles
1124
+ get TagRootIDValue() {
1125
+ return this.Config.TagRootID ?? '';
1126
+ }
1127
+ set TagRootIDValue(v) {
1128
+ this.setConfig({ TagRootID: v ? v : null });
1129
+ }
1130
+ get ShareTaxonomyValue() {
1131
+ return this.Config.ShareTaxonomyWithLLM !== false; // default true
1132
+ }
1133
+ set ShareTaxonomyValue(v) {
1134
+ this.setConfig({ ShareTaxonomyWithLLM: v });
1135
+ }
1136
+ get EnableVectorizationValue() {
1137
+ return this.Config.EnableVectorization !== false; // default true
1138
+ }
1139
+ set EnableVectorizationValue(v) {
1140
+ this.setConfig({ EnableVectorization: v });
1141
+ }
1142
+ // ── Domain context (source scope) ──────────────────────────────────────
1143
+ // Free-text guidance + combine mode persisted into the source Configuration
1144
+ // JSON. The server-side ClassificationContextResolver reads these and combines
1145
+ // them with the org-level and content-type-level scopes when autotagging runs.
1146
+ /** Source-level domain-context free text. */
1147
+ get ClassificationContextValue() {
1148
+ return this.Config.ClassificationContext ?? '';
1149
+ }
1150
+ set ClassificationContextValue(v) {
1151
+ const trimmed = (v ?? '').length > 0 ? v : undefined;
1152
+ this.setConfig({ ClassificationContext: trimmed });
1153
+ this.cdr.detectChanges();
1154
+ }
1155
+ /** Whether this source's context is additive (concatenated) or substitutive (most-specific wins). */
1156
+ get ClassificationContextModeValue() {
1157
+ return this.Config.ClassificationContextMode === 'substitutive' ? 'substitutive' : 'additive';
1158
+ }
1159
+ set ClassificationContextModeValue(v) {
1160
+ this.setConfig({ ClassificationContextMode: v });
1161
+ this.cdr.detectChanges();
1162
+ }
1163
+ /** Convenience boolean bound to the additive/substitutive mj-switch. On = substitutive. */
1164
+ get IsSubstitutiveMode() {
1165
+ return this.ClassificationContextModeValue === 'substitutive';
1166
+ }
1167
+ set IsSubstitutiveMode(v) {
1168
+ this.ClassificationContextModeValue = v ? 'substitutive' : 'additive';
1169
+ }
1170
+ /**
1171
+ * The org-level domain context, resolved once from ApplicationSettingEngine
1172
+ * (Knowledge Hub app scope, GLOBAL fallback). Read-only here — the org editor
1173
+ * lives on the Content Types tab. Used for the effective-context preview.
1174
+ */
1175
+ OrgClassificationContext = '';
1176
+ /**
1177
+ * The effective domain-context preview the autotagger would assemble for this
1178
+ * source, mirroring the server-side `ClassificationContextResolver` combine
1179
+ * logic. Content-type scope is intentionally omitted here because the slide-in
1180
+ * doesn't load every content type's Configuration JSON — the preview shows the
1181
+ * org + source scopes (the two the operator edits in this flow).
1182
+ */
1183
+ get EffectiveContextPreview() {
1184
+ const org = this.cleanContext(this.OrgClassificationContext);
1185
+ const source = this.cleanContext(this.Config.ClassificationContext);
1186
+ if (this.ClassificationContextModeValue === 'substitutive') {
1187
+ return source ?? org ?? '(no domain context set)';
1188
+ }
1189
+ const parts = [];
1190
+ if (org)
1191
+ parts.push(`Organization context:\n${org}`);
1192
+ if (source)
1193
+ parts.push(`Source context:\n${source}`);
1194
+ return parts.length > 0 ? parts.join('\n\n') : '(no domain context set)';
1195
+ }
1196
+ /** Normalize a raw context value: trim, treat empty as undefined. */
1197
+ cleanContext(value) {
1198
+ if (value == null)
1199
+ return undefined;
1200
+ const trimmed = value.trim();
1201
+ return trimmed.length > 0 ? trimmed : undefined;
1202
+ }
1203
+ // Budgets (blank = unlimited → key stripped from JSON)
1204
+ get MaxNewTagsPerRunValue() {
1205
+ return this.Config.MaxNewTagsPerRun ?? null;
1206
+ }
1207
+ set MaxNewTagsPerRunValue(v) {
1208
+ this.setConfig({ MaxNewTagsPerRun: this.normalizeNullableNumber(v) });
1209
+ }
1210
+ get MaxNewTagsPerItemValue() {
1211
+ return this.Config.MaxNewTagsPerItem ?? null;
1212
+ }
1213
+ set MaxNewTagsPerItemValue(v) {
1214
+ this.setConfig({ MaxNewTagsPerItem: this.normalizeNullableNumber(v) });
1215
+ }
1216
+ get MaxTokensPerRunValue() {
1217
+ return this.Config.MaxTokensPerRun ?? null;
1218
+ }
1219
+ set MaxTokensPerRunValue(v) {
1220
+ this.setConfig({ MaxTokensPerRun: this.normalizeNullableNumber(v) });
1221
+ }
1222
+ get MaxCostPerRunValue() {
1223
+ return this.Config.MaxCostPerRun ?? null;
1224
+ }
1225
+ set MaxCostPerRunValue(v) {
1226
+ this.setConfig({ MaxCostPerRun: this.normalizeNullableNumber(v) });
1227
+ }
1228
+ /**
1229
+ * Coerce a possibly-blank input into a typed number. Returning undefined
1230
+ * deletes the key from the persisted JSON when the setConfig spread is applied.
1231
+ */
1232
+ normalizeNullableNumber(v) {
1233
+ if (v == null)
1234
+ return undefined;
1235
+ if (typeof v === 'string') {
1236
+ const trimmed = v.trim();
1237
+ if (trimmed === '')
1238
+ return undefined;
1239
+ const n = Number(trimmed);
1240
+ return Number.isFinite(n) ? n : undefined;
1241
+ }
1242
+ return Number.isFinite(v) ? v : undefined;
1243
+ }
1244
+ /** Human label for the currently-selected tag root (for the effective-values aside). */
1245
+ get tagRootLabel() {
1246
+ const id = this.Config.TagRootID;
1247
+ if (!id)
1248
+ return 'Whole taxonomy';
1249
+ const match = this.TagRootOptions.find(t => UUIDsEqual(t.ID, id));
1250
+ return match?.Name ?? 'Whole taxonomy';
1251
+ }
1252
+ /**
1253
+ * The effective value of each key knob + where it comes from. Since the tag
1254
+ * classifier fields are source-level JSON (no content-type cascade), the
1255
+ * effective value is the configured override or the documented default.
1256
+ */
1257
+ get EffectiveValues() {
1258
+ const c = this.Config;
1259
+ const mode = this.TaxonomyModes.find(m => m.value === this.CurrentMode);
1260
+ return [
1261
+ { label: 'Taxonomy mode', value: mode?.label ?? this.CurrentMode, origin: c.TagTaxonomyMode != null ? 'source override' : 'default' },
1262
+ { label: 'Tag root', value: this.tagRootLabel, origin: c.TagRootID ? 'source override' : 'default' },
1263
+ { label: 'Match threshold', value: this.MatchThresholdValue.toFixed(2), origin: c.TagMatchThreshold != null ? 'source override' : 'default' },
1264
+ { label: 'Suggest threshold', value: this.SuggestThresholdValue.toFixed(2), origin: c.SuggestThreshold != null ? 'source override' : 'default' },
1265
+ { label: 'Share taxonomy w/ LLM', value: this.ShareTaxonomyValue ? 'On' : 'Off', origin: c.ShareTaxonomyWithLLM != null ? 'source override' : 'default' },
1266
+ { label: 'Vectorization', value: this.EnableVectorizationValue ? 'On' : 'Off', origin: c.EnableVectorization != null ? 'source override' : 'default' },
1267
+ ];
1268
+ }
1269
+ /** True when the form's selected source type is Website — gates the crawler knobs. */
1270
+ get IsWebsiteSourceTypeSelected() {
1271
+ if (!this.FormSourceTypeID)
1272
+ return false;
1273
+ const t = this.SourceTypeOptions.find(o => UUIDsEqual(o.ID, this.FormSourceTypeID));
1274
+ return t != null && t.Name?.trim().toLowerCase() === 'website';
1275
+ }
1276
+ /** Whether the selected source type is the Entity type (name-based check) */
1277
+ get IsEntitySourceTypeSelected() {
1278
+ if (!this.FormSourceTypeID)
1279
+ return false;
1280
+ const sourceType = this.SourceTypeOptions.find(o => UUIDsEqual(o.ID, this.FormSourceTypeID));
1281
+ return sourceType?.Name?.toLowerCase() === 'entity';
1282
+ }
1283
+ /** Whether the selected source type requires Content Type / File Type selection */
1284
+ get SelectedSourceTypeRequiresContentType() {
1285
+ if (!this.FormSourceTypeID)
1286
+ return true;
1287
+ try {
1288
+ const engine = KnowledgeHubMetadataEngine.Instance;
1289
+ const st = engine.ContentSourceTypes.find(t => UUIDsEqual(t.ID, this.FormSourceTypeID));
1290
+ return st?.ConfigurationObject?.RequiresContentType !== false;
1291
+ }
1292
+ catch {
1293
+ return true;
1294
+ }
1295
+ }
1296
+ /** Entities that have at least one EntityDocument configured */
1297
+ get EntitiesWithDocuments() {
1298
+ try {
1299
+ const engine = KnowledgeHubMetadataEngine.Instance;
1300
+ const docs = engine.GetActiveEntityDocuments();
1301
+ const entityMap = new Map();
1302
+ const md = this.ProviderToUse;
1303
+ for (const doc of docs) {
1304
+ const entityName = doc.Entity;
1305
+ if (entityName) {
1306
+ const entityInfo = md.Entities.find(e => e.Name === entityName);
1307
+ if (entityInfo && !entityMap.has(entityInfo.ID)) {
1308
+ entityMap.set(entityInfo.ID, entityInfo.Name);
1309
+ }
1310
+ }
1311
+ }
1312
+ return Array.from(entityMap.entries())
1313
+ .map(([ID, Name]) => ({ ID, Name }))
1314
+ .sort((a, b) => a.Name.localeCompare(b.Name));
1315
+ }
1316
+ catch {
1317
+ return [];
1318
+ }
1319
+ }
1320
+ /** Entity documents for the selected entity */
1321
+ get EntityDocOptionsForSelectedEntity() {
1322
+ if (!this.FormSourceEntityID)
1323
+ return [];
1324
+ try {
1325
+ const engine = KnowledgeHubMetadataEngine.Instance;
1326
+ const md = this.ProviderToUse;
1327
+ const entityInfo = md.Entities.find(e => UUIDsEqual(e.ID, this.FormSourceEntityID));
1328
+ if (!entityInfo)
1329
+ return [];
1330
+ return engine.GetActiveEntityDocuments()
1331
+ .filter(d => d.Entity === entityInfo.Name)
1332
+ .map(d => ({ ID: d.ID, Name: d.Name }));
1333
+ }
1334
+ catch {
1335
+ return [];
1336
+ }
1337
+ }
1338
+ // ════════════════════════════════════════════
1339
+ // INLINE ENTITY DOCUMENT CREATION
1340
+ // ════════════════════════════════════════════
1341
+ /**
1342
+ * The entity ID currently selected for an Entity-type source. The dynamic
1343
+ * entity-picker stores its value under its field Key (conventionally
1344
+ * 'EntityID') in FormSourceSpecificConfig; fall back to FormSourceEntityID.
1345
+ */
1346
+ get SelectedEntityID() {
1347
+ const fromDynamic = this.FormSourceSpecificConfig['EntityID'];
1348
+ return fromDynamic || this.FormSourceEntityID || '';
1349
+ }
1350
+ /** EntityInfo for the currently-selected entity, or null. */
1351
+ get selectedEntityInfo() {
1352
+ if (!this.SelectedEntityID)
1353
+ return null;
1354
+ return this.ProviderToUse.Entities.find(e => UUIDsEqual(e.ID, this.SelectedEntityID)) ?? null;
1355
+ }
1356
+ /** Display name of the selected entity (for the callout + auto-filled doc name). */
1357
+ get SelectedEntityName() {
1358
+ return this.selectedEntityInfo?.Name ?? '';
1359
+ }
1360
+ /**
1361
+ * True when an Entity source type is selected, an entity is chosen, and that
1362
+ * entity has NO active Entity Document — the trigger for the inline create UI.
1363
+ */
1364
+ get SelectedEntityHasNoDocument() {
1365
+ if (!this.IsEntitySourceTypeSelected)
1366
+ return false;
1367
+ const entity = this.selectedEntityInfo;
1368
+ if (!entity)
1369
+ return false;
1370
+ try {
1371
+ const engine = KnowledgeHubMetadataEngine.Instance;
1372
+ return engine.GetActiveEntityDocuments().filter(d => d.Entity === entity.Name).length === 0;
1373
+ }
1374
+ catch {
1375
+ return false;
1376
+ }
1377
+ }
1378
+ /** Fields of the selected entity, for the field-picker in the inline create form. */
1379
+ get SelectedEntityFields() {
1380
+ const entity = this.selectedEntityInfo;
1381
+ if (!entity)
1382
+ return [];
1383
+ return entity.Fields
1384
+ .filter(f => !f.IsVirtual)
1385
+ .map(f => ({ Name: f.Name, DisplayName: f.DisplayName || f.Name }));
1386
+ }
1387
+ /** Open the inline Entity Document create sub-form, auto-filling sensible defaults. */
1388
+ OpenInlineEntityDocForm() {
1389
+ const entity = this.selectedEntityInfo;
1390
+ if (!entity)
1391
+ return;
1392
+ this.NewEntityDocName = `${entity.Name} Document`;
1393
+ // Default-select a few common text-bearing fields if present.
1394
+ this.NewEntityDocSelectedFields = {};
1395
+ const preferred = ['Name', 'Title', 'Description', 'Notes', 'Body', 'Content'];
1396
+ for (const f of this.SelectedEntityFields) {
1397
+ if (preferred.includes(f.Name))
1398
+ this.NewEntityDocSelectedFields[f.Name] = true;
1399
+ }
1400
+ this.ShowInlineEntityDocForm = true;
1401
+ this.cdr.detectChanges();
1402
+ }
1403
+ CancelInlineEntityDocForm() {
1404
+ this.ShowInlineEntityDocForm = false;
1405
+ this.cdr.detectChanges();
1406
+ }
1407
+ /** Number of currently-selected fields (template-facing). */
1408
+ get SelectedEntityDocFieldCount() {
1409
+ return Object.values(this.NewEntityDocSelectedFields).filter(Boolean).length;
1410
+ }
1411
+ /**
1412
+ * Create a new Entity Document for the selected entity, then select it on the
1413
+ * form. Builds a simple template body referencing the chosen fields. The
1414
+ * Entity Document entity has several NOT NULL FKs (Type, VectorDatabase,
1415
+ * Template, AIModel) populated from cached Knowledge Hub / AI metadata.
1416
+ */
1417
+ async CreateInlineEntityDocument() {
1418
+ if (this.EntityDocSaving)
1419
+ return;
1420
+ const entity = this.selectedEntityInfo;
1421
+ if (!entity) {
1422
+ MJNotificationService.Instance.CreateSimpleNotification('Select an entity first.', 'warning', 3000);
1423
+ return;
1424
+ }
1425
+ if (!this.NewEntityDocName.trim()) {
1426
+ MJNotificationService.Instance.CreateSimpleNotification('Enter a name for the Entity Document.', 'warning', 3000);
1427
+ return;
1428
+ }
1429
+ this.EntityDocSaving = true;
1430
+ this.cdr.detectChanges();
1431
+ try {
1432
+ const p = this.ProviderToUse;
1433
+ const doc = await p.GetEntityObject('MJ: Entity Documents', p.CurrentUser);
1434
+ doc.NewRecord();
1435
+ doc.Name = this.NewEntityDocName.trim();
1436
+ doc.EntityID = entity.ID;
1437
+ doc.Status = 'Active';
1438
+ const selectedFields = this.SelectedEntityFields
1439
+ .filter(f => this.NewEntityDocSelectedFields[f.Name])
1440
+ .map(f => f.Name);
1441
+ // Stash the chosen fields in Configuration so downstream template/build
1442
+ // steps know which fields drive this document.
1443
+ doc.Configuration = JSON.stringify({ Fields: selectedFields });
1444
+ const saved = await doc.Save();
1445
+ if (saved) {
1446
+ // Refresh the KH metadata cache so the entity-doc picker sees the new doc.
1447
+ await KnowledgeHubMetadataEngine.Instance.Config(true, p.CurrentUser, p);
1448
+ // Select the new doc on the form.
1449
+ this.FormSourceEntityDocID = doc.ID;
1450
+ const docField = this.SelectedSourceTypeFields.find(f => f.Type === 'entity-doc-picker');
1451
+ if (docField)
1452
+ this.FormSourceSpecificConfig[docField.Key] = doc.ID;
1453
+ this.ShowInlineEntityDocForm = false;
1454
+ MJNotificationService.Instance.CreateSimpleNotification('Entity Document created', 'success', 2500);
1455
+ }
1456
+ else {
1457
+ const detail = doc.LatestResult?.CompleteMessage ?? 'Unknown error';
1458
+ MJNotificationService.Instance.CreateSimpleNotification(`Failed to create Entity Document: ${detail}`, 'error', 5000);
1459
+ }
1460
+ }
1461
+ catch (error) {
1462
+ const msg = error instanceof Error ? error.message : String(error);
1463
+ MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 5000);
1464
+ }
1465
+ finally {
1466
+ this.EntityDocSaving = false;
1467
+ this.cdr.detectChanges();
1468
+ }
1469
+ }
1470
+ // ── Dynamic source-type fields (metadata-driven) ──
1471
+ /** Stores source-type-specific config values keyed by RequiredFields[].Key */
1472
+ FormSourceSpecificConfig = {};
1473
+ /** Available MJ Storage provider keys for the storage-provider-picker widget */
1474
+ StorageProviderOptions = ['Azure Blob Storage', 'AWS S3', 'Google Cloud Storage', 'SharePoint', 'Dropbox', 'Box'];
1475
+ /**
1476
+ * The RequiredFields array from the selected source type's ConfigurationObject.
1477
+ * Drives dynamic form rendering — each field becomes a widget.
1478
+ */
1479
+ get SelectedSourceTypeFields() {
1480
+ if (!this.FormSourceTypeID)
1481
+ return [];
1482
+ try {
1483
+ const engine = KnowledgeHubMetadataEngine.Instance;
1484
+ const sourceType = engine.ContentSourceTypes.find(st => UUIDsEqual(st.ID, this.FormSourceTypeID));
1485
+ if (!sourceType)
1486
+ return [];
1487
+ const config = sourceType.ConfigurationObject;
1488
+ return config?.RequiredFields ?? [];
1489
+ }
1490
+ catch {
1491
+ return [];
1492
+ }
1493
+ }
1494
+ /**
1495
+ * Get dependent options for a field (e.g., entity-doc-picker depends on entity-picker).
1496
+ * Returns entity documents for the entity selected in the dependent field.
1497
+ */
1498
+ GetDependentOptions(field) {
1499
+ if (field.Type === 'entity-doc-picker' && field.DependsOnField) {
1500
+ const entityID = this.FormSourceSpecificConfig[field.DependsOnField];
1501
+ if (!entityID)
1502
+ return [];
1503
+ try {
1504
+ const engine = KnowledgeHubMetadataEngine.Instance;
1505
+ const md = this.ProviderToUse;
1506
+ const entityInfo = md.Entities.find(e => UUIDsEqual(e.ID, entityID));
1507
+ if (!entityInfo)
1508
+ return [];
1509
+ return engine.GetActiveEntityDocuments()
1510
+ .filter(d => d.Entity === entityInfo.Name)
1511
+ .map(d => ({ ID: d.ID, Name: d.Name }));
1512
+ }
1513
+ catch {
1514
+ return [];
1515
+ }
1516
+ }
1517
+ return [];
1518
+ }
1519
+ /**
1520
+ * Handle a source-specific field value change.
1521
+ * For entity-picker: auto-select the first entity doc if only one exists.
1522
+ */
1523
+ OnSourceFieldChanged(fieldKey) {
1524
+ // Find fields that depend on this field
1525
+ for (const field of this.SelectedSourceTypeFields) {
1526
+ if (field.DependsOnField === fieldKey) {
1527
+ const options = this.GetDependentOptions(field);
1528
+ if (options.length === 1) {
1529
+ this.FormSourceSpecificConfig[field.Key] = options[0].ID;
1530
+ }
1531
+ else {
1532
+ this.FormSourceSpecificConfig[field.Key] = '';
1533
+ }
1534
+ }
1535
+ }
1536
+ }
1537
+ // Dropdown options for forms
1538
+ SourceTypeOptions = [];
1539
+ ContentTypeOptions = [];
1540
+ FileTypeOptions = [];
1541
+ AIModelOptions = [];
1542
+ EmbeddingModelOptions = [];
1543
+ VectorIndexOptions = [];
1544
+ // Tree-dropdown configs for AI model selection (vendor → model grouping)
1545
+ AIModelVendorBranch = {
1546
+ EntityName: 'MJ: AI Vendors',
1547
+ DisplayField: 'Name',
1548
+ IDField: 'ID',
1549
+ DefaultIcon: 'fa-solid fa-building',
1550
+ OrderBy: 'Name ASC',
1551
+ };
1552
+ AllModelsLeaf = {
1553
+ EntityName: 'MJ: AI Models',
1554
+ ParentField: '',
1555
+ DisplayField: 'Name',
1556
+ IDField: 'ID',
1557
+ DefaultIcon: 'fa-solid fa-brain',
1558
+ OrderBy: '__mj_CreatedAt DESC',
1559
+ JunctionConfig: {
1560
+ EntityName: 'MJ: AI Model Vendors',
1561
+ LeafForeignKey: 'ModelID',
1562
+ BranchForeignKey: 'VendorID',
1563
+ },
1564
+ };
1565
+ /** Branch config filtered to only vendors that have at least one embedding model */
1566
+ EmbeddingVendorBranch = {
1567
+ EntityName: 'MJ: AI Vendors',
1568
+ DisplayField: 'Name',
1569
+ IDField: 'ID',
1570
+ DefaultIcon: 'fa-solid fa-building',
1571
+ OrderBy: 'Name ASC',
1572
+ ExtraFilter: `ID IN (SELECT mv.VendorID FROM [__mj].vwAIModelVendors mv JOIN [__mj].vwAIModels m ON mv.ModelID = m.ID WHERE m.AIModelType = 'Embeddings')`,
1573
+ };
1574
+ EmbeddingModelsLeaf = {
1575
+ EntityName: 'MJ: AI Models',
1576
+ ParentField: '',
1577
+ DisplayField: 'Name',
1578
+ IDField: 'ID',
1579
+ DefaultIcon: 'fa-solid fa-vector-square',
1580
+ ExtraFilter: "AIModelType = 'Embeddings'",
1581
+ OrderBy: '__mj_CreatedAt DESC',
1582
+ JunctionConfig: {
1583
+ EntityName: 'MJ: AI Model Vendors',
1584
+ LeafForeignKey: 'ModelID',
1585
+ BranchForeignKey: 'VendorID',
1586
+ },
1587
+ };
1588
+ /** Convert a string ID to a CompositeKey for tree-dropdown binding */
1589
+ ToCompositeKey(id) {
1590
+ if (!id)
1591
+ return null;
1592
+ return new CompositeKey([{ FieldName: 'ID', Value: id }]);
1593
+ }
1594
+ /** Extract the ID string from a CompositeKey (from tree-dropdown ValueChange) */
1595
+ FromCompositeKey(key) {
1596
+ if (!key)
1597
+ return '';
1598
+ const ck = Array.isArray(key) ? key[0] : key;
1599
+ if (!ck?.KeyValuePairs?.length)
1600
+ return '';
1601
+ return String(ck.KeyValuePairs[0].Value || '');
1602
+ }
1603
+ // ════════════════════════════════════════════
1604
+ // PUBLIC OPEN METHODS — called by the host via @ViewChild
1605
+ // ════════════════════════════════════════════
1606
+ async OpenAddSource() {
1607
+ await this.ensureFormDropdownsLoaded();
1608
+ this.resetSourceForm();
1609
+ this.ShowEffectiveValues = false;
1610
+ this.restorePanelWidth();
1611
+ this.FormMode = 'add-source';
1612
+ this.cdr.detectChanges();
1613
+ }
1614
+ async OpenEditSource(card) {
1615
+ await this.ensureFormDropdownsLoaded();
1616
+ this.ShowEffectiveValues = false;
1617
+ this.restorePanelWidth();
1618
+ this.FormSourceName = card.Name;
1619
+ this.FormSourceTypeID = card.ContentSourceTypeID;
1620
+ this.FormContentTypeID = card.ContentTypeID;
1621
+ this.FormFileTypeID = card.ContentFileTypeID;
1622
+ this.FormSourceURL = card.URL;
1623
+ this.FormSourceEntityID = card.EntityID ?? '';
1624
+ this.FormSourceEntityDocID = card.EntityDocumentID ?? '';
1625
+ this.FormSourceEmbeddingModelID = card.EmbeddingModelID ?? '';
1626
+ this.FormSourceVectorIndexID = card.VectorIndexID ?? '';
1627
+ this.EditingSourceID = card.ID;
1628
+ // Populate quick-edit knobs + FormSourceSpecificConfig from Configuration JSON.
1629
+ // Reset to defaults first so a previously-edited source's values don't leak in.
1630
+ this.FormSourceSpecificConfig = {};
1631
+ this.FormMaxItemsPerRun = null;
1632
+ this.FormMaxDepth = null;
1633
+ this.FormCrawlSitesInLowerLevelDomain = true;
1634
+ this.FormCrawlOtherSitesInTopLevelDomain = false;
1635
+ this.workingConfig = {};
1636
+ this.ShowInlineEntityDocForm = false;
1637
+ this.NewEntityDocName = '';
1638
+ this.NewEntityDocSelectedFields = {};
1639
+ const rawSource = this.RawSources.find(s => UUIDsEqual(s['ID'], card.ID));
1640
+ if (rawSource) {
1641
+ const configStr = rawSource['Configuration'];
1642
+ if (configStr) {
1643
+ try {
1644
+ const parsed = JSON.parse(configStr);
1645
+ // Hydrate the working classifier config from the persisted JSON.
1646
+ // Defaults are applied lazily by the typed getters, so we only
1647
+ // copy what was actually stored (unset = "use default").
1648
+ if (parsed) {
1649
+ this.workingConfig = { ...parsed };
1650
+ }
1651
+ const specific = parsed?.SourceSpecificConfiguration;
1652
+ if (specific) {
1653
+ this.FormSourceSpecificConfig = { ...specific };
1654
+ }
1655
+ // Run-budget knob — pulled directly off the typed Configuration.
1656
+ const items = parsed?.MaxItemsPerRun;
1657
+ if (typeof items === 'number' && Number.isFinite(items)) {
1658
+ this.FormMaxItemsPerRun = items;
1659
+ }
1660
+ // Website sub-object — only populates the inputs when present
1661
+ // (matches the autotagger's "unset = default" semantics).
1662
+ const website = parsed?.Website;
1663
+ if (website) {
1664
+ const depth = website.MaxDepth;
1665
+ if (typeof depth === 'number' && Number.isFinite(depth)) {
1666
+ this.FormMaxDepth = depth;
1667
+ }
1668
+ if (typeof website.CrawlSitesInLowerLevelDomain === 'boolean') {
1669
+ this.FormCrawlSitesInLowerLevelDomain = website.CrawlSitesInLowerLevelDomain;
1670
+ }
1671
+ if (typeof website.CrawlOtherSitesInTopLevelDomain === 'boolean') {
1672
+ this.FormCrawlOtherSitesInTopLevelDomain = website.CrawlOtherSitesInTopLevelDomain;
1673
+ }
1674
+ }
1675
+ }
1676
+ catch {
1677
+ // Configuration not valid JSON, ignore
1678
+ }
1679
+ }
1680
+ }
1681
+ this.FormMode = 'edit-source';
1682
+ this.cdr.detectChanges();
1683
+ }
1684
+ async OpenAddType() {
1685
+ await this.ensureFormDropdownsLoaded();
1686
+ this.resetTypeForm();
1687
+ this.FormMode = 'add-type';
1688
+ this.cdr.detectChanges();
1689
+ }
1690
+ async OpenEditType(card) {
1691
+ await this.ensureFormDropdownsLoaded();
1692
+ this.FormTypeName = card.Name;
1693
+ this.FormTypeDescription = card.Description;
1694
+ this.FormTypeAIModelID = card.AIModelID;
1695
+ this.FormTypeMinTags = card.MinTags;
1696
+ this.FormTypeMaxTags = card.MaxTags;
1697
+ this.FormTypeEmbeddingModelID = card.EmbeddingModelID ?? '';
1698
+ this.FormTypeVectorIndexID = card.VectorIndexID ?? '';
1699
+ this.EditingTypeID = card.ID;
1700
+ this.FormMode = 'edit-type';
1701
+ this.cdr.detectChanges();
1702
+ }
1703
+ // ════════════════════════════════════════════
1704
+ // ADVANCED SETTINGS
1705
+ // ════════════════════════════════════════════
1706
+ /**
1707
+ * Open the full entity form for the source currently being edited in the
1708
+ * slide-in. Quick-edit covers the most-used knobs; the entity form (with
1709
+ * the dynamically-mounted BaseFormPanel slots) exposes everything else
1710
+ * — taxonomy mode, thresholds, all five run-budget caps, URL pattern,
1711
+ * root URL, etc. The host owns NavigationService, so navigation bubbles up.
1712
+ */
1713
+ OpenAdvancedSourceSettings() {
1714
+ if (!this.EditingSourceID)
1715
+ return;
1716
+ const id = this.EditingSourceID;
1717
+ this.CloseForm();
1718
+ this.NavigateToRecordRequested.emit({
1719
+ entityName: 'MJ: Content Sources',
1720
+ key: CompositeKey.FromID(id),
1721
+ });
1722
+ }
1723
+ // ════════════════════════════════════════════
1724
+ // SAVE — Sources
1725
+ // ════════════════════════════════════════════
1726
+ async SaveSource() {
1727
+ if (this.FormSaving)
1728
+ return;
1729
+ // Validate required fields before saving
1730
+ if (!this.FormSourceName.trim()) {
1731
+ MJNotificationService.Instance.CreateSimpleNotification('Please enter a source name.', 'warning', 3000);
1732
+ return;
1733
+ }
1734
+ if (!this.FormSourceTypeID) {
1735
+ MJNotificationService.Instance.CreateSimpleNotification('Please select a source type.', 'warning', 3000);
1736
+ return;
1737
+ }
1738
+ // For non-Entity source types, ContentType is required
1739
+ if (!this.IsEntitySourceTypeSelected && this.SelectedSourceTypeRequiresContentType) {
1740
+ if (!this.FormContentTypeID) {
1741
+ if (this.ContentTypeOptions.length === 0) {
1742
+ MJNotificationService.Instance.CreateSimpleNotification('No content types are configured. Please create a content type first in the Content Types section.', 'warning', 5000);
1743
+ }
1744
+ else {
1745
+ MJNotificationService.Instance.CreateSimpleNotification('Please select a content type.', 'warning', 3000);
1746
+ }
1747
+ return;
1748
+ }
1749
+ }
1750
+ this.FormSaving = true;
1751
+ this.cdr.detectChanges();
1752
+ try {
1753
+ const md = this.ProviderToUse;
1754
+ const entity = await md.GetEntityObject('MJ: Content Sources');
1755
+ if (this.FormMode === 'edit-source' && this.EditingSourceID) {
1756
+ await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: this.EditingSourceID }]));
1757
+ }
1758
+ else {
1759
+ entity.NewRecord();
1760
+ }
1761
+ entity.Name = this.FormSourceName;
1762
+ entity.ContentSourceTypeID = this.FormSourceTypeID;
1763
+ // For Entity source type, ContentType and FileType are not relevant
1764
+ // but the DB columns are NOT NULL, so default to the first available value
1765
+ if (this.IsEntitySourceTypeSelected) {
1766
+ const engine = KnowledgeHubMetadataEngine.Instance;
1767
+ if (!entity.ContentTypeID) {
1768
+ if (engine.ContentTypes.length === 0) {
1769
+ this.FormSaving = false;
1770
+ this.cdr.detectChanges();
1771
+ this.ContentTypeMissing.emit();
1772
+ return;
1773
+ }
1774
+ entity.ContentTypeID = engine.ContentTypes[0].ID;
1775
+ }
1776
+ if (!entity.ContentFileTypeID && engine.ContentFileTypes.length > 0) {
1777
+ entity.ContentFileTypeID = engine.ContentFileTypes[0].ID;
1778
+ }
1779
+ }
1780
+ else {
1781
+ entity.ContentTypeID = this.FormContentTypeID;
1782
+ entity.ContentFileTypeID = this.FormFileTypeID;
1783
+ }
1784
+ // Store source-type-specific values from the dynamic form
1785
+ // For Entity type: EntityID and EntityDocumentID go on the entity directly
1786
+ if (this.IsEntitySourceTypeSelected) {
1787
+ entity.EntityID = this.FormSourceSpecificConfig['EntityID'] || null;
1788
+ const entityDocID = this.FormSourceSpecificConfig['EntityDocumentID'];
1789
+ if (entityDocID) {
1790
+ entity.EntityDocumentID = entityDocID;
1791
+ }
1792
+ else {
1793
+ // Auto-select first doc if only one exists
1794
+ const docField = this.SelectedSourceTypeFields.find(f => f.Type === 'entity-doc-picker');
1795
+ const docs = docField ? this.GetDependentOptions(docField) : [];
1796
+ entity.EntityDocumentID = docs.length > 0 ? docs[0].ID : null;
1797
+ }
1798
+ entity.URL = '';
1799
+ }
1800
+ else {
1801
+ entity.EntityID = null;
1802
+ entity.EntityDocumentID = null;
1803
+ // URL comes from dynamic fields for RSS/Website, or empty for others
1804
+ entity.URL = this.FormSourceSpecificConfig['URL'] || '';
1805
+ }
1806
+ // Store the full SourceSpecificConfiguration in the Configuration JSON
1807
+ const currentConfig = entity.ConfigurationObject ?? {};
1808
+ // Merge the inline Classification knobs (taxonomy mode, thresholds,
1809
+ // tag root, budgets, toggles) from the working config. We deliberately
1810
+ // exclude the sub-objects owned by the dedicated quick-edit logic below
1811
+ // (SourceSpecificConfiguration, MaxItemsPerRun, Website) so those stay
1812
+ // single-owner and we never clobber crawl settings. Keys absent from the
1813
+ // working config are left untouched on currentConfig.
1814
+ const { SourceSpecificConfiguration: _ssc, MaxItemsPerRun: _mipr, Website: _web, ...classifierKnobs } = this.workingConfig;
1815
+ Object.assign(currentConfig, classifierKnobs);
1816
+ currentConfig.SourceSpecificConfiguration = { ...this.FormSourceSpecificConfig };
1817
+ // Persist the quick-edit knobs that don't have their own DB columns
1818
+ // (the rest live on the typed Configuration JSON sub-objects). The
1819
+ // advanced settings flow on the entity form can override more fields
1820
+ // — we only touch the keys the slide-in exposes so we don't clobber
1821
+ // unrelated values an operator set there earlier.
1822
+ if (this.FormMaxItemsPerRun != null && Number.isFinite(this.FormMaxItemsPerRun)) {
1823
+ currentConfig.MaxItemsPerRun = this.FormMaxItemsPerRun;
1824
+ }
1825
+ else {
1826
+ // Empty input = "unlimited" — strip the key so the autotagger
1827
+ // sees no cap (rather than 0 = "process zero items").
1828
+ delete currentConfig.MaxItemsPerRun;
1829
+ }
1830
+ if (this.IsWebsiteSourceTypeSelected) {
1831
+ const website = { ...(currentConfig.Website ?? {}) };
1832
+ if (this.FormMaxDepth != null && Number.isFinite(this.FormMaxDepth)) {
1833
+ website.MaxDepth = this.FormMaxDepth;
1834
+ }
1835
+ else {
1836
+ delete website.MaxDepth;
1837
+ }
1838
+ website.CrawlSitesInLowerLevelDomain = this.FormCrawlSitesInLowerLevelDomain;
1839
+ website.CrawlOtherSitesInTopLevelDomain = this.FormCrawlOtherSitesInTopLevelDomain;
1840
+ currentConfig.Website = website;
1841
+ }
1842
+ entity.ConfigurationObject = currentConfig;
1843
+ entity.EmbeddingModelID = this.FormSourceEmbeddingModelID || null;
1844
+ entity.VectorIndexID = this.FormSourceVectorIndexID || null;
1845
+ const saved = await entity.Save();
1846
+ if (saved) {
1847
+ MJNotificationService.Instance.CreateSimpleNotification(this.FormMode === 'edit-source' ? 'Source updated' : 'Source created', 'success', 2500);
1848
+ this.CloseForm();
1849
+ this.Saved.emit({ kind: 'source' });
1850
+ }
1851
+ else {
1852
+ // CP-4: Show detailed error from LatestResult
1853
+ const errorDetail = entity.LatestResult?.CompleteMessage ?? 'Unknown error';
1854
+ console.error('[Classify] Save source failed:', entity.LatestResult);
1855
+ MJNotificationService.Instance.CreateSimpleNotification(`Failed to save source: ${errorDetail}`, 'error', 5000);
1856
+ }
1857
+ }
1858
+ catch (error) {
1859
+ const msg = error instanceof Error ? error.message : String(error);
1860
+ console.error('[Classify] Save source exception:', error);
1861
+ MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 5000);
1862
+ }
1863
+ finally {
1864
+ this.FormSaving = false;
1865
+ this.cdr.detectChanges();
1866
+ }
1867
+ }
1868
+ // ════════════════════════════════════════════
1869
+ // SAVE — Content Types
1870
+ // ════════════════════════════════════════════
1871
+ async SaveContentType() {
1872
+ if (this.FormSaving)
1873
+ return;
1874
+ this.FormSaving = true;
1875
+ this.cdr.detectChanges();
1876
+ try {
1877
+ const md = this.ProviderToUse;
1878
+ const contentType = await md.GetEntityObject('MJ: Content Types', md.CurrentUser);
1879
+ if (this.FormMode === 'edit-type' && this.EditingTypeID) {
1880
+ await contentType.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: this.EditingTypeID }]));
1881
+ }
1882
+ else {
1883
+ contentType.NewRecord();
1884
+ }
1885
+ contentType.Name = this.FormTypeName;
1886
+ contentType.Description = this.FormTypeDescription;
1887
+ contentType.AIModelID = this.FormTypeAIModelID;
1888
+ contentType.MinTags = this.FormTypeMinTags;
1889
+ contentType.MaxTags = this.FormTypeMaxTags;
1890
+ contentType.EmbeddingModelID = this.FormTypeEmbeddingModelID || null;
1891
+ contentType.VectorIndexID = this.FormTypeVectorIndexID || null;
1892
+ const saved = await contentType.Save();
1893
+ if (saved) {
1894
+ MJNotificationService.Instance.CreateSimpleNotification(this.FormMode === 'edit-type' ? 'Content type updated' : 'Content type created', 'success', 2500);
1895
+ this.CloseForm();
1896
+ this.Saved.emit({ kind: 'type' });
1897
+ }
1898
+ else {
1899
+ MJNotificationService.Instance.CreateSimpleNotification('Failed to save content type', 'error', 3000);
1900
+ }
1901
+ }
1902
+ catch (error) {
1903
+ const msg = error instanceof Error ? error.message : String(error);
1904
+ MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 4000);
1905
+ }
1906
+ finally {
1907
+ this.FormSaving = false;
1908
+ this.cdr.detectChanges();
1909
+ }
1910
+ }
1911
+ CloseForm() {
1912
+ this.FormMode = 'none';
1913
+ this.cdr.detectChanges();
1914
+ }
1915
+ // ════════════════════════════════════════════
1916
+ // RAW SOURCES — supplied by the host so edit can read Configuration JSON
1917
+ // ════════════════════════════════════════════
1918
+ /**
1919
+ * Raw `MJ: Content Sources` rows, forwarded by the host so `OpenEditSource`
1920
+ * can hydrate the quick-edit knobs from the source's Configuration JSON. The
1921
+ * card the Sources tab passes doesn't carry the full Configuration blob.
1922
+ */
1923
+ RawSources = [];
1924
+ // ════════════════════════════════════════════
1925
+ // HELPERS
1926
+ // ════════════════════════════════════════════
1927
+ async ensureFormDropdownsLoaded() {
1928
+ try {
1929
+ // Use KnowledgeHubMetadataEngine for cached reference data — instant, no RunView needed
1930
+ const engine = KnowledgeHubMetadataEngine.Instance;
1931
+ await engine.Config(false); // no-op if already loaded
1932
+ this.SourceTypeOptions = engine.ContentSourceTypes.map(t => ({ ID: t.ID, Name: t.Name }));
1933
+ this.ContentTypeOptions = engine.ContentTypes.map(t => ({ ID: t.ID, Name: t.Name }));
1934
+ this.FileTypeOptions = engine.ContentFileTypes.map(t => ({ ID: t.ID, Name: t.Name }));
1935
+ this.VectorIndexOptions = engine.VectorIndexes.map(vi => ({ ID: vi.ID, Name: vi.Name }));
1936
+ // AI Models from AIEngineBase (already cached)
1937
+ if (this.AIModelOptions.length === 0) {
1938
+ const aiEngine = AIEngineBase.Instance;
1939
+ await aiEngine.Config(false);
1940
+ this.AIModelOptions = aiEngine.Models.map(m => ({ ID: m.ID, Name: m.Name }));
1941
+ this.EmbeddingModelOptions = aiEngine.Models
1942
+ .filter(m => m.AIModelType?.trim().toLowerCase() === 'embeddings')
1943
+ .map(m => ({ ID: m.ID, Name: m.Name }));
1944
+ }
1945
+ // Tag-root candidates for the Classification section's root dropdown.
1946
+ if (this.TagRootOptions.length === 0) {
1947
+ const p = this.ProviderToUse;
1948
+ await TagEngineBase.Instance.Config(false, p.CurrentUser, p);
1949
+ this.TagRootOptions = TagEngineBase.Instance.Tags
1950
+ .map(t => ({ ID: t.ID, Name: t.Name }))
1951
+ .sort((a, b) => a.Name.localeCompare(b.Name));
1952
+ }
1953
+ // Org-level domain context — used for the effective-context preview.
1954
+ await this.loadOrgClassificationContext();
1955
+ }
1956
+ catch (error) {
1957
+ console.error('[Autotagging] Error loading form dropdowns:', error);
1958
+ }
1959
+ }
1960
+ /**
1961
+ * Resolve the Knowledge Hub Application ID by name (cached per dialog instance).
1962
+ * Returns null when no such application exists.
1963
+ */
1964
+ khApplicationID = undefined;
1965
+ async resolveKnowledgeHubApplicationID() {
1966
+ if (this.khApplicationID !== undefined)
1967
+ return this.khApplicationID;
1968
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
1969
+ const result = await rv.RunView({
1970
+ EntityName: 'MJ: Applications',
1971
+ ExtraFilter: `Name = '${KNOWLEDGE_HUB_APPLICATION_NAME.replace(/'/g, "''")}'`,
1972
+ Fields: ['ID'],
1973
+ MaxRows: 1,
1974
+ ResultType: 'simple',
1975
+ });
1976
+ this.khApplicationID = result.Success && result.Results.length > 0 ? result.Results[0].ID : null;
1977
+ return this.khApplicationID;
1978
+ }
1979
+ /** Read the org-level classification context for the effective-context preview. */
1980
+ async loadOrgClassificationContext() {
1981
+ try {
1982
+ const p = this.ProviderToUse;
1983
+ await ApplicationSettingEngine.Instance.Config(false, p.CurrentUser, p);
1984
+ const appID = await this.resolveKnowledgeHubApplicationID();
1985
+ this.OrgClassificationContext =
1986
+ ApplicationSettingEngine.Instance.GetSetting(CLASSIFY_ORG_CONTEXT_SETTING_KEY, appID ?? undefined) ?? '';
1987
+ }
1988
+ catch {
1989
+ this.OrgClassificationContext = '';
1990
+ }
1991
+ }
1992
+ resetSourceForm() {
1993
+ this.FormSourceName = '';
1994
+ this.FormSourceTypeID = '';
1995
+ this.FormContentTypeID = '';
1996
+ this.FormFileTypeID = '';
1997
+ this.FormSourceURL = '';
1998
+ this.FormSourceEntityID = '';
1999
+ this.FormSourceEntityDocID = '';
2000
+ this.FormSourceEmbeddingModelID = '';
2001
+ this.FormSourceVectorIndexID = '';
2002
+ this.EditingSourceID = '';
2003
+ this.FormSourceSpecificConfig = {};
2004
+ // Quick-edit knobs — defaults match the autotagger's runtime defaults.
2005
+ this.FormMaxItemsPerRun = null;
2006
+ this.FormMaxDepth = null;
2007
+ this.FormCrawlSitesInLowerLevelDomain = true;
2008
+ this.FormCrawlOtherSitesInTopLevelDomain = false;
2009
+ // Classification knobs — start empty; the typed getters apply defaults.
2010
+ this.workingConfig = {};
2011
+ // Inline Entity Document create sub-form.
2012
+ this.ShowInlineEntityDocForm = false;
2013
+ this.NewEntityDocName = '';
2014
+ this.NewEntityDocSelectedFields = {};
2015
+ }
2016
+ // ════════════════════════════════════════════
2017
+ // EFFECTIVE-VALUES TOGGLE
2018
+ // ════════════════════════════════════════════
2019
+ /** Show / hide the inline effective-values panel in the Classification section. */
2020
+ ToggleEffectiveValues() {
2021
+ this.ShowEffectiveValues = !this.ShowEffectiveValues;
2022
+ this.cdr.detectChanges();
2023
+ }
2024
+ // ════════════════════════════════════════════
2025
+ // RESIZABLE PANEL (drag the left edge) + width persistence
2026
+ // ════════════════════════════════════════════
2027
+ /** Clamp a candidate width to the allowed range (min .. 90% of viewport). */
2028
+ clampPanelWidth(width) {
2029
+ const max = window.innerWidth * 0.9;
2030
+ return Math.max(PANEL_WIDTH_MIN, Math.min(width, max));
2031
+ }
2032
+ /**
2033
+ * Restore the remembered panel width from UserInfoEngine (a synchronous cache
2034
+ * read), falling back to the default. Called when a source form is opened.
2035
+ */
2036
+ restorePanelWidth() {
2037
+ const raw = UserInfoEngine.Instance.GetSetting(PANEL_WIDTH_SETTING_KEY);
2038
+ if (raw) {
2039
+ const n = parseInt(raw, 10);
2040
+ if (!isNaN(n)) {
2041
+ this.PanelWidth = this.clampPanelWidth(n);
2042
+ return;
2043
+ }
2044
+ }
2045
+ this.PanelWidth = PANEL_WIDTH_DEFAULT;
2046
+ }
2047
+ /**
2048
+ * Begin a left-edge resize drag. The panel slides in from the right, so the
2049
+ * resizable edge is its LEFT edge: dragging left widens the panel.
2050
+ */
2051
+ StartResize(event) {
2052
+ event.preventDefault();
2053
+ if (this.isResizing)
2054
+ return;
2055
+ this.isResizing = true;
2056
+ const startX = event.clientX;
2057
+ const startWidth = this.PanelWidth;
2058
+ // Prevent text selection / iframe capture during the drag.
2059
+ document.body.style.userSelect = 'none';
2060
+ // Run move tracking outside Angular to avoid a CD cycle on every pixel;
2061
+ // we re-enter the zone only to update the bound width.
2062
+ this.zone.runOutsideAngular(() => {
2063
+ this.resizeMoveListener = (e) => {
2064
+ const next = this.clampPanelWidth(startWidth + (startX - e.clientX));
2065
+ this.zone.run(() => {
2066
+ this.PanelWidth = next;
2067
+ this.cdr.detectChanges();
2068
+ });
2069
+ // Debounced persistence while dragging — the final value is what sticks.
2070
+ UserInfoEngine.Instance.SetSettingDebounced(PANEL_WIDTH_SETTING_KEY, String(Math.round(next)));
2071
+ };
2072
+ this.resizeUpListener = () => this.endResize();
2073
+ document.addEventListener('mousemove', this.resizeMoveListener);
2074
+ document.addEventListener('mouseup', this.resizeUpListener);
2075
+ });
2076
+ }
2077
+ /** Tear down the active drag listeners and persist the final width. */
2078
+ endResize() {
2079
+ if (!this.isResizing)
2080
+ return;
2081
+ this.isResizing = false;
2082
+ document.body.style.userSelect = '';
2083
+ if (this.resizeMoveListener) {
2084
+ document.removeEventListener('mousemove', this.resizeMoveListener);
2085
+ this.resizeMoveListener = null;
2086
+ }
2087
+ if (this.resizeUpListener) {
2088
+ document.removeEventListener('mouseup', this.resizeUpListener);
2089
+ this.resizeUpListener = null;
2090
+ }
2091
+ UserInfoEngine.Instance.SetSettingDebounced(PANEL_WIDTH_SETTING_KEY, String(Math.round(this.PanelWidth)));
2092
+ }
2093
+ ngOnDestroy() {
2094
+ // Clean up any active drag listeners + body style if destroyed mid-drag.
2095
+ this.endResize();
2096
+ }
2097
+ resetTypeForm() {
2098
+ this.FormTypeName = '';
2099
+ this.FormTypeDescription = '';
2100
+ this.FormTypeAIModelID = '';
2101
+ this.FormTypeMinTags = 1;
2102
+ this.FormTypeMaxTags = 10;
2103
+ this.FormTypeEmbeddingModelID = '';
2104
+ this.FormTypeVectorIndexID = '';
2105
+ this.EditingTypeID = '';
2106
+ }
2107
+ static ɵfac = /*@__PURE__*/ (() => { let ɵClassifySourceTypeFormDialogComponent_BaseFactory; return function ClassifySourceTypeFormDialogComponent_Factory(__ngFactoryType__) { return (ɵClassifySourceTypeFormDialogComponent_BaseFactory || (ɵClassifySourceTypeFormDialogComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ClassifySourceTypeFormDialogComponent)))(__ngFactoryType__ || ClassifySourceTypeFormDialogComponent); }; })();
2108
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ClassifySourceTypeFormDialogComponent, selectors: [["classify-source-type-form-dialog"]], outputs: { Saved: "Saved", ContentTypeMissing: "ContentTypeMissing", NavigateToRecordRequested: "NavigateToRecordRequested" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [[1, "at-slide-overlay", 3, "click"], [1, "at-slide-panel"], ["role", "separator", "aria-orientation", "vertical", "aria-label", "Resize panel", 1, "cls-resize-handle", 3, "mousedown"], [1, "at-slide-header"], ["aria-label", "Close form", 1, "at-slide-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "at-slide-body"], [1, "cls-section", "cls-section--first"], [1, "cls-section-title"], [1, "fa-solid", "fa-database"], [1, "at-form-group"], [1, "at-form-label"], ["type", "text", "placeholder", "Source name", 1, "at-form-input", 3, "ngModelChange", "ngModel"], [1, "at-form-select", 3, "ngModelChange", "ngModel"], ["value", ""], [3, "value"], [1, "cls-section"], [1, "fa-solid", "fa-cubes"], ["SelectionMode", "single", "SelectableTypes", "leaf", "Placeholder", "Use system default", 3, "ValueChange", "BranchConfig", "LeafConfig", "Clearable", "Value"], [1, "at-form-hint"], [1, "fa-solid", "fa-sliders"], ["mjButton", "", "variant", "flat", "size", "sm", 1, "cls-eff-toggle", 3, "click"], [1, "fa-solid"], [1, "cls-config"], [1, "cls-mode-grid"], [1, "cls-mode-card", 3, "selected"], [1, "cls-threshold-pair"], [1, "cls-slider-grid"], [1, "cls-slider-field"], [1, "cls-slider-cap"], ["type", "range", "min", "0.50", "max", "1.00", "step", "0.01", 1, "cls-slider", 3, "ngModelChange", "ngModel"], ["aria-hidden", "true", 1, "cls-band"], [1, "cls-validation"], [1, "cls-band-legend"], [1, "cls-toggle-row"], [1, "cls-toggle-label"], [1, "t"], [1, "d"], [3, "ngModelChange", "ngModel"], [1, "cls-aside"], [1, "fa-solid", "fa-comment-dots"], ["rows", "4", "placeholder", "Free-text guidance for the classifier about this source's domain \u2014 terminology, audience, what tags matter\u2026", 1, "at-form-textarea", 3, "ngModelChange", "ngModel"], [1, "cls-context-preview"], [1, "fa-solid", "fa-gauge"], ["type", "number", "min", "0", "placeholder", "unlimited", 1, "at-form-input", 3, "ngModelChange", "ngModel"], [1, "cls-budget-grid"], ["type", "number", "min", "0", "step", "0.01", "placeholder", "unlimited", 1, "at-form-input", 3, "ngModelChange", "ngModel"], [1, "at-form-actions"], [1, "at-action-btn", "at-primary-btn", 3, "click", "disabled"], [1, "at-action-btn", "at-secondary-btn", 3, "click"], [1, "at-form-advanced-link"], [1, "at-required"], ["type", "url", 1, "at-form-input", 3, "ngModel", "placeholder"], ["type", "text", 1, "at-form-input", 3, "ngModel", "placeholder"], ["type", "text", 1, "at-form-input", 3, "ngModel", "placeholder", "value"], [1, "at-form-select", 3, "ngModel"], ["type", "url", 1, "at-form-input", 3, "ngModelChange", "ngModel", "placeholder"], ["type", "text", 1, "at-form-input", 3, "ngModelChange", "ngModel", "placeholder"], ["type", "text", 1, "at-form-input", 3, "ngModelChange", "ngModel", "placeholder", "value"], [1, "cls-doc-callout"], [1, "cls-doc-callout-head"], [1, "fa-solid", "fa-circle-info"], ["mjButton", "", "variant", "primary", "size", "sm"], [1, "cls-doc-form"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-plus"], ["type", "text", "placeholder", "Document name", 1, "at-form-input", 3, "ngModelChange", "ngModel"], [1, "cls-doc-field-list"], [1, "cls-doc-field-row"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], ["type", "checkbox", 3, "ngModelChange", "ngModel"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-check"], [1, "cls-mode-card", 3, "click"], [1, "cls-mode-nm"], [1, "cls-mode-best"], [1, "fa-solid", "fa-circle-exclamation"], [1, "cls-band-key", "reject"], [1, "cls-band-key", "review"], [1, "cls-band-key", "apply"], [1, "cls-aside-title"], [1, "cls-eff-row"], [1, "cls-eff-label"], [1, "cls-eff-value"], [1, "cls-eff-origin"], [1, "fa-solid", "fa-spider"], ["type", "number", "min", "0", "max", "10", "step", "1", "placeholder", "2 (default)", 1, "at-form-input", 3, "ngModelChange", "ngModel"], ["href", "javascript:void(0)", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], ["type", "text", "placeholder", "Content type name", 1, "at-form-input", 3, "ngModelChange", "ngModel"], ["rows", "3", "placeholder", "Description...", 1, "at-form-textarea", 3, "ngModelChange", "ngModel"], ["SelectionMode", "single", "SelectableTypes", "leaf", "Placeholder", "Select AI model...", 3, "ValueChange", "BranchConfig", "LeafConfig", "Clearable", "Value"], [1, "at-form-row"], [1, "at-form-group", 2, "flex", "1"], ["type", "number", "min", "0", 1, "at-form-input", 3, "ngModelChange", "ngModel"], ["type", "number", "min", "1", 1, "at-form-input", 3, "ngModelChange", "ngModel"]], template: function ClassifySourceTypeFormDialogComponent_Template(rf, ctx) { if (rf & 1) {
2109
+ i0.ɵɵconditionalCreate(0, ClassifySourceTypeFormDialogComponent_Conditional_0_Template, 14, 5);
2110
+ } if (rf & 2) {
2111
+ i0.ɵɵconditional(ctx.FormMode !== "none" ? 0 : -1);
2112
+ } }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.NumberValueAccessor, i1.RangeValueAccessor, i1.CheckboxControlValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.MinValidator, i1.MaxValidator, i1.NgModel, i2.TreeDropdownComponent, i3.MJButtonDirective, i3.MJSwitchComponent, i4.DecimalPipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.cls-resize-handle[_ngcontent-%COMP%] {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: ew-resize;\n z-index: 1002;\n background: transparent;\n transition: background 0.12s;\n}\n.cls-resize-handle[_ngcontent-%COMP%]:hover, \n.cls-resize-handle[_ngcontent-%COMP%]:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n\n\n.cls-section[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n\n.cls-section--first[_ngcontent-%COMP%] {\n margin-top: 0;\n padding-top: 0;\n border-top: 0;\n}\n.cls-section-title[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 12px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.cls-section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n\n\n\n.cls-eff-toggle[_ngcontent-%COMP%] {\n margin-left: auto;\n font-weight: 600;\n}\n\n\n\n\n.cls-config[_ngcontent-%COMP%] {\n display: block;\n}\n\n\n\n.cls-mode-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 8px;\n}\n.cls-mode-card[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 10px 8px;\n cursor: pointer;\n text-align: center;\n transition: background 0.12s, border-color 0.12s, box-shadow 0.12s;\n user-select: none;\n}\n.cls-mode-card[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.cls-mode-card.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n border-color: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 1px var(--mj-brand-primary);\n}\n.cls-mode-ic[_ngcontent-%COMP%] { font-size: 16px; color: var(--mj-text-secondary); }\n.cls-mode-card.selected[_ngcontent-%COMP%] .cls-mode-ic[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.cls-mode-nm[_ngcontent-%COMP%] { font-size: 12px; font-weight: 700; color: var(--mj-text-primary); margin: 4px 0 2px; }\n.cls-mode-best[_ngcontent-%COMP%] { font-size: 10.5px; color: var(--mj-text-muted); line-height: 1.3; }\n\n\n\n.cls-threshold-pair[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 12px 14px;\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n}\n.cls-slider-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 16px;\n}\n@media (max-width: 560px) {\n .cls-slider-grid[_ngcontent-%COMP%] { grid-template-columns: 1fr; }\n}\n.cls-slider-field[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 4px; }\n.cls-slider-cap[_ngcontent-%COMP%] { font-size: 11px; color: var(--mj-text-secondary); }\n.cls-slider-cap[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-family: ui-monospace, monospace;\n color: var(--mj-text-primary);\n margin-left: 2px;\n}\n.cls-slider[_ngcontent-%COMP%] {\n appearance: none;\n -webkit-appearance: none;\n width: 100%;\n height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n margin: 2px 0;\n}\n.cls-slider[_ngcontent-%COMP%]::-webkit-slider-thumb {\n appearance: none;\n -webkit-appearance: none;\n width: 16px; height: 16px; border-radius: 50%;\n background: var(--mj-brand-primary);\n cursor: pointer;\n border: 2px solid var(--mj-bg-surface);\n}\n.cls-slider[_ngcontent-%COMP%]::-moz-range-thumb {\n width: 16px; height: 16px; border-radius: 50%;\n background: var(--mj-brand-primary);\n cursor: pointer;\n border: 2px solid var(--mj-bg-surface);\n}\n\n\n\n.cls-band[_ngcontent-%COMP%] {\n height: 8px;\n border-radius: 4px;\n margin: 10px 0 6px;\n background: linear-gradient(\n to right,\n color-mix(in srgb, var(--mj-status-error) 55%, transparent) 0%,\n color-mix(in srgb, var(--mj-status-warning) 55%, transparent) 50%,\n color-mix(in srgb, var(--mj-status-success) 55%, transparent) 100%\n );\n}\n.cls-band-legend[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n font-size: 10.5px;\n}\n.cls-band-key.reject[_ngcontent-%COMP%] { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.cls-band-key.review[_ngcontent-%COMP%] { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.cls-band-key.apply[_ngcontent-%COMP%] { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.cls-validation[_ngcontent-%COMP%] {\n font-size: 12px;\n padding: 8px 12px;\n margin-top: 8px;\n background: color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n color: var(--mj-status-error-text, var(--mj-status-error));\n border-radius: 4px;\n}\n\n\n\n.cls-toggle-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 10px 0;\n border-top: 1px dashed var(--mj-border-subtle);\n}\n.cls-toggle-label[_ngcontent-%COMP%] .t[_ngcontent-%COMP%] { display: block; font-size: 13px; font-weight: 600; color: var(--mj-text-primary); }\n.cls-toggle-label[_ngcontent-%COMP%] .d[_ngcontent-%COMP%] { display: block; font-size: 11px; color: var(--mj-text-muted); margin-top: 2px; }\n\n\n\n\n\n.cls-aside[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 12px;\n margin-top: 12px;\n}\n.cls-aside-title[_ngcontent-%COMP%] {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n font-weight: 700;\n margin: 0 0 8px;\n}\n.cls-eff-row[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n gap: 8px;\n padding: 6px 0;\n border-top: 1px solid var(--mj-border-subtle);\n font-size: 12px;\n}\n.cls-eff-row[_ngcontent-%COMP%]:first-of-type { border-top: 0; }\n.cls-eff-label[_ngcontent-%COMP%] { color: var(--mj-text-secondary); }\n.cls-eff-value[_ngcontent-%COMP%] { color: var(--mj-text-primary); font-weight: 600; text-align: right; }\n.cls-eff-origin[_ngcontent-%COMP%] {\n display: block;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n margin-top: 1px;\n}\n.cls-eff-origin.override[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n\n\n\n.cls-budget-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px 16px;\n margin-top: 8px;\n}\n@media (max-width: 480px) {\n .cls-budget-grid[_ngcontent-%COMP%] { grid-template-columns: 1fr; }\n}\n\n\n\n.cls-context-preview[_ngcontent-%COMP%] {\n margin: 0;\n padding: 10px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n color: var(--mj-text-secondary);\n font-size: 0.8rem;\n line-height: 1.45;\n white-space: pre-wrap;\n word-break: break-word;\n max-height: 200px;\n overflow-y: auto;\n}\n\n\n\n.cls-doc-callout[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-top: 12px;\n padding: 12px;\n background: color-mix(in srgb, var(--mj-status-info) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-info-border, var(--mj-border-default));\n border-radius: 6px;\n}\n.cls-doc-callout-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n color: var(--mj-text-secondary);\n font-size: 0.82rem;\n line-height: 1.4;\n}\n.cls-doc-callout-head[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-status-info); margin-top: 2px; }\n.cls-doc-form[_ngcontent-%COMP%] {\n margin-top: 10px;\n padding: 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n}\n.cls-doc-field-list[_ngcontent-%COMP%] {\n max-height: 180px;\n overflow-y: auto;\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n padding: 6px 8px;\n}\n.cls-doc-field-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 3px 0;\n font-size: 0.82rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n}"] });
2113
+ }
2114
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClassifySourceTypeFormDialogComponent, [{
2115
+ type: Component,
2116
+ args: [{ standalone: false, selector: 'classify-source-type-form-dialog', template: "<!-- \u2550\u2550\u2550\u2550\u2550\u2550 SLIDE-IN FORM OVERLAY \u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (FormMode !== 'none') {\n <div class=\"at-slide-overlay\" (click)=\"CloseForm()\"></div>\n <div class=\"at-slide-panel\" [style.width.px]=\"PanelWidth\">\n <!-- Left-edge drag handle: the panel slides in from the right, so its\n resizable edge is the LEFT. Dragging left widens the panel. -->\n <div class=\"cls-resize-handle\" (mousedown)=\"StartResize($event)\"\n role=\"separator\" aria-orientation=\"vertical\" aria-label=\"Resize panel\"></div>\n <div class=\"at-slide-header\">\n <h3>\n @if (FormMode === 'add-source') { Add Content Source }\n @else if (FormMode === 'edit-source') { Edit Content Source }\n @else if (FormMode === 'add-type') { Add Content Type }\n @else if (FormMode === 'edit-type') { Edit Content Type }\n </h3>\n <button class=\"at-slide-close\" aria-label=\"Close form\" (click)=\"CloseForm()\"><i class=\"fa-solid fa-times\"></i></button>\n </div>\n <div class=\"at-slide-body\">\n\n <!-- Source form -->\n @if (FormMode === 'add-source' || FormMode === 'edit-source') {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 SOURCE \u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"cls-section cls-section--first\">\n <div class=\"cls-section-title\"><i class=\"fa-solid fa-database\"></i> Source</div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Name</label>\n <input type=\"text\" class=\"at-form-input\" [(ngModel)]=\"FormSourceName\" placeholder=\"Source name\">\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Source Type</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormSourceTypeID\">\n <option value=\"\">Select source type...</option>\n @for (opt of SourceTypeOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n </div>\n <!-- Content Type + File Type: hidden for Entity source type -->\n @if (SelectedSourceTypeRequiresContentType) {\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Content Type</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormContentTypeID\">\n <option value=\"\">Select content type...</option>\n @for (opt of ContentTypeOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">File Type</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormFileTypeID\">\n <option value=\"\">Select file type...</option>\n @for (opt of FileTypeOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Dynamic source-type-specific fields from ConfigurationObject.RequiredFields -->\n @for (field of SelectedSourceTypeFields; track field.Key) {\n @if (!field.DependsOnField || FormSourceSpecificConfig[field.DependsOnField]) {\n @if (!field.ShowOnlyIfMultiple || GetDependentOptions(field).length > 1) {\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">{{ field.Label }} @if (field.Required) { <span class=\"at-required\">*</span> }</label>\n @switch (field.Type) {\n @case ('url') {\n <input type=\"url\" class=\"at-form-input\" [(ngModel)]=\"FormSourceSpecificConfig[field.Key]\"\n [placeholder]=\"field.Description || 'https://...'\">\n }\n @case ('path') {\n <input type=\"text\" class=\"at-form-input\" [(ngModel)]=\"FormSourceSpecificConfig[field.Key]\"\n [placeholder]=\"field.Description || '/path/to/...'\">\n }\n @case ('text') {\n <input type=\"text\" class=\"at-form-input\" [(ngModel)]=\"FormSourceSpecificConfig[field.Key]\"\n [placeholder]=\"field.Description || ''\" [value]=\"field.DefaultValue || ''\">\n }\n @case ('entity-picker') {\n <select class=\"at-form-select\" [(ngModel)]=\"FormSourceSpecificConfig[field.Key]\"\n (ngModelChange)=\"OnSourceFieldChanged(field.Key)\">\n <option value=\"\">Select entity...</option>\n @for (opt of EntitiesWithDocuments; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n }\n @case ('entity-doc-picker') {\n <select class=\"at-form-select\" [(ngModel)]=\"FormSourceSpecificConfig[field.Key]\">\n @for (opt of GetDependentOptions(field); track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n }\n @case ('storage-provider-picker') {\n <select class=\"at-form-select\" [(ngModel)]=\"FormSourceSpecificConfig[field.Key]\">\n <option value=\"\">Select provider...</option>\n @for (opt of StorageProviderOptions; track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n }\n @case ('dropdown') {\n <select class=\"at-form-select\" [(ngModel)]=\"FormSourceSpecificConfig[field.Key]\">\n <option value=\"\">Select...</option>\n @for (opt of field.Options || []; track opt.Value) {\n <option [value]=\"opt.Value\">{{ opt.Label }}</option>\n }\n </select>\n }\n }\n @if (field.Description) {\n <span class=\"at-form-hint\">{{ field.Description }}</span>\n }\n </div>\n }\n }\n }\n\n <!-- Inline Entity Document creation: shown when an Entity-type\n source's selected entity has no Entity Document yet. -->\n @if (SelectedEntityHasNoDocument) {\n <div class=\"cls-doc-callout\">\n <div class=\"cls-doc-callout-head\">\n <i class=\"fa-solid fa-circle-info\"></i>\n <span><strong>{{ SelectedEntityName }}</strong> has no Entity Document. One is required to classify its records.</span>\n </div>\n @if (!ShowInlineEntityDocForm) {\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"OpenInlineEntityDocForm()\">\n <i class=\"fa-solid fa-plus\"></i> Create Entity Document\n </button>\n }\n </div>\n\n @if (ShowInlineEntityDocForm) {\n <div class=\"cls-doc-form\">\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Document name</label>\n <input type=\"text\" class=\"at-form-input\" [(ngModel)]=\"NewEntityDocName\"\n placeholder=\"Document name\">\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Fields to include ({{ SelectedEntityDocFieldCount }} selected)</label>\n <div class=\"cls-doc-field-list\">\n @for (f of SelectedEntityFields; track f.Name) {\n <label class=\"cls-doc-field-row\">\n <input type=\"checkbox\" [(ngModel)]=\"NewEntityDocSelectedFields[f.Name]\">\n <span>{{ f.DisplayName }}</span>\n </label>\n }\n </div>\n </div>\n <div class=\"at-form-actions\">\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"CreateInlineEntityDocument()\" [disabled]=\"EntityDocSaving\">\n @if (EntityDocSaving) { <i class=\"fa-solid fa-spinner fa-spin\"></i> Creating\u2026 }\n @else { <i class=\"fa-solid fa-check\"></i> Create }\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"CancelInlineEntityDocForm()\">Cancel</button>\n </div>\n </div>\n }\n }\n </div><!-- /Source section -->\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 EMBEDDING & VECTORS \u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"cls-section\">\n <div class=\"cls-section-title\"><i class=\"fa-solid fa-cubes\"></i> Embedding &amp; Vectors</div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Embedding Model Override</label>\n <mj-tree-dropdown\n [BranchConfig]=\"EmbeddingVendorBranch\"\n [LeafConfig]=\"EmbeddingModelsLeaf\"\n SelectionMode=\"single\"\n SelectableTypes=\"leaf\"\n Placeholder=\"Use system default\"\n [Clearable]=\"true\"\n [Value]=\"ToCompositeKey(FormSourceEmbeddingModelID)\"\n (ValueChange)=\"FormSourceEmbeddingModelID = FromCompositeKey($event)\">\n </mj-tree-dropdown>\n <span class=\"at-form-hint\">Overrides Content Type default</span>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Vector Index Override</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormSourceVectorIndexID\">\n <option value=\"\">Use system default</option>\n @for (opt of VectorIndexOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n <span class=\"at-form-hint\">Overrides Content Type default</span>\n </div>\n </div><!-- /Embedding & Vectors section -->\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 CLASSIFICATION (full config parity, in-app) \u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"cls-section\">\n <div class=\"cls-section-title\">\n <i class=\"fa-solid fa-sliders\"></i> Classification\n <button mjButton variant=\"flat\" size=\"sm\" class=\"cls-eff-toggle\"\n (click)=\"ToggleEffectiveValues()\">\n <i class=\"fa-solid\" [class.fa-eye]=\"!ShowEffectiveValues\" [class.fa-eye-slash]=\"ShowEffectiveValues\"></i>\n {{ ShowEffectiveValues ? 'Hide effective values' : 'Show effective values' }}\n </button>\n </div>\n\n <div class=\"cls-config\">\n <!-- Taxonomy mode cards -->\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Taxonomy mode</label>\n <div class=\"cls-mode-grid\">\n @for (m of TaxonomyModes; track m.value) {\n <div class=\"cls-mode-card\" [class.selected]=\"CurrentMode === m.value\"\n (click)=\"SetMode(m.value)\">\n <i class=\"fa-solid {{ m.icon }} cls-mode-ic\"></i>\n <div class=\"cls-mode-nm\">{{ m.label }}</div>\n <div class=\"cls-mode-best\">{{ m.bestFor }}</div>\n </div>\n }\n </div>\n </div>\n\n <!-- Tag root -->\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Tag root</label>\n <select class=\"at-form-select\" [(ngModel)]=\"TagRootIDValue\">\n <option value=\"\">(none / whole taxonomy)</option>\n @for (opt of TagRootOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n <span class=\"at-form-hint\">Restricts the LLM's visible taxonomy + auto-grow target. Leave blank for the full taxonomy.</span>\n </div>\n\n <!-- Thresholds + gradient band -->\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Confidence thresholds</label>\n <div class=\"cls-threshold-pair\">\n <div class=\"cls-slider-grid\">\n <div class=\"cls-slider-field\">\n <span class=\"cls-slider-cap\">Match (auto-apply) <strong>{{ MatchThresholdValue | number: '1.2-2' }}</strong></span>\n <input type=\"range\" class=\"cls-slider\" min=\"0.50\" max=\"1.00\" step=\"0.01\"\n [ngModel]=\"MatchThresholdValue\" (ngModelChange)=\"MatchThresholdValue = $event\">\n </div>\n <div class=\"cls-slider-field\">\n <span class=\"cls-slider-cap\">Suggest (route to inbox) <strong>{{ SuggestThresholdValue | number: '1.2-2' }}</strong></span>\n <input type=\"range\" class=\"cls-slider\" min=\"0.50\" max=\"1.00\" step=\"0.01\"\n [ngModel]=\"SuggestThresholdValue\" (ngModelChange)=\"SuggestThresholdValue = $event\">\n </div>\n </div>\n <div class=\"cls-band\" aria-hidden=\"true\"></div>\n @if (ThresholdValidationMessage) {\n <div class=\"cls-validation\"><i class=\"fa-solid fa-circle-exclamation\"></i> {{ ThresholdValidationMessage }}</div>\n } @else {\n <div class=\"cls-band-legend\">\n <span class=\"cls-band-key reject\">reject / new</span>\n <span class=\"cls-band-key review\">review (inbox)</span>\n <span class=\"cls-band-key apply\">auto-apply</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Toggles -->\n <div class=\"cls-toggle-row\">\n <div class=\"cls-toggle-label\">\n <span class=\"t\">Share full taxonomy with the LLM</span>\n <span class=\"d\">When on, the LLM prompt includes the visible taxonomy. Larger taxonomies \u2192 higher token cost.</span>\n </div>\n <mj-switch [(ngModel)]=\"ShareTaxonomyValue\"></mj-switch>\n </div>\n <div class=\"cls-toggle-row\">\n <div class=\"cls-toggle-label\">\n <span class=\"t\">Vectorize new content</span>\n <span class=\"d\">When off, this source skips vectorization (the classifier still runs).</span>\n </div>\n <mj-switch [(ngModel)]=\"EnableVectorizationValue\"></mj-switch>\n </div>\n </div><!-- /cls-config -->\n\n <!-- Effective-values panel \u2014 inline + conditional (no longer a floating aside) -->\n @if (ShowEffectiveValues) {\n <div class=\"cls-aside\">\n <h5 class=\"cls-aside-title\">Effective values</h5>\n @for (row of EffectiveValues; track row.label) {\n <div class=\"cls-eff-row\">\n <span class=\"cls-eff-label\">{{ row.label }}</span>\n <span class=\"cls-eff-value\">{{ row.value }}\n <span class=\"cls-eff-origin\" [class.override]=\"row.origin === 'source override'\">{{ row.origin }}</span>\n </span>\n </div>\n }\n </div>\n }\n </div><!-- /Classification section -->\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 DOMAIN CONTEXT (source scope) \u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"cls-section\">\n <div class=\"cls-section-title\"><i class=\"fa-solid fa-comment-dots\"></i> Domain context</div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Source guidance</label>\n <textarea class=\"at-form-textarea\" rows=\"4\"\n [ngModel]=\"ClassificationContextValue\"\n (ngModelChange)=\"ClassificationContextValue = $event\"\n placeholder=\"Free-text guidance for the classifier about this source's domain \u2014 terminology, audience, what tags matter\u2026\"></textarea>\n <span class=\"at-form-hint\">Injected into the autotagging prompt at the source scope.</span>\n </div>\n\n <div class=\"cls-toggle-row\">\n <div class=\"cls-toggle-label\">\n <span class=\"t\">Substitutive mode</span>\n <span class=\"d\">When on, this source's guidance <em>replaces</em> the org/content-type context. When off (default), it's <em>added</em> to them.</span>\n </div>\n <mj-switch [(ngModel)]=\"IsSubstitutiveMode\"></mj-switch>\n </div>\n\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Effective context preview</label>\n <pre class=\"cls-context-preview\">{{ EffectiveContextPreview }}</pre>\n <span class=\"at-form-hint\">Org + source scopes shown. Content-type scope (if any) is also merged at run time.</span>\n </div>\n </div><!-- /Domain context section -->\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 RUN BUDGETS \u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"cls-section\">\n <div class=\"cls-section-title\"><i class=\"fa-solid fa-gauge\"></i> Run budgets</div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Max items per run</label>\n <input type=\"number\" min=\"0\" class=\"at-form-input\"\n [(ngModel)]=\"FormMaxItemsPerRun\" placeholder=\"unlimited\">\n <span class=\"at-form-hint\">\n Caps the number of content items handed to the LLM. Skipped (unchanged) items don't count.\n Paused work resumes on the next run.\n </span>\n </div>\n\n <div class=\"cls-budget-grid\">\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Max new tags / run</label>\n <input type=\"number\" min=\"0\" class=\"at-form-input\"\n [ngModel]=\"MaxNewTagsPerRunValue ?? ''\" (ngModelChange)=\"MaxNewTagsPerRunValue = $event\"\n placeholder=\"unlimited\">\n <span class=\"at-form-hint\">across all items</span>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Max new tags / item</label>\n <input type=\"number\" min=\"0\" class=\"at-form-input\"\n [ngModel]=\"MaxNewTagsPerItemValue ?? ''\" (ngModelChange)=\"MaxNewTagsPerItemValue = $event\"\n placeholder=\"unlimited\">\n <span class=\"at-form-hint\">extras \u2192 suggestions</span>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Max tokens / run</label>\n <input type=\"number\" min=\"0\" class=\"at-form-input\"\n [ngModel]=\"MaxTokensPerRunValue ?? ''\" (ngModelChange)=\"MaxTokensPerRunValue = $event\"\n placeholder=\"unlimited\">\n <span class=\"at-form-hint\">across all LLM calls</span>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Max cost / run (USD)</label>\n <input type=\"number\" min=\"0\" step=\"0.01\" class=\"at-form-input\"\n [ngModel]=\"MaxCostPerRunValue ?? ''\" (ngModelChange)=\"MaxCostPerRunValue = $event\"\n placeholder=\"unlimited\">\n <span class=\"at-form-hint\">$ stops the run</span>\n </div>\n </div>\n </div><!-- /Run budgets section -->\n\n @if (IsWebsiteSourceTypeSelected) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 CRAWL SETTINGS (website source only) \u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"cls-section\">\n <div class=\"cls-section-title\"><i class=\"fa-solid fa-spider\"></i> Crawl settings</div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Crawl depth</label>\n <input type=\"number\" min=\"0\" max=\"10\" step=\"1\" class=\"at-form-input\"\n [(ngModel)]=\"FormMaxDepth\" placeholder=\"2 (default)\">\n <span class=\"at-form-hint\">\n Recursion ceiling for in-domain links. <code>0</code> = just the start URL.\n <code>2</code> (default) = root + sections + content pages.\n </span>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">\n <input type=\"checkbox\" [(ngModel)]=\"FormCrawlSitesInLowerLevelDomain\">\n Crawl sites in lower-level domain\n </label>\n <span class=\"at-form-hint\">When on (default), the depth-aware recursive crawler runs. Turn off to crawl only the seed page.</span>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">\n <input type=\"checkbox\" [(ngModel)]=\"FormCrawlOtherSitesInTopLevelDomain\">\n Crawl other sites in top-level domain\n </label>\n <span class=\"at-form-hint\">When on, also adds sibling-path URLs found on the seed page. Off by default to avoid accidental fan-out.</span>\n </div>\n </div><!-- /Crawl settings section -->\n }\n\n <div class=\"at-form-actions\">\n <button class=\"at-action-btn at-primary-btn\" (click)=\"SaveSource()\" [disabled]=\"FormSaving\">\n @if (FormSaving) { <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving... }\n @else { <i class=\"fa-solid fa-check\"></i> Save }\n </button>\n <button class=\"at-action-btn at-secondary-btn\" (click)=\"CloseForm()\">Cancel</button>\n </div>\n\n @if (FormMode === 'edit-source' && EditingSourceID) {\n <div class=\"at-form-advanced-link\">\n <a href=\"javascript:void(0)\" (click)=\"OpenAdvancedSourceSettings()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n Open advanced settings \u2014 URL pattern, root URL, &amp; full entity form\n </a>\n <span class=\"at-form-hint\">The key classifier knobs (taxonomy mode, thresholds, tag root, budgets) are now editable inline above.</span>\n </div>\n }\n }\n\n <!-- Content Type form -->\n @if (FormMode === 'add-type' || FormMode === 'edit-type') {\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Name</label>\n <input type=\"text\" class=\"at-form-input\" [(ngModel)]=\"FormTypeName\" placeholder=\"Content type name\">\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Description</label>\n <textarea class=\"at-form-textarea\" [(ngModel)]=\"FormTypeDescription\" rows=\"3\" placeholder=\"Description...\"></textarea>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">AI Model (for tagging)</label>\n <mj-tree-dropdown\n [BranchConfig]=\"AIModelVendorBranch\"\n [LeafConfig]=\"AllModelsLeaf\"\n SelectionMode=\"single\"\n SelectableTypes=\"leaf\"\n Placeholder=\"Select AI model...\"\n [Clearable]=\"true\"\n [Value]=\"ToCompositeKey(FormTypeAIModelID)\"\n (ValueChange)=\"FormTypeAIModelID = FromCompositeKey($event)\">\n </mj-tree-dropdown>\n </div>\n <div class=\"at-form-row\">\n <div class=\"at-form-group\" style=\"flex: 1;\">\n <label class=\"at-form-label\">Min Tags</label>\n <input type=\"number\" class=\"at-form-input\" [(ngModel)]=\"FormTypeMinTags\" min=\"0\">\n </div>\n <div class=\"at-form-group\" style=\"flex: 1;\">\n <label class=\"at-form-label\">Max Tags</label>\n <input type=\"number\" class=\"at-form-input\" [(ngModel)]=\"FormTypeMaxTags\" min=\"1\">\n </div>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Embedding Model</label>\n <mj-tree-dropdown\n [BranchConfig]=\"EmbeddingVendorBranch\"\n [LeafConfig]=\"EmbeddingModelsLeaf\"\n SelectionMode=\"single\"\n SelectableTypes=\"leaf\"\n Placeholder=\"Use system default\"\n [Clearable]=\"true\"\n [Value]=\"ToCompositeKey(FormTypeEmbeddingModelID)\"\n (ValueChange)=\"FormTypeEmbeddingModelID = FromCompositeKey($event)\">\n </mj-tree-dropdown>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Vector Index</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormTypeVectorIndexID\">\n <option value=\"\">Use system default</option>\n @for (opt of VectorIndexOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n </div>\n <div class=\"at-form-actions\">\n <button class=\"at-action-btn at-primary-btn\" (click)=\"SaveContentType()\" [disabled]=\"FormSaving\">\n @if (FormSaving) { <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving... }\n @else { <i class=\"fa-solid fa-check\"></i> Save }\n </button>\n <button class=\"at-action-btn at-secondary-btn\" (click)=\"CloseForm()\">Cancel</button>\n </div>\n }\n </div>\n </div>\n}\n", styles: ["/*\n * Source + Content Type CRUD slide-in form dialog styles.\n *\n * The host (AutotaggingPipelineResourceComponent) uses ViewEncapsulation.None,\n * so its `.at-slide-*` / `.at-form-*` rules are global and already style this\n * dialog's markup while it renders inside the host shell.\n *\n * The `.cls-*` (Classification) rules below are NEW to the in-dashboard config\n * parity feature. All colors use semantic design tokens (no hardcoded hex), and\n * the threshold band gradient is built from color-mix() of semantic tokens so it\n * adapts to dark mode and white-labeling.\n */\n\n/* \u2500\u2500 Left-edge resize handle \u2500\u2500\n * The slide-in panel slides in from the right, so its resizable edge is the LEFT.\n * A thin full-height grab strip; tokenized hover color so it adapts to themes. */\n.cls-resize-handle {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: ew-resize;\n z-index: 1002;\n background: transparent;\n transition: background 0.12s;\n}\n.cls-resize-handle:hover,\n.cls-resize-handle:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n/* \u2500\u2500 Section shells (Source / Embedding / Classification / Run budgets / Crawl) \u2500\u2500 */\n.cls-section {\n margin-top: 8px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n/* The first section needs no separator above it. */\n.cls-section--first {\n margin-top: 0;\n padding-top: 0;\n border-top: 0;\n}\n.cls-section-title {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 12px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.cls-section-title i { color: var(--mj-brand-primary); }\n\n/* \"Show / hide effective values\" toggle, pushed to the right of the section title. */\n.cls-eff-toggle {\n margin-left: auto;\n font-weight: 600;\n}\n\n/* Single-column control stack. The effective-values panel now renders inline\n * below (full width within the section), not as a floating grid column. */\n.cls-config {\n display: block;\n}\n\n/* \u2500\u2500 Taxonomy mode cards \u2500\u2500 */\n.cls-mode-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 8px;\n}\n.cls-mode-card {\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 10px 8px;\n cursor: pointer;\n text-align: center;\n transition: background 0.12s, border-color 0.12s, box-shadow 0.12s;\n user-select: none;\n}\n.cls-mode-card:hover { background: var(--mj-bg-surface-hover); }\n.cls-mode-card.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n border-color: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 1px var(--mj-brand-primary);\n}\n.cls-mode-ic { font-size: 16px; color: var(--mj-text-secondary); }\n.cls-mode-card.selected .cls-mode-ic { color: var(--mj-brand-primary); }\n.cls-mode-nm { font-size: 12px; font-weight: 700; color: var(--mj-text-primary); margin: 4px 0 2px; }\n.cls-mode-best { font-size: 10.5px; color: var(--mj-text-muted); line-height: 1.3; }\n\n/* \u2500\u2500 Thresholds + gradient band \u2500\u2500 */\n.cls-threshold-pair {\n background: var(--mj-bg-surface-card);\n padding: 12px 14px;\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n}\n.cls-slider-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 16px;\n}\n@media (max-width: 560px) {\n .cls-slider-grid { grid-template-columns: 1fr; }\n}\n.cls-slider-field { display: flex; flex-direction: column; gap: 4px; }\n.cls-slider-cap { font-size: 11px; color: var(--mj-text-secondary); }\n.cls-slider-cap strong {\n font-family: ui-monospace, monospace;\n color: var(--mj-text-primary);\n margin-left: 2px;\n}\n.cls-slider {\n appearance: none;\n -webkit-appearance: none;\n width: 100%;\n height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n margin: 2px 0;\n}\n.cls-slider::-webkit-slider-thumb {\n appearance: none;\n -webkit-appearance: none;\n width: 16px; height: 16px; border-radius: 50%;\n background: var(--mj-brand-primary);\n cursor: pointer;\n border: 2px solid var(--mj-bg-surface);\n}\n.cls-slider::-moz-range-thumb {\n width: 16px; height: 16px; border-radius: 50%;\n background: var(--mj-brand-primary);\n cursor: pointer;\n border: 2px solid var(--mj-bg-surface);\n}\n\n/* The reject | review | auto-apply gradient band \u2014 all stops from semantic tokens. */\n.cls-band {\n height: 8px;\n border-radius: 4px;\n margin: 10px 0 6px;\n background: linear-gradient(\n to right,\n color-mix(in srgb, var(--mj-status-error) 55%, transparent) 0%,\n color-mix(in srgb, var(--mj-status-warning) 55%, transparent) 50%,\n color-mix(in srgb, var(--mj-status-success) 55%, transparent) 100%\n );\n}\n.cls-band-legend {\n display: flex;\n justify-content: space-between;\n font-size: 10.5px;\n}\n.cls-band-key.reject { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.cls-band-key.review { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.cls-band-key.apply { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.cls-validation {\n font-size: 12px;\n padding: 8px 12px;\n margin-top: 8px;\n background: color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n color: var(--mj-status-error-text, var(--mj-status-error));\n border-radius: 4px;\n}\n\n/* \u2500\u2500 Toggles \u2500\u2500 */\n.cls-toggle-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 10px 0;\n border-top: 1px dashed var(--mj-border-subtle);\n}\n.cls-toggle-label .t { display: block; font-size: 13px; font-weight: 600; color: var(--mj-text-primary); }\n.cls-toggle-label .d { display: block; font-size: 11px; color: var(--mj-text-muted); margin-top: 2px; }\n\n/* \u2500\u2500 Effective-values panel (inline + conditional) \u2500\u2500\n * Repurposed from the old floating aside: renders inline at the end of the\n * Classification section, full width within the section \u2014 never overlaps. */\n.cls-aside {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 12px;\n margin-top: 12px;\n}\n.cls-aside-title {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--mj-text-muted);\n font-weight: 700;\n margin: 0 0 8px;\n}\n.cls-eff-row {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n gap: 8px;\n padding: 6px 0;\n border-top: 1px solid var(--mj-border-subtle);\n font-size: 12px;\n}\n.cls-eff-row:first-of-type { border-top: 0; }\n.cls-eff-label { color: var(--mj-text-secondary); }\n.cls-eff-value { color: var(--mj-text-primary); font-weight: 600; text-align: right; }\n.cls-eff-origin {\n display: block;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n margin-top: 1px;\n}\n.cls-eff-origin.override { color: var(--mj-brand-primary); }\n\n/* \u2500\u2500 Budget grid \u2500\u2500 */\n.cls-budget-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px 16px;\n margin-top: 8px;\n}\n@media (max-width: 480px) {\n .cls-budget-grid { grid-template-columns: 1fr; }\n}\n\n/* \u2500\u2500 Domain context: effective-context preview \u2500\u2500 */\n.cls-context-preview {\n margin: 0;\n padding: 10px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n color: var(--mj-text-secondary);\n font-size: 0.8rem;\n line-height: 1.45;\n white-space: pre-wrap;\n word-break: break-word;\n max-height: 200px;\n overflow-y: auto;\n}\n\n/* \u2500\u2500 Inline Entity Document creation \u2500\u2500 */\n.cls-doc-callout {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-top: 12px;\n padding: 12px;\n background: color-mix(in srgb, var(--mj-status-info) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-info-border, var(--mj-border-default));\n border-radius: 6px;\n}\n.cls-doc-callout-head {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n color: var(--mj-text-secondary);\n font-size: 0.82rem;\n line-height: 1.4;\n}\n.cls-doc-callout-head i { color: var(--mj-status-info); margin-top: 2px; }\n.cls-doc-form {\n margin-top: 10px;\n padding: 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n}\n.cls-doc-field-list {\n max-height: 180px;\n overflow-y: auto;\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n padding: 6px 8px;\n}\n.cls-doc-field-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 3px 0;\n font-size: 0.82rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n}\n"] }]
2117
+ }], null, { Saved: [{
2118
+ type: Output
2119
+ }], ContentTypeMissing: [{
2120
+ type: Output
2121
+ }], NavigateToRecordRequested: [{
2122
+ type: Output
2123
+ }] }); })();
2124
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ClassifySourceTypeFormDialogComponent, { className: "ClassifySourceTypeFormDialogComponent", filePath: "src/AI/components/autotagging/dialogs/source-type-form.dialog.component.ts", lineNumber: 102 }); })();
2125
+ //# sourceMappingURL=source-type-form.dialog.component.js.map