@atlashub/smartstack 3.21.0 → 3.25.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.
- package/dist/chunks/{AgentSkillsPage-7si3Ng8e.js → AgentSkillsPage-BWQSCYl-.js} +2 -2
- package/dist/chunks/{AgentSkillsPage-7si3Ng8e.js.map → AgentSkillsPage-BWQSCYl-.js.map} +1 -1
- package/dist/chunks/{AgentSkillsPage-D0cD1QdM.js → AgentSkillsPage-IQcMnBaD.js} +2 -2
- package/dist/chunks/{AgentSkillsPage-D0cD1QdM.js.map → AgentSkillsPage-IQcMnBaD.js.map} +1 -1
- package/dist/chunks/{AgentWorkloadPage-H_7ze33H.js → AgentWorkloadPage-DqrjkvWL.js} +2 -2
- package/dist/chunks/{AgentWorkloadPage-H_7ze33H.js.map → AgentWorkloadPage-DqrjkvWL.js.map} +1 -1
- package/dist/chunks/{AgentWorkloadPage-D4d86cdV.js → AgentWorkloadPage-w-HiyFYP.js} +2 -2
- package/dist/chunks/{AgentWorkloadPage-D4d86cdV.js.map → AgentWorkloadPage-w-HiyFYP.js.map} +1 -1
- package/dist/chunks/{ApiCatalogDetailPage-2ktkRrCb.js → ApiCatalogDetailPage-D3L8Yf4G.js} +3 -3
- package/dist/chunks/{ApiCatalogDetailPage-2ktkRrCb.js.map → ApiCatalogDetailPage-D3L8Yf4G.js.map} +1 -1
- package/dist/chunks/{ApiCatalogDetailPage-BQ53xuwD.js → ApiCatalogDetailPage-MPT3Kz6H.js} +2 -2
- package/dist/chunks/{ApiCatalogDetailPage-BQ53xuwD.js.map → ApiCatalogDetailPage-MPT3Kz6H.js.map} +1 -1
- package/dist/chunks/{ApiCatalogPage-BEqTDJz8.js → ApiCatalogPage-D4Hg3uiS.js} +2 -2
- package/dist/chunks/{ApiCatalogPage-BEqTDJz8.js.map → ApiCatalogPage-D4Hg3uiS.js.map} +1 -1
- package/dist/chunks/{ApiCatalogPage-BBkWSLI8.js → ApiCatalogPage-DRg5Cz0r.js} +2 -2
- package/dist/chunks/{ApiCatalogPage-BBkWSLI8.js.map → ApiCatalogPage-DRg5Cz0r.js.map} +1 -1
- package/dist/chunks/{ApplicationDetailPage-BYJ2YMPq.js → ApplicationDetailPage-Caizuyn2.js} +2 -2
- package/dist/chunks/{ApplicationDetailPage-BYJ2YMPq.js.map → ApplicationDetailPage-Caizuyn2.js.map} +1 -1
- package/dist/chunks/{ApplicationDetailPage-D8-bf1as.js → ApplicationDetailPage-CuCW6aMB.js} +4 -4
- package/dist/chunks/{ApplicationDetailPage-D8-bf1as.js.map → ApplicationDetailPage-CuCW6aMB.js.map} +1 -1
- package/dist/chunks/{ApplicationsDashboardPage-BBlLms2r.js → ApplicationsDashboardPage-B2MW8-Kc.js} +2 -2
- package/dist/chunks/{ApplicationsDashboardPage-BBlLms2r.js.map → ApplicationsDashboardPage-B2MW8-Kc.js.map} +1 -1
- package/dist/chunks/{ApplicationsDashboardPage-DTWZxJJM.js → ApplicationsDashboardPage-BDIjFIYZ.js} +3 -3
- package/dist/chunks/{ApplicationsDashboardPage-DTWZxJJM.js.map → ApplicationsDashboardPage-BDIjFIYZ.js.map} +1 -1
- package/dist/chunks/{ApplicationsGridPage-BQaMsK1K.js → ApplicationsGridPage-DV-FihKj.js} +2 -2
- package/dist/chunks/{ApplicationsGridPage-BQaMsK1K.js.map → ApplicationsGridPage-DV-FihKj.js.map} +1 -1
- package/dist/chunks/{ApplicationsGridPage-DbVcvezt.js → ApplicationsGridPage-DXsTfXPI.js} +2 -2
- package/dist/chunks/{ApplicationsGridPage-DbVcvezt.js.map → ApplicationsGridPage-DXsTfXPI.js.map} +1 -1
- package/dist/chunks/{ApplicationsListPage-DYKM2Yeo.js → ApplicationsListPage--CGkyBuJ.js} +2 -2
- package/dist/chunks/{ApplicationsListPage-DYKM2Yeo.js.map → ApplicationsListPage--CGkyBuJ.js.map} +1 -1
- package/dist/chunks/{ApplicationsListPage-C91v2rZt.js → ApplicationsListPage-JUX823bh.js} +2 -2
- package/dist/chunks/{ApplicationsListPage-C91v2rZt.js.map → ApplicationsListPage-JUX823bh.js.map} +1 -1
- package/dist/chunks/{ApplicationsPage-BCbgotIx.js → ApplicationsPage-6zgFye6w.js} +2 -2
- package/dist/chunks/{ApplicationsPage-BCbgotIx.js.map → ApplicationsPage-6zgFye6w.js.map} +1 -1
- package/dist/chunks/{ApplicationsPage-CW3-Hjlu.js → ApplicationsPage-CQPuuiO6.js} +4 -4
- package/dist/chunks/{ApplicationsPage-CW3-Hjlu.js.map → ApplicationsPage-CQPuuiO6.js.map} +1 -1
- package/dist/chunks/{AssignmentRulesPage-D8vfGDBN.js → AssignmentRulesPage-CFffeEbo.js} +2 -2
- package/dist/chunks/{AssignmentRulesPage-D8vfGDBN.js.map → AssignmentRulesPage-CFffeEbo.js.map} +1 -1
- package/dist/chunks/{AssignmentRulesPage-CxktlEMB.js → AssignmentRulesPage-D78UeUId.js} +2 -2
- package/dist/chunks/{AssignmentRulesPage-CxktlEMB.js.map → AssignmentRulesPage-D78UeUId.js.map} +1 -1
- package/dist/chunks/{AssignmentsPage-DmfBYQAD.js → AssignmentsPage-Cww2ifZF.js} +2 -2
- package/dist/chunks/{AssignmentsPage-DmfBYQAD.js.map → AssignmentsPage-Cww2ifZF.js.map} +1 -1
- package/dist/chunks/{AssignmentsPage-sRCCBmRc.js → AssignmentsPage-DE_QS2LO.js} +2 -2
- package/dist/chunks/{AssignmentsPage-sRCCBmRc.js.map → AssignmentsPage-DE_QS2LO.js.map} +1 -1
- package/dist/chunks/{AuthCallbackPage-C7XiZxKb.js → AuthCallbackPage-CA2nO6DG.js} +2 -2
- package/dist/chunks/{AuthCallbackPage-C7XiZxKb.js.map → AuthCallbackPage-CA2nO6DG.js.map} +1 -1
- package/dist/chunks/{AuthCallbackPage-BCe_bwJM.js → AuthCallbackPage-CDUAoX-N.js} +2 -2
- package/dist/chunks/{AuthCallbackPage-BCe_bwJM.js.map → AuthCallbackPage-CDUAoX-N.js.map} +1 -1
- package/dist/chunks/{ConfirmEmailPage-BUfGSqxF.js → ConfirmEmailPage-BqsILAYH.js} +2 -2
- package/dist/chunks/{ConfirmEmailPage-BUfGSqxF.js.map → ConfirmEmailPage-BqsILAYH.js.map} +1 -1
- package/dist/chunks/{ConfirmEmailPage-Buj4x-rx.js → ConfirmEmailPage-INeHCuMB.js} +2 -2
- package/dist/chunks/{ConfirmEmailPage-Buj4x-rx.js.map → ConfirmEmailPage-INeHCuMB.js.map} +1 -1
- package/dist/chunks/{CreateSupportTicketPage-CKDX_HQm.js → CreateSupportTicketPage-BWeuV2aU.js} +2 -2
- package/dist/chunks/{CreateSupportTicketPage-CKDX_HQm.js.map → CreateSupportTicketPage-BWeuV2aU.js.map} +1 -1
- package/dist/chunks/{CreateSupportTicketPage-0LgY-_pu.js → CreateSupportTicketPage-OBwF4v7b.js} +2 -2
- package/dist/chunks/{CreateSupportTicketPage-0LgY-_pu.js.map → CreateSupportTicketPage-OBwF4v7b.js.map} +1 -1
- package/dist/chunks/{DashboardPage-CUZ80NGV.js → DashboardPage-CKHqWrdS.js} +3 -3
- package/dist/chunks/{DashboardPage-CUZ80NGV.js.map → DashboardPage-CKHqWrdS.js.map} +1 -1
- package/dist/chunks/{DashboardPage-CaNOAstg.js → DashboardPage-COmc9b__.js} +3 -3
- package/dist/chunks/{DashboardPage-CaNOAstg.js.map → DashboardPage-COmc9b__.js.map} +1 -1
- package/dist/chunks/{DashboardPage-B48_rQFi.js → DashboardPage-CfKZHiSj.js} +2 -2
- package/dist/chunks/{DashboardPage-B48_rQFi.js.map → DashboardPage-CfKZHiSj.js.map} +1 -1
- package/dist/chunks/{DashboardPage-CUZV1J9t.js → DashboardPage-CwEZZ3jx.js} +2 -2
- package/dist/chunks/{DashboardPage-CUZV1J9t.js.map → DashboardPage-CwEZZ3jx.js.map} +1 -1
- package/dist/chunks/{EscalationConfigPage-CdzAbnGy.js → EscalationConfigPage--7lgZ0kJ.js} +2 -2
- package/dist/chunks/{EscalationConfigPage-CdzAbnGy.js.map → EscalationConfigPage--7lgZ0kJ.js.map} +1 -1
- package/dist/chunks/{EscalationConfigPage-CYGIl_e6.js → EscalationConfigPage-DPyiBcqV.js} +2 -2
- package/dist/chunks/{EscalationConfigPage-CYGIl_e6.js.map → EscalationConfigPage-DPyiBcqV.js.map} +1 -1
- package/dist/chunks/{ForceChangePasswordPage-lRpkwcX7.js → ForceChangePasswordPage-BE-6umub.js} +2 -2
- package/dist/chunks/{ForceChangePasswordPage-lRpkwcX7.js.map → ForceChangePasswordPage-BE-6umub.js.map} +1 -1
- package/dist/chunks/{ForceChangePasswordPage-CvmYAV3r.js → ForceChangePasswordPage-CnsYoWmV.js} +2 -2
- package/dist/chunks/{ForceChangePasswordPage-CvmYAV3r.js.map → ForceChangePasswordPage-CnsYoWmV.js.map} +1 -1
- package/dist/chunks/{ForgotPasswordPage-0u49E4Pw.js → ForgotPasswordPage-CSq4DnFF.js} +2 -2
- package/dist/chunks/{ForgotPasswordPage-0u49E4Pw.js.map → ForgotPasswordPage-CSq4DnFF.js.map} +1 -1
- package/dist/chunks/{ForgotPasswordPage-CxQUqKOm.js → ForgotPasswordPage-DZLVolAC.js} +2 -2
- package/dist/chunks/{ForgotPasswordPage-CxQUqKOm.js.map → ForgotPasswordPage-DZLVolAC.js.map} +1 -1
- package/dist/chunks/{GroupDetailPage-DFBvVO1S.js → GroupDetailPage-Bf9Wb_2j.js} +5 -5
- package/dist/chunks/{GroupDetailPage-DFBvVO1S.js.map → GroupDetailPage-Bf9Wb_2j.js.map} +1 -1
- package/dist/chunks/{GroupDetailPage-B2FkKrGG.js → GroupDetailPage-R-hf3rJ7.js} +2 -2
- package/dist/chunks/{GroupDetailPage-B2FkKrGG.js.map → GroupDetailPage-R-hf3rJ7.js.map} +1 -1
- package/dist/chunks/{MyAccessRequestsPage-C9IX4c0K.js → MyAccessRequestsPage-BIisvWM6.js} +2 -2
- package/dist/chunks/{MyAccessRequestsPage-C9IX4c0K.js.map → MyAccessRequestsPage-BIisvWM6.js.map} +1 -1
- package/dist/chunks/{MyAccessRequestsPage-D6pVULNM.js → MyAccessRequestsPage-BLSV7Tbx.js} +2 -2
- package/dist/chunks/{MyAccessRequestsPage-D6pVULNM.js.map → MyAccessRequestsPage-BLSV7Tbx.js.map} +1 -1
- package/dist/chunks/{MyTenantsPage-BEcYYdGR.js → MyTenantsPage-D-7k9CP1.js} +3 -3
- package/dist/chunks/{MyTenantsPage-BEcYYdGR.js.map → MyTenantsPage-D-7k9CP1.js.map} +1 -1
- package/dist/chunks/{MyTenantsPage-D9f85zjF.js → MyTenantsPage-DqGW6aDt.js} +2 -2
- package/dist/chunks/{MyTenantsPage-D9f85zjF.js.map → MyTenantsPage-DqGW6aDt.js.map} +1 -1
- package/dist/chunks/{MyTicketsPage-DJR8h6y1.js → MyTicketsPage--DgDsnZA.js} +2 -2
- package/dist/chunks/{MyTicketsPage-DJR8h6y1.js.map → MyTicketsPage--DgDsnZA.js.map} +1 -1
- package/dist/chunks/{MyTicketsPage-DiOUExKJ.js → MyTicketsPage-CqJ3Aqob.js} +2 -2
- package/dist/chunks/{MyTicketsPage-DiOUExKJ.js.map → MyTicketsPage-CqJ3Aqob.js.map} +1 -1
- package/dist/chunks/{NavigationAppsPage-CeHbxfZw.js → NavigationAppsPage-Bebis_RT.js} +2 -2
- package/dist/chunks/{NavigationAppsPage-CeHbxfZw.js.map → NavigationAppsPage-Bebis_RT.js.map} +1 -1
- package/dist/chunks/{NavigationAppsPage-If7tmCFY.js → NavigationAppsPage-THNPOAjv.js} +2 -2
- package/dist/chunks/{NavigationAppsPage-If7tmCFY.js.map → NavigationAppsPage-THNPOAjv.js.map} +1 -1
- package/dist/chunks/{NotificationsPage-C29Lln5o.js → NotificationsPage-CAbNW_Cn.js} +2 -2
- package/dist/chunks/{NotificationsPage-C29Lln5o.js.map → NotificationsPage-CAbNW_Cn.js.map} +1 -1
- package/dist/chunks/{NotificationsPage-BiaLRb0s.js → NotificationsPage-DxwizUhL.js} +2 -2
- package/dist/chunks/{NotificationsPage-BiaLRb0s.js.map → NotificationsPage-DxwizUhL.js.map} +1 -1
- package/dist/chunks/{OnboardingWizardPage-DQrBKNBq.js → OnboardingWizardPage-C6HlbJ3K.js} +2 -2
- package/dist/chunks/{OnboardingWizardPage-DQrBKNBq.js.map → OnboardingWizardPage-C6HlbJ3K.js.map} +1 -1
- package/dist/chunks/{OnboardingWizardPage-BQah4cI8.js → OnboardingWizardPage-CyC2zONO.js} +2 -2
- package/dist/chunks/{OnboardingWizardPage-BQah4cI8.js.map → OnboardingWizardPage-CyC2zONO.js.map} +1 -1
- package/dist/chunks/{PermissionDetailPage-Ckjdjvf9.js → PermissionDetailPage-BDHiNgky.js} +2 -2
- package/dist/chunks/{PermissionDetailPage-Ckjdjvf9.js.map → PermissionDetailPage-BDHiNgky.js.map} +1 -1
- package/dist/chunks/{PermissionDetailPage-Dh8v7mGj.js → PermissionDetailPage-C5K17ydY.js} +2 -2
- package/dist/chunks/{PermissionDetailPage-Dh8v7mGj.js.map → PermissionDetailPage-C5K17ydY.js.map} +1 -1
- package/dist/chunks/{PermissionsPage-l0PnY-EE.js → PermissionsPage-COI5LJPo.js} +2 -2
- package/dist/chunks/{PermissionsPage-l0PnY-EE.js.map → PermissionsPage-COI5LJPo.js.map} +1 -1
- package/dist/chunks/{PermissionsPage-DLy9U3P3.js → PermissionsPage-CkOwH2_d.js} +2 -2
- package/dist/chunks/{PermissionsPage-DLy9U3P3.js.map → PermissionsPage-CkOwH2_d.js.map} +1 -1
- package/dist/chunks/{PortalDashboardPage-DFBx38-x.js → PortalDashboardPage-CoEC4CmC.js} +2 -2
- package/dist/chunks/{PortalDashboardPage-DFBx38-x.js.map → PortalDashboardPage-CoEC4CmC.js.map} +1 -1
- package/dist/chunks/{PortalDashboardPage-rQYhrX0q.js → PortalDashboardPage-DrYymEf-.js} +2 -2
- package/dist/chunks/{PortalDashboardPage-rQYhrX0q.js.map → PortalDashboardPage-DrYymEf-.js.map} +1 -1
- package/dist/chunks/{PreferencesPage-BBu8yZQB.js → PreferencesPage-CJRaU3ba.js} +2 -2
- package/dist/chunks/{PreferencesPage-BBu8yZQB.js.map → PreferencesPage-CJRaU3ba.js.map} +1 -1
- package/dist/chunks/{PreferencesPage-B81MsNV1.js → PreferencesPage-Cqr9mAab.js} +2 -2
- package/dist/chunks/{PreferencesPage-B81MsNV1.js.map → PreferencesPage-Cqr9mAab.js.map} +1 -1
- package/dist/chunks/{ProfilePage-DDrl10zj.js → ProfilePage-BZVpg6-l.js} +2 -2
- package/dist/chunks/{ProfilePage-DDrl10zj.js.map → ProfilePage-BZVpg6-l.js.map} +1 -1
- package/dist/chunks/{ProfilePage-DPoXwdnc.js → ProfilePage-Cu_FITeL.js} +2 -2
- package/dist/chunks/{ProfilePage-DPoXwdnc.js.map → ProfilePage-Cu_FITeL.js.map} +1 -1
- package/dist/chunks/{ReferencesManagementPage-eFsKjIEK.js → ReferencesManagementPage-DUlVk9Ps.js} +3 -3
- package/dist/chunks/{ReferencesManagementPage-eFsKjIEK.js.map → ReferencesManagementPage-DUlVk9Ps.js.map} +1 -1
- package/dist/chunks/{ReferencesManagementPage-DhVsuElE.js → ReferencesManagementPage-ZCuYtqd7.js} +2 -2
- package/dist/chunks/{ReferencesManagementPage-DhVsuElE.js.map → ReferencesManagementPage-ZCuYtqd7.js.map} +1 -1
- package/dist/chunks/{RegisterPage-CiQib3-6.js → RegisterPage-C4xmVwh9.js} +2 -2
- package/dist/chunks/{RegisterPage-CiQib3-6.js.map → RegisterPage-C4xmVwh9.js.map} +1 -1
- package/dist/chunks/{RegisterPage-bXCcJD88.js → RegisterPage-DGyzoIHT.js} +2 -2
- package/dist/chunks/{RegisterPage-bXCcJD88.js.map → RegisterPage-DGyzoIHT.js.map} +1 -1
- package/dist/chunks/{ResetPasswordPage-Dqiahhnj.js → ResetPasswordPage-DqDD6VPR.js} +2 -2
- package/dist/chunks/{ResetPasswordPage-Dqiahhnj.js.map → ResetPasswordPage-DqDD6VPR.js.map} +1 -1
- package/dist/chunks/{ResetPasswordPage-CubPG3yv.js → ResetPasswordPage-Glu-aeqv.js} +2 -2
- package/dist/chunks/{ResetPasswordPage-CubPG3yv.js.map → ResetPasswordPage-Glu-aeqv.js.map} +1 -1
- package/dist/chunks/{ResolutionModal-Bg7XZmR1.js → ResolutionModal-CxjANAOP.js} +2 -2
- package/dist/chunks/{ResolutionModal-Bg7XZmR1.js.map → ResolutionModal-CxjANAOP.js.map} +1 -1
- package/dist/chunks/{ResolutionModal-DqRk_T0n.js → ResolutionModal-Duat18qV.js} +2 -2
- package/dist/chunks/{ResolutionModal-DqRk_T0n.js.map → ResolutionModal-Duat18qV.js.map} +1 -1
- package/dist/chunks/{RoleDetailPage-Blau6_4c.js → RoleDetailPage-BQffUSnt.js} +3 -3
- package/dist/chunks/{RoleDetailPage-Blau6_4c.js.map → RoleDetailPage-BQffUSnt.js.map} +1 -1
- package/dist/chunks/{RoleDetailPage-CiRVxxIP.js → RoleDetailPage-JTm5lD1_.js} +2 -2
- package/dist/chunks/{RoleDetailPage-CiRVxxIP.js.map → RoleDetailPage-JTm5lD1_.js.map} +1 -1
- package/dist/chunks/{RolesPage-Pm-RN3lP.js → RolesPage-B9rRzciI.js} +2 -2
- package/dist/chunks/{RolesPage-Pm-RN3lP.js.map → RolesPage-B9rRzciI.js.map} +1 -1
- package/dist/chunks/{RolesPage-Cb8joqdJ.js → RolesPage-BN8_zMOC.js} +2 -2
- package/dist/chunks/{RolesPage-Cb8joqdJ.js.map → RolesPage-BN8_zMOC.js.map} +1 -1
- package/dist/chunks/{SlaConfigPage-B86McKM6.js → SlaConfigPage-B7kZNig4.js} +2 -2
- package/dist/chunks/{SlaConfigPage-B86McKM6.js.map → SlaConfigPage-B7kZNig4.js.map} +1 -1
- package/dist/chunks/{SlaConfigPage-BY7gvYU6.js → SlaConfigPage-okvZfA_K.js} +2 -2
- package/dist/chunks/{SlaConfigPage-BY7gvYU6.js.map → SlaConfigPage-okvZfA_K.js.map} +1 -1
- package/dist/chunks/{SupportPermissionsPage-BYxcLMSd.js → SupportPermissionsPage-DGAPqJbl.js} +2 -2
- package/dist/chunks/{SupportPermissionsPage-BYxcLMSd.js.map → SupportPermissionsPage-DGAPqJbl.js.map} +1 -1
- package/dist/chunks/{SupportPermissionsPage-MXqXNJIZ.js → SupportPermissionsPage-Dg_wLOme.js} +2 -2
- package/dist/chunks/{SupportPermissionsPage-MXqXNJIZ.js.map → SupportPermissionsPage-Dg_wLOme.js.map} +1 -1
- package/dist/chunks/{TemplatesPage-BDguJ401.js → TemplatesPage-DT9fhlAU.js} +2 -2
- package/dist/chunks/{TemplatesPage-BDguJ401.js.map → TemplatesPage-DT9fhlAU.js.map} +1 -1
- package/dist/chunks/{TemplatesPage-DdnGgioU.js → TemplatesPage-DiEk538p.js} +2 -2
- package/dist/chunks/{TemplatesPage-DdnGgioU.js.map → TemplatesPage-DiEk538p.js.map} +1 -1
- package/dist/chunks/{TenantCard-ffwWsgFQ.js → TenantCard-BbSYk9_Z.js} +2 -2
- package/dist/chunks/{TenantCard-ffwWsgFQ.js.map → TenantCard-BbSYk9_Z.js.map} +1 -1
- package/dist/chunks/{TenantCard-CUjb6og9.js → TenantCard-CEkiKxcZ.js} +2 -2
- package/dist/chunks/{TenantCard-CUjb6og9.js.map → TenantCard-CEkiKxcZ.js.map} +1 -1
- package/dist/chunks/{TenantScopeSelector-Dz7i1I43.js → TenantScopeSelector-BWfYxvEa.js} +2 -2
- package/dist/chunks/{TenantScopeSelector-Dz7i1I43.js.map → TenantScopeSelector-BWfYxvEa.js.map} +1 -1
- package/dist/chunks/{TenantScopeSelector-Cym_Zyps.js → TenantScopeSelector-D-BKgQPV.js} +2 -2
- package/dist/chunks/{TenantScopeSelector-Cym_Zyps.js.map → TenantScopeSelector-D-BKgQPV.js.map} +1 -1
- package/dist/chunks/{TicketDetailPage-GOh9GX7E.js → TicketDetailPage-C1mNS9Up.js} +2 -2
- package/dist/chunks/{TicketDetailPage-GOh9GX7E.js.map → TicketDetailPage-C1mNS9Up.js.map} +1 -1
- package/dist/chunks/{TicketDetailPage-Du8WMyqf.js → TicketDetailPage-ieVDRh42.js} +2 -2
- package/dist/chunks/{TicketDetailPage-Du8WMyqf.js.map → TicketDetailPage-ieVDRh42.js.map} +1 -1
- package/dist/chunks/{TicketsPage-Bqd6moQy.js → TicketsPage-CnuWsnIW.js} +2 -2
- package/dist/chunks/{TicketsPage-Bqd6moQy.js.map → TicketsPage-CnuWsnIW.js.map} +1 -1
- package/dist/chunks/{TicketsPage-WdU4Bb7M.js → TicketsPage-jjyY15_D.js} +2 -2
- package/dist/chunks/{TicketsPage-WdU4Bb7M.js.map → TicketsPage-jjyY15_D.js.map} +1 -1
- package/dist/chunks/{UserCreateTicketPage-Cm1emgwR.js → UserCreateTicketPage-B8Tvf-ag.js} +2 -2
- package/dist/chunks/{UserCreateTicketPage-Cm1emgwR.js.map → UserCreateTicketPage-B8Tvf-ag.js.map} +1 -1
- package/dist/chunks/{UserCreateTicketPage-BPw-5Y_D.js → UserCreateTicketPage-DnOsDlfO.js} +2 -2
- package/dist/chunks/{UserCreateTicketPage-BPw-5Y_D.js.map → UserCreateTicketPage-DnOsDlfO.js.map} +1 -1
- package/dist/chunks/{UserDashboardPage-BP5WeXPS.js → UserDashboardPage-BrtkJ-NB.js} +2 -2
- package/dist/chunks/{UserDashboardPage-BP5WeXPS.js.map → UserDashboardPage-BrtkJ-NB.js.map} +1 -1
- package/dist/chunks/{UserDashboardPage-B53C8fUq.js → UserDashboardPage-KLB5CQP5.js} +2 -2
- package/dist/chunks/{UserDashboardPage-B53C8fUq.js.map → UserDashboardPage-KLB5CQP5.js.map} +1 -1
- package/dist/chunks/{UserDetailPage-B110bmGX.js → UserDetailPage-U7smBQoF.js} +5 -5
- package/dist/chunks/{UserDetailPage-B110bmGX.js.map → UserDetailPage-U7smBQoF.js.map} +1 -1
- package/dist/chunks/{UserDetailPage-CV2VCE46.js → UserDetailPage-_J6lcKAU.js} +2 -2
- package/dist/chunks/{UserDetailPage-CV2VCE46.js.map → UserDetailPage-_J6lcKAU.js.map} +1 -1
- package/dist/chunks/{UserTicketDetailPage-CCNJON1V.js → UserTicketDetailPage-CWoYQgH-.js} +2 -2
- package/dist/chunks/{UserTicketDetailPage-CCNJON1V.js.map → UserTicketDetailPage-CWoYQgH-.js.map} +1 -1
- package/dist/chunks/{UserTicketDetailPage-V0mLXrox.js → UserTicketDetailPage-DkufSlvZ.js} +2 -2
- package/dist/chunks/{UserTicketDetailPage-V0mLXrox.js.map → UserTicketDetailPage-DkufSlvZ.js.map} +1 -1
- package/dist/chunks/{UsersGroupsPage-CmdaU-z-.js → UsersGroupsPage-C38s2-Rq.js} +3 -3
- package/dist/chunks/{UsersGroupsPage-CmdaU-z-.js.map → UsersGroupsPage-C38s2-Rq.js.map} +1 -1
- package/dist/chunks/{UsersGroupsPage-BgfAMgEP.js → UsersGroupsPage-Dq3rAteo.js} +2 -2
- package/dist/chunks/{UsersGroupsPage-BgfAMgEP.js.map → UsersGroupsPage-Dq3rAteo.js.map} +1 -1
- package/dist/chunks/{UsersPage-Bg7033pp.js → UsersPage-B5C5KEUR.js} +2 -2
- package/dist/chunks/{UsersPage-Bg7033pp.js.map → UsersPage-B5C5KEUR.js.map} +1 -1
- package/dist/chunks/{UsersPage-TYAfwPY1.js → UsersPage-CXC9Hvq6.js} +2 -2
- package/dist/chunks/{UsersPage-TYAfwPY1.js.map → UsersPage-CXC9Hvq6.js.map} +1 -1
- package/dist/chunks/{accessRequestsApi-DZeDvzwv.js → accessRequestsApi-B-4TJ5_U.js} +2 -2
- package/dist/chunks/{accessRequestsApi-DZeDvzwv.js.map → accessRequestsApi-B-4TJ5_U.js.map} +1 -1
- package/dist/chunks/{accessRequestsApi-ZXFPCid2.js → accessRequestsApi-DZSfThpd.js} +2 -2
- package/dist/chunks/{accessRequestsApi-ZXFPCid2.js.map → accessRequestsApi-DZSfThpd.js.map} +1 -1
- package/dist/chunks/{aiApi-CsH8DXgs.js → aiApi-B20Teu2v.js} +2 -2
- package/dist/chunks/{aiApi-CsH8DXgs.js.map → aiApi-B20Teu2v.js.map} +1 -1
- package/dist/chunks/{aiApi-CVPzFTXa.js → aiApi-DMGz-RPM.js} +2 -2
- package/dist/chunks/{aiApi-CVPzFTXa.js.map → aiApi-DMGz-RPM.js.map} +1 -1
- package/dist/chunks/{applicationAnalyticsApi-B8AhFYLr.js → applicationAnalyticsApi-Bwa75Fzd.js} +2 -2
- package/dist/chunks/{applicationAnalyticsApi-B8AhFYLr.js.map → applicationAnalyticsApi-Bwa75Fzd.js.map} +1 -1
- package/dist/chunks/{applicationAnalyticsApi-Ce_1qOk-.js → applicationAnalyticsApi-CLBqRPfN.js} +2 -2
- package/dist/chunks/{applicationAnalyticsApi-Ce_1qOk-.js.map → applicationAnalyticsApi-CLBqRPfN.js.map} +1 -1
- package/dist/chunks/{groupsApi-BgCk2fsp.js → groupsApi-QzXI-5xu.js} +2 -2
- package/dist/chunks/{groupsApi-BgCk2fsp.js.map → groupsApi-QzXI-5xu.js.map} +1 -1
- package/dist/chunks/{groupsApi-BIbG665N.js → groupsApi-hB9kSWEd.js} +2 -2
- package/dist/chunks/{groupsApi-BIbG665N.js.map → groupsApi-hB9kSWEd.js.map} +1 -1
- package/dist/chunks/{index-Cb3LotuT.js → index--NGcBYUu.js} +3 -3
- package/dist/chunks/{index-Cb3LotuT.js.map → index--NGcBYUu.js.map} +1 -1
- package/dist/chunks/{index-C33zcyF4.js → index--aPwOFjF.js} +2 -2
- package/dist/chunks/{index-C33zcyF4.js.map → index--aPwOFjF.js.map} +1 -1
- package/dist/chunks/{index-sMr9qND_.js → index-0VrOtwP0.js} +2 -2
- package/dist/chunks/{index-sMr9qND_.js.map → index-0VrOtwP0.js.map} +1 -1
- package/dist/chunks/{index-DDKetfKq.js → index-37U271aw.js} +2 -2
- package/dist/chunks/{index-DDKetfKq.js.map → index-37U271aw.js.map} +1 -1
- package/dist/chunks/{index-B9fS7ir6.js → index-B7qZTuQ-.js} +2 -2
- package/dist/chunks/{index-B9fS7ir6.js.map → index-B7qZTuQ-.js.map} +1 -1
- package/dist/chunks/{index-CdjBY7L8.js → index-Bedzmqr-.js} +2 -2
- package/dist/chunks/{index-CdjBY7L8.js.map → index-Bedzmqr-.js.map} +1 -1
- package/dist/chunks/{index-CHG_O1fS.js → index-Betxo5g5.js} +2 -2
- package/dist/chunks/{index-CHG_O1fS.js.map → index-Betxo5g5.js.map} +1 -1
- package/dist/chunks/{index-jiGu-H8x.js → index-BmaJz475.js} +2 -2
- package/dist/chunks/{index-jiGu-H8x.js.map → index-BmaJz475.js.map} +1 -1
- package/dist/chunks/{index-C53JoVNk.js → index-Buhqag3v.js} +2 -2
- package/dist/chunks/{index-C53JoVNk.js.map → index-Buhqag3v.js.map} +1 -1
- package/dist/chunks/{index-DO0Rw7hX.js → index-C3VxlfKq.js} +2 -2
- package/dist/chunks/{index-DO0Rw7hX.js.map → index-C3VxlfKq.js.map} +1 -1
- package/dist/chunks/{index-CSQ60fpG.js → index-CgpRo8Oe.js} +2 -2
- package/dist/chunks/{index-CSQ60fpG.js.map → index-CgpRo8Oe.js.map} +1 -1
- package/dist/chunks/{index-B-e-ELsf.js → index-DOY0w8Iu.js} +8 -8
- package/dist/chunks/{index-B-e-ELsf.js.map → index-DOY0w8Iu.js.map} +1 -1
- package/dist/chunks/{index-D2REDIRX.js → index-DwuvIOrQ.js} +2 -2
- package/dist/chunks/{index-D2REDIRX.js.map → index-DwuvIOrQ.js.map} +1 -1
- package/dist/chunks/{index-DCcl7Qof.js → index-DzedSLdI.js} +2 -2
- package/dist/chunks/{index-DCcl7Qof.js.map → index-DzedSLdI.js.map} +1 -1
- package/dist/chunks/{index-2wUhd9Lu.js → index-IgLVXPg8.js} +10 -10
- package/dist/chunks/index-IgLVXPg8.js.map +1 -0
- package/dist/chunks/{index-CwSaRXXg.js → index-lpIzhufD.js} +1916 -1900
- package/dist/chunks/index-lpIzhufD.js.map +1 -0
- package/dist/chunks/{index-Cuwn2q-f.js → index-mLUKwbGl.js} +4 -4
- package/dist/chunks/{index-Cuwn2q-f.js.map → index-mLUKwbGl.js.map} +1 -1
- package/dist/chunks/{index-B0mk2tNY.js → index-tO6MMIFB.js} +2 -2
- package/dist/chunks/{index-B0mk2tNY.js.map → index-tO6MMIFB.js.map} +1 -1
- package/dist/chunks/{tenantIconMap-BpNANQ5s.js → tenantIconMap-BQD9byc8.js} +2 -2
- package/dist/chunks/{tenantIconMap-BpNANQ5s.js.map → tenantIconMap-BQD9byc8.js.map} +1 -1
- package/dist/chunks/{tenantIconMap-DtdUgvJO.js → tenantIconMap-CTMuSt18.js} +2 -2
- package/dist/chunks/{tenantIconMap-DtdUgvJO.js.map → tenantIconMap-CTMuSt18.js.map} +1 -1
- package/dist/chunks/{ticketingApi-Bu4rKwLl.js → ticketingApi-BNIdox5t.js} +2 -2
- package/dist/chunks/{ticketingApi-Bu4rKwLl.js.map → ticketingApi-BNIdox5t.js.map} +1 -1
- package/dist/chunks/{ticketingApi-r4Avm9iS.js → ticketingApi-J0vC_t7r.js} +2 -2
- package/dist/chunks/{ticketingApi-r4Avm9iS.js.map → ticketingApi-J0vC_t7r.js.map} +1 -1
- package/dist/chunks/{useAccessRequests-B9bF4swg.js → useAccessRequests-DCNNLnxk.js} +3 -3
- package/dist/chunks/{useAccessRequests-B9bF4swg.js.map → useAccessRequests-DCNNLnxk.js.map} +1 -1
- package/dist/chunks/{useAccessRequests-JyPUX3Om.js → useAccessRequests-DT7X4FAK.js} +2 -2
- package/dist/chunks/{useAccessRequests-JyPUX3Om.js.map → useAccessRequests-DT7X4FAK.js.map} +1 -1
- package/dist/chunks/{useUserAccessRequests-DjPQenC2.js → useUserAccessRequests-BYbmG4c7.js} +2 -2
- package/dist/chunks/{useUserAccessRequests-DjPQenC2.js.map → useUserAccessRequests-BYbmG4c7.js.map} +1 -1
- package/dist/chunks/{useUserAccessRequests-BB6FHW14.js → useUserAccessRequests-CylKxRN6.js} +2 -2
- package/dist/chunks/{useUserAccessRequests-BB6FHW14.js.map → useUserAccessRequests-CylKxRN6.js.map} +1 -1
- package/dist/hooks/useCollapsibleState.d.ts +5 -2
- package/dist/hooks/useCollapsibleState.d.ts.map +1 -1
- package/dist/i18n/config.d.ts +1 -0
- package/dist/i18n/config.d.ts.map +1 -1
- package/dist/main.d.ts +0 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/smartstack.cjs +1 -1
- package/dist/smartstack.js +1 -1
- package/dist/utils/permissions.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/index-2wUhd9Lu.js.map +0 -1
- package/dist/chunks/index-CwSaRXXg.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage-B48_rQFi.js","sources":["../../src/components/dashboard/DeviceBreakdownChart.tsx","../../src/components/dashboard/EngagementMetricsCard.tsx","../../src/pages/platform/administration/DashboardPage.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Monitor, Smartphone, Tablet } from 'lucide-react';\r\nimport type { DeviceAnalyticsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface DeviceBreakdownChartProps {\r\n readonly data: DeviceAnalyticsDto | null;\r\n}\r\n\r\nconst deviceIcons: Record<string, React.ReactNode> = {\r\n Desktop: <Monitor className=\"w-4 h-4\" />,\r\n Mobile: <Smartphone className=\"w-4 h-4\" />,\r\n Tablet: <Tablet className=\"w-4 h-4\" />,\r\n Unknown: <Monitor className=\"w-4 h-4 opacity-50\" />\r\n};\r\n\r\nconst deviceColors = [\r\n '#3b82f6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#6b7280'\r\n];\r\n\r\nconst browserColors = [\r\n '#3b82f6',\r\n '#8b5cf6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#ef4444'\r\n];\r\n\r\nexport const DeviceBreakdownChart: React.FC<DeviceBreakdownChartProps> = ({ data }) => {\r\n if (!data || (!data.byDeviceType?.length && !data.byBrowser?.length)) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No device data available\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n {/* Device Type Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Device Type\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byDeviceType.map((device, index) => (\r\n <div key={device.deviceType} className=\"flex items-center gap-3\">\r\n <div className=\"flex items-center gap-2 w-28\">\r\n {deviceIcons[device.deviceType] || deviceIcons.Unknown}\r\n <span className=\"text-sm\">{device.deviceType}</span>\r\n </div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${device.percentage}%`,\r\n backgroundColor: deviceColors[index % deviceColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{device.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({device.percentage.toFixed(1)}%)\r\n </span>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Browser Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Browser\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byBrowser.map((browser, index) => {\r\n const maxCount = Math.max(...data.byBrowser.map(b => b.count), 1);\r\n const percentage = (browser.count / maxCount) * 100;\r\n\r\n return (\r\n <div key={browser.browser} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{browser.browser}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: browserColors[index % browserColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{browser.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface EngagementMetricsCardProps {\r\n readonly data: EngagementMetricsDto | null;\r\n}\r\n\r\nconst sessionColors = ['#ef4444', '#f59e0b', '#22c55e', '#3b82f6'];\r\n\r\nexport const EngagementMetricsCard: React.FC<EngagementMetricsCardProps> = ({ data }) => {\r\n if (!data) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No engagement data available\r\n </div>\r\n );\r\n }\r\n\r\n const maxBucketCount = Math.max(...data.sessionDistribution.map(b => b.count), 1);\r\n const maxHourCount = Math.max(...data.peakUsageHours.map(h => h.accessCount), 1);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Session Duration Distribution */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Session Duration Distribution\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.sessionDistribution.map((bucket, index) => {\r\n const percentage = (bucket.count / maxBucketCount) * 100;\r\n\r\n return (\r\n <div key={bucket.bucket} className=\"flex items-center gap-3\">\r\n <div className=\"w-20 text-sm\">{bucket.label}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: sessionColors[index % sessionColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-16 text-right\">\r\n <span className=\"font-medium\">{bucket.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n sessions\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Peak Usage Hours */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Peak Usage Hours\r\n </h4>\r\n <div className=\"flex items-end gap-1 h-32 overflow-x-auto pb-2\">\r\n {data.peakUsageHours.map((hourData) => {\r\n const heightPercentage = (hourData.accessCount / maxHourCount) * 100;\r\n\r\n return (\r\n <div\r\n key={hourData.hour}\r\n className=\"flex-1 min-w-[20px] flex flex-col items-center gap-1\"\r\n >\r\n <div\r\n className=\"w-full bg-gradient-to-t from-blue-500 to-cyan-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${heightPercentage}%`,\r\n minHeight: hourData.accessCount > 0 ? '4px' : '0'\r\n }}\r\n title={`${hourData.hour}h: ${hourData.accessCount} accesses`}\r\n />\r\n {hourData.hour % 3 === 0 && (\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {hourData.hour}h\r\n </span>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Engagement Summary */}\r\n <div className=\"grid grid-cols-2 gap-4 pt-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-blue-600\">\r\n {data.dailyActiveUsers}\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Daily Active Users\r\n </div>\r\n </div>\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-green-600\">\r\n {(data.retentionRate * 100).toFixed(1)}%\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Retention Rate\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Users,\r\n UserCheck,\r\n UserX,\r\n UserPlus,\r\n Activity,\r\n AlertTriangle,\r\n Key,\r\n Shield,\r\n TrendingUp,\r\n RefreshCw,\r\n Loader2,\r\n Clock,\r\n Globe,\r\n Monitor,\r\n} from 'lucide-react';\r\nimport {\r\n adminApi,\r\n type UserDashboardOverviewDto,\r\n type UserStatusCountDto,\r\n type UserRoleDistributionDto,\r\n type UserTrendDto,\r\n type SecurityAlertDto,\r\n type ActiveSessionsStatsDto,\r\n type LatestActiveSessionDto,\r\n} from '@/services/api/adminApi';\r\nimport { applicationAnalyticsApi } from '@/services/api/applicationAnalyticsApi';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport type { DeviceAnalyticsDto, EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\nimport { DeviceBreakdownChart } from '@/components/dashboard/DeviceBreakdownChart';\r\nimport { EngagementMetricsCard } from '@/components/dashboard/EngagementMetricsCard';\r\n\r\nconst statusColors: Record<string, string> = {\r\n Active: '#22c55e',\r\n Inactive: '#ef4444',\r\n};\r\n\r\nexport function AdminDashboardPage(): ReactElement {\r\n const { t } = useTranslation(['admin', 'navigation']);\r\n const navigate = useNavigate();\r\n const { currentTenant, isGlobalView } = useTenant();\r\n const [loading, setLoading] = useState(true);\r\n const [refreshing, setRefreshing] = useState(false);\r\n const [period, setPeriod] = useState(30);\r\n\r\n const [overview, setOverview] = useState<UserDashboardOverviewDto | null>(null);\r\n const [statusData, setStatusData] = useState<UserStatusCountDto[]>([]);\r\n const [roleData, setRoleData] = useState<UserRoleDistributionDto[]>([]);\r\n const [trends, setTrends] = useState<UserTrendDto[]>([]);\r\n const [latestSessions, setLatestSessions] = useState<LatestActiveSessionDto[]>([]);\r\n const [securityAlerts, setSecurityAlerts] = useState<SecurityAlertDto[]>([]);\r\n const [sessionStats, setSessionStats] = useState<ActiveSessionsStatsDto | null>(null);\r\n const [deviceStats, setDeviceStats] = useState<DeviceAnalyticsDto | null>(null);\r\n const [engagementMetrics, setEngagementMetrics] = useState<EngagementMetricsDto | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n // Ref to track if component is still mounted (StrictMode protection)\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n\r\n const loadData = useCallback(async (signal?: AbortSignal) => {\r\n try {\r\n setError(null);\r\n const [\r\n overviewRes,\r\n statusRes,\r\n roleRes,\r\n trendsRes,\r\n latestSessionsRes,\r\n alertsRes,\r\n sessionsRes,\r\n deviceRes,\r\n engagementRes,\r\n ] = await Promise.all([\r\n adminApi.dashboard.getOverview(period, { signal }),\r\n adminApi.dashboard.getByStatus({ signal }),\r\n adminApi.dashboard.getByRole({ signal }),\r\n adminApi.dashboard.getTrends(period, { signal }),\r\n adminApi.dashboard.getLatestActiveSessions(5, { signal }),\r\n adminApi.dashboard.getSecurityAlerts(3, 24, { signal }),\r\n adminApi.dashboard.getActiveSessions({ signal }),\r\n applicationAnalyticsApi.getDeviceStats(period, { signal }),\r\n applicationAnalyticsApi.getEngagementMetrics(period, { signal }),\r\n ]);\r\n\r\n // Only update state if request wasn't aborted\r\n if (!signal?.aborted) {\r\n setOverview(overviewRes ?? null);\r\n setStatusData(statusRes ?? []);\r\n setRoleData(roleRes ?? []);\r\n setTrends(trendsRes ?? []);\r\n setLatestSessions(latestSessionsRes ?? []);\r\n setSecurityAlerts(alertsRes ?? []);\r\n setSessionStats(sessionsRes ?? null);\r\n setDeviceStats(deviceRes ?? null);\r\n setEngagementMetrics(engagementRes ?? null);\r\n }\r\n } catch (err: unknown) {\r\n // Ignore abort errors (expected in StrictMode)\r\n if (err instanceof Error && err.name === 'CanceledError') {\r\n return;\r\n }\r\n console.error('Failed to load dashboard data:', err);\r\n const axiosError = err as { response?: { status?: number; data?: { message?: string } } };\r\n if (axiosError.response?.status === 401) {\r\n setError('Session expirée. Veuillez vous reconnecter.');\r\n } else if (axiosError.response?.status === 403) {\r\n setError('Vous n\\'avez pas les permissions nécessaires pour accéder au dashboard.');\r\n } else {\r\n setError('Erreur lors du chargement des données. Vérifiez que l\\'API est accessible.');\r\n }\r\n } finally {\r\n if (!signal?.aborted) {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }\r\n }, [period, currentTenant?.id, isGlobalView]);\r\n\r\n useEffect(() => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n loadData(controller.signal);\r\n\r\n // Cleanup: abort request when component unmounts or period changes\r\n return () => {\r\n controller.abort();\r\n };\r\n }, [loadData]);\r\n\r\n const handleRefresh = () => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n setRefreshing(true);\r\n loadData(controller.signal);\r\n };\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center min-h-[400px]\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-primary-600)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Breadcrumb */}\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title') },\r\n { label: t('dashboard.title') }\r\n ]}\r\n />\r\n\r\n {/* Error Banner */}\r\n {error && (\r\n <div className=\"bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 flex items-center gap-3\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-red-800 dark:text-red-200 font-medium\">{error}</p>\r\n </div>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200\"\r\n >\r\n <RefreshCw className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Users className=\"w-6 h-6\" />\r\n {t('admin:header.title')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)] mt-1\">\r\n Vue d'ensemble de la gestion des utilisateurs\r\n </p>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <select\r\n value={period}\r\n onChange={(e) => setPeriod(Number(e.target.value))}\r\n className=\"input\"\r\n >\r\n <option value={7}>7 derniers jours</option>\r\n <option value={30}>30 derniers jours</option>\r\n <option value={90}>90 derniers jours</option>\r\n </select>\r\n <button\r\n onClick={handleRefresh}\r\n disabled={refreshing}\r\n className=\"btn btn-secondary flex items-center gap-2\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />\r\n Actualiser\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* KPI Cards */}\r\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4\">\r\n <KpiCard\r\n title=\"Total Utilisateurs\"\r\n value={overview?.totalUsers ?? 0}\r\n icon={<Users className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n />\r\n <KpiCard\r\n title=\"Actifs\"\r\n value={overview?.activeUsers ?? 0}\r\n icon={<UserCheck className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n />\r\n <KpiCard\r\n title=\"Inactifs\"\r\n value={overview?.inactiveUsers ?? 0}\r\n icon={<UserX className=\"w-5 h-5\" />}\r\n color=\"red\"\r\n />\r\n <KpiCard\r\n title=\"Nouveaux\"\r\n value={overview?.newUsers ?? 0}\r\n icon={<UserPlus className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Sessions\"\r\n value={overview?.totalSessions ?? 0}\r\n icon={<Activity className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Connexions Echouées\"\r\n value={overview?.failedLogins ?? 0}\r\n icon={<AlertTriangle className=\"w-5 h-5\" />}\r\n color={(overview?.failedLogins ?? 0) > 10 ? 'red' : 'yellow'}\r\n subtitle={`${period} derniers jours`}\r\n />\r\n </div>\r\n\r\n {/* Security Alerts */}\r\n {(securityAlerts?.length ?? 0) > 0 && (\r\n <div className=\"card p-4 border-l-4 border-red-500\">\r\n <h3 className=\"font-semibold text-red-600 flex items-center gap-2 mb-3\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n Alertes Sécurité ({securityAlerts?.length ?? 0})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {(securityAlerts ?? []).slice(0, 5).map((alert) => (\r\n <button\r\n type=\"button\"\r\n key={alert.userId}\r\n className=\"w-full flex items-center justify-between p-2 bg-red-50 dark:bg-red-900/20 rounded cursor-pointer hover:bg-red-100 dark:hover:bg-red-900/30 text-left\"\r\n onClick={() => navigate(`/administration/users/${alert.userId}`)}\r\n >\r\n <div>\r\n <span className=\"font-medium\">{alert.fullName}</span>\r\n <span className=\"ml-2 text-sm text-[var(--text-secondary)]\">{alert.email}</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <span className=\"text-xs text-red-600 font-medium\">\r\n {alert.failedAttempts} échecs\r\n </span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {alert.ipAddresses?.length ?? 0} IP(s)\r\n </span>\r\n </div>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Charts Row */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Status Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <UserCheck className=\"w-5 h-5\" />\r\n Utilisateurs par Statut\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(statusData ?? []).map((item) => {\r\n const total = (statusData ?? []).reduce((sum, s) => sum + s.count, 0);\r\n const percentage = total > 0 ? (item.count / total) * 100 : 0;\r\n return (\r\n <div key={item.status} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{item.status === 'Active' ? 'Actifs' : 'Inactifs'}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: statusColors[item.status] || '#6b7280',\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{item.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({percentage.toFixed(0)}%)\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Role Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Key className=\"w-5 h-5\" />\r\n Utilisateurs par Rôle\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(roleData?.length ?? 0) > 0 ? (\r\n (roleData ?? []).map((item, index) => {\r\n const maxCount = Math.max(...(roleData ?? []).map(r => r.count), 1);\r\n const percentage = (item.count / maxCount) * 100;\r\n const colors = ['#3b82f6', '#8b5cf6', '#22c55e', '#f59e0b', '#ef4444'];\r\n return (\r\n <div key={item.roleName} className=\"flex items-center gap-3\">\r\n <div className=\"w-32 text-sm truncate\" title={item.roleName}>{item.roleName}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: colors[index % colors.length],\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })\r\n ) : (\r\n <div className=\"text-center py-4 text-[var(--text-secondary)]\">\r\n Aucun rôle configuré\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* System Stats */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* System Overview */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Shield className=\"w-5 h-5\" />\r\n Configuration Système\r\n </h3>\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-purple-600\">{overview?.totalRoles ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Rôles</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-green-600\">{overview?.totalPermissions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Permissions</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-blue-600\">{overview?.usersLoggedInRecently ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Connectés récemment</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-orange-600\">{sessionStats?.totalActiveSessions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Sessions actives</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Active Sessions Stats */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Sessions Actives\r\n </h3>\r\n {sessionStats && ((sessionStats.byBrowser?.length ?? 0) > 0 || (sessionStats.byCountry?.length ?? 0) > 0) ? (\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2\">Par Navigateur</h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byBrowser ?? []).map((item) => (\r\n <div key={item.browser} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.browser}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2 flex items-center gap-1\">\r\n <Globe className=\"w-4 h-4\" /> Par Pays\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byCountry?.length ?? 0) > 0 ? (\r\n (sessionStats.byCountry ?? []).map((item) => (\r\n <div key={item.country} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.country}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))\r\n ) : (\r\n <span className=\"text-[var(--text-secondary)] text-sm\">Non disponible</span>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Device & Engagement Metrics */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Device Analytics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Appareils & Navigateurs\r\n </h3>\r\n <DeviceBreakdownChart data={deviceStats} />\r\n </div>\r\n\r\n {/* Engagement Metrics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Activity className=\"w-5 h-5\" />\r\n Engagement Utilisateurs\r\n </h3>\r\n <EngagementMetricsCard data={engagementMetrics} />\r\n </div>\r\n </div>\r\n\r\n {/* Trends Chart */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <TrendingUp className=\"w-5 h-5\" />\r\n Tendances ({period} derniers jours)\r\n </h3>\r\n <div className=\"h-64\">\r\n <TrendChart data={trends ?? []} />\r\n </div>\r\n </div>\r\n\r\n {/* Latest Active Sessions */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Clock className=\"w-5 h-5\" />\r\n Dernières Sessions Actives\r\n </h3>\r\n {(latestSessions?.length ?? 0) > 0 ? (\r\n <div className=\"overflow-x-auto\">\r\n <table className=\"w-full\">\r\n <thead>\r\n <tr className=\"border-b border-[var(--border-color)]\">\r\n <th className=\"text-left p-3 font-medium\">Utilisateur</th>\r\n <th className=\"text-right p-3 font-medium\">Durée</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {(latestSessions ?? []).map((session) => (\r\n <tr\r\n key={session.userId + session.loginAt}\r\n className=\"border-b border-[var(--border-color)] hover:bg-[var(--bg-secondary)] cursor-pointer\"\r\n onClick={() => navigate(`/administration/users/${session.userId}`)}\r\n >\r\n <td className=\"p-3 font-medium\">{session.fullName}</td>\r\n <td className=\"p-3 text-right\">\r\n <span className=\"px-2 py-1 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400\">\r\n {session.duration}\r\n </span>\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nfunction KpiCard({\r\n title,\r\n value,\r\n icon,\r\n color,\r\n subtitle,\r\n}: {\r\n title: string;\r\n value: string | number;\r\n icon: React.ReactNode;\r\n color: 'blue' | 'green' | 'yellow' | 'red';\r\n subtitle?: string;\r\n}) {\r\n const colorClasses = {\r\n blue: 'bg-blue-50 text-blue-600 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800',\r\n green: 'bg-green-50 text-green-600 border-green-200 dark:bg-green-900/20 dark:border-green-800',\r\n yellow: 'bg-yellow-50 text-yellow-600 border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800',\r\n red: 'bg-red-50 text-red-600 border-red-200 dark:bg-red-900/20 dark:border-red-800',\r\n };\r\n\r\n return (\r\n <div className={`card p-4 border ${colorClasses[color]}`}>\r\n <div className=\"flex items-center justify-between mb-2\">\r\n <span className=\"text-sm font-medium opacity-80\">{title}</span>\r\n {icon}\r\n </div>\r\n <div className=\"text-2xl font-bold\">{value}</div>\r\n {subtitle && <div className=\"text-xs opacity-70 mt-1\">{subtitle}</div>}\r\n </div>\r\n );\r\n}\r\n\r\nfunction TrendChart({ data }: { data: UserTrendDto[] }) {\r\n if (data.length === 0) {\r\n return (\r\n <div className=\"flex items-center justify-center h-full text-[var(--text-secondary)]\">\r\n Aucune donnée de tendance disponible\r\n </div>\r\n );\r\n }\r\n\r\n const maxValue = Math.max(...data.flatMap((d) => [d.newUsers, d.logins]), 1);\r\n\r\n return (\r\n <div className=\"flex flex-col h-full\">\r\n <div className=\"flex items-center gap-4 mb-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-blue-500\" />\r\n <span className=\"text-sm\">Nouveaux utilisateurs</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-green-500\" />\r\n <span className=\"text-sm\">Connexions</span>\r\n </div>\r\n </div>\r\n <div className=\"flex-1 flex items-end gap-1 overflow-x-auto pb-4\">\r\n {data.map((item) => (\r\n <div key={`${item.date}`} className=\"flex-1 min-w-[20px] flex gap-0.5\">\r\n <div\r\n className=\"flex-1 bg-blue-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.newUsers / maxValue) * 100}%`,\r\n minHeight: item.newUsers > 0 ? '4px' : '0',\r\n }}\r\n title={`Nouveaux: ${item.newUsers}`}\r\n />\r\n <div\r\n className=\"flex-1 bg-green-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.logins / maxValue) * 100}%`,\r\n minHeight: item.logins > 0 ? '4px' : '0',\r\n }}\r\n title={`Connexions: ${item.logins}`}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n <div className=\"flex justify-between text-xs text-[var(--text-secondary)] mt-2\">\r\n <span>{data[0] && new Date(data[0].date).toLocaleDateString('fr-FR')}</span>\r\n <span>{data.at(-1) && new Date(data.at(-1)!.date).toLocaleDateString('fr-FR')}</span>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["deviceIcons","jsx","Monitor","Smartphone","Tablet","deviceColors","browserColors","DeviceBreakdownChart","data","jsxs","device","index","browser","maxCount","b","percentage","sessionColors","EngagementMetricsCard","maxBucketCount","maxHourCount","h","bucket","hourData","heightPercentage","statusColors","AdminDashboardPage","useTranslation","navigate","useNavigate","currentTenant","isGlobalView","useTenant","loading","setLoading","useState","refreshing","setRefreshing","period","setPeriod","overview","setOverview","statusData","setStatusData","roleData","setRoleData","trends","setTrends","latestSessions","setLatestSessions","securityAlerts","setSecurityAlerts","sessionStats","setSessionStats","deviceStats","setDeviceStats","engagementMetrics","setEngagementMetrics","error","setError","abortControllerRef","useRef","loadData","useCallback","signal","overviewRes","statusRes","roleRes","trendsRes","latestSessionsRes","alertsRes","sessionsRes","deviceRes","engagementRes","adminApi","applicationAnalyticsApi","err","axiosError","useEffect","controller","handleRefresh","Loader2","Breadcrumb","AlertTriangle","RefreshCw","Users","e","KpiCard","UserCheck","UserX","UserPlus","Activity","alert","item","total","sum","s","Key","r","colors","Shield","Globe","TrendingUp","TrendChart","Clock","session","title","value","icon","color","subtitle","colorClasses","maxValue","d"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage-CfKZHiSj.js","sources":["../../src/components/dashboard/DeviceBreakdownChart.tsx","../../src/components/dashboard/EngagementMetricsCard.tsx","../../src/pages/platform/administration/DashboardPage.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Monitor, Smartphone, Tablet } from 'lucide-react';\r\nimport type { DeviceAnalyticsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface DeviceBreakdownChartProps {\r\n readonly data: DeviceAnalyticsDto | null;\r\n}\r\n\r\nconst deviceIcons: Record<string, React.ReactNode> = {\r\n Desktop: <Monitor className=\"w-4 h-4\" />,\r\n Mobile: <Smartphone className=\"w-4 h-4\" />,\r\n Tablet: <Tablet className=\"w-4 h-4\" />,\r\n Unknown: <Monitor className=\"w-4 h-4 opacity-50\" />\r\n};\r\n\r\nconst deviceColors = [\r\n '#3b82f6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#6b7280'\r\n];\r\n\r\nconst browserColors = [\r\n '#3b82f6',\r\n '#8b5cf6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#ef4444'\r\n];\r\n\r\nexport const DeviceBreakdownChart: React.FC<DeviceBreakdownChartProps> = ({ data }) => {\r\n if (!data || (!data.byDeviceType?.length && !data.byBrowser?.length)) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No device data available\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n {/* Device Type Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Device Type\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byDeviceType.map((device, index) => (\r\n <div key={device.deviceType} className=\"flex items-center gap-3\">\r\n <div className=\"flex items-center gap-2 w-28\">\r\n {deviceIcons[device.deviceType] || deviceIcons.Unknown}\r\n <span className=\"text-sm\">{device.deviceType}</span>\r\n </div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${device.percentage}%`,\r\n backgroundColor: deviceColors[index % deviceColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{device.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({device.percentage.toFixed(1)}%)\r\n </span>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Browser Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Browser\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byBrowser.map((browser, index) => {\r\n const maxCount = Math.max(...data.byBrowser.map(b => b.count), 1);\r\n const percentage = (browser.count / maxCount) * 100;\r\n\r\n return (\r\n <div key={browser.browser} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{browser.browser}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: browserColors[index % browserColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{browser.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface EngagementMetricsCardProps {\r\n readonly data: EngagementMetricsDto | null;\r\n}\r\n\r\nconst sessionColors = ['#ef4444', '#f59e0b', '#22c55e', '#3b82f6'];\r\n\r\nexport const EngagementMetricsCard: React.FC<EngagementMetricsCardProps> = ({ data }) => {\r\n if (!data) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No engagement data available\r\n </div>\r\n );\r\n }\r\n\r\n const maxBucketCount = Math.max(...data.sessionDistribution.map(b => b.count), 1);\r\n const maxHourCount = Math.max(...data.peakUsageHours.map(h => h.accessCount), 1);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Session Duration Distribution */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Session Duration Distribution\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.sessionDistribution.map((bucket, index) => {\r\n const percentage = (bucket.count / maxBucketCount) * 100;\r\n\r\n return (\r\n <div key={bucket.bucket} className=\"flex items-center gap-3\">\r\n <div className=\"w-20 text-sm\">{bucket.label}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: sessionColors[index % sessionColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-16 text-right\">\r\n <span className=\"font-medium\">{bucket.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n sessions\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Peak Usage Hours */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Peak Usage Hours\r\n </h4>\r\n <div className=\"flex items-end gap-1 h-32 overflow-x-auto pb-2\">\r\n {data.peakUsageHours.map((hourData) => {\r\n const heightPercentage = (hourData.accessCount / maxHourCount) * 100;\r\n\r\n return (\r\n <div\r\n key={hourData.hour}\r\n className=\"flex-1 min-w-[20px] flex flex-col items-center gap-1\"\r\n >\r\n <div\r\n className=\"w-full bg-gradient-to-t from-blue-500 to-cyan-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${heightPercentage}%`,\r\n minHeight: hourData.accessCount > 0 ? '4px' : '0'\r\n }}\r\n title={`${hourData.hour}h: ${hourData.accessCount} accesses`}\r\n />\r\n {hourData.hour % 3 === 0 && (\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {hourData.hour}h\r\n </span>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Engagement Summary */}\r\n <div className=\"grid grid-cols-2 gap-4 pt-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-blue-600\">\r\n {data.dailyActiveUsers}\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Daily Active Users\r\n </div>\r\n </div>\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-green-600\">\r\n {(data.retentionRate * 100).toFixed(1)}%\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Retention Rate\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Users,\r\n UserCheck,\r\n UserX,\r\n UserPlus,\r\n Activity,\r\n AlertTriangle,\r\n Key,\r\n Shield,\r\n TrendingUp,\r\n RefreshCw,\r\n Loader2,\r\n Clock,\r\n Globe,\r\n Monitor,\r\n} from 'lucide-react';\r\nimport {\r\n adminApi,\r\n type UserDashboardOverviewDto,\r\n type UserStatusCountDto,\r\n type UserRoleDistributionDto,\r\n type UserTrendDto,\r\n type SecurityAlertDto,\r\n type ActiveSessionsStatsDto,\r\n type LatestActiveSessionDto,\r\n} from '@/services/api/adminApi';\r\nimport { applicationAnalyticsApi } from '@/services/api/applicationAnalyticsApi';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport type { DeviceAnalyticsDto, EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\nimport { DeviceBreakdownChart } from '@/components/dashboard/DeviceBreakdownChart';\r\nimport { EngagementMetricsCard } from '@/components/dashboard/EngagementMetricsCard';\r\n\r\nconst statusColors: Record<string, string> = {\r\n Active: '#22c55e',\r\n Inactive: '#ef4444',\r\n};\r\n\r\nexport function AdminDashboardPage(): ReactElement {\r\n const { t } = useTranslation(['admin', 'navigation']);\r\n const navigate = useNavigate();\r\n const { currentTenant, isGlobalView } = useTenant();\r\n const [loading, setLoading] = useState(true);\r\n const [refreshing, setRefreshing] = useState(false);\r\n const [period, setPeriod] = useState(30);\r\n\r\n const [overview, setOverview] = useState<UserDashboardOverviewDto | null>(null);\r\n const [statusData, setStatusData] = useState<UserStatusCountDto[]>([]);\r\n const [roleData, setRoleData] = useState<UserRoleDistributionDto[]>([]);\r\n const [trends, setTrends] = useState<UserTrendDto[]>([]);\r\n const [latestSessions, setLatestSessions] = useState<LatestActiveSessionDto[]>([]);\r\n const [securityAlerts, setSecurityAlerts] = useState<SecurityAlertDto[]>([]);\r\n const [sessionStats, setSessionStats] = useState<ActiveSessionsStatsDto | null>(null);\r\n const [deviceStats, setDeviceStats] = useState<DeviceAnalyticsDto | null>(null);\r\n const [engagementMetrics, setEngagementMetrics] = useState<EngagementMetricsDto | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n // Ref to track if component is still mounted (StrictMode protection)\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n\r\n const loadData = useCallback(async (signal?: AbortSignal) => {\r\n try {\r\n setError(null);\r\n const [\r\n overviewRes,\r\n statusRes,\r\n roleRes,\r\n trendsRes,\r\n latestSessionsRes,\r\n alertsRes,\r\n sessionsRes,\r\n deviceRes,\r\n engagementRes,\r\n ] = await Promise.all([\r\n adminApi.dashboard.getOverview(period, { signal }),\r\n adminApi.dashboard.getByStatus({ signal }),\r\n adminApi.dashboard.getByRole({ signal }),\r\n adminApi.dashboard.getTrends(period, { signal }),\r\n adminApi.dashboard.getLatestActiveSessions(5, { signal }),\r\n adminApi.dashboard.getSecurityAlerts(3, 24, { signal }),\r\n adminApi.dashboard.getActiveSessions({ signal }),\r\n applicationAnalyticsApi.getDeviceStats(period, { signal }),\r\n applicationAnalyticsApi.getEngagementMetrics(period, { signal }),\r\n ]);\r\n\r\n // Only update state if request wasn't aborted\r\n if (!signal?.aborted) {\r\n setOverview(overviewRes ?? null);\r\n setStatusData(statusRes ?? []);\r\n setRoleData(roleRes ?? []);\r\n setTrends(trendsRes ?? []);\r\n setLatestSessions(latestSessionsRes ?? []);\r\n setSecurityAlerts(alertsRes ?? []);\r\n setSessionStats(sessionsRes ?? null);\r\n setDeviceStats(deviceRes ?? null);\r\n setEngagementMetrics(engagementRes ?? null);\r\n }\r\n } catch (err: unknown) {\r\n // Ignore abort errors (expected in StrictMode)\r\n if (err instanceof Error && err.name === 'CanceledError') {\r\n return;\r\n }\r\n console.error('Failed to load dashboard data:', err);\r\n const axiosError = err as { response?: { status?: number; data?: { message?: string } } };\r\n if (axiosError.response?.status === 401) {\r\n setError('Session expirée. Veuillez vous reconnecter.');\r\n } else if (axiosError.response?.status === 403) {\r\n setError('Vous n\\'avez pas les permissions nécessaires pour accéder au dashboard.');\r\n } else {\r\n setError('Erreur lors du chargement des données. Vérifiez que l\\'API est accessible.');\r\n }\r\n } finally {\r\n if (!signal?.aborted) {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }\r\n }, [period, currentTenant?.id, isGlobalView]);\r\n\r\n useEffect(() => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n loadData(controller.signal);\r\n\r\n // Cleanup: abort request when component unmounts or period changes\r\n return () => {\r\n controller.abort();\r\n };\r\n }, [loadData]);\r\n\r\n const handleRefresh = () => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n setRefreshing(true);\r\n loadData(controller.signal);\r\n };\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center min-h-[400px]\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-primary-600)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Breadcrumb */}\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title') },\r\n { label: t('dashboard.title') }\r\n ]}\r\n />\r\n\r\n {/* Error Banner */}\r\n {error && (\r\n <div className=\"bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 flex items-center gap-3\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-red-800 dark:text-red-200 font-medium\">{error}</p>\r\n </div>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200\"\r\n >\r\n <RefreshCw className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Users className=\"w-6 h-6\" />\r\n {t('admin:header.title')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)] mt-1\">\r\n Vue d'ensemble de la gestion des utilisateurs\r\n </p>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <select\r\n value={period}\r\n onChange={(e) => setPeriod(Number(e.target.value))}\r\n className=\"input\"\r\n >\r\n <option value={7}>7 derniers jours</option>\r\n <option value={30}>30 derniers jours</option>\r\n <option value={90}>90 derniers jours</option>\r\n </select>\r\n <button\r\n onClick={handleRefresh}\r\n disabled={refreshing}\r\n className=\"btn btn-secondary flex items-center gap-2\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />\r\n Actualiser\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* KPI Cards */}\r\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4\">\r\n <KpiCard\r\n title=\"Total Utilisateurs\"\r\n value={overview?.totalUsers ?? 0}\r\n icon={<Users className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n />\r\n <KpiCard\r\n title=\"Actifs\"\r\n value={overview?.activeUsers ?? 0}\r\n icon={<UserCheck className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n />\r\n <KpiCard\r\n title=\"Inactifs\"\r\n value={overview?.inactiveUsers ?? 0}\r\n icon={<UserX className=\"w-5 h-5\" />}\r\n color=\"red\"\r\n />\r\n <KpiCard\r\n title=\"Nouveaux\"\r\n value={overview?.newUsers ?? 0}\r\n icon={<UserPlus className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Sessions\"\r\n value={overview?.totalSessions ?? 0}\r\n icon={<Activity className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Connexions Echouées\"\r\n value={overview?.failedLogins ?? 0}\r\n icon={<AlertTriangle className=\"w-5 h-5\" />}\r\n color={(overview?.failedLogins ?? 0) > 10 ? 'red' : 'yellow'}\r\n subtitle={`${period} derniers jours`}\r\n />\r\n </div>\r\n\r\n {/* Security Alerts */}\r\n {(securityAlerts?.length ?? 0) > 0 && (\r\n <div className=\"card p-4 border-l-4 border-red-500\">\r\n <h3 className=\"font-semibold text-red-600 flex items-center gap-2 mb-3\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n Alertes Sécurité ({securityAlerts?.length ?? 0})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {(securityAlerts ?? []).slice(0, 5).map((alert) => (\r\n <button\r\n type=\"button\"\r\n key={alert.userId}\r\n className=\"w-full flex items-center justify-between p-2 bg-red-50 dark:bg-red-900/20 rounded cursor-pointer hover:bg-red-100 dark:hover:bg-red-900/30 text-left\"\r\n onClick={() => navigate(`/administration/users/${alert.userId}`)}\r\n >\r\n <div>\r\n <span className=\"font-medium\">{alert.fullName}</span>\r\n <span className=\"ml-2 text-sm text-[var(--text-secondary)]\">{alert.email}</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <span className=\"text-xs text-red-600 font-medium\">\r\n {alert.failedAttempts} échecs\r\n </span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {alert.ipAddresses?.length ?? 0} IP(s)\r\n </span>\r\n </div>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Charts Row */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Status Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <UserCheck className=\"w-5 h-5\" />\r\n Utilisateurs par Statut\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(statusData ?? []).map((item) => {\r\n const total = (statusData ?? []).reduce((sum, s) => sum + s.count, 0);\r\n const percentage = total > 0 ? (item.count / total) * 100 : 0;\r\n return (\r\n <div key={item.status} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{item.status === 'Active' ? 'Actifs' : 'Inactifs'}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: statusColors[item.status] || '#6b7280',\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{item.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({percentage.toFixed(0)}%)\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Role Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Key className=\"w-5 h-5\" />\r\n Utilisateurs par Rôle\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(roleData?.length ?? 0) > 0 ? (\r\n (roleData ?? []).map((item, index) => {\r\n const maxCount = Math.max(...(roleData ?? []).map(r => r.count), 1);\r\n const percentage = (item.count / maxCount) * 100;\r\n const colors = ['#3b82f6', '#8b5cf6', '#22c55e', '#f59e0b', '#ef4444'];\r\n return (\r\n <div key={item.roleName} className=\"flex items-center gap-3\">\r\n <div className=\"w-32 text-sm truncate\" title={item.roleName}>{item.roleName}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: colors[index % colors.length],\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })\r\n ) : (\r\n <div className=\"text-center py-4 text-[var(--text-secondary)]\">\r\n Aucun rôle configuré\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* System Stats */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* System Overview */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Shield className=\"w-5 h-5\" />\r\n Configuration Système\r\n </h3>\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-purple-600\">{overview?.totalRoles ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Rôles</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-green-600\">{overview?.totalPermissions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Permissions</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-blue-600\">{overview?.usersLoggedInRecently ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Connectés récemment</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-orange-600\">{sessionStats?.totalActiveSessions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Sessions actives</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Active Sessions Stats */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Sessions Actives\r\n </h3>\r\n {sessionStats && ((sessionStats.byBrowser?.length ?? 0) > 0 || (sessionStats.byCountry?.length ?? 0) > 0) ? (\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2\">Par Navigateur</h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byBrowser ?? []).map((item) => (\r\n <div key={item.browser} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.browser}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2 flex items-center gap-1\">\r\n <Globe className=\"w-4 h-4\" /> Par Pays\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byCountry?.length ?? 0) > 0 ? (\r\n (sessionStats.byCountry ?? []).map((item) => (\r\n <div key={item.country} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.country}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))\r\n ) : (\r\n <span className=\"text-[var(--text-secondary)] text-sm\">Non disponible</span>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Device & Engagement Metrics */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Device Analytics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Appareils & Navigateurs\r\n </h3>\r\n <DeviceBreakdownChart data={deviceStats} />\r\n </div>\r\n\r\n {/* Engagement Metrics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Activity className=\"w-5 h-5\" />\r\n Engagement Utilisateurs\r\n </h3>\r\n <EngagementMetricsCard data={engagementMetrics} />\r\n </div>\r\n </div>\r\n\r\n {/* Trends Chart */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <TrendingUp className=\"w-5 h-5\" />\r\n Tendances ({period} derniers jours)\r\n </h3>\r\n <div className=\"h-64\">\r\n <TrendChart data={trends ?? []} />\r\n </div>\r\n </div>\r\n\r\n {/* Latest Active Sessions */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Clock className=\"w-5 h-5\" />\r\n Dernières Sessions Actives\r\n </h3>\r\n {(latestSessions?.length ?? 0) > 0 ? (\r\n <div className=\"overflow-x-auto\">\r\n <table className=\"w-full\">\r\n <thead>\r\n <tr className=\"border-b border-[var(--border-color)]\">\r\n <th className=\"text-left p-3 font-medium\">Utilisateur</th>\r\n <th className=\"text-right p-3 font-medium\">Durée</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {(latestSessions ?? []).map((session) => (\r\n <tr\r\n key={session.userId + session.loginAt}\r\n className=\"border-b border-[var(--border-color)] hover:bg-[var(--bg-secondary)] cursor-pointer\"\r\n onClick={() => navigate(`/administration/users/${session.userId}`)}\r\n >\r\n <td className=\"p-3 font-medium\">{session.fullName}</td>\r\n <td className=\"p-3 text-right\">\r\n <span className=\"px-2 py-1 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400\">\r\n {session.duration}\r\n </span>\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nfunction KpiCard({\r\n title,\r\n value,\r\n icon,\r\n color,\r\n subtitle,\r\n}: {\r\n title: string;\r\n value: string | number;\r\n icon: React.ReactNode;\r\n color: 'blue' | 'green' | 'yellow' | 'red';\r\n subtitle?: string;\r\n}) {\r\n const colorClasses = {\r\n blue: 'bg-blue-50 text-blue-600 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800',\r\n green: 'bg-green-50 text-green-600 border-green-200 dark:bg-green-900/20 dark:border-green-800',\r\n yellow: 'bg-yellow-50 text-yellow-600 border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800',\r\n red: 'bg-red-50 text-red-600 border-red-200 dark:bg-red-900/20 dark:border-red-800',\r\n };\r\n\r\n return (\r\n <div className={`card p-4 border ${colorClasses[color]}`}>\r\n <div className=\"flex items-center justify-between mb-2\">\r\n <span className=\"text-sm font-medium opacity-80\">{title}</span>\r\n {icon}\r\n </div>\r\n <div className=\"text-2xl font-bold\">{value}</div>\r\n {subtitle && <div className=\"text-xs opacity-70 mt-1\">{subtitle}</div>}\r\n </div>\r\n );\r\n}\r\n\r\nfunction TrendChart({ data }: { data: UserTrendDto[] }) {\r\n if (data.length === 0) {\r\n return (\r\n <div className=\"flex items-center justify-center h-full text-[var(--text-secondary)]\">\r\n Aucune donnée de tendance disponible\r\n </div>\r\n );\r\n }\r\n\r\n const maxValue = Math.max(...data.flatMap((d) => [d.newUsers, d.logins]), 1);\r\n\r\n return (\r\n <div className=\"flex flex-col h-full\">\r\n <div className=\"flex items-center gap-4 mb-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-blue-500\" />\r\n <span className=\"text-sm\">Nouveaux utilisateurs</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-green-500\" />\r\n <span className=\"text-sm\">Connexions</span>\r\n </div>\r\n </div>\r\n <div className=\"flex-1 flex items-end gap-1 overflow-x-auto pb-4\">\r\n {data.map((item) => (\r\n <div key={`${item.date}`} className=\"flex-1 min-w-[20px] flex gap-0.5\">\r\n <div\r\n className=\"flex-1 bg-blue-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.newUsers / maxValue) * 100}%`,\r\n minHeight: item.newUsers > 0 ? '4px' : '0',\r\n }}\r\n title={`Nouveaux: ${item.newUsers}`}\r\n />\r\n <div\r\n className=\"flex-1 bg-green-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.logins / maxValue) * 100}%`,\r\n minHeight: item.logins > 0 ? '4px' : '0',\r\n }}\r\n title={`Connexions: ${item.logins}`}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n <div className=\"flex justify-between text-xs text-[var(--text-secondary)] mt-2\">\r\n <span>{data[0] && new Date(data[0].date).toLocaleDateString('fr-FR')}</span>\r\n <span>{data.at(-1) && new Date(data.at(-1)!.date).toLocaleDateString('fr-FR')}</span>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["deviceIcons","jsx","Monitor","Smartphone","Tablet","deviceColors","browserColors","DeviceBreakdownChart","data","jsxs","device","index","browser","maxCount","b","percentage","sessionColors","EngagementMetricsCard","maxBucketCount","maxHourCount","h","bucket","hourData","heightPercentage","statusColors","AdminDashboardPage","useTranslation","navigate","useNavigate","currentTenant","isGlobalView","useTenant","loading","setLoading","useState","refreshing","setRefreshing","period","setPeriod","overview","setOverview","statusData","setStatusData","roleData","setRoleData","trends","setTrends","latestSessions","setLatestSessions","securityAlerts","setSecurityAlerts","sessionStats","setSessionStats","deviceStats","setDeviceStats","engagementMetrics","setEngagementMetrics","error","setError","abortControllerRef","useRef","loadData","useCallback","signal","overviewRes","statusRes","roleRes","trendsRes","latestSessionsRes","alertsRes","sessionsRes","deviceRes","engagementRes","adminApi","applicationAnalyticsApi","err","axiosError","useEffect","controller","handleRefresh","Loader2","Breadcrumb","AlertTriangle","RefreshCw","Users","e","KpiCard","UserCheck","UserX","UserPlus","Activity","alert","item","total","sum","s","Key","r","colors","Shield","Globe","TrendingUp","TrendChart","Clock","session","title","value","icon","color","subtitle","colorClasses","maxValue","d"],"mappings":"gTAQMA,EAA+C,CACnD,QAASC,EAAAA,IAACC,EAAAA,QAAA,CAAQ,UAAU,SAAA,CAAU,EACtC,OAAQD,EAAAA,IAACE,EAAAA,WAAA,CAAW,UAAU,SAAA,CAAU,EACxC,OAAQF,EAAAA,IAACG,EAAAA,OAAA,CAAO,UAAU,SAAA,CAAU,EACpC,QAASH,EAAAA,IAACC,EAAAA,QAAA,CAAQ,UAAU,oBAAA,CAAqB,CACnD,EAEMG,EAAe,CACnB,UACA,UACA,UACA,SACF,EAEMC,EAAgB,CACpB,UACA,UACA,UACA,UACA,SACF,EAEaC,GAA4D,CAAC,CAAE,KAAAC,KACtE,CAACA,GAAS,CAACA,EAAK,cAAc,QAAU,CAACA,EAAK,WAAW,OAEzDP,EAAAA,IAAC,MAAA,CAAI,UAAU,gDAAgD,SAAA,2BAE/D,EAKFQ,EAAAA,KAAC,MAAA,CAAI,UAAU,wCAEb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAR,EAAAA,IAAC,KAAA,CAAG,UAAU,wDAAwD,SAAA,iBAEtE,EACAA,EAAAA,IAAC,MAAA,CAAI,UAAU,YACZ,SAAAO,EAAK,aAAa,IAAI,CAACE,EAAQC,IAC9BF,OAAC,MAAA,CAA4B,UAAU,0BACrC,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,+BACZ,SAAA,CAAAT,EAAYU,EAAO,UAAU,GAAKV,EAAY,QAC/CC,EAAAA,IAAC,OAAA,CAAK,UAAU,UAAW,WAAO,UAAA,CAAW,CAAA,EAC/C,EACAA,EAAAA,IAAC,MAAA,CAAI,UAAU,mEACb,SAAAA,EAAAA,IAAC,MAAA,CACC,UAAU,kDACV,MAAO,CACL,MAAO,GAAGS,EAAO,UAAU,IAC3B,gBAAiBL,EAAaM,EAAQN,EAAa,MAAM,CAAA,CAC3D,CAAA,EAEJ,EACAI,EAAAA,KAAC,MAAA,CAAI,UAAU,kBACb,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAK,UAAU,cAAe,SAAAS,EAAO,MAAM,EAC5CD,EAAAA,KAAC,OAAA,CAAK,UAAU,4CAA4C,SAAA,CAAA,IACxDC,EAAO,WAAW,QAAQ,CAAC,EAAE,IAAA,CAAA,CACjC,CAAA,CAAA,CACF,CAAA,GAnBQA,EAAO,UAoBjB,CACD,CAAA,CACH,CAAA,EACF,SAGC,MAAA,CACC,SAAA,CAAAT,EAAAA,IAAC,KAAA,CAAG,UAAU,wDAAwD,SAAA,aAEtE,EACAA,EAAAA,IAAC,OAAI,UAAU,YACZ,WAAK,UAAU,IAAI,CAACW,EAASD,IAAU,CACtC,MAAME,EAAW,KAAK,IAAI,GAAGL,EAAK,UAAU,IAAIM,GAAKA,EAAE,KAAK,EAAG,CAAC,EAC1DC,EAAcH,EAAQ,MAAQC,EAAY,IAEhD,OACEJ,EAAAA,KAAC,MAAA,CAA0B,UAAU,0BACnC,SAAA,CAAAR,EAAAA,IAAC,MAAA,CAAI,UAAU,eAAgB,SAAAW,EAAQ,QAAQ,EAC/CX,EAAAA,IAAC,MAAA,CAAI,UAAU,mEACb,SAAAA,EAAAA,IAAC,MAAA,CACC,UAAU,kDACV,MAAO,CACL,MAAO,GAAGc,CAAU,IACpB,gBAAiBT,EAAcK,EAAQL,EAAc,MAAM,CAAA,CAC7D,CAAA,EAEJ,EACAL,EAAAA,IAAC,MAAA,CAAI,UAAU,8BAA+B,WAAQ,KAAA,CAAM,CAAA,CAAA,EAXpDW,EAAQ,OAYlB,CAEJ,CAAC,CAAA,CACH,CAAA,CAAA,CACF,CAAA,EACF,EC9FEI,EAAgB,CAAC,UAAW,UAAW,UAAW,SAAS,EAEpDC,GAA8D,CAAC,CAAE,KAAAT,KAAW,CACvF,GAAI,CAACA,EACH,OACEP,EAAAA,IAAC,MAAA,CAAI,UAAU,gDAAgD,SAAA,+BAE/D,EAIJ,MAAMiB,EAAiB,KAAK,IAAI,GAAGV,EAAK,oBAAoB,IAAIM,GAAKA,EAAE,KAAK,EAAG,CAAC,EAC1EK,EAAe,KAAK,IAAI,GAAGX,EAAK,eAAe,IAAIY,GAAKA,EAAE,WAAW,EAAG,CAAC,EAE/E,OACEX,EAAAA,KAAC,MAAA,CAAI,UAAU,YAEb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAR,EAAAA,IAAC,KAAA,CAAG,UAAU,wDAAwD,SAAA,gCAEtE,EACAA,EAAAA,IAAC,OAAI,UAAU,YACZ,WAAK,oBAAoB,IAAI,CAACoB,EAAQV,IAAU,CAC/C,MAAMI,EAAcM,EAAO,MAAQH,EAAkB,IAErD,OACET,EAAAA,KAAC,MAAA,CAAwB,UAAU,0BACjC,SAAA,CAAAR,EAAAA,IAAC,MAAA,CAAI,UAAU,eAAgB,SAAAoB,EAAO,MAAM,EAC5CpB,EAAAA,IAAC,MAAA,CAAI,UAAU,mEACb,SAAAA,EAAAA,IAAC,MAAA,CACC,UAAU,kDACV,MAAO,CACL,MAAO,GAAGc,CAAU,IACpB,gBAAiBC,EAAcL,EAAQK,EAAc,MAAM,CAAA,CAC7D,CAAA,EAEJ,EACAP,EAAAA,KAAC,MAAA,CAAI,UAAU,kBACb,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAK,UAAU,cAAe,SAAAoB,EAAO,MAAM,EAC5CpB,EAAAA,IAAC,OAAA,CAAK,UAAU,4CAA4C,SAAA,UAAA,CAE5D,CAAA,CAAA,CACF,CAAA,CAAA,EAhBQoB,EAAO,MAiBjB,CAEJ,CAAC,CAAA,CACH,CAAA,EACF,SAGC,MAAA,CACC,SAAA,CAAApB,EAAAA,IAAC,KAAA,CAAG,UAAU,wDAAwD,SAAA,mBAEtE,EACAA,MAAC,OAAI,UAAU,iDACZ,WAAK,eAAe,IAAKqB,GAAa,CACrC,MAAMC,EAAoBD,EAAS,YAAcH,EAAgB,IAEjE,OACEV,EAAAA,KAAC,MAAA,CAEC,UAAU,uDAEV,SAAA,CAAAR,EAAAA,IAAC,MAAA,CACC,UAAU,2GACV,MAAO,CACL,OAAQ,GAAGsB,CAAgB,IAC3B,UAAWD,EAAS,YAAc,EAAI,MAAQ,GAAA,EAEhD,MAAO,GAAGA,EAAS,IAAI,MAAMA,EAAS,WAAW,WAAA,CAAA,EAElDA,EAAS,KAAO,IAAM,GACrBb,EAAAA,KAAC,OAAA,CAAK,UAAU,uCACb,SAAA,CAAAa,EAAS,KAAK,GAAA,CAAA,CACjB,CAAA,CAAA,EAdGA,EAAS,IAAA,CAkBpB,CAAC,CAAA,CACH,CAAA,EACF,EAGAb,EAAAA,KAAC,MAAA,CAAI,UAAU,oEACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,sDACb,SAAA,CAAAR,EAAAA,IAAC,MAAA,CAAI,UAAU,mCACZ,SAAAO,EAAK,iBACR,EACAP,EAAAA,IAAC,MAAA,CAAI,UAAU,4CAA4C,SAAA,oBAAA,CAE3D,CAAA,EACF,EACAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,sDACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,oCACX,SAAA,EAAAD,EAAK,cAAgB,KAAK,QAAQ,CAAC,EAAE,GAAA,EACzC,EACAP,EAAAA,IAAC,MAAA,CAAI,UAAU,4CAA4C,SAAA,gBAAA,CAE3D,CAAA,CAAA,CACF,CAAA,CAAA,CACF,CAAA,EACF,CAEJ,ECzEMuB,GAAuC,CAC3C,OAAQ,UACR,SAAU,SACZ,EAEO,SAASC,IAAmC,CACjD,KAAM,CAAE,CAAA,EAAMC,GAAAA,eAAe,CAAC,QAAS,YAAY,CAAC,EAC9CC,EAAWC,EAAAA,YAAA,EACX,CAAE,cAAAC,EAAe,aAAAC,CAAA,EAAiBC,YAAA,EAClC,CAACC,EAASC,CAAU,EAAIC,EAAAA,SAAS,EAAI,EACrC,CAACC,EAAYC,CAAa,EAAIF,EAAAA,SAAS,EAAK,EAC5C,CAACG,EAAQC,CAAS,EAAIJ,EAAAA,SAAS,EAAE,EAEjC,CAACK,EAAUC,CAAW,EAAIN,EAAAA,SAA0C,IAAI,EACxE,CAACO,EAAYC,CAAa,EAAIR,EAAAA,SAA+B,CAAA,CAAE,EAC/D,CAACS,EAAUC,CAAW,EAAIV,EAAAA,SAAoC,CAAA,CAAE,EAChE,CAACW,EAAQC,CAAS,EAAIZ,EAAAA,SAAyB,CAAA,CAAE,EACjD,CAACa,EAAgBC,CAAiB,EAAId,EAAAA,SAAmC,CAAA,CAAE,EAC3E,CAACe,EAAgBC,CAAiB,EAAIhB,EAAAA,SAA6B,CAAA,CAAE,EACrE,CAACiB,EAAcC,CAAe,EAAIlB,EAAAA,SAAwC,IAAI,EAC9E,CAACmB,EAAaC,CAAc,EAAIpB,EAAAA,SAAoC,IAAI,EACxE,CAACqB,EAAmBC,CAAoB,EAAItB,EAAAA,SAAsC,IAAI,EACtF,CAACuB,EAAOC,CAAQ,EAAIxB,EAAAA,SAAwB,IAAI,EAGhDyB,EAAqBC,EAAAA,OAA+B,IAAI,EAExDC,EAAWC,cAAY,MAAOC,GAAyB,CAC3D,GAAI,CACFL,EAAS,IAAI,EACb,KAAM,CACJM,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,CAAA,EACE,MAAM,QAAQ,IAAI,CACpBC,EAAAA,SAAS,UAAU,YAAYpC,EAAQ,CAAE,OAAA0B,EAAQ,EACjDU,EAAAA,SAAS,UAAU,YAAY,CAAE,OAAAV,EAAQ,EACzCU,EAAAA,SAAS,UAAU,UAAU,CAAE,OAAAV,EAAQ,EACvCU,EAAAA,SAAS,UAAU,UAAUpC,EAAQ,CAAE,OAAA0B,EAAQ,EAC/CU,EAAAA,SAAS,UAAU,wBAAwB,EAAG,CAAE,OAAAV,EAAQ,EACxDU,EAAAA,SAAS,UAAU,kBAAkB,EAAG,GAAI,CAAE,OAAAV,EAAQ,EACtDU,EAAAA,SAAS,UAAU,kBAAkB,CAAE,OAAAV,EAAQ,EAC/CW,EAAAA,wBAAwB,eAAerC,EAAQ,CAAE,OAAA0B,EAAQ,EACzDW,EAAAA,wBAAwB,qBAAqBrC,EAAQ,CAAE,OAAA0B,EAAQ,CAAA,CAChE,EAGIA,GAAQ,UACXvB,EAAYwB,GAAe,IAAI,EAC/BtB,EAAcuB,GAAa,EAAE,EAC7BrB,EAAYsB,GAAW,EAAE,EACzBpB,EAAUqB,GAAa,EAAE,EACzBnB,EAAkBoB,GAAqB,EAAE,EACzClB,EAAkBmB,GAAa,EAAE,EACjCjB,EAAgBkB,GAAe,IAAI,EACnChB,EAAeiB,GAAa,IAAI,EAChCf,EAAqBgB,GAAiB,IAAI,EAE9C,OAASG,EAAc,CAErB,GAAIA,aAAe,OAASA,EAAI,OAAS,gBACvC,OAEF,QAAQ,MAAM,iCAAkCA,CAAG,EACnD,MAAMC,EAAaD,EACfC,EAAW,UAAU,SAAW,IAClClB,EAAS,6CAA6C,EAC7CkB,EAAW,UAAU,SAAW,IACzClB,EAAS,wEAAyE,EAElFA,EAAS,2EAA4E,CAEzF,QAAA,CACOK,GAAQ,UACX9B,EAAW,EAAK,EAChBG,EAAc,EAAK,EAEvB,CACF,EAAG,CAACC,EAAQR,GAAe,GAAIC,CAAY,CAAC,EAE5C+C,EAAAA,UAAU,IAAM,CAEdlB,EAAmB,SAAS,MAAA,EAC5B,MAAMmB,EAAa,IAAI,gBACvB,OAAAnB,EAAmB,QAAUmB,EAE7BjB,EAASiB,EAAW,MAAM,EAGnB,IAAM,CACXA,EAAW,MAAA,CACb,CACF,EAAG,CAACjB,CAAQ,CAAC,EAEb,MAAMkB,EAAgB,IAAM,CAE1BpB,EAAmB,SAAS,MAAA,EAC5B,MAAMmB,EAAa,IAAI,gBACvBnB,EAAmB,QAAUmB,EAE7B1C,EAAc,EAAI,EAClByB,EAASiB,EAAW,MAAM,CAC5B,EAEA,OAAI9C,EAEA/B,MAAC,OAAI,UAAU,iDACb,eAAC+E,EAAAA,QAAA,CAAQ,UAAU,uDAAuD,CAAA,CAC5E,EAKFvE,EAAAA,KAAC,MAAA,CAAI,UAAU,YAEb,SAAA,CAAAR,EAAAA,IAACgF,EAAAA,WAAA,CACC,MAAO,CACL,CAAE,MAAO,EAAE,cAAc,CAAA,EACzB,CAAE,MAAO,EAAE,iBAAiB,CAAA,CAAE,CAChC,CAAA,EAIDxB,GACChD,EAAAA,KAAC,MAAA,CAAI,UAAU,gHACb,SAAA,CAAAR,EAAAA,IAACiF,EAAAA,cAAA,CAAc,UAAU,sDAAA,CAAuD,EAChFjF,EAAAA,IAAC,OAAI,UAAU,SACb,eAAC,IAAA,CAAE,UAAU,6CAA8C,SAAAwD,CAAA,CAAM,CAAA,CACnE,EACAxD,EAAAA,IAAC,SAAA,CACC,QAAS8E,EACT,UAAU,4EAEV,SAAA9E,EAAAA,IAACkF,EAAAA,UAAA,CAAU,UAAU,SAAA,CAAU,CAAA,CAAA,CACjC,EACF,EAIF1E,EAAAA,KAAC,MAAA,CAAI,UAAU,oCACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,wEACZ,SAAA,CAAAR,EAAAA,IAACmF,EAAAA,MAAA,CAAM,UAAU,SAAA,CAAU,EAC1B,EAAE,oBAAoB,CAAA,EACzB,EACAnF,EAAAA,IAAC,IAAA,CAAE,UAAU,oCAAoC,SAAA,+CAAA,CAEjD,CAAA,EACF,EACAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAA,EAAAA,KAAC,SAAA,CACC,MAAO4B,EACP,SAAWgD,GAAM/C,EAAU,OAAO+C,EAAE,OAAO,KAAK,CAAC,EACjD,UAAU,QAEV,SAAA,CAAApF,EAAAA,IAAC,SAAA,CAAO,MAAO,EAAG,SAAA,mBAAgB,EAClCA,EAAAA,IAAC,SAAA,CAAO,MAAO,GAAI,SAAA,oBAAiB,EACpCA,EAAAA,IAAC,SAAA,CAAO,MAAO,GAAI,SAAA,mBAAA,CAAiB,CAAA,CAAA,CAAA,EAEtCQ,EAAAA,KAAC,SAAA,CACC,QAASsE,EACT,SAAU5C,EACV,UAAU,4CAEV,SAAA,CAAAlC,MAACkF,EAAAA,WAAU,UAAW,WAAWhD,EAAa,eAAiB,EAAE,GAAI,EAAE,YAAA,CAAA,CAAA,CAEzE,CAAA,CACF,CAAA,EACF,EAGA1B,EAAAA,KAAC,MAAA,CAAI,UAAU,uDACb,SAAA,CAAAR,EAAAA,IAACqF,EAAA,CACC,MAAM,qBACN,MAAO/C,GAAU,YAAc,EAC/B,KAAMtC,EAAAA,IAACmF,EAAAA,MAAA,CAAM,UAAU,SAAA,CAAU,EACjC,MAAM,MAAA,CAAA,EAERnF,EAAAA,IAACqF,EAAA,CACC,MAAM,SACN,MAAO/C,GAAU,aAAe,EAChC,KAAMtC,EAAAA,IAACsF,EAAAA,UAAA,CAAU,UAAU,SAAA,CAAU,EACrC,MAAM,OAAA,CAAA,EAERtF,EAAAA,IAACqF,EAAA,CACC,MAAM,WACN,MAAO/C,GAAU,eAAiB,EAClC,KAAMtC,EAAAA,IAACuF,EAAAA,MAAA,CAAM,UAAU,SAAA,CAAU,EACjC,MAAM,KAAA,CAAA,EAERvF,EAAAA,IAACqF,EAAA,CACC,MAAM,WACN,MAAO/C,GAAU,UAAY,EAC7B,KAAMtC,EAAAA,IAACwF,EAAAA,SAAA,CAAS,UAAU,SAAA,CAAU,EACpC,MAAM,OACN,SAAU,GAAGpD,CAAM,iBAAA,CAAA,EAErBpC,EAAAA,IAACqF,EAAA,CACC,MAAM,WACN,MAAO/C,GAAU,eAAiB,EAClC,KAAMtC,EAAAA,IAACyF,EAAAA,SAAA,CAAS,UAAU,SAAA,CAAU,EACpC,MAAM,QACN,SAAU,GAAGrD,CAAM,iBAAA,CAAA,EAErBpC,EAAAA,IAACqF,EAAA,CACC,MAAM,sBACN,MAAO/C,GAAU,cAAgB,EACjC,KAAMtC,EAAAA,IAACiF,EAAAA,cAAA,CAAc,UAAU,SAAA,CAAU,EACzC,OAAQ3C,GAAU,cAAgB,GAAK,GAAK,MAAQ,SACpD,SAAU,GAAGF,CAAM,iBAAA,CAAA,CACrB,EACF,GAGEY,GAAgB,QAAU,GAAK,GAC/BxC,OAAC,MAAA,CAAI,UAAU,qCACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,0DACZ,SAAA,CAAAR,EAAAA,IAACiF,EAAAA,cAAA,CAAc,UAAU,SAAA,CAAU,EAAE,qBAClBjC,GAAgB,QAAU,EAAE,GAAA,EACjD,EACAhD,EAAAA,IAAC,MAAA,CAAI,UAAU,qCACX,UAAAgD,GAAkB,CAAA,GAAI,MAAM,EAAG,CAAC,EAAE,IAAK0C,GACvClF,EAAAA,KAAC,SAAA,CACC,KAAK,SAEL,UAAU,uJACV,QAAS,IAAMkB,EAAS,yBAAyBgE,EAAM,MAAM,EAAE,EAE/D,SAAA,CAAAlF,OAAC,MAAA,CACC,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAK,UAAU,cAAe,SAAA0F,EAAM,SAAS,EAC9C1F,EAAAA,IAAC,OAAA,CAAK,UAAU,4CAA6C,WAAM,KAAA,CAAM,CAAA,EAC3E,EACAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAA,EAAAA,KAAC,OAAA,CAAK,UAAU,mCACb,SAAA,CAAAkF,EAAM,eAAe,SAAA,EACxB,EACAlF,EAAAA,KAAC,OAAA,CAAK,UAAU,uCACb,SAAA,CAAAkF,EAAM,aAAa,QAAU,EAAE,QAAA,CAAA,CAClC,CAAA,CAAA,CACF,CAAA,CAAA,EAfKA,EAAM,MAAA,CAiBd,CAAA,CACH,CAAA,EACF,EAIFlF,EAAAA,KAAC,MAAA,CAAI,UAAU,wCAEb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,WACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,6CACZ,SAAA,CAAAR,EAAAA,IAACsF,EAAAA,UAAA,CAAU,UAAU,SAAA,CAAU,EAAE,yBAAA,EAEnC,EACAtF,EAAAA,IAAC,OAAI,UAAU,YACX,aAAc,CAAA,GAAI,IAAK2F,GAAS,CAChC,MAAMC,GAASpD,GAAc,CAAA,GAAI,OAAO,CAACqD,EAAKC,IAAMD,EAAMC,EAAE,MAAO,CAAC,EAC9DhF,EAAa8E,EAAQ,EAAKD,EAAK,MAAQC,EAAS,IAAM,EAC5D,OACEpF,EAAAA,KAAC,MAAA,CAAsB,UAAU,0BAC/B,SAAA,CAAAR,EAAAA,IAAC,OAAI,UAAU,eAAgB,WAAK,SAAW,SAAW,SAAW,UAAA,CAAW,EAChFA,EAAAA,IAAC,MAAA,CAAI,UAAU,mEACb,SAAAA,EAAAA,IAAC,MAAA,CACC,UAAU,kDACV,MAAO,CACL,MAAO,GAAGc,CAAU,IACpB,gBAAiBS,GAAaoE,EAAK,MAAM,GAAK,SAAA,CAChD,CAAA,EAEJ,EACAnF,EAAAA,KAAC,MAAA,CAAI,UAAU,kBACb,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAK,UAAU,cAAe,SAAA2F,EAAK,MAAM,EAC1CnF,EAAAA,KAAC,OAAA,CAAK,UAAU,4CAA4C,SAAA,CAAA,IACxDM,EAAW,QAAQ,CAAC,EAAE,IAAA,CAAA,CAC1B,CAAA,CAAA,CACF,CAAA,CAAA,EAhBQ6E,EAAK,MAiBf,CAEJ,CAAC,CAAA,CACH,CAAA,EACF,EAGAnF,EAAAA,KAAC,MAAA,CAAI,UAAU,WACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,6CACZ,SAAA,CAAAR,EAAAA,IAAC+F,EAAAA,IAAA,CAAI,UAAU,SAAA,CAAU,EAAE,uBAAA,EAE7B,EACA/F,EAAAA,IAAC,MAAA,CAAI,UAAU,YACX,aAAU,QAAU,GAAK,GACxB0C,GAAY,CAAA,GAAI,IAAI,CAACiD,EAAMjF,IAAU,CACpC,MAAME,EAAW,KAAK,IAAI,IAAI8B,GAAY,CAAA,GAAI,IAAIsD,GAAKA,EAAE,KAAK,EAAG,CAAC,EAC5DlF,EAAc6E,EAAK,MAAQ/E,EAAY,IACvCqF,EAAS,CAAC,UAAW,UAAW,UAAW,UAAW,SAAS,EACrE,OACEzF,EAAAA,KAAC,MAAA,CAAwB,UAAU,0BACjC,SAAA,CAAAR,EAAAA,IAAC,OAAI,UAAU,wBAAwB,MAAO2F,EAAK,SAAW,WAAK,QAAA,CAAS,EAC5E3F,EAAAA,IAAC,MAAA,CAAI,UAAU,mEACb,SAAAA,EAAAA,IAAC,MAAA,CACC,UAAU,kDACV,MAAO,CACL,MAAO,GAAGc,CAAU,IACpB,gBAAiBmF,EAAOvF,EAAQuF,EAAO,MAAM,CAAA,CAC/C,CAAA,EAEJ,EACAjG,EAAAA,IAAC,MAAA,CAAI,UAAU,8BAA+B,WAAK,KAAA,CAAM,CAAA,CAAA,EAXjD2F,EAAK,QAYf,CAEJ,CAAC,EAED3F,EAAAA,IAAC,OAAI,UAAU,gDAAgD,gCAE/D,CAAA,CAEJ,CAAA,CAAA,CACF,CAAA,EACF,EAGAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,wCAEb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,WACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,6CACZ,SAAA,CAAAR,EAAAA,IAACkG,EAAAA,OAAA,CAAO,UAAU,SAAA,CAAU,EAAE,uBAAA,EAEhC,EACA1F,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,sDACb,SAAA,CAAAR,MAAC,MAAA,CAAI,UAAU,qCAAsC,SAAAsC,GAAU,YAAc,EAAE,EAC/EtC,EAAAA,IAAC,MAAA,CAAI,UAAU,uCAAuC,SAAA,OAAA,CAAK,CAAA,EAC7D,EACAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,sDACb,SAAA,CAAAR,MAAC,MAAA,CAAI,UAAU,oCAAqC,SAAAsC,GAAU,kBAAoB,EAAE,EACpFtC,EAAAA,IAAC,MAAA,CAAI,UAAU,uCAAuC,SAAA,aAAA,CAAW,CAAA,EACnE,EACAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,sDACb,SAAA,CAAAR,MAAC,MAAA,CAAI,UAAU,mCAAoC,SAAAsC,GAAU,uBAAyB,EAAE,EACxFtC,EAAAA,IAAC,MAAA,CAAI,UAAU,uCAAuC,SAAA,qBAAA,CAAmB,CAAA,EAC3E,EACAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,sDACb,SAAA,CAAAR,MAAC,MAAA,CAAI,UAAU,qCAAsC,SAAAkD,GAAc,qBAAuB,EAAE,EAC5FlD,EAAAA,IAAC,MAAA,CAAI,UAAU,uCAAuC,SAAA,kBAAA,CAAgB,CAAA,CAAA,CACxE,CAAA,CAAA,CACF,CAAA,EACF,EAGAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,WACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,6CACZ,SAAA,CAAAR,EAAAA,IAACC,EAAAA,QAAA,CAAQ,UAAU,SAAA,CAAU,EAAE,kBAAA,EAEjC,EACCiD,KAAkBA,EAAa,WAAW,QAAU,GAAK,IAAMA,EAAa,WAAW,QAAU,GAAK,GACrG1C,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAR,EAAAA,IAAC,KAAA,CAAG,UAAU,wDAAwD,SAAA,iBAAc,EACpFA,EAAAA,IAAC,MAAA,CAAI,UAAU,YACX,YAAa,WAAa,CAAA,GAAI,IAAK2F,GACnCnF,EAAAA,KAAC,MAAA,CAAuB,UAAU,4CAChC,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAM,WAAK,OAAA,CAAQ,EACpBA,EAAAA,IAAC,OAAA,CAAK,UAAU,cAAe,WAAK,KAAA,CAAM,CAAA,GAFlC2F,EAAK,OAGf,CACD,CAAA,CACH,CAAA,EACF,SACC,MAAA,CACC,SAAA,CAAAnF,EAAAA,KAAC,KAAA,CAAG,UAAU,gFACZ,SAAA,CAAAR,EAAAA,IAACmG,EAAAA,MAAA,CAAM,UAAU,SAAA,CAAU,EAAE,WAAA,EAC/B,QACC,MAAA,CAAI,UAAU,YACX,UAAAjD,EAAa,WAAW,QAAU,GAAK,GACtCA,EAAa,WAAa,CAAA,GAAI,IAAKyC,GAClCnF,OAAC,MAAA,CAAuB,UAAU,4CAChC,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAM,WAAK,OAAA,CAAQ,EACpBA,EAAAA,IAAC,OAAA,CAAK,UAAU,cAAe,WAAK,KAAA,CAAM,CAAA,CAAA,EAFlC2F,EAAK,OAGf,CACD,QAEA,OAAA,CAAK,UAAU,uCAAuC,SAAA,gBAAA,CAAc,CAAA,CAEzE,CAAA,CAAA,CACF,CAAA,CAAA,CACF,EAEA3F,EAAAA,IAAC,MAAA,CAAI,UAAU,gDAAgD,SAAA,uBAAA,CAE/D,CAAA,CAAA,CAEJ,CAAA,EACF,EAGAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,wCAEb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,WACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,6CACZ,SAAA,CAAAR,EAAAA,IAACC,EAAAA,QAAA,CAAQ,UAAU,SAAA,CAAU,EAAE,yBAAA,EAEjC,EACAD,EAAAA,IAACM,GAAA,CAAqB,KAAM8C,CAAA,CAAa,CAAA,EAC3C,EAGA5C,EAAAA,KAAC,MAAA,CAAI,UAAU,WACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,6CACZ,SAAA,CAAAR,EAAAA,IAACyF,EAAAA,SAAA,CAAS,UAAU,SAAA,CAAU,EAAE,yBAAA,EAElC,EACAzF,EAAAA,IAACgB,GAAA,CAAsB,KAAMsC,CAAA,CAAmB,CAAA,CAAA,CAClD,CAAA,EACF,EAGA9C,EAAAA,KAAC,MAAA,CAAI,UAAU,WACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,6CACZ,SAAA,CAAAR,EAAAA,IAACoG,EAAAA,WAAA,CAAW,UAAU,SAAA,CAAU,EAAE,cACtBhE,EAAO,kBAAA,EACrB,EACApC,EAAAA,IAAC,MAAA,CAAI,UAAU,OACb,SAAAA,MAACqG,IAAW,KAAMzD,GAAU,CAAA,CAAC,CAAG,CAAA,CAClC,CAAA,EACF,EAGApC,EAAAA,KAAC,MAAA,CAAI,UAAU,WACb,SAAA,CAAAA,EAAAA,KAAC,KAAA,CAAG,UAAU,6CACZ,SAAA,CAAAR,EAAAA,IAACsG,EAAAA,MAAA,CAAM,UAAU,SAAA,CAAU,EAAE,4BAAA,EAE/B,GACExD,GAAgB,QAAU,GAAK,EAC/B9C,EAAAA,IAAC,MAAA,CAAI,UAAU,kBACb,SAAAQ,EAAAA,KAAC,QAAA,CAAM,UAAU,SACf,SAAA,CAAAR,MAAC,QAAA,CACC,SAAAQ,EAAAA,KAAC,KAAA,CAAG,UAAU,wCACZ,SAAA,CAAAR,EAAAA,IAAC,KAAA,CAAG,UAAU,4BAA4B,SAAA,cAAW,EACrDA,EAAAA,IAAC,KAAA,CAAG,UAAU,6BAA6B,SAAA,OAAA,CAAK,CAAA,CAAA,CAClD,CAAA,CACF,QACC,QAAA,CACG,UAAA8C,GAAkB,IAAI,IAAKyD,GAC3B/F,EAAAA,KAAC,KAAA,CAEC,UAAU,sFACV,QAAS,IAAMkB,EAAS,yBAAyB6E,EAAQ,MAAM,EAAE,EAEjE,SAAA,CAAAvG,EAAAA,IAAC,KAAA,CAAG,UAAU,kBAAmB,SAAAuG,EAAQ,SAAS,EAClDvG,EAAAA,IAAC,KAAA,CAAG,UAAU,iBACZ,SAAAA,EAAAA,IAAC,QAAK,UAAU,6GACb,SAAAuG,EAAQ,QAAA,CACX,CAAA,CACF,CAAA,CAAA,EATKA,EAAQ,OAASA,EAAQ,OAAA,CAWjC,CAAA,CACH,CAAA,EACF,EACF,EAEAvG,MAAC,MAAA,CAAI,UAAU,gDAAgD,SAAA,uBAAA,CAE/D,CAAA,CAAA,CAEJ,CAAA,EACF,CAEJ,CAEA,SAASqF,EAAQ,CACf,MAAAmB,EACA,MAAAC,EACA,KAAAC,EACA,MAAAC,EACA,SAAAC,CACF,EAMG,CACD,MAAMC,EAAe,CACnB,KAAM,oFACN,MAAO,yFACP,OAAQ,8FACR,IAAK,8EAAA,EAGP,cACG,MAAA,CAAI,UAAW,mBAAmBA,EAAaF,CAAK,CAAC,GACpD,SAAA,CAAAnG,EAAAA,KAAC,MAAA,CAAI,UAAU,yCACb,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAK,UAAU,iCAAkC,SAAAwG,EAAM,EACvDE,CAAA,EACH,EACA1G,EAAAA,IAAC,MAAA,CAAI,UAAU,qBAAsB,SAAAyG,EAAM,EAC1CG,GAAY5G,EAAAA,IAAC,MAAA,CAAI,UAAU,0BAA2B,SAAA4G,CAAA,CAAS,CAAA,EAClE,CAEJ,CAEA,SAASP,GAAW,CAAE,KAAA9F,GAAkC,CACtD,GAAIA,EAAK,SAAW,EAClB,OACEP,EAAAA,IAAC,MAAA,CAAI,UAAU,uEAAuE,SAAA,uCAEtF,EAIJ,MAAM8G,EAAW,KAAK,IAAI,GAAGvG,EAAK,QAASwG,GAAM,CAACA,EAAE,SAAUA,EAAE,MAAM,CAAC,EAAG,CAAC,EAE3E,OACEvG,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,+BACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAR,EAAAA,IAAC,MAAA,CAAI,UAAU,6BAAA,CAA8B,EAC7CA,EAAAA,IAAC,OAAA,CAAK,UAAU,UAAU,SAAA,uBAAA,CAAqB,CAAA,EACjD,EACAQ,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAR,EAAAA,IAAC,MAAA,CAAI,UAAU,8BAAA,CAA+B,EAC9CA,EAAAA,IAAC,OAAA,CAAK,UAAU,UAAU,SAAA,YAAA,CAAU,CAAA,CAAA,CACtC,CAAA,EACF,EACAA,EAAAA,IAAC,MAAA,CAAI,UAAU,mDACZ,SAAAO,EAAK,IAAKoF,GACTnF,EAAAA,KAAC,MAAA,CAAyB,UAAU,mCAClC,SAAA,CAAAR,EAAAA,IAAC,MAAA,CACC,UAAU,4EACV,MAAO,CACL,OAAQ,GAAI2F,EAAK,SAAWmB,EAAY,GAAG,IAC3C,UAAWnB,EAAK,SAAW,EAAI,MAAQ,GAAA,EAEzC,MAAO,aAAaA,EAAK,QAAQ,EAAA,CAAA,EAEnC3F,EAAAA,IAAC,MAAA,CACC,UAAU,6EACV,MAAO,CACL,OAAQ,GAAI2F,EAAK,OAASmB,EAAY,GAAG,IACzC,UAAWnB,EAAK,OAAS,EAAI,MAAQ,GAAA,EAEvC,MAAO,eAAeA,EAAK,MAAM,EAAA,CAAA,CACnC,CAAA,EAhBQ,GAAGA,EAAK,IAAI,EAiBtB,CACD,CAAA,CACH,EACAnF,EAAAA,KAAC,MAAA,CAAI,UAAU,iEACb,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAM,SAAAO,EAAK,CAAC,GAAK,IAAI,KAAKA,EAAK,CAAC,EAAE,IAAI,EAAE,mBAAmB,OAAO,CAAA,CAAE,QACpE,OAAA,CAAM,SAAAA,EAAK,GAAG,EAAE,GAAK,IAAI,KAAKA,EAAK,GAAG,EAAE,EAAG,IAAI,EAAE,mBAAmB,OAAO,CAAA,CAAE,CAAA,CAAA,CAChF,CAAA,EACF,CAEJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("react"),se=require("react-router-dom"),ae=require("react-i18next"),c=require("./index-2wUhd9Lu.js"),r=require("lucide-react"),te=require("./ticketingApi-r4Avm9iS.js"),re={Low:"var(--info-text)",Medium:"var(--warning-text)",High:"var(--warning-text)",Critical:"var(--error-text)"},ne={Open:"var(--warning-text)",InProgress:"var(--info-text)",OnHold:"var(--warning-text)",Resolved:"var(--success-text)",Closed:"var(--text-secondary)",Rejected:"var(--error-text)"};function ce(){const{t:s}=ae.useTranslation("support"),l=se.useNavigate(),{hasPermission:o}=c.useAuth(),{isGlpi:t,glpiBaseUrl:m}=c.useTicketingProvider(),{currentTenant:p}=c.useTenant(),[k,L]=n.useState(!0),[$,A]=n.useState(!1),[x,E]=n.useState(30),R=o("support.sla.read"),[v,I]=n.useState(null),[P,H]=n.useState([]),[D,q]=n.useState([]),[C,G]=n.useState([]),[F,O]=n.useState([]),[g,U]=n.useState(null),[u,W]=n.useState(null),[N,V]=n.useState([]),[y,z]=n.useState([]),[i,K]=n.useState(null),[w,B]=n.useState(!1),S=n.useCallback(async()=>{try{const[a,d,h,b,f,Y,Z]=await Promise.all([c.dashboardApi.getOverview(x),c.dashboardApi.getByStatus(),c.dashboardApi.getByPriority(),c.dashboardApi.getAgentWorkload(),c.dashboardApi.getTrends(x),c.dashboardApi.getSatisfactionStats(x),c.dashboardApi.getSlaCompliance(x)]);if(I(a),H(d),q(h),G(b),O(f),U(Y),W(Z),t)try{const T=await c.supportApi.tickets.getGlpiSyncStats();K(T)}catch{}if(R){const[T,ee]=await Promise.all([c.slaApi.getBreachedTickets(),c.slaApi.getTicketsApproachingBreach(60)]);V(T),z(ee)}}catch(a){console.error("Failed to load dashboard data:",a)}finally{L(!1),A(!1)}},[x,R,t]);n.useEffect(()=>{S()},[S]);const X=()=>{A(!0),S()},_=async()=>{if(!(!p?.id||w)){B(!0);try{await te.ticketingApi.triggerSync(p.id),await S()}catch{}finally{B(!1)}}};if(k)return e.jsx("div",{className:"flex items-center justify-center min-h-[400px]",children:e.jsx(r.Loader2,{className:"w-8 h-8 animate-spin text-[var(--color-primary-600)]"})});const J=a=>a>=95?"text-[var(--success-text)]":a>=80?"text-[var(--warning-text)]":"text-[var(--error-text)]",Q=a=>a>=4?"text-[var(--success-text)]":a>=3?"text-[var(--warning-text)]":"text-[var(--error-text)]";return e.jsxs("div",{className:"space-y-6",children:[e.jsx(c.Breadcrumb,{items:[{label:s("title","Support"),href:"/support"},{label:s("dashboard.title","Dashboard")}]}),e.jsx(c.PageHeader,{title:s("dashboard.title"),subtitle:s("dashboard.subtitle"),icon:e.jsx(r.LayoutDashboard,{className:"w-6 h-6"}),actions:e.jsxs(e.Fragment,{children:[e.jsxs("select",{value:x,onChange:a=>E(Number(a.target.value)),className:"input",children:[e.jsx("option",{value:7,children:s("dashboard.period7")}),e.jsx("option",{value:30,children:s("dashboard.period30")}),e.jsx("option",{value:90,children:s("dashboard.period90")})]}),e.jsxs("button",{onClick:X,disabled:$,className:"btn btn-secondary flex items-center gap-2",children:[e.jsx(r.RefreshCw,{className:`w-4 h-4 ${$?"animate-spin":""}`}),s("dashboard.refresh")]})]})}),t&&e.jsxs("div",{className:"flex items-center gap-3 p-4 rounded-lg bg-[var(--info-bg)] border border-[var(--info-border)] text-[var(--info-text)]",children:[e.jsx(r.Info,{className:"w-5 h-5 flex-shrink-0"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("p",{className:"font-medium",children:s("glpi.managedByGlpi")}),e.jsx("p",{className:"text-sm opacity-80",children:s("glpi.dashboardSyncInfo")})]}),m&&e.jsxs("a",{href:m,target:"_blank",rel:"noopener noreferrer",className:"btn btn-secondary flex items-center gap-2 text-sm",children:[e.jsx(r.ExternalLink,{className:"w-4 h-4"}),s("glpi.openGlpi")]})]}),t&&i&&e.jsxs("div",{className:"card p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsxs("h3",{className:"font-semibold flex items-center gap-2",children:[e.jsx(r.RefreshCw,{className:"w-5 h-5"}),s("glpi.sync.title","GLPI Sync Status")]}),e.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:s("glpi.sync.subtitle","Synchronization overview with GLPI")})]}),e.jsxs("button",{onClick:_,disabled:w,className:"btn btn-secondary flex items-center gap-2",children:[e.jsx(r.RefreshCw,{className:`w-4 h-4 ${w?"animate-spin":""}`}),w?s("glpi.sync.syncing","Syncing..."):s("glpi.sync.triggerSync","Sync Now")]})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-4",children:[e.jsxs("div",{className:"card p-4 text-center border bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]",children:[e.jsx("div",{className:"text-2xl font-bold",children:i.totalMappedTickets}),e.jsx("div",{className:"text-sm opacity-80",children:s("glpi.sync.totalSynced","Total Synced")})]}),e.jsxs("div",{className:"card p-4 text-center border bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]",children:[e.jsx("div",{className:"text-2xl font-bold",children:i.ticketsSyncedOk}),e.jsx("div",{className:"text-sm opacity-80",children:s("glpi.sync.syncSuccess","Successful")})]}),e.jsxs("div",{className:"card p-4 text-center border bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]",children:[e.jsx("div",{className:"text-2xl font-bold",children:i.ticketsWithSyncErrors}),e.jsx("div",{className:"text-sm opacity-80",children:s("glpi.sync.syncErrors","Errors")})]}),e.jsxs("div",{className:`card p-4 text-center border ${i.successRate>=90?"bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]":"bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]"}`,children:[e.jsxs("div",{className:"text-2xl font-bold",children:[i.successRate,"%"]}),e.jsx("div",{className:"text-sm opacity-80",children:s("glpi.sync.successRate","Success Rate")})]})]}),e.jsxs("div",{className:"flex items-center gap-6 text-sm text-[var(--text-secondary)]",children:[e.jsxs("div",{children:[e.jsxs("span",{className:"font-medium",children:[s("glpi.sync.lastSync","Last Sync"),":"]})," ",i.lastSyncAt?new Date(i.lastSyncAt).toLocaleString():s("glpi.sync.never","Never")]}),e.jsxs("div",{children:[e.jsxs("span",{className:"font-medium",children:[s("glpi.sync.syncInterval","Interval"),":"]})," ",s("glpi.sync.everyNMinutes","Every {{n}} min",{n:i.syncIntervalMinutes})]}),e.jsx("div",{children:e.jsx("span",{className:`px-2 py-0.5 rounded text-xs font-medium ${i.syncEnabled?"bg-[var(--success-bg)] text-[var(--success-text)]":"bg-[var(--bg-secondary)] text-[var(--text-secondary)]"}`,children:i.syncEnabled?s("glpi.sync.enabled","Enabled"):s("glpi.sync.disabled","Disabled")})})]}),i.lastSyncError&&e.jsxs("div",{className:"p-3 rounded-lg bg-[var(--error-bg)] border border-[var(--error-border)]",children:[e.jsx("p",{className:"text-sm font-medium text-[var(--error-text)]",children:s("glpi.sync.lastError","Last Sync Error")}),e.jsx("p",{className:"text-sm text-[var(--error-text)] opacity-80 mt-1",children:i.lastSyncError})]})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4",children:[e.jsx(j,{title:s("dashboard.totalTickets"),value:v?.totalTickets??0,icon:e.jsx(r.Headphones,{className:"w-5 h-5"}),color:"blue"}),e.jsx(j,{title:s("dashboard.newTickets"),value:v?.newTickets??0,icon:e.jsx(r.TrendingUp,{className:"w-5 h-5"}),color:"green",subtitle:s("dashboard.lastNDays",{period:x})}),e.jsx(j,{title:s("dashboard.openTickets"),value:v?.openTickets??0,icon:e.jsx(r.Clock,{className:"w-5 h-5"}),color:"yellow"}),e.jsx(j,{title:s("dashboard.resolvedTickets"),value:v?.resolvedTickets??0,icon:e.jsx(r.CheckCircle,{className:"w-5 h-5"}),color:"green",subtitle:s("dashboard.lastNDays",{period:x})}),e.jsx(j,{title:s("dashboard.slaCompliance"),value:`${v?.slaCompliancePercentage?.toFixed(1)??0}%`,icon:e.jsx(r.AlertTriangle,{className:"w-5 h-5"}),color:(v?.slaCompliancePercentage??0)>=90?"green":"red"}),e.jsx(j,{title:s("dashboard.avgSatisfaction"),value:`${v?.averageSatisfaction?.toFixed(1)??0}/5`,icon:e.jsx(r.Star,{className:"w-5 h-5"}),color:(v?.averageSatisfaction??0)>=4?"green":"yellow"})]}),R&&(N.length>0||y.length>0)&&e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4",children:[N.length>0&&e.jsxs("div",{className:"card p-4 border-l-4 border-[var(--error-border)]",children:[e.jsxs("h3",{className:"font-semibold text-[var(--error-text)] flex items-center gap-2 mb-3",children:[e.jsx(r.XCircle,{className:"w-5 h-5"}),s("dashboard.slaBreached")," (",N.length,")"]}),e.jsx("div",{className:"space-y-2 max-h-40 overflow-y-auto",children:N.slice(0,5).map(a=>e.jsxs("button",{type:"button",className:"w-full flex items-center justify-between p-2 bg-[var(--error-bg)] rounded cursor-pointer hover:opacity-80 text-left",onClick:()=>l(`/support/tickets/${a.ticketId}`),children:[e.jsxs("div",{children:[e.jsx("span",{className:"font-mono text-sm",children:a.ticketNumber}),e.jsx("span",{className:"ml-2 text-sm",children:a.ticketTitle})]}),e.jsxs("span",{className:"text-xs text-[var(--error-text)] font-medium",children:[a.responseBreached&&"Response"," ",a.resolutionBreached&&"Resolution"]})]},a.id))})]}),y.length>0&&e.jsxs("div",{className:"card p-4 border-l-4 border-[var(--warning-border)]",children:[e.jsxs("h3",{className:"font-semibold text-[var(--warning-text)] flex items-center gap-2 mb-3",children:[e.jsx(r.AlertTriangle,{className:"w-5 h-5"}),s("dashboard.approachingBreach")," (",y.length,")"]}),e.jsx("div",{className:"space-y-2 max-h-40 overflow-y-auto",children:y.slice(0,5).map(a=>e.jsxs("button",{type:"button",className:"w-full flex items-center justify-between p-2 bg-[var(--warning-bg)] rounded cursor-pointer hover:opacity-80 text-left",onClick:()=>l(`/support/tickets/${a.ticketId}`),children:[e.jsxs("div",{children:[e.jsx("span",{className:"font-mono text-sm",children:a.ticketNumber}),e.jsx("span",{className:"ml-2 text-sm",children:a.ticketTitle})]}),e.jsxs("span",{className:"text-xs text-[var(--warning-text)] font-medium",children:[Math.round(a.responseSlaPercentage),"% Response"]})]},a.id))})]})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.ticketsByStatus")}),e.jsx("div",{className:"space-y-3",children:P.map(a=>{const d=P.reduce((b,f)=>b+f.count,0),h=d>0?a.count/d*100:0;return e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-24 text-sm",children:a.status}),e.jsx("div",{className:"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full transition-all duration-500",style:{width:`${h}%`,backgroundColor:ne[a.status]||"#6b7280"}})}),e.jsx("div",{className:"w-16 text-right text-sm font-medium",children:a.count})]},a.status)})})]}),e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.activeTicketsByPriority")}),e.jsx("div",{className:"space-y-3",children:D.map(a=>{const d=D.reduce((b,f)=>b+f.count,0),h=d>0?a.count/d*100:0;return e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-24 text-sm",children:a.priority}),e.jsx("div",{className:"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full transition-all duration-500",style:{width:`${h}%`,backgroundColor:re[a.priority]||"#6b7280"}})}),e.jsx("div",{className:"w-16 text-right text-sm font-medium",children:a.count})]},a.priority)})})]})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.slaPerformance")}),u&&e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsxs("div",{className:`text-3xl font-bold ${J(u.compliancePercentage)}`,children:[u.compliancePercentage.toFixed(1),"%"]}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.complianceRate")})]}),e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:"text-3xl font-bold",children:u.ticketsWithinSla}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.withinSla")})]}),e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:"text-3xl font-bold text-[var(--error-text)]",children:u.ticketsBreached}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.breached")})]}),e.jsxs("div",{className:"space-y-2 p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsxs("div",{className:"flex justify-between text-sm",children:[e.jsxs("span",{children:[s("dashboard.avgResponse"),":"]}),e.jsx("span",{className:"font-medium",children:M(u.averageResponseMinutes)})]}),e.jsxs("div",{className:"flex justify-between text-sm",children:[e.jsxs("span",{children:[s("dashboard.avgResolution"),":"]}),e.jsx("span",{className:"font-medium",children:M(u.averageResolutionMinutes)})]})]})]})]}),e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.customerSatisfaction")}),g&&e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:`text-3xl font-bold ${Q(g.averageRating)}`,children:g.averageRating.toFixed(1)}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.averageRating")}),e.jsx("div",{className:"flex justify-center mt-1",children:[1,2,3,4,5].map(a=>e.jsx(r.Star,{className:`w-4 h-4 ${a<=Math.round(g.averageRating)?"text-[var(--warning-text)] fill-[var(--warning-text)]":"text-[var(--text-muted)]"}`},a))})]}),e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:"text-3xl font-bold",children:g.totalResponses}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.totalResponses")})]}),e.jsxs("div",{className:"col-span-2 p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:"text-sm font-medium mb-2",children:s("dashboard.ratingDistribution")}),e.jsx("div",{className:"space-y-1",children:[5,4,3,2,1].map(a=>{const d=g.ratingDistribution[a]||0,h=g.totalResponses>0?d/g.totalResponses*100:0;return e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[e.jsx("span",{className:"w-4",children:a}),e.jsx(r.Star,{className:"w-3 h-3 text-[var(--warning-text)] fill-[var(--warning-text)]"}),e.jsx("div",{className:"flex-1 h-3 bg-[var(--bg-primary)] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-[var(--warning-text)] rounded-full",style:{width:`${h}%`}})}),e.jsx("span",{className:"w-8 text-right text-xs",children:d})]},a)})})]})]})]})]}),e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.ticketTrends",{period:x})}),e.jsx("div",{className:"h-64",children:e.jsx(le,{data:F,t:s})})]}),e.jsxs("div",{className:"card p-4",children:[e.jsxs("h3",{className:"font-semibold mb-4 flex items-center gap-2",children:[e.jsx(r.Users,{className:"w-5 h-5"}),s("dashboard.agentWorkload")]}),C.length>0?e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-[var(--border-color)]",children:[e.jsx("th",{className:"text-left p-3 font-medium",children:s("dashboard.agent")}),e.jsx("th",{className:"text-center p-3 font-medium",children:s("dashboard.total")}),e.jsx("th",{className:"text-center p-3 font-medium",children:s("dashboard.open")}),e.jsx("th",{className:"text-center p-3 font-medium",children:s("dashboard.inProgress")}),e.jsx("th",{className:"text-center p-3 font-medium",children:s("dashboard.onHold")}),e.jsx("th",{className:"text-left p-3 font-medium",children:s("dashboard.load")})]})}),e.jsx("tbody",{children:C.map(a=>{const d=Math.max(...C.map(b=>b.totalAssigned)),h=d>0?a.totalAssigned/d*100:0;return e.jsxs("tr",{className:"border-b border-[var(--border-color)]",children:[e.jsxs("td",{className:"p-3",children:[e.jsx("div",{className:"font-medium",children:a.name}),e.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:a.email})]}),e.jsx("td",{className:"text-center p-3 font-semibold",children:a.totalAssigned}),e.jsx("td",{className:"text-center p-3",children:e.jsx("span",{className:"px-2 py-1 bg-[var(--warning-bg)] text-[var(--warning-text)] rounded-[var(--radius-badge)] text-sm",children:a.openCount})}),e.jsx("td",{className:"text-center p-3",children:e.jsx("span",{className:"px-2 py-1 bg-[var(--info-bg)] text-[var(--info-text)] rounded-[var(--radius-badge)] text-sm",children:a.inProgressCount})}),e.jsx("td",{className:"text-center p-3",children:e.jsx("span",{className:"px-2 py-1 bg-[var(--warning-bg)] text-[var(--warning-text)] rounded-[var(--radius-badge)] text-sm",children:a.onHoldCount})}),e.jsx("td",{className:"p-3 w-32",children:e.jsx("div",{className:"h-2 bg-[var(--bg-secondary)] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-[var(--info-text)] rounded-full",style:{width:`${h}%`}})})})]},a.userId)})})]})}):e.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:s("dashboard.noAgentsAssigned")})]})]})}function j({title:s,value:l,icon:o,color:t,subtitle:m,trend:p}){const k={blue:"bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]",green:"bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]",yellow:"bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]",red:"bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]"};return e.jsxs("div",{className:`card p-4 border ${k[t]}`,children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("span",{className:"text-sm font-medium opacity-80",children:s}),o]}),e.jsx("div",{className:"text-2xl font-bold",children:l}),m&&e.jsx("div",{className:"text-xs opacity-70 mt-1",children:m}),p&&e.jsxs("div",{className:`flex items-center gap-1 mt-1 text-xs ${p.isUp?"text-[var(--success-text)]":"text-[var(--error-text)]"}`,children:[p.isUp?e.jsx(r.ArrowUp,{className:"w-3 h-3"}):e.jsx(r.ArrowDown,{className:"w-3 h-3"}),p.value,"%"]})]})}function le({data:s,t:l}){if(s.length===0)return e.jsx("div",{className:"flex items-center justify-center h-full text-[var(--text-secondary)]",children:l("dashboard.noTrendData")});const o=Math.max(...s.flatMap(t=>[t.created,t.resolved]),1);return e.jsxs("div",{className:"flex flex-col h-full",children:[e.jsxs("div",{className:"flex items-center gap-4 mb-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 rounded bg-[var(--info-text)]"}),e.jsx("span",{className:"text-sm",children:l("dashboard.created")})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 rounded bg-[var(--success-text)]"}),e.jsx("span",{className:"text-sm",children:l("dashboard.resolved")})]})]}),e.jsx("div",{className:"flex-1 flex items-end gap-1 overflow-x-auto pb-4",children:s.map(t=>e.jsxs("div",{className:"flex-1 min-w-[20px] flex gap-0.5",children:[e.jsx("div",{className:"flex-1 bg-[var(--info-text)] rounded-t transition-all duration-300 hover:opacity-80",style:{height:`${t.created/o*100}%`,minHeight:t.created>0?"4px":"0"},title:`Created: ${t.created}`}),e.jsx("div",{className:"flex-1 bg-[var(--success-text)] rounded-t transition-all duration-300 hover:opacity-80",style:{height:`${t.resolved/o*100}%`,minHeight:t.resolved>0?"4px":"0"},title:`Resolved: ${t.resolved}`})]},`${t.date}`))}),e.jsxs("div",{className:"flex justify-between text-xs text-[var(--text-secondary)] mt-2",children:[e.jsx("span",{children:s[0]&&new Date(s[0].date).toLocaleDateString()}),e.jsx("span",{children:s.at(-1)&&new Date(s.at(-1).date).toLocaleDateString()})]})]})}function M(s){if(s<60)return`${Math.round(s)}m`;const l=Math.floor(s/60),o=Math.round(s%60);if(l<24)return o>0?`${l}h ${o}m`:`${l}h`;const t=Math.floor(l/24),m=l%24;return m>0?`${t}d ${m}h`:`${t}d`}exports.DashboardPage=ce;
|
|
2
|
-
//# sourceMappingURL=DashboardPage-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("react"),se=require("react-router-dom"),ae=require("react-i18next"),c=require("./index-IgLVXPg8.js"),r=require("lucide-react"),te=require("./ticketingApi-J0vC_t7r.js"),re={Low:"var(--info-text)",Medium:"var(--warning-text)",High:"var(--warning-text)",Critical:"var(--error-text)"},ne={Open:"var(--warning-text)",InProgress:"var(--info-text)",OnHold:"var(--warning-text)",Resolved:"var(--success-text)",Closed:"var(--text-secondary)",Rejected:"var(--error-text)"};function ce(){const{t:s}=ae.useTranslation("support"),l=se.useNavigate(),{hasPermission:o}=c.useAuth(),{isGlpi:t,glpiBaseUrl:m}=c.useTicketingProvider(),{currentTenant:p}=c.useTenant(),[k,L]=n.useState(!0),[$,A]=n.useState(!1),[x,E]=n.useState(30),R=o("support.sla.read"),[v,I]=n.useState(null),[P,H]=n.useState([]),[D,q]=n.useState([]),[C,G]=n.useState([]),[F,O]=n.useState([]),[g,U]=n.useState(null),[u,W]=n.useState(null),[N,V]=n.useState([]),[y,z]=n.useState([]),[i,K]=n.useState(null),[w,B]=n.useState(!1),S=n.useCallback(async()=>{try{const[a,d,h,b,f,Y,Z]=await Promise.all([c.dashboardApi.getOverview(x),c.dashboardApi.getByStatus(),c.dashboardApi.getByPriority(),c.dashboardApi.getAgentWorkload(),c.dashboardApi.getTrends(x),c.dashboardApi.getSatisfactionStats(x),c.dashboardApi.getSlaCompliance(x)]);if(I(a),H(d),q(h),G(b),O(f),U(Y),W(Z),t)try{const T=await c.supportApi.tickets.getGlpiSyncStats();K(T)}catch{}if(R){const[T,ee]=await Promise.all([c.slaApi.getBreachedTickets(),c.slaApi.getTicketsApproachingBreach(60)]);V(T),z(ee)}}catch(a){console.error("Failed to load dashboard data:",a)}finally{L(!1),A(!1)}},[x,R,t]);n.useEffect(()=>{S()},[S]);const X=()=>{A(!0),S()},_=async()=>{if(!(!p?.id||w)){B(!0);try{await te.ticketingApi.triggerSync(p.id),await S()}catch{}finally{B(!1)}}};if(k)return e.jsx("div",{className:"flex items-center justify-center min-h-[400px]",children:e.jsx(r.Loader2,{className:"w-8 h-8 animate-spin text-[var(--color-primary-600)]"})});const J=a=>a>=95?"text-[var(--success-text)]":a>=80?"text-[var(--warning-text)]":"text-[var(--error-text)]",Q=a=>a>=4?"text-[var(--success-text)]":a>=3?"text-[var(--warning-text)]":"text-[var(--error-text)]";return e.jsxs("div",{className:"space-y-6",children:[e.jsx(c.Breadcrumb,{items:[{label:s("title","Support"),href:"/support"},{label:s("dashboard.title","Dashboard")}]}),e.jsx(c.PageHeader,{title:s("dashboard.title"),subtitle:s("dashboard.subtitle"),icon:e.jsx(r.LayoutDashboard,{className:"w-6 h-6"}),actions:e.jsxs(e.Fragment,{children:[e.jsxs("select",{value:x,onChange:a=>E(Number(a.target.value)),className:"input",children:[e.jsx("option",{value:7,children:s("dashboard.period7")}),e.jsx("option",{value:30,children:s("dashboard.period30")}),e.jsx("option",{value:90,children:s("dashboard.period90")})]}),e.jsxs("button",{onClick:X,disabled:$,className:"btn btn-secondary flex items-center gap-2",children:[e.jsx(r.RefreshCw,{className:`w-4 h-4 ${$?"animate-spin":""}`}),s("dashboard.refresh")]})]})}),t&&e.jsxs("div",{className:"flex items-center gap-3 p-4 rounded-lg bg-[var(--info-bg)] border border-[var(--info-border)] text-[var(--info-text)]",children:[e.jsx(r.Info,{className:"w-5 h-5 flex-shrink-0"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("p",{className:"font-medium",children:s("glpi.managedByGlpi")}),e.jsx("p",{className:"text-sm opacity-80",children:s("glpi.dashboardSyncInfo")})]}),m&&e.jsxs("a",{href:m,target:"_blank",rel:"noopener noreferrer",className:"btn btn-secondary flex items-center gap-2 text-sm",children:[e.jsx(r.ExternalLink,{className:"w-4 h-4"}),s("glpi.openGlpi")]})]}),t&&i&&e.jsxs("div",{className:"card p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsxs("h3",{className:"font-semibold flex items-center gap-2",children:[e.jsx(r.RefreshCw,{className:"w-5 h-5"}),s("glpi.sync.title","GLPI Sync Status")]}),e.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:s("glpi.sync.subtitle","Synchronization overview with GLPI")})]}),e.jsxs("button",{onClick:_,disabled:w,className:"btn btn-secondary flex items-center gap-2",children:[e.jsx(r.RefreshCw,{className:`w-4 h-4 ${w?"animate-spin":""}`}),w?s("glpi.sync.syncing","Syncing..."):s("glpi.sync.triggerSync","Sync Now")]})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-4",children:[e.jsxs("div",{className:"card p-4 text-center border bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]",children:[e.jsx("div",{className:"text-2xl font-bold",children:i.totalMappedTickets}),e.jsx("div",{className:"text-sm opacity-80",children:s("glpi.sync.totalSynced","Total Synced")})]}),e.jsxs("div",{className:"card p-4 text-center border bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]",children:[e.jsx("div",{className:"text-2xl font-bold",children:i.ticketsSyncedOk}),e.jsx("div",{className:"text-sm opacity-80",children:s("glpi.sync.syncSuccess","Successful")})]}),e.jsxs("div",{className:"card p-4 text-center border bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]",children:[e.jsx("div",{className:"text-2xl font-bold",children:i.ticketsWithSyncErrors}),e.jsx("div",{className:"text-sm opacity-80",children:s("glpi.sync.syncErrors","Errors")})]}),e.jsxs("div",{className:`card p-4 text-center border ${i.successRate>=90?"bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]":"bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]"}`,children:[e.jsxs("div",{className:"text-2xl font-bold",children:[i.successRate,"%"]}),e.jsx("div",{className:"text-sm opacity-80",children:s("glpi.sync.successRate","Success Rate")})]})]}),e.jsxs("div",{className:"flex items-center gap-6 text-sm text-[var(--text-secondary)]",children:[e.jsxs("div",{children:[e.jsxs("span",{className:"font-medium",children:[s("glpi.sync.lastSync","Last Sync"),":"]})," ",i.lastSyncAt?new Date(i.lastSyncAt).toLocaleString():s("glpi.sync.never","Never")]}),e.jsxs("div",{children:[e.jsxs("span",{className:"font-medium",children:[s("glpi.sync.syncInterval","Interval"),":"]})," ",s("glpi.sync.everyNMinutes","Every {{n}} min",{n:i.syncIntervalMinutes})]}),e.jsx("div",{children:e.jsx("span",{className:`px-2 py-0.5 rounded text-xs font-medium ${i.syncEnabled?"bg-[var(--success-bg)] text-[var(--success-text)]":"bg-[var(--bg-secondary)] text-[var(--text-secondary)]"}`,children:i.syncEnabled?s("glpi.sync.enabled","Enabled"):s("glpi.sync.disabled","Disabled")})})]}),i.lastSyncError&&e.jsxs("div",{className:"p-3 rounded-lg bg-[var(--error-bg)] border border-[var(--error-border)]",children:[e.jsx("p",{className:"text-sm font-medium text-[var(--error-text)]",children:s("glpi.sync.lastError","Last Sync Error")}),e.jsx("p",{className:"text-sm text-[var(--error-text)] opacity-80 mt-1",children:i.lastSyncError})]})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4",children:[e.jsx(j,{title:s("dashboard.totalTickets"),value:v?.totalTickets??0,icon:e.jsx(r.Headphones,{className:"w-5 h-5"}),color:"blue"}),e.jsx(j,{title:s("dashboard.newTickets"),value:v?.newTickets??0,icon:e.jsx(r.TrendingUp,{className:"w-5 h-5"}),color:"green",subtitle:s("dashboard.lastNDays",{period:x})}),e.jsx(j,{title:s("dashboard.openTickets"),value:v?.openTickets??0,icon:e.jsx(r.Clock,{className:"w-5 h-5"}),color:"yellow"}),e.jsx(j,{title:s("dashboard.resolvedTickets"),value:v?.resolvedTickets??0,icon:e.jsx(r.CheckCircle,{className:"w-5 h-5"}),color:"green",subtitle:s("dashboard.lastNDays",{period:x})}),e.jsx(j,{title:s("dashboard.slaCompliance"),value:`${v?.slaCompliancePercentage?.toFixed(1)??0}%`,icon:e.jsx(r.AlertTriangle,{className:"w-5 h-5"}),color:(v?.slaCompliancePercentage??0)>=90?"green":"red"}),e.jsx(j,{title:s("dashboard.avgSatisfaction"),value:`${v?.averageSatisfaction?.toFixed(1)??0}/5`,icon:e.jsx(r.Star,{className:"w-5 h-5"}),color:(v?.averageSatisfaction??0)>=4?"green":"yellow"})]}),R&&(N.length>0||y.length>0)&&e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4",children:[N.length>0&&e.jsxs("div",{className:"card p-4 border-l-4 border-[var(--error-border)]",children:[e.jsxs("h3",{className:"font-semibold text-[var(--error-text)] flex items-center gap-2 mb-3",children:[e.jsx(r.XCircle,{className:"w-5 h-5"}),s("dashboard.slaBreached")," (",N.length,")"]}),e.jsx("div",{className:"space-y-2 max-h-40 overflow-y-auto",children:N.slice(0,5).map(a=>e.jsxs("button",{type:"button",className:"w-full flex items-center justify-between p-2 bg-[var(--error-bg)] rounded cursor-pointer hover:opacity-80 text-left",onClick:()=>l(`/support/tickets/${a.ticketId}`),children:[e.jsxs("div",{children:[e.jsx("span",{className:"font-mono text-sm",children:a.ticketNumber}),e.jsx("span",{className:"ml-2 text-sm",children:a.ticketTitle})]}),e.jsxs("span",{className:"text-xs text-[var(--error-text)] font-medium",children:[a.responseBreached&&"Response"," ",a.resolutionBreached&&"Resolution"]})]},a.id))})]}),y.length>0&&e.jsxs("div",{className:"card p-4 border-l-4 border-[var(--warning-border)]",children:[e.jsxs("h3",{className:"font-semibold text-[var(--warning-text)] flex items-center gap-2 mb-3",children:[e.jsx(r.AlertTriangle,{className:"w-5 h-5"}),s("dashboard.approachingBreach")," (",y.length,")"]}),e.jsx("div",{className:"space-y-2 max-h-40 overflow-y-auto",children:y.slice(0,5).map(a=>e.jsxs("button",{type:"button",className:"w-full flex items-center justify-between p-2 bg-[var(--warning-bg)] rounded cursor-pointer hover:opacity-80 text-left",onClick:()=>l(`/support/tickets/${a.ticketId}`),children:[e.jsxs("div",{children:[e.jsx("span",{className:"font-mono text-sm",children:a.ticketNumber}),e.jsx("span",{className:"ml-2 text-sm",children:a.ticketTitle})]}),e.jsxs("span",{className:"text-xs text-[var(--warning-text)] font-medium",children:[Math.round(a.responseSlaPercentage),"% Response"]})]},a.id))})]})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.ticketsByStatus")}),e.jsx("div",{className:"space-y-3",children:P.map(a=>{const d=P.reduce((b,f)=>b+f.count,0),h=d>0?a.count/d*100:0;return e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-24 text-sm",children:a.status}),e.jsx("div",{className:"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full transition-all duration-500",style:{width:`${h}%`,backgroundColor:ne[a.status]||"#6b7280"}})}),e.jsx("div",{className:"w-16 text-right text-sm font-medium",children:a.count})]},a.status)})})]}),e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.activeTicketsByPriority")}),e.jsx("div",{className:"space-y-3",children:D.map(a=>{const d=D.reduce((b,f)=>b+f.count,0),h=d>0?a.count/d*100:0;return e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-24 text-sm",children:a.priority}),e.jsx("div",{className:"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full transition-all duration-500",style:{width:`${h}%`,backgroundColor:re[a.priority]||"#6b7280"}})}),e.jsx("div",{className:"w-16 text-right text-sm font-medium",children:a.count})]},a.priority)})})]})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.slaPerformance")}),u&&e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsxs("div",{className:`text-3xl font-bold ${J(u.compliancePercentage)}`,children:[u.compliancePercentage.toFixed(1),"%"]}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.complianceRate")})]}),e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:"text-3xl font-bold",children:u.ticketsWithinSla}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.withinSla")})]}),e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:"text-3xl font-bold text-[var(--error-text)]",children:u.ticketsBreached}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.breached")})]}),e.jsxs("div",{className:"space-y-2 p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsxs("div",{className:"flex justify-between text-sm",children:[e.jsxs("span",{children:[s("dashboard.avgResponse"),":"]}),e.jsx("span",{className:"font-medium",children:M(u.averageResponseMinutes)})]}),e.jsxs("div",{className:"flex justify-between text-sm",children:[e.jsxs("span",{children:[s("dashboard.avgResolution"),":"]}),e.jsx("span",{className:"font-medium",children:M(u.averageResolutionMinutes)})]})]})]})]}),e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.customerSatisfaction")}),g&&e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:`text-3xl font-bold ${Q(g.averageRating)}`,children:g.averageRating.toFixed(1)}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.averageRating")}),e.jsx("div",{className:"flex justify-center mt-1",children:[1,2,3,4,5].map(a=>e.jsx(r.Star,{className:`w-4 h-4 ${a<=Math.round(g.averageRating)?"text-[var(--warning-text)] fill-[var(--warning-text)]":"text-[var(--text-muted)]"}`},a))})]}),e.jsxs("div",{className:"text-center p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:"text-3xl font-bold",children:g.totalResponses}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:s("dashboard.totalResponses")})]}),e.jsxs("div",{className:"col-span-2 p-4 bg-[var(--bg-secondary)] rounded-lg",children:[e.jsx("div",{className:"text-sm font-medium mb-2",children:s("dashboard.ratingDistribution")}),e.jsx("div",{className:"space-y-1",children:[5,4,3,2,1].map(a=>{const d=g.ratingDistribution[a]||0,h=g.totalResponses>0?d/g.totalResponses*100:0;return e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[e.jsx("span",{className:"w-4",children:a}),e.jsx(r.Star,{className:"w-3 h-3 text-[var(--warning-text)] fill-[var(--warning-text)]"}),e.jsx("div",{className:"flex-1 h-3 bg-[var(--bg-primary)] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-[var(--warning-text)] rounded-full",style:{width:`${h}%`}})}),e.jsx("span",{className:"w-8 text-right text-xs",children:d})]},a)})})]})]})]})]}),e.jsxs("div",{className:"card p-4",children:[e.jsx("h3",{className:"font-semibold mb-4",children:s("dashboard.ticketTrends",{period:x})}),e.jsx("div",{className:"h-64",children:e.jsx(le,{data:F,t:s})})]}),e.jsxs("div",{className:"card p-4",children:[e.jsxs("h3",{className:"font-semibold mb-4 flex items-center gap-2",children:[e.jsx(r.Users,{className:"w-5 h-5"}),s("dashboard.agentWorkload")]}),C.length>0?e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-[var(--border-color)]",children:[e.jsx("th",{className:"text-left p-3 font-medium",children:s("dashboard.agent")}),e.jsx("th",{className:"text-center p-3 font-medium",children:s("dashboard.total")}),e.jsx("th",{className:"text-center p-3 font-medium",children:s("dashboard.open")}),e.jsx("th",{className:"text-center p-3 font-medium",children:s("dashboard.inProgress")}),e.jsx("th",{className:"text-center p-3 font-medium",children:s("dashboard.onHold")}),e.jsx("th",{className:"text-left p-3 font-medium",children:s("dashboard.load")})]})}),e.jsx("tbody",{children:C.map(a=>{const d=Math.max(...C.map(b=>b.totalAssigned)),h=d>0?a.totalAssigned/d*100:0;return e.jsxs("tr",{className:"border-b border-[var(--border-color)]",children:[e.jsxs("td",{className:"p-3",children:[e.jsx("div",{className:"font-medium",children:a.name}),e.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:a.email})]}),e.jsx("td",{className:"text-center p-3 font-semibold",children:a.totalAssigned}),e.jsx("td",{className:"text-center p-3",children:e.jsx("span",{className:"px-2 py-1 bg-[var(--warning-bg)] text-[var(--warning-text)] rounded-[var(--radius-badge)] text-sm",children:a.openCount})}),e.jsx("td",{className:"text-center p-3",children:e.jsx("span",{className:"px-2 py-1 bg-[var(--info-bg)] text-[var(--info-text)] rounded-[var(--radius-badge)] text-sm",children:a.inProgressCount})}),e.jsx("td",{className:"text-center p-3",children:e.jsx("span",{className:"px-2 py-1 bg-[var(--warning-bg)] text-[var(--warning-text)] rounded-[var(--radius-badge)] text-sm",children:a.onHoldCount})}),e.jsx("td",{className:"p-3 w-32",children:e.jsx("div",{className:"h-2 bg-[var(--bg-secondary)] rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-[var(--info-text)] rounded-full",style:{width:`${h}%`}})})})]},a.userId)})})]})}):e.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:s("dashboard.noAgentsAssigned")})]})]})}function j({title:s,value:l,icon:o,color:t,subtitle:m,trend:p}){const k={blue:"bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]",green:"bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]",yellow:"bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]",red:"bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]"};return e.jsxs("div",{className:`card p-4 border ${k[t]}`,children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("span",{className:"text-sm font-medium opacity-80",children:s}),o]}),e.jsx("div",{className:"text-2xl font-bold",children:l}),m&&e.jsx("div",{className:"text-xs opacity-70 mt-1",children:m}),p&&e.jsxs("div",{className:`flex items-center gap-1 mt-1 text-xs ${p.isUp?"text-[var(--success-text)]":"text-[var(--error-text)]"}`,children:[p.isUp?e.jsx(r.ArrowUp,{className:"w-3 h-3"}):e.jsx(r.ArrowDown,{className:"w-3 h-3"}),p.value,"%"]})]})}function le({data:s,t:l}){if(s.length===0)return e.jsx("div",{className:"flex items-center justify-center h-full text-[var(--text-secondary)]",children:l("dashboard.noTrendData")});const o=Math.max(...s.flatMap(t=>[t.created,t.resolved]),1);return e.jsxs("div",{className:"flex flex-col h-full",children:[e.jsxs("div",{className:"flex items-center gap-4 mb-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 rounded bg-[var(--info-text)]"}),e.jsx("span",{className:"text-sm",children:l("dashboard.created")})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 rounded bg-[var(--success-text)]"}),e.jsx("span",{className:"text-sm",children:l("dashboard.resolved")})]})]}),e.jsx("div",{className:"flex-1 flex items-end gap-1 overflow-x-auto pb-4",children:s.map(t=>e.jsxs("div",{className:"flex-1 min-w-[20px] flex gap-0.5",children:[e.jsx("div",{className:"flex-1 bg-[var(--info-text)] rounded-t transition-all duration-300 hover:opacity-80",style:{height:`${t.created/o*100}%`,minHeight:t.created>0?"4px":"0"},title:`Created: ${t.created}`}),e.jsx("div",{className:"flex-1 bg-[var(--success-text)] rounded-t transition-all duration-300 hover:opacity-80",style:{height:`${t.resolved/o*100}%`,minHeight:t.resolved>0?"4px":"0"},title:`Resolved: ${t.resolved}`})]},`${t.date}`))}),e.jsxs("div",{className:"flex justify-between text-xs text-[var(--text-secondary)] mt-2",children:[e.jsx("span",{children:s[0]&&new Date(s[0].date).toLocaleDateString()}),e.jsx("span",{children:s.at(-1)&&new Date(s.at(-1).date).toLocaleDateString()})]})]})}function M(s){if(s<60)return`${Math.round(s)}m`;const l=Math.floor(s/60),o=Math.round(s%60);if(l<24)return o>0?`${l}h ${o}m`:`${l}h`;const t=Math.floor(l/24),m=l%24;return m>0?`${t}d ${m}h`:`${t}d`}exports.DashboardPage=ce;
|
|
2
|
+
//# sourceMappingURL=DashboardPage-CwEZZ3jx.js.map
|