@memberjunction/ng-dashboards 5.37.0 → 5.39.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 (328) hide show
  1. package/README.md +46 -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 +89 -842
  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 +1353 -7683
  29. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  30. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts +87 -0
  31. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts.map +1 -0
  32. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js +475 -0
  33. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js.map +1 -0
  34. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts +29 -0
  35. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts.map +1 -0
  36. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js +208 -0
  37. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js.map +1 -0
  38. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts +21 -0
  39. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts.map +1 -0
  40. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js +70 -0
  41. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js.map +1 -0
  42. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +235 -0
  43. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -0
  44. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +1735 -0
  45. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -0
  46. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts +61 -0
  47. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts.map +1 -0
  48. package/dist/AI/components/autotagging/shared/classify.dryrun.js +78 -0
  49. package/dist/AI/components/autotagging/shared/classify.dryrun.js.map +1 -0
  50. package/dist/AI/components/autotagging/shared/classify.format.d.ts +43 -0
  51. package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -0
  52. package/dist/AI/components/autotagging/shared/classify.format.js +209 -0
  53. package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -0
  54. package/dist/AI/components/autotagging/shared/classify.types.d.ts +276 -0
  55. package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -0
  56. package/dist/AI/components/autotagging/shared/classify.types.js +6 -0
  57. package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -0
  58. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts +103 -0
  59. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts.map +1 -0
  60. package/dist/AI/components/autotagging/tabs/health-tab.component.js +571 -0
  61. package/dist/AI/components/autotagging/tabs/health-tab.component.js.map +1 -0
  62. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +40 -0
  63. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -0
  64. package/dist/AI/components/autotagging/tabs/history-tab.component.js +402 -0
  65. package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -0
  66. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts +107 -0
  67. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts.map +1 -0
  68. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js +719 -0
  69. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js.map +1 -0
  70. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +122 -0
  71. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -0
  72. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +752 -0
  73. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -0
  74. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +166 -0
  75. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -0
  76. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1384 -0
  77. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -0
  78. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +70 -0
  79. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -0
  80. package/dist/AI/components/autotagging/tabs/tags-tab.component.js +448 -0
  81. package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -0
  82. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts +397 -0
  83. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts.map +1 -0
  84. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js +3490 -0
  85. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js.map +1 -0
  86. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +47 -0
  87. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -0
  88. package/dist/AI/components/autotagging/tabs/types-tab.component.js +220 -0
  89. package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -0
  90. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +293 -289
  91. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  92. package/dist/AI/components/models/model-management.component.js +209 -208
  93. package/dist/AI/components/models/model-management.component.js.map +1 -1
  94. package/dist/AI/components/prompts/prompt-management.component.js +130 -128
  95. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  96. package/dist/AI/components/requests/agent-requests-resource.component.js +61 -61
  97. package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
  98. package/dist/AI/components/system/system-configuration.component.js +17 -17
  99. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  100. package/dist/AI/components/tags/tags-resource.component.js +550 -532
  101. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  102. package/dist/AI/components/vectors/vector-management-resource.component.js +1 -1
  103. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  104. package/dist/AI/services/ai-instrumentation.service.d.ts +5 -0
  105. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  106. package/dist/AI/services/ai-instrumentation.service.js +14 -2
  107. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  108. package/dist/AI/services/cache-metrics.d.ts +50 -0
  109. package/dist/AI/services/cache-metrics.d.ts.map +1 -0
  110. package/dist/AI/services/cache-metrics.js +43 -0
  111. package/dist/AI/services/cache-metrics.js.map +1 -0
  112. package/dist/APIKeys/api-key-edit-panel.component.js +2 -2
  113. package/dist/APIKeys/api-keys-resource.component.js +132 -131
  114. package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
  115. package/dist/Actions/components/actions-overview.component.js +141 -141
  116. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  117. package/dist/Actions/components/execution-monitoring.component.js +15 -15
  118. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  119. package/dist/Actions/components/explorer/action-explorer.component.d.ts +0 -5
  120. package/dist/Actions/components/explorer/action-explorer.component.d.ts.map +1 -1
  121. package/dist/Actions/components/explorer/action-explorer.component.js +139 -212
  122. package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
  123. package/dist/Admin/admin-data-schema.component.js +2 -2
  124. package/dist/Admin/admin-data-schema.component.js.map +1 -1
  125. package/dist/Admin/admin-dev-tools-resource.component.js +2 -2
  126. package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
  127. package/dist/Admin/admin-identity-access.component.js +2 -2
  128. package/dist/Admin/admin-identity-access.component.js.map +1 -1
  129. package/dist/Admin/admin-monitoring.component.js +2 -2
  130. package/dist/Admin/admin-monitoring.component.js.map +1 -1
  131. package/dist/ApplicationRoles/application-roles-resource.component.js +54 -49
  132. package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
  133. package/dist/Communication/communication-logs-resource.component.d.ts +6 -0
  134. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  135. package/dist/Communication/communication-logs-resource.component.js +72 -50
  136. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  137. package/dist/Communication/communication-monitor-resource.component.js +103 -102
  138. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  139. package/dist/Communication/communication-providers-resource.component.js +52 -51
  140. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  141. package/dist/Communication/communication-runs-resource.component.js +39 -38
  142. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  143. package/dist/Communication/communication-templates-resource.component.d.ts +6 -0
  144. package/dist/Communication/communication-templates-resource.component.d.ts.map +1 -1
  145. package/dist/Communication/communication-templates-resource.component.js +92 -89
  146. package/dist/Communication/communication-templates-resource.component.js.map +1 -1
  147. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +73 -1
  148. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
  149. package/dist/ComponentStudio/component-studio-dashboard.component.js +512 -127
  150. package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
  151. package/dist/ComponentStudio/component-studio-resource.component.d.ts +22 -0
  152. package/dist/ComponentStudio/component-studio-resource.component.d.ts.map +1 -0
  153. package/dist/ComponentStudio/component-studio-resource.component.js +55 -0
  154. package/dist/ComponentStudio/component-studio-resource.component.js.map +1 -0
  155. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +104 -45
  156. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
  157. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +234 -331
  158. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
  159. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts +54 -0
  160. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts.map +1 -0
  161. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js +339 -0
  162. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js.map +1 -0
  163. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts +65 -0
  164. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts.map +1 -0
  165. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js +492 -0
  166. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js.map +1 -0
  167. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts +88 -0
  168. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts.map +1 -0
  169. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js +457 -0
  170. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js.map +1 -0
  171. package/dist/ComponentStudio/components/form-override-dialog.component.d.ts +106 -0
  172. package/dist/ComponentStudio/components/form-override-dialog.component.d.ts.map +1 -0
  173. package/dist/ComponentStudio/components/form-override-dialog.component.js +478 -0
  174. package/dist/ComponentStudio/components/form-override-dialog.component.js.map +1 -0
  175. package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +54 -0
  176. package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
  177. package/dist/ComponentStudio/components/workspace/component-preview.component.js +361 -50
  178. package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
  179. package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts +10 -0
  180. package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts.map +1 -1
  181. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +114 -45
  182. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
  183. package/dist/ComponentStudio/services/canvas-to-code.d.ts +32 -0
  184. package/dist/ComponentStudio/services/canvas-to-code.d.ts.map +1 -0
  185. package/dist/ComponentStudio/services/canvas-to-code.js +347 -0
  186. package/dist/ComponentStudio/services/canvas-to-code.js.map +1 -0
  187. package/dist/ComponentStudio/services/code-to-canvas.d.ts +32 -0
  188. package/dist/ComponentStudio/services/code-to-canvas.d.ts.map +1 -0
  189. package/dist/ComponentStudio/services/code-to-canvas.js +92 -0
  190. package/dist/ComponentStudio/services/code-to-canvas.js.map +1 -0
  191. package/dist/ComponentStudio/services/component-studio-state.service.d.ts +29 -0
  192. package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
  193. package/dist/ComponentStudio/services/component-studio-state.service.js +76 -0
  194. package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
  195. package/dist/ComponentStudio/services/entity-form-override.service.d.ts +86 -0
  196. package/dist/ComponentStudio/services/entity-form-override.service.d.ts.map +1 -0
  197. package/dist/ComponentStudio/services/entity-form-override.service.js +246 -0
  198. package/dist/ComponentStudio/services/entity-form-override.service.js.map +1 -0
  199. package/dist/ComponentStudio/services/field-binding-scanner.d.ts +29 -0
  200. package/dist/ComponentStudio/services/field-binding-scanner.d.ts.map +1 -0
  201. package/dist/ComponentStudio/services/field-binding-scanner.js +110 -0
  202. package/dist/ComponentStudio/services/field-binding-scanner.js.map +1 -0
  203. package/dist/ComponentStudio/services/form-canvas-model.d.ts +56 -0
  204. package/dist/ComponentStudio/services/form-canvas-model.d.ts.map +1 -0
  205. package/dist/ComponentStudio/services/form-canvas-model.js +35 -0
  206. package/dist/ComponentStudio/services/form-canvas-model.js.map +1 -0
  207. package/dist/ComponentStudio/services/form-host-props-fixture.d.ts +10 -0
  208. package/dist/ComponentStudio/services/form-host-props-fixture.d.ts.map +1 -0
  209. package/dist/ComponentStudio/services/form-host-props-fixture.js +10 -0
  210. package/dist/ComponentStudio/services/form-host-props-fixture.js.map +1 -0
  211. package/dist/Credentials/components/credentials-audit-resource.component.js +136 -135
  212. package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
  213. package/dist/Credentials/components/credentials-categories-resource.component.js +155 -152
  214. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  215. package/dist/Credentials/components/credentials-list-resource.component.js +119 -118
  216. package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
  217. package/dist/Credentials/components/credentials-overview-resource.component.js +129 -128
  218. package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
  219. package/dist/Credentials/components/credentials-types-resource.component.js +107 -106
  220. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  221. package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
  222. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  223. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +1 -1
  224. package/dist/DatabaseDesigner/components/entity-list.component.js +115 -114
  225. package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -1
  226. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +5 -6
  227. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -1
  228. package/dist/DatabaseDesigner/database-designer-dashboards.module.js +4 -5
  229. package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -1
  230. package/dist/DevTools/app-state-inspector.component.js +18 -17
  231. package/dist/DevTools/app-state-inspector.component.js.map +1 -1
  232. package/dist/DevTools/class-registry.component.js +88 -85
  233. package/dist/DevTools/class-registry.component.js.map +1 -1
  234. package/dist/DevTools/event-monitor.component.js +155 -150
  235. package/dist/DevTools/event-monitor.component.js.map +1 -1
  236. package/dist/DevTools/graphql-console.component.js +245 -243
  237. package/dist/DevTools/graphql-console.component.js.map +1 -1
  238. package/dist/DevTools/layout-inspector.component.js +18 -17
  239. package/dist/DevTools/layout-inspector.component.js.map +1 -1
  240. package/dist/EntityAdmin/entity-admin-dashboard.component.js +20 -19
  241. package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
  242. package/dist/FormBuilder/form-builder-resource.component.d.ts +964 -0
  243. package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -0
  244. package/dist/FormBuilder/form-builder-resource.component.js +4487 -0
  245. package/dist/FormBuilder/form-builder-resource.component.js.map +1 -0
  246. package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts +55 -0
  247. package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts.map +1 -0
  248. package/dist/FormBuilder/form-builder-version-rail.helpers.js +73 -0
  249. package/dist/FormBuilder/form-builder-version-rail.helpers.js.map +1 -0
  250. package/dist/Home/home-application.d.ts +21 -1
  251. package/dist/Home/home-application.d.ts.map +1 -1
  252. package/dist/Home/home-application.js +60 -8
  253. package/dist/Home/home-application.js.map +1 -1
  254. package/dist/Home/home-dashboard.component.js +2 -2
  255. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
  256. package/dist/Integration/components/activity/activity.component.js +236 -229
  257. package/dist/Integration/components/activity/activity.component.js.map +1 -1
  258. package/dist/Integration/components/connections/connections.component.js +390 -389
  259. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  260. package/dist/Integration/components/overview/overview.component.js +2 -2
  261. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +2 -2
  262. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
  263. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +45 -44
  264. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
  265. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +293 -291
  266. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  267. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +62 -61
  268. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
  269. package/dist/Lists/components/lists-browse-resource.component.d.ts +6 -2
  270. package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
  271. package/dist/Lists/components/lists-browse-resource.component.js +525 -566
  272. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  273. package/dist/Lists/components/lists-categories-resource.component.js +135 -134
  274. package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
  275. package/dist/Lists/components/lists-my-lists-resource.component.js +199 -198
  276. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  277. package/dist/MCP/mcp-dashboard.component.js +443 -438
  278. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  279. package/dist/QueryBrowser/query-browser-resource.component.d.ts +14 -14
  280. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  281. package/dist/QueryBrowser/query-browser-resource.component.js +11 -10
  282. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  283. package/dist/Scheduling/components/scheduling-activity.component.d.ts.map +1 -1
  284. package/dist/Scheduling/components/scheduling-activity.component.js +146 -147
  285. package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
  286. package/dist/Scheduling/components/scheduling-jobs.component.js +76 -75
  287. package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
  288. package/dist/Scheduling/components/scheduling-overview.component.js +97 -96
  289. package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
  290. package/dist/Scheduling/scheduling-dashboard.component.js +24 -22
  291. package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
  292. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts +2 -0
  293. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts.map +1 -1
  294. package/dist/Scheduling/services/scheduling-instrumentation.service.js +1 -0
  295. package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
  296. package/dist/Testing/components/testing-dashboard-tab-resource.component.js +1 -1
  297. package/dist/Testing/components/testing-explorer.component.d.ts +14 -4
  298. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  299. package/dist/Testing/components/testing-explorer.component.js +436 -427
  300. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  301. package/dist/Testing/components/testing-runs-resource.component.js +1 -1
  302. package/dist/Testing/components/testing-runs.component.js +116 -115
  303. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  304. package/dist/Testing/testing-dashboard.component.js +6 -7
  305. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  306. package/dist/VersionHistory/components/labels-resource.component.js +173 -172
  307. package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
  308. package/dist/VersionHistory/components/restore-resource.component.d.ts +6 -0
  309. package/dist/VersionHistory/components/restore-resource.component.d.ts.map +1 -1
  310. package/dist/VersionHistory/components/restore-resource.component.js +116 -92
  311. package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
  312. package/dist/ai-dashboards.module.d.ts +47 -35
  313. package/dist/ai-dashboards.module.d.ts.map +1 -1
  314. package/dist/ai-dashboards.module.js +40 -1
  315. package/dist/ai-dashboards.module.js.map +1 -1
  316. package/dist/communication-dashboards.module.d.ts +1 -1
  317. package/dist/communication-dashboards.module.d.ts.map +1 -1
  318. package/dist/communication-dashboards.module.js +7 -1
  319. package/dist/communication-dashboards.module.js.map +1 -1
  320. package/dist/component-studio-dashboards.module.d.ts +34 -22
  321. package/dist/component-studio-dashboards.module.d.ts.map +1 -1
  322. package/dist/component-studio-dashboards.module.js +65 -9
  323. package/dist/component-studio-dashboards.module.js.map +1 -1
  324. package/dist/testing-dashboards.module.d.ts +4 -5
  325. package/dist/testing-dashboards.module.d.ts.map +1 -1
  326. package/dist/testing-dashboards.module.js +7 -5
  327. package/dist/testing-dashboards.module.js.map +1 -1
  328. package/package.json +55 -53
@@ -0,0 +1,1735 @@
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 } from '@memberjunction/core';
25
+ import { KnowledgeHubMetadataEngine, 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.label;
42
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
43
+ i0.ɵɵtext(0, " Add Content Source ");
44
+ } }
45
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_6_Template(rf, ctx) { if (rf & 1) {
46
+ i0.ɵɵtext(0, " Edit Content Source ");
47
+ } }
48
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_7_Template(rf, ctx) { if (rf & 1) {
49
+ i0.ɵɵtext(0, " Add Content Type ");
50
+ } }
51
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
52
+ i0.ɵɵtext(0, " Edit Content Type ");
53
+ } }
54
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_15_Template(rf, ctx) { if (rf & 1) {
55
+ i0.ɵɵelementStart(0, "option", 15);
56
+ i0.ɵɵtext(1);
57
+ i0.ɵɵelementEnd();
58
+ } if (rf & 2) {
59
+ const opt_r4 = ctx.$implicit;
60
+ i0.ɵɵproperty("value", opt_r4.ID);
61
+ i0.ɵɵadvance();
62
+ i0.ɵɵtextInterpolate(opt_r4.Name);
63
+ } }
64
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_For_7_Template(rf, ctx) { if (rf & 1) {
65
+ i0.ɵɵelementStart(0, "option", 15);
66
+ i0.ɵɵtext(1);
67
+ i0.ɵɵelementEnd();
68
+ } if (rf & 2) {
69
+ const opt_r6 = ctx.$implicit;
70
+ i0.ɵɵproperty("value", opt_r6.ID);
71
+ i0.ɵɵadvance();
72
+ i0.ɵɵtextInterpolate(opt_r6.Name);
73
+ } }
74
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_For_15_Template(rf, ctx) { if (rf & 1) {
75
+ i0.ɵɵelementStart(0, "option", 15);
76
+ i0.ɵɵtext(1);
77
+ i0.ɵɵelementEnd();
78
+ } if (rf & 2) {
79
+ const opt_r7 = ctx.$implicit;
80
+ i0.ɵɵproperty("value", opt_r7.ID);
81
+ i0.ɵɵadvance();
82
+ i0.ɵɵtextInterpolate(opt_r7.Name);
83
+ } }
84
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_Template(rf, ctx) { if (rf & 1) {
85
+ const _r5 = i0.ɵɵgetCurrentView();
86
+ i0.ɵɵelementStart(0, "div", 10)(1, "label", 11);
87
+ i0.ɵɵtext(2, "Content Type");
88
+ i0.ɵɵelementEnd();
89
+ i0.ɵɵelementStart(3, "select", 13);
90
+ 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); });
91
+ i0.ɵɵelementStart(4, "option", 14);
92
+ i0.ɵɵtext(5, "Select content type...");
93
+ i0.ɵɵelementEnd();
94
+ i0.ɵɵrepeaterCreate(6, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_For_7_Template, 2, 2, "option", 15, _forTrack0);
95
+ i0.ɵɵelementEnd()();
96
+ i0.ɵɵelementStart(8, "div", 10)(9, "label", 11);
97
+ i0.ɵɵtext(10, "File Type");
98
+ i0.ɵɵelementEnd();
99
+ i0.ɵɵelementStart(11, "select", 13);
100
+ 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); });
101
+ i0.ɵɵelementStart(12, "option", 14);
102
+ i0.ɵɵtext(13, "Select file type...");
103
+ i0.ɵɵelementEnd();
104
+ i0.ɵɵrepeaterCreate(14, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_For_15_Template, 2, 2, "option", 15, _forTrack0);
105
+ i0.ɵɵelementEnd()();
106
+ } if (rf & 2) {
107
+ const ctx_r1 = i0.ɵɵnextContext(3);
108
+ i0.ɵɵadvance(3);
109
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormContentTypeID);
110
+ i0.ɵɵadvance(3);
111
+ i0.ɵɵrepeater(ctx_r1.ContentTypeOptions);
112
+ i0.ɵɵadvance(5);
113
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormFileTypeID);
114
+ i0.ɵɵadvance(3);
115
+ i0.ɵɵrepeater(ctx_r1.FileTypeOptions);
116
+ } }
117
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Conditional_3_Template(rf, ctx) { if (rf & 1) {
118
+ i0.ɵɵelementStart(0, "span", 48);
119
+ i0.ɵɵtext(1, "*");
120
+ i0.ɵɵelementEnd();
121
+ } }
122
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_4_Template(rf, ctx) { if (rf & 1) {
123
+ const _r8 = i0.ɵɵgetCurrentView();
124
+ i0.ɵɵelementStart(0, "input", 53);
125
+ 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); });
126
+ i0.ɵɵelementEnd();
127
+ } if (rf & 2) {
128
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
129
+ const ctx_r1 = i0.ɵɵnextContext(3);
130
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
131
+ i0.ɵɵproperty("placeholder", field_r9.Description || "https://...");
132
+ } }
133
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_5_Template(rf, ctx) { if (rf & 1) {
134
+ const _r10 = i0.ɵɵgetCurrentView();
135
+ i0.ɵɵelementStart(0, "input", 54);
136
+ 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); });
137
+ i0.ɵɵelementEnd();
138
+ } if (rf & 2) {
139
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
140
+ const ctx_r1 = i0.ɵɵnextContext(3);
141
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
142
+ i0.ɵɵproperty("placeholder", field_r9.Description || "/path/to/...");
143
+ } }
144
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_6_Template(rf, ctx) { if (rf & 1) {
145
+ const _r11 = i0.ɵɵgetCurrentView();
146
+ i0.ɵɵelementStart(0, "input", 55);
147
+ 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); });
148
+ i0.ɵɵelementEnd();
149
+ } if (rf & 2) {
150
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
151
+ const ctx_r1 = i0.ɵɵnextContext(3);
152
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
153
+ i0.ɵɵproperty("placeholder", field_r9.Description || "")("value", field_r9.DefaultValue || "");
154
+ } }
155
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_For_4_Template(rf, ctx) { if (rf & 1) {
156
+ i0.ɵɵelementStart(0, "option", 15);
157
+ i0.ɵɵtext(1);
158
+ i0.ɵɵelementEnd();
159
+ } if (rf & 2) {
160
+ const opt_r13 = ctx.$implicit;
161
+ i0.ɵɵproperty("value", opt_r13.ID);
162
+ i0.ɵɵadvance();
163
+ i0.ɵɵtextInterpolate(opt_r13.Name);
164
+ } }
165
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_Template(rf, ctx) { if (rf & 1) {
166
+ const _r12 = i0.ɵɵgetCurrentView();
167
+ i0.ɵɵelementStart(0, "select", 13);
168
+ 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); });
169
+ 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)); });
170
+ i0.ɵɵelementStart(1, "option", 14);
171
+ i0.ɵɵtext(2, "Select entity...");
172
+ i0.ɵɵelementEnd();
173
+ i0.ɵɵrepeaterCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_For_4_Template, 2, 2, "option", 15, _forTrack0);
174
+ i0.ɵɵelementEnd();
175
+ } if (rf & 2) {
176
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
177
+ const ctx_r1 = i0.ɵɵnextContext(3);
178
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
179
+ i0.ɵɵadvance(3);
180
+ i0.ɵɵrepeater(ctx_r1.EntitiesWithDocuments);
181
+ } }
182
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_For_2_Template(rf, ctx) { if (rf & 1) {
183
+ i0.ɵɵelementStart(0, "option", 15);
184
+ i0.ɵɵtext(1);
185
+ i0.ɵɵelementEnd();
186
+ } if (rf & 2) {
187
+ const opt_r15 = ctx.$implicit;
188
+ i0.ɵɵproperty("value", opt_r15.ID);
189
+ i0.ɵɵadvance();
190
+ i0.ɵɵtextInterpolate(opt_r15.Name);
191
+ } }
192
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_Template(rf, ctx) { if (rf & 1) {
193
+ const _r14 = i0.ɵɵgetCurrentView();
194
+ i0.ɵɵelementStart(0, "select", 13);
195
+ 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); });
196
+ i0.ɵɵrepeaterCreate(1, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_For_2_Template, 2, 2, "option", 15, _forTrack0);
197
+ i0.ɵɵelementEnd();
198
+ } if (rf & 2) {
199
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
200
+ const ctx_r1 = i0.ɵɵnextContext(3);
201
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
202
+ i0.ɵɵadvance();
203
+ i0.ɵɵrepeater(ctx_r1.GetDependentOptions(field_r9));
204
+ } }
205
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_9_For_4_Template(rf, ctx) { if (rf & 1) {
206
+ i0.ɵɵelementStart(0, "option", 15);
207
+ i0.ɵɵtext(1);
208
+ i0.ɵɵelementEnd();
209
+ } if (rf & 2) {
210
+ const opt_r17 = ctx.$implicit;
211
+ i0.ɵɵproperty("value", opt_r17);
212
+ i0.ɵɵadvance();
213
+ i0.ɵɵtextInterpolate(opt_r17);
214
+ } }
215
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_9_Template(rf, ctx) { if (rf & 1) {
216
+ const _r16 = i0.ɵɵgetCurrentView();
217
+ i0.ɵɵelementStart(0, "select", 13);
218
+ 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); });
219
+ i0.ɵɵelementStart(1, "option", 14);
220
+ i0.ɵɵtext(2, "Select provider...");
221
+ i0.ɵɵelementEnd();
222
+ 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);
223
+ i0.ɵɵelementEnd();
224
+ } if (rf & 2) {
225
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
226
+ const ctx_r1 = i0.ɵɵnextContext(3);
227
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
228
+ i0.ɵɵadvance(3);
229
+ i0.ɵɵrepeater(ctx_r1.StorageProviderOptions);
230
+ } }
231
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_For_4_Template(rf, ctx) { if (rf & 1) {
232
+ i0.ɵɵelementStart(0, "option", 15);
233
+ i0.ɵɵtext(1);
234
+ i0.ɵɵelementEnd();
235
+ } if (rf & 2) {
236
+ const opt_r19 = ctx.$implicit;
237
+ i0.ɵɵproperty("value", opt_r19.Value);
238
+ i0.ɵɵadvance();
239
+ i0.ɵɵtextInterpolate(opt_r19.Label);
240
+ } }
241
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_Template(rf, ctx) { if (rf & 1) {
242
+ const _r18 = i0.ɵɵgetCurrentView();
243
+ i0.ɵɵelementStart(0, "select", 13);
244
+ 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); });
245
+ i0.ɵɵelementStart(1, "option", 14);
246
+ i0.ɵɵtext(2, "Select...");
247
+ i0.ɵɵelementEnd();
248
+ i0.ɵɵrepeaterCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_For_4_Template, 2, 2, "option", 15, _forTrack3);
249
+ i0.ɵɵelementEnd();
250
+ } if (rf & 2) {
251
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
252
+ const ctx_r1 = i0.ɵɵnextContext(3);
253
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceSpecificConfig[field_r9.Key]);
254
+ i0.ɵɵadvance(3);
255
+ i0.ɵɵrepeater(field_r9.Options || i0.ɵɵpureFunction0(1, _c0));
256
+ } }
257
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Conditional_11_Template(rf, ctx) { if (rf & 1) {
258
+ i0.ɵɵelementStart(0, "span", 19);
259
+ i0.ɵɵtext(1);
260
+ i0.ɵɵelementEnd();
261
+ } if (rf & 2) {
262
+ const field_r9 = i0.ɵɵnextContext(3).$implicit;
263
+ i0.ɵɵadvance();
264
+ i0.ɵɵtextInterpolate(field_r9.Description);
265
+ } }
266
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
267
+ i0.ɵɵelementStart(0, "div", 10)(1, "label", 11);
268
+ i0.ɵɵtext(2);
269
+ i0.ɵɵconditionalCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Conditional_3_Template, 2, 0, "span", 48);
270
+ i0.ɵɵelementEnd();
271
+ i0.ɵɵconditionalCreate(4, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_4_Template, 1, 2, "input", 49)(5, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_5_Template, 1, 2, "input", 50)(6, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_6_Template, 1, 3, "input", 51)(7, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_7_Template, 5, 1, "select", 52)(8, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_8_Template, 3, 1, "select", 52)(9, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_9_Template, 5, 1, "select", 52)(10, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Case_10_Template, 5, 2, "select", 52);
272
+ i0.ɵɵconditionalCreate(11, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Conditional_11_Template, 2, 1, "span", 19);
273
+ i0.ɵɵelementEnd();
274
+ } if (rf & 2) {
275
+ let tmp_16_0;
276
+ const field_r9 = i0.ɵɵnextContext(2).$implicit;
277
+ i0.ɵɵadvance(2);
278
+ i0.ɵɵtextInterpolate1("", field_r9.Label, " ");
279
+ i0.ɵɵadvance();
280
+ i0.ɵɵconditional(field_r9.Required ? 3 : -1);
281
+ i0.ɵɵadvance();
282
+ 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);
283
+ i0.ɵɵadvance(7);
284
+ i0.ɵɵconditional(field_r9.Description ? 11 : -1);
285
+ } }
286
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Template(rf, ctx) { if (rf & 1) {
287
+ i0.ɵɵconditionalCreate(0, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Conditional_0_Template, 12, 4, "div", 10);
288
+ } if (rf & 2) {
289
+ const field_r9 = i0.ɵɵnextContext().$implicit;
290
+ const ctx_r1 = i0.ɵɵnextContext(3);
291
+ i0.ɵɵconditional(!field_r9.ShowOnlyIfMultiple || ctx_r1.GetDependentOptions(field_r9).length > 1 ? 0 : -1);
292
+ } }
293
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Template(rf, ctx) { if (rf & 1) {
294
+ i0.ɵɵconditionalCreate(0, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Conditional_0_Template, 1, 1);
295
+ } if (rf & 2) {
296
+ const field_r9 = ctx.$implicit;
297
+ const ctx_r1 = i0.ɵɵnextContext(3);
298
+ i0.ɵɵconditional(!field_r9.DependsOnField || ctx_r1.FormSourceSpecificConfig[field_r9.DependsOnField] ? 0 : -1);
299
+ } }
300
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_36_Template(rf, ctx) { if (rf & 1) {
301
+ i0.ɵɵelementStart(0, "option", 15);
302
+ i0.ɵɵtext(1);
303
+ i0.ɵɵelementEnd();
304
+ } if (rf & 2) {
305
+ const opt_r20 = ctx.$implicit;
306
+ i0.ɵɵproperty("value", opt_r20.ID);
307
+ i0.ɵɵadvance();
308
+ i0.ɵɵtextInterpolate(opt_r20.Name);
309
+ } }
310
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_52_Template(rf, ctx) { if (rf & 1) {
311
+ const _r21 = i0.ɵɵgetCurrentView();
312
+ i0.ɵɵelementStart(0, "div", 56);
313
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_52_Template_div_click_0_listener() { const m_r22 = i0.ɵɵrestoreView(_r21).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SetMode(m_r22.value)); });
314
+ i0.ɵɵelement(1, "i");
315
+ i0.ɵɵelementStart(2, "div", 57);
316
+ i0.ɵɵtext(3);
317
+ i0.ɵɵelementEnd();
318
+ i0.ɵɵelementStart(4, "div", 58);
319
+ i0.ɵɵtext(5);
320
+ i0.ɵɵelementEnd()();
321
+ } if (rf & 2) {
322
+ const m_r22 = ctx.$implicit;
323
+ const ctx_r1 = i0.ɵɵnextContext(3);
324
+ i0.ɵɵclassProp("selected", ctx_r1.CurrentMode === m_r22.value);
325
+ i0.ɵɵadvance();
326
+ i0.ɵɵclassMap(i0.ɵɵinterpolate1("fa-solid ", m_r22.icon, " cls-mode-ic"));
327
+ i0.ɵɵadvance(2);
328
+ i0.ɵɵtextInterpolate(m_r22.label);
329
+ i0.ɵɵadvance(2);
330
+ i0.ɵɵtextInterpolate(m_r22.bestFor);
331
+ } }
332
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_60_Template(rf, ctx) { if (rf & 1) {
333
+ i0.ɵɵelementStart(0, "option", 15);
334
+ i0.ɵɵtext(1);
335
+ i0.ɵɵelementEnd();
336
+ } if (rf & 2) {
337
+ const opt_r23 = ctx.$implicit;
338
+ i0.ɵɵproperty("value", opt_r23.ID);
339
+ i0.ɵɵadvance();
340
+ i0.ɵɵtextInterpolate(opt_r23.Name);
341
+ } }
342
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_83_Template(rf, ctx) { if (rf & 1) {
343
+ i0.ɵɵelementStart(0, "div", 32);
344
+ i0.ɵɵelement(1, "i", 59);
345
+ i0.ɵɵtext(2);
346
+ i0.ɵɵelementEnd();
347
+ } if (rf & 2) {
348
+ const ctx_r1 = i0.ɵɵnextContext(3);
349
+ i0.ɵɵadvance(2);
350
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.ThresholdValidationMessage);
351
+ } }
352
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_84_Template(rf, ctx) { if (rf & 1) {
353
+ i0.ɵɵelementStart(0, "div", 33)(1, "span", 60);
354
+ i0.ɵɵtext(2, "reject / new");
355
+ i0.ɵɵelementEnd();
356
+ i0.ɵɵelementStart(3, "span", 61);
357
+ i0.ɵɵtext(4, "review (inbox)");
358
+ i0.ɵɵelementEnd();
359
+ i0.ɵɵelementStart(5, "span", 62);
360
+ i0.ɵɵtext(6, "auto-apply");
361
+ i0.ɵɵelementEnd()();
362
+ } }
363
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_99_For_4_Template(rf, ctx) { if (rf & 1) {
364
+ i0.ɵɵelementStart(0, "div", 64)(1, "span", 65);
365
+ i0.ɵɵtext(2);
366
+ i0.ɵɵelementEnd();
367
+ i0.ɵɵelementStart(3, "span", 66);
368
+ i0.ɵɵtext(4);
369
+ i0.ɵɵelementStart(5, "span", 67);
370
+ i0.ɵɵtext(6);
371
+ i0.ɵɵelementEnd()()();
372
+ } if (rf & 2) {
373
+ const row_r24 = ctx.$implicit;
374
+ i0.ɵɵadvance(2);
375
+ i0.ɵɵtextInterpolate(row_r24.label);
376
+ i0.ɵɵadvance(2);
377
+ i0.ɵɵtextInterpolate1("", row_r24.value, " ");
378
+ i0.ɵɵadvance();
379
+ i0.ɵɵclassProp("override", row_r24.origin === "source override");
380
+ i0.ɵɵadvance();
381
+ i0.ɵɵtextInterpolate(row_r24.origin);
382
+ } }
383
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_99_Template(rf, ctx) { if (rf & 1) {
384
+ i0.ɵɵelementStart(0, "div", 39)(1, "h5", 63);
385
+ i0.ɵɵtext(2, "Effective values");
386
+ i0.ɵɵelementEnd();
387
+ i0.ɵɵrepeaterCreate(3, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_99_For_4_Template, 7, 5, "div", 64, _forTrack4);
388
+ i0.ɵɵelementEnd();
389
+ } if (rf & 2) {
390
+ const ctx_r1 = i0.ɵɵnextContext(3);
391
+ i0.ɵɵadvance(3);
392
+ i0.ɵɵrepeater(ctx_r1.EffectiveValues);
393
+ } }
394
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_135_Template(rf, ctx) { if (rf & 1) {
395
+ const _r25 = i0.ɵɵgetCurrentView();
396
+ i0.ɵɵelementStart(0, "div", 16)(1, "div", 8);
397
+ i0.ɵɵelement(2, "i", 68);
398
+ i0.ɵɵtext(3, " Crawl settings");
399
+ i0.ɵɵelementEnd();
400
+ i0.ɵɵelementStart(4, "div", 10)(5, "label", 11);
401
+ i0.ɵɵtext(6, "Crawl depth");
402
+ i0.ɵɵelementEnd();
403
+ i0.ɵɵelementStart(7, "input", 69);
404
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_135_Template_input_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r25); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormMaxDepth, $event) || (ctx_r1.FormMaxDepth = $event); return i0.ɵɵresetView($event); });
405
+ i0.ɵɵelementEnd();
406
+ i0.ɵɵelementStart(8, "span", 19);
407
+ i0.ɵɵtext(9, " Recursion ceiling for in-domain links. ");
408
+ i0.ɵɵelementStart(10, "code");
409
+ i0.ɵɵtext(11, "0");
410
+ i0.ɵɵelementEnd();
411
+ i0.ɵɵtext(12, " = just the start URL. ");
412
+ i0.ɵɵelementStart(13, "code");
413
+ i0.ɵɵtext(14, "2");
414
+ i0.ɵɵelementEnd();
415
+ i0.ɵɵtext(15, " (default) = root + sections + content pages. ");
416
+ i0.ɵɵelementEnd()();
417
+ i0.ɵɵelementStart(16, "div", 10)(17, "label", 11)(18, "input", 70);
418
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_135_Template_input_ngModelChange_18_listener($event) { i0.ɵɵrestoreView(_r25); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormCrawlSitesInLowerLevelDomain, $event) || (ctx_r1.FormCrawlSitesInLowerLevelDomain = $event); return i0.ɵɵresetView($event); });
419
+ i0.ɵɵelementEnd();
420
+ i0.ɵɵtext(19, " Crawl sites in lower-level domain ");
421
+ i0.ɵɵelementEnd();
422
+ i0.ɵɵelementStart(20, "span", 19);
423
+ i0.ɵɵtext(21, "When on (default), the depth-aware recursive crawler runs. Turn off to crawl only the seed page.");
424
+ i0.ɵɵelementEnd()();
425
+ i0.ɵɵelementStart(22, "div", 10)(23, "label", 11)(24, "input", 70);
426
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_135_Template_input_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r25); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.FormCrawlOtherSitesInTopLevelDomain, $event) || (ctx_r1.FormCrawlOtherSitesInTopLevelDomain = $event); return i0.ɵɵresetView($event); });
427
+ i0.ɵɵelementEnd();
428
+ i0.ɵɵtext(25, " Crawl other sites in top-level domain ");
429
+ i0.ɵɵelementEnd();
430
+ i0.ɵɵelementStart(26, "span", 19);
431
+ i0.ɵɵtext(27, "When on, also adds sibling-path URLs found on the seed page. Off by default to avoid accidental fan-out.");
432
+ i0.ɵɵelementEnd()()();
433
+ } if (rf & 2) {
434
+ const ctx_r1 = i0.ɵɵnextContext(3);
435
+ i0.ɵɵadvance(7);
436
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormMaxDepth);
437
+ i0.ɵɵadvance(11);
438
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormCrawlSitesInLowerLevelDomain);
439
+ i0.ɵɵadvance(6);
440
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormCrawlOtherSitesInTopLevelDomain);
441
+ } }
442
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_138_Template(rf, ctx) { if (rf & 1) {
443
+ i0.ɵɵelement(0, "i", 71);
444
+ i0.ɵɵtext(1, " Saving... ");
445
+ } }
446
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_139_Template(rf, ctx) { if (rf & 1) {
447
+ i0.ɵɵelement(0, "i", 72);
448
+ i0.ɵɵtext(1, " Save ");
449
+ } }
450
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_142_Template(rf, ctx) { if (rf & 1) {
451
+ const _r26 = i0.ɵɵgetCurrentView();
452
+ i0.ɵɵelementStart(0, "div", 47)(1, "a", 73);
453
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_142_Template_a_click_1_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OpenAdvancedSourceSettings()); });
454
+ i0.ɵɵelement(2, "i", 74);
455
+ i0.ɵɵtext(3, " Open advanced settings \u2014 URL pattern, root URL, & full entity form ");
456
+ i0.ɵɵelementEnd();
457
+ i0.ɵɵelementStart(4, "span", 19);
458
+ i0.ɵɵtext(5, "The key classifier knobs (taxonomy mode, thresholds, tag root, budgets) are now editable inline above.");
459
+ i0.ɵɵelementEnd()();
460
+ } }
461
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template(rf, ctx) { if (rf & 1) {
462
+ const _r3 = i0.ɵɵgetCurrentView();
463
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 8);
464
+ i0.ɵɵelement(2, "i", 9);
465
+ i0.ɵɵtext(3, " Source");
466
+ i0.ɵɵelementEnd();
467
+ i0.ɵɵelementStart(4, "div", 10)(5, "label", 11);
468
+ i0.ɵɵtext(6, "Name");
469
+ i0.ɵɵelementEnd();
470
+ i0.ɵɵelementStart(7, "input", 12);
471
+ 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); });
472
+ i0.ɵɵelementEnd()();
473
+ i0.ɵɵelementStart(8, "div", 10)(9, "label", 11);
474
+ i0.ɵɵtext(10, "Source Type");
475
+ i0.ɵɵelementEnd();
476
+ i0.ɵɵelementStart(11, "select", 13);
477
+ 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); });
478
+ i0.ɵɵelementStart(12, "option", 14);
479
+ i0.ɵɵtext(13, "Select source type...");
480
+ i0.ɵɵelementEnd();
481
+ i0.ɵɵrepeaterCreate(14, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_15_Template, 2, 2, "option", 15, _forTrack0);
482
+ i0.ɵɵelementEnd()();
483
+ i0.ɵɵconditionalCreate(16, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_16_Template, 16, 2);
484
+ i0.ɵɵrepeaterCreate(17, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_18_Template, 1, 1, null, null, _forTrack1);
485
+ i0.ɵɵelementEnd();
486
+ i0.ɵɵelementStart(19, "div", 16)(20, "div", 8);
487
+ i0.ɵɵelement(21, "i", 17);
488
+ i0.ɵɵtext(22, " Embedding & Vectors");
489
+ i0.ɵɵelementEnd();
490
+ i0.ɵɵelementStart(23, "div", 10)(24, "label", 11);
491
+ i0.ɵɵtext(25, "Embedding Model Override");
492
+ i0.ɵɵelementEnd();
493
+ i0.ɵɵelementStart(26, "mj-tree-dropdown", 18);
494
+ i0.ɵɵlistener("ValueChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_mj_tree_dropdown_ValueChange_26_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.FormSourceEmbeddingModelID = ctx_r1.FromCompositeKey($event)); });
495
+ i0.ɵɵelementEnd();
496
+ i0.ɵɵelementStart(27, "span", 19);
497
+ i0.ɵɵtext(28, "Overrides Content Type default");
498
+ i0.ɵɵelementEnd()();
499
+ i0.ɵɵelementStart(29, "div", 10)(30, "label", 11);
500
+ i0.ɵɵtext(31, "Vector Index Override");
501
+ i0.ɵɵelementEnd();
502
+ i0.ɵɵelementStart(32, "select", 13);
503
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_select_ngModelChange_32_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); });
504
+ i0.ɵɵelementStart(33, "option", 14);
505
+ i0.ɵɵtext(34, "Use system default");
506
+ i0.ɵɵelementEnd();
507
+ i0.ɵɵrepeaterCreate(35, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_36_Template, 2, 2, "option", 15, _forTrack0);
508
+ i0.ɵɵelementEnd();
509
+ i0.ɵɵelementStart(37, "span", 19);
510
+ i0.ɵɵtext(38, "Overrides Content Type default");
511
+ i0.ɵɵelementEnd()()();
512
+ i0.ɵɵelementStart(39, "div", 16)(40, "div", 8);
513
+ i0.ɵɵelement(41, "i", 20);
514
+ i0.ɵɵtext(42, " Classification ");
515
+ i0.ɵɵelementStart(43, "button", 21);
516
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_button_click_43_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleEffectiveValues()); });
517
+ i0.ɵɵelement(44, "i", 22);
518
+ i0.ɵɵtext(45);
519
+ i0.ɵɵelementEnd()();
520
+ i0.ɵɵelementStart(46, "div", 23)(47, "div", 10)(48, "label", 11);
521
+ i0.ɵɵtext(49, "Taxonomy mode");
522
+ i0.ɵɵelementEnd();
523
+ i0.ɵɵelementStart(50, "div", 24);
524
+ i0.ɵɵrepeaterCreate(51, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_52_Template, 6, 7, "div", 25, _forTrack2);
525
+ i0.ɵɵelementEnd()();
526
+ i0.ɵɵelementStart(53, "div", 10)(54, "label", 11);
527
+ i0.ɵɵtext(55, "Tag root");
528
+ i0.ɵɵelementEnd();
529
+ i0.ɵɵelementStart(56, "select", 13);
530
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_select_ngModelChange_56_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); });
531
+ i0.ɵɵelementStart(57, "option", 14);
532
+ i0.ɵɵtext(58, "(none / whole taxonomy)");
533
+ i0.ɵɵelementEnd();
534
+ i0.ɵɵrepeaterCreate(59, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_For_60_Template, 2, 2, "option", 15, _forTrack0);
535
+ i0.ɵɵelementEnd();
536
+ i0.ɵɵelementStart(61, "span", 19);
537
+ i0.ɵɵtext(62, "Restricts the LLM's visible taxonomy + auto-grow target. Leave blank for the full taxonomy.");
538
+ i0.ɵɵelementEnd()();
539
+ i0.ɵɵelementStart(63, "div", 10)(64, "label", 11);
540
+ i0.ɵɵtext(65, "Confidence thresholds");
541
+ i0.ɵɵelementEnd();
542
+ i0.ɵɵelementStart(66, "div", 26)(67, "div", 27)(68, "div", 28)(69, "span", 29);
543
+ i0.ɵɵtext(70, "Match (auto-apply) ");
544
+ i0.ɵɵelementStart(71, "strong");
545
+ i0.ɵɵtext(72);
546
+ i0.ɵɵpipe(73, "number");
547
+ i0.ɵɵelementEnd()();
548
+ i0.ɵɵelementStart(74, "input", 30);
549
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_74_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MatchThresholdValue = $event); });
550
+ i0.ɵɵelementEnd()();
551
+ i0.ɵɵelementStart(75, "div", 28)(76, "span", 29);
552
+ i0.ɵɵtext(77, "Suggest (route to inbox) ");
553
+ i0.ɵɵelementStart(78, "strong");
554
+ i0.ɵɵtext(79);
555
+ i0.ɵɵpipe(80, "number");
556
+ i0.ɵɵelementEnd()();
557
+ i0.ɵɵelementStart(81, "input", 30);
558
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_81_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SuggestThresholdValue = $event); });
559
+ i0.ɵɵelementEnd()()();
560
+ i0.ɵɵelement(82, "div", 31);
561
+ i0.ɵɵconditionalCreate(83, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_83_Template, 3, 1, "div", 32)(84, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_84_Template, 7, 0, "div", 33);
562
+ i0.ɵɵelementEnd()();
563
+ i0.ɵɵelementStart(85, "div", 34)(86, "div", 35)(87, "span", 36);
564
+ i0.ɵɵtext(88, "Share full taxonomy with the LLM");
565
+ i0.ɵɵelementEnd();
566
+ i0.ɵɵelementStart(89, "span", 37);
567
+ i0.ɵɵtext(90, "When on, the LLM prompt includes the visible taxonomy. Larger taxonomies \u2192 higher token cost.");
568
+ i0.ɵɵelementEnd()();
569
+ i0.ɵɵelementStart(91, "mj-switch", 38);
570
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_mj_switch_ngModelChange_91_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); });
571
+ i0.ɵɵelementEnd()();
572
+ i0.ɵɵelementStart(92, "div", 34)(93, "div", 35)(94, "span", 36);
573
+ i0.ɵɵtext(95, "Vectorize new content");
574
+ i0.ɵɵelementEnd();
575
+ i0.ɵɵelementStart(96, "span", 37);
576
+ i0.ɵɵtext(97, "When off, this source skips vectorization (the classifier still runs).");
577
+ i0.ɵɵelementEnd()();
578
+ i0.ɵɵelementStart(98, "mj-switch", 38);
579
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_mj_switch_ngModelChange_98_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); });
580
+ i0.ɵɵelementEnd()()();
581
+ i0.ɵɵconditionalCreate(99, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_99_Template, 5, 0, "div", 39);
582
+ i0.ɵɵelementEnd();
583
+ i0.ɵɵelementStart(100, "div", 16)(101, "div", 8);
584
+ i0.ɵɵelement(102, "i", 40);
585
+ i0.ɵɵtext(103, " Run budgets");
586
+ i0.ɵɵelementEnd();
587
+ i0.ɵɵelementStart(104, "div", 10)(105, "label", 11);
588
+ i0.ɵɵtext(106, "Max items per run");
589
+ i0.ɵɵelementEnd();
590
+ i0.ɵɵelementStart(107, "input", 41);
591
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_107_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); });
592
+ i0.ɵɵelementEnd();
593
+ i0.ɵɵelementStart(108, "span", 19);
594
+ i0.ɵɵtext(109, " Caps the number of content items handed to the LLM. Skipped (unchanged) items don't count. Paused work resumes on the next run. ");
595
+ i0.ɵɵelementEnd()();
596
+ i0.ɵɵelementStart(110, "div", 42)(111, "div", 10)(112, "label", 11);
597
+ i0.ɵɵtext(113, "Max new tags / run");
598
+ i0.ɵɵelementEnd();
599
+ i0.ɵɵelementStart(114, "input", 41);
600
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_114_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MaxNewTagsPerRunValue = $event); });
601
+ i0.ɵɵelementEnd();
602
+ i0.ɵɵelementStart(115, "span", 19);
603
+ i0.ɵɵtext(116, "across all items");
604
+ i0.ɵɵelementEnd()();
605
+ i0.ɵɵelementStart(117, "div", 10)(118, "label", 11);
606
+ i0.ɵɵtext(119, "Max new tags / item");
607
+ i0.ɵɵelementEnd();
608
+ i0.ɵɵelementStart(120, "input", 41);
609
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_120_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MaxNewTagsPerItemValue = $event); });
610
+ i0.ɵɵelementEnd();
611
+ i0.ɵɵelementStart(121, "span", 19);
612
+ i0.ɵɵtext(122, "extras \u2192 suggestions");
613
+ i0.ɵɵelementEnd()();
614
+ i0.ɵɵelementStart(123, "div", 10)(124, "label", 11);
615
+ i0.ɵɵtext(125, "Max tokens / run");
616
+ i0.ɵɵelementEnd();
617
+ i0.ɵɵelementStart(126, "input", 41);
618
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_126_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MaxTokensPerRunValue = $event); });
619
+ i0.ɵɵelementEnd();
620
+ i0.ɵɵelementStart(127, "span", 19);
621
+ i0.ɵɵtext(128, "across all LLM calls");
622
+ i0.ɵɵelementEnd()();
623
+ i0.ɵɵelementStart(129, "div", 10)(130, "label", 11);
624
+ i0.ɵɵtext(131, "Max cost / run (USD)");
625
+ i0.ɵɵelementEnd();
626
+ i0.ɵɵelementStart(132, "input", 43);
627
+ i0.ɵɵlistener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_input_ngModelChange_132_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MaxCostPerRunValue = $event); });
628
+ i0.ɵɵelementEnd();
629
+ i0.ɵɵelementStart(133, "span", 19);
630
+ i0.ɵɵtext(134, "$ stops the run");
631
+ i0.ɵɵelementEnd()()()();
632
+ i0.ɵɵconditionalCreate(135, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_135_Template, 28, 3, "div", 16);
633
+ i0.ɵɵelementStart(136, "div", 44)(137, "button", 45);
634
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_button_click_137_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SaveSource()); });
635
+ i0.ɵɵconditionalCreate(138, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_138_Template, 2, 0)(139, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_139_Template, 2, 0);
636
+ i0.ɵɵelementEnd();
637
+ i0.ɵɵelementStart(140, "button", 46);
638
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template_button_click_140_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.CloseForm()); });
639
+ i0.ɵɵtext(141, "Cancel");
640
+ i0.ɵɵelementEnd()();
641
+ i0.ɵɵconditionalCreate(142, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Conditional_142_Template, 6, 0, "div", 47);
642
+ } if (rf & 2) {
643
+ const ctx_r1 = i0.ɵɵnextContext(2);
644
+ i0.ɵɵadvance(7);
645
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceName);
646
+ i0.ɵɵadvance(4);
647
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceTypeID);
648
+ i0.ɵɵadvance(3);
649
+ i0.ɵɵrepeater(ctx_r1.SourceTypeOptions);
650
+ i0.ɵɵadvance(2);
651
+ i0.ɵɵconditional(ctx_r1.SelectedSourceTypeRequiresContentType ? 16 : -1);
652
+ i0.ɵɵadvance();
653
+ i0.ɵɵrepeater(ctx_r1.SelectedSourceTypeFields);
654
+ i0.ɵɵadvance(9);
655
+ i0.ɵɵproperty("BranchConfig", ctx_r1.EmbeddingVendorBranch)("LeafConfig", ctx_r1.EmbeddingModelsLeaf)("Clearable", true)("Value", ctx_r1.ToCompositeKey(ctx_r1.FormSourceEmbeddingModelID));
656
+ i0.ɵɵadvance(6);
657
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormSourceVectorIndexID);
658
+ i0.ɵɵadvance(3);
659
+ i0.ɵɵrepeater(ctx_r1.VectorIndexOptions);
660
+ i0.ɵɵadvance(9);
661
+ i0.ɵɵclassProp("fa-eye", !ctx_r1.ShowEffectiveValues)("fa-eye-slash", ctx_r1.ShowEffectiveValues);
662
+ i0.ɵɵadvance();
663
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.ShowEffectiveValues ? "Hide effective values" : "Show effective values", " ");
664
+ i0.ɵɵadvance(6);
665
+ i0.ɵɵrepeater(ctx_r1.TaxonomyModes);
666
+ i0.ɵɵadvance(5);
667
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.TagRootIDValue);
668
+ i0.ɵɵadvance(3);
669
+ i0.ɵɵrepeater(ctx_r1.TagRootOptions);
670
+ i0.ɵɵadvance(13);
671
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(73, 31, ctx_r1.MatchThresholdValue, "1.2-2"));
672
+ i0.ɵɵadvance(2);
673
+ i0.ɵɵproperty("ngModel", ctx_r1.MatchThresholdValue);
674
+ i0.ɵɵadvance(5);
675
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(80, 34, ctx_r1.SuggestThresholdValue, "1.2-2"));
676
+ i0.ɵɵadvance(2);
677
+ i0.ɵɵproperty("ngModel", ctx_r1.SuggestThresholdValue);
678
+ i0.ɵɵadvance(2);
679
+ i0.ɵɵconditional(ctx_r1.ThresholdValidationMessage ? 83 : 84);
680
+ i0.ɵɵadvance(8);
681
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.ShareTaxonomyValue);
682
+ i0.ɵɵadvance(7);
683
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.EnableVectorizationValue);
684
+ i0.ɵɵadvance();
685
+ i0.ɵɵconditional(ctx_r1.ShowEffectiveValues ? 99 : -1);
686
+ i0.ɵɵadvance(8);
687
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormMaxItemsPerRun);
688
+ i0.ɵɵadvance(7);
689
+ i0.ɵɵproperty("ngModel", ctx_r1.MaxNewTagsPerRunValue ?? "");
690
+ i0.ɵɵadvance(6);
691
+ i0.ɵɵproperty("ngModel", ctx_r1.MaxNewTagsPerItemValue ?? "");
692
+ i0.ɵɵadvance(6);
693
+ i0.ɵɵproperty("ngModel", ctx_r1.MaxTokensPerRunValue ?? "");
694
+ i0.ɵɵadvance(6);
695
+ i0.ɵɵproperty("ngModel", ctx_r1.MaxCostPerRunValue ?? "");
696
+ i0.ɵɵadvance(3);
697
+ i0.ɵɵconditional(ctx_r1.IsWebsiteSourceTypeSelected ? 135 : -1);
698
+ i0.ɵɵadvance(2);
699
+ i0.ɵɵproperty("disabled", ctx_r1.FormSaving);
700
+ i0.ɵɵadvance();
701
+ i0.ɵɵconditional(ctx_r1.FormSaving ? 138 : 139);
702
+ i0.ɵɵadvance(4);
703
+ i0.ɵɵconditional(ctx_r1.FormMode === "edit-source" && ctx_r1.EditingSourceID ? 142 : -1);
704
+ } }
705
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_For_32_Template(rf, ctx) { if (rf & 1) {
706
+ i0.ɵɵelementStart(0, "option", 15);
707
+ i0.ɵɵtext(1);
708
+ i0.ɵɵelementEnd();
709
+ } if (rf & 2) {
710
+ const opt_r28 = ctx.$implicit;
711
+ i0.ɵɵproperty("value", opt_r28.ID);
712
+ i0.ɵɵadvance();
713
+ i0.ɵɵtextInterpolate(opt_r28.Name);
714
+ } }
715
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Conditional_35_Template(rf, ctx) { if (rf & 1) {
716
+ i0.ɵɵelement(0, "i", 71);
717
+ i0.ɵɵtext(1, " Saving... ");
718
+ } }
719
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Conditional_36_Template(rf, ctx) { if (rf & 1) {
720
+ i0.ɵɵelement(0, "i", 72);
721
+ i0.ɵɵtext(1, " Save ");
722
+ } }
723
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template(rf, ctx) { if (rf & 1) {
724
+ const _r27 = i0.ɵɵgetCurrentView();
725
+ i0.ɵɵelementStart(0, "div", 10)(1, "label", 11);
726
+ i0.ɵɵtext(2, "Name");
727
+ i0.ɵɵelementEnd();
728
+ i0.ɵɵelementStart(3, "input", 75);
729
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeName, $event) || (ctx_r1.FormTypeName = $event); return i0.ɵɵresetView($event); });
730
+ i0.ɵɵelementEnd()();
731
+ i0.ɵɵelementStart(4, "div", 10)(5, "label", 11);
732
+ i0.ɵɵtext(6, "Description");
733
+ i0.ɵɵelementEnd();
734
+ i0.ɵɵelementStart(7, "textarea", 76);
735
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_textarea_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeDescription, $event) || (ctx_r1.FormTypeDescription = $event); return i0.ɵɵresetView($event); });
736
+ i0.ɵɵelementEnd()();
737
+ i0.ɵɵelementStart(8, "div", 10)(9, "label", 11);
738
+ i0.ɵɵtext(10, "AI Model (for tagging)");
739
+ i0.ɵɵelementEnd();
740
+ i0.ɵɵelementStart(11, "mj-tree-dropdown", 77);
741
+ i0.ɵɵlistener("ValueChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_mj_tree_dropdown_ValueChange_11_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.FormTypeAIModelID = ctx_r1.FromCompositeKey($event)); });
742
+ i0.ɵɵelementEnd()();
743
+ i0.ɵɵelementStart(12, "div", 78)(13, "div", 79)(14, "label", 11);
744
+ i0.ɵɵtext(15, "Min Tags");
745
+ i0.ɵɵelementEnd();
746
+ i0.ɵɵelementStart(16, "input", 80);
747
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_input_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeMinTags, $event) || (ctx_r1.FormTypeMinTags = $event); return i0.ɵɵresetView($event); });
748
+ i0.ɵɵelementEnd()();
749
+ i0.ɵɵelementStart(17, "div", 79)(18, "label", 11);
750
+ i0.ɵɵtext(19, "Max Tags");
751
+ i0.ɵɵelementEnd();
752
+ i0.ɵɵelementStart(20, "input", 81);
753
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_input_ngModelChange_20_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeMaxTags, $event) || (ctx_r1.FormTypeMaxTags = $event); return i0.ɵɵresetView($event); });
754
+ i0.ɵɵelementEnd()()();
755
+ i0.ɵɵelementStart(21, "div", 10)(22, "label", 11);
756
+ i0.ɵɵtext(23, "Embedding Model");
757
+ i0.ɵɵelementEnd();
758
+ i0.ɵɵelementStart(24, "mj-tree-dropdown", 18);
759
+ i0.ɵɵlistener("ValueChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_mj_tree_dropdown_ValueChange_24_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.FormTypeEmbeddingModelID = ctx_r1.FromCompositeKey($event)); });
760
+ i0.ɵɵelementEnd()();
761
+ i0.ɵɵelementStart(25, "div", 10)(26, "label", 11);
762
+ i0.ɵɵtext(27, "Vector Index");
763
+ i0.ɵɵelementEnd();
764
+ i0.ɵɵelementStart(28, "select", 13);
765
+ i0.ɵɵtwoWayListener("ngModelChange", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_select_ngModelChange_28_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.FormTypeVectorIndexID, $event) || (ctx_r1.FormTypeVectorIndexID = $event); return i0.ɵɵresetView($event); });
766
+ i0.ɵɵelementStart(29, "option", 14);
767
+ i0.ɵɵtext(30, "Use system default");
768
+ i0.ɵɵelementEnd();
769
+ i0.ɵɵrepeaterCreate(31, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_For_32_Template, 2, 2, "option", 15, _forTrack0);
770
+ i0.ɵɵelementEnd()();
771
+ i0.ɵɵelementStart(33, "div", 44)(34, "button", 45);
772
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_button_click_34_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SaveContentType()); });
773
+ i0.ɵɵconditionalCreate(35, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Conditional_35_Template, 2, 0)(36, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Conditional_36_Template, 2, 0);
774
+ i0.ɵɵelementEnd();
775
+ i0.ɵɵelementStart(37, "button", 46);
776
+ i0.ɵɵlistener("click", function ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template_button_click_37_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.CloseForm()); });
777
+ i0.ɵɵtext(38, "Cancel");
778
+ i0.ɵɵelementEnd()();
779
+ } if (rf & 2) {
780
+ const ctx_r1 = i0.ɵɵnextContext(2);
781
+ i0.ɵɵadvance(3);
782
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeName);
783
+ i0.ɵɵadvance(4);
784
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeDescription);
785
+ i0.ɵɵadvance(4);
786
+ i0.ɵɵproperty("BranchConfig", ctx_r1.AIModelVendorBranch)("LeafConfig", ctx_r1.AllModelsLeaf)("Clearable", true)("Value", ctx_r1.ToCompositeKey(ctx_r1.FormTypeAIModelID));
787
+ i0.ɵɵadvance(5);
788
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeMinTags);
789
+ i0.ɵɵadvance(4);
790
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeMaxTags);
791
+ i0.ɵɵadvance(4);
792
+ i0.ɵɵproperty("BranchConfig", ctx_r1.EmbeddingVendorBranch)("LeafConfig", ctx_r1.EmbeddingModelsLeaf)("Clearable", true)("Value", ctx_r1.ToCompositeKey(ctx_r1.FormTypeEmbeddingModelID));
793
+ i0.ɵɵadvance(4);
794
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.FormTypeVectorIndexID);
795
+ i0.ɵɵadvance(3);
796
+ i0.ɵɵrepeater(ctx_r1.VectorIndexOptions);
797
+ i0.ɵɵadvance(3);
798
+ i0.ɵɵproperty("disabled", ctx_r1.FormSaving);
799
+ i0.ɵɵadvance();
800
+ i0.ɵɵconditional(ctx_r1.FormSaving ? 35 : 36);
801
+ } }
802
+ function ClassifySourceTypeFormDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
803
+ const _r1 = i0.ɵɵgetCurrentView();
804
+ i0.ɵɵelementStart(0, "div", 0);
805
+ 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()); });
806
+ i0.ɵɵelementEnd();
807
+ i0.ɵɵelementStart(1, "div", 1)(2, "div", 2);
808
+ 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)); });
809
+ i0.ɵɵelementEnd();
810
+ i0.ɵɵelementStart(3, "div", 3)(4, "h3");
811
+ 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);
812
+ i0.ɵɵelementEnd();
813
+ i0.ɵɵelementStart(9, "button", 4);
814
+ 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()); });
815
+ i0.ɵɵelement(10, "i", 5);
816
+ i0.ɵɵelementEnd()();
817
+ i0.ɵɵelementStart(11, "div", 6);
818
+ i0.ɵɵconditionalCreate(12, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_12_Template, 143, 37);
819
+ i0.ɵɵconditionalCreate(13, ClassifySourceTypeFormDialogComponent_Conditional_0_Conditional_13_Template, 39, 15);
820
+ i0.ɵɵelementEnd()();
821
+ } if (rf & 2) {
822
+ const ctx_r1 = i0.ɵɵnextContext();
823
+ i0.ɵɵadvance();
824
+ i0.ɵɵstyleProp("width", ctx_r1.PanelWidth, "px");
825
+ i0.ɵɵadvance(4);
826
+ 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);
827
+ i0.ɵɵadvance(7);
828
+ i0.ɵɵconditional(ctx_r1.FormMode === "add-source" || ctx_r1.FormMode === "edit-source" ? 12 : -1);
829
+ i0.ɵɵadvance();
830
+ i0.ɵɵconditional(ctx_r1.FormMode === "add-type" || ctx_r1.FormMode === "edit-type" ? 13 : -1);
831
+ } }
832
+ /** Default classifier knob values — mirrors the autotagger's runtime defaults + the reference panel. */
833
+ const DEFAULT_TAXONOMY_MODE = 'auto-grow';
834
+ const DEFAULT_MATCH_THRESHOLD = 0.85;
835
+ const SUGGEST_THRESHOLD_GAP = 0.05;
836
+ const DEFAULT_SHARE_TAXONOMY = true;
837
+ const DEFAULT_ENABLE_VECTORIZATION = true;
838
+ /** Slide-in panel width bounds + default. The source form is field-rich, so it
839
+ * defaults wider than the host's 420px shared default. */
840
+ const PANEL_WIDTH_DEFAULT = 640;
841
+ const PANEL_WIDTH_MIN = 420;
842
+ /** UserInfoEngine setting key for the remembered source-form panel width. */
843
+ const PANEL_WIDTH_SETTING_KEY = 'mj.classify.sourceForm.width';
844
+ export class ClassifySourceTypeFormDialogComponent extends BaseAngularComponent {
845
+ cdr = inject(ChangeDetectorRef);
846
+ zone = inject(NgZone);
847
+ // ── Resizable panel state ──
848
+ /** Current slide-in panel width (px). Bound to the panel via [style.width.px]. */
849
+ PanelWidth = PANEL_WIDTH_DEFAULT;
850
+ /** Whether the inline "Effective values" panel is shown in the Classification section. */
851
+ ShowEffectiveValues = false;
852
+ /** Active-drag bookkeeping for the left-edge resize handle. */
853
+ isResizing = false;
854
+ resizeMoveListener = null;
855
+ resizeUpListener = null;
856
+ // ── Cross-tab / host intents ──
857
+ /** Emitted after a successful save so the host reloads the relevant shared data. */
858
+ Saved = new EventEmitter();
859
+ /** Emitted when a source save is blocked because no content type exists. */
860
+ ContentTypeMissing = new EventEmitter();
861
+ /** Emitted when the user opts into the full entity form (advanced settings). */
862
+ NavigateToRecordRequested = new EventEmitter();
863
+ // ── Slide-in form state ──
864
+ FormMode = 'none';
865
+ FormSaving = false;
866
+ // Source form fields
867
+ FormSourceName = '';
868
+ FormSourceTypeID = '';
869
+ FormContentTypeID = '';
870
+ FormFileTypeID = '';
871
+ FormSourceURL = '';
872
+ EditingSourceID = '';
873
+ // Content Type form fields
874
+ FormTypeName = '';
875
+ FormTypeDescription = '';
876
+ FormTypeAIModelID = '';
877
+ FormTypeMinTags = 1;
878
+ FormTypeMaxTags = 10;
879
+ EditingTypeID = '';
880
+ // Embedding model + vector index form fields (Content Type)
881
+ FormTypeEmbeddingModelID = '';
882
+ FormTypeVectorIndexID = '';
883
+ // Entity source fields (shown when source type is "Entity")
884
+ FormSourceEntityID = '';
885
+ FormSourceEntityDocID = '';
886
+ // Embedding model + vector index form fields (Content Source overrides)
887
+ FormSourceEmbeddingModelID = '';
888
+ FormSourceVectorIndexID = '';
889
+ // Slide-in is the QUICK-EDIT surface for content sources. We only expose the
890
+ // most-useful subset of the new knobs here; the full surface (other budgets,
891
+ // URL pattern, root URL, taxonomy mode, thresholds, …) lives on the entity
892
+ // form opened via the "Open Advanced settings →" link below.
893
+ //
894
+ // Decisions:
895
+ // - MaxItemsPerRun: the single most-asked-for cap → always shown
896
+ // - MaxDepth + the two crawl toggles: Website-only, the symptom that
897
+ // started this whole work
898
+ // - Everything else: too niche for the quick-edit surface
899
+ FormMaxItemsPerRun = null;
900
+ FormMaxDepth = null;
901
+ FormCrawlSitesInLowerLevelDomain = true;
902
+ FormCrawlOtherSitesInTopLevelDomain = false;
903
+ // ── Classification (full config parity) ──────────────────────────────
904
+ // The classifier knobs that used to require navigating out to the entity
905
+ // form's "advanced settings" are now edited inline. They live on the typed
906
+ // Configuration JSON (`MJContentSourceEntity_IContentSourceConfiguration`),
907
+ // accessed via the `Config` getter / `setConfig` merge helper below.
908
+ //
909
+ // For EDIT we hydrate `workingConfig` from the loaded source's
910
+ // ConfigurationObject; for ADD we start from {} and accumulate. On SAVE the
911
+ // working config is merged into the entity's ConfigurationObject so we never
912
+ // clobber Website / SourceSpecificConfiguration sub-objects.
913
+ workingConfig = {};
914
+ /** Selectable taxonomy-mode cards. Exactly the three modes the type allows — no 'hybrid'. */
915
+ TaxonomyModes = [
916
+ { value: 'constrained', label: 'Constrained', icon: 'fa-lock', bestFor: 'Curated, regulated taxonomies' },
917
+ { value: 'auto-grow', label: 'Auto-Grow', icon: 'fa-seedling', bestFor: 'Bounded growth under a tag root' },
918
+ { value: 'free-flow', label: 'Free-Flow', icon: 'fa-water', bestFor: 'Sandbox — anything goes' },
919
+ ];
920
+ /** Tags eligible to be the taxonomy root (loaded from TagEngineBase). */
921
+ TagRootOptions = [];
922
+ // ── Config accessor + merge helper (mirrors TagPipelineConfigurationPanel) ──
923
+ /** The working classifier config — never null; defaults are applied by the typed getters below. */
924
+ get Config() {
925
+ return this.workingConfig;
926
+ }
927
+ /** Merge a partial patch into the working config (immutable spread, like the reference panel). */
928
+ setConfig(patch) {
929
+ this.workingConfig = { ...this.workingConfig, ...patch };
930
+ }
931
+ // Taxonomy mode
932
+ get CurrentMode() {
933
+ return this.Config.TagTaxonomyMode ?? DEFAULT_TAXONOMY_MODE;
934
+ }
935
+ SetMode(mode) {
936
+ this.setConfig({ TagTaxonomyMode: mode });
937
+ }
938
+ // Thresholds — match auto-applies; suggest routes to inbox. When match moves
939
+ // and suggest is unset/above it, default suggest to max(0, match - 0.05).
940
+ get MatchThresholdValue() {
941
+ return this.Config.TagMatchThreshold ?? DEFAULT_MATCH_THRESHOLD;
942
+ }
943
+ set MatchThresholdValue(v) {
944
+ const clamped = Math.max(0, Math.min(1, Number(v) || 0));
945
+ const cur = this.Config.SuggestThreshold;
946
+ const patch = { TagMatchThreshold: clamped };
947
+ if (cur == null || cur >= clamped) {
948
+ patch.SuggestThreshold = Math.max(0, clamped - SUGGEST_THRESHOLD_GAP);
949
+ }
950
+ this.setConfig(patch);
951
+ }
952
+ get SuggestThresholdValue() {
953
+ return this.Config.SuggestThreshold ?? Math.max(0, this.MatchThresholdValue - SUGGEST_THRESHOLD_GAP);
954
+ }
955
+ set SuggestThresholdValue(v) {
956
+ const clamped = Math.max(0, Math.min(this.MatchThresholdValue, Number(v) || 0));
957
+ this.setConfig({ SuggestThreshold: clamped });
958
+ }
959
+ get ThresholdValidationMessage() {
960
+ const m = this.Config.TagMatchThreshold;
961
+ const s = this.Config.SuggestThreshold;
962
+ if (m != null && s != null && s >= m) {
963
+ return 'Suggest threshold must be lower than the match threshold.';
964
+ }
965
+ return null;
966
+ }
967
+ // Tag root + toggles
968
+ get TagRootIDValue() {
969
+ return this.Config.TagRootID ?? '';
970
+ }
971
+ set TagRootIDValue(v) {
972
+ this.setConfig({ TagRootID: v ? v : null });
973
+ }
974
+ get ShareTaxonomyValue() {
975
+ return this.Config.ShareTaxonomyWithLLM !== false; // default true
976
+ }
977
+ set ShareTaxonomyValue(v) {
978
+ this.setConfig({ ShareTaxonomyWithLLM: v });
979
+ }
980
+ get EnableVectorizationValue() {
981
+ return this.Config.EnableVectorization !== false; // default true
982
+ }
983
+ set EnableVectorizationValue(v) {
984
+ this.setConfig({ EnableVectorization: v });
985
+ }
986
+ // Budgets (blank = unlimited → key stripped from JSON)
987
+ get MaxNewTagsPerRunValue() {
988
+ return this.Config.MaxNewTagsPerRun ?? null;
989
+ }
990
+ set MaxNewTagsPerRunValue(v) {
991
+ this.setConfig({ MaxNewTagsPerRun: this.normalizeNullableNumber(v) });
992
+ }
993
+ get MaxNewTagsPerItemValue() {
994
+ return this.Config.MaxNewTagsPerItem ?? null;
995
+ }
996
+ set MaxNewTagsPerItemValue(v) {
997
+ this.setConfig({ MaxNewTagsPerItem: this.normalizeNullableNumber(v) });
998
+ }
999
+ get MaxTokensPerRunValue() {
1000
+ return this.Config.MaxTokensPerRun ?? null;
1001
+ }
1002
+ set MaxTokensPerRunValue(v) {
1003
+ this.setConfig({ MaxTokensPerRun: this.normalizeNullableNumber(v) });
1004
+ }
1005
+ get MaxCostPerRunValue() {
1006
+ return this.Config.MaxCostPerRun ?? null;
1007
+ }
1008
+ set MaxCostPerRunValue(v) {
1009
+ this.setConfig({ MaxCostPerRun: this.normalizeNullableNumber(v) });
1010
+ }
1011
+ /**
1012
+ * Coerce a possibly-blank input into a typed number. Returning undefined
1013
+ * deletes the key from the persisted JSON when the setConfig spread is applied.
1014
+ */
1015
+ normalizeNullableNumber(v) {
1016
+ if (v == null)
1017
+ return undefined;
1018
+ if (typeof v === 'string') {
1019
+ const trimmed = v.trim();
1020
+ if (trimmed === '')
1021
+ return undefined;
1022
+ const n = Number(trimmed);
1023
+ return Number.isFinite(n) ? n : undefined;
1024
+ }
1025
+ return Number.isFinite(v) ? v : undefined;
1026
+ }
1027
+ /** Human label for the currently-selected tag root (for the effective-values aside). */
1028
+ get tagRootLabel() {
1029
+ const id = this.Config.TagRootID;
1030
+ if (!id)
1031
+ return 'Whole taxonomy';
1032
+ const match = this.TagRootOptions.find(t => UUIDsEqual(t.ID, id));
1033
+ return match?.Name ?? 'Whole taxonomy';
1034
+ }
1035
+ /**
1036
+ * The effective value of each key knob + where it comes from. Since the tag
1037
+ * classifier fields are source-level JSON (no content-type cascade), the
1038
+ * effective value is the configured override or the documented default.
1039
+ */
1040
+ get EffectiveValues() {
1041
+ const c = this.Config;
1042
+ const mode = this.TaxonomyModes.find(m => m.value === this.CurrentMode);
1043
+ return [
1044
+ { label: 'Taxonomy mode', value: mode?.label ?? this.CurrentMode, origin: c.TagTaxonomyMode != null ? 'source override' : 'default' },
1045
+ { label: 'Tag root', value: this.tagRootLabel, origin: c.TagRootID ? 'source override' : 'default' },
1046
+ { label: 'Match threshold', value: this.MatchThresholdValue.toFixed(2), origin: c.TagMatchThreshold != null ? 'source override' : 'default' },
1047
+ { label: 'Suggest threshold', value: this.SuggestThresholdValue.toFixed(2), origin: c.SuggestThreshold != null ? 'source override' : 'default' },
1048
+ { label: 'Share taxonomy w/ LLM', value: this.ShareTaxonomyValue ? 'On' : 'Off', origin: c.ShareTaxonomyWithLLM != null ? 'source override' : 'default' },
1049
+ { label: 'Vectorization', value: this.EnableVectorizationValue ? 'On' : 'Off', origin: c.EnableVectorization != null ? 'source override' : 'default' },
1050
+ ];
1051
+ }
1052
+ /** True when the form's selected source type is Website — gates the crawler knobs. */
1053
+ get IsWebsiteSourceTypeSelected() {
1054
+ if (!this.FormSourceTypeID)
1055
+ return false;
1056
+ const t = this.SourceTypeOptions.find(o => UUIDsEqual(o.ID, this.FormSourceTypeID));
1057
+ return t != null && t.Name?.trim().toLowerCase() === 'website';
1058
+ }
1059
+ /** Whether the selected source type is the Entity type (name-based check) */
1060
+ get IsEntitySourceTypeSelected() {
1061
+ if (!this.FormSourceTypeID)
1062
+ return false;
1063
+ const sourceType = this.SourceTypeOptions.find(o => UUIDsEqual(o.ID, this.FormSourceTypeID));
1064
+ return sourceType?.Name?.toLowerCase() === 'entity';
1065
+ }
1066
+ /** Whether the selected source type requires Content Type / File Type selection */
1067
+ get SelectedSourceTypeRequiresContentType() {
1068
+ if (!this.FormSourceTypeID)
1069
+ return true;
1070
+ try {
1071
+ const engine = KnowledgeHubMetadataEngine.Instance;
1072
+ const st = engine.ContentSourceTypes.find(t => UUIDsEqual(t.ID, this.FormSourceTypeID));
1073
+ return st?.ConfigurationObject?.RequiresContentType !== false;
1074
+ }
1075
+ catch {
1076
+ return true;
1077
+ }
1078
+ }
1079
+ /** Entities that have at least one EntityDocument configured */
1080
+ get EntitiesWithDocuments() {
1081
+ try {
1082
+ const engine = KnowledgeHubMetadataEngine.Instance;
1083
+ const docs = engine.GetActiveEntityDocuments();
1084
+ const entityMap = new Map();
1085
+ const md = this.ProviderToUse;
1086
+ for (const doc of docs) {
1087
+ const entityName = doc.Entity;
1088
+ if (entityName) {
1089
+ const entityInfo = md.Entities.find(e => e.Name === entityName);
1090
+ if (entityInfo && !entityMap.has(entityInfo.ID)) {
1091
+ entityMap.set(entityInfo.ID, entityInfo.Name);
1092
+ }
1093
+ }
1094
+ }
1095
+ return Array.from(entityMap.entries())
1096
+ .map(([ID, Name]) => ({ ID, Name }))
1097
+ .sort((a, b) => a.Name.localeCompare(b.Name));
1098
+ }
1099
+ catch {
1100
+ return [];
1101
+ }
1102
+ }
1103
+ /** Entity documents for the selected entity */
1104
+ get EntityDocOptionsForSelectedEntity() {
1105
+ if (!this.FormSourceEntityID)
1106
+ return [];
1107
+ try {
1108
+ const engine = KnowledgeHubMetadataEngine.Instance;
1109
+ const md = this.ProviderToUse;
1110
+ const entityInfo = md.Entities.find(e => UUIDsEqual(e.ID, this.FormSourceEntityID));
1111
+ if (!entityInfo)
1112
+ return [];
1113
+ return engine.GetActiveEntityDocuments()
1114
+ .filter(d => d.Entity === entityInfo.Name)
1115
+ .map(d => ({ ID: d.ID, Name: d.Name }));
1116
+ }
1117
+ catch {
1118
+ return [];
1119
+ }
1120
+ }
1121
+ // ── Dynamic source-type fields (metadata-driven) ──
1122
+ /** Stores source-type-specific config values keyed by RequiredFields[].Key */
1123
+ FormSourceSpecificConfig = {};
1124
+ /** Available MJ Storage provider keys for the storage-provider-picker widget */
1125
+ StorageProviderOptions = ['Azure Blob Storage', 'AWS S3', 'Google Cloud Storage', 'SharePoint', 'Dropbox', 'Box'];
1126
+ /**
1127
+ * The RequiredFields array from the selected source type's ConfigurationObject.
1128
+ * Drives dynamic form rendering — each field becomes a widget.
1129
+ */
1130
+ get SelectedSourceTypeFields() {
1131
+ if (!this.FormSourceTypeID)
1132
+ return [];
1133
+ try {
1134
+ const engine = KnowledgeHubMetadataEngine.Instance;
1135
+ const sourceType = engine.ContentSourceTypes.find(st => UUIDsEqual(st.ID, this.FormSourceTypeID));
1136
+ if (!sourceType)
1137
+ return [];
1138
+ const config = sourceType.ConfigurationObject;
1139
+ return config?.RequiredFields ?? [];
1140
+ }
1141
+ catch {
1142
+ return [];
1143
+ }
1144
+ }
1145
+ /**
1146
+ * Get dependent options for a field (e.g., entity-doc-picker depends on entity-picker).
1147
+ * Returns entity documents for the entity selected in the dependent field.
1148
+ */
1149
+ GetDependentOptions(field) {
1150
+ if (field.Type === 'entity-doc-picker' && field.DependsOnField) {
1151
+ const entityID = this.FormSourceSpecificConfig[field.DependsOnField];
1152
+ if (!entityID)
1153
+ return [];
1154
+ try {
1155
+ const engine = KnowledgeHubMetadataEngine.Instance;
1156
+ const md = this.ProviderToUse;
1157
+ const entityInfo = md.Entities.find(e => UUIDsEqual(e.ID, entityID));
1158
+ if (!entityInfo)
1159
+ return [];
1160
+ return engine.GetActiveEntityDocuments()
1161
+ .filter(d => d.Entity === entityInfo.Name)
1162
+ .map(d => ({ ID: d.ID, Name: d.Name }));
1163
+ }
1164
+ catch {
1165
+ return [];
1166
+ }
1167
+ }
1168
+ return [];
1169
+ }
1170
+ /**
1171
+ * Handle a source-specific field value change.
1172
+ * For entity-picker: auto-select the first entity doc if only one exists.
1173
+ */
1174
+ OnSourceFieldChanged(fieldKey) {
1175
+ // Find fields that depend on this field
1176
+ for (const field of this.SelectedSourceTypeFields) {
1177
+ if (field.DependsOnField === fieldKey) {
1178
+ const options = this.GetDependentOptions(field);
1179
+ if (options.length === 1) {
1180
+ this.FormSourceSpecificConfig[field.Key] = options[0].ID;
1181
+ }
1182
+ else {
1183
+ this.FormSourceSpecificConfig[field.Key] = '';
1184
+ }
1185
+ }
1186
+ }
1187
+ }
1188
+ // Dropdown options for forms
1189
+ SourceTypeOptions = [];
1190
+ ContentTypeOptions = [];
1191
+ FileTypeOptions = [];
1192
+ AIModelOptions = [];
1193
+ EmbeddingModelOptions = [];
1194
+ VectorIndexOptions = [];
1195
+ // Tree-dropdown configs for AI model selection (vendor → model grouping)
1196
+ AIModelVendorBranch = {
1197
+ EntityName: 'MJ: AI Vendors',
1198
+ DisplayField: 'Name',
1199
+ IDField: 'ID',
1200
+ DefaultIcon: 'fa-solid fa-building',
1201
+ OrderBy: 'Name ASC',
1202
+ };
1203
+ AllModelsLeaf = {
1204
+ EntityName: 'MJ: AI Models',
1205
+ ParentField: '',
1206
+ DisplayField: 'Name',
1207
+ IDField: 'ID',
1208
+ DefaultIcon: 'fa-solid fa-brain',
1209
+ OrderBy: '__mj_CreatedAt DESC',
1210
+ JunctionConfig: {
1211
+ EntityName: 'MJ: AI Model Vendors',
1212
+ LeafForeignKey: 'ModelID',
1213
+ BranchForeignKey: 'VendorID',
1214
+ },
1215
+ };
1216
+ /** Branch config filtered to only vendors that have at least one embedding model */
1217
+ EmbeddingVendorBranch = {
1218
+ EntityName: 'MJ: AI Vendors',
1219
+ DisplayField: 'Name',
1220
+ IDField: 'ID',
1221
+ DefaultIcon: 'fa-solid fa-building',
1222
+ OrderBy: 'Name ASC',
1223
+ ExtraFilter: `ID IN (SELECT mv.VendorID FROM [__mj].vwAIModelVendors mv JOIN [__mj].vwAIModels m ON mv.ModelID = m.ID WHERE m.AIModelType = 'Embeddings')`,
1224
+ };
1225
+ EmbeddingModelsLeaf = {
1226
+ EntityName: 'MJ: AI Models',
1227
+ ParentField: '',
1228
+ DisplayField: 'Name',
1229
+ IDField: 'ID',
1230
+ DefaultIcon: 'fa-solid fa-vector-square',
1231
+ ExtraFilter: "AIModelType = 'Embeddings'",
1232
+ OrderBy: '__mj_CreatedAt DESC',
1233
+ JunctionConfig: {
1234
+ EntityName: 'MJ: AI Model Vendors',
1235
+ LeafForeignKey: 'ModelID',
1236
+ BranchForeignKey: 'VendorID',
1237
+ },
1238
+ };
1239
+ /** Convert a string ID to a CompositeKey for tree-dropdown binding */
1240
+ ToCompositeKey(id) {
1241
+ if (!id)
1242
+ return null;
1243
+ return new CompositeKey([{ FieldName: 'ID', Value: id }]);
1244
+ }
1245
+ /** Extract the ID string from a CompositeKey (from tree-dropdown ValueChange) */
1246
+ FromCompositeKey(key) {
1247
+ if (!key)
1248
+ return '';
1249
+ const ck = Array.isArray(key) ? key[0] : key;
1250
+ if (!ck?.KeyValuePairs?.length)
1251
+ return '';
1252
+ return String(ck.KeyValuePairs[0].Value || '');
1253
+ }
1254
+ // ════════════════════════════════════════════
1255
+ // PUBLIC OPEN METHODS — called by the host via @ViewChild
1256
+ // ════════════════════════════════════════════
1257
+ async OpenAddSource() {
1258
+ await this.ensureFormDropdownsLoaded();
1259
+ this.resetSourceForm();
1260
+ this.ShowEffectiveValues = false;
1261
+ this.restorePanelWidth();
1262
+ this.FormMode = 'add-source';
1263
+ this.cdr.detectChanges();
1264
+ }
1265
+ async OpenEditSource(card) {
1266
+ await this.ensureFormDropdownsLoaded();
1267
+ this.ShowEffectiveValues = false;
1268
+ this.restorePanelWidth();
1269
+ this.FormSourceName = card.Name;
1270
+ this.FormSourceTypeID = card.ContentSourceTypeID;
1271
+ this.FormContentTypeID = card.ContentTypeID;
1272
+ this.FormFileTypeID = card.ContentFileTypeID;
1273
+ this.FormSourceURL = card.URL;
1274
+ this.FormSourceEntityID = card.EntityID ?? '';
1275
+ this.FormSourceEntityDocID = card.EntityDocumentID ?? '';
1276
+ this.FormSourceEmbeddingModelID = card.EmbeddingModelID ?? '';
1277
+ this.FormSourceVectorIndexID = card.VectorIndexID ?? '';
1278
+ this.EditingSourceID = card.ID;
1279
+ // Populate quick-edit knobs + FormSourceSpecificConfig from Configuration JSON.
1280
+ // Reset to defaults first so a previously-edited source's values don't leak in.
1281
+ this.FormSourceSpecificConfig = {};
1282
+ this.FormMaxItemsPerRun = null;
1283
+ this.FormMaxDepth = null;
1284
+ this.FormCrawlSitesInLowerLevelDomain = true;
1285
+ this.FormCrawlOtherSitesInTopLevelDomain = false;
1286
+ this.workingConfig = {};
1287
+ const rawSource = this.RawSources.find(s => UUIDsEqual(s['ID'], card.ID));
1288
+ if (rawSource) {
1289
+ const configStr = rawSource['Configuration'];
1290
+ if (configStr) {
1291
+ try {
1292
+ const parsed = JSON.parse(configStr);
1293
+ // Hydrate the working classifier config from the persisted JSON.
1294
+ // Defaults are applied lazily by the typed getters, so we only
1295
+ // copy what was actually stored (unset = "use default").
1296
+ if (parsed) {
1297
+ this.workingConfig = { ...parsed };
1298
+ }
1299
+ const specific = parsed?.SourceSpecificConfiguration;
1300
+ if (specific) {
1301
+ this.FormSourceSpecificConfig = { ...specific };
1302
+ }
1303
+ // Run-budget knob — pulled directly off the typed Configuration.
1304
+ const items = parsed?.MaxItemsPerRun;
1305
+ if (typeof items === 'number' && Number.isFinite(items)) {
1306
+ this.FormMaxItemsPerRun = items;
1307
+ }
1308
+ // Website sub-object — only populates the inputs when present
1309
+ // (matches the autotagger's "unset = default" semantics).
1310
+ const website = parsed?.Website;
1311
+ if (website) {
1312
+ const depth = website.MaxDepth;
1313
+ if (typeof depth === 'number' && Number.isFinite(depth)) {
1314
+ this.FormMaxDepth = depth;
1315
+ }
1316
+ if (typeof website.CrawlSitesInLowerLevelDomain === 'boolean') {
1317
+ this.FormCrawlSitesInLowerLevelDomain = website.CrawlSitesInLowerLevelDomain;
1318
+ }
1319
+ if (typeof website.CrawlOtherSitesInTopLevelDomain === 'boolean') {
1320
+ this.FormCrawlOtherSitesInTopLevelDomain = website.CrawlOtherSitesInTopLevelDomain;
1321
+ }
1322
+ }
1323
+ }
1324
+ catch {
1325
+ // Configuration not valid JSON, ignore
1326
+ }
1327
+ }
1328
+ }
1329
+ this.FormMode = 'edit-source';
1330
+ this.cdr.detectChanges();
1331
+ }
1332
+ async OpenAddType() {
1333
+ await this.ensureFormDropdownsLoaded();
1334
+ this.resetTypeForm();
1335
+ this.FormMode = 'add-type';
1336
+ this.cdr.detectChanges();
1337
+ }
1338
+ async OpenEditType(card) {
1339
+ await this.ensureFormDropdownsLoaded();
1340
+ this.FormTypeName = card.Name;
1341
+ this.FormTypeDescription = card.Description;
1342
+ this.FormTypeAIModelID = card.AIModelID;
1343
+ this.FormTypeMinTags = card.MinTags;
1344
+ this.FormTypeMaxTags = card.MaxTags;
1345
+ this.FormTypeEmbeddingModelID = card.EmbeddingModelID ?? '';
1346
+ this.FormTypeVectorIndexID = card.VectorIndexID ?? '';
1347
+ this.EditingTypeID = card.ID;
1348
+ this.FormMode = 'edit-type';
1349
+ this.cdr.detectChanges();
1350
+ }
1351
+ // ════════════════════════════════════════════
1352
+ // ADVANCED SETTINGS
1353
+ // ════════════════════════════════════════════
1354
+ /**
1355
+ * Open the full entity form for the source currently being edited in the
1356
+ * slide-in. Quick-edit covers the most-used knobs; the entity form (with
1357
+ * the dynamically-mounted BaseFormPanel slots) exposes everything else
1358
+ * — taxonomy mode, thresholds, all five run-budget caps, URL pattern,
1359
+ * root URL, etc. The host owns NavigationService, so navigation bubbles up.
1360
+ */
1361
+ OpenAdvancedSourceSettings() {
1362
+ if (!this.EditingSourceID)
1363
+ return;
1364
+ const id = this.EditingSourceID;
1365
+ this.CloseForm();
1366
+ this.NavigateToRecordRequested.emit({
1367
+ entityName: 'MJ: Content Sources',
1368
+ key: CompositeKey.FromID(id),
1369
+ });
1370
+ }
1371
+ // ════════════════════════════════════════════
1372
+ // SAVE — Sources
1373
+ // ════════════════════════════════════════════
1374
+ async SaveSource() {
1375
+ if (this.FormSaving)
1376
+ return;
1377
+ // Validate required fields before saving
1378
+ if (!this.FormSourceName.trim()) {
1379
+ MJNotificationService.Instance.CreateSimpleNotification('Please enter a source name.', 'warning', 3000);
1380
+ return;
1381
+ }
1382
+ if (!this.FormSourceTypeID) {
1383
+ MJNotificationService.Instance.CreateSimpleNotification('Please select a source type.', 'warning', 3000);
1384
+ return;
1385
+ }
1386
+ // For non-Entity source types, ContentType is required
1387
+ if (!this.IsEntitySourceTypeSelected && this.SelectedSourceTypeRequiresContentType) {
1388
+ if (!this.FormContentTypeID) {
1389
+ if (this.ContentTypeOptions.length === 0) {
1390
+ MJNotificationService.Instance.CreateSimpleNotification('No content types are configured. Please create a content type first in the Content Types section.', 'warning', 5000);
1391
+ }
1392
+ else {
1393
+ MJNotificationService.Instance.CreateSimpleNotification('Please select a content type.', 'warning', 3000);
1394
+ }
1395
+ return;
1396
+ }
1397
+ }
1398
+ this.FormSaving = true;
1399
+ this.cdr.detectChanges();
1400
+ try {
1401
+ const md = this.ProviderToUse;
1402
+ const entity = await md.GetEntityObject('MJ: Content Sources');
1403
+ if (this.FormMode === 'edit-source' && this.EditingSourceID) {
1404
+ await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: this.EditingSourceID }]));
1405
+ }
1406
+ else {
1407
+ entity.NewRecord();
1408
+ }
1409
+ entity.Name = this.FormSourceName;
1410
+ entity.ContentSourceTypeID = this.FormSourceTypeID;
1411
+ // For Entity source type, ContentType and FileType are not relevant
1412
+ // but the DB columns are NOT NULL, so default to the first available value
1413
+ if (this.IsEntitySourceTypeSelected) {
1414
+ const engine = KnowledgeHubMetadataEngine.Instance;
1415
+ if (!entity.ContentTypeID) {
1416
+ if (engine.ContentTypes.length === 0) {
1417
+ this.FormSaving = false;
1418
+ this.cdr.detectChanges();
1419
+ this.ContentTypeMissing.emit();
1420
+ return;
1421
+ }
1422
+ entity.ContentTypeID = engine.ContentTypes[0].ID;
1423
+ }
1424
+ if (!entity.ContentFileTypeID && engine.ContentFileTypes.length > 0) {
1425
+ entity.ContentFileTypeID = engine.ContentFileTypes[0].ID;
1426
+ }
1427
+ }
1428
+ else {
1429
+ entity.ContentTypeID = this.FormContentTypeID;
1430
+ entity.ContentFileTypeID = this.FormFileTypeID;
1431
+ }
1432
+ // Store source-type-specific values from the dynamic form
1433
+ // For Entity type: EntityID and EntityDocumentID go on the entity directly
1434
+ if (this.IsEntitySourceTypeSelected) {
1435
+ entity.EntityID = this.FormSourceSpecificConfig['EntityID'] || null;
1436
+ const entityDocID = this.FormSourceSpecificConfig['EntityDocumentID'];
1437
+ if (entityDocID) {
1438
+ entity.EntityDocumentID = entityDocID;
1439
+ }
1440
+ else {
1441
+ // Auto-select first doc if only one exists
1442
+ const docField = this.SelectedSourceTypeFields.find(f => f.Type === 'entity-doc-picker');
1443
+ const docs = docField ? this.GetDependentOptions(docField) : [];
1444
+ entity.EntityDocumentID = docs.length > 0 ? docs[0].ID : null;
1445
+ }
1446
+ entity.URL = '';
1447
+ }
1448
+ else {
1449
+ entity.EntityID = null;
1450
+ entity.EntityDocumentID = null;
1451
+ // URL comes from dynamic fields for RSS/Website, or empty for others
1452
+ entity.URL = this.FormSourceSpecificConfig['URL'] || '';
1453
+ }
1454
+ // Store the full SourceSpecificConfiguration in the Configuration JSON
1455
+ const currentConfig = entity.ConfigurationObject ?? {};
1456
+ // Merge the inline Classification knobs (taxonomy mode, thresholds,
1457
+ // tag root, budgets, toggles) from the working config. We deliberately
1458
+ // exclude the sub-objects owned by the dedicated quick-edit logic below
1459
+ // (SourceSpecificConfiguration, MaxItemsPerRun, Website) so those stay
1460
+ // single-owner and we never clobber crawl settings. Keys absent from the
1461
+ // working config are left untouched on currentConfig.
1462
+ const { SourceSpecificConfiguration: _ssc, MaxItemsPerRun: _mipr, Website: _web, ...classifierKnobs } = this.workingConfig;
1463
+ Object.assign(currentConfig, classifierKnobs);
1464
+ currentConfig.SourceSpecificConfiguration = { ...this.FormSourceSpecificConfig };
1465
+ // Persist the quick-edit knobs that don't have their own DB columns
1466
+ // (the rest live on the typed Configuration JSON sub-objects). The
1467
+ // advanced settings flow on the entity form can override more fields
1468
+ // — we only touch the keys the slide-in exposes so we don't clobber
1469
+ // unrelated values an operator set there earlier.
1470
+ if (this.FormMaxItemsPerRun != null && Number.isFinite(this.FormMaxItemsPerRun)) {
1471
+ currentConfig.MaxItemsPerRun = this.FormMaxItemsPerRun;
1472
+ }
1473
+ else {
1474
+ // Empty input = "unlimited" — strip the key so the autotagger
1475
+ // sees no cap (rather than 0 = "process zero items").
1476
+ delete currentConfig.MaxItemsPerRun;
1477
+ }
1478
+ if (this.IsWebsiteSourceTypeSelected) {
1479
+ const website = { ...(currentConfig.Website ?? {}) };
1480
+ if (this.FormMaxDepth != null && Number.isFinite(this.FormMaxDepth)) {
1481
+ website.MaxDepth = this.FormMaxDepth;
1482
+ }
1483
+ else {
1484
+ delete website.MaxDepth;
1485
+ }
1486
+ website.CrawlSitesInLowerLevelDomain = this.FormCrawlSitesInLowerLevelDomain;
1487
+ website.CrawlOtherSitesInTopLevelDomain = this.FormCrawlOtherSitesInTopLevelDomain;
1488
+ currentConfig.Website = website;
1489
+ }
1490
+ entity.ConfigurationObject = currentConfig;
1491
+ entity.EmbeddingModelID = this.FormSourceEmbeddingModelID || null;
1492
+ entity.VectorIndexID = this.FormSourceVectorIndexID || null;
1493
+ const saved = await entity.Save();
1494
+ if (saved) {
1495
+ MJNotificationService.Instance.CreateSimpleNotification(this.FormMode === 'edit-source' ? 'Source updated' : 'Source created', 'success', 2500);
1496
+ this.CloseForm();
1497
+ this.Saved.emit({ kind: 'source' });
1498
+ }
1499
+ else {
1500
+ // CP-4: Show detailed error from LatestResult
1501
+ const errorDetail = entity.LatestResult?.CompleteMessage ?? 'Unknown error';
1502
+ console.error('[Classify] Save source failed:', entity.LatestResult);
1503
+ MJNotificationService.Instance.CreateSimpleNotification(`Failed to save source: ${errorDetail}`, 'error', 5000);
1504
+ }
1505
+ }
1506
+ catch (error) {
1507
+ const msg = error instanceof Error ? error.message : String(error);
1508
+ console.error('[Classify] Save source exception:', error);
1509
+ MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 5000);
1510
+ }
1511
+ finally {
1512
+ this.FormSaving = false;
1513
+ this.cdr.detectChanges();
1514
+ }
1515
+ }
1516
+ // ════════════════════════════════════════════
1517
+ // SAVE — Content Types
1518
+ // ════════════════════════════════════════════
1519
+ async SaveContentType() {
1520
+ if (this.FormSaving)
1521
+ return;
1522
+ this.FormSaving = true;
1523
+ this.cdr.detectChanges();
1524
+ try {
1525
+ const md = this.ProviderToUse;
1526
+ const contentType = await md.GetEntityObject('MJ: Content Types', md.CurrentUser);
1527
+ if (this.FormMode === 'edit-type' && this.EditingTypeID) {
1528
+ await contentType.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: this.EditingTypeID }]));
1529
+ }
1530
+ else {
1531
+ contentType.NewRecord();
1532
+ }
1533
+ contentType.Name = this.FormTypeName;
1534
+ contentType.Description = this.FormTypeDescription;
1535
+ contentType.AIModelID = this.FormTypeAIModelID;
1536
+ contentType.MinTags = this.FormTypeMinTags;
1537
+ contentType.MaxTags = this.FormTypeMaxTags;
1538
+ contentType.EmbeddingModelID = this.FormTypeEmbeddingModelID || null;
1539
+ contentType.VectorIndexID = this.FormTypeVectorIndexID || null;
1540
+ const saved = await contentType.Save();
1541
+ if (saved) {
1542
+ MJNotificationService.Instance.CreateSimpleNotification(this.FormMode === 'edit-type' ? 'Content type updated' : 'Content type created', 'success', 2500);
1543
+ this.CloseForm();
1544
+ this.Saved.emit({ kind: 'type' });
1545
+ }
1546
+ else {
1547
+ MJNotificationService.Instance.CreateSimpleNotification('Failed to save content type', 'error', 3000);
1548
+ }
1549
+ }
1550
+ catch (error) {
1551
+ const msg = error instanceof Error ? error.message : String(error);
1552
+ MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 4000);
1553
+ }
1554
+ finally {
1555
+ this.FormSaving = false;
1556
+ this.cdr.detectChanges();
1557
+ }
1558
+ }
1559
+ CloseForm() {
1560
+ this.FormMode = 'none';
1561
+ this.cdr.detectChanges();
1562
+ }
1563
+ // ════════════════════════════════════════════
1564
+ // RAW SOURCES — supplied by the host so edit can read Configuration JSON
1565
+ // ════════════════════════════════════════════
1566
+ /**
1567
+ * Raw `MJ: Content Sources` rows, forwarded by the host so `OpenEditSource`
1568
+ * can hydrate the quick-edit knobs from the source's Configuration JSON. The
1569
+ * card the Sources tab passes doesn't carry the full Configuration blob.
1570
+ */
1571
+ RawSources = [];
1572
+ // ════════════════════════════════════════════
1573
+ // HELPERS
1574
+ // ════════════════════════════════════════════
1575
+ async ensureFormDropdownsLoaded() {
1576
+ try {
1577
+ // Use KnowledgeHubMetadataEngine for cached reference data — instant, no RunView needed
1578
+ const engine = KnowledgeHubMetadataEngine.Instance;
1579
+ await engine.Config(false); // no-op if already loaded
1580
+ this.SourceTypeOptions = engine.ContentSourceTypes.map(t => ({ ID: t.ID, Name: t.Name }));
1581
+ this.ContentTypeOptions = engine.ContentTypes.map(t => ({ ID: t.ID, Name: t.Name }));
1582
+ this.FileTypeOptions = engine.ContentFileTypes.map(t => ({ ID: t.ID, Name: t.Name }));
1583
+ this.VectorIndexOptions = engine.VectorIndexes.map(vi => ({ ID: vi.ID, Name: vi.Name }));
1584
+ // AI Models from AIEngineBase (already cached)
1585
+ if (this.AIModelOptions.length === 0) {
1586
+ const aiEngine = AIEngineBase.Instance;
1587
+ await aiEngine.Config(false);
1588
+ this.AIModelOptions = aiEngine.Models.map(m => ({ ID: m.ID, Name: m.Name }));
1589
+ this.EmbeddingModelOptions = aiEngine.Models
1590
+ .filter(m => m.AIModelType?.trim().toLowerCase() === 'embeddings')
1591
+ .map(m => ({ ID: m.ID, Name: m.Name }));
1592
+ }
1593
+ // Tag-root candidates for the Classification section's root dropdown.
1594
+ if (this.TagRootOptions.length === 0) {
1595
+ const p = this.ProviderToUse;
1596
+ await TagEngineBase.Instance.Config(false, p.CurrentUser, p);
1597
+ this.TagRootOptions = TagEngineBase.Instance.Tags
1598
+ .map(t => ({ ID: t.ID, Name: t.Name }))
1599
+ .sort((a, b) => a.Name.localeCompare(b.Name));
1600
+ }
1601
+ }
1602
+ catch (error) {
1603
+ console.error('[Autotagging] Error loading form dropdowns:', error);
1604
+ }
1605
+ }
1606
+ resetSourceForm() {
1607
+ this.FormSourceName = '';
1608
+ this.FormSourceTypeID = '';
1609
+ this.FormContentTypeID = '';
1610
+ this.FormFileTypeID = '';
1611
+ this.FormSourceURL = '';
1612
+ this.FormSourceEntityID = '';
1613
+ this.FormSourceEntityDocID = '';
1614
+ this.FormSourceEmbeddingModelID = '';
1615
+ this.FormSourceVectorIndexID = '';
1616
+ this.EditingSourceID = '';
1617
+ this.FormSourceSpecificConfig = {};
1618
+ // Quick-edit knobs — defaults match the autotagger's runtime defaults.
1619
+ this.FormMaxItemsPerRun = null;
1620
+ this.FormMaxDepth = null;
1621
+ this.FormCrawlSitesInLowerLevelDomain = true;
1622
+ this.FormCrawlOtherSitesInTopLevelDomain = false;
1623
+ // Classification knobs — start empty; the typed getters apply defaults.
1624
+ this.workingConfig = {};
1625
+ }
1626
+ // ════════════════════════════════════════════
1627
+ // EFFECTIVE-VALUES TOGGLE
1628
+ // ════════════════════════════════════════════
1629
+ /** Show / hide the inline effective-values panel in the Classification section. */
1630
+ ToggleEffectiveValues() {
1631
+ this.ShowEffectiveValues = !this.ShowEffectiveValues;
1632
+ this.cdr.detectChanges();
1633
+ }
1634
+ // ════════════════════════════════════════════
1635
+ // RESIZABLE PANEL (drag the left edge) + width persistence
1636
+ // ════════════════════════════════════════════
1637
+ /** Clamp a candidate width to the allowed range (min .. 90% of viewport). */
1638
+ clampPanelWidth(width) {
1639
+ const max = window.innerWidth * 0.9;
1640
+ return Math.max(PANEL_WIDTH_MIN, Math.min(width, max));
1641
+ }
1642
+ /**
1643
+ * Restore the remembered panel width from UserInfoEngine (a synchronous cache
1644
+ * read), falling back to the default. Called when a source form is opened.
1645
+ */
1646
+ restorePanelWidth() {
1647
+ const raw = UserInfoEngine.Instance.GetSetting(PANEL_WIDTH_SETTING_KEY);
1648
+ if (raw) {
1649
+ const n = parseInt(raw, 10);
1650
+ if (!isNaN(n)) {
1651
+ this.PanelWidth = this.clampPanelWidth(n);
1652
+ return;
1653
+ }
1654
+ }
1655
+ this.PanelWidth = PANEL_WIDTH_DEFAULT;
1656
+ }
1657
+ /**
1658
+ * Begin a left-edge resize drag. The panel slides in from the right, so the
1659
+ * resizable edge is its LEFT edge: dragging left widens the panel.
1660
+ */
1661
+ StartResize(event) {
1662
+ event.preventDefault();
1663
+ if (this.isResizing)
1664
+ return;
1665
+ this.isResizing = true;
1666
+ const startX = event.clientX;
1667
+ const startWidth = this.PanelWidth;
1668
+ // Prevent text selection / iframe capture during the drag.
1669
+ document.body.style.userSelect = 'none';
1670
+ // Run move tracking outside Angular to avoid a CD cycle on every pixel;
1671
+ // we re-enter the zone only to update the bound width.
1672
+ this.zone.runOutsideAngular(() => {
1673
+ this.resizeMoveListener = (e) => {
1674
+ const next = this.clampPanelWidth(startWidth + (startX - e.clientX));
1675
+ this.zone.run(() => {
1676
+ this.PanelWidth = next;
1677
+ this.cdr.detectChanges();
1678
+ });
1679
+ // Debounced persistence while dragging — the final value is what sticks.
1680
+ UserInfoEngine.Instance.SetSettingDebounced(PANEL_WIDTH_SETTING_KEY, String(Math.round(next)));
1681
+ };
1682
+ this.resizeUpListener = () => this.endResize();
1683
+ document.addEventListener('mousemove', this.resizeMoveListener);
1684
+ document.addEventListener('mouseup', this.resizeUpListener);
1685
+ });
1686
+ }
1687
+ /** Tear down the active drag listeners and persist the final width. */
1688
+ endResize() {
1689
+ if (!this.isResizing)
1690
+ return;
1691
+ this.isResizing = false;
1692
+ document.body.style.userSelect = '';
1693
+ if (this.resizeMoveListener) {
1694
+ document.removeEventListener('mousemove', this.resizeMoveListener);
1695
+ this.resizeMoveListener = null;
1696
+ }
1697
+ if (this.resizeUpListener) {
1698
+ document.removeEventListener('mouseup', this.resizeUpListener);
1699
+ this.resizeUpListener = null;
1700
+ }
1701
+ UserInfoEngine.Instance.SetSettingDebounced(PANEL_WIDTH_SETTING_KEY, String(Math.round(this.PanelWidth)));
1702
+ }
1703
+ ngOnDestroy() {
1704
+ // Clean up any active drag listeners + body style if destroyed mid-drag.
1705
+ this.endResize();
1706
+ }
1707
+ resetTypeForm() {
1708
+ this.FormTypeName = '';
1709
+ this.FormTypeDescription = '';
1710
+ this.FormTypeAIModelID = '';
1711
+ this.FormTypeMinTags = 1;
1712
+ this.FormTypeMaxTags = 10;
1713
+ this.FormTypeEmbeddingModelID = '';
1714
+ this.FormTypeVectorIndexID = '';
1715
+ this.EditingTypeID = '';
1716
+ }
1717
+ static ɵfac = /*@__PURE__*/ (() => { let ɵClassifySourceTypeFormDialogComponent_BaseFactory; return function ClassifySourceTypeFormDialogComponent_Factory(__ngFactoryType__) { return (ɵClassifySourceTypeFormDialogComponent_BaseFactory || (ɵClassifySourceTypeFormDialogComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ClassifySourceTypeFormDialogComponent)))(__ngFactoryType__ || ClassifySourceTypeFormDialogComponent); }; })();
1718
+ 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-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-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"], ["type", "checkbox", 3, "ngModelChange", "ngModel"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-check"], ["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) {
1719
+ i0.ɵɵconditionalCreate(0, ClassifySourceTypeFormDialogComponent_Conditional_0_Template, 14, 5);
1720
+ } if (rf & 2) {
1721
+ i0.ɵɵconditional(ctx.FormMode !== "none" ? 0 : -1);
1722
+ } }, 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}"] });
1723
+ }
1724
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClassifySourceTypeFormDialogComponent, [{
1725
+ type: Component,
1726
+ 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 </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 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"] }]
1727
+ }], null, { Saved: [{
1728
+ type: Output
1729
+ }], ContentTypeMissing: [{
1730
+ type: Output
1731
+ }], NavigateToRecordRequested: [{
1732
+ type: Output
1733
+ }] }); })();
1734
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ClassifySourceTypeFormDialogComponent, { className: "ClassifySourceTypeFormDialogComponent", filePath: "src/AI/components/autotagging/dialogs/source-type-form.dialog.component.ts", lineNumber: 72 }); })();
1735
+ //# sourceMappingURL=source-type-form.dialog.component.js.map