@memberjunction/ng-dashboards 5.38.0 → 5.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/README.md +14 -7
  2. package/dist/AI/components/agents/agent-configuration.component.js +199 -198
  3. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  4. package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts.map +1 -1
  5. package/dist/AI/components/analytics/ai-analytics-resource.component.js +20 -17
  6. package/dist/AI/components/analytics/ai-analytics-resource.component.js.map +1 -1
  7. package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts +15 -0
  8. package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts.map +1 -1
  9. package/dist/AI/components/analytics/cost-budget/cost-budget.component.js +166 -58
  10. package/dist/AI/components/analytics/cost-budget/cost-budget.component.js.map +1 -1
  11. package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts.map +1 -1
  12. package/dist/AI/components/analytics/executive-summary/executive-summary.component.js +2 -1
  13. package/dist/AI/components/analytics/executive-summary/executive-summary.component.js.map +1 -1
  14. package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts +1 -0
  15. package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts.map +1 -1
  16. package/dist/AI/components/analytics/model-performance/model-performance.component.js +55 -36
  17. package/dist/AI/components/analytics/model-performance/model-performance.component.js.map +1 -1
  18. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts +9 -1
  19. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts.map +1 -1
  20. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js +158 -117
  21. package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js.map +1 -1
  22. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts +1 -0
  23. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts.map +1 -1
  24. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js +22 -8
  25. package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js.map +1 -1
  26. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +217 -860
  27. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  28. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +1717 -7802
  29. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  30. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts +56 -0
  31. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts.map +1 -0
  32. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js +423 -0
  33. package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js.map +1 -0
  34. package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts +70 -0
  35. package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts.map +1 -0
  36. package/dist/AI/components/autotagging/components/classify-item-grid.component.js +308 -0
  37. package/dist/AI/components/autotagging/components/classify-item-grid.component.js.map +1 -0
  38. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts +29 -0
  39. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts.map +1 -0
  40. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js +186 -0
  41. package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js.map +1 -0
  42. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts +69 -0
  43. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts.map +1 -0
  44. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js +278 -0
  45. package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js.map +1 -0
  46. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts +73 -0
  47. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts.map +1 -0
  48. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js +393 -0
  49. package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js.map +1 -0
  50. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts +122 -0
  51. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts.map +1 -0
  52. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js +908 -0
  53. package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js.map +1 -0
  54. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts +87 -0
  55. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts.map +1 -0
  56. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js +475 -0
  57. package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js.map +1 -0
  58. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts +29 -0
  59. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts.map +1 -0
  60. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js +208 -0
  61. package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js.map +1 -0
  62. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts +21 -0
  63. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts.map +1 -0
  64. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js +70 -0
  65. package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js.map +1 -0
  66. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +333 -0
  67. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -0
  68. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +2125 -0
  69. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -0
  70. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts +61 -0
  71. package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts.map +1 -0
  72. package/dist/AI/components/autotagging/shared/classify.dryrun.js +78 -0
  73. package/dist/AI/components/autotagging/shared/classify.dryrun.js.map +1 -0
  74. package/dist/AI/components/autotagging/shared/classify.format.d.ts +58 -0
  75. package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -0
  76. package/dist/AI/components/autotagging/shared/classify.format.js +260 -0
  77. package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -0
  78. package/dist/AI/components/autotagging/shared/classify.types.d.ts +319 -0
  79. package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -0
  80. package/dist/AI/components/autotagging/shared/classify.types.js +6 -0
  81. package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -0
  82. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts +103 -0
  83. package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts.map +1 -0
  84. package/dist/AI/components/autotagging/tabs/health-tab.component.js +571 -0
  85. package/dist/AI/components/autotagging/tabs/health-tab.component.js.map +1 -0
  86. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +77 -0
  87. package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -0
  88. package/dist/AI/components/autotagging/tabs/history-tab.component.js +519 -0
  89. package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -0
  90. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts +107 -0
  91. package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts.map +1 -0
  92. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js +719 -0
  93. package/dist/AI/components/autotagging/tabs/inbox-tab.component.js.map +1 -0
  94. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +131 -0
  95. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -0
  96. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +813 -0
  97. package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -0
  98. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +177 -0
  99. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -0
  100. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1465 -0
  101. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -0
  102. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +78 -0
  103. package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -0
  104. package/dist/AI/components/autotagging/tabs/tags-tab.component.js +492 -0
  105. package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -0
  106. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts +397 -0
  107. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts.map +1 -0
  108. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js +3490 -0
  109. package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js.map +1 -0
  110. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +56 -0
  111. package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -0
  112. package/dist/AI/components/autotagging/tabs/types-tab.component.js +271 -0
  113. package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -0
  114. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +3 -0
  115. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  116. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +306 -290
  117. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  118. package/dist/AI/components/execution-monitoring.component.js +1 -1
  119. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  120. package/dist/AI/components/models/model-management.component.js +209 -208
  121. package/dist/AI/components/models/model-management.component.js.map +1 -1
  122. package/dist/AI/components/prompts/prompt-management.component.js +130 -128
  123. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  124. package/dist/AI/components/requests/agent-requests-resource.component.js +61 -61
  125. package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
  126. package/dist/AI/components/system/system-configuration.component.js +17 -17
  127. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  128. package/dist/AI/components/tags/tags-resource.component.d.ts +1 -0
  129. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  130. package/dist/AI/components/tags/tags-resource.component.js +578 -538
  131. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  132. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +3 -0
  133. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  134. package/dist/AI/components/vectors/vector-management-resource.component.js +331 -303
  135. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  136. package/dist/AI/services/ai-instrumentation.service.d.ts +5 -0
  137. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  138. package/dist/AI/services/ai-instrumentation.service.js +14 -2
  139. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  140. package/dist/AI/services/cache-metrics.d.ts +50 -0
  141. package/dist/AI/services/cache-metrics.d.ts.map +1 -0
  142. package/dist/AI/services/cache-metrics.js +43 -0
  143. package/dist/AI/services/cache-metrics.js.map +1 -0
  144. package/dist/APIKeys/api-applications-panel.component.js +2 -2
  145. package/dist/APIKeys/api-key-create-dialog.component.js +2 -2
  146. package/dist/APIKeys/api-key-edit-panel.component.js +2 -2
  147. package/dist/APIKeys/api-keys-resource.component.js +132 -131
  148. package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
  149. package/dist/Actions/components/actions-overview.component.js +141 -141
  150. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  151. package/dist/Actions/components/execution-monitoring.component.js +15 -15
  152. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  153. package/dist/Actions/components/explorer/action-explorer.component.d.ts +0 -5
  154. package/dist/Actions/components/explorer/action-explorer.component.d.ts.map +1 -1
  155. package/dist/Actions/components/explorer/action-explorer.component.js +139 -212
  156. package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
  157. package/dist/Admin/admin-data-schema.component.js +2 -2
  158. package/dist/Admin/admin-data-schema.component.js.map +1 -1
  159. package/dist/Admin/admin-dev-tools-resource.component.js +2 -2
  160. package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
  161. package/dist/Admin/admin-identity-access.component.js +2 -2
  162. package/dist/Admin/admin-identity-access.component.js.map +1 -1
  163. package/dist/Admin/admin-monitoring.component.js +2 -2
  164. package/dist/Admin/admin-monitoring.component.js.map +1 -1
  165. package/dist/ApplicationRoles/application-roles-resource.component.js +54 -49
  166. package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
  167. package/dist/Communication/communication-logs-resource.component.d.ts +6 -0
  168. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  169. package/dist/Communication/communication-logs-resource.component.js +72 -50
  170. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  171. package/dist/Communication/communication-monitor-resource.component.js +103 -102
  172. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  173. package/dist/Communication/communication-providers-resource.component.js +52 -51
  174. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  175. package/dist/Communication/communication-runs-resource.component.js +39 -38
  176. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  177. package/dist/Communication/communication-templates-resource.component.d.ts +6 -0
  178. package/dist/Communication/communication-templates-resource.component.d.ts.map +1 -1
  179. package/dist/Communication/communication-templates-resource.component.js +92 -89
  180. package/dist/Communication/communication-templates-resource.component.js.map +1 -1
  181. package/dist/Credentials/components/credentials-audit-resource.component.js +136 -135
  182. package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
  183. package/dist/Credentials/components/credentials-categories-resource.component.js +155 -152
  184. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  185. package/dist/Credentials/components/credentials-list-resource.component.js +119 -118
  186. package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
  187. package/dist/Credentials/components/credentials-overview-resource.component.js +129 -128
  188. package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
  189. package/dist/Credentials/components/credentials-types-resource.component.js +107 -106
  190. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  191. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +31 -340
  192. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  193. package/dist/DataExplorer/data-explorer-dashboard.component.js +468 -1958
  194. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  195. package/dist/DataExplorer/data-explorer-resource.component.d.ts.map +1 -1
  196. package/dist/DataExplorer/data-explorer-resource.component.js +10 -0
  197. package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
  198. package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +1 -1
  199. package/dist/DatabaseDesigner/components/entity-list.component.js +115 -114
  200. package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -1
  201. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +5 -6
  202. package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -1
  203. package/dist/DatabaseDesigner/database-designer-dashboards.module.js +4 -5
  204. package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -1
  205. package/dist/DevTools/app-state-inspector.component.js +18 -17
  206. package/dist/DevTools/app-state-inspector.component.js.map +1 -1
  207. package/dist/DevTools/class-registry.component.js +88 -85
  208. package/dist/DevTools/class-registry.component.js.map +1 -1
  209. package/dist/DevTools/event-monitor.component.js +155 -150
  210. package/dist/DevTools/event-monitor.component.js.map +1 -1
  211. package/dist/DevTools/graphql-console.component.js +245 -243
  212. package/dist/DevTools/graphql-console.component.js.map +1 -1
  213. package/dist/DevTools/layout-inspector.component.js +18 -17
  214. package/dist/DevTools/layout-inspector.component.js.map +1 -1
  215. package/dist/EntityAdmin/entity-admin-dashboard.component.js +20 -19
  216. package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
  217. package/dist/Home/home-dashboard.component.js +2 -2
  218. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
  219. package/dist/Integration/components/activity/activity.component.js +236 -229
  220. package/dist/Integration/components/activity/activity.component.js.map +1 -1
  221. package/dist/Integration/components/connections/connections.component.js +390 -389
  222. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  223. package/dist/Integration/components/overview/overview.component.js +2 -2
  224. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -1
  225. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +14 -11
  226. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
  227. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +27 -2
  228. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
  229. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +244 -119
  230. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
  231. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +293 -291
  232. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  233. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +62 -61
  234. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
  235. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts +65 -0
  236. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts.map +1 -0
  237. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js +176 -0
  238. package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js.map +1 -0
  239. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts +81 -0
  240. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts.map +1 -0
  241. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js +308 -0
  242. package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js.map +1 -0
  243. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts +85 -0
  244. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts.map +1 -0
  245. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js +362 -0
  246. package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js.map +1 -0
  247. package/dist/KnowledgeHub/index.d.ts +3 -0
  248. package/dist/KnowledgeHub/index.d.ts.map +1 -1
  249. package/dist/KnowledgeHub/index.js +3 -0
  250. package/dist/KnowledgeHub/index.js.map +1 -1
  251. package/dist/Lists/components/lists-browse-resource.component.d.ts +6 -2
  252. package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
  253. package/dist/Lists/components/lists-browse-resource.component.js +525 -566
  254. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  255. package/dist/Lists/components/lists-categories-resource.component.js +135 -134
  256. package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
  257. package/dist/Lists/components/lists-my-lists-resource.component.js +199 -198
  258. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  259. package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
  260. package/dist/MCP/mcp-dashboard.component.js +443 -438
  261. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  262. package/dist/QueryBrowser/query-browser-resource.component.js +1 -1
  263. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  264. package/dist/Scheduling/components/scheduling-activity.component.d.ts.map +1 -1
  265. package/dist/Scheduling/components/scheduling-activity.component.js +146 -147
  266. package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
  267. package/dist/Scheduling/components/scheduling-jobs.component.js +76 -75
  268. package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
  269. package/dist/Scheduling/components/scheduling-overview.component.js +97 -96
  270. package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
  271. package/dist/Scheduling/scheduling-dashboard.component.js +24 -22
  272. package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
  273. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts +2 -0
  274. package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts.map +1 -1
  275. package/dist/Scheduling/services/scheduling-instrumentation.service.js +1 -0
  276. package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
  277. package/dist/Testing/components/testing-dashboard-tab-resource.component.js +1 -1
  278. package/dist/Testing/components/testing-explorer.component.d.ts +14 -4
  279. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  280. package/dist/Testing/components/testing-explorer.component.js +436 -427
  281. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  282. package/dist/Testing/components/testing-runs-resource.component.js +1 -1
  283. package/dist/Testing/components/testing-runs.component.js +116 -115
  284. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  285. package/dist/Testing/testing-dashboard.component.js +6 -7
  286. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  287. package/dist/VersionHistory/components/labels-resource.component.js +173 -172
  288. package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
  289. package/dist/VersionHistory/components/restore-resource.component.d.ts +6 -0
  290. package/dist/VersionHistory/components/restore-resource.component.d.ts.map +1 -1
  291. package/dist/VersionHistory/components/restore-resource.component.js +116 -92
  292. package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
  293. package/dist/ai-dashboards.module.d.ts +57 -35
  294. package/dist/ai-dashboards.module.d.ts.map +1 -1
  295. package/dist/ai-dashboards.module.js +80 -1
  296. package/dist/ai-dashboards.module.js.map +1 -1
  297. package/dist/communication-dashboards.module.d.ts +1 -1
  298. package/dist/communication-dashboards.module.d.ts.map +1 -1
  299. package/dist/communication-dashboards.module.js +7 -1
  300. package/dist/communication-dashboards.module.js.map +1 -1
  301. package/dist/data-explorer-dashboards.module.d.ts +12 -14
  302. package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
  303. package/dist/data-explorer-dashboards.module.js +5 -14
  304. package/dist/data-explorer-dashboards.module.js.map +1 -1
  305. package/dist/public-api.d.ts +3 -0
  306. package/dist/public-api.d.ts.map +1 -1
  307. package/dist/public-api.js +3 -0
  308. package/dist/public-api.js.map +1 -1
  309. package/dist/testing-dashboards.module.d.ts +4 -5
  310. package/dist/testing-dashboards.module.d.ts.map +1 -1
  311. package/dist/testing-dashboards.module.js +7 -5
  312. package/dist/testing-dashboards.module.js.map +1 -1
  313. package/package.json +57 -54
  314. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts +0 -79
  315. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts.map +0 -1
  316. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +0 -195
  317. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js.map +0 -1
  318. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts +0 -226
  319. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +0 -1
  320. package/dist/DataExplorer/components/view-selector/view-selector.component.js +0 -861
  321. package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +0 -1
@@ -13,32 +13,25 @@ import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
13
13
  import { RunView, EntityFieldTSType } from '@memberjunction/core';
14
14
  // CompositeKey is used via buildCompositeKey from ng-entity-viewer
15
15
  import { UserInfoEngine } from '@memberjunction/core-entities';
16
- import { EntityViewerComponent, ViewConfigPanelComponent, buildCompositeKey, buildPkString } from '@memberjunction/ng-entity-viewer';
17
- import { ViewSelectorComponent } from './components/view-selector/view-selector.component';
18
- import { createEmptyFilter } from '@memberjunction/ng-filter-builder';
16
+ import { ViewWorkspaceComponent, buildCompositeKey, buildPkString } from '@memberjunction/ng-entity-viewer';
19
17
  import { UserViewEngine } from '@memberjunction/core-entities';
20
18
  import { MJEventType, MJGlobal } from '@memberjunction/global';
21
19
  import * as i0 from "@angular/core";
22
20
  import * as i1 from "./services/explorer-state.service";
23
21
  import * as i2 from "@memberjunction/ng-shared-generic";
24
- import * as i3 from "@memberjunction/ng-export-service";
25
- import * as i4 from "@angular/forms";
26
- import * as i5 from "@memberjunction/ng-entity-viewer";
27
- import * as i6 from "@memberjunction/ng-list-management";
28
- import * as i7 from "./components/navigation-panel/navigation-panel.component";
29
- import * as i8 from "./components/view-selector/view-selector.component";
30
- import * as i9 from "./components/filter-dialog/filter-dialog.component";
31
- import * as i10 from "@angular/common";
22
+ import * as i3 from "@angular/forms";
23
+ import * as i4 from "@memberjunction/ng-entity-viewer";
24
+ import * as i5 from "./components/navigation-panel/navigation-panel.component";
25
+ import * as i6 from "@angular/common";
32
26
  const _c0 = ["filterInput"];
33
27
  const _forTrack0 = ($index, $item) => $item.label;
34
- const _forTrack1 = ($index, $item) => $item.name;
35
- const _forTrack2 = ($index, $item) => $item.entityId + "|" + $item.recordId;
36
- const _forTrack3 = ($index, $item) => $item.ID;
37
- const _forTrack4 = ($index, $item) => $item.userFavoriteId;
38
- const _forTrack5 = ($index, $item) => $item.applicationId;
28
+ const _forTrack1 = ($index, $item) => $item.entityId + "|" + $item.recordId;
29
+ const _forTrack2 = ($index, $item) => $item.ID;
30
+ const _forTrack3 = ($index, $item) => $item.userFavoriteId;
31
+ const _forTrack4 = ($index, $item) => $item.applicationId;
39
32
  function DataExplorerDashboardComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
40
33
  const _r1 = i0.ɵɵgetCurrentView();
41
- i0.ɵɵelementStart(0, "div", 23)(1, "mj-explorer-navigation-panel", 24);
34
+ i0.ɵɵelementStart(0, "div", 15)(1, "mj-explorer-navigation-panel", 16);
42
35
  i0.ɵɵlistener("entitySelected", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_entitySelected_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntitySelected($event)); })("toggleCollapse", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_toggleCollapse_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleNavigationPanel()); })("sectionToggled", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_sectionToggled_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.stateService.toggleSection($event)); })("openRecord", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_openRecord_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRecordFromNav($event)); })("selectRecord", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_selectRecord_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSelectRecordFromNav($event)); })("expandAndFocus", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_expandAndFocus_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onExpandAndFocus($event)); });
43
36
  i0.ɵɵelementEnd()();
44
37
  } if (rf & 2) {
@@ -50,23 +43,23 @@ function DataExplorerDashboardComponent_Conditional_1_Template(rf, ctx) { if (rf
50
43
  i0.ɵɵproperty("entities", ctx_r1.entities)("appEntityGroups", ctx_r1.appEntityGroups)("selectedEntityName", ctx_r1.state.selectedEntityName)("favorites", ctx_r1.state.favorites)("recentItems", ctx_r1.state.recentItems)("collapsed", ctx_r1.state.navigationPanelCollapsed)("allowedEntityNames", ctx_r1.allowedEntityNames)("favoritesSectionExpanded", ctx_r1.state.favoritesSectionExpanded)("recentSectionExpanded", ctx_r1.state.recentSectionExpanded)("entitiesSectionExpanded", ctx_r1.state.entitiesSectionExpanded)("viewsSectionExpanded", ctx_r1.state.viewsSectionExpanded);
51
44
  } }
52
45
  function DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
53
- i0.ɵɵelement(0, "i", 29);
46
+ i0.ɵɵelement(0, "i", 21);
54
47
  } if (rf & 2) {
55
48
  const crumb_r5 = i0.ɵɵnextContext().$implicit;
56
49
  i0.ɵɵclassMap(crumb_r5.icon);
57
50
  } }
58
51
  function DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
59
- i0.ɵɵelement(0, "i", 28);
52
+ i0.ɵɵelement(0, "i", 20);
60
53
  } }
61
54
  function DataExplorerDashboardComponent_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
62
55
  const _r3 = i0.ɵɵgetCurrentView();
63
- i0.ɵɵelementStart(0, "span", 25);
56
+ i0.ɵɵelementStart(0, "span", 17);
64
57
  i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_3_For_2_Template_span_click_0_listener() { const ctx_r3 = i0.ɵɵrestoreView(_r3); const crumb_r5 = ctx_r3.$implicit; const ɵ$index_13_r6 = ctx_r3.$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onBreadcrumbClick(crumb_r5, ɵ$index_13_r6)); });
65
- i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_1_Template, 1, 2, "i", 26);
66
- i0.ɵɵelementStart(2, "span", 27);
58
+ i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_1_Template, 1, 2, "i", 18);
59
+ i0.ɵɵelementStart(2, "span", 19);
67
60
  i0.ɵɵtext(3);
68
61
  i0.ɵɵelementEnd()();
69
- i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_4_Template, 1, 0, "i", 28);
62
+ i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_4_Template, 1, 0, "i", 20);
70
63
  } if (rf & 2) {
71
64
  const crumb_r5 = ctx.$implicit;
72
65
  const ɵ$index_13_r6 = ctx.$index;
@@ -81,7 +74,7 @@ function DataExplorerDashboardComponent_Conditional_3_For_2_Template(rf, ctx) {
81
74
  i0.ɵɵconditional(!(ɵ$index_13_r6 === ɵ$count_13_r7 - 1) ? 4 : -1);
82
75
  } }
83
76
  function DataExplorerDashboardComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
84
- i0.ɵɵelementStart(0, "div", 5);
77
+ i0.ɵɵelementStart(0, "div", 4);
85
78
  i0.ɵɵrepeaterCreate(1, DataExplorerDashboardComponent_Conditional_3_For_2_Template, 5, 8, null, null, _forTrack0);
86
79
  i0.ɵɵelementEnd();
87
80
  } if (rf & 2) {
@@ -90,7 +83,7 @@ function DataExplorerDashboardComponent_Conditional_3_Template(rf, ctx) { if (rf
90
83
  i0.ɵɵrepeater(ctx_r1.breadcrumbs);
91
84
  } }
92
85
  function DataExplorerDashboardComponent_Conditional_6_Conditional_3_Template(rf, ctx) { if (rf & 1) {
93
- i0.ɵɵelementStart(0, "span", 32);
86
+ i0.ɵɵelementStart(0, "span", 24);
94
87
  i0.ɵɵtext(1);
95
88
  i0.ɵɵpipe(2, "number");
96
89
  i0.ɵɵpipe(3, "number");
@@ -101,7 +94,7 @@ function DataExplorerDashboardComponent_Conditional_6_Conditional_3_Template(rf,
101
94
  i0.ɵɵtextInterpolate2("", i0.ɵɵpipeBind1(2, 2, ctx_r1.filteredRecordCount), " of ", i0.ɵɵpipeBind1(3, 4, ctx_r1.totalRecordCount), " records");
102
95
  } }
103
96
  function DataExplorerDashboardComponent_Conditional_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
104
- i0.ɵɵelementStart(0, "span", 32);
97
+ i0.ɵɵelementStart(0, "span", 24);
105
98
  i0.ɵɵtext(1);
106
99
  i0.ɵɵpipe(2, "number");
107
100
  i0.ɵɵelementEnd();
@@ -110,30 +103,12 @@ function DataExplorerDashboardComponent_Conditional_6_Conditional_4_Template(rf,
110
103
  i0.ɵɵadvance();
111
104
  i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind1(2, 1, ctx_r1.totalRecordCount), " records");
112
105
  } }
113
- function DataExplorerDashboardComponent_Conditional_6_Conditional_8_Template(rf, ctx) { if (rf & 1) {
114
- i0.ɵɵelementStart(0, "span", 36);
115
- i0.ɵɵtext(1);
116
- i0.ɵɵelementEnd();
117
- } if (rf & 2) {
118
- const ctx_r1 = i0.ɵɵnextContext(2);
119
- i0.ɵɵadvance();
120
- i0.ɵɵtextInterpolate(ctx_r1.selectedRecords.length);
121
- } }
122
106
  function DataExplorerDashboardComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
123
- const _r8 = i0.ɵɵgetCurrentView();
124
- i0.ɵɵelement(0, "i", 30);
125
- i0.ɵɵelementStart(1, "h2", 31);
107
+ i0.ɵɵelement(0, "i", 22);
108
+ i0.ɵɵelementStart(1, "h2", 23);
126
109
  i0.ɵɵtext(2);
127
110
  i0.ɵɵelementEnd();
128
- i0.ɵɵconditionalCreate(3, DataExplorerDashboardComponent_Conditional_6_Conditional_3_Template, 4, 6, "span", 32)(4, DataExplorerDashboardComponent_Conditional_6_Conditional_4_Template, 3, 3, "span", 32);
129
- i0.ɵɵelementStart(5, "mj-view-selector", 33);
130
- i0.ɵɵlistener("viewSelected", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_viewSelected_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewSelected($event)); })("saveViewRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_saveViewRequested_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSaveViewRequested($event)); })("manageViewsRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_manageViewsRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onManageViewsRequested()); })("openInTabRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_openInTabRequested_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenInTabRequested($event)); })("configureViewRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_configureViewRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onConfigureViewRequested()); })("createNewRecordRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_createNewRecordRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCreateNewRecord()); })("exportRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_exportRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onExport()); })("duplicateViewRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_duplicateViewRequested_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDuplicateView($event)); })("quickSaveRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_quickSaveRequested_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onQuickSaveRequested($event)); })("revertRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_revertRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRevertView()); });
131
- i0.ɵɵelementEnd();
132
- i0.ɵɵelementStart(6, "button", 34);
133
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_6_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onAddToListClick()); });
134
- i0.ɵɵelement(7, "i", 35);
135
- i0.ɵɵconditionalCreate(8, DataExplorerDashboardComponent_Conditional_6_Conditional_8_Template, 2, 1, "span", 36);
136
- i0.ɵɵelementEnd();
111
+ i0.ɵɵconditionalCreate(3, DataExplorerDashboardComponent_Conditional_6_Conditional_3_Template, 4, 6, "span", 24)(4, DataExplorerDashboardComponent_Conditional_6_Conditional_4_Template, 3, 3, "span", 24);
137
112
  } if (rf & 2) {
138
113
  const ctx_r1 = i0.ɵɵnextContext();
139
114
  i0.ɵɵclassMap(ctx_r1.getEntityIcon(ctx_r1.selectedEntity));
@@ -141,26 +116,19 @@ function DataExplorerDashboardComponent_Conditional_6_Template(rf, ctx) { if (rf
141
116
  i0.ɵɵtextInterpolate(ctx_r1.selectedEntity.DisplayNameOrName);
142
117
  i0.ɵɵadvance();
143
118
  i0.ɵɵconditional(ctx_r1.debouncedFilterText && ctx_r1.filteredRecordCount !== ctx_r1.totalRecordCount ? 3 : 4);
144
- i0.ɵɵadvance(2);
145
- i0.ɵɵproperty("entity", ctx_r1.selectedEntity)("selectedViewId", ctx_r1.state.selectedViewId)("viewModified", ctx_r1.state.viewModified);
146
- i0.ɵɵadvance();
147
- i0.ɵɵclassProp("disabled", !ctx_r1.hasSelectedRecords);
148
- i0.ɵɵproperty("disabled", !ctx_r1.hasSelectedRecords)("title", ctx_r1.hasSelectedRecords ? "Add " + ctx_r1.selectedRecords.length + " selected record(s) to a list" : "Select records to add to a list");
149
- i0.ɵɵadvance(2);
150
- i0.ɵɵconditional(ctx_r1.hasSelectedRecords ? 8 : -1);
151
119
  } }
152
120
  function DataExplorerDashboardComponent_Conditional_7_Conditional_0_Template(rf, ctx) { if (rf & 1) {
153
- i0.ɵɵelement(0, "i", 30);
121
+ i0.ɵɵelement(0, "i", 22);
154
122
  } if (rf & 2) {
155
123
  const ctx_r1 = i0.ɵɵnextContext(2);
156
124
  i0.ɵɵclassMap(ctx_r1.displayIcon);
157
125
  } }
158
126
  function DataExplorerDashboardComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
159
- i0.ɵɵconditionalCreate(0, DataExplorerDashboardComponent_Conditional_7_Conditional_0_Template, 1, 2, "i", 37);
160
- i0.ɵɵelementStart(1, "h2", 31);
127
+ i0.ɵɵconditionalCreate(0, DataExplorerDashboardComponent_Conditional_7_Conditional_0_Template, 1, 2, "i", 25);
128
+ i0.ɵɵelementStart(1, "h2", 23);
161
129
  i0.ɵɵtext(2);
162
130
  i0.ɵɵelementEnd();
163
- i0.ɵɵelementStart(3, "span", 32);
131
+ i0.ɵɵelementStart(3, "span", 24);
164
132
  i0.ɵɵtext(4);
165
133
  i0.ɵɵelementEnd();
166
134
  } if (rf & 2) {
@@ -172,20 +140,20 @@ function DataExplorerDashboardComponent_Conditional_7_Template(rf, ctx) { if (rf
172
140
  i0.ɵɵtextInterpolate1("", ctx_r1.entities.length, " entities available");
173
141
  } }
174
142
  function DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template(rf, ctx) { if (rf & 1) {
175
- const _r11 = i0.ɵɵgetCurrentView();
176
- i0.ɵɵelementStart(0, "button", 41);
177
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearRecordFilter()); });
178
- i0.ɵɵelement(1, "i", 42);
143
+ const _r10 = i0.ɵɵgetCurrentView();
144
+ i0.ɵɵelementStart(0, "button", 29);
145
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearRecordFilter()); });
146
+ i0.ɵɵelement(1, "i", 30);
179
147
  i0.ɵɵelementEnd();
180
148
  } }
181
149
  function DataExplorerDashboardComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
182
- const _r9 = i0.ɵɵgetCurrentView();
183
- i0.ɵɵelementStart(0, "div", 9);
184
- i0.ɵɵelement(1, "i", 38);
185
- i0.ɵɵelementStart(2, "input", 39, 0);
186
- i0.ɵɵlistener("input", function DataExplorerDashboardComponent_Conditional_9_Template_input_input_2_listener() { i0.ɵɵrestoreView(_r9); const filterInput_r10 = i0.ɵɵreference(3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterInputChanged(filterInput_r10.value)); });
150
+ const _r8 = i0.ɵɵgetCurrentView();
151
+ i0.ɵɵelementStart(0, "div", 8);
152
+ i0.ɵɵelement(1, "i", 26);
153
+ i0.ɵɵelementStart(2, "input", 27, 0);
154
+ i0.ɵɵlistener("input", function DataExplorerDashboardComponent_Conditional_9_Template_input_input_2_listener() { i0.ɵɵrestoreView(_r8); const filterInput_r9 = i0.ɵɵreference(3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterInputChanged(filterInput_r9.value)); });
187
155
  i0.ɵɵelementEnd();
188
- i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template, 2, 0, "button", 40);
156
+ i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template, 2, 0, "button", 28);
189
157
  i0.ɵɵelementEnd();
190
158
  } if (rf & 2) {
191
159
  const ctx_r1 = i0.ɵɵnextContext();
@@ -194,141 +162,9 @@ function DataExplorerDashboardComponent_Conditional_9_Template(rf, ctx) { if (rf
194
162
  i0.ɵɵadvance(2);
195
163
  i0.ɵɵconditional(ctx_r1.liveFilterText ? 4 : -1);
196
164
  } }
197
- function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_2_Template(rf, ctx) { if (rf & 1) {
198
- const _r14 = i0.ɵɵgetCurrentView();
199
- i0.ɵɵelementStart(0, "div", 60);
200
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_2_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.closeDateFieldDropdown()); });
201
- i0.ɵɵelementEnd();
202
- } }
203
- function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
204
- i0.ɵɵelement(0, "i", 61);
205
- } if (rf & 2) {
206
- const ctx_r1 = i0.ɵɵnextContext(3);
207
- i0.ɵɵclassProp("rotated", ctx_r1.isDateFieldDropdownOpen);
208
- } }
209
- function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
210
- i0.ɵɵelement(0, "i", 66);
211
- } }
212
- function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Template(rf, ctx) { if (rf & 1) {
213
- const _r15 = i0.ɵɵgetCurrentView();
214
- i0.ɵɵelementStart(0, "div", 63);
215
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Template_div_click_0_listener() { const field_r16 = i0.ɵɵrestoreView(_r15).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.setTimelineDateField(field_r16.name)); });
216
- i0.ɵɵelement(1, "i", 64);
217
- i0.ɵɵelementStart(2, "span", 65);
218
- i0.ɵɵtext(3);
219
- i0.ɵɵelementEnd();
220
- i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Conditional_4_Template, 1, 0, "i", 66);
221
- i0.ɵɵelementEnd();
222
- } if (rf & 2) {
223
- const field_r16 = ctx.$implicit;
224
- const ctx_r1 = i0.ɵɵnextContext(4);
225
- i0.ɵɵclassProp("selected", field_r16.name === ctx_r1.effectiveTimelineDateField);
226
- i0.ɵɵadvance(3);
227
- i0.ɵɵtextInterpolate(field_r16.displayName);
228
- i0.ɵɵadvance();
229
- i0.ɵɵconditional(field_r16.name === ctx_r1.effectiveTimelineDateField ? 4 : -1);
230
- } }
231
- function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_Template(rf, ctx) { if (rf & 1) {
232
- i0.ɵɵelementStart(0, "div", 58);
233
- i0.ɵɵrepeaterCreate(1, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Template, 5, 4, "div", 62, _forTrack1);
234
- i0.ɵɵelementEnd();
235
- } if (rf & 2) {
236
- const ctx_r1 = i0.ɵɵnextContext(3);
237
- i0.ɵɵadvance();
238
- i0.ɵɵrepeater(ctx_r1.availableDateFields);
239
- } }
240
- function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template(rf, ctx) { if (rf & 1) {
241
- const _r13 = i0.ɵɵgetCurrentView();
242
- i0.ɵɵelementStart(0, "div", 43)(1, "div", 51);
243
- i0.ɵɵconditionalCreate(2, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_2_Template, 1, 0, "div", 52);
244
- i0.ɵɵelementStart(3, "div", 53)(4, "button", 54);
245
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleDateFieldDropdown()); });
246
- i0.ɵɵelement(5, "i", 55);
247
- i0.ɵɵelementStart(6, "span", 56);
248
- i0.ɵɵtext(7);
249
- i0.ɵɵelementEnd();
250
- i0.ɵɵconditionalCreate(8, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_8_Template, 1, 2, "i", 57);
251
- i0.ɵɵelementEnd();
252
- i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_Template, 3, 0, "div", 58);
253
- i0.ɵɵelementEnd()();
254
- i0.ɵɵelementStart(10, "button", 59);
255
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleTimelineOrientation()); });
256
- i0.ɵɵelement(11, "i");
257
- i0.ɵɵelementEnd();
258
- i0.ɵɵelementStart(12, "button", 59);
259
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleTimelineSortOrder()); });
260
- i0.ɵɵelement(13, "i");
261
- i0.ɵɵelementEnd()();
262
- } if (rf & 2) {
263
- const ctx_r1 = i0.ɵɵnextContext(2);
264
- i0.ɵɵadvance(2);
265
- i0.ɵɵconditional(ctx_r1.isDateFieldDropdownOpen ? 2 : -1);
266
- i0.ɵɵadvance(2);
267
- i0.ɵɵclassProp("open", ctx_r1.isDateFieldDropdownOpen);
268
- i0.ɵɵproperty("disabled", ctx_r1.availableDateFields.length <= 1);
269
- i0.ɵɵadvance(3);
270
- i0.ɵɵtextInterpolate(ctx_r1.effectiveTimelineDateFieldDisplayName);
271
- i0.ɵɵadvance();
272
- i0.ɵɵconditional(ctx_r1.availableDateFields.length > 1 ? 8 : -1);
273
- i0.ɵɵadvance();
274
- i0.ɵɵconditional(ctx_r1.isDateFieldDropdownOpen && ctx_r1.availableDateFields.length > 1 ? 9 : -1);
275
- i0.ɵɵadvance();
276
- i0.ɵɵproperty("title", ctx_r1.state.timelineOrientation === "vertical" ? "Switch to Horizontal" : "Switch to Vertical");
277
- i0.ɵɵadvance();
278
- i0.ɵɵclassMap(ctx_r1.state.timelineOrientation === "vertical" ? "fa-solid fa-ellipsis-vertical" : "fa-solid fa-ellipsis");
279
- i0.ɵɵadvance();
280
- i0.ɵɵproperty("title", ctx_r1.state.timelineSortOrder === "desc" ? "Showing Newest First (click for Oldest First)" : "Showing Oldest First (click for Newest First)");
281
- i0.ɵɵadvance();
282
- i0.ɵɵclassMap(ctx_r1.state.timelineSortOrder === "desc" ? "fa-solid fa-arrow-down-wide-short" : "fa-solid fa-arrow-up-wide-short");
283
- } }
284
- function DataExplorerDashboardComponent_Conditional_11_Conditional_6_Template(rf, ctx) { if (rf & 1) {
285
- const _r17 = i0.ɵɵgetCurrentView();
286
- i0.ɵɵelementStart(0, "button", 67);
287
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onViewModeChanged("timeline")); });
288
- i0.ɵɵelement(1, "i", 68);
289
- i0.ɵɵelementEnd();
290
- } if (rf & 2) {
291
- const ctx_r1 = i0.ɵɵnextContext(2);
292
- i0.ɵɵclassProp("active", ctx_r1.state.viewMode === "timeline");
293
- } }
294
- function DataExplorerDashboardComponent_Conditional_11_Conditional_7_Template(rf, ctx) { if (rf & 1) {
295
- const _r18 = i0.ɵɵgetCurrentView();
296
- i0.ɵɵelementStart(0, "button", 69);
297
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_7_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onViewModeChanged("map")); });
298
- i0.ɵɵelement(1, "i", 70);
299
- i0.ɵɵelementEnd();
300
- } if (rf & 2) {
301
- const ctx_r1 = i0.ɵɵnextContext(2);
302
- i0.ɵɵclassProp("active", ctx_r1.state.viewMode === "map");
303
- } }
304
- function DataExplorerDashboardComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
305
- const _r12 = i0.ɵɵgetCurrentView();
306
- i0.ɵɵconditionalCreate(0, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template, 14, 13, "div", 43);
307
- i0.ɵɵelementStart(1, "div", 44)(2, "button", 45);
308
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewModeChanged("grid")); });
309
- i0.ɵɵelement(3, "i", 46);
310
- i0.ɵɵelementEnd();
311
- i0.ɵɵelementStart(4, "button", 47);
312
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewModeChanged("cards")); });
313
- i0.ɵɵelement(5, "i", 48);
314
- i0.ɵɵelementEnd();
315
- i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_11_Conditional_6_Template, 2, 2, "button", 49);
316
- i0.ɵɵconditionalCreate(7, DataExplorerDashboardComponent_Conditional_11_Conditional_7_Template, 2, 2, "button", 50);
317
- i0.ɵɵelementEnd();
318
- } if (rf & 2) {
319
- const ctx_r1 = i0.ɵɵnextContext();
320
- i0.ɵɵconditional(ctx_r1.state.viewMode === "timeline" && ctx_r1.entityHasDateFields ? 0 : -1);
321
- i0.ɵɵadvance(2);
322
- i0.ɵɵclassProp("active", ctx_r1.state.viewMode === "grid");
323
- i0.ɵɵadvance(2);
324
- i0.ɵɵclassProp("active", ctx_r1.state.viewMode === "cards");
325
- i0.ɵɵadvance(2);
326
- i0.ɵɵconditional(ctx_r1.entityHasDateFields ? 6 : -1);
327
- i0.ɵɵadvance();
328
- i0.ɵɵconditional(ctx_r1.selectedEntity.SupportsGeoCoding ? 7 : -1);
329
- } }
165
+ function DataExplorerDashboardComponent_Conditional_11_Template(rf, ctx) { }
330
166
  function DataExplorerDashboardComponent_Conditional_12_Conditional_2_Template(rf, ctx) { if (rf & 1) {
331
- i0.ɵɵelementStart(0, "span", 73);
167
+ i0.ɵɵelementStart(0, "span", 33);
332
168
  i0.ɵɵtext(1);
333
169
  i0.ɵɵelementEnd();
334
170
  } if (rf & 2) {
@@ -337,11 +173,11 @@ function DataExplorerDashboardComponent_Conditional_12_Conditional_2_Template(rf
337
173
  i0.ɵɵtextInterpolate(ctx_r1.recentRecords.length + ctx_r1.favoriteRecords.length);
338
174
  } }
339
175
  function DataExplorerDashboardComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
340
- const _r19 = i0.ɵɵgetCurrentView();
341
- i0.ɵɵelementStart(0, "button", 71);
342
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_12_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessPanel()); });
343
- i0.ɵɵelement(1, "i", 72);
344
- i0.ɵɵconditionalCreate(2, DataExplorerDashboardComponent_Conditional_12_Conditional_2_Template, 2, 1, "span", 73);
176
+ const _r11 = i0.ɵɵgetCurrentView();
177
+ i0.ɵɵelementStart(0, "button", 31);
178
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_12_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessPanel()); });
179
+ i0.ɵɵelement(1, "i", 32);
180
+ i0.ɵɵconditionalCreate(2, DataExplorerDashboardComponent_Conditional_12_Conditional_2_Template, 2, 1, "span", 33);
345
181
  i0.ɵɵelementEnd();
346
182
  } if (rf & 2) {
347
183
  const ctx_r1 = i0.ɵɵnextContext();
@@ -350,19 +186,19 @@ function DataExplorerDashboardComponent_Conditional_12_Template(rf, ctx) { if (r
350
186
  i0.ɵɵconditional(ctx_r1.recentRecords.length + ctx_r1.favoriteRecords.length > 0 ? 2 : -1);
351
187
  } }
352
188
  function DataExplorerDashboardComponent_Conditional_14_Conditional_1_Template(rf, ctx) { if (rf & 1) {
353
- i0.ɵɵelementStart(0, "div", 74);
354
- i0.ɵɵelement(1, "mj-loading", 75);
189
+ i0.ɵɵelementStart(0, "div", 34);
190
+ i0.ɵɵelement(1, "mj-loading", 35);
355
191
  i0.ɵɵelementEnd();
356
192
  } }
357
193
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
358
- const _r21 = i0.ɵɵgetCurrentView();
359
- i0.ɵɵelementStart(0, "button", 107);
360
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r21); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.entityFilterText = ""); });
361
- i0.ɵɵelement(1, "i", 42);
194
+ const _r13 = i0.ɵɵgetCurrentView();
195
+ i0.ɵɵelementStart(0, "button", 67);
196
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.entityFilterText = ""); });
197
+ i0.ɵɵelement(1, "i", 30);
362
198
  i0.ɵɵelementEnd();
363
199
  } }
364
200
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
365
- i0.ɵɵelementStart(0, "span", 82);
201
+ i0.ɵɵelementStart(0, "span", 42);
366
202
  i0.ɵɵtext(1, "/");
367
203
  i0.ɵɵelementEnd();
368
204
  } }
@@ -373,49 +209,49 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional
373
209
  i0.ɵɵtextInterpolate1(" across ", ctx_r1.applicationCount, " applications ");
374
210
  } }
375
211
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
376
- i0.ɵɵelementStart(0, "span", 113);
212
+ i0.ɵɵelementStart(0, "span", 73);
377
213
  i0.ɵɵtext(1);
378
214
  i0.ɵɵelementEnd();
379
215
  } if (rf & 2) {
380
- const entity_r23 = i0.ɵɵnextContext().$implicit;
216
+ const entity_r15 = i0.ɵɵnextContext().$implicit;
381
217
  i0.ɵɵadvance();
382
- i0.ɵɵtextInterpolate(entity_r23.Description);
218
+ i0.ɵɵtextInterpolate(entity_r15.Description);
383
219
  } }
384
220
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template(rf, ctx) { if (rf & 1) {
385
- const _r22 = i0.ɵɵgetCurrentView();
386
- i0.ɵɵelementStart(0, "div", 109);
387
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template_div_click_0_listener() { const entity_r23 = i0.ɵɵrestoreView(_r22).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r23)); });
388
- i0.ɵɵelementStart(1, "div", 110);
221
+ const _r14 = i0.ɵɵgetCurrentView();
222
+ i0.ɵɵelementStart(0, "div", 69);
223
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template_div_click_0_listener() { const entity_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r15)); });
224
+ i0.ɵɵelementStart(1, "div", 70);
389
225
  i0.ɵɵelement(2, "i");
390
226
  i0.ɵɵelementEnd();
391
- i0.ɵɵelementStart(3, "div", 111)(4, "span", 112);
227
+ i0.ɵɵelementStart(3, "div", 71)(4, "span", 72);
392
228
  i0.ɵɵtext(5);
393
229
  i0.ɵɵelementEnd();
394
- i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Conditional_6_Template, 2, 1, "span", 113);
230
+ i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Conditional_6_Template, 2, 1, "span", 73);
395
231
  i0.ɵɵelementEnd();
396
- i0.ɵɵelementStart(7, "button", 114);
397
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template_button_click_7_listener($event) { const entity_r23 = i0.ɵɵrestoreView(_r22).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.toggleEntityFavorite(entity_r23, $event)); });
232
+ i0.ɵɵelementStart(7, "button", 74);
233
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template_button_click_7_listener($event) { const entity_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.toggleEntityFavorite(entity_r15, $event)); });
398
234
  i0.ɵɵelement(8, "i");
399
235
  i0.ɵɵelementEnd()();
400
236
  } if (rf & 2) {
401
- const entity_r23 = ctx.$implicit;
237
+ const entity_r15 = ctx.$implicit;
402
238
  const ctx_r1 = i0.ɵɵnextContext(4);
403
- i0.ɵɵproperty("title", entity_r23.Description || entity_r23.DisplayNameOrName);
239
+ i0.ɵɵproperty("title", entity_r15.Description || entity_r15.DisplayNameOrName);
404
240
  i0.ɵɵadvance(2);
405
- i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r23));
241
+ i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r15));
406
242
  i0.ɵɵadvance(3);
407
- i0.ɵɵtextInterpolate(entity_r23.DisplayNameOrName);
243
+ i0.ɵɵtextInterpolate(entity_r15.DisplayNameOrName);
408
244
  i0.ɵɵadvance();
409
- i0.ɵɵconditional(entity_r23.Description ? 6 : -1);
245
+ i0.ɵɵconditional(entity_r15.Description ? 6 : -1);
410
246
  i0.ɵɵadvance();
411
- i0.ɵɵclassProp("favorited", ctx_r1.isEntityFavorited(entity_r23));
412
- i0.ɵɵproperty("title", ctx_r1.isEntityFavorited(entity_r23) ? "Remove from favorites" : "Add to favorites");
247
+ i0.ɵɵclassProp("favorited", ctx_r1.isEntityFavorited(entity_r15));
248
+ i0.ɵɵproperty("title", ctx_r1.isEntityFavorited(entity_r15) ? "Remove from favorites" : "Add to favorites");
413
249
  i0.ɵɵadvance();
414
- i0.ɵɵclassMap(ctx_r1.isEntityFavorited(entity_r23) ? "fa-solid fa-star" : "fa-regular fa-star");
250
+ i0.ɵɵclassMap(ctx_r1.isEntityFavorited(entity_r15) ? "fa-solid fa-star" : "fa-regular fa-star");
415
251
  } }
416
252
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
417
- i0.ɵɵelementStart(0, "div", 89);
418
- i0.ɵɵrepeaterCreate(1, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template, 9, 10, "div", 108, _forTrack3);
253
+ i0.ɵɵelementStart(0, "div", 49);
254
+ i0.ɵɵrepeaterCreate(1, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template, 9, 10, "div", 68, _forTrack2);
419
255
  i0.ɵɵelementEnd();
420
256
  } if (rf & 2) {
421
257
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -423,96 +259,96 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional
423
259
  i0.ɵɵrepeater(ctx_r1.flatFilteredEntities);
424
260
  } }
425
261
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Conditional_6_Template(rf, ctx) { if (rf & 1) {
426
- i0.ɵɵelementStart(0, "span", 113);
262
+ i0.ɵɵelementStart(0, "span", 73);
427
263
  i0.ɵɵtext(1);
428
264
  i0.ɵɵelementEnd();
429
265
  } if (rf & 2) {
430
- const entity_r27 = i0.ɵɵnextContext().$implicit;
266
+ const entity_r19 = i0.ɵɵnextContext().$implicit;
431
267
  i0.ɵɵadvance();
432
- i0.ɵɵtextInterpolate(entity_r27.Description);
268
+ i0.ɵɵtextInterpolate(entity_r19.Description);
433
269
  } }
434
270
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template(rf, ctx) { if (rf & 1) {
435
- const _r26 = i0.ɵɵgetCurrentView();
436
- i0.ɵɵelementStart(0, "div", 109);
437
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template_div_click_0_listener() { const entity_r27 = i0.ɵɵrestoreView(_r26).$implicit; const ctx_r1 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r27)); });
438
- i0.ɵɵelementStart(1, "div", 110);
271
+ const _r18 = i0.ɵɵgetCurrentView();
272
+ i0.ɵɵelementStart(0, "div", 69);
273
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template_div_click_0_listener() { const entity_r19 = i0.ɵɵrestoreView(_r18).$implicit; const ctx_r1 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r19)); });
274
+ i0.ɵɵelementStart(1, "div", 70);
439
275
  i0.ɵɵelement(2, "i");
440
276
  i0.ɵɵelementEnd();
441
- i0.ɵɵelementStart(3, "div", 111)(4, "span", 112);
277
+ i0.ɵɵelementStart(3, "div", 71)(4, "span", 72);
442
278
  i0.ɵɵtext(5);
443
279
  i0.ɵɵelementEnd();
444
- i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Conditional_6_Template, 2, 1, "span", 113);
280
+ i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Conditional_6_Template, 2, 1, "span", 73);
445
281
  i0.ɵɵelementEnd();
446
- i0.ɵɵelementStart(7, "button", 114);
447
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template_button_click_7_listener($event) { const entity_r27 = i0.ɵɵrestoreView(_r26).$implicit; const ctx_r1 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r1.toggleEntityFavorite(entity_r27, $event)); });
282
+ i0.ɵɵelementStart(7, "button", 74);
283
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template_button_click_7_listener($event) { const entity_r19 = i0.ɵɵrestoreView(_r18).$implicit; const ctx_r1 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r1.toggleEntityFavorite(entity_r19, $event)); });
448
284
  i0.ɵɵelement(8, "i");
449
285
  i0.ɵɵelementEnd()();
450
286
  } if (rf & 2) {
451
- const entity_r27 = ctx.$implicit;
287
+ const entity_r19 = ctx.$implicit;
452
288
  const ctx_r1 = i0.ɵɵnextContext(6);
453
- i0.ɵɵproperty("title", entity_r27.Description || entity_r27.DisplayNameOrName);
289
+ i0.ɵɵproperty("title", entity_r19.Description || entity_r19.DisplayNameOrName);
454
290
  i0.ɵɵadvance(2);
455
- i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r27));
291
+ i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r19));
456
292
  i0.ɵɵadvance(3);
457
- i0.ɵɵtextInterpolate(entity_r27.DisplayNameOrName);
293
+ i0.ɵɵtextInterpolate(entity_r19.DisplayNameOrName);
458
294
  i0.ɵɵadvance();
459
- i0.ɵɵconditional(entity_r27.Description ? 6 : -1);
295
+ i0.ɵɵconditional(entity_r19.Description ? 6 : -1);
460
296
  i0.ɵɵadvance();
461
- i0.ɵɵclassProp("favorited", ctx_r1.isEntityFavorited(entity_r27));
462
- i0.ɵɵproperty("title", ctx_r1.isEntityFavorited(entity_r27) ? "Remove from favorites" : "Add to favorites");
297
+ i0.ɵɵclassProp("favorited", ctx_r1.isEntityFavorited(entity_r19));
298
+ i0.ɵɵproperty("title", ctx_r1.isEntityFavorited(entity_r19) ? "Remove from favorites" : "Add to favorites");
463
299
  i0.ɵɵadvance();
464
- i0.ɵɵclassMap(ctx_r1.isEntityFavorited(entity_r27) ? "fa-solid fa-star" : "fa-regular fa-star");
300
+ i0.ɵɵclassMap(ctx_r1.isEntityFavorited(entity_r19) ? "fa-solid fa-star" : "fa-regular fa-star");
465
301
  } }
466
302
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_Template(rf, ctx) { if (rf & 1) {
467
- i0.ɵɵelementStart(0, "div", 121)(1, "div", 89);
468
- i0.ɵɵrepeaterCreate(2, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template, 9, 10, "div", 108, _forTrack3);
303
+ i0.ɵɵelementStart(0, "div", 81)(1, "div", 49);
304
+ i0.ɵɵrepeaterCreate(2, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template, 9, 10, "div", 68, _forTrack2);
469
305
  i0.ɵɵelementEnd()();
470
306
  } if (rf & 2) {
471
- const group_r25 = i0.ɵɵnextContext().$implicit;
307
+ const group_r17 = i0.ɵɵnextContext().$implicit;
472
308
  i0.ɵɵadvance(2);
473
- i0.ɵɵrepeater(group_r25.entities);
309
+ i0.ɵɵrepeater(group_r17.entities);
474
310
  } }
475
311
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template(rf, ctx) { if (rf & 1) {
476
- const _r24 = i0.ɵɵgetCurrentView();
477
- i0.ɵɵelementStart(0, "div", 115)(1, "div", 116);
478
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template_div_click_1_listener() { const group_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.toggleAppGroup(group_r25.applicationId)); });
479
- i0.ɵɵelementStart(2, "div", 117);
312
+ const _r16 = i0.ɵɵgetCurrentView();
313
+ i0.ɵɵelementStart(0, "div", 75)(1, "div", 76);
314
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template_div_click_1_listener() { const group_r17 = i0.ɵɵrestoreView(_r16).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.toggleAppGroup(group_r17.applicationId)); });
315
+ i0.ɵɵelementStart(2, "div", 77);
480
316
  i0.ɵɵelement(3, "i");
481
317
  i0.ɵɵelementEnd();
482
- i0.ɵɵelementStart(4, "span", 118);
318
+ i0.ɵɵelementStart(4, "span", 78);
483
319
  i0.ɵɵtext(5);
484
320
  i0.ɵɵelementEnd();
485
- i0.ɵɵelementStart(6, "span", 119);
321
+ i0.ɵɵelementStart(6, "span", 79);
486
322
  i0.ɵɵtext(7);
487
323
  i0.ɵɵelementEnd();
488
- i0.ɵɵelement(8, "i", 120);
324
+ i0.ɵɵelement(8, "i", 80);
489
325
  i0.ɵɵelementEnd();
490
- i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_Template, 4, 0, "div", 121);
326
+ i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_Template, 4, 0, "div", 81);
491
327
  i0.ɵɵelementEnd();
492
328
  } if (rf & 2) {
493
- const group_r25 = ctx.$implicit;
329
+ const group_r17 = ctx.$implicit;
494
330
  i0.ɵɵadvance(2);
495
- i0.ɵɵstyleProp("background", group_r25.applicationColor ? group_r25.applicationColor + "15" : null)("color", group_r25.applicationColor || null);
331
+ i0.ɵɵstyleProp("background", group_r17.applicationColor ? group_r17.applicationColor + "15" : null)("color", group_r17.applicationColor || null);
496
332
  i0.ɵɵadvance();
497
- i0.ɵɵclassMap(group_r25.applicationIcon || "fa-solid fa-folder");
333
+ i0.ɵɵclassMap(group_r17.applicationIcon || "fa-solid fa-folder");
498
334
  i0.ɵɵadvance(2);
499
- i0.ɵɵtextInterpolate(group_r25.applicationName);
335
+ i0.ɵɵtextInterpolate(group_r17.applicationName);
500
336
  i0.ɵɵadvance(2);
501
- i0.ɵɵtextInterpolate(group_r25.entities.length);
337
+ i0.ɵɵtextInterpolate(group_r17.entities.length);
502
338
  i0.ɵɵadvance();
503
- i0.ɵɵclassProp("expanded", group_r25.isExpanded);
339
+ i0.ɵɵclassProp("expanded", group_r17.isExpanded);
504
340
  i0.ɵɵadvance();
505
- i0.ɵɵconditional(group_r25.isExpanded ? 9 : -1);
341
+ i0.ɵɵconditional(group_r17.isExpanded ? 9 : -1);
506
342
  } }
507
343
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
508
- i0.ɵɵrepeaterCreate(0, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template, 10, 11, "div", 115, _forTrack5);
344
+ i0.ɵɵrepeaterCreate(0, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template, 10, 11, "div", 75, _forTrack4);
509
345
  } if (rf & 2) {
510
346
  const ctx_r1 = i0.ɵɵnextContext(3);
511
347
  i0.ɵɵrepeater(ctx_r1.filteredAppEntityGroups);
512
348
  } }
513
349
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_21_Template(rf, ctx) { if (rf & 1) {
514
- i0.ɵɵelementStart(0, "div", 90);
515
- i0.ɵɵelement(1, "i", 122);
350
+ i0.ɵɵelementStart(0, "div", 50);
351
+ i0.ɵɵelement(1, "i", 82);
516
352
  i0.ɵɵelementStart(2, "p");
517
353
  i0.ɵɵtext(3);
518
354
  i0.ɵɵelementEnd()();
@@ -522,8 +358,8 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional
522
358
  i0.ɵɵtextInterpolate1("No entities match \"", ctx_r1.entityFilterText, "\"");
523
359
  } }
524
360
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_22_Template(rf, ctx) { if (rf & 1) {
525
- i0.ɵɵelementStart(0, "div", 91);
526
- i0.ɵɵelement(1, "i", 123);
361
+ i0.ɵɵelementStart(0, "div", 51);
362
+ i0.ɵɵelement(1, "i", 83);
527
363
  i0.ɵɵelementStart(2, "h3");
528
364
  i0.ɵɵtext(3, "No Entities Available");
529
365
  i0.ɵɵelementEnd();
@@ -532,167 +368,167 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional
532
368
  i0.ɵɵelementEnd()();
533
369
  } }
534
370
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template(rf, ctx) { if (rf & 1) {
535
- const _r28 = i0.ɵɵgetCurrentView();
536
- i0.ɵɵelementStart(0, "div", 124);
537
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template_div_click_0_listener() { const record_r29 = i0.ɵɵrestoreView(_r28).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onRecentRecordClick(record_r29)); });
538
- i0.ɵɵelementStart(1, "div", 125);
371
+ const _r20 = i0.ɵɵgetCurrentView();
372
+ i0.ɵɵelementStart(0, "div", 84);
373
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template_div_click_0_listener() { const record_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onRecentRecordClick(record_r21)); });
374
+ i0.ɵɵelementStart(1, "div", 85);
539
375
  i0.ɵɵelement(2, "i");
540
376
  i0.ɵɵelementEnd();
541
- i0.ɵɵelementStart(3, "div", 126)(4, "div", 127);
377
+ i0.ɵɵelementStart(3, "div", 86)(4, "div", 87);
542
378
  i0.ɵɵtext(5);
543
379
  i0.ɵɵelementEnd();
544
- i0.ɵɵelementStart(6, "div", 128);
380
+ i0.ɵɵelementStart(6, "div", 88);
545
381
  i0.ɵɵtext(7);
546
382
  i0.ɵɵelementEnd()();
547
- i0.ɵɵelementStart(8, "span", 129);
383
+ i0.ɵɵelementStart(8, "span", 89);
548
384
  i0.ɵɵtext(9);
549
385
  i0.ɵɵelementEnd()();
550
386
  } if (rf & 2) {
551
- const record_r29 = ctx.$implicit;
387
+ const record_r21 = ctx.$implicit;
552
388
  const ctx_r1 = i0.ɵɵnextContext(3);
553
389
  i0.ɵɵadvance(2);
554
- i0.ɵɵclassMap(ctx_r1.getEntityIconById(record_r29.entityId));
390
+ i0.ɵɵclassMap(ctx_r1.getEntityIconById(record_r21.entityId));
555
391
  i0.ɵɵadvance(3);
556
- i0.ɵɵtextInterpolate(record_r29.recordName || record_r29.recordId);
392
+ i0.ɵɵtextInterpolate(record_r21.recordName || record_r21.recordId);
557
393
  i0.ɵɵadvance(2);
558
- i0.ɵɵtextInterpolate(record_r29.entityName);
394
+ i0.ɵɵtextInterpolate(record_r21.entityName);
559
395
  i0.ɵɵadvance(2);
560
- i0.ɵɵtextInterpolate(ctx_r1.formatRelativeTime(record_r29.latestAt));
396
+ i0.ɵɵtextInterpolate(ctx_r1.formatRelativeTime(record_r21.latestAt));
561
397
  } }
562
398
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_41_Template(rf, ctx) { if (rf & 1) {
563
- i0.ɵɵelementStart(0, "div", 104);
399
+ i0.ɵɵelementStart(0, "div", 64);
564
400
  i0.ɵɵtext(1, "No recent records");
565
401
  i0.ɵɵelementEnd();
566
402
  } }
567
403
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template(rf, ctx) { if (rf & 1) {
568
- const _r30 = i0.ɵɵgetCurrentView();
569
- i0.ɵɵelementStart(0, "div", 124);
570
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template_div_click_0_listener() { const entity_r31 = i0.ɵɵrestoreView(_r30).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r31)); });
571
- i0.ɵɵelementStart(1, "div", 125);
404
+ const _r22 = i0.ɵɵgetCurrentView();
405
+ i0.ɵɵelementStart(0, "div", 84);
406
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template_div_click_0_listener() { const entity_r23 = i0.ɵɵrestoreView(_r22).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r23)); });
407
+ i0.ɵɵelementStart(1, "div", 85);
572
408
  i0.ɵɵelement(2, "i");
573
409
  i0.ɵɵelementEnd();
574
- i0.ɵɵelementStart(3, "div", 126)(4, "div", 127);
410
+ i0.ɵɵelementStart(3, "div", 86)(4, "div", 87);
575
411
  i0.ɵɵtext(5);
576
412
  i0.ɵɵelementEnd()()();
577
413
  } if (rf & 2) {
578
- const entity_r31 = ctx.$implicit;
414
+ const entity_r23 = ctx.$implicit;
579
415
  const ctx_r1 = i0.ɵɵnextContext(3);
580
416
  i0.ɵɵadvance(2);
581
- i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r31));
417
+ i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r23));
582
418
  i0.ɵɵadvance(3);
583
- i0.ɵɵtextInterpolate(entity_r31.DisplayNameOrName);
419
+ i0.ɵɵtextInterpolate(entity_r23.DisplayNameOrName);
584
420
  } }
585
421
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_53_Template(rf, ctx) { if (rf & 1) {
586
- i0.ɵɵelementStart(0, "div", 104);
422
+ i0.ɵɵelementStart(0, "div", 64);
587
423
  i0.ɵɵtext(1, "No recent entities");
588
424
  i0.ɵɵelementEnd();
589
425
  } }
590
426
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template(rf, ctx) { if (rf & 1) {
591
- const _r32 = i0.ɵɵgetCurrentView();
592
- i0.ɵɵelementStart(0, "div", 124);
593
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template_div_click_0_listener() { const record_r33 = i0.ɵɵrestoreView(_r32).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onFavoriteRecordClick(record_r33)); });
594
- i0.ɵɵelementStart(1, "div", 125);
427
+ const _r24 = i0.ɵɵgetCurrentView();
428
+ i0.ɵɵelementStart(0, "div", 84);
429
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template_div_click_0_listener() { const record_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onFavoriteRecordClick(record_r25)); });
430
+ i0.ɵɵelementStart(1, "div", 85);
595
431
  i0.ɵɵelement(2, "i");
596
432
  i0.ɵɵelementEnd();
597
- i0.ɵɵelementStart(3, "div", 126)(4, "div", 127);
433
+ i0.ɵɵelementStart(3, "div", 86)(4, "div", 87);
598
434
  i0.ɵɵtext(5);
599
435
  i0.ɵɵelementEnd();
600
- i0.ɵɵelementStart(6, "div", 128);
436
+ i0.ɵɵelementStart(6, "div", 88);
601
437
  i0.ɵɵtext(7);
602
438
  i0.ɵɵelementEnd()()();
603
439
  } if (rf & 2) {
604
- const record_r33 = ctx.$implicit;
440
+ const record_r25 = ctx.$implicit;
605
441
  const ctx_r1 = i0.ɵɵnextContext(3);
606
442
  i0.ɵɵadvance(2);
607
- i0.ɵɵclassMap(ctx_r1.getEntityIconById(record_r33.entityId));
443
+ i0.ɵɵclassMap(ctx_r1.getEntityIconById(record_r25.entityId));
608
444
  i0.ɵɵadvance(3);
609
- i0.ɵɵtextInterpolate(record_r33.recordName || record_r33.recordId);
445
+ i0.ɵɵtextInterpolate(record_r25.recordName || record_r25.recordId);
610
446
  i0.ɵɵadvance(2);
611
- i0.ɵɵtextInterpolate(record_r33.entityName);
447
+ i0.ɵɵtextInterpolate(record_r25.entityName);
612
448
  } }
613
449
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_65_Template(rf, ctx) { if (rf & 1) {
614
- i0.ɵɵelementStart(0, "div", 104);
450
+ i0.ɵɵelementStart(0, "div", 64);
615
451
  i0.ɵɵtext(1, "No favorite records");
616
452
  i0.ɵɵelementEnd();
617
453
  } }
618
454
  function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template(rf, ctx) { if (rf & 1) {
619
- const _r20 = i0.ɵɵgetCurrentView();
620
- i0.ɵɵelementStart(0, "div", 76)(1, "div", 77)(2, "div", 78);
621
- i0.ɵɵelement(3, "i", 79);
622
- i0.ɵɵelementStart(4, "input", 80, 0);
623
- i0.ɵɵtwoWayListener("ngModelChange", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.entityFilterText, $event) || (ctx_r1.entityFilterText = $event); return i0.ɵɵresetView($event); });
455
+ const _r12 = i0.ɵɵgetCurrentView();
456
+ i0.ɵɵelementStart(0, "div", 36)(1, "div", 37)(2, "div", 38);
457
+ i0.ɵɵelement(3, "i", 39);
458
+ i0.ɵɵelementStart(4, "input", 40, 0);
459
+ i0.ɵɵtwoWayListener("ngModelChange", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.entityFilterText, $event) || (ctx_r1.entityFilterText = $event); return i0.ɵɵresetView($event); });
624
460
  i0.ɵɵelementEnd();
625
- i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template, 2, 0, "button", 81)(7, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_7_Template, 2, 0, "span", 82);
461
+ i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template, 2, 0, "button", 41)(7, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_7_Template, 2, 0, "span", 42);
626
462
  i0.ɵɵelementEnd();
627
- i0.ɵɵelementStart(8, "div", 83)(9, "span", 84);
463
+ i0.ɵɵelementStart(8, "div", 43)(9, "span", 44);
628
464
  i0.ɵɵtext(10);
629
465
  i0.ɵɵconditionalCreate(11, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_11_Template, 1, 1);
630
466
  i0.ɵɵelementEnd();
631
- i0.ɵɵelementStart(12, "div", 85)(13, "button", 86);
632
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setHomeViewMode("all")); });
467
+ i0.ɵɵelementStart(12, "div", 45)(13, "button", 46);
468
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setHomeViewMode("all")); });
633
469
  i0.ɵɵtext(14, " All Entities ");
634
470
  i0.ɵɵelementEnd();
635
- i0.ɵɵelementStart(15, "button", 86);
636
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setHomeViewMode("favorites")); });
637
- i0.ɵɵelement(16, "i", 87);
471
+ i0.ɵɵelementStart(15, "button", 46);
472
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setHomeViewMode("favorites")); });
473
+ i0.ɵɵelement(16, "i", 47);
638
474
  i0.ɵɵtext(17, " My Favorites ");
639
475
  i0.ɵɵelementEnd()()()();
640
- i0.ɵɵelementStart(18, "div", 88);
641
- i0.ɵɵconditionalCreate(19, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_Template, 3, 0, "div", 89)(20, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_Template, 2, 0);
642
- i0.ɵɵconditionalCreate(21, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_21_Template, 4, 1, "div", 90);
643
- i0.ɵɵconditionalCreate(22, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_22_Template, 6, 0, "div", 91);
476
+ i0.ɵɵelementStart(18, "div", 48);
477
+ i0.ɵɵconditionalCreate(19, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_Template, 3, 0, "div", 49)(20, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_Template, 2, 0);
478
+ i0.ɵɵconditionalCreate(21, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_21_Template, 4, 1, "div", 50);
479
+ i0.ɵɵconditionalCreate(22, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_22_Template, 6, 0, "div", 51);
644
480
  i0.ɵɵelementEnd()();
645
- i0.ɵɵelementStart(23, "div", 92)(24, "div", 93)(25, "h3");
481
+ i0.ɵɵelementStart(23, "div", 52)(24, "div", 53)(25, "h3");
646
482
  i0.ɵɵtext(26, "Quick Access");
647
483
  i0.ɵɵelementEnd();
648
- i0.ɵɵelementStart(27, "button", 94);
649
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_27_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessPanel()); });
650
- i0.ɵɵelement(28, "i", 95);
484
+ i0.ɵɵelementStart(27, "button", 54);
485
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_27_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessPanel()); });
486
+ i0.ɵɵelement(28, "i", 55);
651
487
  i0.ɵɵelementEnd()();
652
- i0.ɵɵelementStart(29, "div", 96)(30, "div", 97)(31, "div", 98);
653
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_31_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("recentRecords")); });
654
- i0.ɵɵelement(32, "i", 99);
488
+ i0.ɵɵelementStart(29, "div", 56)(30, "div", 57)(31, "div", 58);
489
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_31_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("recentRecords")); });
490
+ i0.ɵɵelement(32, "i", 59);
655
491
  i0.ɵɵelementStart(33, "span");
656
492
  i0.ɵɵtext(34, "Recent Records");
657
493
  i0.ɵɵelementEnd();
658
- i0.ɵɵelementStart(35, "span", 100);
494
+ i0.ɵɵelementStart(35, "span", 60);
659
495
  i0.ɵɵtext(36);
660
496
  i0.ɵɵelementEnd();
661
- i0.ɵɵelement(37, "i", 101);
497
+ i0.ɵɵelement(37, "i", 61);
662
498
  i0.ɵɵelementEnd();
663
- i0.ɵɵelementStart(38, "div", 102);
664
- i0.ɵɵrepeaterCreate(39, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template, 10, 5, "div", 103, _forTrack2);
665
- i0.ɵɵconditionalCreate(41, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_41_Template, 2, 0, "div", 104);
499
+ i0.ɵɵelementStart(38, "div", 62);
500
+ i0.ɵɵrepeaterCreate(39, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template, 10, 5, "div", 63, _forTrack1);
501
+ i0.ɵɵconditionalCreate(41, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_41_Template, 2, 0, "div", 64);
666
502
  i0.ɵɵelementEnd()();
667
- i0.ɵɵelementStart(42, "div", 97)(43, "div", 98);
668
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_43_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("recentEntities")); });
669
- i0.ɵɵelement(44, "i", 105);
503
+ i0.ɵɵelementStart(42, "div", 57)(43, "div", 58);
504
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_43_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("recentEntities")); });
505
+ i0.ɵɵelement(44, "i", 65);
670
506
  i0.ɵɵelementStart(45, "span");
671
507
  i0.ɵɵtext(46, "Recent Entities");
672
508
  i0.ɵɵelementEnd();
673
- i0.ɵɵelementStart(47, "span", 100);
509
+ i0.ɵɵelementStart(47, "span", 60);
674
510
  i0.ɵɵtext(48);
675
511
  i0.ɵɵelementEnd();
676
- i0.ɵɵelement(49, "i", 101);
512
+ i0.ɵɵelement(49, "i", 61);
677
513
  i0.ɵɵelementEnd();
678
- i0.ɵɵelementStart(50, "div", 102);
679
- i0.ɵɵrepeaterCreate(51, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template, 6, 3, "div", 103, _forTrack3);
680
- i0.ɵɵconditionalCreate(53, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_53_Template, 2, 0, "div", 104);
514
+ i0.ɵɵelementStart(50, "div", 62);
515
+ i0.ɵɵrepeaterCreate(51, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template, 6, 3, "div", 63, _forTrack2);
516
+ i0.ɵɵconditionalCreate(53, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_53_Template, 2, 0, "div", 64);
681
517
  i0.ɵɵelementEnd()();
682
- i0.ɵɵelementStart(54, "div", 97)(55, "div", 98);
683
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_55_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("favoriteRecords")); });
684
- i0.ɵɵelement(56, "i", 106);
518
+ i0.ɵɵelementStart(54, "div", 57)(55, "div", 58);
519
+ i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_55_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("favoriteRecords")); });
520
+ i0.ɵɵelement(56, "i", 66);
685
521
  i0.ɵɵelementStart(57, "span");
686
522
  i0.ɵɵtext(58, "Favorite Records");
687
523
  i0.ɵɵelementEnd();
688
- i0.ɵɵelementStart(59, "span", 100);
524
+ i0.ɵɵelementStart(59, "span", 60);
689
525
  i0.ɵɵtext(60);
690
526
  i0.ɵɵelementEnd();
691
- i0.ɵɵelement(61, "i", 101);
527
+ i0.ɵɵelement(61, "i", 61);
692
528
  i0.ɵɵelementEnd();
693
- i0.ɵɵelementStart(62, "div", 102);
694
- i0.ɵɵrepeaterCreate(63, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template, 8, 4, "div", 103, _forTrack4);
695
- i0.ɵɵconditionalCreate(65, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_65_Template, 2, 0, "div", 104);
529
+ i0.ɵɵelementStart(62, "div", 62);
530
+ i0.ɵɵrepeaterCreate(63, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template, 8, 4, "div", 63, _forTrack3);
531
+ i0.ɵɵconditionalCreate(65, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_65_Template, 2, 0, "div", 64);
696
532
  i0.ɵɵelementEnd()()()();
697
533
  } if (rf & 2) {
698
534
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -743,8 +579,8 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template(rf
743
579
  i0.ɵɵconditional(ctx_r1.quickAccessFavoriteRecords.length === 0 ? 65 : -1);
744
580
  } }
745
581
  function DataExplorerDashboardComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
746
- i0.ɵɵelementStart(0, "div", 13);
747
- i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_14_Conditional_1_Template, 2, 0, "div", 74)(2, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template, 66, 27);
582
+ i0.ɵɵelementStart(0, "div", 12);
583
+ i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_14_Conditional_1_Template, 2, 0, "div", 34)(2, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template, 66, 27);
748
584
  i0.ɵɵelementEnd();
749
585
  } if (rf & 2) {
750
586
  const ctx_r1 = i0.ɵɵnextContext();
@@ -752,40 +588,25 @@ function DataExplorerDashboardComponent_Conditional_14_Template(rf, ctx) { if (r
752
588
  i0.ɵɵconditional(ctx_r1.isLoadingEntities ? 1 : 2);
753
589
  } }
754
590
  function DataExplorerDashboardComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
755
- const _r34 = i0.ɵɵgetCurrentView();
756
- i0.ɵɵelementStart(0, "mj-entity-viewer", 130, 1);
757
- i0.ɵɵlistener("viewModeChange", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_viewModeChange_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewModeChanged($event)); })("filterTextChange", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_filterTextChange_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterTextChanged($event)); })("recordSelected", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_recordSelected_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewerRecordSelected($event)); })("recordOpened", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_recordOpened_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewerRecordOpened($event)); })("dataLoaded", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_dataLoaded_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDataLoaded($event)); })("filteredCountChanged", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_filteredCountChanged_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilteredCountChanged($event)); })("gridStateChanged", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_gridStateChanged_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onGridStateChanged($event)); })("selectionChanged", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_selectionChanged_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSelectionChanged($event)); })("addToListRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_addToListRequested_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onAddToListRequested($event)); })("mapRenderModeChange", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_mapRenderModeChange_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onMapRenderModeChange($event)); })("mapDisplayStateChange", function DataExplorerDashboardComponent_Conditional_15_Template_mj_entity_viewer_mapDisplayStateChange_0_listener($event) { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onMapDisplayStateChange($event)); });
591
+ const _r26 = i0.ɵɵgetCurrentView();
592
+ i0.ɵɵelementStart(0, "mj-view-workspace", 90);
593
+ i0.ɵɵlistener("SelectedViewChange", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_SelectedViewChange_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSelected($event)); })("ViewSelected", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_ViewSelected_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSelected($event)); })("OpenViewInTabRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_OpenViewInTabRequested_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenInTabRequested($event)); })("OpenRecordRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_OpenRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceOpenRecord($event)); })("OpenRelatedRecordRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_OpenRelatedRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRelatedRecordRequested($event)); })("CreateNewRecordRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_CreateNewRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCreateNewRecordRequested($event)); })("RecordSelected", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_RecordSelected_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewerRecordSelected($event)); })("AfterViewSave", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_AfterViewSave_0_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSaved()); })("AfterViewDelete", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_AfterViewDelete_0_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSaved()); })("FilterTextChanged", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_FilterTextChanged_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterTextChanged($event)); })("DataLoaded", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_DataLoaded_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDataLoaded($event)); })("FilteredCountChanged", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_FilteredCountChanged_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilteredCountChanged($event)); });
758
594
  i0.ɵɵelementEnd();
759
595
  } if (rf & 2) {
760
596
  const ctx_r1 = i0.ɵɵnextContext();
761
- i0.ɵɵproperty("entity", ctx_r1.selectedEntity)("viewEntity", ctx_r1.selectedViewEntity)("viewMode", ctx_r1.state.viewMode)("filterText", ctx_r1.debouncedFilterText)("selectedRecordId", ctx_r1.state.selectedRecordId)("config", ctx_r1.viewerConfig)("gridState", ctx_r1.currentGridState)("timelineConfig", ctx_r1.currentTimelineConfig)("gridSelectionMode", "checkbox")("showGridToolbar", false)("showAddToListButton", false)("mapRenderMode", ctx_r1.state.mapRenderMode || "point")("mapDisplayState", ctx_r1.mapDisplayState);
597
+ i0.ɵɵproperty("Entity", ctx_r1.selectedEntity)("AutoSaveView", true)("SelectedView", ctx_r1.selectedViewEntity)("FilterText", ctx_r1.debouncedFilterText)("SelectedRecordId", ctx_r1.state.selectedRecordId)("ViewerConfig", ctx_r1.viewerConfig);
762
598
  } }
763
599
  function DataExplorerDashboardComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
764
- const _r35 = i0.ɵɵgetCurrentView();
765
- i0.ɵɵelementStart(0, "div", 131)(1, "div", 132)(2, "button", 133);
766
- i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_16_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.openListManagementDialog()); });
767
- i0.ɵɵelement(3, "i", 35);
768
- i0.ɵɵelementStart(4, "span");
769
- i0.ɵɵtext(5, "Add to List");
770
- i0.ɵɵelementEnd()()();
771
- i0.ɵɵelementStart(6, "mj-entity-record-detail-panel", 134);
772
- i0.ɵɵlistener("close", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_close_6_listener() { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDetailPanelClosed()); })("openRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openRecord_6_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRecord($event)); })("navigateToRelated", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_navigateToRelated_6_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onNavigateToRelated($event)); })("openRelatedRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openRelatedRecord_6_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRelatedRecord($event)); })("openForeignKeyRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openForeignKeyRecord_6_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenForeignKeyRecord($event)); });
600
+ const _r27 = i0.ɵɵgetCurrentView();
601
+ i0.ɵɵelementStart(0, "div", 91)(1, "mj-entity-record-detail-panel", 92);
602
+ i0.ɵɵlistener("close", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_close_1_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDetailPanelClosed()); })("openRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openRecord_1_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRecord($event)); })("navigateToRelated", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_navigateToRelated_1_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onNavigateToRelated($event)); })("openRelatedRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openRelatedRecord_1_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRelatedRecord($event)); })("openForeignKeyRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openForeignKeyRecord_1_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenForeignKeyRecord($event)); });
773
603
  i0.ɵɵelementEnd()();
774
604
  } if (rf & 2) {
775
605
  const ctx_r1 = i0.ɵɵnextContext();
776
606
  i0.ɵɵstyleProp("width", ctx_r1.state.detailPanelWidth, "px");
777
- i0.ɵɵadvance(6);
607
+ i0.ɵɵadvance();
778
608
  i0.ɵɵproperty("entity", ctx_r1.detailPanelEntity)("record", ctx_r1.selectedRecord);
779
609
  } }
780
- function DataExplorerDashboardComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
781
- const _r36 = i0.ɵɵgetCurrentView();
782
- i0.ɵɵelementStart(0, "mj-list-management-dialog", 135);
783
- i0.ɵɵlistener("complete", function DataExplorerDashboardComponent_Conditional_20_Template_mj_list_management_dialog_complete_0_listener($event) { i0.ɵɵrestoreView(_r36); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onListManagementComplete($event)); })("cancel", function DataExplorerDashboardComponent_Conditional_20_Template_mj_list_management_dialog_cancel_0_listener() { i0.ɵɵrestoreView(_r36); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onListManagementCancel()); });
784
- i0.ɵɵelementEnd();
785
- } if (rf & 2) {
786
- const ctx_r1 = i0.ɵɵnextContext();
787
- i0.ɵɵproperty("config", ctx_r1.listManagementConfig)("visible", ctx_r1.showListManagementDialog);
788
- } }
789
610
  /**
790
611
  * Data Explorer Dashboard - Power user interface for exploring data across entities
791
612
  * Combines card-based browsing with grid views and relationship visualization
@@ -797,18 +618,13 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
797
618
  stateService;
798
619
  cdr;
799
620
  recentAccessService;
800
- exportService;
801
621
  ngZone;
802
622
  destroy$ = new Subject();
803
623
  metadata = this.ProviderToUse;
804
624
  /** Reference to the filter input for keyboard shortcuts */
805
625
  filterInputRef;
806
- /** Reference to the view selector for refreshing after save */
807
- viewSelectorRef;
808
- /** Reference to the entity viewer for refreshing after view save */
809
- entityViewerRef;
810
- /** Reference to the view config panel for passing filter state */
811
- viewConfigPanelRef;
626
+ /** Reference to the view workspace (owns view CRUD + the inner data renderer) */
627
+ viewWorkspaceRef;
812
628
  /**
813
629
  * Optional filter to constrain which entities are shown in the explorer.
814
630
  * Can filter by applicationId, schemaNames, or explicit entityNames.
@@ -872,8 +688,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
872
688
  breadcrumbs = [];
873
689
  // Loading state for entities
874
690
  isLoadingEntities = true;
875
- // Date field dropdown state
876
- isDateFieldDropdownOpen = false;
877
691
  // Recent records from User Record Logs
878
692
  recentRecords = [];
879
693
  // Favorite records from User Favorites (non-entity favorites)
@@ -882,31 +696,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
882
696
  isLoadingRecentRecords = true;
883
697
  // Entity filter for recent records (null = show all, string = filter by entityId)
884
698
  recentRecordsEntityFilter = null;
885
- // Export functionality
886
- showExportDialog = false;
887
- exportDialogConfig = null;
888
- // List management
889
- showListManagementDialog = false;
890
- listManagementConfig = null;
891
- // Selection tracking for grid - needed to enable Add to List button in header
892
- selectedRecordIds = [];
893
- selectedRecords = [];
894
- // Quick Save Dialog state (F-001)
895
- showQuickSaveDialog = false;
896
- quickSaveSummary = null;
897
- // Pending new-view context: carries name/description/sharing from quick save dialog
898
- // to the config panel when user clicks "Customize columns, filters & sorting..."
899
- pendingNewViewName = '';
900
- pendingNewViewDescription = '';
901
- pendingNewViewIsShared = false;
902
- // Duplicate View Dialog state (F-005)
903
- showDuplicateDialog = false;
904
- duplicateSourceViewName = '';
905
- duplicateSummary = null;
906
- duplicateTargetViewId = null;
907
- // Shared View Warning Dialog state (Scenario 5)
908
- showSharedViewWarning = false;
909
- pendingQuickSaveEvent = null;
910
699
  async GetResourceDisplayName(data) {
911
700
  return "Data Explorer";
912
701
  }
@@ -1081,114 +870,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
1081
870
  get displayIcon() {
1082
871
  return this.contextIcon;
1083
872
  }
1084
- /**
1085
- * Check if the currently selected entity has date fields available for timeline view.
1086
- * Used to conditionally show the timeline toggle button in the header.
1087
- */
1088
- get entityHasDateFields() {
1089
- if (!this.selectedEntity)
1090
- return false;
1091
- return this.selectedEntity.Fields.some(f => f.TSType === EntityFieldTSType.Date);
1092
- }
1093
- /**
1094
- * Get available date fields for the currently selected entity.
1095
- * Used for the date field selector in timeline view.
1096
- */
1097
- get availableDateFields() {
1098
- if (!this.selectedEntity)
1099
- return [];
1100
- return this.selectedEntity.Fields
1101
- .filter(f => f.TSType === EntityFieldTSType.Date)
1102
- .sort((a, b) => {
1103
- // Prioritize DefaultInView fields, then by Sequence
1104
- if (a.DefaultInView && !b.DefaultInView)
1105
- return -1;
1106
- if (!a.DefaultInView && b.DefaultInView)
1107
- return 1;
1108
- return a.Sequence - b.Sequence;
1109
- })
1110
- .map(f => ({
1111
- name: f.Name,
1112
- displayName: f.DisplayNameOrName
1113
- }));
1114
- }
1115
- /**
1116
- * Get the effective timeline date field name.
1117
- * Returns stored value if valid, otherwise first available date field.
1118
- */
1119
- get effectiveTimelineDateField() {
1120
- const available = this.availableDateFields;
1121
- if (available.length === 0)
1122
- return null;
1123
- // Check if stored value is still valid
1124
- if (this.state.timelineDateFieldName && available.some(f => f.name === this.state.timelineDateFieldName)) {
1125
- return this.state.timelineDateFieldName;
1126
- }
1127
- // Default to first available
1128
- return available[0].name;
1129
- }
1130
- /**
1131
- * Get the display name of the effective timeline date field.
1132
- */
1133
- get effectiveTimelineDateFieldDisplayName() {
1134
- const fieldName = this.effectiveTimelineDateField;
1135
- if (!fieldName)
1136
- return '';
1137
- const field = this.availableDateFields.find(f => f.name === fieldName);
1138
- return field?.displayName || fieldName;
1139
- }
1140
- /**
1141
- * Set the timeline date field.
1142
- */
1143
- setTimelineDateField(fieldName) {
1144
- this.state.timelineDateFieldName = fieldName;
1145
- this.stateService.updateState({ timelineDateFieldName: fieldName });
1146
- this.isDateFieldDropdownOpen = false;
1147
- this.cdr.detectChanges();
1148
- }
1149
- /**
1150
- * Toggle the date field dropdown open/closed.
1151
- */
1152
- toggleDateFieldDropdown() {
1153
- this.isDateFieldDropdownOpen = !this.isDateFieldDropdownOpen;
1154
- }
1155
- /**
1156
- * Close the date field dropdown.
1157
- */
1158
- closeDateFieldDropdown() {
1159
- this.isDateFieldDropdownOpen = false;
1160
- }
1161
- /**
1162
- * Toggle timeline orientation between vertical and horizontal.
1163
- */
1164
- toggleTimelineOrientation() {
1165
- const newOrientation = this.state.timelineOrientation === 'vertical' ? 'horizontal' : 'vertical';
1166
- this.state.timelineOrientation = newOrientation;
1167
- this.stateService.updateState({ timelineOrientation: newOrientation });
1168
- this.cdr.detectChanges();
1169
- }
1170
- /**
1171
- * Toggle timeline sort order between newest first (desc) and oldest first (asc).
1172
- */
1173
- toggleTimelineSortOrder() {
1174
- const newSortOrder = this.state.timelineSortOrder === 'desc' ? 'asc' : 'desc';
1175
- this.state.timelineSortOrder = newSortOrder;
1176
- this.stateService.updateState({ timelineSortOrder: newSortOrder });
1177
- this.cdr.detectChanges();
1178
- }
1179
- /**
1180
- * Get the current timeline configuration for the entity-viewer.
1181
- */
1182
- get currentTimelineConfig() {
1183
- const dateField = this.effectiveTimelineDateField;
1184
- if (!dateField)
1185
- return null;
1186
- return {
1187
- dateFieldName: dateField,
1188
- orientation: this.state.timelineOrientation,
1189
- sortOrder: this.state.timelineSortOrder
1190
- };
1191
- }
1192
873
  /**
1193
874
  * Configuration for mj-entity-viewer composite component
1194
875
  * Hides the built-in header since we have a custom header in the dashboard
@@ -1196,129 +877,116 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
1196
877
  */
1197
878
  viewerConfig = {
1198
879
  showFilter: false, // We have our own filter in the dashboard header
1199
- showViewModeToggle: false, // We have our own toggle in the dashboard header
880
+ showViewModeToggle: true, // Use the viewer's metadata-driven view-type dropdown (no legacy header toggle)
1200
881
  showRecordCount: false, // We show count in the dashboard header
1201
882
  showPagination: true, // Show the pagination UI with "Load More" button
1202
883
  serverSideFiltering: true, // Use RunView's UserSearchString for filtering
1203
884
  serverSideSorting: true, // Use RunView's OrderBy for sorting
1204
885
  height: '100%'
1205
886
  };
1206
- /**
1207
- * Current grid state (built from view entity or local state changes)
1208
- * This is passed to mj-entity-viewer to control column display
1209
- */
1210
- currentGridState = null;
1211
- // Filter dialog state (rendered at dashboard level for full viewport width)
1212
- isFilterDialogOpen = false;
1213
- filterDialogFields = [];
1214
- filterDialogState = createEmptyFilter();
1215
- filterDialogDisabled = false;
1216
- // View save state
1217
- isSavingView = false;
1218
- constructor(stateService, cdr, recentAccessService, exportService, ngZone) {
887
+ constructor(stateService, cdr, recentAccessService, ngZone) {
1219
888
  super();
1220
889
  this.stateService = stateService;
1221
890
  this.cdr = cdr;
1222
891
  this.recentAccessService = recentAccessService;
1223
- this.exportService = exportService;
1224
892
  this.ngZone = ngZone;
1225
893
  this.state = this.stateService.CurrentState;
1226
894
  }
1227
895
  async ngOnInit() {
1228
896
  super.ngOnInit();
1229
- // Ensure UserInfoEngine is configured before we try to access user settings
1230
- // This prevents race conditions where we try to load default view settings
1231
- // before the user settings have been loaded from the server
1232
- await UserInfoEngine.Instance.Config(false);
1233
- // Read initial query params — prefer params forwarded from the resource wrapper
1234
- // (which has Data.Configuration.queryParams from the shell), then fall back to
1235
- // this component's own GetQueryParams() for cases where the dashboard is used standalone.
1236
- const wrapperParams = this.initialQueryParams && Object.keys(this.initialQueryParams).length > 0
1237
- ? this.initialQueryParams
1238
- : null;
1239
- const ownParams = this.GetQueryParams();
1240
- const rawParams = wrapperParams || (Object.keys(ownParams).length > 0 ? ownParams : {});
1241
- const urlState = this.buildDeepLinkFromParams(rawParams);
1242
- // Set context for state service (enables context-specific settings)
1243
- this.stateService.Provider = this.ProviderToUse;
1244
- await this.stateService.setContext(this.entityFilter);
1245
- this.state = this.stateService.CurrentState;
1246
- // User search text starts empty - it's separate from smart filter
1247
- this.liveFilterText = '';
1248
- this.debouncedFilterText = '';
1249
- // Load available entities (async to support applicationId filter)
1250
- // Pass urlState so we don't restore persisted entity if URL specifies one
1251
- await this.loadEntities(urlState);
1252
- // Apply URL state after entities are loaded
1253
- if (urlState) {
1254
- await this.applyUrlState(urlState);
1255
- }
1256
- else if (this.deepLink) {
1257
- await this.applyDeepLink(this.deepLink);
1258
- }
1259
- // Subscribe to state changes
1260
- this.stateService.State
1261
- .pipe(takeUntil(this.destroy$))
1262
- .subscribe(state => {
1263
- const entityChanged = state.selectedEntityName !== this.state.selectedEntityName;
1264
- this.state = state;
1265
- // Self-correct map mode: if a URL-sourced mode is pending and state
1266
- // has diverged (e.g., reset to 'point' by some init step), re-apply it.
1267
- // _pendingMapMode stays alive until the map component emits real state
1268
- // via onMapDisplayStateChange (user interaction), NOT on first state match.
1269
- if (this._pendingMapMode && state.mapRenderMode !== this._pendingMapMode) {
1270
- const mode = this._pendingMapMode;
1271
- this.stateService.updateState({ mapRenderMode: mode });
1272
- return; // Let the next subscription fire handle the rest
897
+ try {
898
+ // Ensure UserInfoEngine is configured before we try to access user settings
899
+ // This prevents race conditions where we try to load default view settings
900
+ // before the user settings have been loaded from the server
901
+ await UserInfoEngine.Instance.Config(false);
902
+ // Read initial query params prefer params forwarded from the resource wrapper
903
+ // (which has Data.Configuration.queryParams from the shell), then fall back to
904
+ // this component's own GetQueryParams() for cases where the dashboard is used standalone.
905
+ const wrapperParams = this.initialQueryParams && Object.keys(this.initialQueryParams).length > 0
906
+ ? this.initialQueryParams
907
+ : null;
908
+ const ownParams = this.GetQueryParams();
909
+ const rawParams = wrapperParams || (Object.keys(ownParams).length > 0 ? ownParams : {});
910
+ const urlState = this.buildDeepLinkFromParams(rawParams);
911
+ // Set context for state service (enables context-specific settings)
912
+ this.stateService.Provider = this.ProviderToUse;
913
+ await this.stateService.setContext(this.entityFilter);
914
+ this.state = this.stateService.CurrentState;
915
+ // User search text starts empty - it's separate from smart filter
916
+ this.liveFilterText = '';
917
+ this.debouncedFilterText = '';
918
+ // Load available entities (async to support applicationId filter)
919
+ // Pass urlState so we don't restore persisted entity if URL specifies one
920
+ await this.loadEntities(urlState);
921
+ // Apply URL state after entities are loaded
922
+ if (urlState) {
923
+ await this.applyUrlState(urlState);
1273
924
  }
1274
- // When entity changes, clear user search text and update title
1275
- if (entityChanged) {
1276
- this.liveFilterText = '';
1277
- this.debouncedFilterText = '';
1278
- this.emitDisplayName();
925
+ else if (this.deepLink) {
926
+ await this.applyDeepLink(this.deepLink);
1279
927
  }
1280
- this.onStateChanged();
1281
- // Update URL query params to reflect current state (for deep linking)
928
+ // Subscribe to state changes
929
+ this.stateService.State
930
+ .pipe(takeUntil(this.destroy$))
931
+ .subscribe(state => {
932
+ const entityChanged = state.selectedEntityName !== this.state.selectedEntityName;
933
+ this.state = state;
934
+ // When entity changes, clear user search text and update title
935
+ if (entityChanged) {
936
+ this.liveFilterText = '';
937
+ this.debouncedFilterText = '';
938
+ this.emitDisplayName();
939
+ }
940
+ this.onStateChanged();
941
+ // Update URL query params to reflect current state (for deep linking)
942
+ this.pushCurrentStateToUrl();
943
+ this.cdr.detectChanges();
944
+ });
945
+ // Subscribe to breadcrumb changes
946
+ this.stateService.Breadcrumbs
947
+ .pipe(takeUntil(this.destroy$))
948
+ .subscribe(breadcrumbs => {
949
+ this.breadcrumbs = breadcrumbs;
950
+ this.cdr.detectChanges();
951
+ });
952
+ // Setup debounced filter - 500ms delay allows comfortable typing before triggering search
953
+ // IMPORTANT: Do NOT call setSmartFilterPrompt here. Updating the state service triggers
954
+ // URL updates (via pushCurrentStateToUrl → UpdateQueryParams), which in turn can trigger
955
+ // OnQueryParamsChanged, which would clear the filter text. The debouncedFilterText flows
956
+ // directly to the entity-viewer via [filterText] binding — no state service involvement needed.
957
+ this.filterInput$
958
+ .pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$))
959
+ .subscribe(filterText => {
960
+ this.debouncedFilterText = filterText;
961
+ this.cdr.detectChanges();
962
+ });
963
+ // Subscribe to recent records changes
964
+ this.stateService.RecentRecords
965
+ .pipe(takeUntil(this.destroy$))
966
+ .subscribe(records => {
967
+ this.recentRecords = records;
968
+ this.isLoadingRecentRecords = false;
969
+ this.cdr.detectChanges();
970
+ });
971
+ // Subscribe to favorite records changes
972
+ this.stateService.FavoriteRecords
973
+ .pipe(takeUntil(this.destroy$))
974
+ .subscribe(records => {
975
+ this.favoriteRecords = records;
976
+ this.cdr.detectChanges();
977
+ });
978
+ // Push initial state to URL (covers deepLink and persisted state)
1282
979
  this.pushCurrentStateToUrl();
1283
- this.cdr.detectChanges();
1284
- });
1285
- // Subscribe to breadcrumb changes
1286
- this.stateService.Breadcrumbs
1287
- .pipe(takeUntil(this.destroy$))
1288
- .subscribe(breadcrumbs => {
1289
- this.breadcrumbs = breadcrumbs;
1290
- this.cdr.detectChanges();
1291
- });
1292
- // Setup debounced filter - 500ms delay allows comfortable typing before triggering search
1293
- // IMPORTANT: Do NOT call setSmartFilterPrompt here. Updating the state service triggers
1294
- // URL updates (via pushCurrentStateToUrl → UpdateQueryParams), which in turn can trigger
1295
- // OnQueryParamsChanged, which would clear the filter text. The debouncedFilterText flows
1296
- // directly to the entity-viewer via [filterText] binding — no state service involvement needed.
1297
- this.filterInput$
1298
- .pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$))
1299
- .subscribe(filterText => {
1300
- this.debouncedFilterText = filterText;
1301
- this.cdr.detectChanges();
1302
- });
1303
- // Subscribe to recent records changes
1304
- this.stateService.RecentRecords
1305
- .pipe(takeUntil(this.destroy$))
1306
- .subscribe(records => {
1307
- this.recentRecords = records;
1308
- this.isLoadingRecentRecords = false;
1309
- this.cdr.detectChanges();
1310
- });
1311
- // Subscribe to favorite records changes
1312
- this.stateService.FavoriteRecords
1313
- .pipe(takeUntil(this.destroy$))
1314
- .subscribe(records => {
1315
- this.favoriteRecords = records;
1316
- this.cdr.detectChanges();
1317
- });
1318
- // Push initial state to URL (covers deepLink and persisted state)
1319
- this.pushCurrentStateToUrl();
1320
- // Notify that loading is complete (for resource wrapper integration)
1321
- this.NotifyLoadComplete();
980
+ }
981
+ catch (err) {
982
+ // Never let a setup failure hang the app loading screen — log it and still signal completion.
983
+ console.error('[DataExplorer] ngOnInit setup failed (signaling load complete anyway):', err);
984
+ }
985
+ finally {
986
+ // ALWAYS notify load complete — the loading screen waits on this; a thrown/awaited error before
987
+ // it would otherwise hang the screen forever on a direct-URL (deep-link) refresh.
988
+ this.NotifyLoadComplete();
989
+ }
1322
990
  }
1323
991
  /**
1324
992
  * Handle keyboard shortcuts
@@ -1346,41 +1014,31 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
1346
1014
  this.focusFilterInput();
1347
1015
  return;
1348
1016
  }
1349
- // View management shortcuts (only when an entity is selected)
1017
+ // View management shortcuts (only when an entity is selected). These delegate to the
1018
+ // view workspace, which now owns the full saved-view lifecycle.
1350
1019
  if (this.selectedEntity && (event.metaKey || event.ctrlKey)) {
1351
1020
  // Ctrl+S / Cmd+S: Save current view
1352
1021
  if (event.key === 's' && !event.shiftKey) {
1353
1022
  event.preventDefault();
1354
- this.onQuickSaveRequested(false);
1023
+ this.viewWorkspaceRef?.onQuickSaveRequested(false);
1355
1024
  return;
1356
1025
  }
1357
1026
  // Ctrl+Shift+S / Cmd+Shift+S: Save as new view
1358
1027
  if (event.key === 'S' || (event.key === 's' && event.shiftKey)) {
1359
1028
  event.preventDefault();
1360
- this.onQuickSaveRequested(true);
1029
+ this.viewWorkspaceRef?.onQuickSaveRequested(true);
1361
1030
  return;
1362
1031
  }
1363
- // Ctrl+Shift+V / Cmd+Shift+V: Open view selector
1364
- if ((event.key === 'V' || (event.key === 'v' && event.shiftKey))) {
1365
- event.preventDefault();
1366
- this.viewSelectorRef?.toggleDropdown();
1367
- return;
1368
- }
1369
- // Ctrl+, / Cmd+,: Toggle config panel
1032
+ // Ctrl+, / Cmd+,: Open config panel
1370
1033
  if (event.key === ',') {
1371
1034
  event.preventDefault();
1372
- if (this.state.viewConfigPanelOpen) {
1373
- this.onCloseViewConfigPanel();
1374
- }
1375
- else {
1376
- this.onConfigureViewRequested();
1377
- }
1035
+ this.viewWorkspaceRef?.onConfigureViewRequested();
1378
1036
  return;
1379
1037
  }
1380
1038
  // Ctrl+Z / Cmd+Z: Revert unsaved changes (only when modified)
1381
1039
  if (event.key === 'z' && !event.shiftKey && this.state.viewModified) {
1382
1040
  event.preventDefault();
1383
- this.onRevertView();
1041
+ void this.viewWorkspaceRef?.onRevertView();
1384
1042
  return;
1385
1043
  }
1386
1044
  }
@@ -1451,932 +1109,157 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
1451
1109
  this.isLoadingEntities = false;
1452
1110
  this.cdr.detectChanges();
1453
1111
  });
1454
- }
1455
- }
1456
- /**
1457
- * Load entity IDs associated with a specific application
1458
- */
1459
- async loadApplicationEntityIds(applicationId) {
1460
- this.applicationEntityIds.clear();
1461
- const rv = RunView.FromMetadataProvider(this.ProviderToUse);
1462
- const result = await rv.RunView({
1463
- EntityName: 'MJ: Application Entities',
1464
- ExtraFilter: `ApplicationID = '${applicationId}'`,
1465
- ResultType: 'entity_object'
1466
- });
1467
- if (result.Success && result.Results) {
1468
- for (const appEntity of result.Results) {
1469
- this.applicationEntityIds.add(appEntity.EntityID);
1470
- }
1471
- }
1472
- }
1473
- /**
1474
- * Apply the configured filter to the entity list
1475
- */
1476
- applyEntityFilter(entities) {
1477
- if (!this.entityFilter) {
1478
- return entities;
1479
- }
1480
- return entities.filter(entity => {
1481
- // Filter by application (via ApplicationEntities)
1482
- if (this.entityFilter.applicationId) {
1483
- if (!this.applicationEntityIds.has(entity.ID)) {
1484
- return false;
1485
- }
1486
- }
1487
- // Filter by schema names
1488
- if (this.entityFilter.schemaNames && this.entityFilter.schemaNames.length > 0) {
1489
- if (!this.entityFilter.schemaNames.includes(entity.SchemaName)) {
1490
- return false;
1491
- }
1492
- }
1493
- // Filter by explicit entity names
1494
- if (this.entityFilter.entityNames && this.entityFilter.entityNames.length > 0) {
1495
- if (!this.entityFilter.entityNames.includes(entity.Name)) {
1496
- return false;
1497
- }
1498
- }
1499
- // Filter out system entities unless explicitly included
1500
- if (!this.entityFilter.includeSystemEntities) {
1501
- // Skip entities with names starting with __ (MJ system entities)
1502
- if (entity.Name.startsWith('__')) {
1503
- return false;
1504
- }
1505
- // Could add more system schema checks here if needed
1506
- }
1507
- return true;
1508
- });
1509
- }
1510
- /**
1511
- * Handle entity selection from navigation panel or home screen
1512
- */
1513
- onEntitySelected(entity) {
1514
- // Ensure any pending grid state changes are saved before switching entities
1515
- // This ensures column resizes/reorders are saved to the current entity's view before switching
1516
- this.entityViewerRef?.EnsurePendingChangesSaved();
1517
- this.resetRecordCounts();
1518
- // Clear the previous entity's view — it belongs to the old entity and its sort/filter
1519
- // state would leak into the new entity's query (e.g., ORDER BY FirstName on Groups)
1520
- this.selectedViewEntity = null;
1521
- this.selectedEntity = entity;
1522
- this.reconcileViewModeForEntity(entity);
1523
- // Load user's saved default grid state for this entity (if any)
1524
- // This ensures formatting and column settings persist across sessions
1525
- this.currentGridState = this.loadUserDefaultGridState();
1526
- this.stateService.selectEntity(entity.Name);
1527
- // Track entity access for recent entities
1528
- this.stateService.trackEntityAccess(entity.Name, entity.ID);
1529
- // mj-entity-viewer will automatically load data when entity changes
1530
- }
1531
- /**
1532
- * Handle state changes from external sources
1533
- */
1534
- onStateChanged() {
1535
- if (this.state.selectedEntityName !== this.selectedEntity?.Name) {
1536
- this.resetRecordCounts();
1537
- this.selectedEntity = this.entities.find(e => e.Name === this.state.selectedEntityName) || null;
1538
- this.reconcileViewModeForEntity(this.selectedEntity);
1539
- // Load user's saved default grid state for this entity (if any)
1540
- this.currentGridState = this.loadUserDefaultGridState();
1541
- }
1542
- }
1543
- /**
1544
- * Reset viewMode to 'grid' if the current mode isn't supported by the given entity
1545
- * (e.g., switching to an entity without geocoding while viewMode is 'map').
1546
- */
1547
- reconcileViewModeForEntity(entity) {
1548
- if (!entity)
1549
- return;
1550
- const mode = this.state.viewMode;
1551
- const hasDateFields = entity.Fields.some(f => f.TSType === EntityFieldTSType.Date);
1552
- const modeUnsupported = (mode === 'map' && !entity.SupportsGeoCoding) ||
1553
- (mode === 'timeline' && !hasDateFields);
1554
- if (modeUnsupported) {
1555
- this.stateService.setViewMode('grid');
1556
- }
1557
- }
1558
- /**
1559
- * Reset record counts when entity changes.
1560
- * The actual counts will be updated when mj-entity-viewer emits dataLoaded event.
1561
- */
1562
- resetRecordCounts() {
1563
- this.totalRecordCount = 0;
1564
- this.filteredRecordCount = 0;
1565
- }
1566
- // ========================================
1567
- // VIEW MANAGEMENT
1568
- // ========================================
1569
- /**
1570
- * Handle view selection from view selector dropdown
1571
- */
1572
- onViewSelected(event) {
1573
- // Ensure any pending grid state changes are saved before switching views
1574
- // This ensures column resizes/reorders are saved to the current view before switching
1575
- this.entityViewerRef?.EnsurePendingChangesSaved();
1576
- this.selectedViewEntity = event.view;
1577
- this.stateService.selectView(event.viewId);
1578
- // When a view is selected, apply its configuration
1579
- if (event.view) {
1580
- // Parse and apply the view's grid state
1581
- this.currentGridState = this.parseViewGridState(event.view);
1582
- // Apply the view's filter - for Smart Filter views, use SmartFilterPrompt
1583
- // For regular filter views, the WhereClause is applied in the entity-viewer
1584
- if (event.view.SmartFilterEnabled && event.view.SmartFilterPrompt) {
1585
- this.stateService.setSmartFilterPrompt(event.view.SmartFilterPrompt);
1586
- }
1587
- else {
1588
- // Clear the smart filter when switching to a view with regular filters
1589
- this.stateService.setSmartFilterPrompt('');
1590
- }
1591
- // Always clear user search text when switching views - smart filter is separate
1592
- this.liveFilterText = '';
1593
- this.debouncedFilterText = '';
1594
- }
1595
- else {
1596
- // Switching to default view - load user's saved defaults from UserInfoEngine
1597
- this.currentGridState = this.loadUserDefaultGridState();
1598
- this.stateService.setSmartFilterPrompt('');
1599
- this.liveFilterText = '';
1600
- this.debouncedFilterText = '';
1601
- }
1602
- // detectChanges pushes the new bindings to entity-viewer; its viewEntity setter
1603
- // already calls deferReload() so no explicit refresh() is needed.
1604
- this.cdr.detectChanges();
1605
- }
1606
- /**
1607
- * Load user's saved default grid state from UserInfoEngine
1608
- * Returns null if no saved state exists
1609
- */
1610
- loadUserDefaultGridState() {
1611
- if (!this.selectedEntity)
1612
- return null;
1613
- try {
1614
- const settingKey = `default-view-setting/${this.selectedEntity.Name}`;
1615
- const savedState = UserInfoEngine.Instance.GetSetting(settingKey);
1616
- if (savedState) {
1617
- const gridState = JSON.parse(savedState);
1618
- if (gridState && Array.isArray(gridState.columnSettings)) {
1619
- // Validate columns and sorts against current entity to prevent stale
1620
- // fields from a previously viewed entity leaking into the query
1621
- const validColumns = gridState.columnSettings.filter((col) => this.selectedEntity.Fields.some(f => f.Name === col.Name));
1622
- const validSorts = (gridState.sortSettings || []).filter((s) => this.selectedEntity.Fields.some(f => f.Name === s.field));
1623
- if (validColumns.length > 0) {
1624
- return {
1625
- columnSettings: validColumns,
1626
- sortSettings: validSorts
1627
- };
1628
- }
1629
- }
1630
- }
1631
- }
1632
- catch (error) {
1633
- console.warn('[DataExplorer] Failed to load user default grid state:', error);
1634
- }
1635
- return null;
1636
- }
1637
- /**
1638
- * Parse GridState JSON from a UserView entity
1639
- * Returns null if no valid GridState is present
1640
- */
1641
- parseViewGridState(view) {
1642
- if (!view.GridState) {
1643
- return null;
1644
- }
1645
- try {
1646
- const parsed = view.GridStateObject;
1647
- // Validate structure - expect columnSettings array
1648
- if (parsed && Array.isArray(parsed.columnSettings)) {
1649
- // Validate columns and sorts against current entity to prevent stale
1650
- // fields from a previously viewed entity leaking into the query
1651
- const validColumns = this.selectedEntity
1652
- ? parsed.columnSettings.filter((col) => this.selectedEntity.Fields.some(f => f.Name === col.Name))
1653
- : parsed.columnSettings;
1654
- const validSorts = this.selectedEntity
1655
- ? (parsed.sortSettings || []).filter((s) => this.selectedEntity.Fields.some(f => f.Name === s.field))
1656
- : parsed.sortSettings || [];
1657
- if (validColumns.length > 0) {
1658
- return {
1659
- columnSettings: validColumns,
1660
- sortSettings: validSorts,
1661
- aggregates: parsed.aggregates || undefined
1662
- };
1663
- }
1664
- return null;
1665
- }
1666
- return null;
1667
- }
1668
- catch (error) {
1669
- // BUG-010: Warn user about parse failure instead of silently returning null
1670
- console.warn('[DataExplorer] Failed to parse GridState:', error);
1671
- this.showNotification('Warning: Could not parse view grid configuration', 'info', 3000);
1672
- return null;
1673
- }
1674
- }
1675
- /**
1676
- * Handle grid state changes from entity-viewer (column resize, reorder, etc.)
1677
- * Updates the local currentGridState and marks view as modified
1678
- */
1679
- onGridStateChanged(event) {
1680
- this.currentGridState = event.gridState;
1681
- // Mark view as modified if we have a selected view
1682
- if (this.state.selectedViewId) {
1683
- this.stateService.setViewModified(true);
1684
- }
1685
- }
1686
- /**
1687
- * Whether the config panel should default to save-as-new mode (BUG-011)
1688
- */
1689
- defaultSaveAsNew = false;
1690
- /**
1691
- * Handle save view request from view selector (BUG-011: forward saveAsNew intent)
1692
- */
1693
- onSaveViewRequested(event) {
1694
- this.defaultSaveAsNew = event.saveAsNew || false;
1695
- this.stateService.openViewConfigPanel();
1696
- }
1697
- /**
1698
- * Handle manage views request - opens view browser
1699
- */
1700
- onManageViewsRequested() {
1701
- // TODO: Implement navigation to view management
1702
- }
1703
- /**
1704
- * Handle open in tab request - opens the view as a ViewResource in a new tab
1705
- */
1706
- onOpenInTabRequested(viewId) {
1707
- // Get the view name from the component's selectedViewEntity (set when view is selected)
1708
- const viewName = this.selectedViewEntity?.Name || 'View';
1709
- // Use NavigationService to open as a proper ViewResource (not entity record)
1710
- this.navigationService.OpenView(viewId, viewName, { forceNewTab: true });
1711
- }
1712
- /**
1713
- * Handle configure view request - opens the configuration panel
1714
- */
1715
- onConfigureViewRequested() {
1716
- this.stateService.openViewConfigPanel();
1717
- }
1718
- /**
1719
- * Close the view configuration panel
1720
- */
1721
- onCloseViewConfigPanel() {
1722
- this.stateService.closeViewConfigPanel();
1723
- this.clearPendingNewViewState();
1724
- }
1725
- clearPendingNewViewState() {
1726
- this.pendingNewViewName = '';
1727
- this.pendingNewViewDescription = '';
1728
- this.pendingNewViewIsShared = false;
1729
- this.defaultSaveAsNew = false;
1730
- }
1731
- // ========================================
1732
- // FILTER DIALOG (at dashboard level for full width)
1733
- // ========================================
1734
- /**
1735
- * Handle request to open filter dialog from view config panel
1736
- * The dialog is rendered at dashboard level to allow full viewport width
1737
- */
1738
- onOpenFilterDialogRequest(event) {
1739
- this.filterDialogState = event.filterState;
1740
- this.filterDialogFields = event.filterFields;
1741
- this.filterDialogDisabled = !this.viewConfigPanelRef?.canEdit;
1742
- this.isFilterDialogOpen = true;
1743
- this.cdr.detectChanges();
1744
- }
1745
- /**
1746
- * Close the filter dialog
1747
- */
1748
- onCloseFilterDialog() {
1749
- this.isFilterDialogOpen = false;
1750
- this.cdr.detectChanges();
1751
- }
1752
- /**
1753
- * Handle filter applied from dialog - pass back to view config panel
1754
- */
1755
- onFilterApplied(filter) {
1756
- this.filterDialogState = filter;
1757
- this.isFilterDialogOpen = false;
1758
- // The view config panel will pick up the new filter state via input binding
1759
- this.cdr.detectChanges();
1760
- }
1761
- /**
1762
- * Handle save view from config panel
1763
- * BUG-001: Panel only closes on success (not on failure)
1764
- * BUG-002: Shows success/error notifications
1765
- * BUG-008: Consistent filter handling for both create and update paths
1766
- */
1767
- async onSaveView(event) {
1768
- if (!this.selectedEntity)
1769
- return;
1770
- this.isSavingView = true;
1771
- this.cdr.detectChanges();
1772
- try {
1773
- const md = this.ProviderToUse;
1774
- // Build GridState in Kendo-compatible format
1775
- const gridState = this.buildGridState(event);
1776
- // Build SortState in Kendo-compatible format
1777
- const sortState = this.buildSortState(event);
1778
- // BUG-008: Consistent filter state for both paths
1779
- const filterStateJson = event.filterState
1780
- ? JSON.stringify(event.filterState)
1781
- : JSON.stringify({ logic: 'and', filters: [] });
1782
- if (event.saveAsNew || !this.selectedViewEntity) {
1783
- // Create new view
1784
- const newView = await md.GetEntityObject('MJ: User Views');
1785
- newView.Name = event.name || 'Custom';
1786
- newView.Description = event.description;
1787
- newView.EntityID = this.selectedEntity.ID;
1788
- newView.UserID = md.CurrentUser.ID;
1789
- newView.IsShared = event.isShared;
1790
- newView.IsDefault = false;
1791
- // Set state via typed object setters
1792
- if (gridState) {
1793
- newView.GridStateObject = gridState;
1794
- }
1795
- if (sortState) {
1796
- newView.SortStateObject = sortState;
1797
- }
1798
- // Set Smart Filter settings
1799
- newView.SmartFilterEnabled = event.smartFilterEnabled;
1800
- newView.SmartFilterPrompt = event.smartFilterPrompt;
1801
- // BUG-008: Always set FilterState consistently (raw string — Kendo CompositeFilterDescriptor shape)
1802
- newView.FilterState = filterStateJson;
1803
- const saved = await newView.Save();
1804
- if (saved) {
1805
- this.selectedViewEntity = newView;
1806
- this.stateService.selectView(newView.ID);
1807
- this.stateService.setViewModified(false);
1808
- this.currentGridState = this.parseViewGridState(newView);
1809
- this.cdr.detectChanges();
1810
- await this.viewSelectorRef?.loadViews();
1811
- // BUG-007: Await the refresh
1812
- await this.entityViewerRef?.loadData();
1813
- // BUG-001: Only close panel on success
1814
- this.stateService.closeViewConfigPanel();
1815
- // BUG-002: Show success notification
1816
- this.showNotification(`View "${newView.Name}" created successfully`, 'success', 2500);
1817
- this.clearPendingNewViewState();
1818
- }
1819
- else {
1820
- // BUG-001: Panel stays open on failure
1821
- // BUG-002: Show error notification
1822
- this.showNotification('Failed to create view', 'error', 3500);
1823
- }
1824
- }
1825
- else {
1826
- // Update existing view
1827
- this.selectedViewEntity.Name = event.name;
1828
- this.selectedViewEntity.Description = event.description;
1829
- this.selectedViewEntity.IsShared = event.isShared;
1830
- // Update state via typed object setters
1831
- if (gridState) {
1832
- this.selectedViewEntity.GridStateObject = gridState;
1833
- }
1834
- if (sortState) {
1835
- this.selectedViewEntity.SortStateObject = sortState;
1836
- }
1837
- // Update Smart Filter settings
1838
- this.selectedViewEntity.SmartFilterEnabled = event.smartFilterEnabled;
1839
- this.selectedViewEntity.SmartFilterPrompt = event.smartFilterPrompt;
1840
- // BUG-008: Always set FilterState consistently (raw string — Kendo CompositeFilterDescriptor shape)
1841
- this.selectedViewEntity.FilterState = filterStateJson;
1842
- const saved = await this.selectedViewEntity.Save();
1843
- if (saved) {
1844
- this.stateService.setViewModified(false);
1845
- this.currentGridState = this.parseViewGridState(this.selectedViewEntity);
1846
- this.cdr.detectChanges();
1847
- await this.viewSelectorRef?.loadViews();
1848
- // BUG-007: Await the refresh
1849
- await this.entityViewerRef?.loadData();
1850
- // BUG-001: Only close panel on success
1851
- this.stateService.closeViewConfigPanel();
1852
- // BUG-002: Show success notification
1853
- this.showNotification(`View "${event.name}" updated successfully`, 'success', 2500);
1854
- }
1855
- else {
1856
- // BUG-001: Panel stays open on failure
1857
- // BUG-002: Show error notification
1858
- this.showNotification('Failed to update view', 'error', 3500);
1859
- }
1860
- }
1861
- this.cdr.detectChanges();
1862
- }
1863
- catch (error) {
1864
- console.error('[DataExplorer] Error saving view:', error);
1865
- // BUG-002: Show error notification with details
1866
- const errorMsg = error instanceof Error ? error.message : 'Unknown error';
1867
- this.showNotification(`Failed to save view: ${errorMsg}`, 'error', 4000);
1868
- }
1869
- finally {
1870
- this.ngZone.run(() => {
1871
- this.isSavingView = false;
1872
- this.cdr.detectChanges();
1873
- });
1874
- }
1875
- }
1876
- /**
1877
- * Handle saving default view settings to user settings
1878
- * Used for dynamic/default views that persist to MJ: User Settings
1879
- */
1880
- async onSaveDefaultViewSettings(event) {
1881
- if (!this.selectedEntity)
1882
- return;
1883
- this.isSavingView = true;
1884
- this.cdr.detectChanges();
1885
- try {
1886
- // Build GridState from the event
1887
- const gridState = this.buildGridState(event);
1888
- if (gridState) {
1889
- // Build sort settings if present - prefer sortItems (multi-sort)
1890
- if (event.sortItems && event.sortItems.length > 0) {
1891
- gridState.sortSettings = event.sortItems.map(item => ({
1892
- field: item.field,
1893
- dir: item.direction
1894
- }));
1895
- }
1896
- else if (event.sortField) {
1897
- // Fallback to deprecated sortField for backward compatibility
1898
- gridState.sortSettings = [{
1899
- field: event.sortField,
1900
- dir: event.sortDirection
1901
- }];
1902
- }
1903
- // Save to user settings using the same key pattern as entity-data-grid
1904
- const settingKey = `default-view-setting/${this.selectedEntity.Name}`;
1905
- await UserInfoEngine.Instance.SetSetting(settingKey, JSON.stringify(gridState));
1906
- // Update currentGridState to reflect saved state
1907
- this.currentGridState = {
1908
- columnSettings: gridState.columnSettings,
1909
- sortSettings: gridState.sortSettings,
1910
- aggregates: gridState.aggregates
1911
- };
1912
- // Force change detection to ensure grid picks up the new gridState
1913
- this.cdr.detectChanges();
1914
- // Refresh the entity viewer data to apply saved aggregates and fetch their values
1915
- this.entityViewerRef?.refresh();
1916
- // Show success notification
1917
- this.showNotification('Default view settings saved', 'success', 2500);
1918
- }
1919
- this.stateService.closeViewConfigPanel();
1920
- this.cdr.detectChanges();
1921
- }
1922
- catch (error) {
1923
- console.error('[DataExplorer] Error saving default view settings:', error);
1924
- // Show error notification
1925
- this.showNotification('Failed to save default view settings', 'error', 3500);
1926
- }
1927
- finally {
1928
- this.ngZone.run(() => {
1929
- this.isSavingView = false;
1930
- this.cdr.detectChanges();
1931
- });
1932
- }
1933
- }
1934
- /**
1935
- * Build GridState in Kendo-compatible format
1936
- * Format: { columnSettings: [...], sortSettings: [...], aggregates: {...} }
1937
- *
1938
- * Priority for column settings:
1939
- * 1. If event.columns provided (from config panel) - use those
1940
- * 2. If currentGridState exists (from grid interactions) - use that
1941
- * 3. Otherwise return null
1942
- */
1943
- buildGridState(event) {
1944
- let columnSettings;
1945
- // First check if the event has columns configured (from config panel)
1946
- if (event.columns.length > 0) {
1947
- columnSettings = event.columns.map((col, idx) => ({
1948
- ID: col.fieldId,
1949
- Name: col.fieldName,
1950
- DisplayName: col.displayName,
1951
- userDisplayName: col.userDisplayName, // Include user-defined column alias
1952
- hidden: false, // Visible columns only
1953
- width: col.width || undefined,
1954
- orderIndex: idx,
1955
- format: col.format // Include column format settings
1956
- }));
1957
- }
1958
- // Otherwise, use the current grid state if available (from grid interactions)
1959
- else if (this.currentGridState?.columnSettings && this.currentGridState.columnSettings.length > 0) {
1960
- columnSettings = this.currentGridState.columnSettings;
1961
- }
1962
- // BUG-005: Third fallback - use entity DefaultInView fields so we never return null
1963
- else if (this.selectedEntity) {
1964
- columnSettings = this.selectedEntity.Fields
1965
- .filter(f => f.DefaultInView)
1966
- .map((f, idx) => ({
1967
- ID: f.ID,
1968
- Name: f.Name,
1969
- DisplayName: f.DisplayNameOrName,
1970
- hidden: false,
1971
- width: f.DefaultColumnWidth || undefined,
1972
- orderIndex: idx
1973
- }));
1974
- if (columnSettings.length === 0) {
1975
- return null;
1976
- }
1977
- }
1978
- // No columns to save
1979
- else {
1980
- return null;
1981
- }
1982
- // Build sort settings - prefer event.sortItems (multi-sort), fall back to currentGridState
1983
- let sortSettings;
1984
- if (event.sortItems && event.sortItems.length > 0) {
1985
- sortSettings = event.sortItems.map(item => ({
1986
- field: item.field,
1987
- dir: item.direction // 'asc' or 'desc'
1988
- }));
1989
- }
1990
- else if (event.sortField) {
1991
- // Fallback to deprecated sortField for backward compatibility
1992
- sortSettings = [{
1993
- field: event.sortField,
1994
- dir: event.sortDirection
1995
- }];
1996
- }
1997
- else if (this.currentGridState?.sortSettings && this.currentGridState.sortSettings.length > 0) {
1998
- sortSettings = this.currentGridState.sortSettings;
1999
- }
2000
- // Build aggregate settings from event or current state
2001
- let aggregates;
2002
- if (event.aggregatesConfig) {
2003
- aggregates = event.aggregatesConfig;
2004
- }
2005
- else if (this.currentGridState?.aggregates) {
2006
- aggregates = this.currentGridState.aggregates;
2007
- }
2008
- return { columnSettings, sortSettings, aggregates };
2009
- }
2010
- /**
2011
- * Build SortState in Kendo-compatible format
2012
- * Format: [{field, direction}] where direction is 'asc' or 'desc'
2013
- * Supports multi-column sorting via sortItems array
2014
- */
2015
- buildSortState(event) {
2016
- // Prefer sortItems array (multi-sort) over deprecated sortField
2017
- if (event.sortItems && event.sortItems.length > 0) {
2018
- return event.sortItems.map(item => ({
2019
- field: item.field,
2020
- direction: item.direction
2021
- }));
2022
- }
2023
- // Fallback to deprecated sortField for backward compatibility
2024
- if (event.sortField) {
2025
- return [{
2026
- field: event.sortField,
2027
- direction: event.sortDirection
2028
- }];
2029
- }
2030
- return null;
2031
- }
2032
- /**
2033
- * Handle delete view from config panel
2034
- */
2035
- async onDeleteView() {
2036
- if (!this.selectedViewEntity)
2037
- return;
2038
- const viewName = this.selectedViewEntity.Name;
2039
- try {
2040
- const deleted = await this.selectedViewEntity.Delete();
2041
- if (deleted) {
2042
- this.selectedViewEntity = null;
2043
- this.stateService.selectView(null);
2044
- this.stateService.closeViewConfigPanel();
2045
- await this.viewSelectorRef?.loadViews();
2046
- this.showNotification(`View "${viewName}" deleted`, 'success', 2500);
2047
- }
2048
- else {
2049
- this.showNotification('Failed to delete view', 'error', 3500);
2050
- }
2051
- }
2052
- catch (error) {
2053
- console.error('[DataExplorer] Error deleting view:', error);
2054
- const errorMsg = error instanceof Error ? error.message : 'Unknown error';
2055
- this.showNotification(`Failed to delete view: ${errorMsg}`, 'error', 4000);
2056
- }
2057
- }
2058
- // ========================================
2059
- // QUICK SAVE, DUPLICATE, REVERT (F-001, F-005, F-007)
2060
- // ========================================
2061
- /**
2062
- * Handle quick save request from view selector (F-001)
2063
- * Builds a summary from the current config panel state and opens the Quick Save dialog
2064
- * @param saveAsNew - true when user explicitly clicked "Save As New"
2065
- */
2066
- onQuickSaveRequested(saveAsNew) {
2067
- this.defaultSaveAsNew = saveAsNew;
2068
- // Build summary from config panel if available
2069
- this.quickSaveSummary = this.viewConfigPanelRef?.BuildSummary() ?? null;
2070
- this.showQuickSaveDialog = true;
2071
- this.cdr.detectChanges();
2072
- }
2073
- /**
2074
- * Handle quick save event from Quick Save dialog (F-001)
2075
- * If updating a shared view, intercepts to show the shared view warning first.
2076
- * Otherwise constructs a ViewSaveEvent and delegates to onSaveView.
2077
- */
2078
- async onQuickSave(event) {
2079
- this.showQuickSaveDialog = false;
2080
- // If updating (not save-as-new) a shared view, show the warning dialog
2081
- if (!event.SaveAsNew && this.selectedViewEntity?.IsShared) {
2082
- this.pendingQuickSaveEvent = event;
2083
- this.showSharedViewWarning = true;
2084
- this.cdr.detectChanges();
2085
- return;
2086
- }
2087
- await this.executeQuickSave(event);
2088
- }
2089
- /**
2090
- * Execute the actual quick save (called directly or after shared view warning confirmation)
2091
- */
2092
- async executeQuickSave(event) {
2093
- const viewSaveEvent = {
2094
- name: event.Name,
2095
- description: event.Description,
2096
- isShared: event.IsShared,
2097
- saveAsNew: event.SaveAsNew,
2098
- columns: [],
2099
- sortField: null,
2100
- sortDirection: 'asc',
2101
- sortItems: [],
2102
- smartFilterEnabled: false,
2103
- smartFilterPrompt: '',
2104
- filterState: this.filterDialogState ?? null,
2105
- aggregatesConfig: null
2106
- };
2107
- await this.onSaveView(viewSaveEvent);
2108
- }
2109
- /**
2110
- * Handle shared view warning dialog action
2111
- */
2112
- async onSharedViewAction(action) {
2113
- this.showSharedViewWarning = false;
2114
- const event = this.pendingQuickSaveEvent;
2115
- this.pendingQuickSaveEvent = null;
2116
- if (!event)
2117
- return;
2118
- if (action === 'update-shared') {
2119
- // Proceed with the update
2120
- await this.executeQuickSave(event);
2121
- }
2122
- else if (action === 'save-as-copy') {
2123
- // Save as a new personal copy instead
2124
- await this.executeQuickSave({
2125
- ...event,
2126
- SaveAsNew: true,
2127
- IsShared: false
2128
- });
2129
- }
2130
- // 'cancel' - do nothing
2131
- this.cdr.detectChanges();
2132
- }
2133
- /**
2134
- * Handle shared view warning cancel
2135
- */
2136
- onSharedViewWarningCancel() {
2137
- this.showSharedViewWarning = false;
2138
- this.pendingQuickSaveEvent = null;
2139
- this.cdr.detectChanges();
2140
- }
2141
- /**
2142
- * Handle quick save dialog close
2143
- */
2144
- onQuickSaveClose() {
2145
- this.showQuickSaveDialog = false;
2146
- this.cdr.detectChanges();
2147
- }
2148
- /**
2149
- * Handle quick save "Open Advanced" - close dialog and open full config panel
2150
- */
2151
- onQuickSaveOpenAdvanced(event) {
2152
- // Carry form data from quick save dialog to the config panel
2153
- this.pendingNewViewName = event.Name;
2154
- this.pendingNewViewDescription = event.Description;
2155
- this.pendingNewViewIsShared = event.IsShared;
2156
- this.defaultSaveAsNew = true;
2157
- this.showQuickSaveDialog = false;
2158
- this.stateService.openViewConfigPanel();
2159
- this.cdr.detectChanges();
2160
- }
2161
- /**
2162
- * Handle duplicate view request (F-005)
2163
- * Opens the Duplicate View Dialog so user can choose a name for the copy
2164
- */
2165
- async onDuplicateView(viewId) {
2166
- const targetId = viewId || this.selectedViewEntity?.ID;
2167
- if (!targetId || !this.selectedEntity)
2168
- return;
2169
- // Find the view to get its name for the dialog
2170
- const allViews = [...(this.viewSelectorRef?.myViews ?? []), ...(this.viewSelectorRef?.sharedViews ?? [])];
2171
- const viewItem = allViews.find(v => v.id === targetId);
2172
- this.duplicateTargetViewId = targetId;
2173
- this.duplicateSourceViewName = viewItem?.name || this.selectedViewEntity?.Name || 'View';
2174
- this.duplicateSummary = this.buildDuplicateSummary(viewItem?.entity ?? this.selectedViewEntity);
2175
- this.showDuplicateDialog = true;
2176
- this.cdr.detectChanges();
1112
+ }
2177
1113
  }
2178
1114
  /**
2179
- * Build a ViewConfigSummary from a view entity for the duplicate dialog
1115
+ * Load entity IDs associated with a specific application
2180
1116
  */
2181
- buildDuplicateSummary(view) {
2182
- if (!view)
2183
- return null;
2184
- let columnCount = 0;
2185
- let filterCount = 0;
2186
- let sortCount = 0;
2187
- let aggregateCount = 0;
2188
- try {
2189
- const gridState = view.GridStateObject;
2190
- if (gridState?.columnSettings && Array.isArray(gridState.columnSettings)) {
2191
- columnCount = gridState.columnSettings.filter((c) => !c.hidden).length;
1117
+ async loadApplicationEntityIds(applicationId) {
1118
+ this.applicationEntityIds.clear();
1119
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
1120
+ const result = await rv.RunView({
1121
+ EntityName: 'MJ: Application Entities',
1122
+ ExtraFilter: `ApplicationID = '${applicationId}'`,
1123
+ ResultType: 'entity_object'
1124
+ });
1125
+ if (result.Success && result.Results) {
1126
+ for (const appEntity of result.Results) {
1127
+ this.applicationEntityIds.add(appEntity.EntityID);
2192
1128
  }
2193
1129
  }
2194
- catch { /* ignore */ }
2195
- try {
2196
- const filterState = view.FilterStateObject;
2197
- if (filterState?.filters?.length)
2198
- filterCount = filterState.filters.length;
2199
- }
2200
- catch { /* ignore */ }
2201
- try {
2202
- const sortState = view.SortStateObject;
2203
- if (Array.isArray(sortState))
2204
- sortCount = sortState.length;
2205
- }
2206
- catch { /* ignore */ }
2207
- return {
2208
- ColumnCount: columnCount,
2209
- FilterCount: filterCount,
2210
- SortCount: sortCount,
2211
- SmartFilterActive: view.SmartFilterEnabled || false,
2212
- SmartFilterPrompt: view.SmartFilterPrompt || '',
2213
- AggregateCount: aggregateCount
2214
- };
2215
1130
  }
2216
1131
  /**
2217
- * Handle duplicate dialog confirmation - actually creates the copy
1132
+ * Apply the configured filter to the entity list
2218
1133
  */
2219
- async onDuplicateConfirmed(event) {
2220
- this.showDuplicateDialog = false;
2221
- const targetId = this.duplicateTargetViewId;
2222
- this.duplicateTargetViewId = null;
2223
- if (!targetId || !this.selectedEntity)
2224
- return;
2225
- const md = this.ProviderToUse;
2226
- const rv = RunView.FromMetadataProvider(this.ProviderToUse);
2227
- try {
2228
- const result = await rv.RunView({
2229
- EntityName: 'MJ: User Views',
2230
- ExtraFilter: `ID = '${targetId}'`,
2231
- ResultType: 'entity_object'
2232
- });
2233
- if (!result.Success || !result.Results || result.Results.length === 0) {
2234
- this.showNotification('Could not find view to duplicate', 'error', 3500);
2235
- return;
1134
+ applyEntityFilter(entities) {
1135
+ if (!this.entityFilter) {
1136
+ return entities;
1137
+ }
1138
+ return entities.filter(entity => {
1139
+ // Filter by application (via ApplicationEntities)
1140
+ if (this.entityFilter.applicationId) {
1141
+ if (!this.applicationEntityIds.has(entity.ID)) {
1142
+ return false;
1143
+ }
2236
1144
  }
2237
- const sourceView = result.Results[0];
2238
- const newView = await md.GetEntityObject('MJ: User Views');
2239
- newView.Name = event.Name;
2240
- newView.Description = sourceView.Description || '';
2241
- newView.EntityID = sourceView.EntityID;
2242
- newView.IsShared = false;
2243
- newView.IsDefault = false;
2244
- newView.GridState = sourceView.GridState;
2245
- newView.FilterState = sourceView.FilterState;
2246
- newView.SortState = sourceView.SortState;
2247
- newView.SmartFilterEnabled = sourceView.SmartFilterEnabled || false;
2248
- newView.SmartFilterPrompt = sourceView.SmartFilterPrompt || '';
2249
- const saved = await newView.Save();
2250
- if (saved) {
2251
- this.showNotification(`View duplicated as "${newView.Name}"`, 'success', 2500);
2252
- await this.viewSelectorRef?.loadViews();
1145
+ // Filter by schema names
1146
+ if (this.entityFilter.schemaNames && this.entityFilter.schemaNames.length > 0) {
1147
+ if (!this.entityFilter.schemaNames.includes(entity.SchemaName)) {
1148
+ return false;
1149
+ }
2253
1150
  }
2254
- else {
2255
- this.showNotification('Failed to duplicate view', 'error', 3500);
1151
+ // Filter by explicit entity names
1152
+ if (this.entityFilter.entityNames && this.entityFilter.entityNames.length > 0) {
1153
+ if (!this.entityFilter.entityNames.includes(entity.Name)) {
1154
+ return false;
1155
+ }
2256
1156
  }
2257
- }
2258
- catch (error) {
2259
- console.error('[DataExplorer] Error duplicating view:', error);
2260
- const errorMsg = error instanceof Error ? error.message : 'Unknown error';
2261
- this.showNotification(`Failed to duplicate view: ${errorMsg}`, 'error', 4000);
2262
- }
1157
+ // Filter out system entities unless explicitly included
1158
+ if (!this.entityFilter.includeSystemEntities) {
1159
+ // Skip entities with names starting with __ (MJ system entities)
1160
+ if (entity.Name.startsWith('__')) {
1161
+ return false;
1162
+ }
1163
+ // Could add more system schema checks here if needed
1164
+ }
1165
+ return true;
1166
+ });
2263
1167
  }
2264
1168
  /**
2265
- * Handle duplicate dialog cancel
1169
+ * Handle entity selection from navigation panel or home screen
2266
1170
  */
2267
- onDuplicateCancel() {
2268
- this.showDuplicateDialog = false;
2269
- this.duplicateTargetViewId = null;
2270
- this.cdr.detectChanges();
1171
+ onEntitySelected(entity) {
1172
+ this.resetRecordCounts();
1173
+ // Clear the previous entity's view — it belongs to the old entity and its sort/filter
1174
+ // state would leak into the new entity's query (e.g., ORDER BY FirstName on Groups).
1175
+ // The workspace resets its own view/grid state when its [Entity] input changes.
1176
+ this.selectedViewEntity = null;
1177
+ this.selectedEntity = entity;
1178
+ this.reconcileViewModeForEntity(entity);
1179
+ this.stateService.selectEntity(entity.Name);
1180
+ // Track entity access for recent entities
1181
+ this.stateService.trackEntityAccess(entity.Name, entity.ID);
1182
+ // mj-entity-viewer will automatically load data when entity changes
2271
1183
  }
2272
1184
  /**
2273
- * Handle duplicate from config panel (F-005)
2274
- * Duplicates the currently selected view
1185
+ * Handle state changes from external sources
2275
1186
  */
2276
- onDuplicateFromPanel() {
2277
- if (this.selectedViewEntity?.ID) {
2278
- this.stateService.closeViewConfigPanel();
2279
- this.onDuplicateView(this.selectedViewEntity.ID);
1187
+ onStateChanged() {
1188
+ if (this.state.selectedEntityName !== this.selectedEntity?.Name) {
1189
+ this.resetRecordCounts();
1190
+ this.selectedEntity = this.entities.find(e => e.Name === this.state.selectedEntityName) || null;
1191
+ this.reconcileViewModeForEntity(this.selectedEntity);
2280
1192
  }
2281
1193
  }
2282
1194
  /**
2283
- * Handle revert view request (F-007)
2284
- * Re-parses the saved view's GridState and resets modified flag
1195
+ * Reset viewMode to 'grid' if the current mode isn't supported by the given entity
1196
+ * (e.g., switching to an entity without geocoding while viewMode is 'map').
2285
1197
  */
2286
- async onRevertView() {
2287
- if (!this.selectedViewEntity)
1198
+ reconcileViewModeForEntity(entity) {
1199
+ if (!entity)
2288
1200
  return;
2289
- try {
2290
- // Re-parse the saved grid state from the view entity
2291
- const gridState = this.parseViewGridState(this.selectedViewEntity);
2292
- if (gridState) {
2293
- this.currentGridState = gridState;
2294
- }
2295
- // Reset modified flag
2296
- this.stateService.setViewModified(false);
2297
- // Refresh the viewer to apply the reverted state
2298
- await this.entityViewerRef?.loadData();
2299
- this.showNotification('View reverted to last saved state', 'info', 2500);
2300
- this.cdr.detectChanges();
2301
- }
2302
- catch (error) {
2303
- console.error('[DataExplorer] Error reverting view:', error);
2304
- this.showNotification('Failed to revert view', 'error', 3500);
1201
+ const mode = this.state.viewMode;
1202
+ const hasDateFields = entity.Fields.some(f => f.TSType === EntityFieldTSType.Date);
1203
+ const modeUnsupported = (mode === 'map' && !entity.SupportsGeoCoding) ||
1204
+ (mode === 'timeline' && !hasDateFields);
1205
+ if (modeUnsupported) {
1206
+ this.stateService.setViewMode('grid');
2305
1207
  }
2306
1208
  }
2307
1209
  /**
2308
- * Handle inline view name change from ViewHeader (F-002)
2309
- * Updates the view entity name and saves immediately
1210
+ * Reset record counts when entity changes.
1211
+ * The actual counts will be updated when mj-entity-viewer emits dataLoaded event.
2310
1212
  */
2311
- async onViewNameChanged(newName) {
2312
- if (!this.selectedViewEntity || !newName.trim())
2313
- return;
2314
- try {
2315
- this.selectedViewEntity.Name = newName.trim();
2316
- const saved = await this.selectedViewEntity.Save();
2317
- if (saved) {
2318
- this.showNotification(`View renamed to "${newName.trim()}"`, 'success', 2500);
2319
- // Refresh the view selector to show the updated name
2320
- this.viewSelectorRef?.loadViews();
2321
- }
2322
- else {
2323
- this.showNotification('Failed to rename view', 'error', 3500);
2324
- }
2325
- this.cdr.detectChanges();
2326
- }
2327
- catch (error) {
2328
- console.error('[DataExplorer] Error renaming view:', error);
2329
- this.showNotification('Failed to rename view', 'error', 3500);
2330
- }
1213
+ resetRecordCounts() {
1214
+ this.totalRecordCount = 0;
1215
+ this.filteredRecordCount = 0;
2331
1216
  }
2332
1217
  // ========================================
2333
- // VIEW MODE & FILTERING (Dashboard Header)
1218
+ // VIEW WORKSPACE EVENT HANDLERS
1219
+ // (View CRUD now lives in mj-view-workspace; these thin handlers only drive
1220
+ // Explorer routing + URL/state sync.)
2334
1221
  // ========================================
2335
1222
  /**
2336
- * Handle view mode toggle from dashboard header
1223
+ * Handle a view selection emitted by the workspace. Tracks the selected view for routing/export
1224
+ * and syncs the selected-view-id + smart-filter into the Explorer state service for URL sync.
1225
+ * Grid-state application is owned by the workspace.
2337
1226
  */
2338
- onViewModeChanged(mode) {
2339
- this.stateService.setViewMode(mode);
2340
- // Mark view as modified when view mode changes
2341
- if (this.state.selectedViewId) {
2342
- this.stateService.setViewModified(true);
1227
+ onWorkspaceViewSelected(view) {
1228
+ this.selectedViewEntity = view;
1229
+ this.stateService.selectView(view?.ID ?? null);
1230
+ if (view && view.SmartFilterEnabled && view.SmartFilterPrompt) {
1231
+ this.stateService.setSmartFilterPrompt(view.SmartFilterPrompt);
2343
1232
  }
2344
- }
2345
- /**
2346
- * Get the current map display state for passing to the EntityViewer/MapView.
2347
- */
2348
- get mapDisplayState() {
2349
- if (this.state.mapZoom == null) {
2350
- return null;
1233
+ else {
1234
+ this.stateService.setSmartFilterPrompt('');
2351
1235
  }
2352
- return {
2353
- ZoomLevel: this.state.mapZoom,
2354
- CenterLat: this.state.mapCenterLat ?? 20,
2355
- CenterLng: this.state.mapCenterLng ?? 0
2356
- };
1236
+ // User search text is separate from a saved view's filter — always clear on view switch.
1237
+ this.liveFilterText = '';
1238
+ this.debouncedFilterText = '';
1239
+ this.cdr.detectChanges();
2357
1240
  }
2358
1241
  /**
2359
- * Handle map display state changes from the map component.
2360
- * Persists zoom, center, and render mode across page reloads.
1242
+ * Handle the workspace's "open view in tab" request — route via NavigationService.
2361
1243
  */
1244
+ onOpenInTabRequested(viewId) {
1245
+ const viewName = this.selectedViewEntity?.Name || 'View';
1246
+ this.navigationService.OpenView(viewId, viewName, { forceNewTab: true });
1247
+ }
2362
1248
  /**
2363
- * Handle map render mode change (user clicked mode button in map component).
1249
+ * Handle the workspace's "create new record" request route via NavigationService.
2364
1250
  */
2365
- onMapRenderModeChange(mode) {
2366
- this._pendingMapMode = null; // User-initiated — clear any pending URL mode
2367
- this.stateService.updateState({ mapRenderMode: mode });
1251
+ onCreateNewRecordRequested(entity) {
1252
+ this.navigationService.OpenNewEntityRecord(entity.Name);
2368
1253
  }
2369
1254
  /**
2370
- * Handle map display state change (zoom/pan fires on moveend).
1255
+ * Clear the Explorer "view modified" flag after the workspace persists/reverts a view.
2371
1256
  */
2372
- onMapDisplayStateChange(state) {
2373
- this._pendingMapMode = null; // Map is interactive now — clear pending
2374
- this.stateService.updateState({
2375
- mapZoom: state.ZoomLevel ?? null,
2376
- mapCenterLat: state.CenterLat ?? null,
2377
- mapCenterLng: state.CenterLng ?? null
2378
- });
1257
+ onWorkspaceViewSaved() {
1258
+ this.stateService.setViewModified(false);
2379
1259
  }
1260
+ // ========================================
1261
+ // VIEW MODE & FILTERING (Dashboard Header)
1262
+ // ========================================
2380
1263
  /**
2381
1264
  * Handle smart filter change from dashboard header
2382
1265
  */
@@ -2448,6 +1331,16 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2448
1331
  RecordPKey: event.compositeKey
2449
1332
  });
2450
1333
  }
1334
+ /**
1335
+ * Handle the workspace's OpenRecordRequested (record open from the inner viewer). Builds the
1336
+ * composite key from the record and routes to the full record view via the OpenEntityRecord output.
1337
+ */
1338
+ onWorkspaceOpenRecord(event) {
1339
+ this.OpenEntityRecord.emit({
1340
+ EntityName: event.entity.Name,
1341
+ RecordPKey: buildCompositeKey(event.record, event.entity)
1342
+ });
1343
+ }
2451
1344
  /**
2452
1345
  * Handle data loaded from mj-entity-viewer
2453
1346
  */
@@ -2528,174 +1421,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2528
1421
  // Use NavigationService to open a new record form
2529
1422
  this.navigationService.OpenNewEntityRecord(this.selectedEntity.Name);
2530
1423
  }
2531
- /**
2532
- * Handle export request - opens the export dialog
2533
- */
2534
- async onExport() {
2535
- if (!this.selectedEntity) {
2536
- console.error('Cannot export: No entity selected');
2537
- return;
2538
- }
2539
- try {
2540
- this.showNotification('Preparing export...', 'info', 2000);
2541
- // Load the export data
2542
- const data = await this.getExportData();
2543
- // Get visible columns for export
2544
- const columns = this.getExportColumns();
2545
- // Generate file name
2546
- const viewName = this.selectedViewEntity?.Name || 'Data';
2547
- const fileName = `${this.selectedEntity.Name}_${viewName}_${new Date().toISOString().split('T')[0]}`;
2548
- // Configure and show the export dialog
2549
- this.exportDialogConfig = {
2550
- data,
2551
- columns,
2552
- defaultFileName: fileName,
2553
- availableFormats: ['excel', 'csv', 'json'],
2554
- defaultFormat: 'excel',
2555
- showSamplingOptions: true,
2556
- defaultSamplingMode: 'all',
2557
- dialogTitle: `Export ${this.selectedEntity.Name}`
2558
- };
2559
- this.showExportDialog = true;
2560
- this.cdr.detectChanges();
2561
- }
2562
- catch (e) {
2563
- this.showNotification('Error preparing export', 'error', 5000);
2564
- console.error('Export error:', e);
2565
- }
2566
- }
2567
- /**
2568
- * Handle export dialog close
2569
- */
2570
- onExportDialogClosed(result) {
2571
- this.showExportDialog = false;
2572
- this.exportDialogConfig = null;
2573
- this.cdr.detectChanges();
2574
- if (result.exported) {
2575
- this.showNotification('Export complete', 'success', 2000);
2576
- }
2577
- }
2578
- /**
2579
- * Get visible columns for export based on current grid/view state
2580
- */
2581
- getExportColumns() {
2582
- if (!this.selectedEntity)
2583
- return [];
2584
- // Priority 1: Current grid state (reflects actual displayed columns)
2585
- if (this.currentGridState?.columnSettings && this.currentGridState.columnSettings.length > 0) {
2586
- const visibleColumns = this.currentGridState.columnSettings.filter(col => col.hidden !== true);
2587
- return visibleColumns.map(col => {
2588
- const field = this.selectedEntity?.Fields.find(f => f.Name === col.Name);
2589
- return {
2590
- name: col.Name,
2591
- displayName: col.DisplayName || col.Name,
2592
- dataType: this.mapFieldTypeToExportType(field?.Type)
2593
- };
2594
- });
2595
- }
2596
- // Priority 2: View's column configuration
2597
- if (this.selectedViewEntity?.Columns) {
2598
- const visibleColumns = this.selectedViewEntity.Columns.filter(col => !col.hidden);
2599
- return visibleColumns.map(col => {
2600
- const field = this.selectedEntity?.Fields.find(f => f.Name === col.Name);
2601
- return {
2602
- name: col.Name,
2603
- displayName: col.DisplayName || col.Name,
2604
- dataType: this.mapFieldTypeToExportType(field?.Type)
2605
- };
2606
- });
2607
- }
2608
- // Priority 3: All non-virtual fields
2609
- const visibleFields = this.selectedEntity.Fields.filter(f => !f.IsVirtual);
2610
- return visibleFields.map(f => ({
2611
- name: f.Name,
2612
- displayName: f.DisplayNameOrName,
2613
- dataType: this.mapFieldTypeToExportType(f.Type)
2614
- }));
2615
- }
2616
- /**
2617
- * Map MemberJunction field types to export column types
2618
- */
2619
- mapFieldTypeToExportType(fieldType) {
2620
- if (!fieldType)
2621
- return 'string';
2622
- const type = fieldType.toLowerCase();
2623
- if (type.includes('int') || type.includes('decimal') || type.includes('float') || type.includes('numeric')) {
2624
- return 'number';
2625
- }
2626
- if (type.includes('date') || type.includes('time')) {
2627
- return 'date';
2628
- }
2629
- if (type.includes('bit') || type.includes('bool')) {
2630
- return 'boolean';
2631
- }
2632
- if (type.includes('money') || type.includes('currency')) {
2633
- return 'currency';
2634
- }
2635
- return 'string';
2636
- }
2637
- /**
2638
- * Get the data for export - loads all records for the current view/entity
2639
- */
2640
- async getExportData() {
2641
- if (!this.selectedEntity) {
2642
- throw new Error('No entity selected for export');
2643
- }
2644
- const md = this.ProviderToUse;
2645
- const rv = RunView.FromMetadataProvider(this.ProviderToUse);
2646
- // Build the run view params based on current state
2647
- const baseParams = {
2648
- EntityName: this.selectedEntity.Name,
2649
- ExtraFilter: this.buildExtraFilter(),
2650
- OrderBy: this.buildOrderBy(),
2651
- IgnoreMaxRows: true,
2652
- ForceAuditLog: true,
2653
- AuditLogDescription: `Export of Data From ${this.selectedViewEntity ? '"' + this.selectedViewEntity.Name + '"' : this.selectedEntity.Name} View for User ${md.CurrentUser.Email}`
2654
- };
2655
- // Add smart filter if present
2656
- const params = this.debouncedFilterText
2657
- ? { ...baseParams, UserSearchString: this.debouncedFilterText }
2658
- : baseParams;
2659
- const result = await rv.RunView(params);
2660
- if (result && result.Success) {
2661
- return result.Results;
2662
- }
2663
- else {
2664
- throw new Error('Unable to get export data: ' + (result?.ErrorMessage || 'Unknown error'));
2665
- }
2666
- }
2667
- /**
2668
- * Build the ExtraFilter string based on current view and filter state
2669
- */
2670
- buildExtraFilter() {
2671
- const filters = [];
2672
- // Add view filter if a view is selected
2673
- if (this.selectedViewEntity?.WhereClause) {
2674
- filters.push(`(${this.selectedViewEntity.WhereClause})`);
2675
- }
2676
- // Add smart filter if present
2677
- if (this.debouncedFilterText) {
2678
- // Smart filter is applied via UserSearchString in RunView, not ExtraFilter
2679
- // So we don't need to add it here
2680
- }
2681
- return filters.join(' AND ');
2682
- }
2683
- /**
2684
- * Build the OrderBy string based on current view state
2685
- */
2686
- buildOrderBy() {
2687
- // Use view's OrderByClause if available
2688
- if (this.selectedViewEntity?.OrderByClause) {
2689
- return this.selectedViewEntity.OrderByClause;
2690
- }
2691
- // Use grid state sort if available
2692
- if (this.currentGridState?.sortSettings && this.currentGridState.sortSettings.length > 0) {
2693
- const sorts = this.currentGridState.sortSettings.map(s => `${s.field} ${s.dir.toUpperCase()}`);
2694
- return sorts.join(', ');
2695
- }
2696
- // Default sort by primary key
2697
- return this.selectedEntity.FirstPrimaryKey.Name;
2698
- }
2699
1424
  /**
2700
1425
  * Show a notification to the user
2701
1426
  */
@@ -2847,10 +1572,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2847
1572
  * Apply a deep link to navigate to a specific entity/record
2848
1573
  */
2849
1574
  async applyDeepLink(deepLink) {
2850
- // Apply view mode if specified
2851
- if (deepLink.viewMode) {
2852
- this.stateService.setViewMode(deepLink.viewMode);
2853
- }
1575
+ // ViewTypeID-only: view type is no longer deep-linked — the inner viewer persists it.
2854
1576
  // Navigate to entity if specified
2855
1577
  if (deepLink.entity) {
2856
1578
  const entity = this.entities.find(e => e.Name.toLowerCase() === deepLink.entity.toLowerCase());
@@ -2876,12 +1598,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2876
1598
  }
2877
1599
  /** Record ID to select once data loads (from deep link) */
2878
1600
  pendingRecordSelection = null;
2879
- /**
2880
- * Pending map mode from URL that must survive initialization state resets.
2881
- * Set during applyUrlState, cleared once state matches or after first successful re-apply.
2882
- * The state subscription self-corrects: any time state diverges from this value, it re-applies.
2883
- */
2884
- _pendingMapMode = null;
2885
1601
  // ========================================
2886
1602
  // BREADCRUMB NAVIGATION
2887
1603
  // ========================================
@@ -2965,19 +1681,17 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
2965
1681
  const entity = params['entity'] || null;
2966
1682
  const record = params['record'] || null;
2967
1683
  const filterParam = params['filter'] || null;
2968
- const view = params['view'] || null;
2969
1684
  const viewId = params['viewId'] || null;
2970
- const mapMode = params['mapMode'] || null;
2971
- if (!entity && !record && !filterParam && !view && !viewId && !mapMode) {
1685
+ if (!entity && !record && !filterParam && !viewId) {
2972
1686
  return null;
2973
1687
  }
1688
+ // ViewTypeID-only: the active view type is persisted via UserView.ViewTypeID / per-user settings
1689
+ // by the inner viewer, NOT via URL query params. So we no longer read/write view/mapMode here.
2974
1690
  return {
2975
1691
  entity: entity || undefined,
2976
1692
  record: record || undefined,
2977
1693
  filter: filterParam || undefined,
2978
- viewMode: view || undefined,
2979
- viewId: viewId || undefined,
2980
- mapMode: mapMode || undefined
1694
+ viewId: viewId || undefined
2981
1695
  };
2982
1696
  }
2983
1697
  /**
@@ -3019,13 +1733,13 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3019
1733
  pushCurrentStateToUrl() {
3020
1734
  const hasEntity = !!this.state.selectedEntityName;
3021
1735
  const hasViewId = !!(this.state.selectedViewId && hasEntity);
1736
+ // ViewTypeID-only: the active view type is persisted by the inner viewer (UserView.ViewTypeID /
1737
+ // per-user settings), not via URL. We only round-trip entity / record / saved-view selection.
3022
1738
  const queryParams = {
3023
1739
  entity: this.state.selectedEntityName || null,
3024
1740
  record: (this.state.selectedRecordId && hasEntity) ? this.state.selectedRecordId : null,
3025
1741
  filter: null, // Never in URL — filters live in saved views (DB), not query strings
3026
- view: (this.state.viewMode && this.state.viewMode !== 'grid') ? this.state.viewMode : null,
3027
- viewId: hasViewId ? this.state.selectedViewId : null,
3028
- mapMode: this.state.viewMode === 'map' ? (this.state.mapRenderMode || 'point') : null
1742
+ viewId: hasViewId ? this.state.selectedViewId : null
3029
1743
  };
3030
1744
  this.UpdateQueryParams(queryParams);
3031
1745
  }
@@ -3034,19 +1748,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3034
1748
  * Used both during init and for popstate handling.
3035
1749
  */
3036
1750
  async applyUrlState(urlState) {
3037
- // Store URL-sourced map mode BEFORE switching to map view various init steps
3038
- // can reset mapRenderMode to 'point'. The state subscription self-corrects using this.
3039
- if (urlState.mapMode && ['point', 'choropleth', 'heatmap'].includes(urlState.mapMode)) {
3040
- this._pendingMapMode = urlState.mapMode;
3041
- }
3042
- // Apply view mode (may trigger map component creation if switching to 'map')
3043
- if (urlState.viewMode) {
3044
- this.stateService.setViewMode(urlState.viewMode);
3045
- }
3046
- // Apply map render mode to state
3047
- if (this._pendingMapMode) {
3048
- this.stateService.updateState({ mapRenderMode: this._pendingMapMode });
3049
- }
1751
+ // ViewTypeID-only: view type / map mode are no longer URL-driventhe inner viewer persists them.
3050
1752
  // Navigate to entity if specified
3051
1753
  if (urlState.entity) {
3052
1754
  const entity = this.entities.find(e => e.Name.toLowerCase() === urlState.entity.toLowerCase());
@@ -3058,7 +1760,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3058
1760
  this.selectedEntity = entity;
3059
1761
  this.stateService.selectEntity(entity.Name);
3060
1762
  }
3061
- // Restore saved view by ID if specified
1763
+ // Restore saved view by ID if specified. The workspace applies the view's grid state
1764
+ // itself once selectedViewEntity flows into its [SelectedView] input.
3062
1765
  if (urlState.viewId) {
3063
1766
  await this.restoreViewFromUrl(urlState.viewId, entity);
3064
1767
  }
@@ -3066,7 +1769,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3066
1769
  // No specific view — clear view selection to use default
3067
1770
  this.selectedViewEntity = null;
3068
1771
  this.stateService.selectView(null);
3069
- this.currentGridState = this.loadUserDefaultGridState();
3070
1772
  }
3071
1773
  // Filters live in saved views (DB), never in URL query strings.
3072
1774
  // Clear smart filter on entity change when no specific view is selected.
@@ -3122,8 +1824,9 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3122
1824
  }
3123
1825
  /**
3124
1826
  * Restore a saved view from the URL's viewId parameter.
3125
- * Looks up the view by ID, sets it as selected, and applies its grid state and filters.
3126
- * Must be async because UserViewEngine's cache may not be populated yet on cold page loads.
1827
+ * Looks up the view by ID and sets it as selected; the workspace applies its grid state once
1828
+ * selectedViewEntity flows into its [SelectedView] input. Must be async because UserViewEngine's
1829
+ * cache may not be populated yet on cold page loads.
3127
1830
  */
3128
1831
  async restoreViewFromUrl(viewId, entity) {
3129
1832
  // Ensure the view engine cache is populated before querying —
@@ -3134,7 +1837,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3134
1837
  if (view) {
3135
1838
  this.selectedViewEntity = view;
3136
1839
  this.stateService.selectView(viewId);
3137
- this.currentGridState = this.parseViewGridState(view);
3138
1840
  // Apply the view's smart filter if it has one
3139
1841
  if (view.SmartFilterEnabled && view.SmartFilterPrompt) {
3140
1842
  this.stateService.setSmartFilterPrompt(view.SmartFilterPrompt);
@@ -3144,7 +1846,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3144
1846
  console.warn('[DataExplorer] restoreViewFromUrl: view NOT FOUND, falling back to default. viewId=', viewId);
3145
1847
  this.selectedViewEntity = null;
3146
1848
  this.stateService.selectView(null);
3147
- this.currentGridState = this.loadUserDefaultGridState();
3148
1849
  }
3149
1850
  this.cdr.detectChanges();
3150
1851
  }
@@ -3382,219 +2083,48 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3382
2083
  get isAtHomeLevel() {
3383
2084
  return !this.selectedEntity;
3384
2085
  }
3385
- // ========================================
3386
- // SELECTION TRACKING
3387
- // ========================================
3388
- /**
3389
- * Handle selection changes from entity-viewer grid.
3390
- * Tracks selected records to enable the Add to List button in the header toolbar.
3391
- */
3392
- onSelectionChanged(event) {
3393
- this.selectedRecords = event.records || [];
3394
- this.selectedRecordIds = event.recordIds || [];
3395
- this.cdr.detectChanges();
3396
- }
3397
- /**
3398
- * Check if there are selected records (for enabling Add to List button)
3399
- */
3400
- get hasSelectedRecords() {
3401
- return this.selectedRecords.length > 0;
3402
- }
3403
- // ========================================
3404
- // LIST MANAGEMENT
3405
- // ========================================
3406
- /**
3407
- * Handle Add to List button click from header toolbar.
3408
- * Opens the list management dialog for selected records.
3409
- */
3410
- onAddToListClick() {
3411
- if (!this.selectedEntity || this.selectedRecords.length === 0) {
3412
- console.warn('Add to List: No entity selected or no records selected');
3413
- return;
3414
- }
3415
- // Build the event object and delegate to existing handler
3416
- const event = {
3417
- entityInfo: this.selectedEntity,
3418
- records: this.selectedRecords,
3419
- recordIds: this.selectedRecordIds
3420
- };
3421
- this.onAddToListRequested(event);
3422
- }
3423
- /**
3424
- * Handle Add to List request from entity-viewer grid toolbar.
3425
- * Opens the list management dialog for multiple selected records.
3426
- */
3427
- onAddToListRequested(event) {
3428
- // Validate input
3429
- if (!event.entityInfo) {
3430
- console.error('Add to List: entityInfo is missing from event');
3431
- return;
3432
- }
3433
- if (!event.records || event.records.length === 0) {
3434
- console.error('Add to List: No records in event. Event:', event);
3435
- return;
3436
- }
3437
- console.log(`Add to List: Processing ${event.records.length} record(s) for entity "${event.entityInfo.Name}"`);
3438
- // Get display names for the records
3439
- const recordDisplayNames = event.records.map(record => {
3440
- try {
3441
- if (event.entityInfo.NameField) {
3442
- const nameValue = record[event.entityInfo.NameField.Name];
3443
- if (nameValue)
3444
- return String(nameValue);
3445
- }
3446
- return buildPkString(record, event.entityInfo) || 'Unknown';
3447
- }
3448
- catch (err) {
3449
- console.error('Add to List: Error getting record display name:', err);
3450
- return 'Unknown';
3451
- }
3452
- });
3453
- // Get raw primary key values (not concatenated strings) for list membership
3454
- const pkFieldName = event.entityInfo.PrimaryKeys[0]?.Name;
3455
- const recordIds = event.records.map(record => {
3456
- try {
3457
- if (!pkFieldName || record[pkFieldName] === null || record[pkFieldName] === undefined) {
3458
- console.error('Add to List: Record has no primary key:', record);
3459
- return '';
3460
- }
3461
- return String(record[pkFieldName]);
3462
- }
3463
- catch (err) {
3464
- console.error('Add to List: Error getting record ID:', err);
3465
- return '';
3466
- }
3467
- }).filter(id => id !== '');
3468
- if (recordIds.length === 0) {
3469
- console.error('Add to List: No valid record IDs found');
3470
- return;
3471
- }
3472
- const recordCount = event.records.length;
3473
- const dialogTitle = recordCount === 1
3474
- ? `Manage Lists for "${recordDisplayNames[0]}"`
3475
- : `Add ${recordCount} Records to List`;
3476
- console.log(`Add to List: Opening dialog for ${recordIds.length} record(s)`);
3477
- this.listManagementConfig = {
3478
- mode: 'manage',
3479
- entityId: event.entityInfo.ID,
3480
- entityName: event.entityInfo.Name,
3481
- recordIds: recordIds,
3482
- recordDisplayNames: recordDisplayNames,
3483
- allowCreate: true,
3484
- allowRemove: recordCount === 1, // Only allow remove for single record
3485
- showMembership: recordCount === 1, // Only show membership for single record
3486
- dialogTitle: dialogTitle
3487
- };
3488
- this.showListManagementDialog = true;
3489
- this.cdr.detectChanges();
3490
- }
3491
- /**
3492
- * Open the list management dialog for the currently selected record
3493
- */
3494
- openListManagementDialog() {
3495
- if (!this.selectedEntity || !this.selectedRecord) {
3496
- return;
3497
- }
3498
- // Use the raw primary key value (not concatenated string) for list membership
3499
- // This matches how records are stored in List Details and enables proper subquery filtering
3500
- const pkFieldName = this.selectedEntity.PrimaryKeys[0]?.Name;
3501
- const recordId = pkFieldName ? String(this.selectedRecord[pkFieldName] ?? '') : '';
3502
- const recordName = this.getRecordDisplayName(this.selectedRecord);
3503
- this.listManagementConfig = {
3504
- mode: 'manage',
3505
- entityId: this.selectedEntity.ID,
3506
- entityName: this.selectedEntity.Name,
3507
- recordIds: [recordId],
3508
- recordDisplayNames: [recordName],
3509
- allowCreate: true,
3510
- allowRemove: true,
3511
- showMembership: true,
3512
- dialogTitle: `Manage Lists for "${recordName}"`
3513
- };
3514
- this.showListManagementDialog = true;
3515
- this.cdr.detectChanges();
3516
- }
3517
2086
  /**
3518
- * Handle completion of the list management dialog
2087
+ * NAVIGATION handler: open a *related* record on a (possibly different) entity, bubbled up from a
2088
+ * plug-in renderer through the workspace (e.g. a grid foreign-key drill-through). Resolves the
2089
+ * target entity and shows the record in the detail panel, mirroring the FK navigation path used
2090
+ * by {@link onOpenForeignKeyRecord}.
2091
+ *
2092
+ * @param nav the related-record navigation payload: the target entity name and the record's key.
3519
2093
  */
3520
- onListManagementComplete(result) {
3521
- this.showListManagementDialog = false;
3522
- this.listManagementConfig = null;
3523
- if (result.action === 'apply') {
3524
- const addedCount = result.added.length;
3525
- const removedCount = result.removed.length;
3526
- if (addedCount > 0 || removedCount > 0) {
3527
- let message = '';
3528
- if (addedCount > 0) {
3529
- message += `Added to ${addedCount} list(s)`;
3530
- }
3531
- if (removedCount > 0) {
3532
- if (message)
3533
- message += ', ';
3534
- message += `Removed from ${removedCount} list(s)`;
3535
- }
3536
- this.showNotification(message, 'success', 2500);
3537
- }
2094
+ onOpenRelatedRecordRequested(nav) {
2095
+ if (nav?.entityName && nav.recordKey != null) {
2096
+ void this.loadAndShowRecordInDetailPanel(nav.entityName, String(nav.recordKey));
3538
2097
  }
3539
- this.cdr.detectChanges();
3540
- }
3541
- /**
3542
- * Handle cancellation of the list management dialog
3543
- */
3544
- onListManagementCancel() {
3545
- this.showListManagementDialog = false;
3546
- this.listManagementConfig = null;
3547
- this.cdr.detectChanges();
3548
2098
  }
3549
- static ɵfac = function DataExplorerDashboardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DataExplorerDashboardComponent)(i0.ɵɵdirectiveInject(i1.ExplorerStateService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i2.RecentAccessService), i0.ɵɵdirectiveInject(i3.ExportService), i0.ɵɵdirectiveInject(i0.NgZone)); };
2099
+ static ɵfac = function DataExplorerDashboardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DataExplorerDashboardComponent)(i0.ɵɵdirectiveInject(i1.ExplorerStateService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i2.RecentAccessService), i0.ɵɵdirectiveInject(i0.NgZone)); };
3550
2100
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DataExplorerDashboardComponent, selectors: [["mj-data-explorer-dashboard"]], viewQuery: function DataExplorerDashboardComponent_Query(rf, ctx) { if (rf & 1) {
3551
- i0.ɵɵviewQuery(_c0, 5)(ViewSelectorComponent, 5)(EntityViewerComponent, 5)(ViewConfigPanelComponent, 5);
2101
+ i0.ɵɵviewQuery(_c0, 5)(ViewWorkspaceComponent, 5);
3552
2102
  } if (rf & 2) {
3553
2103
  let _t;
3554
2104
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.filterInputRef = _t.first);
3555
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.viewSelectorRef = _t.first);
3556
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.entityViewerRef = _t.first);
3557
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.viewConfigPanelRef = _t.first);
2105
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.viewWorkspaceRef = _t.first);
3558
2106
  } }, hostBindings: function DataExplorerDashboardComponent_HostBindings(rf, ctx) { if (rf & 1) {
3559
2107
  i0.ɵɵlistener("keydown", function DataExplorerDashboardComponent_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, i0.ɵɵresolveDocument);
3560
- } }, inputs: { entityFilter: "entityFilter", deepLink: "deepLink", contextName: "contextName", contextIcon: "contextIcon", initialQueryParams: "initialQueryParams" }, outputs: { DisplayNameChanged: "DisplayNameChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 24, vars: 40, consts: [["filterInput", ""], ["entityViewer", ""], [1, "data-explorer-container"], [1, "navigation-panel", 3, "collapsed", "width"], [1, "content-area"], [1, "breadcrumb-bar"], [1, "content-header"], [1, "header-left"], [1, "header-center"], [1, "smart-filter-container"], [1, "header-right"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "active"], [1, "content-body"], [1, "home-view-concept-d"], [3, "entity", "viewEntity", "viewMode", "filterText", "selectedRecordId", "config", "gridState", "timelineConfig", "gridSelectionMode", "showGridToolbar", "showAddToListButton", "mapRenderMode", "mapDisplayState"], [1, "detail-panel", 3, "width"], [3, "close", "save", "saveDefaults", "delete", "duplicate", "openFilterDialogRequest", "entity", "viewEntity", "isOpen", "currentGridState", "externalFilterState", "isSaving", "DefaultSaveAsNew", "PendingNewViewName", "PendingNewViewDescription", "PendingNewViewIsShared"], [3, "close", "apply", "isOpen", "fields", "filter", "disabled"], [3, "closed", "visible", "config"], [3, "config", "visible"], [3, "Save", "Close", "OpenAdvanced", "IsOpen", "ViewEntity", "EntityName", "Summary", "IsSaving", "DefaultSaveAsNew"], [3, "Duplicate", "Cancel", "IsOpen", "SourceViewName", "Summary"], [3, "Action", "Cancel", "IsOpen", "ViewName"], [1, "navigation-panel"], [3, "entitySelected", "toggleCollapse", "sectionToggled", "openRecord", "selectRecord", "expandAndFocus", "entities", "appEntityGroups", "selectedEntityName", "favorites", "recentItems", "collapsed", "allowedEntityNames", "favoritesSectionExpanded", "recentSectionExpanded", "entitiesSectionExpanded", "viewsSectionExpanded"], [1, "breadcrumb-item", 3, "click", "title"], [1, "breadcrumb-icon", 3, "class"], [1, "breadcrumb-label"], [1, "fa-solid", "fa-chevron-right", "breadcrumb-separator"], [1, "breadcrumb-icon"], [1, "entity-icon"], [1, "entity-title"], [1, "record-count"], [3, "viewSelected", "saveViewRequested", "manageViewsRequested", "openInTabRequested", "configureViewRequested", "createNewRecordRequested", "exportRequested", "duplicateViewRequested", "quickSaveRequested", "revertRequested", "entity", "selectedViewId", "viewModified"], [1, "header-action-btn", 3, "click", "disabled", "title"], [1, "fa-solid", "fa-list-check"], [1, "selection-badge"], [1, "entity-icon", 3, "class"], [1, "fa-solid", "fa-search", "filter-icon"], ["type", "text", "placeholder", "Filter records... (press / to focus)", 1, "smart-filter-input", 3, "input", "value"], [1, "clear-filter-btn"], [1, "clear-filter-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "view-specific-controls"], [1, "view-mode-toggle"], ["title", "Grid View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-list"], ["title", "Cards View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-grip"], ["title", "Timeline View", 1, "toggle-btn", 3, "active"], ["title", "Map View", 1, "toggle-btn", 3, "active"], [1, "date-field-selector-container"], [1, "date-field-backdrop"], [1, "date-field-selector-wrapper"], [1, "date-field-selector-button", 3, "click", "disabled"], [1, "fa-solid", "fa-calendar-days", "date-field-icon"], [1, "date-field-name"], [1, "fa-solid", "fa-chevron-down", "date-field-arrow", 3, "rotated"], [1, "date-field-dropdown-panel"], [1, "view-specific-btn", 3, "click", "title"], [1, "date-field-backdrop", 3, "click"], [1, "fa-solid", "fa-chevron-down", "date-field-arrow"], [1, "date-field-dropdown-item", 3, "selected"], [1, "date-field-dropdown-item", 3, "click"], [1, "fa-regular", "fa-calendar", "item-icon"], [1, "item-name"], [1, "fa-solid", "fa-check", "selected-check"], ["title", "Timeline View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-timeline"], ["title", "Map View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-map-location-dot"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "qa-badge"], [1, "loading-state"], ["text", "Loading entities...", "size", "medium"], [1, "home-main-area"], [1, "search-hero"], [1, "search-hero-container"], [1, "fa-solid", "fa-magnifying-glass", "search-hero-icon"], ["type", "text", "placeholder", "Search entities...", 1, "search-hero-input", 3, "ngModelChange", "ngModel"], [1, "search-hero-clear"], [1, "search-hero-shortcut"], [1, "search-meta-row"], [1, "search-entity-count"], [1, "pill-toggle"], [1, "pill-btn", 3, "click"], [1, "fa-solid", "fa-star"], [1, "entity-groups-area"], [1, "entity-item-grid"], [1, "home-no-results"], [1, "empty-state"], [1, "quick-access-panel"], [1, "qa-header"], [1, "qa-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "qa-body"], [1, "qa-section"], [1, "qa-section-header", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left", "qa-section-icon"], [1, "qa-section-count"], [1, "fa-solid", "fa-chevron-down", "qa-section-chevron"], [1, "qa-section-body"], [1, "qa-item"], [1, "qa-empty"], [1, "fa-solid", "fa-table", "qa-section-icon"], [1, "fa-solid", "fa-star", "qa-section-icon", 2, "color", "var(--mj-status-warning)"], [1, "search-hero-clear", 3, "click"], [1, "entity-item", 3, "title"], [1, "entity-item", 3, "click", "title"], [1, "entity-item-icon"], [1, "entity-item-text"], [1, "entity-item-name"], [1, "entity-item-desc"], [1, "entity-item-fav", 3, "click", "title"], [1, "app-group"], [1, "app-group-header", 3, "click"], [1, "app-group-icon"], [1, "app-group-name"], [1, "app-group-count"], [1, "fa-solid", "fa-chevron-right", "app-group-chevron"], [1, "app-group-entities"], [1, "fa-solid", "fa-magnifying-glass"], [1, "fa-solid", "fa-database", "empty-icon"], [1, "qa-item", 3, "click"], [1, "qa-item-icon"], [1, "qa-item-info"], [1, "qa-item-name"], [1, "qa-item-meta"], [1, "qa-item-time"], [3, "viewModeChange", "filterTextChange", "recordSelected", "recordOpened", "dataLoaded", "filteredCountChanged", "gridStateChanged", "selectionChanged", "addToListRequested", "mapRenderModeChange", "mapDisplayStateChange", "entity", "viewEntity", "viewMode", "filterText", "selectedRecordId", "config", "gridState", "timelineConfig", "gridSelectionMode", "showGridToolbar", "showAddToListButton", "mapRenderMode", "mapDisplayState"], [1, "detail-panel"], [1, "detail-panel-actions"], ["title", "Add to List", 1, "detail-action-btn", 3, "click"], [3, "close", "openRecord", "navigateToRelated", "openRelatedRecord", "openForeignKeyRecord", "entity", "record"], [3, "complete", "cancel", "config", "visible"]], template: function DataExplorerDashboardComponent_Template(rf, ctx) { if (rf & 1) {
3561
- i0.ɵɵelementStart(0, "div", 2);
3562
- i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_1_Template, 2, 16, "div", 3);
3563
- i0.ɵɵelementStart(2, "div", 4);
3564
- i0.ɵɵconditionalCreate(3, DataExplorerDashboardComponent_Conditional_3_Template, 3, 0, "div", 5);
3565
- i0.ɵɵelementStart(4, "div", 6)(5, "div", 7);
3566
- i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_6_Template, 9, 12)(7, DataExplorerDashboardComponent_Conditional_7_Template, 5, 3);
2108
+ } }, inputs: { entityFilter: "entityFilter", deepLink: "deepLink", contextName: "contextName", contextIcon: "contextIcon", initialQueryParams: "initialQueryParams" }, outputs: { DisplayNameChanged: "DisplayNameChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 17, vars: 12, consts: [["filterInput", ""], [1, "data-explorer-container"], [1, "navigation-panel", 3, "collapsed", "width"], [1, "content-area"], [1, "breadcrumb-bar"], [1, "content-header"], [1, "header-left"], [1, "header-center"], [1, "smart-filter-container"], [1, "header-right"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "active"], [1, "content-body"], [1, "home-view-concept-d"], [3, "Entity", "AutoSaveView", "SelectedView", "FilterText", "SelectedRecordId", "ViewerConfig"], [1, "detail-panel", 3, "width"], [1, "navigation-panel"], [3, "entitySelected", "toggleCollapse", "sectionToggled", "openRecord", "selectRecord", "expandAndFocus", "entities", "appEntityGroups", "selectedEntityName", "favorites", "recentItems", "collapsed", "allowedEntityNames", "favoritesSectionExpanded", "recentSectionExpanded", "entitiesSectionExpanded", "viewsSectionExpanded"], [1, "breadcrumb-item", 3, "click", "title"], [1, "breadcrumb-icon", 3, "class"], [1, "breadcrumb-label"], [1, "fa-solid", "fa-chevron-right", "breadcrumb-separator"], [1, "breadcrumb-icon"], [1, "entity-icon"], [1, "entity-title"], [1, "record-count"], [1, "entity-icon", 3, "class"], [1, "fa-solid", "fa-search", "filter-icon"], ["type", "text", "placeholder", "Filter records... (press / to focus)", 1, "smart-filter-input", 3, "input", "value"], [1, "clear-filter-btn"], [1, "clear-filter-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "qa-badge"], [1, "loading-state"], ["text", "Loading entities...", "size", "medium"], [1, "home-main-area"], [1, "search-hero"], [1, "search-hero-container"], [1, "fa-solid", "fa-magnifying-glass", "search-hero-icon"], ["type", "text", "placeholder", "Search entities...", 1, "search-hero-input", 3, "ngModelChange", "ngModel"], [1, "search-hero-clear"], [1, "search-hero-shortcut"], [1, "search-meta-row"], [1, "search-entity-count"], [1, "pill-toggle"], [1, "pill-btn", 3, "click"], [1, "fa-solid", "fa-star"], [1, "entity-groups-area"], [1, "entity-item-grid"], [1, "home-no-results"], [1, "empty-state"], [1, "quick-access-panel"], [1, "qa-header"], [1, "qa-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "qa-body"], [1, "qa-section"], [1, "qa-section-header", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left", "qa-section-icon"], [1, "qa-section-count"], [1, "fa-solid", "fa-chevron-down", "qa-section-chevron"], [1, "qa-section-body"], [1, "qa-item"], [1, "qa-empty"], [1, "fa-solid", "fa-table", "qa-section-icon"], [1, "fa-solid", "fa-star", "qa-section-icon", 2, "color", "var(--mj-status-warning)"], [1, "search-hero-clear", 3, "click"], [1, "entity-item", 3, "title"], [1, "entity-item", 3, "click", "title"], [1, "entity-item-icon"], [1, "entity-item-text"], [1, "entity-item-name"], [1, "entity-item-desc"], [1, "entity-item-fav", 3, "click", "title"], [1, "app-group"], [1, "app-group-header", 3, "click"], [1, "app-group-icon"], [1, "app-group-name"], [1, "app-group-count"], [1, "fa-solid", "fa-chevron-right", "app-group-chevron"], [1, "app-group-entities"], [1, "fa-solid", "fa-magnifying-glass"], [1, "fa-solid", "fa-database", "empty-icon"], [1, "qa-item", 3, "click"], [1, "qa-item-icon"], [1, "qa-item-info"], [1, "qa-item-name"], [1, "qa-item-meta"], [1, "qa-item-time"], [3, "SelectedViewChange", "ViewSelected", "OpenViewInTabRequested", "OpenRecordRequested", "OpenRelatedRecordRequested", "CreateNewRecordRequested", "RecordSelected", "AfterViewSave", "AfterViewDelete", "FilterTextChanged", "DataLoaded", "FilteredCountChanged", "Entity", "AutoSaveView", "SelectedView", "FilterText", "SelectedRecordId", "ViewerConfig"], [1, "detail-panel"], [3, "close", "openRecord", "navigateToRelated", "openRelatedRecord", "openForeignKeyRecord", "entity", "record"]], template: function DataExplorerDashboardComponent_Template(rf, ctx) { if (rf & 1) {
2109
+ i0.ɵɵelementStart(0, "div", 1);
2110
+ i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_1_Template, 2, 16, "div", 2);
2111
+ i0.ɵɵelementStart(2, "div", 3);
2112
+ i0.ɵɵconditionalCreate(3, DataExplorerDashboardComponent_Conditional_3_Template, 3, 0, "div", 4);
2113
+ i0.ɵɵelementStart(4, "div", 5)(5, "div", 6);
2114
+ i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_6_Template, 5, 4)(7, DataExplorerDashboardComponent_Conditional_7_Template, 5, 3);
3567
2115
  i0.ɵɵelementEnd();
3568
- i0.ɵɵelementStart(8, "div", 8);
3569
- i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_9_Template, 5, 2, "div", 9);
2116
+ i0.ɵɵelementStart(8, "div", 7);
2117
+ i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_9_Template, 5, 2, "div", 8);
3570
2118
  i0.ɵɵelementEnd();
3571
- i0.ɵɵelementStart(10, "div", 10);
3572
- i0.ɵɵconditionalCreate(11, DataExplorerDashboardComponent_Conditional_11_Template, 8, 7);
3573
- i0.ɵɵconditionalCreate(12, DataExplorerDashboardComponent_Conditional_12_Template, 3, 3, "button", 11);
2119
+ i0.ɵɵelementStart(10, "div", 9);
2120
+ i0.ɵɵconditionalCreate(11, DataExplorerDashboardComponent_Conditional_11_Template, 0, 0);
2121
+ i0.ɵɵconditionalCreate(12, DataExplorerDashboardComponent_Conditional_12_Template, 3, 3, "button", 10);
3574
2122
  i0.ɵɵelementEnd()();
3575
- i0.ɵɵelementStart(13, "div", 12);
3576
- i0.ɵɵconditionalCreate(14, DataExplorerDashboardComponent_Conditional_14_Template, 3, 1, "div", 13)(15, DataExplorerDashboardComponent_Conditional_15_Template, 2, 13, "mj-entity-viewer", 14);
2123
+ i0.ɵɵelementStart(13, "div", 11);
2124
+ i0.ɵɵconditionalCreate(14, DataExplorerDashboardComponent_Conditional_14_Template, 3, 1, "div", 12)(15, DataExplorerDashboardComponent_Conditional_15_Template, 1, 6, "mj-view-workspace", 13);
3577
2125
  i0.ɵɵelementEnd()();
3578
- i0.ɵɵconditionalCreate(16, DataExplorerDashboardComponent_Conditional_16_Template, 7, 4, "div", 15);
3579
- i0.ɵɵelementStart(17, "mj-view-config-panel", 16);
3580
- i0.ɵɵlistener("close", function DataExplorerDashboardComponent_Template_mj_view_config_panel_close_17_listener() { return ctx.onCloseViewConfigPanel(); })("save", function DataExplorerDashboardComponent_Template_mj_view_config_panel_save_17_listener($event) { return ctx.onSaveView($event); })("saveDefaults", function DataExplorerDashboardComponent_Template_mj_view_config_panel_saveDefaults_17_listener($event) { return ctx.onSaveDefaultViewSettings($event); })("delete", function DataExplorerDashboardComponent_Template_mj_view_config_panel_delete_17_listener() { return ctx.onDeleteView(); })("duplicate", function DataExplorerDashboardComponent_Template_mj_view_config_panel_duplicate_17_listener() { return ctx.onDuplicateFromPanel(); })("openFilterDialogRequest", function DataExplorerDashboardComponent_Template_mj_view_config_panel_openFilterDialogRequest_17_listener($event) { return ctx.onOpenFilterDialogRequest($event); });
3581
- i0.ɵɵelementEnd();
3582
- i0.ɵɵelementStart(18, "mj-filter-dialog", 17);
3583
- i0.ɵɵlistener("close", function DataExplorerDashboardComponent_Template_mj_filter_dialog_close_18_listener() { return ctx.onCloseFilterDialog(); })("apply", function DataExplorerDashboardComponent_Template_mj_filter_dialog_apply_18_listener($event) { return ctx.onFilterApplied($event); });
3584
- i0.ɵɵelementEnd();
3585
- i0.ɵɵelementStart(19, "mj-export-dialog", 18);
3586
- i0.ɵɵlistener("closed", function DataExplorerDashboardComponent_Template_mj_export_dialog_closed_19_listener($event) { return ctx.onExportDialogClosed($event); });
2126
+ i0.ɵɵconditionalCreate(16, DataExplorerDashboardComponent_Conditional_16_Template, 2, 4, "div", 14);
3587
2127
  i0.ɵɵelementEnd();
3588
- i0.ɵɵconditionalCreate(20, DataExplorerDashboardComponent_Conditional_20_Template, 1, 2, "mj-list-management-dialog", 19);
3589
- i0.ɵɵelementStart(21, "mj-quick-save-dialog", 20);
3590
- i0.ɵɵlistener("Save", function DataExplorerDashboardComponent_Template_mj_quick_save_dialog_Save_21_listener($event) { return ctx.onQuickSave($event); })("Close", function DataExplorerDashboardComponent_Template_mj_quick_save_dialog_Close_21_listener() { return ctx.onQuickSaveClose(); })("OpenAdvanced", function DataExplorerDashboardComponent_Template_mj_quick_save_dialog_OpenAdvanced_21_listener($event) { return ctx.onQuickSaveOpenAdvanced($event); });
3591
- i0.ɵɵelementEnd();
3592
- i0.ɵɵelementStart(22, "mj-duplicate-view-dialog", 21);
3593
- i0.ɵɵlistener("Duplicate", function DataExplorerDashboardComponent_Template_mj_duplicate_view_dialog_Duplicate_22_listener($event) { return ctx.onDuplicateConfirmed($event); })("Cancel", function DataExplorerDashboardComponent_Template_mj_duplicate_view_dialog_Cancel_22_listener() { return ctx.onDuplicateCancel(); });
3594
- i0.ɵɵelementEnd();
3595
- i0.ɵɵelementStart(23, "mj-shared-view-warning-dialog", 22);
3596
- i0.ɵɵlistener("Action", function DataExplorerDashboardComponent_Template_mj_shared_view_warning_dialog_Action_23_listener($event) { return ctx.onSharedViewAction($event); })("Cancel", function DataExplorerDashboardComponent_Template_mj_shared_view_warning_dialog_Cancel_23_listener() { return ctx.onSharedViewWarningCancel(); });
3597
- i0.ɵɵelementEnd()();
3598
2128
  } if (rf & 2) {
3599
2129
  i0.ɵɵadvance();
3600
2130
  i0.ɵɵconditional(!ctx.isAtHomeLevel ? 1 : -1);
@@ -3616,21 +2146,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
3616
2146
  i0.ɵɵconditional(!ctx.selectedEntity ? 14 : 15);
3617
2147
  i0.ɵɵadvance(2);
3618
2148
  i0.ɵɵconditional(ctx.state.detailPanelOpen && ctx.selectedRecord ? 16 : -1);
3619
- i0.ɵɵadvance();
3620
- i0.ɵɵproperty("entity", ctx.selectedEntity)("viewEntity", ctx.selectedViewEntity)("isOpen", ctx.state.viewConfigPanelOpen)("currentGridState", ctx.currentGridState)("externalFilterState", ctx.filterDialogState)("isSaving", ctx.isSavingView)("DefaultSaveAsNew", ctx.defaultSaveAsNew)("PendingNewViewName", ctx.pendingNewViewName)("PendingNewViewDescription", ctx.pendingNewViewDescription)("PendingNewViewIsShared", ctx.pendingNewViewIsShared);
3621
- i0.ɵɵadvance();
3622
- i0.ɵɵproperty("isOpen", ctx.isFilterDialogOpen)("fields", ctx.filterDialogFields)("filter", ctx.filterDialogState)("disabled", ctx.filterDialogDisabled);
3623
- i0.ɵɵadvance();
3624
- i0.ɵɵproperty("visible", ctx.showExportDialog)("config", ctx.exportDialogConfig);
3625
- i0.ɵɵadvance();
3626
- i0.ɵɵconditional(ctx.showListManagementDialog && ctx.listManagementConfig ? 20 : -1);
3627
- i0.ɵɵadvance();
3628
- i0.ɵɵproperty("IsOpen", ctx.showQuickSaveDialog)("ViewEntity", ctx.selectedViewEntity)("EntityName", (ctx.selectedEntity == null ? null : ctx.selectedEntity.DisplayNameOrName) ?? "")("Summary", ctx.quickSaveSummary)("IsSaving", ctx.isSavingView)("DefaultSaveAsNew", ctx.defaultSaveAsNew);
3629
- i0.ɵɵadvance();
3630
- i0.ɵɵproperty("IsOpen", ctx.showDuplicateDialog)("SourceViewName", ctx.duplicateSourceViewName)("Summary", ctx.duplicateSummary);
3631
- i0.ɵɵadvance();
3632
- i0.ɵɵproperty("IsOpen", ctx.showSharedViewWarning)("ViewName", (ctx.selectedViewEntity == null ? null : ctx.selectedViewEntity.Name) ?? "");
3633
- } }, dependencies: [i4.DefaultValueAccessor, i4.NgControlStatus, i4.NgModel, i5.EntityViewerComponent, i5.EntityRecordDetailPanelComponent, i5.ViewConfigPanelComponent, i5.QuickSaveDialogComponent, i5.DuplicateViewDialogComponent, i5.SharedViewWarningDialogComponent, i2.LoadingComponent, i3.ExportDialogComponent, i6.ListManagementDialogComponent, i7.NavigationPanelComponent, i8.ViewSelectorComponent, i9.FilterDialogComponent, i10.DecimalPipe], styles: [".data-explorer-container[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed[_ngcontent-%COMP%] {\n width: 48px;\n}\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n\n\n.breadcrumb-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; \n\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n\n\n.header-left[_ngcontent-%COMP%] mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n\n\n.header-action-btn[_ngcontent-%COMP%] {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn[_ngcontent-%COMP%]:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n.selection-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n\n.date-field-selector-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .selected-check[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n\n\n\n.view-specific-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.view-specific-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n display: flex;\n flex-direction: column;\n}\n\n.loading-container[_ngcontent-%COMP%], \n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 40px;\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n font-size: 64px;\n color: var(--mj-border-default);\n margin-bottom: 24px;\n}\n\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n\n.home-view-concept-d[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 320px;\n}\n\n\n\n\n\n\n.search-hero[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container[_ngcontent-%COMP%] {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n\n\n.search-meta-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%] {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n\n\n\n\n.entity-groups-area[_ngcontent-%COMP%] {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n}\n\n.app-group-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon[_ngcontent-%COMP%] {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name[_ngcontent-%COMP%] {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.app-group-entities[_ngcontent-%COMP%] {\n padding: 4px 14px 10px 60px;\n}\n\n\n\n\n\n\n.entity-item-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-fav[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.entity-item-fav.favorited[_ngcontent-%COMP%] {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n\n\n\n\n\n.quick-access-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.qa-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-section[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n user-select: none;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-count[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n margin-left: auto;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-chevron[_ngcontent-%COMP%] {\n font-size: 10px;\n transition: transform 0.15s;\n}\n\n.qa-section.collapsed[_ngcontent-%COMP%] .qa-section-chevron[_ngcontent-%COMP%] {\n transform: rotate(-90deg);\n}\n\n.qa-section-body[_ngcontent-%COMP%] {\n padding: 0 8px 8px;\n}\n\n.qa-section.collapsed[_ngcontent-%COMP%] .qa-section-body[_ngcontent-%COMP%] {\n display: none;\n}\n\n.qa-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty[_ngcontent-%COMP%] {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n\n\n.qa-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n\n\n.home-no-results[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.home-no-results[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n margin-bottom: 10px;\n display: block;\n}\n\n.home-no-results[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin: 0;\n}\n\n.detail-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel[_ngcontent-%COMP%] mj-entity-record-detail-panel[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes _ngcontent-%COMP%_slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n\n\n.detail-panel-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n[_nghost-%COMP%] mj-explorer-grid-view, \n[_nghost-%COMP%] mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n\n\n\n\n\n\n\n.content-header.home-header[_ngcontent-%COMP%] {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n\n\n.filter-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] .smart-filter-input[_ngcontent-%COMP%] {\n padding-left: 40px;\n}\n\n\n\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] .toggle-btn[_ngcontent-%COMP%] {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n}\n\n\n\n\n\n\n.empty-state.small[_ngcontent-%COMP%] {\n height: auto;\n padding: 32px;\n background: var(--mj-bg-surface-card);\n}\n\n.empty-state.small[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 40px;\n margin-bottom: 16px;\n}\n\n.empty-state.small[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.empty-state.small[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n@media (max-width: 1200px) {\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center[_ngcontent-%COMP%] {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero[_ngcontent-%COMP%] {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area[_ngcontent-%COMP%] {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities[_ngcontent-%COMP%] {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 0;\n }\n\n .quick-access-panel[_ngcontent-%COMP%] {\n width: 100%;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .navigation-panel[_ngcontent-%COMP%] {\n display: none;\n }\n\n .content-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .content-body[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n\n .app-group-name[_ngcontent-%COMP%] {\n font-size: 17px;\n }\n\n .entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}"], data: { animation: [
2149
+ } }, dependencies: [i3.DefaultValueAccessor, i3.NgControlStatus, i3.NgModel, i4.EntityRecordDetailPanelComponent, i4.ViewWorkspaceComponent, i2.LoadingComponent, i5.NavigationPanelComponent, i6.DecimalPipe], styles: [".data-explorer-container[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed[_ngcontent-%COMP%] {\n width: 48px;\n}\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n\n\n.breadcrumb-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; \n\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n\n\n.header-left[_ngcontent-%COMP%] mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n\n\n.header-action-btn[_ngcontent-%COMP%] {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn[_ngcontent-%COMP%]:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n.selection-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n\n.date-field-selector-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .selected-check[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n\n\n\n.view-specific-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.view-specific-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n display: flex;\n flex-direction: column;\n \n\n\n\n\n\n\n\n\n isolation: isolate;\n}\n\n.loading-container[_ngcontent-%COMP%], \n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 40px;\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n font-size: 64px;\n color: var(--mj-border-default);\n margin-bottom: 24px;\n}\n\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n\n.home-view-concept-d[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 320px;\n}\n\n\n\n\n\n\n.search-hero[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container[_ngcontent-%COMP%] {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n\n\n.search-meta-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%] {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n\n\n\n\n.entity-groups-area[_ngcontent-%COMP%] {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n}\n\n.app-group-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon[_ngcontent-%COMP%] {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name[_ngcontent-%COMP%] {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.app-group-entities[_ngcontent-%COMP%] {\n padding: 4px 14px 10px 60px;\n}\n\n\n\n\n\n\n.entity-item-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-fav[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.entity-item-fav.favorited[_ngcontent-%COMP%] {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n\n\n\n\n\n.quick-access-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.qa-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-section[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n user-select: none;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-count[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n margin-left: auto;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-chevron[_ngcontent-%COMP%] {\n font-size: 10px;\n transition: transform 0.15s;\n}\n\n.qa-section.collapsed[_ngcontent-%COMP%] .qa-section-chevron[_ngcontent-%COMP%] {\n transform: rotate(-90deg);\n}\n\n.qa-section-body[_ngcontent-%COMP%] {\n padding: 0 8px 8px;\n}\n\n.qa-section.collapsed[_ngcontent-%COMP%] .qa-section-body[_ngcontent-%COMP%] {\n display: none;\n}\n\n.qa-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty[_ngcontent-%COMP%] {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n\n\n.qa-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n\n\n.home-no-results[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.home-no-results[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n margin-bottom: 10px;\n display: block;\n}\n\n.home-no-results[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin: 0;\n}\n\n.detail-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel[_ngcontent-%COMP%] mj-entity-record-detail-panel[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes _ngcontent-%COMP%_slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n\n\n.detail-panel-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n[_nghost-%COMP%] mj-explorer-grid-view, \n[_nghost-%COMP%] mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n\n\n\n\n\n\n\n.content-header.home-header[_ngcontent-%COMP%] {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n\n\n.filter-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] .smart-filter-input[_ngcontent-%COMP%] {\n padding-left: 40px;\n}\n\n\n\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] .toggle-btn[_ngcontent-%COMP%] {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n}\n\n\n\n\n\n\n.empty-state.small[_ngcontent-%COMP%] {\n height: auto;\n padding: 32px;\n background: var(--mj-bg-surface-card);\n}\n\n.empty-state.small[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 40px;\n margin-bottom: 16px;\n}\n\n.empty-state.small[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.empty-state.small[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n@media (max-width: 1200px) {\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center[_ngcontent-%COMP%] {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero[_ngcontent-%COMP%] {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area[_ngcontent-%COMP%] {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities[_ngcontent-%COMP%] {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 0;\n }\n\n .quick-access-panel[_ngcontent-%COMP%] {\n width: 100%;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .navigation-panel[_ngcontent-%COMP%] {\n display: none;\n }\n\n .content-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .content-body[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n\n .app-group-name[_ngcontent-%COMP%] {\n font-size: 17px;\n }\n\n .entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}"], data: { animation: [
3634
2150
  trigger('slideInLeft', [
3635
2151
  transition(':enter', [
3636
2152
  style({ transform: 'translateX(-100%)', opacity: 0 }),
@@ -3658,19 +2174,13 @@ export { DataExplorerDashboardComponent };
3658
2174
  animate('200ms ease-in', style({ transform: 'translateX(-100%)', opacity: 0 }))
3659
2175
  ])
3660
2176
  ])
3661
- ], template: "<div class=\"data-explorer-container\">\n <!-- Navigation Panel (Left) - Hidden at home level, animated -->\n @if (!isAtHomeLevel) {\n <div\n class=\"navigation-panel\"\n [class.collapsed]=\"state.navigationPanelCollapsed\"\n [style.width.px]=\"state.navigationPanelCollapsed ? 48 : state.navigationPanelWidth\"\n [@slideInLeft]>\n\n <mj-explorer-navigation-panel\n [entities]=\"entities\"\n [appEntityGroups]=\"appEntityGroups\"\n [selectedEntityName]=\"state.selectedEntityName\"\n [favorites]=\"state.favorites\"\n [recentItems]=\"state.recentItems\"\n [collapsed]=\"state.navigationPanelCollapsed\"\n [allowedEntityNames]=\"allowedEntityNames\"\n [favoritesSectionExpanded]=\"state.favoritesSectionExpanded\"\n [recentSectionExpanded]=\"state.recentSectionExpanded\"\n [entitiesSectionExpanded]=\"state.entitiesSectionExpanded\"\n [viewsSectionExpanded]=\"state.viewsSectionExpanded\"\n (entitySelected)=\"onEntitySelected($event)\"\n (toggleCollapse)=\"toggleNavigationPanel()\"\n (sectionToggled)=\"stateService.toggleSection($event)\"\n (openRecord)=\"onOpenRecordFromNav($event)\"\n (selectRecord)=\"onSelectRecordFromNav($event)\"\n (expandAndFocus)=\"onExpandAndFocus($event)\">\n </mj-explorer-navigation-panel>\n </div>\n }\n\n <!-- Main Content Area -->\n <div class=\"content-area\">\n <!-- Breadcrumb Bar - Hidden at home level -->\n @if (!isAtHomeLevel && breadcrumbs.length > 0) {\n <div class=\"breadcrumb-bar\">\n @for (crumb of breadcrumbs; track crumb.label; let i = $index; let last = $last) {\n <span\n class=\"breadcrumb-item\"\n [class.clickable]=\"!last\"\n [class.current]=\"last\"\n (click)=\"onBreadcrumbClick(crumb, i)\"\n [title]=\"crumb.label\">\n @if (crumb.icon) {\n <i [class]=\"crumb.icon\" class=\"breadcrumb-icon\"></i>\n }\n <span class=\"breadcrumb-label\">{{ crumb.label }}</span>\n </span>\n @if (!last) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n }\n }\n </div>\n }\n\n <!-- Header -->\n <div class=\"content-header\" [class.home-header]=\"isAtHomeLevel\">\n <div class=\"header-left\">\n @if (selectedEntity) {\n <i [class]=\"getEntityIcon(selectedEntity)\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ selectedEntity.DisplayNameOrName }}</h2>\n @if (debouncedFilterText && filteredRecordCount !== totalRecordCount) {\n <span class=\"record-count\">{{ filteredRecordCount | number }} of {{ totalRecordCount | number }} records</span>\n } @else {\n <span class=\"record-count\">{{ totalRecordCount | number }} records</span>\n }\n\n <!-- View Selector -->\n <mj-view-selector\n [entity]=\"selectedEntity\"\n [selectedViewId]=\"state.selectedViewId\"\n [viewModified]=\"state.viewModified\"\n (viewSelected)=\"onViewSelected($event)\"\n (saveViewRequested)=\"onSaveViewRequested($event)\"\n (manageViewsRequested)=\"onManageViewsRequested()\"\n (openInTabRequested)=\"onOpenInTabRequested($event)\"\n (configureViewRequested)=\"onConfigureViewRequested()\"\n (createNewRecordRequested)=\"onCreateNewRecord()\"\n (exportRequested)=\"onExport()\"\n (duplicateViewRequested)=\"onDuplicateView($event)\"\n (quickSaveRequested)=\"onQuickSaveRequested($event)\"\n (revertRequested)=\"onRevertView()\">\n </mj-view-selector>\n\n <!-- Add to List Button -->\n <button\n class=\"header-action-btn\"\n [class.disabled]=\"!hasSelectedRecords\"\n [disabled]=\"!hasSelectedRecords\"\n (click)=\"onAddToListClick()\"\n [title]=\"hasSelectedRecords ? 'Add ' + selectedRecords.length + ' selected record(s) to a list' : 'Select records to add to a list'\">\n <i class=\"fa-solid fa-list-check\"></i>\n @if (hasSelectedRecords) {\n <span class=\"selection-badge\">{{ selectedRecords.length }}</span>\n }\n </button>\n } @else {\n @if (displayIcon) {\n <i [class]=\"displayIcon\" class=\"entity-icon\"></i>\n }\n <h2 class=\"entity-title\">{{ displayTitle }}</h2>\n <span class=\"record-count\">{{ entities.length }} entities available</span>\n }\n </div>\n\n <div class=\"header-center\">\n @if (selectedEntity) {\n <div class=\"smart-filter-container\">\n <i class=\"fa-solid fa-search filter-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"smart-filter-input\"\n placeholder=\"Filter records... (press / to focus)\"\n [value]=\"liveFilterText\"\n (input)=\"onFilterInputChanged(filterInput.value)\"\n />\n @if (liveFilterText) {\n <button class=\"clear-filter-btn\" (click)=\"clearRecordFilter()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n <!-- Home-level search moved to search hero section -->\n </div>\n\n <div class=\"header-right\">\n @if (selectedEntity) {\n <!-- View-specific controls \u2014 positioned LEFT of the view mode toggle -->\n <!-- These controls are contextual to the active view mode -->\n @if (state.viewMode === 'timeline' && entityHasDateFields) {\n <div class=\"view-specific-controls\">\n <!-- Date Field Selector -->\n <div class=\"date-field-selector-container\">\n @if (isDateFieldDropdownOpen) {\n <div class=\"date-field-backdrop\" (click)=\"closeDateFieldDropdown()\"></div>\n }\n <div class=\"date-field-selector-wrapper\">\n <button\n class=\"date-field-selector-button\"\n [class.open]=\"isDateFieldDropdownOpen\"\n [disabled]=\"availableDateFields.length <= 1\"\n (click)=\"toggleDateFieldDropdown()\">\n <i class=\"fa-solid fa-calendar-days date-field-icon\"></i>\n <span class=\"date-field-name\">{{ effectiveTimelineDateFieldDisplayName }}</span>\n @if (availableDateFields.length > 1) {\n <i class=\"fa-solid fa-chevron-down date-field-arrow\" [class.rotated]=\"isDateFieldDropdownOpen\"></i>\n }\n </button>\n @if (isDateFieldDropdownOpen && availableDateFields.length > 1) {\n <div class=\"date-field-dropdown-panel\">\n @for (field of availableDateFields; track field.name) {\n <div\n class=\"date-field-dropdown-item\"\n [class.selected]=\"field.name === effectiveTimelineDateField\"\n (click)=\"setTimelineDateField(field.name)\">\n <i class=\"fa-regular fa-calendar item-icon\"></i>\n <span class=\"item-name\">{{ field.displayName }}</span>\n @if (field.name === effectiveTimelineDateField) {\n <i class=\"fa-solid fa-check selected-check\"></i>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n <!-- Orientation Toggle -->\n <button\n class=\"view-specific-btn\"\n (click)=\"toggleTimelineOrientation()\"\n [title]=\"state.timelineOrientation === 'vertical' ? 'Switch to Horizontal' : 'Switch to Vertical'\">\n <i [class]=\"state.timelineOrientation === 'vertical' ? 'fa-solid fa-ellipsis-vertical' : 'fa-solid fa-ellipsis'\"></i>\n </button>\n <!-- Sort Order Toggle -->\n <button\n class=\"view-specific-btn\"\n (click)=\"toggleTimelineSortOrder()\"\n [title]=\"state.timelineSortOrder === 'desc' ? 'Showing Newest First (click for Oldest First)' : 'Showing Oldest First (click for Newest First)'\">\n <i [class]=\"state.timelineSortOrder === 'desc' ? 'fa-solid fa-arrow-down-wide-short' : 'fa-solid fa-arrow-up-wide-short'\"></i>\n </button>\n </div>\n }\n\n <!-- View Mode Toggle \u2014 always rightmost in the header -->\n <div class=\"view-mode-toggle\">\n <button\n class=\"toggle-btn\"\n [class.active]=\"state.viewMode === 'grid'\"\n (click)=\"onViewModeChanged('grid')\"\n title=\"Grid View\">\n <i class=\"fa-solid fa-list\"></i>\n </button>\n <button\n class=\"toggle-btn\"\n [class.active]=\"state.viewMode === 'cards'\"\n (click)=\"onViewModeChanged('cards')\"\n title=\"Cards View\">\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n @if (entityHasDateFields) {\n <button\n class=\"toggle-btn\"\n [class.active]=\"state.viewMode === 'timeline'\"\n (click)=\"onViewModeChanged('timeline')\"\n title=\"Timeline View\">\n <i class=\"fa-solid fa-timeline\"></i>\n </button>\n }\n @if (selectedEntity.SupportsGeoCoding) {\n <button\n class=\"toggle-btn\"\n [class.active]=\"state.viewMode === 'map'\"\n (click)=\"onViewModeChanged('map')\"\n title=\"Map View\">\n <i class=\"fa-solid fa-map-location-dot\"></i>\n </button>\n }\n </div>\n }\n @if (!selectedEntity) {\n <!-- Quick Access panel toggle -->\n <button\n class=\"header-action-btn\"\n [class.active]=\"state.quickAccessPanelOpen\"\n (click)=\"toggleQuickAccessPanel()\"\n title=\"Recents & Favorites\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n @if (recentRecords.length + favoriteRecords.length > 0) {\n <span class=\"qa-badge\">{{ recentRecords.length + favoriteRecords.length }}</span>\n }\n </button>\n }\n </div>\n </div>\n\n <!-- Content Body - Using mj-entity-viewer composite -->\n <div class=\"content-body\" [class.home-content]=\"isAtHomeLevel\">\n @if (!selectedEntity) {\n <!-- Concept D: Application Groups + Search-First Home View -->\n <div class=\"home-view-concept-d\">\n @if (isLoadingEntities) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading entities...\" size=\"medium\"></mj-loading>\n </div>\n } @else {\n <div class=\"home-main-area\" [class.panel-open]=\"state.quickAccessPanelOpen\">\n <!-- Search Hero -->\n <div class=\"search-hero\">\n <div class=\"search-hero-container\">\n <i class=\"fa-solid fa-magnifying-glass search-hero-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"search-hero-input\"\n placeholder=\"Search entities...\"\n [(ngModel)]=\"entityFilterText\"\n />\n @if (entityFilterText) {\n <button class=\"search-hero-clear\" (click)=\"entityFilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n } @else {\n <span class=\"search-hero-shortcut\">/</span>\n }\n </div>\n\n <!-- Meta row: entity count + All/Favorites pills -->\n <div class=\"search-meta-row\">\n <span class=\"search-entity-count\">\n {{ filteredEntityCount }} entities\n @if (applicationCount > 0) {\n across {{ applicationCount }} applications\n }\n </span>\n <div class=\"pill-toggle\">\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'all'\"\n (click)=\"setHomeViewMode('all')\">\n All Entities\n </button>\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'favorites'\"\n (click)=\"setHomeViewMode('favorites')\">\n <i class=\"fa-solid fa-star\"></i> My Favorites\n </button>\n </div>\n </div>\n </div>\n\n <!-- Entity Groups Area -->\n <div class=\"entity-groups-area\">\n @if (entityFilter?.applicationId) {\n <!-- Single-app mode: flat entity grid (no grouping) -->\n <div class=\"entity-item-grid\">\n @for (entity of flatFilteredEntities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n } @else {\n <!-- Multi-app mode: grouped by application -->\n @for (group of filteredAppEntityGroups; track group.applicationId) {\n <div class=\"app-group\">\n <div class=\"app-group-header\" (click)=\"toggleAppGroup(group.applicationId)\">\n <div\n class=\"app-group-icon\"\n [style.background]=\"group.applicationColor ? group.applicationColor + '15' : null\"\n [style.color]=\"group.applicationColor || null\">\n <i [class]=\"group.applicationIcon || 'fa-solid fa-folder'\"></i>\n </div>\n <span class=\"app-group-name\">{{ group.applicationName }}</span>\n <span class=\"app-group-count\">{{ group.entities.length }}</span>\n <i class=\"fa-solid fa-chevron-right app-group-chevron\"\n [class.expanded]=\"group.isExpanded\"></i>\n </div>\n @if (group.isExpanded) {\n <div class=\"app-group-entities\">\n <div class=\"entity-item-grid\">\n @for (entity of group.entities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- No results -->\n @if (filteredEntityCount === 0 && entities.length > 0) {\n <div class=\"home-no-results\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <p>No entities match \"{{ entityFilterText }}\"</p>\n </div>\n }\n @if (entities.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database empty-icon\"></i>\n <h3>No Entities Available</h3>\n <p>There are no entities configured for this application.</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Quick Access Panel (right slide-in) -->\n <div class=\"quick-access-panel\" [class.open]=\"state.quickAccessPanelOpen\">\n <div class=\"qa-header\">\n <h3>Quick Access</h3>\n <button class=\"qa-close-btn\" (click)=\"toggleQuickAccessPanel()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div class=\"qa-body\">\n <!-- Recent Records (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('recentRecords')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('recentRecords')\">\n <i class=\"fa-solid fa-clock-rotate-left qa-section-icon\"></i>\n <span>Recent Records</span>\n <span class=\"qa-section-count\">{{ quickAccessRecentRecords.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (record of quickAccessRecentRecords; track record.entityId + '|' + record.recordId) {\n <div class=\"qa-item\" (click)=\"onRecentRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ record.entityName }}</div>\n </div>\n <span class=\"qa-item-time\">{{ formatRelativeTime(record.latestAt) }}</span>\n </div>\n }\n @if (quickAccessRecentRecords.length === 0) {\n <div class=\"qa-empty\">No recent records</div>\n }\n </div>\n </div>\n\n <!-- Recent Entities (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('recentEntities')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('recentEntities')\">\n <i class=\"fa-solid fa-table qa-section-icon\"></i>\n <span>Recent Entities</span>\n <span class=\"qa-section-count\">{{ quickAccessRecentEntities.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (entity of quickAccessRecentEntities; track entity.ID) {\n <div class=\"qa-item\" (click)=\"onEntitySelected(entity)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ entity.DisplayNameOrName }}</div>\n </div>\n </div>\n }\n @if (quickAccessRecentEntities.length === 0) {\n <div class=\"qa-empty\">No recent entities</div>\n }\n </div>\n </div>\n\n <!-- Favorite Records (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('favoriteRecords')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('favoriteRecords')\">\n <i class=\"fa-solid fa-star qa-section-icon\" style=\"color: var(--mj-status-warning);\"></i>\n <span>Favorite Records</span>\n <span class=\"qa-section-count\">{{ quickAccessFavoriteRecords.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (record of quickAccessFavoriteRecords; track record.userFavoriteId) {\n <div class=\"qa-item\" (click)=\"onFavoriteRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ record.entityName }}</div>\n </div>\n </div>\n }\n @if (quickAccessFavoriteRecords.length === 0) {\n <div class=\"qa-empty\">No favorite records</div>\n }\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else {\n <mj-entity-viewer\n #entityViewer\n [entity]=\"selectedEntity\"\n [viewEntity]=\"selectedViewEntity\"\n [viewMode]=\"state.viewMode\"\n [filterText]=\"debouncedFilterText\"\n [selectedRecordId]=\"state.selectedRecordId\"\n [config]=\"viewerConfig\"\n [gridState]=\"currentGridState\"\n [timelineConfig]=\"currentTimelineConfig\"\n [gridSelectionMode]=\"'checkbox'\"\n [showGridToolbar]=\"false\"\n [showAddToListButton]=\"false\"\n (viewModeChange)=\"onViewModeChanged($event)\"\n (filterTextChange)=\"onFilterTextChanged($event)\"\n (recordSelected)=\"onViewerRecordSelected($event)\"\n (recordOpened)=\"onViewerRecordOpened($event)\"\n (dataLoaded)=\"onDataLoaded($event)\"\n (filteredCountChanged)=\"onFilteredCountChanged($event)\"\n (gridStateChanged)=\"onGridStateChanged($event)\"\n (selectionChanged)=\"onSelectionChanged($event)\"\n (addToListRequested)=\"onAddToListRequested($event)\"\n [mapRenderMode]=\"state.mapRenderMode || 'point'\"\n [mapDisplayState]=\"mapDisplayState\"\n (mapRenderModeChange)=\"onMapRenderModeChange($event)\"\n (mapDisplayStateChange)=\"onMapDisplayStateChange($event)\">\n </mj-entity-viewer>\n }\n </div>\n </div>\n\n <!-- Detail Panel (Right - Slide In) -->\n @if (state.detailPanelOpen && selectedRecord) {\n <div class=\"detail-panel\" [style.width.px]=\"state.detailPanelWidth\">\n <!-- Detail Panel Actions Bar -->\n <div class=\"detail-panel-actions\">\n <button\n class=\"detail-action-btn\"\n (click)=\"openListManagementDialog()\"\n title=\"Add to List\">\n <i class=\"fa-solid fa-list-check\"></i>\n <span>Add to List</span>\n </button>\n </div>\n <mj-entity-record-detail-panel\n [entity]=\"detailPanelEntity\"\n [record]=\"selectedRecord\"\n (close)=\"onDetailPanelClosed()\"\n (openRecord)=\"onOpenRecord($event)\"\n (navigateToRelated)=\"onNavigateToRelated($event)\"\n (openRelatedRecord)=\"onOpenRelatedRecord($event)\"\n (openForeignKeyRecord)=\"onOpenForeignKeyRecord($event)\">\n </mj-entity-record-detail-panel>\n </div>\n }\n\n <!-- View Configuration Panel -->\n <mj-view-config-panel\n [entity]=\"selectedEntity\"\n [viewEntity]=\"selectedViewEntity\"\n [isOpen]=\"state.viewConfigPanelOpen\"\n [currentGridState]=\"currentGridState\"\n [externalFilterState]=\"filterDialogState\"\n [isSaving]=\"isSavingView\"\n [DefaultSaveAsNew]=\"defaultSaveAsNew\"\n [PendingNewViewName]=\"pendingNewViewName\"\n [PendingNewViewDescription]=\"pendingNewViewDescription\"\n [PendingNewViewIsShared]=\"pendingNewViewIsShared\"\n (close)=\"onCloseViewConfigPanel()\"\n (save)=\"onSaveView($event)\"\n (saveDefaults)=\"onSaveDefaultViewSettings($event)\"\n (delete)=\"onDeleteView()\"\n (duplicate)=\"onDuplicateFromPanel()\"\n (openFilterDialogRequest)=\"onOpenFilterDialogRequest($event)\">\n </mj-view-config-panel>\n\n <!-- Filter Dialog (rendered at dashboard level for full viewport width) -->\n <mj-filter-dialog\n [isOpen]=\"isFilterDialogOpen\"\n [fields]=\"filterDialogFields\"\n [filter]=\"filterDialogState\"\n [disabled]=\"filterDialogDisabled\"\n (close)=\"onCloseFilterDialog()\"\n (apply)=\"onFilterApplied($event)\">\n </mj-filter-dialog>\n\n <!-- Export Dialog -->\n <mj-export-dialog\n [visible]=\"showExportDialog\"\n [config]=\"exportDialogConfig\"\n (closed)=\"onExportDialogClosed($event)\">\n </mj-export-dialog>\n\n <!-- List Management Dialog -->\n @if (showListManagementDialog && listManagementConfig) {\n <mj-list-management-dialog\n [config]=\"listManagementConfig\"\n [visible]=\"showListManagementDialog\"\n (complete)=\"onListManagementComplete($event)\"\n (cancel)=\"onListManagementCancel()\">\n </mj-list-management-dialog>\n }\n\n <!-- Quick Save Dialog (F-001) -->\n <mj-quick-save-dialog\n [IsOpen]=\"showQuickSaveDialog\"\n [ViewEntity]=\"selectedViewEntity\"\n [EntityName]=\"selectedEntity?.DisplayNameOrName ?? ''\"\n [Summary]=\"quickSaveSummary\"\n [IsSaving]=\"isSavingView\"\n [DefaultSaveAsNew]=\"defaultSaveAsNew\"\n (Save)=\"onQuickSave($event)\"\n (Close)=\"onQuickSaveClose()\"\n (OpenAdvanced)=\"onQuickSaveOpenAdvanced($event)\">\n </mj-quick-save-dialog>\n\n <!-- Duplicate View Dialog (F-005) -->\n <mj-duplicate-view-dialog\n [IsOpen]=\"showDuplicateDialog\"\n [SourceViewName]=\"duplicateSourceViewName\"\n [Summary]=\"duplicateSummary\"\n (Duplicate)=\"onDuplicateConfirmed($event)\"\n (Cancel)=\"onDuplicateCancel()\">\n </mj-duplicate-view-dialog>\n\n <!-- Shared View Warning Dialog (view-creation-flow Scenario 5) -->\n <mj-shared-view-warning-dialog\n [IsOpen]=\"showSharedViewWarning\"\n [ViewName]=\"selectedViewEntity?.Name ?? ''\"\n (Action)=\"onSharedViewAction($event)\"\n (Cancel)=\"onSharedViewWarningCancel()\">\n </mj-shared-view-warning-dialog>\n</div>\n", styles: [".data-explorer-container {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed {\n width: 48px;\n}\n\n.content-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n/* Breadcrumb Bar */\n.breadcrumb-bar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; /* Above sibling .content-body so header dropdowns render on top of grid/map content */\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n/* View Selector within header */\n.header-left ::ng-deep mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n/* Header Action Button (Add to List, etc.) */\n.header-action-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn i {\n font-size: 14px;\n}\n.selection-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Timeline Date Field Selector - Styled Dropdown */\n.date-field-selector-container {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper {\n position: relative;\n}\n\n.date-field-selector-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item .item-icon {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item .item-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item .selected-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n/* View-specific controls \u2014 contextual controls for the active view mode.\n Positioned LEFT of the view mode toggle with a subtle visual separator. */\n.view-specific-controls {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.view-specific-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Legacy \u2014 keep for backward compat but no longer used in template */\n.timeline-orientation-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n display: flex;\n flex-direction: column;\n}\n\n.loading-container,\n.loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 40px;\n}\n\n.empty-icon {\n font-size: 64px;\n color: var(--mj-border-default);\n margin-bottom: 24px;\n}\n\n.empty-state h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n CONCEPT D: HOME VIEW LAYOUT\n ============================================ */\n\n.home-view-concept-d {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open {\n margin-right: 320px;\n}\n\n/* ============================================\n SEARCH HERO\n ============================================ */\n\n.search-hero {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n/* Meta row: entity count + pills */\n.search-meta-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn i {\n font-size: 11px;\n}\n\n/* ============================================\n APPLICATION GROUPS\n ============================================ */\n\n.entity-groups-area {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group {\n margin-bottom: 4px;\n}\n\n.app-group-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded {\n transform: rotate(90deg);\n}\n\n.app-group-entities {\n padding: 4px 14px 10px 60px;\n}\n\n/* ============================================\n ENTITY ITEM GRID (pills)\n ============================================ */\n\n.entity-item-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item:hover .entity-item-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item:hover .entity-item-fav {\n opacity: 1;\n}\n\n.entity-item-fav.favorited {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n/* ============================================\n QUICK ACCESS PANEL (right slide-in)\n ============================================ */\n\n.quick-access-panel {\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open {\n transform: translateX(0);\n}\n\n.qa-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-section {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-section-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n user-select: none;\n}\n\n.qa-section-header .qa-section-icon {\n font-size: 12px;\n}\n\n.qa-section-header .qa-section-count {\n background: var(--mj-bg-surface-card);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n margin-left: auto;\n}\n\n.qa-section-header .qa-section-chevron {\n font-size: 10px;\n transition: transform 0.15s;\n}\n\n.qa-section.collapsed .qa-section-chevron {\n transform: rotate(-90deg);\n}\n\n.qa-section-body {\n padding: 0 8px 8px;\n}\n\n.qa-section.collapsed .qa-section-body {\n display: none;\n}\n\n.qa-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n/* Quick Access toggle button badge */\n.qa-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n/* No results state for home view */\n.home-no-results {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.home-no-results i {\n font-size: 28px;\n margin-bottom: 10px;\n display: block;\n}\n\n.home-no-results p {\n font-size: 14px;\n margin: 0;\n}\n\n.detail-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel mj-entity-record-detail-panel {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n/* Detail Panel Actions Bar */\n.detail-panel-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn i {\n font-size: 12px;\n}\n\n:host ::ng-deep mj-explorer-grid-view,\n:host ::ng-deep mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* ============================================\n HOME SCREEN STYLES\n ============================================ */\n\n/* Home-level header adjustments */\n.content-header.home-header {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content {\n padding: 0;\n}\n\n/* Smart filter with search icon (entity-level filter) */\n.filter-icon {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container .smart-filter-input {\n padding-left: 40px;\n}\n\n/* ============================================\n VIEW MODE TOGGLE OVERRIDES\n ============================================ */\n\n.view-mode-toggle .toggle-btn {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label {\n font-size: 12px;\n font-weight: 500;\n}\n\n/* ============================================\n EMPTY STATE VARIANTS\n ============================================ */\n\n.empty-state.small {\n height: auto;\n padding: 32px;\n background: var(--mj-bg-surface-card);\n}\n\n.empty-state.small .empty-icon {\n font-size: 40px;\n margin-bottom: 16px;\n}\n\n.empty-state.small h3 {\n font-size: 16px;\n}\n\n.empty-state.small p {\n font-size: 13px;\n}\n\n/* ============================================\n RESPONSIVE STYLES\n ============================================ */\n\n@media (max-width: 1200px) {\n .entity-item-grid {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open {\n margin-right: 0;\n }\n\n .quick-access-panel {\n width: 100%;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container {\n flex-direction: column;\n }\n\n .navigation-panel {\n display: none;\n }\n\n .content-header {\n padding: 12px 16px;\n }\n\n .content-body {\n padding: 12px 16px;\n }\n\n .entity-item-grid {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle {\n display: none;\n }\n\n .app-group-name {\n font-size: 17px;\n }\n\n .entity-item-name {\n font-size: 14px;\n }\n}\n"] }]
3662
- }], () => [{ type: i1.ExplorerStateService }, { type: i0.ChangeDetectorRef }, { type: i2.RecentAccessService }, { type: i3.ExportService }, { type: i0.NgZone }], { filterInputRef: [{
2177
+ ], template: "<div class=\"data-explorer-container\">\n <!-- Navigation Panel (Left) - Hidden at home level, animated -->\n @if (!isAtHomeLevel) {\n <div\n class=\"navigation-panel\"\n [class.collapsed]=\"state.navigationPanelCollapsed\"\n [style.width.px]=\"state.navigationPanelCollapsed ? 48 : state.navigationPanelWidth\"\n [@slideInLeft]>\n\n <mj-explorer-navigation-panel\n [entities]=\"entities\"\n [appEntityGroups]=\"appEntityGroups\"\n [selectedEntityName]=\"state.selectedEntityName\"\n [favorites]=\"state.favorites\"\n [recentItems]=\"state.recentItems\"\n [collapsed]=\"state.navigationPanelCollapsed\"\n [allowedEntityNames]=\"allowedEntityNames\"\n [favoritesSectionExpanded]=\"state.favoritesSectionExpanded\"\n [recentSectionExpanded]=\"state.recentSectionExpanded\"\n [entitiesSectionExpanded]=\"state.entitiesSectionExpanded\"\n [viewsSectionExpanded]=\"state.viewsSectionExpanded\"\n (entitySelected)=\"onEntitySelected($event)\"\n (toggleCollapse)=\"toggleNavigationPanel()\"\n (sectionToggled)=\"stateService.toggleSection($event)\"\n (openRecord)=\"onOpenRecordFromNav($event)\"\n (selectRecord)=\"onSelectRecordFromNav($event)\"\n (expandAndFocus)=\"onExpandAndFocus($event)\">\n </mj-explorer-navigation-panel>\n </div>\n }\n\n <!-- Main Content Area -->\n <div class=\"content-area\">\n <!-- Breadcrumb Bar - Hidden at home level -->\n @if (!isAtHomeLevel && breadcrumbs.length > 0) {\n <div class=\"breadcrumb-bar\">\n @for (crumb of breadcrumbs; track crumb.label; let i = $index; let last = $last) {\n <span\n class=\"breadcrumb-item\"\n [class.clickable]=\"!last\"\n [class.current]=\"last\"\n (click)=\"onBreadcrumbClick(crumb, i)\"\n [title]=\"crumb.label\">\n @if (crumb.icon) {\n <i [class]=\"crumb.icon\" class=\"breadcrumb-icon\"></i>\n }\n <span class=\"breadcrumb-label\">{{ crumb.label }}</span>\n </span>\n @if (!last) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n }\n }\n </div>\n }\n\n <!-- Header -->\n <div class=\"content-header\" [class.home-header]=\"isAtHomeLevel\">\n <div class=\"header-left\">\n @if (selectedEntity) {\n <i [class]=\"getEntityIcon(selectedEntity)\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ selectedEntity.DisplayNameOrName }}</h2>\n @if (debouncedFilterText && filteredRecordCount !== totalRecordCount) {\n <span class=\"record-count\">{{ filteredRecordCount | number }} of {{ totalRecordCount | number }} records</span>\n } @else {\n <span class=\"record-count\">{{ totalRecordCount | number }} records</span>\n }\n\n <!-- View selector + view header now live inside mj-view-workspace (below). -->\n <!-- Add-to-List is now owned inside the grid plug-in renderer (it hosts its own dialog). -->\n } @else {\n @if (displayIcon) {\n <i [class]=\"displayIcon\" class=\"entity-icon\"></i>\n }\n <h2 class=\"entity-title\">{{ displayTitle }}</h2>\n <span class=\"record-count\">{{ entities.length }} entities available</span>\n }\n </div>\n\n <div class=\"header-center\">\n @if (selectedEntity) {\n <div class=\"smart-filter-container\">\n <i class=\"fa-solid fa-search filter-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"smart-filter-input\"\n placeholder=\"Filter records... (press / to focus)\"\n [value]=\"liveFilterText\"\n (input)=\"onFilterInputChanged(filterInput.value)\"\n />\n @if (liveFilterText) {\n <button class=\"clear-filter-btn\" (click)=\"clearRecordFilter()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n <!-- Home-level search moved to search hero section -->\n </div>\n\n <div class=\"header-right\">\n @if (selectedEntity) {\n <!-- View-type switcher AND all view-specific controls (timeline date/orientation/sort,\n map render mode, etc.) now live inside the plug-in renderers hosted by\n mj-view-workspace. Nothing view-type-specific lives in this header anymore. -->\n }\n @if (!selectedEntity) {\n <!-- Quick Access panel toggle -->\n <button\n class=\"header-action-btn\"\n [class.active]=\"state.quickAccessPanelOpen\"\n (click)=\"toggleQuickAccessPanel()\"\n title=\"Recents & Favorites\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n @if (recentRecords.length + favoriteRecords.length > 0) {\n <span class=\"qa-badge\">{{ recentRecords.length + favoriteRecords.length }}</span>\n }\n </button>\n }\n </div>\n </div>\n\n <!-- Content Body - Using mj-entity-viewer composite -->\n <div class=\"content-body\" [class.home-content]=\"isAtHomeLevel\">\n @if (!selectedEntity) {\n <!-- Concept D: Application Groups + Search-First Home View -->\n <div class=\"home-view-concept-d\">\n @if (isLoadingEntities) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading entities...\" size=\"medium\"></mj-loading>\n </div>\n } @else {\n <div class=\"home-main-area\" [class.panel-open]=\"state.quickAccessPanelOpen\">\n <!-- Search Hero -->\n <div class=\"search-hero\">\n <div class=\"search-hero-container\">\n <i class=\"fa-solid fa-magnifying-glass search-hero-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"search-hero-input\"\n placeholder=\"Search entities...\"\n [(ngModel)]=\"entityFilterText\"\n />\n @if (entityFilterText) {\n <button class=\"search-hero-clear\" (click)=\"entityFilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n } @else {\n <span class=\"search-hero-shortcut\">/</span>\n }\n </div>\n\n <!-- Meta row: entity count + All/Favorites pills -->\n <div class=\"search-meta-row\">\n <span class=\"search-entity-count\">\n {{ filteredEntityCount }} entities\n @if (applicationCount > 0) {\n across {{ applicationCount }} applications\n }\n </span>\n <div class=\"pill-toggle\">\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'all'\"\n (click)=\"setHomeViewMode('all')\">\n All Entities\n </button>\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'favorites'\"\n (click)=\"setHomeViewMode('favorites')\">\n <i class=\"fa-solid fa-star\"></i> My Favorites\n </button>\n </div>\n </div>\n </div>\n\n <!-- Entity Groups Area -->\n <div class=\"entity-groups-area\">\n @if (entityFilter?.applicationId) {\n <!-- Single-app mode: flat entity grid (no grouping) -->\n <div class=\"entity-item-grid\">\n @for (entity of flatFilteredEntities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n } @else {\n <!-- Multi-app mode: grouped by application -->\n @for (group of filteredAppEntityGroups; track group.applicationId) {\n <div class=\"app-group\">\n <div class=\"app-group-header\" (click)=\"toggleAppGroup(group.applicationId)\">\n <div\n class=\"app-group-icon\"\n [style.background]=\"group.applicationColor ? group.applicationColor + '15' : null\"\n [style.color]=\"group.applicationColor || null\">\n <i [class]=\"group.applicationIcon || 'fa-solid fa-folder'\"></i>\n </div>\n <span class=\"app-group-name\">{{ group.applicationName }}</span>\n <span class=\"app-group-count\">{{ group.entities.length }}</span>\n <i class=\"fa-solid fa-chevron-right app-group-chevron\"\n [class.expanded]=\"group.isExpanded\"></i>\n </div>\n @if (group.isExpanded) {\n <div class=\"app-group-entities\">\n <div class=\"entity-item-grid\">\n @for (entity of group.entities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- No results -->\n @if (filteredEntityCount === 0 && entities.length > 0) {\n <div class=\"home-no-results\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <p>No entities match \"{{ entityFilterText }}\"</p>\n </div>\n }\n @if (entities.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database empty-icon\"></i>\n <h3>No Entities Available</h3>\n <p>There are no entities configured for this application.</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Quick Access Panel (right slide-in) -->\n <div class=\"quick-access-panel\" [class.open]=\"state.quickAccessPanelOpen\">\n <div class=\"qa-header\">\n <h3>Quick Access</h3>\n <button class=\"qa-close-btn\" (click)=\"toggleQuickAccessPanel()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div class=\"qa-body\">\n <!-- Recent Records (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('recentRecords')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('recentRecords')\">\n <i class=\"fa-solid fa-clock-rotate-left qa-section-icon\"></i>\n <span>Recent Records</span>\n <span class=\"qa-section-count\">{{ quickAccessRecentRecords.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (record of quickAccessRecentRecords; track record.entityId + '|' + record.recordId) {\n <div class=\"qa-item\" (click)=\"onRecentRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ record.entityName }}</div>\n </div>\n <span class=\"qa-item-time\">{{ formatRelativeTime(record.latestAt) }}</span>\n </div>\n }\n @if (quickAccessRecentRecords.length === 0) {\n <div class=\"qa-empty\">No recent records</div>\n }\n </div>\n </div>\n\n <!-- Recent Entities (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('recentEntities')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('recentEntities')\">\n <i class=\"fa-solid fa-table qa-section-icon\"></i>\n <span>Recent Entities</span>\n <span class=\"qa-section-count\">{{ quickAccessRecentEntities.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (entity of quickAccessRecentEntities; track entity.ID) {\n <div class=\"qa-item\" (click)=\"onEntitySelected(entity)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ entity.DisplayNameOrName }}</div>\n </div>\n </div>\n }\n @if (quickAccessRecentEntities.length === 0) {\n <div class=\"qa-empty\">No recent entities</div>\n }\n </div>\n </div>\n\n <!-- Favorite Records (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('favoriteRecords')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('favoriteRecords')\">\n <i class=\"fa-solid fa-star qa-section-icon\" style=\"color: var(--mj-status-warning);\"></i>\n <span>Favorite Records</span>\n <span class=\"qa-section-count\">{{ quickAccessFavoriteRecords.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (record of quickAccessFavoriteRecords; track record.userFavoriteId) {\n <div class=\"qa-item\" (click)=\"onFavoriteRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ record.entityName }}</div>\n </div>\n </div>\n }\n @if (quickAccessFavoriteRecords.length === 0) {\n <div class=\"qa-empty\">No favorite records</div>\n }\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else {\n <!--\n mj-view-workspace owns the saved-view lifecycle (select / save / duplicate / rename /\n delete / revert / quick-save) and the inner data renderer. Every view type is now a\n self-contained plug-in: view-type-specific features (export / add-to-list / delete /\n grid-state / timeline + map controls) live INSIDE the plug-in renderers and no longer\n bubble through the workspace. The dashboard only handles navigation (open record / open\n related record / create new record) + the generic filter/data-load/count signals + URL\n and view-CRUD state sync. AutoSaveView=true \u2192 the workspace persists view CRUD itself.\n -->\n <mj-view-workspace\n [Entity]=\"selectedEntity\"\n [AutoSaveView]=\"true\"\n [SelectedView]=\"selectedViewEntity\"\n [FilterText]=\"debouncedFilterText\"\n [SelectedRecordId]=\"state.selectedRecordId\"\n [ViewerConfig]=\"viewerConfig\"\n (SelectedViewChange)=\"onWorkspaceViewSelected($event)\"\n (ViewSelected)=\"onWorkspaceViewSelected($event)\"\n (OpenViewInTabRequested)=\"onOpenInTabRequested($event)\"\n (OpenRecordRequested)=\"onWorkspaceOpenRecord($event)\"\n (OpenRelatedRecordRequested)=\"onOpenRelatedRecordRequested($event)\"\n (CreateNewRecordRequested)=\"onCreateNewRecordRequested($event)\"\n (RecordSelected)=\"onViewerRecordSelected($event)\"\n (AfterViewSave)=\"onWorkspaceViewSaved()\"\n (AfterViewDelete)=\"onWorkspaceViewSaved()\"\n (FilterTextChanged)=\"onFilterTextChanged($event)\"\n (DataLoaded)=\"onDataLoaded($event)\"\n (FilteredCountChanged)=\"onFilteredCountChanged($event)\">\n </mj-view-workspace>\n }\n </div>\n </div>\n\n <!-- Detail Panel (Right - Slide In) -->\n @if (state.detailPanelOpen && selectedRecord) {\n <div class=\"detail-panel\" [style.width.px]=\"state.detailPanelWidth\">\n <mj-entity-record-detail-panel\n [entity]=\"detailPanelEntity\"\n [record]=\"selectedRecord\"\n (close)=\"onDetailPanelClosed()\"\n (openRecord)=\"onOpenRecord($event)\"\n (navigateToRelated)=\"onNavigateToRelated($event)\"\n (openRelatedRecord)=\"onOpenRelatedRecord($event)\"\n (openForeignKeyRecord)=\"onOpenForeignKeyRecord($event)\">\n </mj-entity-record-detail-panel>\n </div>\n }\n\n <!-- View config panel, filter dialog, quick-save/duplicate/shared-view-warning dialogs\n now live inside mj-view-workspace (the saved-view lifecycle moved there).\n Export + Add-to-List dialogs now live inside the grid plug-in renderer (it hosts its own\n Generic dialogs), so they are no longer rendered at the dashboard level. -->\n</div>\n", styles: [".data-explorer-container {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed {\n width: 48px;\n}\n\n.content-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n/* Breadcrumb Bar */\n.breadcrumb-bar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; /* Above sibling .content-body so header dropdowns render on top of grid/map content */\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n/* View Selector within header */\n.header-left ::ng-deep mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn:hover {\n color: var(--mj-text-primary);\n}\n.toggle-btn.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n/* Header Action Button (Add to List, etc.) */\n.header-action-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn i {\n font-size: 14px;\n}\n.selection-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Timeline Date Field Selector - Styled Dropdown */\n.date-field-selector-container {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper {\n position: relative;\n}\n\n.date-field-selector-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item .item-icon {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item .item-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item .selected-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n/* View-specific controls \u2014 contextual controls for the active view mode.\n Positioned LEFT of the view mode toggle with a subtle visual separator. */\n.view-specific-controls {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.view-specific-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Legacy \u2014 keep for backward compat but no longer used in template */\n.timeline-orientation-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n display: flex;\n flex-direction: column;\n /* Contain the body's stacking context. The view components inside (grid\n option menus, the map's Leaflet panes/toolbar, etc.) use z-index values up\n to ~1000; .content-header sits at z-index 2 (kept below the shell header \u2014\n see #2701). Without this, those body z-indices leak into the shared context\n and paint over the header's own dropdowns (view-selector, date-field).\n `isolation: isolate` flattens all body z-indices into one context beneath\n the header. Safe because modals + the detail panel render at the dashboard\n root (outside .content-body), so they still overlay everything. */\n isolation: isolate;\n}\n\n.loading-container,\n.loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 40px;\n}\n\n.empty-icon {\n font-size: 64px;\n color: var(--mj-border-default);\n margin-bottom: 24px;\n}\n\n.empty-state h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n CONCEPT D: HOME VIEW LAYOUT\n ============================================ */\n\n.home-view-concept-d {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open {\n margin-right: 320px;\n}\n\n/* ============================================\n SEARCH HERO\n ============================================ */\n\n.search-hero {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n/* Meta row: entity count + pills */\n.search-meta-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn i {\n font-size: 11px;\n}\n\n/* ============================================\n APPLICATION GROUPS\n ============================================ */\n\n.entity-groups-area {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group {\n margin-bottom: 4px;\n}\n\n.app-group-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded {\n transform: rotate(90deg);\n}\n\n.app-group-entities {\n padding: 4px 14px 10px 60px;\n}\n\n/* ============================================\n ENTITY ITEM GRID (pills)\n ============================================ */\n\n.entity-item-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item:hover .entity-item-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item:hover .entity-item-fav {\n opacity: 1;\n}\n\n.entity-item-fav.favorited {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n/* ============================================\n QUICK ACCESS PANEL (right slide-in)\n ============================================ */\n\n.quick-access-panel {\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open {\n transform: translateX(0);\n}\n\n.qa-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-section {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-section-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n user-select: none;\n}\n\n.qa-section-header .qa-section-icon {\n font-size: 12px;\n}\n\n.qa-section-header .qa-section-count {\n background: var(--mj-bg-surface-card);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n margin-left: auto;\n}\n\n.qa-section-header .qa-section-chevron {\n font-size: 10px;\n transition: transform 0.15s;\n}\n\n.qa-section.collapsed .qa-section-chevron {\n transform: rotate(-90deg);\n}\n\n.qa-section-body {\n padding: 0 8px 8px;\n}\n\n.qa-section.collapsed .qa-section-body {\n display: none;\n}\n\n.qa-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n/* Quick Access toggle button badge */\n.qa-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n/* No results state for home view */\n.home-no-results {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.home-no-results i {\n font-size: 28px;\n margin-bottom: 10px;\n display: block;\n}\n\n.home-no-results p {\n font-size: 14px;\n margin: 0;\n}\n\n.detail-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel mj-entity-record-detail-panel {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n/* Detail Panel Actions Bar */\n.detail-panel-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn i {\n font-size: 12px;\n}\n\n:host ::ng-deep mj-explorer-grid-view,\n:host ::ng-deep mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* ============================================\n HOME SCREEN STYLES\n ============================================ */\n\n/* Home-level header adjustments */\n.content-header.home-header {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content {\n padding: 0;\n}\n\n/* Smart filter with search icon (entity-level filter) */\n.filter-icon {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container .smart-filter-input {\n padding-left: 40px;\n}\n\n/* ============================================\n VIEW MODE TOGGLE OVERRIDES\n ============================================ */\n\n.view-mode-toggle .toggle-btn {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label {\n font-size: 12px;\n font-weight: 500;\n}\n\n/* ============================================\n EMPTY STATE VARIANTS\n ============================================ */\n\n.empty-state.small {\n height: auto;\n padding: 32px;\n background: var(--mj-bg-surface-card);\n}\n\n.empty-state.small .empty-icon {\n font-size: 40px;\n margin-bottom: 16px;\n}\n\n.empty-state.small h3 {\n font-size: 16px;\n}\n\n.empty-state.small p {\n font-size: 13px;\n}\n\n/* ============================================\n RESPONSIVE STYLES\n ============================================ */\n\n@media (max-width: 1200px) {\n .entity-item-grid {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open {\n margin-right: 0;\n }\n\n .quick-access-panel {\n width: 100%;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container {\n flex-direction: column;\n }\n\n .navigation-panel {\n display: none;\n }\n\n .content-header {\n padding: 12px 16px;\n }\n\n .content-body {\n padding: 12px 16px;\n }\n\n .entity-item-grid {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle {\n display: none;\n }\n\n .app-group-name {\n font-size: 17px;\n }\n\n .entity-item-name {\n font-size: 14px;\n }\n}\n"] }]
2178
+ }], () => [{ type: i1.ExplorerStateService }, { type: i0.ChangeDetectorRef }, { type: i2.RecentAccessService }, { type: i0.NgZone }], { filterInputRef: [{
3663
2179
  type: ViewChild,
3664
2180
  args: ['filterInput']
3665
- }], viewSelectorRef: [{
3666
- type: ViewChild,
3667
- args: [ViewSelectorComponent]
3668
- }], entityViewerRef: [{
3669
- type: ViewChild,
3670
- args: [EntityViewerComponent]
3671
- }], viewConfigPanelRef: [{
2181
+ }], viewWorkspaceRef: [{
3672
2182
  type: ViewChild,
3673
- args: [ViewConfigPanelComponent]
2183
+ args: [ViewWorkspaceComponent]
3674
2184
  }], entityFilter: [{
3675
2185
  type: Input
3676
2186
  }], deepLink: [{
@@ -3687,5 +2197,5 @@ export { DataExplorerDashboardComponent };
3687
2197
  type: HostListener,
3688
2198
  args: ['document:keydown', ['$event']]
3689
2199
  }] }); })();
3690
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DataExplorerDashboardComponent, { className: "DataExplorerDashboardComponent", filePath: "src/DataExplorer/data-explorer-dashboard.component.ts", lineNumber: 77 }); })();
2200
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DataExplorerDashboardComponent, { className: "DataExplorerDashboardComponent", filePath: "src/DataExplorer/data-explorer-dashboard.component.ts", lineNumber: 55 }); })();
3691
2201
  //# sourceMappingURL=data-explorer-dashboard.component.js.map