@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-CUZV1J9t.js","sources":["../../src/pages/platform/support/DashboardPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport {\r\n LayoutDashboard,\r\n Headphones,\r\n Clock,\r\n AlertTriangle,\r\n TrendingUp,\r\n Users,\r\n Star,\r\n CheckCircle,\r\n XCircle,\r\n ArrowUp,\r\n ArrowDown,\r\n Loader2,\r\n RefreshCw,\r\n ExternalLink,\r\n Info,\r\n} from 'lucide-react';\r\nimport { PageHeader } from '@/components/ui/PageHeader';\r\nimport { useAuth } from '@/contexts/AuthContext';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport { useTicketingProvider } from '@/hooks/useTicketingProvider';\r\nimport { supportApi, type GlpiSyncStatsDto } from '@/services/api/ticketApi';\r\nimport { ticketingApi } from '@/services/api/ticketingApi';\r\nimport {\r\n dashboardApi,\r\n slaApi,\r\n type DashboardOverviewDto,\r\n type StatusCountDto,\r\n type PriorityCountDto,\r\n type AgentWorkloadDto,\r\n type TrendDataDto,\r\n type SatisfactionStatsDto,\r\n type SlaComplianceDto,\r\n type TicketSlaDto,\r\n} from '@/services/api/supportApi';\r\n\r\nconst priorityColors: Record<string, string> = {\r\n Low: 'var(--info-text)',\r\n Medium: 'var(--warning-text)',\r\n High: 'var(--warning-text)',\r\n Critical: 'var(--error-text)',\r\n};\r\n\r\nconst statusColors: Record<string, string> = {\r\n Open: 'var(--warning-text)',\r\n InProgress: 'var(--info-text)',\r\n OnHold: 'var(--warning-text)',\r\n Resolved: 'var(--success-text)',\r\n Closed: 'var(--text-secondary)',\r\n Rejected: 'var(--error-text)',\r\n};\r\n\r\nexport function DashboardPage(): ReactElement {\r\n const { t } = useTranslation('support');\r\n const navigate = useNavigate();\r\n const { hasPermission } = useAuth();\r\n const { isGlpi, glpiBaseUrl } = useTicketingProvider();\r\n const { currentTenant } = 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 // Permission checks\r\n const canViewSla = hasPermission('support.sla.read');\r\n\r\n // Data states\r\n const [overview, setOverview] = useState<DashboardOverviewDto | null>(null);\r\n const [statusData, setStatusData] = useState<StatusCountDto[]>([]);\r\n const [priorityData, setPriorityData] = useState<PriorityCountDto[]>([]);\r\n const [agentWorkload, setAgentWorkload] = useState<AgentWorkloadDto[]>([]);\r\n const [trends, setTrends] = useState<TrendDataDto[]>([]);\r\n const [satisfaction, setSatisfaction] = useState<SatisfactionStatsDto | null>(null);\r\n const [slaCompliance, setSlaCompliance] = useState<SlaComplianceDto | null>(null);\r\n const [breachedTickets, setBreachedTickets] = useState<TicketSlaDto[]>([]);\r\n const [approachingBreach, setApproachingBreach] = useState<TicketSlaDto[]>([]);\r\n const [glpiSyncStats, setGlpiSyncStats] = useState<GlpiSyncStatsDto | null>(null);\r\n const [syncing, setSyncing] = useState(false);\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n const [\r\n overviewRes,\r\n statusRes,\r\n priorityRes,\r\n workloadRes,\r\n trendsRes,\r\n satisfactionRes,\r\n slaRes,\r\n ] = await Promise.all([\r\n dashboardApi.getOverview(period),\r\n dashboardApi.getByStatus(),\r\n dashboardApi.getByPriority(),\r\n dashboardApi.getAgentWorkload(),\r\n dashboardApi.getTrends(period),\r\n dashboardApi.getSatisfactionStats(period),\r\n dashboardApi.getSlaCompliance(period),\r\n ]);\r\n\r\n setOverview(overviewRes);\r\n setStatusData(statusRes);\r\n setPriorityData(priorityRes);\r\n setAgentWorkload(workloadRes);\r\n setTrends(trendsRes);\r\n setSatisfaction(satisfactionRes);\r\n setSlaCompliance(slaRes);\r\n\r\n // Load GLPI sync stats if GLPI is provider\r\n if (isGlpi) {\r\n try {\r\n const syncStats = await supportApi.tickets.getGlpiSyncStats();\r\n setGlpiSyncStats(syncStats);\r\n } catch {\r\n // Sync stats are optional\r\n }\r\n }\r\n\r\n // SLA detail endpoints require support.sla.read permission\r\n if (canViewSla) {\r\n const [breachedRes, approachingRes] = await Promise.all([\r\n slaApi.getBreachedTickets(),\r\n slaApi.getTicketsApproachingBreach(60),\r\n ]);\r\n setBreachedTickets(breachedRes);\r\n setApproachingBreach(approachingRes);\r\n }\r\n } catch (error) {\r\n console.error('Failed to load dashboard data:', error);\r\n } finally {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }, [period, canViewSla, isGlpi]);\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n const handleRefresh = () => {\r\n setRefreshing(true);\r\n loadData();\r\n };\r\n\r\n const handleTriggerSync = async () => {\r\n if (!currentTenant?.id || syncing) return;\r\n setSyncing(true);\r\n try {\r\n await ticketingApi.triggerSync(currentTenant.id);\r\n // Reload data after sync\r\n await loadData();\r\n } catch {\r\n // Error handled silently\r\n } finally {\r\n setSyncing(false);\r\n }\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 const getComplianceColor = (percentage: number) => {\r\n if (percentage >= 95) return 'text-[var(--success-text)]';\r\n if (percentage >= 80) return 'text-[var(--warning-text)]';\r\n return 'text-[var(--error-text)]';\r\n };\r\n\r\n const getRatingColor = (rating: number) => {\r\n if (rating >= 4) return 'text-[var(--success-text)]';\r\n if (rating >= 3) return 'text-[var(--warning-text)]';\r\n return 'text-[var(--error-text)]';\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('title', 'Support'), href: '/support' },\r\n { label: t('dashboard.title', 'Dashboard') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <PageHeader\r\n title={t('dashboard.title')}\r\n subtitle={t('dashboard.subtitle')}\r\n icon={<LayoutDashboard className=\"w-6 h-6\" />}\r\n actions={\r\n <>\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}>{t('dashboard.period7')}</option>\r\n <option value={30}>{t('dashboard.period30')}</option>\r\n <option value={90}>{t('dashboard.period90')}</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 {t('dashboard.refresh')}\r\n </button>\r\n </>\r\n }\r\n />\r\n\r\n {/* GLPI Provider Banner */}\r\n {isGlpi && (\r\n <div className=\"flex items-center gap-3 p-4 rounded-lg bg-[var(--info-bg)] border border-[var(--info-border)] text-[var(--info-text)]\">\r\n <Info className=\"w-5 h-5 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"font-medium\">{t('glpi.managedByGlpi')}</p>\r\n <p className=\"text-sm opacity-80\">{t('glpi.dashboardSyncInfo')}</p>\r\n </div>\r\n {glpiBaseUrl && (\r\n <a\r\n href={glpiBaseUrl}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"btn btn-secondary flex items-center gap-2 text-sm\"\r\n >\r\n <ExternalLink className=\"w-4 h-4\" />\r\n {t('glpi.openGlpi')}\r\n </a>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* GLPI Sync Status */}\r\n {isGlpi && glpiSyncStats && (\r\n <div className=\"card p-4 space-y-4\">\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h3 className=\"font-semibold flex items-center gap-2\">\r\n <RefreshCw className=\"w-5 h-5\" />\r\n {t('glpi.sync.title', 'GLPI Sync Status')}\r\n </h3>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">{t('glpi.sync.subtitle', 'Synchronization overview with GLPI')}</p>\r\n </div>\r\n <button\r\n onClick={handleTriggerSync}\r\n disabled={syncing}\r\n className=\"btn btn-secondary flex items-center gap-2\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${syncing ? 'animate-spin' : ''}`} />\r\n {syncing ? t('glpi.sync.syncing', 'Syncing...') : t('glpi.sync.triggerSync', 'Sync Now')}\r\n </button>\r\n </div>\r\n\r\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\r\n <div className=\"card p-4 text-center border bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]\">\r\n <div className=\"text-2xl font-bold\">{glpiSyncStats.totalMappedTickets}</div>\r\n <div className=\"text-sm opacity-80\">{t('glpi.sync.totalSynced', 'Total Synced')}</div>\r\n </div>\r\n <div className=\"card p-4 text-center border bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]\">\r\n <div className=\"text-2xl font-bold\">{glpiSyncStats.ticketsSyncedOk}</div>\r\n <div className=\"text-sm opacity-80\">{t('glpi.sync.syncSuccess', 'Successful')}</div>\r\n </div>\r\n <div className=\"card p-4 text-center border bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]\">\r\n <div className=\"text-2xl font-bold\">{glpiSyncStats.ticketsWithSyncErrors}</div>\r\n <div className=\"text-sm opacity-80\">{t('glpi.sync.syncErrors', 'Errors')}</div>\r\n </div>\r\n <div className={`card p-4 text-center border ${glpiSyncStats.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)]'}`}>\r\n <div className=\"text-2xl font-bold\">{glpiSyncStats.successRate}%</div>\r\n <div className=\"text-sm opacity-80\">{t('glpi.sync.successRate', 'Success Rate')}</div>\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-center gap-6 text-sm text-[var(--text-secondary)]\">\r\n <div>\r\n <span className=\"font-medium\">{t('glpi.sync.lastSync', 'Last Sync')}:</span>{' '}\r\n {glpiSyncStats.lastSyncAt\r\n ? new Date(glpiSyncStats.lastSyncAt).toLocaleString()\r\n : t('glpi.sync.never', 'Never')}\r\n </div>\r\n <div>\r\n <span className=\"font-medium\">{t('glpi.sync.syncInterval', 'Interval')}:</span>{' '}\r\n {t('glpi.sync.everyNMinutes', 'Every {{n}} min', { n: glpiSyncStats.syncIntervalMinutes })}\r\n </div>\r\n <div>\r\n <span className={`px-2 py-0.5 rounded text-xs font-medium ${glpiSyncStats.syncEnabled ? 'bg-[var(--success-bg)] text-[var(--success-text)]' : 'bg-[var(--bg-secondary)] text-[var(--text-secondary)]'}`}>\r\n {glpiSyncStats.syncEnabled ? t('glpi.sync.enabled', 'Enabled') : t('glpi.sync.disabled', 'Disabled')}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n {glpiSyncStats.lastSyncError && (\r\n <div className=\"p-3 rounded-lg bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <p className=\"text-sm font-medium text-[var(--error-text)]\">{t('glpi.sync.lastError', 'Last Sync Error')}</p>\r\n <p className=\"text-sm text-[var(--error-text)] opacity-80 mt-1\">{glpiSyncStats.lastSyncError}</p>\r\n </div>\r\n )}\r\n </div>\r\n )}\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={t('dashboard.totalTickets')}\r\n value={overview?.totalTickets ?? 0}\r\n icon={<Headphones className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n />\r\n <KpiCard\r\n title={t('dashboard.newTickets')}\r\n value={overview?.newTickets ?? 0}\r\n icon={<TrendingUp className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={t('dashboard.lastNDays', { period })}\r\n />\r\n <KpiCard\r\n title={t('dashboard.openTickets')}\r\n value={overview?.openTickets ?? 0}\r\n icon={<Clock className=\"w-5 h-5\" />}\r\n color=\"yellow\"\r\n />\r\n <KpiCard\r\n title={t('dashboard.resolvedTickets')}\r\n value={overview?.resolvedTickets ?? 0}\r\n icon={<CheckCircle className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={t('dashboard.lastNDays', { period })}\r\n />\r\n <KpiCard\r\n title={t('dashboard.slaCompliance')}\r\n value={`${overview?.slaCompliancePercentage?.toFixed(1) ?? 0}%`}\r\n icon={<AlertTriangle className=\"w-5 h-5\" />}\r\n color={(overview?.slaCompliancePercentage ?? 0) >= 90 ? 'green' : 'red'}\r\n />\r\n <KpiCard\r\n title={t('dashboard.avgSatisfaction')}\r\n value={`${overview?.averageSatisfaction?.toFixed(1) ?? 0}/5`}\r\n icon={<Star className=\"w-5 h-5\" />}\r\n color={(overview?.averageSatisfaction ?? 0) >= 4 ? 'green' : 'yellow'}\r\n />\r\n </div>\r\n\r\n {/* SLA Alerts - only visible with support.sla.read permission */}\r\n {canViewSla && (breachedTickets.length > 0 || approachingBreach.length > 0) && (\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n {breachedTickets.length > 0 && (\r\n <div className=\"card p-4 border-l-4 border-[var(--error-border)]\">\r\n <h3 className=\"font-semibold text-[var(--error-text)] flex items-center gap-2 mb-3\">\r\n <XCircle className=\"w-5 h-5\" />\r\n {t('dashboard.slaBreached')} ({breachedTickets.length})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {breachedTickets.slice(0, 5).map((ticket) => (\r\n <button\r\n type=\"button\"\r\n key={ticket.id}\r\n className=\"w-full flex items-center justify-between p-2 bg-[var(--error-bg)] rounded cursor-pointer hover:opacity-80 text-left\"\r\n onClick={() => navigate(`/support/tickets/${ticket.ticketId}`)}\r\n >\r\n <div>\r\n <span className=\"font-mono text-sm\">{ticket.ticketNumber}</span>\r\n <span className=\"ml-2 text-sm\">{ticket.ticketTitle}</span>\r\n </div>\r\n <span className=\"text-xs text-[var(--error-text)] font-medium\">\r\n {ticket.responseBreached && 'Response'}{' '}\r\n {ticket.resolutionBreached && 'Resolution'}\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {approachingBreach.length > 0 && (\r\n <div className=\"card p-4 border-l-4 border-[var(--warning-border)]\">\r\n <h3 className=\"font-semibold text-[var(--warning-text)] flex items-center gap-2 mb-3\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n {t('dashboard.approachingBreach')} ({approachingBreach.length})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {approachingBreach.slice(0, 5).map((ticket) => (\r\n <button\r\n type=\"button\"\r\n key={ticket.id}\r\n className=\"w-full flex items-center justify-between p-2 bg-[var(--warning-bg)] rounded cursor-pointer hover:opacity-80 text-left\"\r\n onClick={() => navigate(`/support/tickets/${ticket.ticketId}`)}\r\n >\r\n <div>\r\n <span className=\"font-mono text-sm\">{ticket.ticketNumber}</span>\r\n <span className=\"ml-2 text-sm\">{ticket.ticketTitle}</span>\r\n </div>\r\n <span className=\"text-xs text-[var(--warning-text)] font-medium\">\r\n {Math.round(ticket.responseSlaPercentage)}% Response\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\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\">{t('dashboard.ticketsByStatus')}</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}</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-16 text-right text-sm font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Priority Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4\">{t('dashboard.activeTicketsByPriority')}</h3>\r\n <div className=\"space-y-3\">\r\n {priorityData.map((item) => {\r\n const total = priorityData.reduce((sum, p) => sum + p.count, 0);\r\n const percentage = total > 0 ? (item.count / total) * 100 : 0;\r\n return (\r\n <div key={item.priority} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{item.priority}</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: priorityColors[item.priority] || '#6b7280',\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-16 text-right text-sm font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* SLA & Satisfaction Row */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* SLA Compliance */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4\">{t('dashboard.slaPerformance')}</h3>\r\n {slaCompliance && (\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 ${getComplianceColor(slaCompliance.compliancePercentage)}`}>\r\n {slaCompliance.compliancePercentage.toFixed(1)}%\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.complianceRate')}</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\">{slaCompliance.ticketsWithinSla}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.withinSla')}</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-[var(--error-text)]\">{slaCompliance.ticketsBreached}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.breached')}</div>\r\n </div>\r\n <div className=\"space-y-2 p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"flex justify-between text-sm\">\r\n <span>{t('dashboard.avgResponse')}:</span>\r\n <span className=\"font-medium\">{formatDuration(slaCompliance.averageResponseMinutes)}</span>\r\n </div>\r\n <div className=\"flex justify-between text-sm\">\r\n <span>{t('dashboard.avgResolution')}:</span>\r\n <span className=\"font-medium\">{formatDuration(slaCompliance.averageResolutionMinutes)}</span>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Satisfaction */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4\">{t('dashboard.customerSatisfaction')}</h3>\r\n {satisfaction && (\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 ${getRatingColor(satisfaction.averageRating)}`}>\r\n {satisfaction.averageRating.toFixed(1)}\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.averageRating')}</div>\r\n <div className=\"flex justify-center mt-1\">\r\n {[1, 2, 3, 4, 5].map((star) => (\r\n <Star\r\n key={star}\r\n className={`w-4 h-4 ${star <= Math.round(satisfaction.averageRating)\r\n ? 'text-[var(--warning-text)] fill-[var(--warning-text)]'\r\n : 'text-[var(--text-muted)]'\r\n }`}\r\n />\r\n ))}\r\n </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\">{satisfaction.totalResponses}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.totalResponses')}</div>\r\n </div>\r\n <div className=\"col-span-2 p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-sm font-medium mb-2\">{t('dashboard.ratingDistribution')}</div>\r\n <div className=\"space-y-1\">\r\n {[5, 4, 3, 2, 1].map((rating) => {\r\n const count = satisfaction.ratingDistribution[rating] || 0;\r\n const percentage =\r\n satisfaction.totalResponses > 0\r\n ? (count / satisfaction.totalResponses) * 100\r\n : 0;\r\n return (\r\n <div key={rating} className=\"flex items-center gap-2 text-sm\">\r\n <span className=\"w-4\">{rating}</span>\r\n <Star className=\"w-3 h-3 text-[var(--warning-text)] fill-[var(--warning-text)]\" />\r\n <div className=\"flex-1 h-3 bg-[var(--bg-primary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full bg-[var(--warning-text)] rounded-full\"\r\n style={{ width: `${percentage}%` }}\r\n />\r\n </div>\r\n <span className=\"w-8 text-right text-xs\">{count}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n )}\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\">{t('dashboard.ticketTrends', { period })}</h3>\r\n <div className=\"h-64\">\r\n <TrendChart data={trends} t={t} />\r\n </div>\r\n </div>\r\n\r\n {/* Agent Workload */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Users className=\"w-5 h-5\" />\r\n {t('dashboard.agentWorkload')}\r\n </h3>\r\n {agentWorkload.length > 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\">{t('dashboard.agent')}</th>\r\n <th className=\"text-center p-3 font-medium\">{t('dashboard.total')}</th>\r\n <th className=\"text-center p-3 font-medium\">{t('dashboard.open')}</th>\r\n <th className=\"text-center p-3 font-medium\">{t('dashboard.inProgress')}</th>\r\n <th className=\"text-center p-3 font-medium\">{t('dashboard.onHold')}</th>\r\n <th className=\"text-left p-3 font-medium\">{t('dashboard.load')}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {agentWorkload.map((agent) => {\r\n const maxLoad = Math.max(...agentWorkload.map((a) => a.totalAssigned));\r\n const loadPercentage = maxLoad > 0 ? (agent.totalAssigned / maxLoad) * 100 : 0;\r\n return (\r\n <tr key={agent.userId} className=\"border-b border-[var(--border-color)]\">\r\n <td className=\"p-3\">\r\n <div className=\"font-medium\">{agent.name}</div>\r\n <div className=\"text-xs text-[var(--text-secondary)]\">{agent.email}</div>\r\n </td>\r\n <td className=\"text-center p-3 font-semibold\">{agent.totalAssigned}</td>\r\n <td className=\"text-center p-3\">\r\n <span className=\"px-2 py-1 bg-[var(--warning-bg)] text-[var(--warning-text)] rounded-[var(--radius-badge)] text-sm\">\r\n {agent.openCount}\r\n </span>\r\n </td>\r\n <td className=\"text-center p-3\">\r\n <span className=\"px-2 py-1 bg-[var(--info-bg)] text-[var(--info-text)] rounded-[var(--radius-badge)] text-sm\">\r\n {agent.inProgressCount}\r\n </span>\r\n </td>\r\n <td className=\"text-center p-3\">\r\n <span className=\"px-2 py-1 bg-[var(--warning-bg)] text-[var(--warning-text)] rounded-[var(--radius-badge)] text-sm\">\r\n {agent.onHoldCount}\r\n </span>\r\n </td>\r\n <td className=\"p-3 w-32\">\r\n <div className=\"h-2 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full bg-[var(--info-text)] rounded-full\"\r\n style={{ width: `${loadPercentage}%` }}\r\n />\r\n </div>\r\n </td>\r\n </tr>\r\n );\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 {t('dashboard.noAgentsAssigned')}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// KPI Card Component\r\nfunction KpiCard({\r\n title,\r\n value,\r\n icon,\r\n color,\r\n subtitle,\r\n trend,\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 trend?: { value: number; isUp: boolean };\r\n}) {\r\n const colorClasses = {\r\n blue: 'bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]',\r\n green: 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]',\r\n yellow: 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]',\r\n red: 'bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]',\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 {trend && (\r\n <div className={`flex items-center gap-1 mt-1 text-xs ${trend.isUp ? 'text-[var(--success-text)]' : 'text-[var(--error-text)]'}`}>\r\n {trend.isUp ? <ArrowUp className=\"w-3 h-3\" /> : <ArrowDown className=\"w-3 h-3\" />}\r\n {trend.value}%\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Simple Trend Chart Component\r\ntype TrendTFunction = ReturnType<typeof useTranslation>['t'];\r\n\r\nfunction TrendChart({ data, t }: { data: TrendDataDto[]; t: TrendTFunction }) {\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 {t('dashboard.noTrendData')}\r\n </div>\r\n );\r\n }\r\n\r\n const maxValue = Math.max(...data.flatMap((d) => [d.created, d.resolved]), 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-[var(--info-text)]\" />\r\n <span className=\"text-sm\">{t('dashboard.created')}</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-[var(--success-text)]\" />\r\n <span className=\"text-sm\">{t('dashboard.resolved')}</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-[var(--info-text)] rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{ height: `${(item.created / maxValue) * 100}%`, minHeight: item.created > 0 ? '4px' : '0' }}\r\n title={`Created: ${item.created}`}\r\n />\r\n <div\r\n className=\"flex-1 bg-[var(--success-text)] rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{ height: `${(item.resolved / maxValue) * 100}%`, minHeight: item.resolved > 0 ? '4px' : '0' }}\r\n title={`Resolved: ${item.resolved}`}\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()}</span>\r\n <span>{data.at(-1) && new Date(data.at(-1)!.date).toLocaleDateString()}</span>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Format duration helper\r\nfunction formatDuration(minutes: number): string {\r\n if (minutes < 60) return `${Math.round(minutes)}m`;\r\n const hours = Math.floor(minutes / 60);\r\n const mins = Math.round(minutes % 60);\r\n if (hours < 24) return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;\r\n const days = Math.floor(hours / 24);\r\n const remainingHours = hours % 24;\r\n return remainingHours > 0 ? `${days}d ${remainingHours}h` : `${days}d`;\r\n}\r\n"],"names":["priorityColors","statusColors","DashboardPage","t","useTranslation","navigate","useNavigate","hasPermission","useAuth","isGlpi","glpiBaseUrl","useTicketingProvider","currentTenant","useTenant","loading","setLoading","useState","refreshing","setRefreshing","period","setPeriod","canViewSla","overview","setOverview","statusData","setStatusData","priorityData","setPriorityData","agentWorkload","setAgentWorkload","trends","setTrends","satisfaction","setSatisfaction","slaCompliance","setSlaCompliance","breachedTickets","setBreachedTickets","approachingBreach","setApproachingBreach","glpiSyncStats","setGlpiSyncStats","syncing","setSyncing","loadData","useCallback","overviewRes","statusRes","priorityRes","workloadRes","trendsRes","satisfactionRes","slaRes","dashboardApi","syncStats","supportApi","breachedRes","approachingRes","slaApi","error","useEffect","handleRefresh","handleTriggerSync","ticketingApi","jsx","Loader2","getComplianceColor","percentage","getRatingColor","rating","jsxs","Breadcrumb","PageHeader","LayoutDashboard","Fragment","e","RefreshCw","Info","ExternalLink","KpiCard","Headphones","TrendingUp","Clock","CheckCircle","AlertTriangle","Star","XCircle","ticket","item","total","sum","s","p","formatDuration","star","count","TrendChart","Users","agent","maxLoad","a","loadPercentage","title","value","icon","color","subtitle","trend","colorClasses","ArrowUp","ArrowDown","data","maxValue","d","minutes","hours","mins","days","remainingHours"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage-CwEZZ3jx.js","sources":["../../src/pages/platform/support/DashboardPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport {\r\n LayoutDashboard,\r\n Headphones,\r\n Clock,\r\n AlertTriangle,\r\n TrendingUp,\r\n Users,\r\n Star,\r\n CheckCircle,\r\n XCircle,\r\n ArrowUp,\r\n ArrowDown,\r\n Loader2,\r\n RefreshCw,\r\n ExternalLink,\r\n Info,\r\n} from 'lucide-react';\r\nimport { PageHeader } from '@/components/ui/PageHeader';\r\nimport { useAuth } from '@/contexts/AuthContext';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport { useTicketingProvider } from '@/hooks/useTicketingProvider';\r\nimport { supportApi, type GlpiSyncStatsDto } from '@/services/api/ticketApi';\r\nimport { ticketingApi } from '@/services/api/ticketingApi';\r\nimport {\r\n dashboardApi,\r\n slaApi,\r\n type DashboardOverviewDto,\r\n type StatusCountDto,\r\n type PriorityCountDto,\r\n type AgentWorkloadDto,\r\n type TrendDataDto,\r\n type SatisfactionStatsDto,\r\n type SlaComplianceDto,\r\n type TicketSlaDto,\r\n} from '@/services/api/supportApi';\r\n\r\nconst priorityColors: Record<string, string> = {\r\n Low: 'var(--info-text)',\r\n Medium: 'var(--warning-text)',\r\n High: 'var(--warning-text)',\r\n Critical: 'var(--error-text)',\r\n};\r\n\r\nconst statusColors: Record<string, string> = {\r\n Open: 'var(--warning-text)',\r\n InProgress: 'var(--info-text)',\r\n OnHold: 'var(--warning-text)',\r\n Resolved: 'var(--success-text)',\r\n Closed: 'var(--text-secondary)',\r\n Rejected: 'var(--error-text)',\r\n};\r\n\r\nexport function DashboardPage(): ReactElement {\r\n const { t } = useTranslation('support');\r\n const navigate = useNavigate();\r\n const { hasPermission } = useAuth();\r\n const { isGlpi, glpiBaseUrl } = useTicketingProvider();\r\n const { currentTenant } = 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 // Permission checks\r\n const canViewSla = hasPermission('support.sla.read');\r\n\r\n // Data states\r\n const [overview, setOverview] = useState<DashboardOverviewDto | null>(null);\r\n const [statusData, setStatusData] = useState<StatusCountDto[]>([]);\r\n const [priorityData, setPriorityData] = useState<PriorityCountDto[]>([]);\r\n const [agentWorkload, setAgentWorkload] = useState<AgentWorkloadDto[]>([]);\r\n const [trends, setTrends] = useState<TrendDataDto[]>([]);\r\n const [satisfaction, setSatisfaction] = useState<SatisfactionStatsDto | null>(null);\r\n const [slaCompliance, setSlaCompliance] = useState<SlaComplianceDto | null>(null);\r\n const [breachedTickets, setBreachedTickets] = useState<TicketSlaDto[]>([]);\r\n const [approachingBreach, setApproachingBreach] = useState<TicketSlaDto[]>([]);\r\n const [glpiSyncStats, setGlpiSyncStats] = useState<GlpiSyncStatsDto | null>(null);\r\n const [syncing, setSyncing] = useState(false);\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n const [\r\n overviewRes,\r\n statusRes,\r\n priorityRes,\r\n workloadRes,\r\n trendsRes,\r\n satisfactionRes,\r\n slaRes,\r\n ] = await Promise.all([\r\n dashboardApi.getOverview(period),\r\n dashboardApi.getByStatus(),\r\n dashboardApi.getByPriority(),\r\n dashboardApi.getAgentWorkload(),\r\n dashboardApi.getTrends(period),\r\n dashboardApi.getSatisfactionStats(period),\r\n dashboardApi.getSlaCompliance(period),\r\n ]);\r\n\r\n setOverview(overviewRes);\r\n setStatusData(statusRes);\r\n setPriorityData(priorityRes);\r\n setAgentWorkload(workloadRes);\r\n setTrends(trendsRes);\r\n setSatisfaction(satisfactionRes);\r\n setSlaCompliance(slaRes);\r\n\r\n // Load GLPI sync stats if GLPI is provider\r\n if (isGlpi) {\r\n try {\r\n const syncStats = await supportApi.tickets.getGlpiSyncStats();\r\n setGlpiSyncStats(syncStats);\r\n } catch {\r\n // Sync stats are optional\r\n }\r\n }\r\n\r\n // SLA detail endpoints require support.sla.read permission\r\n if (canViewSla) {\r\n const [breachedRes, approachingRes] = await Promise.all([\r\n slaApi.getBreachedTickets(),\r\n slaApi.getTicketsApproachingBreach(60),\r\n ]);\r\n setBreachedTickets(breachedRes);\r\n setApproachingBreach(approachingRes);\r\n }\r\n } catch (error) {\r\n console.error('Failed to load dashboard data:', error);\r\n } finally {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }, [period, canViewSla, isGlpi]);\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n const handleRefresh = () => {\r\n setRefreshing(true);\r\n loadData();\r\n };\r\n\r\n const handleTriggerSync = async () => {\r\n if (!currentTenant?.id || syncing) return;\r\n setSyncing(true);\r\n try {\r\n await ticketingApi.triggerSync(currentTenant.id);\r\n // Reload data after sync\r\n await loadData();\r\n } catch {\r\n // Error handled silently\r\n } finally {\r\n setSyncing(false);\r\n }\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 const getComplianceColor = (percentage: number) => {\r\n if (percentage >= 95) return 'text-[var(--success-text)]';\r\n if (percentage >= 80) return 'text-[var(--warning-text)]';\r\n return 'text-[var(--error-text)]';\r\n };\r\n\r\n const getRatingColor = (rating: number) => {\r\n if (rating >= 4) return 'text-[var(--success-text)]';\r\n if (rating >= 3) return 'text-[var(--warning-text)]';\r\n return 'text-[var(--error-text)]';\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('title', 'Support'), href: '/support' },\r\n { label: t('dashboard.title', 'Dashboard') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <PageHeader\r\n title={t('dashboard.title')}\r\n subtitle={t('dashboard.subtitle')}\r\n icon={<LayoutDashboard className=\"w-6 h-6\" />}\r\n actions={\r\n <>\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}>{t('dashboard.period7')}</option>\r\n <option value={30}>{t('dashboard.period30')}</option>\r\n <option value={90}>{t('dashboard.period90')}</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 {t('dashboard.refresh')}\r\n </button>\r\n </>\r\n }\r\n />\r\n\r\n {/* GLPI Provider Banner */}\r\n {isGlpi && (\r\n <div className=\"flex items-center gap-3 p-4 rounded-lg bg-[var(--info-bg)] border border-[var(--info-border)] text-[var(--info-text)]\">\r\n <Info className=\"w-5 h-5 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"font-medium\">{t('glpi.managedByGlpi')}</p>\r\n <p className=\"text-sm opacity-80\">{t('glpi.dashboardSyncInfo')}</p>\r\n </div>\r\n {glpiBaseUrl && (\r\n <a\r\n href={glpiBaseUrl}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"btn btn-secondary flex items-center gap-2 text-sm\"\r\n >\r\n <ExternalLink className=\"w-4 h-4\" />\r\n {t('glpi.openGlpi')}\r\n </a>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* GLPI Sync Status */}\r\n {isGlpi && glpiSyncStats && (\r\n <div className=\"card p-4 space-y-4\">\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h3 className=\"font-semibold flex items-center gap-2\">\r\n <RefreshCw className=\"w-5 h-5\" />\r\n {t('glpi.sync.title', 'GLPI Sync Status')}\r\n </h3>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">{t('glpi.sync.subtitle', 'Synchronization overview with GLPI')}</p>\r\n </div>\r\n <button\r\n onClick={handleTriggerSync}\r\n disabled={syncing}\r\n className=\"btn btn-secondary flex items-center gap-2\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${syncing ? 'animate-spin' : ''}`} />\r\n {syncing ? t('glpi.sync.syncing', 'Syncing...') : t('glpi.sync.triggerSync', 'Sync Now')}\r\n </button>\r\n </div>\r\n\r\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\r\n <div className=\"card p-4 text-center border bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]\">\r\n <div className=\"text-2xl font-bold\">{glpiSyncStats.totalMappedTickets}</div>\r\n <div className=\"text-sm opacity-80\">{t('glpi.sync.totalSynced', 'Total Synced')}</div>\r\n </div>\r\n <div className=\"card p-4 text-center border bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]\">\r\n <div className=\"text-2xl font-bold\">{glpiSyncStats.ticketsSyncedOk}</div>\r\n <div className=\"text-sm opacity-80\">{t('glpi.sync.syncSuccess', 'Successful')}</div>\r\n </div>\r\n <div className=\"card p-4 text-center border bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]\">\r\n <div className=\"text-2xl font-bold\">{glpiSyncStats.ticketsWithSyncErrors}</div>\r\n <div className=\"text-sm opacity-80\">{t('glpi.sync.syncErrors', 'Errors')}</div>\r\n </div>\r\n <div className={`card p-4 text-center border ${glpiSyncStats.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)]'}`}>\r\n <div className=\"text-2xl font-bold\">{glpiSyncStats.successRate}%</div>\r\n <div className=\"text-sm opacity-80\">{t('glpi.sync.successRate', 'Success Rate')}</div>\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-center gap-6 text-sm text-[var(--text-secondary)]\">\r\n <div>\r\n <span className=\"font-medium\">{t('glpi.sync.lastSync', 'Last Sync')}:</span>{' '}\r\n {glpiSyncStats.lastSyncAt\r\n ? new Date(glpiSyncStats.lastSyncAt).toLocaleString()\r\n : t('glpi.sync.never', 'Never')}\r\n </div>\r\n <div>\r\n <span className=\"font-medium\">{t('glpi.sync.syncInterval', 'Interval')}:</span>{' '}\r\n {t('glpi.sync.everyNMinutes', 'Every {{n}} min', { n: glpiSyncStats.syncIntervalMinutes })}\r\n </div>\r\n <div>\r\n <span className={`px-2 py-0.5 rounded text-xs font-medium ${glpiSyncStats.syncEnabled ? 'bg-[var(--success-bg)] text-[var(--success-text)]' : 'bg-[var(--bg-secondary)] text-[var(--text-secondary)]'}`}>\r\n {glpiSyncStats.syncEnabled ? t('glpi.sync.enabled', 'Enabled') : t('glpi.sync.disabled', 'Disabled')}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n {glpiSyncStats.lastSyncError && (\r\n <div className=\"p-3 rounded-lg bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <p className=\"text-sm font-medium text-[var(--error-text)]\">{t('glpi.sync.lastError', 'Last Sync Error')}</p>\r\n <p className=\"text-sm text-[var(--error-text)] opacity-80 mt-1\">{glpiSyncStats.lastSyncError}</p>\r\n </div>\r\n )}\r\n </div>\r\n )}\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={t('dashboard.totalTickets')}\r\n value={overview?.totalTickets ?? 0}\r\n icon={<Headphones className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n />\r\n <KpiCard\r\n title={t('dashboard.newTickets')}\r\n value={overview?.newTickets ?? 0}\r\n icon={<TrendingUp className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={t('dashboard.lastNDays', { period })}\r\n />\r\n <KpiCard\r\n title={t('dashboard.openTickets')}\r\n value={overview?.openTickets ?? 0}\r\n icon={<Clock className=\"w-5 h-5\" />}\r\n color=\"yellow\"\r\n />\r\n <KpiCard\r\n title={t('dashboard.resolvedTickets')}\r\n value={overview?.resolvedTickets ?? 0}\r\n icon={<CheckCircle className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={t('dashboard.lastNDays', { period })}\r\n />\r\n <KpiCard\r\n title={t('dashboard.slaCompliance')}\r\n value={`${overview?.slaCompliancePercentage?.toFixed(1) ?? 0}%`}\r\n icon={<AlertTriangle className=\"w-5 h-5\" />}\r\n color={(overview?.slaCompliancePercentage ?? 0) >= 90 ? 'green' : 'red'}\r\n />\r\n <KpiCard\r\n title={t('dashboard.avgSatisfaction')}\r\n value={`${overview?.averageSatisfaction?.toFixed(1) ?? 0}/5`}\r\n icon={<Star className=\"w-5 h-5\" />}\r\n color={(overview?.averageSatisfaction ?? 0) >= 4 ? 'green' : 'yellow'}\r\n />\r\n </div>\r\n\r\n {/* SLA Alerts - only visible with support.sla.read permission */}\r\n {canViewSla && (breachedTickets.length > 0 || approachingBreach.length > 0) && (\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n {breachedTickets.length > 0 && (\r\n <div className=\"card p-4 border-l-4 border-[var(--error-border)]\">\r\n <h3 className=\"font-semibold text-[var(--error-text)] flex items-center gap-2 mb-3\">\r\n <XCircle className=\"w-5 h-5\" />\r\n {t('dashboard.slaBreached')} ({breachedTickets.length})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {breachedTickets.slice(0, 5).map((ticket) => (\r\n <button\r\n type=\"button\"\r\n key={ticket.id}\r\n className=\"w-full flex items-center justify-between p-2 bg-[var(--error-bg)] rounded cursor-pointer hover:opacity-80 text-left\"\r\n onClick={() => navigate(`/support/tickets/${ticket.ticketId}`)}\r\n >\r\n <div>\r\n <span className=\"font-mono text-sm\">{ticket.ticketNumber}</span>\r\n <span className=\"ml-2 text-sm\">{ticket.ticketTitle}</span>\r\n </div>\r\n <span className=\"text-xs text-[var(--error-text)] font-medium\">\r\n {ticket.responseBreached && 'Response'}{' '}\r\n {ticket.resolutionBreached && 'Resolution'}\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {approachingBreach.length > 0 && (\r\n <div className=\"card p-4 border-l-4 border-[var(--warning-border)]\">\r\n <h3 className=\"font-semibold text-[var(--warning-text)] flex items-center gap-2 mb-3\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n {t('dashboard.approachingBreach')} ({approachingBreach.length})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {approachingBreach.slice(0, 5).map((ticket) => (\r\n <button\r\n type=\"button\"\r\n key={ticket.id}\r\n className=\"w-full flex items-center justify-between p-2 bg-[var(--warning-bg)] rounded cursor-pointer hover:opacity-80 text-left\"\r\n onClick={() => navigate(`/support/tickets/${ticket.ticketId}`)}\r\n >\r\n <div>\r\n <span className=\"font-mono text-sm\">{ticket.ticketNumber}</span>\r\n <span className=\"ml-2 text-sm\">{ticket.ticketTitle}</span>\r\n </div>\r\n <span className=\"text-xs text-[var(--warning-text)] font-medium\">\r\n {Math.round(ticket.responseSlaPercentage)}% Response\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\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\">{t('dashboard.ticketsByStatus')}</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}</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-16 text-right text-sm font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Priority Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4\">{t('dashboard.activeTicketsByPriority')}</h3>\r\n <div className=\"space-y-3\">\r\n {priorityData.map((item) => {\r\n const total = priorityData.reduce((sum, p) => sum + p.count, 0);\r\n const percentage = total > 0 ? (item.count / total) * 100 : 0;\r\n return (\r\n <div key={item.priority} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{item.priority}</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: priorityColors[item.priority] || '#6b7280',\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-16 text-right text-sm font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* SLA & Satisfaction Row */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* SLA Compliance */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4\">{t('dashboard.slaPerformance')}</h3>\r\n {slaCompliance && (\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 ${getComplianceColor(slaCompliance.compliancePercentage)}`}>\r\n {slaCompliance.compliancePercentage.toFixed(1)}%\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.complianceRate')}</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\">{slaCompliance.ticketsWithinSla}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.withinSla')}</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-[var(--error-text)]\">{slaCompliance.ticketsBreached}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.breached')}</div>\r\n </div>\r\n <div className=\"space-y-2 p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"flex justify-between text-sm\">\r\n <span>{t('dashboard.avgResponse')}:</span>\r\n <span className=\"font-medium\">{formatDuration(slaCompliance.averageResponseMinutes)}</span>\r\n </div>\r\n <div className=\"flex justify-between text-sm\">\r\n <span>{t('dashboard.avgResolution')}:</span>\r\n <span className=\"font-medium\">{formatDuration(slaCompliance.averageResolutionMinutes)}</span>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Satisfaction */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4\">{t('dashboard.customerSatisfaction')}</h3>\r\n {satisfaction && (\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 ${getRatingColor(satisfaction.averageRating)}`}>\r\n {satisfaction.averageRating.toFixed(1)}\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.averageRating')}</div>\r\n <div className=\"flex justify-center mt-1\">\r\n {[1, 2, 3, 4, 5].map((star) => (\r\n <Star\r\n key={star}\r\n className={`w-4 h-4 ${star <= Math.round(satisfaction.averageRating)\r\n ? 'text-[var(--warning-text)] fill-[var(--warning-text)]'\r\n : 'text-[var(--text-muted)]'\r\n }`}\r\n />\r\n ))}\r\n </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\">{satisfaction.totalResponses}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{t('dashboard.totalResponses')}</div>\r\n </div>\r\n <div className=\"col-span-2 p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-sm font-medium mb-2\">{t('dashboard.ratingDistribution')}</div>\r\n <div className=\"space-y-1\">\r\n {[5, 4, 3, 2, 1].map((rating) => {\r\n const count = satisfaction.ratingDistribution[rating] || 0;\r\n const percentage =\r\n satisfaction.totalResponses > 0\r\n ? (count / satisfaction.totalResponses) * 100\r\n : 0;\r\n return (\r\n <div key={rating} className=\"flex items-center gap-2 text-sm\">\r\n <span className=\"w-4\">{rating}</span>\r\n <Star className=\"w-3 h-3 text-[var(--warning-text)] fill-[var(--warning-text)]\" />\r\n <div className=\"flex-1 h-3 bg-[var(--bg-primary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full bg-[var(--warning-text)] rounded-full\"\r\n style={{ width: `${percentage}%` }}\r\n />\r\n </div>\r\n <span className=\"w-8 text-right text-xs\">{count}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n )}\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\">{t('dashboard.ticketTrends', { period })}</h3>\r\n <div className=\"h-64\">\r\n <TrendChart data={trends} t={t} />\r\n </div>\r\n </div>\r\n\r\n {/* Agent Workload */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Users className=\"w-5 h-5\" />\r\n {t('dashboard.agentWorkload')}\r\n </h3>\r\n {agentWorkload.length > 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\">{t('dashboard.agent')}</th>\r\n <th className=\"text-center p-3 font-medium\">{t('dashboard.total')}</th>\r\n <th className=\"text-center p-3 font-medium\">{t('dashboard.open')}</th>\r\n <th className=\"text-center p-3 font-medium\">{t('dashboard.inProgress')}</th>\r\n <th className=\"text-center p-3 font-medium\">{t('dashboard.onHold')}</th>\r\n <th className=\"text-left p-3 font-medium\">{t('dashboard.load')}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {agentWorkload.map((agent) => {\r\n const maxLoad = Math.max(...agentWorkload.map((a) => a.totalAssigned));\r\n const loadPercentage = maxLoad > 0 ? (agent.totalAssigned / maxLoad) * 100 : 0;\r\n return (\r\n <tr key={agent.userId} className=\"border-b border-[var(--border-color)]\">\r\n <td className=\"p-3\">\r\n <div className=\"font-medium\">{agent.name}</div>\r\n <div className=\"text-xs text-[var(--text-secondary)]\">{agent.email}</div>\r\n </td>\r\n <td className=\"text-center p-3 font-semibold\">{agent.totalAssigned}</td>\r\n <td className=\"text-center p-3\">\r\n <span className=\"px-2 py-1 bg-[var(--warning-bg)] text-[var(--warning-text)] rounded-[var(--radius-badge)] text-sm\">\r\n {agent.openCount}\r\n </span>\r\n </td>\r\n <td className=\"text-center p-3\">\r\n <span className=\"px-2 py-1 bg-[var(--info-bg)] text-[var(--info-text)] rounded-[var(--radius-badge)] text-sm\">\r\n {agent.inProgressCount}\r\n </span>\r\n </td>\r\n <td className=\"text-center p-3\">\r\n <span className=\"px-2 py-1 bg-[var(--warning-bg)] text-[var(--warning-text)] rounded-[var(--radius-badge)] text-sm\">\r\n {agent.onHoldCount}\r\n </span>\r\n </td>\r\n <td className=\"p-3 w-32\">\r\n <div className=\"h-2 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full bg-[var(--info-text)] rounded-full\"\r\n style={{ width: `${loadPercentage}%` }}\r\n />\r\n </div>\r\n </td>\r\n </tr>\r\n );\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 {t('dashboard.noAgentsAssigned')}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// KPI Card Component\r\nfunction KpiCard({\r\n title,\r\n value,\r\n icon,\r\n color,\r\n subtitle,\r\n trend,\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 trend?: { value: number; isUp: boolean };\r\n}) {\r\n const colorClasses = {\r\n blue: 'bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]',\r\n green: 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]',\r\n yellow: 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]',\r\n red: 'bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]',\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 {trend && (\r\n <div className={`flex items-center gap-1 mt-1 text-xs ${trend.isUp ? 'text-[var(--success-text)]' : 'text-[var(--error-text)]'}`}>\r\n {trend.isUp ? <ArrowUp className=\"w-3 h-3\" /> : <ArrowDown className=\"w-3 h-3\" />}\r\n {trend.value}%\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Simple Trend Chart Component\r\ntype TrendTFunction = ReturnType<typeof useTranslation>['t'];\r\n\r\nfunction TrendChart({ data, t }: { data: TrendDataDto[]; t: TrendTFunction }) {\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 {t('dashboard.noTrendData')}\r\n </div>\r\n );\r\n }\r\n\r\n const maxValue = Math.max(...data.flatMap((d) => [d.created, d.resolved]), 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-[var(--info-text)]\" />\r\n <span className=\"text-sm\">{t('dashboard.created')}</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-[var(--success-text)]\" />\r\n <span className=\"text-sm\">{t('dashboard.resolved')}</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-[var(--info-text)] rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{ height: `${(item.created / maxValue) * 100}%`, minHeight: item.created > 0 ? '4px' : '0' }}\r\n title={`Created: ${item.created}`}\r\n />\r\n <div\r\n className=\"flex-1 bg-[var(--success-text)] rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{ height: `${(item.resolved / maxValue) * 100}%`, minHeight: item.resolved > 0 ? '4px' : '0' }}\r\n title={`Resolved: ${item.resolved}`}\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()}</span>\r\n <span>{data.at(-1) && new Date(data.at(-1)!.date).toLocaleDateString()}</span>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Format duration helper\r\nfunction formatDuration(minutes: number): string {\r\n if (minutes < 60) return `${Math.round(minutes)}m`;\r\n const hours = Math.floor(minutes / 60);\r\n const mins = Math.round(minutes % 60);\r\n if (hours < 24) return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;\r\n const days = Math.floor(hours / 24);\r\n const remainingHours = hours % 24;\r\n return remainingHours > 0 ? `${days}d ${remainingHours}h` : `${days}d`;\r\n}\r\n"],"names":["priorityColors","statusColors","DashboardPage","t","useTranslation","navigate","useNavigate","hasPermission","useAuth","isGlpi","glpiBaseUrl","useTicketingProvider","currentTenant","useTenant","loading","setLoading","useState","refreshing","setRefreshing","period","setPeriod","canViewSla","overview","setOverview","statusData","setStatusData","priorityData","setPriorityData","agentWorkload","setAgentWorkload","trends","setTrends","satisfaction","setSatisfaction","slaCompliance","setSlaCompliance","breachedTickets","setBreachedTickets","approachingBreach","setApproachingBreach","glpiSyncStats","setGlpiSyncStats","syncing","setSyncing","loadData","useCallback","overviewRes","statusRes","priorityRes","workloadRes","trendsRes","satisfactionRes","slaRes","dashboardApi","syncStats","supportApi","breachedRes","approachingRes","slaApi","error","useEffect","handleRefresh","handleTriggerSync","ticketingApi","jsx","Loader2","getComplianceColor","percentage","getRatingColor","rating","jsxs","Breadcrumb","PageHeader","LayoutDashboard","Fragment","e","RefreshCw","Info","ExternalLink","KpiCard","Headphones","TrendingUp","Clock","CheckCircle","AlertTriangle","Star","XCircle","ticket","item","total","sum","s","p","formatDuration","star","count","TrendChart","Users","agent","maxLoad","a","loadPercentage","title","value","icon","color","subtitle","trend","colorClasses","ArrowUp","ArrowDown","data","maxValue","d","minutes","hours","mins","days","remainingHours"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),l=require("react"),M=require("react-i18next"),i=require("lucide-react"),d=require("./index-
|
|
2
|
-
//# sourceMappingURL=EscalationConfigPage
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),l=require("react"),M=require("react-i18next"),i=require("lucide-react"),d=require("./index-IgLVXPg8.js"),x=["Supervisor","Manager","Director"],b={None:"bg-[var(--bg-secondary)] text-[var(--text-secondary)]",Supervisor:"bg-[var(--info-bg)] text-[var(--info-text)]",Manager:"bg-[var(--warning-bg)] text-[var(--warning-text)]",Director:"bg-[var(--error-bg)] text-[var(--error-text)]"},$={ResponseBreach:i.Clock,ResolutionBreach:i.AlertTriangle,ManualRequest:i.Bell};function T(){const{t:a}=M.useTranslation("support"),[y,f]=l.useState(!0),[p,v]=l.useState(!1),[N,R]=l.useState([]),[g,w]=l.useState([]),[m,h]=l.useState(null),[c,o]=l.useState({delayAfterBreachMinutes:0,notifyRoleId:null,isActive:!0}),u=l.useCallback(async()=>{try{f(!0);const[s,t]=await Promise.all([d.slaApi.getEscalationRules(),d.api.get("/api/administration/permissions/roles")]);R(s),w(t)}catch(s){console.error("Failed to load escalation data:",s)}finally{f(!1)}},[]);l.useEffect(()=>{u()},[u]);const A=s=>{h(s),o({delayAfterBreachMinutes:s.delayAfterBreachMinutes,notifyRoleId:s.notifyRoleId,isActive:s.isActive})},k=()=>{h(null),o({delayAfterBreachMinutes:0,notifyRoleId:null,isActive:!0})},C=async()=>{if(m)try{v(!0),await d.api.put(`/api/support/sla/escalation-rules/${m.id}`,c),u(),h(null)}catch(s){console.error("Failed to save escalation rule:",s)}finally{v(!1)}},S=s=>{if(s===0)return a("escalation.delay.immediate");if(s<60)return`${s} min`;const t=Math.floor(s/60),n=s%60;return n===0?`${t}h`:`${t}h ${n}min`},B=s=>s?g.find(n=>n.id===s)?.name||a("escalation.unknownRole"):a("escalation.notConfigured"),E=N.reduce((s,t)=>(s[t.level]||(s[t.level]=[]),s[t.level].push(t),s),{});return e.jsxs("div",{className:"space-y-6",children:[e.jsx(d.Breadcrumb,{items:[{label:a("title","Support"),href:"/support"},{label:a("escalation.title")}]}),e.jsx("div",{className:"flex items-center justify-between",children:e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl font-bold flex items-center gap-2",children:[e.jsx(i.TrendingUp,{className:"w-6 h-6"}),a("escalation.title")]}),e.jsx("p",{className:"text-[var(--text-secondary)]",children:a("escalation.subtitle")})]})}),y?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx(i.Loader2,{className:"w-8 h-8 animate-spin text-[var(--color-primary-600)]"})}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"card p-6 bg-[var(--bg-secondary)]",children:[e.jsxs("h3",{className:"text-lg font-semibold mb-4 flex items-center gap-2",children:[e.jsx(i.Users,{className:"w-5 h-5"}),a("escalation.hierarchy")]}),e.jsx("div",{className:"flex items-center gap-4",children:x.map((s,t)=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:`px-4 py-2 rounded-[var(--radius-badge)] font-medium ${b[s]}`,children:a(`escalation.levels.${s}`)}),t<2&&e.jsx("div",{className:"text-[var(--text-secondary)]",children:"→"})]},s))}),e.jsx("p",{className:"mt-4 text-sm text-[var(--text-secondary)]",children:a("escalation.hierarchyDescription")})]}),e.jsx("div",{className:"space-y-6",children:Object.entries(E).filter(([s])=>s!=="None").sort((s,t)=>x.indexOf(s[0])-x.indexOf(t[0])).map(([s,t])=>e.jsxs("div",{className:"card overflow-hidden",children:[e.jsx("div",{className:`px-6 py-3 ${b[s]} border-b border-[var(--border-color)]`,children:e.jsx("h3",{className:"font-semibold",children:a("escalation.level",{number:x.indexOf(s)+1,label:a(`escalation.levels.${s}`)})})}),e.jsx("div",{className:"divide-y divide-[var(--border-color)]",children:t.map(n=>{const j=$[n.triggerType]||i.AlertTriangle,I=m?.id===n.id;return e.jsx("div",{className:`p-4 ${n.isActive?"":"opacity-60"}`,children:I?e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(j,{className:"w-5 h-5"}),e.jsx("span",{className:"font-medium",children:a(`escalation.triggerTypes.${n.triggerType}`)})]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",children:a("escalation.form.delayAfterBreach")}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"number",min:"0",value:c.delayAfterBreachMinutes,onChange:r=>o({...c,delayAfterBreachMinutes:parseInt(r.target.value)||0}),className:"input w-24"}),e.jsx("span",{className:"text-sm text-[var(--text-secondary)]",children:a("escalation.form.minutes")})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",children:a("escalation.form.notifyRole")}),e.jsxs("select",{value:c.notifyRoleId||"",onChange:r=>o({...c,notifyRoleId:r.target.value||null}),className:"input w-full",children:[e.jsx("option",{value:"",children:a("escalation.form.none")}),g.map(r=>e.jsx("option",{value:r.id,children:r.name},r.id))]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",children:a("escalation.form.status")}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:c.isActive,onChange:r=>o({...c,isActive:r.target.checked}),className:"rounded border-[var(--border-color)]"}),e.jsx("span",{className:"text-sm",children:a("escalation.form.active")})]})]})]}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs("button",{onClick:k,className:"btn btn-secondary flex items-center gap-1",children:[e.jsx(i.X,{className:"w-4 h-4"}),a("common:actions.cancel")]}),e.jsxs("button",{onClick:C,disabled:p,className:"btn btn-primary flex items-center gap-1",children:[p?e.jsx(i.Loader2,{className:"w-4 h-4 animate-spin"}):e.jsx(i.Check,{className:"w-4 h-4"}),a("common:actions.save")]})]})]}):e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(j,{className:"w-5 h-5 text-[var(--text-secondary)]"}),e.jsx("span",{className:"font-medium",children:a(`escalation.triggerTypes.${n.triggerType}`)}),n.isSystemDefault?e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-[var(--bg-secondary)] text-[var(--text-secondary)] border border-[var(--border-color)]",children:a("escalation.scope.system")}):e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]",children:a("escalation.scope.tenant")})]}),e.jsxs("div",{className:"text-sm text-[var(--text-secondary)]",children:[e.jsx(i.Clock,{className:"w-4 h-4 inline mr-1"}),S(n.delayAfterBreachMinutes)]}),e.jsxs("div",{className:"text-sm text-[var(--text-secondary)]",children:[e.jsx(i.Bell,{className:"w-4 h-4 inline mr-1"}),B(n.notifyRoleId)]}),!n.isActive&&e.jsx("span",{className:"text-xs px-2 py-0.5 rounded bg-[var(--bg-secondary)] text-[var(--text-secondary)]",children:a("escalation.disabled")})]}),e.jsxs("button",{onClick:()=>A(n),className:"btn btn-secondary btn-sm flex items-center gap-1",children:[e.jsx(i.Edit,{className:"w-4 h-4"}),a("common:actions.edit")]})]})},n.id)})})]},s))}),e.jsxs("div",{className:"card p-6",children:[e.jsx("h3",{className:"text-lg font-semibold mb-4",children:a("escalation.howItWorks.title")}),e.jsx("div",{className:"space-y-4 text-sm text-[var(--text-secondary)]",children:[1,2,3,4].map(s=>e.jsxs("div",{className:"flex gap-3",children:[e.jsx("div",{className:"w-6 h-6 rounded-full bg-[var(--info-bg)] text-[var(--info-text)] flex items-center justify-center text-xs font-bold flex-shrink-0",children:s}),e.jsx("p",{children:a(`escalation.howItWorks.step${s}`)})]},s))})]})]})]})}exports.EscalationConfigPage=T;
|
|
2
|
+
//# sourceMappingURL=EscalationConfigPage--7lgZ0kJ.js.map
|
package/dist/chunks/{EscalationConfigPage-CdzAbnGy.js.map → EscalationConfigPage--7lgZ0kJ.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EscalationConfigPage-CdzAbnGy.js","sources":["../../src/pages/platform/support/EscalationConfigPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n TrendingUp,\r\n Loader2,\r\n AlertTriangle,\r\n Bell,\r\n Clock,\r\n Users,\r\n Edit,\r\n Check,\r\n X,\r\n} from 'lucide-react';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { slaApi, type EscalationRuleDto } from '@/services/api/supportApi';\r\nimport { api } from '@/services/api/apiClient';\r\n\r\ninterface RoleDto {\r\n id: string;\r\n name: string;\r\n description: string | null;\r\n}\r\n\r\nconst LEVEL_ORDER = ['Supervisor', 'Manager', 'Director'] as const;\r\n\r\nconst levelColors: Record<string, string> = {\r\n None: 'bg-[var(--bg-secondary)] text-[var(--text-secondary)]',\r\n Supervisor: 'bg-[var(--info-bg)] text-[var(--info-text)]',\r\n Manager: 'bg-[var(--warning-bg)] text-[var(--warning-text)]',\r\n Director: 'bg-[var(--error-bg)] text-[var(--error-text)]',\r\n};\r\n\r\nconst triggerTypeIcons: Record<string, typeof AlertTriangle> = {\r\n ResponseBreach: Clock,\r\n ResolutionBreach: AlertTriangle,\r\n ManualRequest: Bell,\r\n};\r\n\r\nexport function EscalationConfigPage(): ReactElement {\r\n const { t } = useTranslation('support');\r\n const [loading, setLoading] = useState(true);\r\n const [saving, setSaving] = useState(false);\r\n const [rules, setRules] = useState<EscalationRuleDto[]>([]);\r\n const [roles, setRoles] = useState<RoleDto[]>([]);\r\n const [editingRule, setEditingRule] = useState<EscalationRuleDto | null>(null);\r\n const [editForm, setEditForm] = useState<{\r\n delayAfterBreachMinutes: number;\r\n notifyRoleId: string | null;\r\n isActive: boolean;\r\n }>({ delayAfterBreachMinutes: 0, notifyRoleId: null, isActive: true });\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n const [rulesRes, rolesRes] = await Promise.all([\r\n slaApi.getEscalationRules(),\r\n api.get<RoleDto[]>('/api/administration/permissions/roles'),\r\n ]);\r\n setRules(rulesRes);\r\n setRoles(rolesRes);\r\n } catch (error) {\r\n console.error('Failed to load escalation data:', error);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n const handleEdit = (rule: EscalationRuleDto) => {\r\n setEditingRule(rule);\r\n setEditForm({\r\n delayAfterBreachMinutes: rule.delayAfterBreachMinutes,\r\n notifyRoleId: rule.notifyRoleId,\r\n isActive: rule.isActive,\r\n });\r\n };\r\n\r\n const handleCancelEdit = () => {\r\n setEditingRule(null);\r\n setEditForm({ delayAfterBreachMinutes: 0, notifyRoleId: null, isActive: true });\r\n };\r\n\r\n const handleSave = async () => {\r\n if (!editingRule) return;\r\n\r\n try {\r\n setSaving(true);\r\n await api.put(`/api/support/sla/escalation-rules/${editingRule.id}`, editForm);\r\n loadData();\r\n setEditingRule(null);\r\n } catch (error) {\r\n console.error('Failed to save escalation rule:', error);\r\n } finally {\r\n setSaving(false);\r\n }\r\n };\r\n\r\n const formatDelay = (minutes: number) => {\r\n if (minutes === 0) return t('escalation.delay.immediate');\r\n if (minutes < 60) return `${minutes} min`;\r\n const hours = Math.floor(minutes / 60);\r\n const remainingMinutes = minutes % 60;\r\n if (remainingMinutes === 0) return `${hours}h`;\r\n return `${hours}h ${remainingMinutes}min`;\r\n };\r\n\r\n const getRoleName = (roleId: string | null) => {\r\n if (!roleId) return t('escalation.notConfigured');\r\n const role = roles.find((r) => r.id === roleId);\r\n return role?.name || t('escalation.unknownRole');\r\n };\r\n\r\n const groupedRules = rules.reduce((acc, rule) => {\r\n if (!acc[rule.level]) {\r\n acc[rule.level] = [];\r\n }\r\n acc[rule.level].push(rule);\r\n return acc;\r\n }, {} as Record<string, EscalationRuleDto[]>);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('title', 'Support'), href: '/support' },\r\n { label: t('escalation.title') }\r\n ]}\r\n />\r\n\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold flex items-center gap-2\">\r\n <TrendingUp className=\"w-6 h-6\" />\r\n {t('escalation.title')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n {t('escalation.subtitle')}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {loading ? (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-primary-600)]\" />\r\n </div>\r\n ) : (\r\n <>\r\n <div className=\"card p-6 bg-[var(--bg-secondary)]\">\r\n <h3 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Users className=\"w-5 h-5\" />\r\n {t('escalation.hierarchy')}\r\n </h3>\r\n <div className=\"flex items-center gap-4\">\r\n {LEVEL_ORDER.map((level, index) => (\r\n <div key={level} className=\"flex items-center gap-2\">\r\n <div className={`px-4 py-2 rounded-[var(--radius-badge)] font-medium ${levelColors[level]}`}>\r\n {t(`escalation.levels.${level}`)}\r\n </div>\r\n {index < 2 && (\r\n <div className=\"text-[var(--text-secondary)]\">→</div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n <p className=\"mt-4 text-sm text-[var(--text-secondary)]\">\r\n {t('escalation.hierarchyDescription')}\r\n </p>\r\n </div>\r\n\r\n <div className=\"space-y-6\">\r\n {Object.entries(groupedRules)\r\n .filter(([level]) => level !== 'None')\r\n .sort((a, b) => {\r\n return LEVEL_ORDER.indexOf(a[0] as typeof LEVEL_ORDER[number]) - LEVEL_ORDER.indexOf(b[0] as typeof LEVEL_ORDER[number]);\r\n })\r\n .map(([level, levelRules]) => (\r\n <div key={level} className=\"card overflow-hidden\">\r\n <div className={`px-6 py-3 ${levelColors[level]} border-b border-[var(--border-color)]`}>\r\n <h3 className=\"font-semibold\">\r\n {t('escalation.level', {\r\n number: LEVEL_ORDER.indexOf(level as typeof LEVEL_ORDER[number]) + 1,\r\n label: t(`escalation.levels.${level}`),\r\n })}\r\n </h3>\r\n </div>\r\n <div className=\"divide-y divide-[var(--border-color)]\">\r\n {levelRules.map((rule) => {\r\n const TriggerIcon = triggerTypeIcons[rule.triggerType] || AlertTriangle;\r\n const isEditing = editingRule?.id === rule.id;\r\n\r\n return (\r\n <div\r\n key={rule.id}\r\n className={`p-4 ${!rule.isActive ? 'opacity-60' : ''}`}\r\n >\r\n {isEditing ? (\r\n <div className=\"space-y-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <TriggerIcon className=\"w-5 h-5\" />\r\n <span className=\"font-medium\">\r\n {t(`escalation.triggerTypes.${rule.triggerType}`)}\r\n </span>\r\n </div>\r\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\r\n <div>\r\n <label className=\"block text-sm font-medium mb-1\">\r\n {t('escalation.form.delayAfterBreach')}\r\n </label>\r\n <div className=\"flex items-center gap-2\">\r\n <input\r\n type=\"number\"\r\n min=\"0\"\r\n value={editForm.delayAfterBreachMinutes}\r\n onChange={(e) =>\r\n setEditForm({\r\n ...editForm,\r\n delayAfterBreachMinutes: parseInt(e.target.value) || 0,\r\n })\r\n }\r\n className=\"input w-24\"\r\n />\r\n <span className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('escalation.form.minutes')}\r\n </span>\r\n </div>\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium mb-1\">\r\n {t('escalation.form.notifyRole')}\r\n </label>\r\n <select\r\n value={editForm.notifyRoleId || ''}\r\n onChange={(e) =>\r\n setEditForm({\r\n ...editForm,\r\n notifyRoleId: e.target.value || null,\r\n })\r\n }\r\n className=\"input w-full\"\r\n >\r\n <option value=\"\">{t('escalation.form.none')}</option>\r\n {roles.map((role) => (\r\n <option key={role.id} value={role.id}>\r\n {role.name}\r\n </option>\r\n ))}\r\n </select>\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium mb-1\">\r\n {t('escalation.form.status')}\r\n </label>\r\n <label className=\"flex items-center gap-2\">\r\n <input\r\n type=\"checkbox\"\r\n checked={editForm.isActive}\r\n onChange={(e) =>\r\n setEditForm({\r\n ...editForm,\r\n isActive: e.target.checked,\r\n })\r\n }\r\n className=\"rounded border-[var(--border-color)]\"\r\n />\r\n <span className=\"text-sm\">{t('escalation.form.active')}</span>\r\n </label>\r\n </div>\r\n </div>\r\n <div className=\"flex justify-end gap-2\">\r\n <button\r\n onClick={handleCancelEdit}\r\n className=\"btn btn-secondary flex items-center gap-1\"\r\n >\r\n <X className=\"w-4 h-4\" />\r\n {t('common:actions.cancel')}\r\n </button>\r\n <button\r\n onClick={handleSave}\r\n disabled={saving}\r\n className=\"btn btn-primary flex items-center gap-1\"\r\n >\r\n {saving ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <Check className=\"w-4 h-4\" />\r\n )}\r\n {t('common:actions.save')}\r\n </button>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <TriggerIcon className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n <span className=\"font-medium\">\r\n {t(`escalation.triggerTypes.${rule.triggerType}`)}\r\n </span>\r\n {rule.isSystemDefault ? (\r\n <span className=\"text-[10px] px-1.5 py-0.5 rounded bg-[var(--bg-secondary)] text-[var(--text-secondary)] border border-[var(--border-color)]\">\r\n {t('escalation.scope.system')}\r\n </span>\r\n ) : (\r\n <span className=\"text-[10px] px-1.5 py-0.5 rounded bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]\">\r\n {t('escalation.scope.tenant')}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n <Clock className=\"w-4 h-4 inline mr-1\" />\r\n {formatDelay(rule.delayAfterBreachMinutes)}\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n <Bell className=\"w-4 h-4 inline mr-1\" />\r\n {getRoleName(rule.notifyRoleId)}\r\n </div>\r\n {!rule.isActive && (\r\n <span className=\"text-xs px-2 py-0.5 rounded bg-[var(--bg-secondary)] text-[var(--text-secondary)]\">\r\n {t('escalation.disabled')}\r\n </span>\r\n )}\r\n </div>\r\n <button\r\n onClick={() => handleEdit(rule)}\r\n className=\"btn btn-secondary btn-sm flex items-center gap-1\"\r\n >\r\n <Edit className=\"w-4 h-4\" />\r\n {t('common:actions.edit')}\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n\r\n <div className=\"card p-6\">\r\n <h3 className=\"text-lg font-semibold mb-4\">{t('escalation.howItWorks.title')}</h3>\r\n <div className=\"space-y-4 text-sm text-[var(--text-secondary)]\">\r\n {[1, 2, 3, 4].map((step) => (\r\n <div key={step} className=\"flex gap-3\">\r\n <div className=\"w-6 h-6 rounded-full bg-[var(--info-bg)] text-[var(--info-text)] flex items-center justify-center text-xs font-bold flex-shrink-0\">\r\n {step}\r\n </div>\r\n <p>{t(`escalation.howItWorks.step${step}`)}</p>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n );\r\n}\r\n"],"names":["LEVEL_ORDER","levelColors","triggerTypeIcons","Clock","AlertTriangle","Bell","EscalationConfigPage","t","useTranslation","loading","setLoading","useState","saving","setSaving","rules","setRules","roles","setRoles","editingRule","setEditingRule","editForm","setEditForm","loadData","useCallback","rulesRes","rolesRes","slaApi","api","error","useEffect","handleEdit","rule","handleCancelEdit","handleSave","formatDelay","minutes","hours","remainingMinutes","getRoleName","roleId","r","groupedRules","acc","jsxs","jsx","Breadcrumb","TrendingUp","Loader2","Fragment","Users","level","index","a","b","levelRules","TriggerIcon","isEditing","e","role","X","Check","Edit","step"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EscalationConfigPage--7lgZ0kJ.js","sources":["../../src/pages/platform/support/EscalationConfigPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n TrendingUp,\r\n Loader2,\r\n AlertTriangle,\r\n Bell,\r\n Clock,\r\n Users,\r\n Edit,\r\n Check,\r\n X,\r\n} from 'lucide-react';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { slaApi, type EscalationRuleDto } from '@/services/api/supportApi';\r\nimport { api } from '@/services/api/apiClient';\r\n\r\ninterface RoleDto {\r\n id: string;\r\n name: string;\r\n description: string | null;\r\n}\r\n\r\nconst LEVEL_ORDER = ['Supervisor', 'Manager', 'Director'] as const;\r\n\r\nconst levelColors: Record<string, string> = {\r\n None: 'bg-[var(--bg-secondary)] text-[var(--text-secondary)]',\r\n Supervisor: 'bg-[var(--info-bg)] text-[var(--info-text)]',\r\n Manager: 'bg-[var(--warning-bg)] text-[var(--warning-text)]',\r\n Director: 'bg-[var(--error-bg)] text-[var(--error-text)]',\r\n};\r\n\r\nconst triggerTypeIcons: Record<string, typeof AlertTriangle> = {\r\n ResponseBreach: Clock,\r\n ResolutionBreach: AlertTriangle,\r\n ManualRequest: Bell,\r\n};\r\n\r\nexport function EscalationConfigPage(): ReactElement {\r\n const { t } = useTranslation('support');\r\n const [loading, setLoading] = useState(true);\r\n const [saving, setSaving] = useState(false);\r\n const [rules, setRules] = useState<EscalationRuleDto[]>([]);\r\n const [roles, setRoles] = useState<RoleDto[]>([]);\r\n const [editingRule, setEditingRule] = useState<EscalationRuleDto | null>(null);\r\n const [editForm, setEditForm] = useState<{\r\n delayAfterBreachMinutes: number;\r\n notifyRoleId: string | null;\r\n isActive: boolean;\r\n }>({ delayAfterBreachMinutes: 0, notifyRoleId: null, isActive: true });\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n const [rulesRes, rolesRes] = await Promise.all([\r\n slaApi.getEscalationRules(),\r\n api.get<RoleDto[]>('/api/administration/permissions/roles'),\r\n ]);\r\n setRules(rulesRes);\r\n setRoles(rolesRes);\r\n } catch (error) {\r\n console.error('Failed to load escalation data:', error);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n const handleEdit = (rule: EscalationRuleDto) => {\r\n setEditingRule(rule);\r\n setEditForm({\r\n delayAfterBreachMinutes: rule.delayAfterBreachMinutes,\r\n notifyRoleId: rule.notifyRoleId,\r\n isActive: rule.isActive,\r\n });\r\n };\r\n\r\n const handleCancelEdit = () => {\r\n setEditingRule(null);\r\n setEditForm({ delayAfterBreachMinutes: 0, notifyRoleId: null, isActive: true });\r\n };\r\n\r\n const handleSave = async () => {\r\n if (!editingRule) return;\r\n\r\n try {\r\n setSaving(true);\r\n await api.put(`/api/support/sla/escalation-rules/${editingRule.id}`, editForm);\r\n loadData();\r\n setEditingRule(null);\r\n } catch (error) {\r\n console.error('Failed to save escalation rule:', error);\r\n } finally {\r\n setSaving(false);\r\n }\r\n };\r\n\r\n const formatDelay = (minutes: number) => {\r\n if (minutes === 0) return t('escalation.delay.immediate');\r\n if (minutes < 60) return `${minutes} min`;\r\n const hours = Math.floor(minutes / 60);\r\n const remainingMinutes = minutes % 60;\r\n if (remainingMinutes === 0) return `${hours}h`;\r\n return `${hours}h ${remainingMinutes}min`;\r\n };\r\n\r\n const getRoleName = (roleId: string | null) => {\r\n if (!roleId) return t('escalation.notConfigured');\r\n const role = roles.find((r) => r.id === roleId);\r\n return role?.name || t('escalation.unknownRole');\r\n };\r\n\r\n const groupedRules = rules.reduce((acc, rule) => {\r\n if (!acc[rule.level]) {\r\n acc[rule.level] = [];\r\n }\r\n acc[rule.level].push(rule);\r\n return acc;\r\n }, {} as Record<string, EscalationRuleDto[]>);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('title', 'Support'), href: '/support' },\r\n { label: t('escalation.title') }\r\n ]}\r\n />\r\n\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold flex items-center gap-2\">\r\n <TrendingUp className=\"w-6 h-6\" />\r\n {t('escalation.title')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)]\">\r\n {t('escalation.subtitle')}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {loading ? (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-primary-600)]\" />\r\n </div>\r\n ) : (\r\n <>\r\n <div className=\"card p-6 bg-[var(--bg-secondary)]\">\r\n <h3 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Users className=\"w-5 h-5\" />\r\n {t('escalation.hierarchy')}\r\n </h3>\r\n <div className=\"flex items-center gap-4\">\r\n {LEVEL_ORDER.map((level, index) => (\r\n <div key={level} className=\"flex items-center gap-2\">\r\n <div className={`px-4 py-2 rounded-[var(--radius-badge)] font-medium ${levelColors[level]}`}>\r\n {t(`escalation.levels.${level}`)}\r\n </div>\r\n {index < 2 && (\r\n <div className=\"text-[var(--text-secondary)]\">→</div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n <p className=\"mt-4 text-sm text-[var(--text-secondary)]\">\r\n {t('escalation.hierarchyDescription')}\r\n </p>\r\n </div>\r\n\r\n <div className=\"space-y-6\">\r\n {Object.entries(groupedRules)\r\n .filter(([level]) => level !== 'None')\r\n .sort((a, b) => {\r\n return LEVEL_ORDER.indexOf(a[0] as typeof LEVEL_ORDER[number]) - LEVEL_ORDER.indexOf(b[0] as typeof LEVEL_ORDER[number]);\r\n })\r\n .map(([level, levelRules]) => (\r\n <div key={level} className=\"card overflow-hidden\">\r\n <div className={`px-6 py-3 ${levelColors[level]} border-b border-[var(--border-color)]`}>\r\n <h3 className=\"font-semibold\">\r\n {t('escalation.level', {\r\n number: LEVEL_ORDER.indexOf(level as typeof LEVEL_ORDER[number]) + 1,\r\n label: t(`escalation.levels.${level}`),\r\n })}\r\n </h3>\r\n </div>\r\n <div className=\"divide-y divide-[var(--border-color)]\">\r\n {levelRules.map((rule) => {\r\n const TriggerIcon = triggerTypeIcons[rule.triggerType] || AlertTriangle;\r\n const isEditing = editingRule?.id === rule.id;\r\n\r\n return (\r\n <div\r\n key={rule.id}\r\n className={`p-4 ${!rule.isActive ? 'opacity-60' : ''}`}\r\n >\r\n {isEditing ? (\r\n <div className=\"space-y-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <TriggerIcon className=\"w-5 h-5\" />\r\n <span className=\"font-medium\">\r\n {t(`escalation.triggerTypes.${rule.triggerType}`)}\r\n </span>\r\n </div>\r\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\r\n <div>\r\n <label className=\"block text-sm font-medium mb-1\">\r\n {t('escalation.form.delayAfterBreach')}\r\n </label>\r\n <div className=\"flex items-center gap-2\">\r\n <input\r\n type=\"number\"\r\n min=\"0\"\r\n value={editForm.delayAfterBreachMinutes}\r\n onChange={(e) =>\r\n setEditForm({\r\n ...editForm,\r\n delayAfterBreachMinutes: parseInt(e.target.value) || 0,\r\n })\r\n }\r\n className=\"input w-24\"\r\n />\r\n <span className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('escalation.form.minutes')}\r\n </span>\r\n </div>\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium mb-1\">\r\n {t('escalation.form.notifyRole')}\r\n </label>\r\n <select\r\n value={editForm.notifyRoleId || ''}\r\n onChange={(e) =>\r\n setEditForm({\r\n ...editForm,\r\n notifyRoleId: e.target.value || null,\r\n })\r\n }\r\n className=\"input w-full\"\r\n >\r\n <option value=\"\">{t('escalation.form.none')}</option>\r\n {roles.map((role) => (\r\n <option key={role.id} value={role.id}>\r\n {role.name}\r\n </option>\r\n ))}\r\n </select>\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium mb-1\">\r\n {t('escalation.form.status')}\r\n </label>\r\n <label className=\"flex items-center gap-2\">\r\n <input\r\n type=\"checkbox\"\r\n checked={editForm.isActive}\r\n onChange={(e) =>\r\n setEditForm({\r\n ...editForm,\r\n isActive: e.target.checked,\r\n })\r\n }\r\n className=\"rounded border-[var(--border-color)]\"\r\n />\r\n <span className=\"text-sm\">{t('escalation.form.active')}</span>\r\n </label>\r\n </div>\r\n </div>\r\n <div className=\"flex justify-end gap-2\">\r\n <button\r\n onClick={handleCancelEdit}\r\n className=\"btn btn-secondary flex items-center gap-1\"\r\n >\r\n <X className=\"w-4 h-4\" />\r\n {t('common:actions.cancel')}\r\n </button>\r\n <button\r\n onClick={handleSave}\r\n disabled={saving}\r\n className=\"btn btn-primary flex items-center gap-1\"\r\n >\r\n {saving ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <Check className=\"w-4 h-4\" />\r\n )}\r\n {t('common:actions.save')}\r\n </button>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <TriggerIcon className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n <span className=\"font-medium\">\r\n {t(`escalation.triggerTypes.${rule.triggerType}`)}\r\n </span>\r\n {rule.isSystemDefault ? (\r\n <span className=\"text-[10px] px-1.5 py-0.5 rounded bg-[var(--bg-secondary)] text-[var(--text-secondary)] border border-[var(--border-color)]\">\r\n {t('escalation.scope.system')}\r\n </span>\r\n ) : (\r\n <span className=\"text-[10px] px-1.5 py-0.5 rounded bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]\">\r\n {t('escalation.scope.tenant')}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n <Clock className=\"w-4 h-4 inline mr-1\" />\r\n {formatDelay(rule.delayAfterBreachMinutes)}\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n <Bell className=\"w-4 h-4 inline mr-1\" />\r\n {getRoleName(rule.notifyRoleId)}\r\n </div>\r\n {!rule.isActive && (\r\n <span className=\"text-xs px-2 py-0.5 rounded bg-[var(--bg-secondary)] text-[var(--text-secondary)]\">\r\n {t('escalation.disabled')}\r\n </span>\r\n )}\r\n </div>\r\n <button\r\n onClick={() => handleEdit(rule)}\r\n className=\"btn btn-secondary btn-sm flex items-center gap-1\"\r\n >\r\n <Edit className=\"w-4 h-4\" />\r\n {t('common:actions.edit')}\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n\r\n <div className=\"card p-6\">\r\n <h3 className=\"text-lg font-semibold mb-4\">{t('escalation.howItWorks.title')}</h3>\r\n <div className=\"space-y-4 text-sm text-[var(--text-secondary)]\">\r\n {[1, 2, 3, 4].map((step) => (\r\n <div key={step} className=\"flex gap-3\">\r\n <div className=\"w-6 h-6 rounded-full bg-[var(--info-bg)] text-[var(--info-text)] flex items-center justify-center text-xs font-bold flex-shrink-0\">\r\n {step}\r\n </div>\r\n <p>{t(`escalation.howItWorks.step${step}`)}</p>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n );\r\n}\r\n"],"names":["LEVEL_ORDER","levelColors","triggerTypeIcons","Clock","AlertTriangle","Bell","EscalationConfigPage","t","useTranslation","loading","setLoading","useState","saving","setSaving","rules","setRules","roles","setRoles","editingRule","setEditingRule","editForm","setEditForm","loadData","useCallback","rulesRes","rolesRes","slaApi","api","error","useEffect","handleEdit","rule","handleCancelEdit","handleSave","formatDelay","minutes","hours","remainingMinutes","getRoleName","roleId","r","groupedRules","acc","jsxs","jsx","Breadcrumb","TrendingUp","Loader2","Fragment","Users","level","index","a","b","levelRules","TriggerIcon","isEditing","e","role","X","Check","Edit","step"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsxs as s, jsx as e, Fragment as F } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState as c, useCallback as O, useEffect as L } from "react";
|
|
3
3
|
import { useTranslation as P } from "react-i18next";
|
|
4
4
|
import { TrendingUp as U, Loader2 as b, Users as W, Bell as w, AlertTriangle as R, Clock as A, X as q, Check as V, Edit as X } from "lucide-react";
|
|
5
|
-
import { Z, i as y, B as _ } from "./index-
|
|
5
|
+
import { Z, i as y, B as _ } from "./index-lpIzhufD.js";
|
|
6
6
|
const d = ["Supervisor", "Manager", "Director"], N = {
|
|
7
7
|
None: "bg-[var(--bg-secondary)] text-[var(--text-secondary)]",
|
|
8
8
|
Supervisor: "bg-[var(--info-bg)] text-[var(--info-text)]",
|
|
@@ -228,4 +228,4 @@ function Y() {
|
|
|
228
228
|
export {
|
|
229
229
|
Y as EscalationConfigPage
|
|
230
230
|
};
|
|
231
|
-
//# sourceMappingURL=EscalationConfigPage-
|
|
231
|
+
//# sourceMappingURL=EscalationConfigPage-DPyiBcqV.js.map
|