@memberjunction/ng-dashboards 6.2.0-edge.5 → 6.2.0-edge.7

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 (293) hide show
  1. package/README.md +35 -0
  2. package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js +2 -2
  3. package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js.map +1 -1
  4. package/dist/AI/components/analytics/realtime/realtime-management.component.d.ts.map +1 -1
  5. package/dist/AI/components/analytics/realtime/realtime-management.component.js +3 -1
  6. package/dist/AI/components/analytics/realtime/realtime-management.component.js.map +1 -1
  7. package/dist/AI/components/analytics/realtime/realtime-overview.component.d.ts +1 -1
  8. package/dist/AI/components/analytics/realtime/realtime-overview.component.js +3 -3
  9. package/dist/AI/components/analytics/realtime/realtime-overview.component.js.map +1 -1
  10. package/dist/AI/components/analytics/realtime/realtime-session-data.d.ts +6 -4
  11. package/dist/AI/components/analytics/realtime/realtime-session-data.d.ts.map +1 -1
  12. package/dist/AI/components/analytics/realtime/realtime-session-data.js +8 -2
  13. package/dist/AI/components/analytics/realtime/realtime-session-data.js.map +1 -1
  14. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +1 -1
  15. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  16. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +21 -13
  17. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  18. package/dist/AI/components/autotagging/components/classify-item-grid.component.js +1 -1
  19. package/dist/AI/components/autotagging/components/classify-item-grid.component.js.map +1 -1
  20. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts.map +1 -1
  21. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js +1 -0
  22. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js.map +1 -1
  23. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -1
  24. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +1 -0
  25. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -1
  26. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
  27. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1 -0
  28. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
  29. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +7 -1
  30. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  31. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +210 -57
  32. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  33. package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts +12 -11
  34. package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts.map +1 -1
  35. package/dist/AI/components/duplicates/duplicate-detection-run-scope.js +15 -15
  36. package/dist/AI/components/duplicates/duplicate-detection-run-scope.js.map +1 -1
  37. package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
  38. package/dist/AI/components/execution-monitoring.component.js +28 -16
  39. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  40. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +1 -0
  41. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
  42. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +32 -8
  43. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
  44. package/dist/AI/components/tags/tags-resource.component.d.ts +1 -1
  45. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  46. package/dist/AI/components/tags/tags-resource.component.js +18 -9
  47. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  48. package/dist/AI/components/vectors/sensitive-fields.d.ts +9 -4
  49. package/dist/AI/components/vectors/sensitive-fields.d.ts.map +1 -1
  50. package/dist/AI/components/vectors/sensitive-fields.js +39 -14
  51. package/dist/AI/components/vectors/sensitive-fields.js.map +1 -1
  52. package/dist/AI/components/vectors/vector-document-rules.d.ts +13 -0
  53. package/dist/AI/components/vectors/vector-document-rules.d.ts.map +1 -1
  54. package/dist/AI/components/vectors/vector-document-rules.js +14 -0
  55. package/dist/AI/components/vectors/vector-document-rules.js.map +1 -1
  56. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +34 -14
  57. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  58. package/dist/AI/components/vectors/vector-management-resource.component.js +134 -51
  59. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  60. package/dist/AI/components/vectors/vector-store-selection.d.ts +32 -0
  61. package/dist/AI/components/vectors/vector-store-selection.d.ts.map +1 -0
  62. package/dist/AI/components/vectors/vector-store-selection.js +57 -0
  63. package/dist/AI/components/vectors/vector-store-selection.js.map +1 -0
  64. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  65. package/dist/AI/services/ai-instrumentation.service.js +4 -2
  66. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  67. package/dist/Actions/action-result-code.d.ts +80 -0
  68. package/dist/Actions/action-result-code.d.ts.map +1 -0
  69. package/dist/Actions/action-result-code.js +163 -0
  70. package/dist/Actions/action-result-code.js.map +1 -0
  71. package/dist/Actions/components/actions-overview.component.d.ts +8 -0
  72. package/dist/Actions/components/actions-overview.component.d.ts.map +1 -1
  73. package/dist/Actions/components/actions-overview.component.js +12 -9
  74. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  75. package/dist/Actions/components/execution-monitoring.component.d.ts +29 -9
  76. package/dist/Actions/components/execution-monitoring.component.d.ts.map +1 -1
  77. package/dist/Actions/components/execution-monitoring.component.js +65 -42
  78. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  79. package/dist/Actions/components/explorer/action-card.component.d.ts.map +1 -1
  80. package/dist/Actions/components/explorer/action-card.component.js +5 -4
  81. package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
  82. package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts +198 -0
  83. package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts.map +1 -0
  84. package/dist/ChiefOfStaff/chief-of-staff-agent-context.js +289 -0
  85. package/dist/ChiefOfStaff/chief-of-staff-agent-context.js.map +1 -0
  86. package/dist/ChiefOfStaff/chief-of-staff-approvals.component.d.ts +29 -0
  87. package/dist/ChiefOfStaff/chief-of-staff-approvals.component.d.ts.map +1 -0
  88. package/dist/ChiefOfStaff/chief-of-staff-approvals.component.js +666 -0
  89. package/dist/ChiefOfStaff/chief-of-staff-approvals.component.js.map +1 -0
  90. package/dist/ChiefOfStaff/chief-of-staff-governance.component.d.ts +56 -0
  91. package/dist/ChiefOfStaff/chief-of-staff-governance.component.d.ts.map +1 -0
  92. package/dist/ChiefOfStaff/chief-of-staff-governance.component.js +515 -0
  93. package/dist/ChiefOfStaff/chief-of-staff-governance.component.js.map +1 -0
  94. package/dist/ChiefOfStaff/chief-of-staff-live-refresh.d.ts +14 -0
  95. package/dist/ChiefOfStaff/chief-of-staff-live-refresh.d.ts.map +1 -0
  96. package/dist/ChiefOfStaff/chief-of-staff-live-refresh.js +39 -0
  97. package/dist/ChiefOfStaff/chief-of-staff-live-refresh.js.map +1 -0
  98. package/dist/ChiefOfStaff/chief-of-staff-overview.component.d.ts +17 -0
  99. package/dist/ChiefOfStaff/chief-of-staff-overview.component.d.ts.map +1 -0
  100. package/dist/ChiefOfStaff/chief-of-staff-overview.component.js +485 -0
  101. package/dist/ChiefOfStaff/chief-of-staff-overview.component.js.map +1 -0
  102. package/dist/ChiefOfStaff/chief-of-staff-page-base.d.ts +139 -0
  103. package/dist/ChiefOfStaff/chief-of-staff-page-base.d.ts.map +1 -0
  104. package/dist/ChiefOfStaff/chief-of-staff-page-base.js +602 -0
  105. package/dist/ChiefOfStaff/chief-of-staff-page-base.js.map +1 -0
  106. package/dist/ChiefOfStaff/index.d.ts +6 -0
  107. package/dist/ChiefOfStaff/index.d.ts.map +1 -0
  108. package/dist/ChiefOfStaff/index.js +6 -0
  109. package/dist/ChiefOfStaff/index.js.map +1 -0
  110. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  111. package/dist/Communication/communication-logs-resource.component.js +2 -1
  112. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  113. package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
  114. package/dist/Communication/communication-monitor-resource.component.js +26 -21
  115. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  116. package/dist/Communication/communication-runs-resource.component.d.ts.map +1 -1
  117. package/dist/Communication/communication-runs-resource.component.js +14 -13
  118. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  119. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
  120. package/dist/ComponentStudio/component-studio-dashboard.component.js +1 -0
  121. package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
  122. package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
  123. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +2 -1
  124. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
  125. package/dist/ComponentStudio/services/component-version.service.d.ts.map +1 -1
  126. package/dist/ComponentStudio/services/component-version.service.js +3 -0
  127. package/dist/ComponentStudio/services/component-version.service.js.map +1 -1
  128. package/dist/DashboardEditor/dashboard-editor.component.d.ts +17 -2
  129. package/dist/DashboardEditor/dashboard-editor.component.d.ts.map +1 -1
  130. package/dist/DashboardEditor/dashboard-editor.component.js +94 -43
  131. package/dist/DashboardEditor/dashboard-editor.component.js.map +1 -1
  132. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +45 -2
  133. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  134. package/dist/DataExplorer/data-explorer-dashboard.component.js +178 -55
  135. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  136. package/dist/DataExplorer/models/explorer-state.interface.d.ts +2 -0
  137. package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
  138. package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
  139. package/dist/DevTools/graphql-console.component.js +2 -2
  140. package/dist/DevTools/lazy-module-status.component.js +2 -2
  141. package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -1
  142. package/dist/FormBuilder/form-builder-resource.component.js +5 -0
  143. package/dist/FormBuilder/form-builder-resource.component.js.map +1 -1
  144. package/dist/Integration/components/connections/connections.component.js +2 -2
  145. package/dist/Integration/services/integration-data.service.d.ts +1 -1
  146. package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
  147. package/dist/Integration/services/integration-data.service.js +4 -3
  148. package/dist/Integration/services/integration-data.service.js.map +1 -1
  149. package/dist/Lists/components/lists-browse-resource.component.js +1 -1
  150. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  151. package/dist/Lists/components/lists-my-lists-resource.component.js +1 -1
  152. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  153. package/dist/LoginStudio/login-studio-resource.component.d.ts +10 -2
  154. package/dist/LoginStudio/login-studio-resource.component.d.ts.map +1 -1
  155. package/dist/LoginStudio/login-studio-resource.component.js +111 -77
  156. package/dist/LoginStudio/login-studio-resource.component.js.map +1 -1
  157. package/dist/MCP/mcp-dashboard.component.d.ts +24 -4
  158. package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
  159. package/dist/MCP/mcp-dashboard.component.js +118 -65
  160. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  161. package/dist/PredictiveStudio/business-predictions.view-models.d.ts +1 -1
  162. package/dist/PredictiveStudio/business-predictions.view-models.d.ts.map +1 -1
  163. package/dist/PredictiveStudio/business-predictions.view-models.js +3 -3
  164. package/dist/PredictiveStudio/business-predictions.view-models.js.map +1 -1
  165. package/dist/PredictiveStudio/components/ps-experiments.component.d.ts +6 -63
  166. package/dist/PredictiveStudio/components/ps-experiments.component.d.ts.map +1 -1
  167. package/dist/PredictiveStudio/components/ps-experiments.component.js +257 -521
  168. package/dist/PredictiveStudio/components/ps-experiments.component.js.map +1 -1
  169. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts +0 -18
  170. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts.map +1 -1
  171. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js +124 -251
  172. package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js.map +1 -1
  173. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +5 -9
  174. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
  175. package/dist/PredictiveStudio/components/ps-pipelines.component.js +98 -130
  176. package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
  177. package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts +53 -4
  178. package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts.map +1 -1
  179. package/dist/PredictiveStudio/components/ps-predictions-grid.component.js +338 -326
  180. package/dist/PredictiveStudio/components/ps-predictions-grid.component.js.map +1 -1
  181. package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts +19 -0
  182. package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts.map +1 -0
  183. package/dist/PredictiveStudio/components/ps-row-drivers.component.js +85 -0
  184. package/dist/PredictiveStudio/components/ps-row-drivers.component.js.map +1 -0
  185. package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts +19 -1
  186. package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts.map +1 -1
  187. package/dist/PredictiveStudio/engine/predictive-studio.engine.js +52 -2
  188. package/dist/PredictiveStudio/engine/predictive-studio.engine.js.map +1 -1
  189. package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts +3 -1
  190. package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts.map +1 -1
  191. package/dist/PredictiveStudio/predictive-studio-agent-context.js +3 -0
  192. package/dist/PredictiveStudio/predictive-studio-agent-context.js.map +1 -1
  193. package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts +27 -4
  194. package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts.map +1 -1
  195. package/dist/PredictiveStudio/predictive-studio-score-history.service.js +94 -61
  196. package/dist/PredictiveStudio/predictive-studio-score-history.service.js.map +1 -1
  197. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts +29 -5
  198. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts.map +1 -1
  199. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js +186 -103
  200. package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js.map +1 -1
  201. package/dist/PredictiveStudio/resources/ps-studio-resource.component.js +1 -1
  202. package/dist/PredictiveStudio/resources/ps-studio-resource.component.js.map +1 -1
  203. package/dist/QueryBrowser/query-browser-resource.component.d.ts +26 -0
  204. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  205. package/dist/QueryBrowser/query-browser-resource.component.js +375 -252
  206. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  207. package/dist/UserRoutines/user-routines-resource.component.d.ts +8 -1
  208. package/dist/UserRoutines/user-routines-resource.component.d.ts.map +1 -1
  209. package/dist/UserRoutines/user-routines-resource.component.js +22 -4
  210. package/dist/UserRoutines/user-routines-resource.component.js.map +1 -1
  211. package/dist/VersionHistory/components/diff-resource.component.d.ts.map +1 -1
  212. package/dist/VersionHistory/components/diff-resource.component.js +1 -0
  213. package/dist/VersionHistory/components/diff-resource.component.js.map +1 -1
  214. package/dist/VideoStudio/components/vs-archetype-editor.component.d.ts +162 -0
  215. package/dist/VideoStudio/components/vs-archetype-editor.component.d.ts.map +1 -0
  216. package/dist/VideoStudio/components/vs-archetype-editor.component.js +1105 -0
  217. package/dist/VideoStudio/components/vs-archetype-editor.component.js.map +1 -0
  218. package/dist/VideoStudio/components/vs-audio-options.component.d.ts +27 -0
  219. package/dist/VideoStudio/components/vs-audio-options.component.d.ts.map +1 -0
  220. package/dist/VideoStudio/components/vs-audio-options.component.js +119 -0
  221. package/dist/VideoStudio/components/vs-audio-options.component.js.map +1 -0
  222. package/dist/VideoStudio/components/vs-copilot-panel.component.d.ts +105 -0
  223. package/dist/VideoStudio/components/vs-copilot-panel.component.d.ts.map +1 -0
  224. package/dist/VideoStudio/components/vs-copilot-panel.component.js +560 -0
  225. package/dist/VideoStudio/components/vs-copilot-panel.component.js.map +1 -0
  226. package/dist/VideoStudio/components/vs-production-brief.component.d.ts +163 -0
  227. package/dist/VideoStudio/components/vs-production-brief.component.d.ts.map +1 -0
  228. package/dist/VideoStudio/components/vs-production-brief.component.js +1054 -0
  229. package/dist/VideoStudio/components/vs-production-brief.component.js.map +1 -0
  230. package/dist/VideoStudio/components/vs-setup-health-card.component.d.ts +43 -0
  231. package/dist/VideoStudio/components/vs-setup-health-card.component.d.ts.map +1 -0
  232. package/dist/VideoStudio/components/vs-setup-health-card.component.js +412 -0
  233. package/dist/VideoStudio/components/vs-setup-health-card.component.js.map +1 -0
  234. package/dist/VideoStudio/components/vs-studio-slide-in.component.d.ts +73 -0
  235. package/dist/VideoStudio/components/vs-studio-slide-in.component.d.ts.map +1 -0
  236. package/dist/VideoStudio/components/vs-studio-slide-in.component.js +271 -0
  237. package/dist/VideoStudio/components/vs-studio-slide-in.component.js.map +1 -0
  238. package/dist/VideoStudio/index.d.ts +12 -0
  239. package/dist/VideoStudio/index.d.ts.map +1 -0
  240. package/dist/VideoStudio/index.js +12 -0
  241. package/dist/VideoStudio/index.js.map +1 -0
  242. package/dist/VideoStudio/resources/video-studio-archetypes-resource.component.d.ts +118 -0
  243. package/dist/VideoStudio/resources/video-studio-archetypes-resource.component.d.ts.map +1 -0
  244. package/dist/VideoStudio/resources/video-studio-archetypes-resource.component.js +964 -0
  245. package/dist/VideoStudio/resources/video-studio-archetypes-resource.component.js.map +1 -0
  246. package/dist/VideoStudio/resources/video-studio-brand-kits-resource.component.d.ts +70 -0
  247. package/dist/VideoStudio/resources/video-studio-brand-kits-resource.component.d.ts.map +1 -0
  248. package/dist/VideoStudio/resources/video-studio-brand-kits-resource.component.js +600 -0
  249. package/dist/VideoStudio/resources/video-studio-brand-kits-resource.component.js.map +1 -0
  250. package/dist/VideoStudio/resources/video-studio-productions-resource.component.d.ts +182 -0
  251. package/dist/VideoStudio/resources/video-studio-productions-resource.component.d.ts.map +1 -0
  252. package/dist/VideoStudio/resources/video-studio-productions-resource.component.js +1481 -0
  253. package/dist/VideoStudio/resources/video-studio-productions-resource.component.js.map +1 -0
  254. package/dist/VideoStudio/services/vs-studio-slide-in-state.service.d.ts +102 -0
  255. package/dist/VideoStudio/services/vs-studio-slide-in-state.service.d.ts.map +1 -0
  256. package/dist/VideoStudio/services/vs-studio-slide-in-state.service.js +240 -0
  257. package/dist/VideoStudio/services/vs-studio-slide-in-state.service.js.map +1 -0
  258. package/dist/VideoStudio/video-studio-agent-context.d.ts +495 -0
  259. package/dist/VideoStudio/video-studio-agent-context.d.ts.map +1 -0
  260. package/dist/VideoStudio/video-studio-agent-context.js +992 -0
  261. package/dist/VideoStudio/video-studio-agent-context.js.map +1 -0
  262. package/dist/ai-dashboards.module.d.ts +25 -21
  263. package/dist/ai-dashboards.module.d.ts.map +1 -1
  264. package/dist/ai-dashboards.module.js +25 -3
  265. package/dist/ai-dashboards.module.js.map +1 -1
  266. package/dist/module.d.ts +13 -12
  267. package/dist/module.d.ts.map +1 -1
  268. package/dist/module.js +7 -0
  269. package/dist/module.js.map +1 -1
  270. package/dist/public-api.d.ts +8 -0
  271. package/dist/public-api.d.ts.map +1 -1
  272. package/dist/public-api.js +10 -0
  273. package/dist/public-api.js.map +1 -1
  274. package/dist/shared/action-scheduled-job.d.ts.map +1 -1
  275. package/dist/shared/action-scheduled-job.js +2 -0
  276. package/dist/shared/action-scheduled-job.js.map +1 -1
  277. package/dist/video-studio-dashboards.module.d.ts +40 -0
  278. package/dist/video-studio-dashboards.module.d.ts.map +1 -0
  279. package/dist/video-studio-dashboards.module.js +159 -0
  280. package/dist/video-studio-dashboards.module.js.map +1 -0
  281. package/package.json +77 -71
  282. package/dist/PredictiveStudio/at-risk.view-models.d.ts +0 -120
  283. package/dist/PredictiveStudio/at-risk.view-models.d.ts.map +0 -1
  284. package/dist/PredictiveStudio/at-risk.view-models.js +0 -261
  285. package/dist/PredictiveStudio/at-risk.view-models.js.map +0 -1
  286. package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts +0 -109
  287. package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts.map +0 -1
  288. package/dist/PredictiveStudio/components/ps-confirm-modal.component.js +0 -323
  289. package/dist/PredictiveStudio/components/ps-confirm-modal.component.js.map +0 -1
  290. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts +0 -137
  291. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts.map +0 -1
  292. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js +0 -826
  293. package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-dashboards",
3
- "version": "6.2.0-edge.5",
3
+ "version": "6.2.0-edge.7",
4
4
  "description": "MemberJunction Dashboards",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -73,6 +73,10 @@
73
73
  "types": "./dist/predictive-studio-dashboards.module.d.ts",
74
74
  "default": "./dist/predictive-studio-dashboards.module.js"
75
75
  },
76
+ "./video-studio-dashboards.module": {
77
+ "types": "./dist/video-studio-dashboards.module.d.ts",
78
+ "default": "./dist/video-studio-dashboards.module.js"
79
+ },
76
80
  "./integration.module": {
77
81
  "types": "./dist/Integration/integration.module.d.ts",
78
82
  "default": "./dist/Integration/integration.module.js"
@@ -98,7 +102,7 @@
98
102
  "@fortawesome/fontawesome-free": "6.7.2",
99
103
  "@types/d3": "^7.4.0",
100
104
  "sass": "^1.97.3",
101
- "@memberjunction/ng-test-utils": "6.2.0-edge.5"
105
+ "@memberjunction/ng-test-utils": "6.2.0-edge.7"
102
106
  },
103
107
  "peerDependencies": {
104
108
  "@angular/animations": "^21.2.22",
@@ -115,74 +119,76 @@
115
119
  "@codemirror/merge": "^6.11.2",
116
120
  "@codemirror/state": "^6.5.4",
117
121
  "@codemirror/view": "^6.39.12",
118
- "@memberjunction/actions-base": "6.2.0-edge.5",
119
- "@memberjunction/ai-core-plus": "6.2.0-edge.5",
120
- "@memberjunction/ai-engine-base": "6.2.0-edge.5",
121
- "@memberjunction/api-keys-base": "6.2.0-edge.5",
122
- "@memberjunction/core": "6.2.0-edge.5",
123
- "@memberjunction/core-entities": "6.2.0-edge.5",
124
- "@memberjunction/credentials": "6.2.0-edge.5",
125
- "@memberjunction/export-engine": "6.2.0-edge.5",
126
- "@memberjunction/feature-pipelines": "6.2.0-edge.5",
127
- "@memberjunction/global": "6.2.0-edge.5",
128
- "@memberjunction/graphql-dataprovider": "6.2.0-edge.5",
129
- "@memberjunction/integration-engine-base": "6.2.0-edge.5",
130
- "@memberjunction/interactive-component-types": "6.2.0-edge.5",
131
- "@memberjunction/lists-base": "6.2.0-edge.5",
132
- "@memberjunction/ng-action-gallery": "6.2.0-edge.5",
133
- "@memberjunction/ng-actions": "6.2.0-edge.5",
134
- "@memberjunction/ng-agent-requests": "6.2.0-edge.5",
135
- "@memberjunction/ng-agents": "6.2.0-edge.5",
136
- "@memberjunction/ng-rubrics": "6.2.0-edge.5",
137
- "@memberjunction/record-set-processor-base": "6.2.0-edge.5",
138
- "@memberjunction/rubrics-base": "6.2.0-edge.5",
139
- "@memberjunction/ng-ai-test-harness": "6.2.0-edge.5",
140
- "@memberjunction/ng-archive-manager": "6.2.0-edge.5",
141
- "@memberjunction/ng-artifacts": "6.2.0-edge.5",
142
- "@memberjunction/ng-base-application": "6.2.0-edge.5",
143
- "@memberjunction/ng-base-forms": "6.2.0-edge.5",
144
- "@memberjunction/ng-base-types": "6.2.0-edge.5",
145
- "@memberjunction/ng-clustering": "6.2.0-edge.5",
146
- "@memberjunction/ng-code-editor": "6.2.0-edge.5",
147
- "@memberjunction/ng-composer": "6.2.0-edge.5",
148
- "@memberjunction/ng-container-directives": "6.2.0-edge.5",
149
- "@memberjunction/ng-conversations": "6.2.0-edge.5",
150
- "@memberjunction/ng-core-entity-forms": "6.2.0-edge.5",
151
- "@memberjunction/ng-credentials": "6.2.0-edge.5",
152
- "@memberjunction/ng-dashboard-viewer": "6.2.0-edge.5",
153
- "@memberjunction/ng-entity-relationship-diagram": "6.2.0-edge.5",
154
- "@memberjunction/ng-entity-viewer": "6.2.0-edge.5",
155
- "@memberjunction/ng-explorer-settings": "6.2.0-edge.5",
156
- "@memberjunction/ng-export-service": "6.2.0-edge.5",
157
- "@memberjunction/ng-filter-builder": "6.2.0-edge.5",
158
- "@memberjunction/ng-list-management": "6.2.0-edge.5",
159
- "@memberjunction/ng-map-view": "6.2.0-edge.5",
160
- "@memberjunction/ng-markdown": "6.2.0-edge.5",
161
- "@memberjunction/ng-media-player": "6.2.0-edge.5",
162
- "@memberjunction/ng-notifications": "6.2.0-edge.5",
163
- "@memberjunction/ng-query-viewer": "6.2.0-edge.5",
164
- "@memberjunction/ng-react": "6.2.0-edge.5",
165
- "@memberjunction/ng-record-process-studio": "6.2.0-edge.5",
166
- "@memberjunction/ng-resource-permissions": "6.2.0-edge.5",
167
- "@memberjunction/ng-scheduling": "6.2.0-edge.5",
168
- "@memberjunction/ng-search": "6.2.0-edge.5",
169
- "@memberjunction/ng-shared": "6.2.0-edge.5",
170
- "@memberjunction/ng-shared-generic": "6.2.0-edge.5",
171
- "@memberjunction/ng-task-graph-editor": "6.2.0-edge.5",
172
- "@memberjunction/ng-tabstrip": "6.2.0-edge.5",
173
- "@memberjunction/ng-testing": "6.2.0-edge.5",
174
- "@memberjunction/ng-trees": "6.2.0-edge.5",
175
- "@memberjunction/ng-ui-components": "6.2.0-edge.5",
176
- "@memberjunction/ng-user-routines": "6.2.0-edge.5",
177
- "@memberjunction/ng-versions": "6.2.0-edge.5",
178
- "@memberjunction/ng-word-cloud": "6.2.0-edge.5",
179
- "@memberjunction/predictive-studio-core": "6.2.0-edge.5",
180
- "@memberjunction/tag-engine-base": "6.2.0-edge.5",
181
- "@memberjunction/templates-base-types": "6.2.0-edge.5",
182
- "@memberjunction/testing-engine-base": "6.2.0-edge.5",
183
- "@memberjunction/theme-engine": "6.2.0-edge.5",
184
- "@memberjunction/work-queue-base": "6.2.0-edge.5",
185
- "@memberjunction/work-queue-core": "6.2.0-edge.5",
122
+ "@memberjunction/actions-base": "6.2.0-edge.7",
123
+ "@memberjunction/ai-core-plus": "6.2.0-edge.7",
124
+ "@memberjunction/ai-engine-base": "6.2.0-edge.7",
125
+ "@memberjunction/api-keys-base": "6.2.0-edge.7",
126
+ "@memberjunction/core": "6.2.0-edge.7",
127
+ "@memberjunction/core-entities": "6.2.0-edge.7",
128
+ "@memberjunction/credentials": "6.2.0-edge.7",
129
+ "@memberjunction/export-engine": "6.2.0-edge.7",
130
+ "@memberjunction/feature-pipelines": "6.2.0-edge.7",
131
+ "@memberjunction/global": "6.2.0-edge.7",
132
+ "@memberjunction/graphql-dataprovider": "6.2.0-edge.7",
133
+ "@memberjunction/integration-engine-base": "6.2.0-edge.7",
134
+ "@memberjunction/interactive-component-types": "6.2.0-edge.7",
135
+ "@memberjunction/lists-base": "6.2.0-edge.7",
136
+ "@memberjunction/ng-action-gallery": "6.2.0-edge.7",
137
+ "@memberjunction/ng-actions": "6.2.0-edge.7",
138
+ "@memberjunction/ng-agent-requests": "6.2.0-edge.7",
139
+ "@memberjunction/ng-agents": "6.2.0-edge.7",
140
+ "@memberjunction/ng-rubrics": "6.2.0-edge.7",
141
+ "@memberjunction/record-set-processor-base": "6.2.0-edge.7",
142
+ "@memberjunction/rubrics-base": "6.2.0-edge.7",
143
+ "@memberjunction/ng-ai-test-harness": "6.2.0-edge.7",
144
+ "@memberjunction/ng-archive-manager": "6.2.0-edge.7",
145
+ "@memberjunction/ng-artifacts": "6.2.0-edge.7",
146
+ "@memberjunction/ng-base-application": "6.2.0-edge.7",
147
+ "@memberjunction/ng-base-forms": "6.2.0-edge.7",
148
+ "@memberjunction/ng-base-types": "6.2.0-edge.7",
149
+ "@memberjunction/ng-brand-kits": "6.2.0-edge.7",
150
+ "@memberjunction/ng-clustering": "6.2.0-edge.7",
151
+ "@memberjunction/ng-code-editor": "6.2.0-edge.7",
152
+ "@memberjunction/ng-composer": "6.2.0-edge.7",
153
+ "@memberjunction/ng-container-directives": "6.2.0-edge.7",
154
+ "@memberjunction/ng-conversations": "6.2.0-edge.7",
155
+ "@memberjunction/ng-core-entity-forms": "6.2.0-edge.7",
156
+ "@memberjunction/ng-credentials": "6.2.0-edge.7",
157
+ "@memberjunction/ng-dashboard-viewer": "6.2.0-edge.7",
158
+ "@memberjunction/ng-entity-relationship-diagram": "6.2.0-edge.7",
159
+ "@memberjunction/ng-entity-viewer": "6.2.0-edge.7",
160
+ "@memberjunction/ng-explorer-settings": "6.2.0-edge.7",
161
+ "@memberjunction/ng-export-service": "6.2.0-edge.7",
162
+ "@memberjunction/ng-filter-builder": "6.2.0-edge.7",
163
+ "@memberjunction/ng-list-management": "6.2.0-edge.7",
164
+ "@memberjunction/ng-map-view": "6.2.0-edge.7",
165
+ "@memberjunction/ng-markdown": "6.2.0-edge.7",
166
+ "@memberjunction/ng-media-player": "6.2.0-edge.7",
167
+ "@memberjunction/ng-notifications": "6.2.0-edge.7",
168
+ "@memberjunction/ng-query-viewer": "6.2.0-edge.7",
169
+ "@memberjunction/ng-react": "6.2.0-edge.7",
170
+ "@memberjunction/ng-record-process-studio": "6.2.0-edge.7",
171
+ "@memberjunction/ng-resource-permissions": "6.2.0-edge.7",
172
+ "@memberjunction/ng-scheduling": "6.2.0-edge.7",
173
+ "@memberjunction/ng-search": "6.2.0-edge.7",
174
+ "@memberjunction/ng-shared": "6.2.0-edge.7",
175
+ "@memberjunction/ng-shared-generic": "6.2.0-edge.7",
176
+ "@memberjunction/ng-task-graph-editor": "6.2.0-edge.7",
177
+ "@memberjunction/ng-tabstrip": "6.2.0-edge.7",
178
+ "@memberjunction/ng-testing": "6.2.0-edge.7",
179
+ "@memberjunction/ng-trees": "6.2.0-edge.7",
180
+ "@memberjunction/ng-ui-components": "6.2.0-edge.7",
181
+ "@memberjunction/ng-user-routines": "6.2.0-edge.7",
182
+ "@memberjunction/ng-versions": "6.2.0-edge.7",
183
+ "@memberjunction/ng-word-cloud": "6.2.0-edge.7",
184
+ "@memberjunction/predictive-studio-core": "6.2.0-edge.7",
185
+ "@memberjunction/tag-engine-base": "6.2.0-edge.7",
186
+ "@memberjunction/templates-base-types": "6.2.0-edge.7",
187
+ "@memberjunction/testing-engine-base": "6.2.0-edge.7",
188
+ "@memberjunction/theme-engine": "6.2.0-edge.7",
189
+ "@memberjunction/video-studio-core": "6.2.0-edge.7",
190
+ "@memberjunction/work-queue-base": "6.2.0-edge.7",
191
+ "@memberjunction/work-queue-core": "6.2.0-edge.7",
186
192
  "ag-grid-angular": "^35.0.1",
187
193
  "ag-grid-community": "^35.0.1",
188
194
  "angular-split": "^20.0.0",
@@ -190,7 +196,7 @@
190
196
  "d3": "^7.8.5",
191
197
  "rxjs": "^7.8.2",
192
198
  "tslib": "^2.8.1",
193
- "@memberjunction/ng-auth-services": "6.2.0-edge.5"
199
+ "@memberjunction/ng-auth-services": "6.2.0-edge.7"
194
200
  },
195
201
  "sideEffects": false,
196
202
  "repository": {
@@ -1,120 +0,0 @@
1
- /**
2
- * Pure derivations for the business workspace's **ranked at-risk list** — turning a model's per-record
3
- * scoring results (`MJ: Process Run Details` payloads) into a "who to focus on" list sorted by risk, and
4
- * the model's global feature importance into plain-language "what's driving this" drivers.
5
- *
6
- * Honest about the gap: MJ stores only GLOBAL feature importance (not per-record/SHAP), so we surface the
7
- * top global drivers once for the whole prediction rather than fabricating per-member attribution.
8
- *
9
- * Framework-free + deterministic → unit-tested with no Angular.
10
- */
11
- import { type OutcomeConfig } from '@memberjunction/predictive-studio-core';
12
- /** A scored record in the at-risk list. */
13
- export interface AtRiskRow {
14
- recordId: string;
15
- /**
16
- * Human-readable label for the record (e.g. the member's name/email), resolved from the model's
17
- * target entity. Null until resolved; the UI falls back to {@link recordId} so the row is never blank.
18
- */
19
- label: string | null;
20
- /** 0–1 prediction score (probability / risk). */
21
- score: number;
22
- /** Risk as a 0–100 integer, for display. */
23
- riskPct: number;
24
- /** Predicted class label, when present (classification). */
25
- class: string | null;
26
- /** Risk band, for color / filtering. */
27
- band: 'high' | 'medium' | 'low' | string;
28
- /** Qualitative status label (e.g. "High", "Critical", "Low Risk"). */
29
- status?: string;
30
- /** Semantic badge color. */
31
- badgeColor?: string;
32
- /** Icon class. */
33
- icon?: string;
34
- /**
35
- * Top signed per-record drivers behind THIS row's prediction (P1-5), humanized + one-hot-collapsed for
36
- * display. `up: true` pushed the risk up, `false` down. Null when the model doesn't produce per-record
37
- * attribution (tree/ensemble/multiclass) — the UI then shows the model's global drivers instead.
38
- */
39
- drivers: RowDriver[] | null;
40
- }
41
- /** A humanized, signed per-record driver for the at-risk row's inline "why". */
42
- export interface RowDriver {
43
- /** Display label (humanized, one-hot base collapsed). */
44
- label: string;
45
- /** Signed contribution magnitude for this row. */
46
- value: number;
47
- /** Whether this pushed the risk UP (value > 0) or down. */
48
- up: boolean;
49
- }
50
- /** Parse + humanize the raw per-record `drivers` (post-preprocessing `feature`/`value`) into {@link RowDriver}s. */
51
- export declare function ParseRowDrivers(raw: unknown): RowDriver[] | null;
52
- /** @deprecated Use {@link ParseRowDrivers}. */
53
- export declare function parseRowDrivers(raw: unknown): RowDriver[] | null;
54
- /**
55
- * Build a human-readable label for a record from its (simple) row of the target entity — preferring a
56
- * single `Name`, else `FirstName`+`LastName`, else `Email`, else any first non-empty string field.
57
- * Returns null when nothing usable is found (caller falls back to the record id).
58
- */
59
- export declare function LabelFromRecord(row: Record<string, unknown> | undefined | null): string | null;
60
- /** @deprecated Use {@link LabelFromRecord}. */
61
- export declare function labelFromRecord(row: Record<string, unknown> | undefined | null): string | null;
62
- /** The raw per-record detail the list is built from (a slice of `MJ: Process Run Details`). */
63
- export interface RunDetailLike {
64
- recordId: string;
65
- ResultPayload?: string | null;
66
- }
67
- /** Options for parsing predictions into at-risk rows. */
68
- export interface ParseAtRiskOptions {
69
- /**
70
- * When true, the model predicts probability of a positive outcome (e.g. `P(Renewed)`).
71
- * Churn / adverse risk is therefore inverted: `riskScore = 1.0 - score`.
72
- * High score (0.99) -> Low Risk (1%, green). Low score (0.10) -> High Risk (90%, red).
73
- */
74
- InvertedRisk?: boolean;
75
- /**
76
- * Configured outcome metadata for the model (labels, thresholds, colors, icons).
77
- * When provided, `resolveScoreBand()` evaluates the dynamic band, status, badgeColor, and icon.
78
- */
79
- OutcomeConfig?: OutcomeConfig;
80
- }
81
- /** Result of detecting whether a model is a renewal model and what its output score represents. */
82
- export interface RenewalPolarityResult {
83
- IsRenewalModel: boolean;
84
- /**
85
- * True if `score` represents adverse lapse risk (P(Lapse) / Churn Risk), e.g. 0.01 = 1% risk.
86
- * False if `score` represents positive outcome probability (P(Renewed)), e.g. 0.99 = 99% renewal chance.
87
- */
88
- ScoreIsLapseRisk: boolean;
89
- }
90
- /**
91
- * Robustly inspects model metadata and sample scoring payloads to determine:
92
- * 1. Whether this is a renewal/retention/churn model (`isRenewalModel`)
93
- * 2. Whether the raw payload `score` represents adverse lapse risk (P(Lapse)) or positive outcome (P(Renewed))
94
- */
95
- export declare function ResolveRenewalPolarity(rawPayloads: Array<string | null | undefined>, targetVariable?: string | null, modelName?: string | null): RenewalPolarityResult;
96
- /** @deprecated Use {@link ResolveRenewalPolarity}. */
97
- export declare function resolveRenewalPolarity(rawPayloads: Array<string | null | undefined>, targetVariable?: string | null, modelName?: string | null): RenewalPolarityResult;
98
- /** Parse + rank the per-record predictions into the at-risk list (highest risk first). */
99
- export declare function ParseAtRiskRows(details: RunDetailLike[], options?: ParseAtRiskOptions): AtRiskRow[];
100
- /** @deprecated Use {@link ParseAtRiskRows}. */
101
- export declare function parseAtRiskRows(details: RunDetailLike[], options?: ParseAtRiskOptions): AtRiskRow[];
102
- /**
103
- * The top plain-language drivers for the whole prediction, from the model's global feature importance.
104
- * Accepts the object form (`{"MembershipType=Student": 0.9, ...}`) or the array form
105
- * (`[{feature, importance}]`), strips one-hot `=value` suffixes, de-duplicates, and returns the
106
- * highest-importance feature names — so a business user sees "what's driving this", not raw weights.
107
- */
108
- export declare function TopGlobalDrivers(featureImportanceJson: string | null | undefined, n?: number): string[];
109
- /** @deprecated Use {@link TopGlobalDrivers}. */
110
- export declare function topGlobalDrivers(featureImportanceJson: string | null | undefined, n?: number): string[];
111
- /**
112
- * Turn a raw feature/column name into a readable label — `RetentionOverdueInvoices` → `Retention Overdue
113
- * Invoices`, `overdue_invoices` → `Overdue Invoices`, and a one-hot `MembershipType=Student` →
114
- * `Membership Type = Student`. Splits camelCase + snake/kebab, spaces one-hot `=`, collapses whitespace,
115
- * and capitalizes the first letter. Already-spaced labels pass through unchanged.
116
- */
117
- export declare function HumanizeFeatureName(name: string): string;
118
- /** @deprecated Use {@link HumanizeFeatureName}. */
119
- export declare function humanizeFeatureName(name: string): string;
120
- //# sourceMappingURL=at-risk.view-models.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"at-risk.view-models.d.ts","sourceRoot":"","sources":["../../src/PredictiveStudio/at-risk.view-models.ts"],"names":[],"mappings":"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"}
@@ -1,261 +0,0 @@
1
- /**
2
- * Pure derivations for the business workspace's **ranked at-risk list** — turning a model's per-record
3
- * scoring results (`MJ: Process Run Details` payloads) into a "who to focus on" list sorted by risk, and
4
- * the model's global feature importance into plain-language "what's driving this" drivers.
5
- *
6
- * Honest about the gap: MJ stores only GLOBAL feature importance (not per-record/SHAP), so we surface the
7
- * top global drivers once for the whole prediction rather than fabricating per-member attribution.
8
- *
9
- * Framework-free + deterministic → unit-tested with no Angular.
10
- */
11
- import { resolveScoreBand, } from '@memberjunction/predictive-studio-core';
12
- /** Parse + humanize the raw per-record `drivers` (post-preprocessing `feature`/`value`) into {@link RowDriver}s. */
13
- export function ParseRowDrivers(raw) {
14
- if (!Array.isArray(raw) || raw.length === 0)
15
- return null;
16
- const out = [];
17
- for (const d of raw) {
18
- const feature = typeof d?.feature === 'string' ? d.feature : '';
19
- const rawVal = typeof d?.value === 'number' ? d.value : typeof d?.importance === 'number' ? d.importance : typeof d?.weight === 'number' ? d.weight : NaN;
20
- const value = Number(rawVal);
21
- if (!feature || !Number.isFinite(value))
22
- continue;
23
- // Keep the one-hot category: for a per-record "why", the category IS the story — "Membership Type =
24
- // Student lowers risk" is actionable where a collapsed "Membership Type" is close to meaningless.
25
- // (Collapsing across categories is only right for GLOBAL importance — see topGlobalDrivers.)
26
- out.push({ label: HumanizeFeatureName(feature), value, up: value > 0 });
27
- }
28
- return out.length > 0 ? out : null;
29
- }
30
- /** @deprecated Use {@link ParseRowDrivers}. */
31
- export function parseRowDrivers(raw) {
32
- return ParseRowDrivers(raw);
33
- }
34
- /**
35
- * Build a human-readable label for a record from its (simple) row of the target entity — preferring a
36
- * single `Name`, else `FirstName`+`LastName`, else `Email`, else any first non-empty string field.
37
- * Returns null when nothing usable is found (caller falls back to the record id).
38
- */
39
- export function LabelFromRecord(row) {
40
- if (!row)
41
- return null;
42
- const str = (v) => (typeof v === 'string' ? v.trim() : '');
43
- const member = str(row['MemberName'] || row['Member'] || row['FullName']);
44
- if (member)
45
- return member;
46
- const name = str(row['Name']);
47
- if (name)
48
- return name;
49
- const full = `${str(row['FirstName'])} ${str(row['LastName'])}`.trim();
50
- const email = str(row['Email']);
51
- if (full && email)
52
- return `${full} (${email})`;
53
- if (full)
54
- return full;
55
- if (email)
56
- return email;
57
- for (const v of Object.values(row)) {
58
- const s = str(v);
59
- if (s && s.length <= 120)
60
- return s;
61
- }
62
- return null;
63
- }
64
- /** @deprecated Use {@link LabelFromRecord}. */
65
- export function labelFromRecord(row) {
66
- return LabelFromRecord(row);
67
- }
68
- /**
69
- * Robustly inspects model metadata and sample scoring payloads to determine:
70
- * 1. Whether this is a renewal/retention/churn model (`isRenewalModel`)
71
- * 2. Whether the raw payload `score` represents adverse lapse risk (P(Lapse)) or positive outcome (P(Renewed))
72
- */
73
- export function ResolveRenewalPolarity(rawPayloads, targetVariable, modelName) {
74
- const target = (targetVariable ?? '').toLowerCase();
75
- const name = (modelName ?? '').toLowerCase();
76
- const isTargetRenewal = target.includes('renew') ||
77
- target.includes('lapse') ||
78
- target.includes('retention') ||
79
- target.includes('churn') ||
80
- target === 'status' ||
81
- name.includes('renew') ||
82
- name.includes('retention') ||
83
- name.includes('churn');
84
- let hasRenewalKeywords = false;
85
- const sampleScoresForRenewed = [];
86
- for (const p of rawPayloads.slice(0, 50)) {
87
- if (!p)
88
- continue;
89
- if (p.includes('"Renewed"') ||
90
- p.includes('"renewed"') ||
91
- p.includes('"Lapsed"') ||
92
- p.includes('"lapsed"') ||
93
- p.includes('Renewal Risk')) {
94
- hasRenewalKeywords = true;
95
- }
96
- try {
97
- const parsed = JSON.parse(p);
98
- const out = (parsed.output ?? parsed);
99
- if (typeof out.score === 'number' && typeof out.class === 'string') {
100
- const cls = out.class.toLowerCase();
101
- if (cls === 'renewed' || cls === 'active') {
102
- sampleScoresForRenewed.push(out.score);
103
- }
104
- }
105
- }
106
- catch {
107
- // skip invalid json
108
- }
109
- }
110
- const isRenewalModel = isTargetRenewal || hasRenewalKeywords;
111
- if (!isRenewalModel) {
112
- return { IsRenewalModel: false, ScoreIsLapseRisk: false };
113
- }
114
- if (sampleScoresForRenewed.length > 0) {
115
- const avg = sampleScoresForRenewed.reduce((a, b) => a + b, 0) / sampleScoresForRenewed.length;
116
- // If members predicted 'Renewed' have small scores (< 0.5), the score represents Lapse Risk (P(Lapse))
117
- return { IsRenewalModel: true, ScoreIsLapseRisk: avg < 0.5 };
118
- }
119
- // Fallback: target or name containing "risk", "lapse", or "churn" outputs lapse probability
120
- const scoreIsLapseRisk = target.includes('risk') ||
121
- target.includes('lapse') ||
122
- target.includes('churn') ||
123
- name.includes('risk') ||
124
- name.includes('churn');
125
- return { IsRenewalModel: true, ScoreIsLapseRisk: scoreIsLapseRisk };
126
- }
127
- /** @deprecated Use {@link ResolveRenewalPolarity}. */
128
- export function resolveRenewalPolarity(rawPayloads, targetVariable, modelName) {
129
- return ResolveRenewalPolarity(rawPayloads, targetVariable, modelName);
130
- }
131
- function bandFor(score) {
132
- return score >= 0.7 ? 'high' : score >= 0.4 ? 'medium' : 'low';
133
- }
134
- /** Parse + rank the per-record predictions into the at-risk list (highest risk first). */
135
- export function ParseAtRiskRows(details, options) {
136
- const rows = [];
137
- const isInverted = options?.InvertedRisk === true;
138
- const outcomeConfig = options?.OutcomeConfig;
139
- for (const d of details) {
140
- if (!d.ResultPayload)
141
- continue;
142
- let parsed;
143
- try {
144
- parsed = JSON.parse(d.ResultPayload);
145
- }
146
- catch {
147
- continue;
148
- }
149
- // Write-back runs nest the prediction under `output`; generic runs carry it at the top level.
150
- const p = parsed.output ?? parsed;
151
- if (typeof p.score !== 'number' || !Number.isFinite(p.score))
152
- continue;
153
- const score = p.score;
154
- const effectiveRisk = isInverted ? Math.max(0, Math.min(1, 1 - score)) : score;
155
- const riskPct = Math.round(effectiveRisk * 100);
156
- let bandKey;
157
- let status = p.status;
158
- let badgeColor = p.badgeColor;
159
- let icon = p.icon;
160
- if (outcomeConfig) {
161
- const resolved = resolveScoreBand(score, outcomeConfig);
162
- if (resolved) {
163
- bandKey = resolved.Key;
164
- status = status ?? resolved.Label;
165
- badgeColor = badgeColor ?? resolved.BadgeColor;
166
- icon = icon ?? resolved.Icon;
167
- }
168
- else {
169
- bandKey = p.band ?? bandFor(effectiveRisk);
170
- }
171
- }
172
- else if (p.band) {
173
- bandKey = p.band;
174
- }
175
- else {
176
- bandKey = bandFor(effectiveRisk);
177
- }
178
- rows.push({
179
- recordId: d.recordId,
180
- label: null,
181
- score,
182
- riskPct,
183
- class: p.class ?? null,
184
- band: bandKey,
185
- status,
186
- badgeColor,
187
- icon,
188
- drivers: ParseRowDrivers(p.drivers),
189
- });
190
- }
191
- return rows.sort((a, b) => b.riskPct - a.riskPct);
192
- }
193
- /** @deprecated Use {@link ParseAtRiskRows}. */
194
- export function parseAtRiskRows(details, options) {
195
- return ParseAtRiskRows(details, options);
196
- }
197
- /**
198
- * The top plain-language drivers for the whole prediction, from the model's global feature importance.
199
- * Accepts the object form (`{"MembershipType=Student": 0.9, ...}`) or the array form
200
- * (`[{feature, importance}]`), strips one-hot `=value` suffixes, de-duplicates, and returns the
201
- * highest-importance feature names — so a business user sees "what's driving this", not raw weights.
202
- */
203
- export function TopGlobalDrivers(featureImportanceJson, n = 3) {
204
- if (!featureImportanceJson)
205
- return [];
206
- let parsed;
207
- try {
208
- parsed = JSON.parse(featureImportanceJson);
209
- }
210
- catch {
211
- return [];
212
- }
213
- const pairs = [];
214
- if (Array.isArray(parsed)) {
215
- for (const e of parsed) {
216
- const name = (e.feature ?? e.name);
217
- const weight = (e.importance ?? e.value);
218
- if (typeof name === 'string' && typeof weight === 'number')
219
- pairs.push({ name, weight: Math.abs(weight) });
220
- }
221
- }
222
- else if (parsed && typeof parsed === 'object') {
223
- for (const [name, weight] of Object.entries(parsed)) {
224
- if (typeof weight === 'number')
225
- pairs.push({ name, weight: Math.abs(weight) });
226
- }
227
- }
228
- // Collapse one-hot columns ("Feature=Value" → "Feature"), keeping each feature's max weight.
229
- const byFeature = new Map();
230
- for (const { name, weight } of pairs) {
231
- const base = name.split('=')[0].trim();
232
- if (!base)
233
- continue;
234
- byFeature.set(base, Math.max(byFeature.get(base) ?? 0, weight));
235
- }
236
- return [...byFeature.entries()].sort((a, b) => b[1] - a[1]).slice(0, n).map(([name]) => HumanizeFeatureName(name));
237
- }
238
- /** @deprecated Use {@link TopGlobalDrivers}. */
239
- export function topGlobalDrivers(featureImportanceJson, n = 3) {
240
- return TopGlobalDrivers(featureImportanceJson, n);
241
- }
242
- /**
243
- * Turn a raw feature/column name into a readable label — `RetentionOverdueInvoices` → `Retention Overdue
244
- * Invoices`, `overdue_invoices` → `Overdue Invoices`, and a one-hot `MembershipType=Student` →
245
- * `Membership Type = Student`. Splits camelCase + snake/kebab, spaces one-hot `=`, collapses whitespace,
246
- * and capitalizes the first letter. Already-spaced labels pass through unchanged.
247
- */
248
- export function HumanizeFeatureName(name) {
249
- return name
250
- .replace(/[_-]+/g, ' ')
251
- .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
252
- .replace(/\s*=\s*/g, ' = ')
253
- .replace(/\s+/g, ' ')
254
- .trim()
255
- .replace(/^\w/, (c) => c.toUpperCase());
256
- }
257
- /** @deprecated Use {@link HumanizeFeatureName}. */
258
- export function humanizeFeatureName(name) {
259
- return HumanizeFeatureName(name);
260
- }
261
- //# sourceMappingURL=at-risk.view-models.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"at-risk.view-models.js","sourceRoot":"","sources":["../../src/PredictiveStudio/at-risk.view-models.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure derivations for the business workspace's **ranked at-risk list** — turning a model's per-record\n * scoring results (`MJ: Process Run Details` payloads) into a \"who to focus on\" list sorted by risk, and\n * the model's global feature importance into plain-language \"what's driving this\" drivers.\n *\n * Honest about the gap: MJ stores only GLOBAL feature importance (not per-record/SHAP), so we surface the\n * top global drivers once for the whole prediction rather than fabricating per-member attribution.\n *\n * Framework-free + deterministic → unit-tested with no Angular.\n */\n\nimport {\n type OutcomeConfig,\n resolveScoreBand,\n} from '@memberjunction/predictive-studio-core';\n\n/** A scored record in the at-risk list. */\nexport interface AtRiskRow {\n recordId: string; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /**\n * Human-readable label for the record (e.g. the member's name/email), resolved from the model's\n * target entity. Null until resolved; the UI falls back to {@link recordId} so the row is never blank.\n */\n label: string | null; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** 0–1 prediction score (probability / risk). */\n score: number; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** Risk as a 0–100 integer, for display. */\n riskPct: number; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** Predicted class label, when present (classification). */\n class: string | null; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** Risk band, for color / filtering. */\n band: 'high' | 'medium' | 'low' | string; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** Qualitative status label (e.g. \"High\", \"Critical\", \"Low Risk\"). */\n status?: string; // case-violation-ok-legacy-back-compat: optional, and the old name is also read off a value the checker cannot type; renaming it stays assignable and silently yields undefined\n /** Semantic badge color. */\n badgeColor?: string; // case-violation-ok-legacy-back-compat: optional, and the old name is also read off a value the checker cannot type; renaming it stays assignable and silently yields undefined\n /** Icon class. */\n icon?: string; // case-violation-ok-legacy-back-compat: optional, and the old name is also read off a value the checker cannot type; renaming it stays assignable and silently yields undefined\n /**\n * Top signed per-record drivers behind THIS row's prediction (P1-5), humanized + one-hot-collapsed for\n * display. `up: true` pushed the risk up, `false` down. Null when the model doesn't produce per-record\n * attribution (tree/ensemble/multiclass) — the UI then shows the model's global drivers instead.\n */\n drivers: RowDriver[] | null; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n}\n\n/** A humanized, signed per-record driver for the at-risk row's inline \"why\". */\nexport interface RowDriver {\n /** Display label (humanized, one-hot base collapsed). */\n label: string; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** Signed contribution magnitude for this row. */\n value: number; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n /** Whether this pushed the risk UP (value > 0) or down. */\n up: boolean; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n}\n\n/** Parse + humanize the raw per-record `drivers` (post-preprocessing `feature`/`value`) into {@link RowDriver}s. */\nexport function ParseRowDrivers(raw: unknown): RowDriver[] | null {\n if (!Array.isArray(raw) || raw.length === 0) return null;\n const out: RowDriver[] = [];\n for (const d of raw as Array<{ feature?: unknown; value?: unknown; importance?: unknown; weight?: unknown }>) {\n const feature = typeof d?.feature === 'string' ? d.feature : '';\n const rawVal = typeof d?.value === 'number' ? d.value : typeof d?.importance === 'number' ? d.importance : typeof d?.weight === 'number' ? d.weight : NaN;\n const value = Number(rawVal);\n if (!feature || !Number.isFinite(value)) continue;\n // Keep the one-hot category: for a per-record \"why\", the category IS the story — \"Membership Type =\n // Student lowers risk\" is actionable where a collapsed \"Membership Type\" is close to meaningless.\n // (Collapsing across categories is only right for GLOBAL importance — see topGlobalDrivers.)\n out.push({ label: HumanizeFeatureName(feature), value, up: value > 0 });\n }\n return out.length > 0 ? out : null;\n}\n\n/** @deprecated Use {@link ParseRowDrivers}. */\nexport function parseRowDrivers(raw: unknown): RowDriver[] | null {\n return ParseRowDrivers(raw);\n}\n\n/**\n * Build a human-readable label for a record from its (simple) row of the target entity — preferring a\n * single `Name`, else `FirstName`+`LastName`, else `Email`, else any first non-empty string field.\n * Returns null when nothing usable is found (caller falls back to the record id).\n */\nexport function LabelFromRecord(row: Record<string, unknown> | undefined | null): string | null {\n if (!row) return null;\n const str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\n const member = str(row['MemberName'] || row['Member'] || row['FullName']);\n if (member) return member;\n const name = str(row['Name']);\n if (name) return name;\n const full = `${str(row['FirstName'])} ${str(row['LastName'])}`.trim();\n const email = str(row['Email']);\n if (full && email) return `${full} (${email})`;\n if (full) return full;\n if (email) return email;\n for (const v of Object.values(row)) {\n const s = str(v);\n if (s && s.length <= 120) return s;\n }\n return null;\n}\n\n/** @deprecated Use {@link LabelFromRecord}. */\nexport function labelFromRecord(row: Record<string, unknown> | undefined | null): string | null {\n return LabelFromRecord(row);\n}\n\n/** The raw per-record detail the list is built from (a slice of `MJ: Process Run Details`). */\nexport interface RunDetailLike {\n recordId: string; // case-violation-ok-legacy-back-compat: the old name is also read off a value typed `any`, where a rename would compile and silently return undefined\n ResultPayload?: string | null;\n}\n\n/** Options for parsing predictions into at-risk rows. */\nexport interface ParseAtRiskOptions {\n /**\n * When true, the model predicts probability of a positive outcome (e.g. `P(Renewed)`).\n * Churn / adverse risk is therefore inverted: `riskScore = 1.0 - score`.\n * High score (0.99) -> Low Risk (1%, green). Low score (0.10) -> High Risk (90%, red).\n */\n InvertedRisk?: boolean;\n /**\n * Configured outcome metadata for the model (labels, thresholds, colors, icons).\n * When provided, `resolveScoreBand()` evaluates the dynamic band, status, badgeColor, and icon.\n */\n OutcomeConfig?: OutcomeConfig;\n}\n\n/** Result of detecting whether a model is a renewal model and what its output score represents. */\nexport interface RenewalPolarityResult {\n IsRenewalModel: boolean;\n /**\n * True if `score` represents adverse lapse risk (P(Lapse) / Churn Risk), e.g. 0.01 = 1% risk.\n * False if `score` represents positive outcome probability (P(Renewed)), e.g. 0.99 = 99% renewal chance.\n */\n ScoreIsLapseRisk: boolean;\n}\n\n/**\n * Robustly inspects model metadata and sample scoring payloads to determine:\n * 1. Whether this is a renewal/retention/churn model (`isRenewalModel`)\n * 2. Whether the raw payload `score` represents adverse lapse risk (P(Lapse)) or positive outcome (P(Renewed))\n */\nexport function ResolveRenewalPolarity(\n rawPayloads: Array<string | null | undefined>,\n targetVariable?: string | null,\n modelName?: string | null,\n): RenewalPolarityResult {\n const target = (targetVariable ?? '').toLowerCase();\n const name = (modelName ?? '').toLowerCase();\n const isTargetRenewal =\n target.includes('renew') ||\n target.includes('lapse') ||\n target.includes('retention') ||\n target.includes('churn') ||\n target === 'status' ||\n name.includes('renew') ||\n name.includes('retention') ||\n name.includes('churn');\n\n let hasRenewalKeywords = false;\n const sampleScoresForRenewed: number[] = [];\n\n for (const p of rawPayloads.slice(0, 50)) {\n if (!p) continue;\n if (\n p.includes('\"Renewed\"') ||\n p.includes('\"renewed\"') ||\n p.includes('\"Lapsed\"') ||\n p.includes('\"lapsed\"') ||\n p.includes('Renewal Risk')\n ) {\n hasRenewalKeywords = true;\n }\n try {\n const parsed = JSON.parse(p);\n const out = (parsed.output ?? parsed) as { score?: number; class?: string };\n if (typeof out.score === 'number' && typeof out.class === 'string') {\n const cls = out.class.toLowerCase();\n if (cls === 'renewed' || cls === 'active') {\n sampleScoresForRenewed.push(out.score);\n }\n }\n } catch {\n // skip invalid json\n }\n }\n\n const isRenewalModel = isTargetRenewal || hasRenewalKeywords;\n if (!isRenewalModel) {\n return { IsRenewalModel: false, ScoreIsLapseRisk: false };\n }\n\n if (sampleScoresForRenewed.length > 0) {\n const avg = sampleScoresForRenewed.reduce((a, b) => a + b, 0) / sampleScoresForRenewed.length;\n // If members predicted 'Renewed' have small scores (< 0.5), the score represents Lapse Risk (P(Lapse))\n return { IsRenewalModel: true, ScoreIsLapseRisk: avg < 0.5 };\n }\n\n // Fallback: target or name containing \"risk\", \"lapse\", or \"churn\" outputs lapse probability\n const scoreIsLapseRisk =\n target.includes('risk') ||\n target.includes('lapse') ||\n target.includes('churn') ||\n name.includes('risk') ||\n name.includes('churn');\n return { IsRenewalModel: true, ScoreIsLapseRisk: scoreIsLapseRisk };\n}\n\n/** @deprecated Use {@link ResolveRenewalPolarity}. */\nexport function resolveRenewalPolarity(\n rawPayloads: Array<string | null | undefined>,\n targetVariable?: string | null,\n modelName?: string | null,\n): RenewalPolarityResult {\n return ResolveRenewalPolarity(rawPayloads, targetVariable, modelName);\n}\n\nfunction bandFor(score: number): AtRiskRow['band'] {\n return score >= 0.7 ? 'high' : score >= 0.4 ? 'medium' : 'low';\n}\n\n/** Parse + rank the per-record predictions into the at-risk list (highest risk first). */\nexport function ParseAtRiskRows(details: RunDetailLike[], options?: ParseAtRiskOptions): AtRiskRow[] {\n const rows: AtRiskRow[] = [];\n const isInverted = options?.InvertedRisk === true;\n const outcomeConfig = options?.OutcomeConfig;\n\n for (const d of details) {\n if (!d.ResultPayload) continue;\n let parsed: {\n score?: number;\n class?: string;\n status?: string;\n band?: string;\n badgeColor?: string;\n icon?: string;\n drivers?: unknown;\n output?: {\n score?: number;\n class?: string;\n status?: string;\n band?: string;\n badgeColor?: string;\n icon?: string;\n drivers?: unknown;\n };\n };\n try {\n parsed = JSON.parse(d.ResultPayload);\n } catch {\n continue;\n }\n // Write-back runs nest the prediction under `output`; generic runs carry it at the top level.\n const p = parsed.output ?? parsed;\n if (typeof p.score !== 'number' || !Number.isFinite(p.score)) continue;\n const score = p.score;\n const effectiveRisk = isInverted ? Math.max(0, Math.min(1, 1 - score)) : score;\n const riskPct = Math.round(effectiveRisk * 100);\n\n let bandKey: string;\n let status: string | undefined = p.status;\n let badgeColor: string | undefined = p.badgeColor;\n let icon: string | undefined = p.icon;\n\n if (outcomeConfig) {\n const resolved = resolveScoreBand(score, outcomeConfig);\n if (resolved) {\n bandKey = resolved.Key;\n status = status ?? resolved.Label;\n badgeColor = badgeColor ?? resolved.BadgeColor;\n icon = icon ?? resolved.Icon;\n } else {\n bandKey = p.band ?? bandFor(effectiveRisk);\n }\n } else if (p.band) {\n bandKey = p.band;\n } else {\n bandKey = bandFor(effectiveRisk);\n }\n\n rows.push({\n recordId: d.recordId,\n label: null,\n score,\n riskPct,\n class: p.class ?? null,\n band: bandKey,\n status,\n badgeColor,\n icon,\n drivers: ParseRowDrivers(p.drivers),\n });\n }\n return rows.sort((a, b) => b.riskPct - a.riskPct);\n}\n\n/** @deprecated Use {@link ParseAtRiskRows}. */\nexport function parseAtRiskRows(details: RunDetailLike[], options?: ParseAtRiskOptions): AtRiskRow[] {\n return ParseAtRiskRows(details, options);\n}\n\n/**\n * The top plain-language drivers for the whole prediction, from the model's global feature importance.\n * Accepts the object form (`{\"MembershipType=Student\": 0.9, ...}`) or the array form\n * (`[{feature, importance}]`), strips one-hot `=value` suffixes, de-duplicates, and returns the\n * highest-importance feature names — so a business user sees \"what's driving this\", not raw weights.\n */\nexport function TopGlobalDrivers(featureImportanceJson: string | null | undefined, n = 3): string[] {\n if (!featureImportanceJson) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(featureImportanceJson);\n } catch {\n return [];\n }\n const pairs: Array<{ name: string; weight: number }> = [];\n if (Array.isArray(parsed)) {\n for (const e of parsed as Array<Record<string, unknown>>) {\n const name = (e.feature ?? e.name) as string | undefined;\n const weight = (e.importance ?? e.value) as number | undefined;\n if (typeof name === 'string' && typeof weight === 'number') pairs.push({ name, weight: Math.abs(weight) });\n }\n } else if (parsed && typeof parsed === 'object') {\n for (const [name, weight] of Object.entries(parsed as Record<string, unknown>)) {\n if (typeof weight === 'number') pairs.push({ name, weight: Math.abs(weight) });\n }\n }\n // Collapse one-hot columns (\"Feature=Value\" → \"Feature\"), keeping each feature's max weight.\n const byFeature = new Map<string, number>();\n for (const { name, weight } of pairs) {\n const base = name.split('=')[0].trim();\n if (!base) continue;\n byFeature.set(base, Math.max(byFeature.get(base) ?? 0, weight));\n }\n return [...byFeature.entries()].sort((a, b) => b[1] - a[1]).slice(0, n).map(([name]) => HumanizeFeatureName(name));\n}\n\n/** @deprecated Use {@link TopGlobalDrivers}. */\nexport function topGlobalDrivers(featureImportanceJson: string | null | undefined, n = 3): string[] {\n return TopGlobalDrivers(featureImportanceJson, n);\n}\n\n/**\n * Turn a raw feature/column name into a readable label — `RetentionOverdueInvoices` → `Retention Overdue\n * Invoices`, `overdue_invoices` → `Overdue Invoices`, and a one-hot `MembershipType=Student` →\n * `Membership Type = Student`. Splits camelCase + snake/kebab, spaces one-hot `=`, collapses whitespace,\n * and capitalizes the first letter. Already-spaced labels pass through unchanged.\n */\nexport function HumanizeFeatureName(name: string): string {\n return name\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/\\s*=\\s*/g, ' = ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/^\\w/, (c) => c.toUpperCase());\n}\n\n/** @deprecated Use {@link HumanizeFeatureName}. */\nexport function humanizeFeatureName(name: string): string {\n return HumanizeFeatureName(name);\n}\n"]}