@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":"index-DCcl7Qof.js","sources":["../../src/pages/platform/administration/entra/EntraDashboardPage.tsx","../../src/pages/platform/administration/entra/EntraGroupsPage.tsx","../../src/pages/platform/administration/entra/EntraUsersPage.tsx","../../src/pages/platform/administration/entra/EntraConflictsPage.tsx","../../src/pages/platform/administration/entra/EntraSettingsPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useAuth } from '@/contexts/AuthContext';\r\nimport { Tooltip } from '@/components/ui/Tooltip';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport type { LucideIcon } from 'lucide-react';\r\nimport {\r\n Cloud,\r\n RefreshCw,\r\n Loader2,\r\n AlertTriangle,\r\n CheckCircle,\r\n XCircle,\r\n Clock,\r\n Users,\r\n Building2,\r\n Link2,\r\n Play,\r\n AlertCircle,\r\n Calendar,\r\n Database,\r\n} from 'lucide-react';\r\nimport {\r\n entraApi,\r\n type EntraSyncStatusDto,\r\n type EntraSyncResultDto,\r\n} from '@/services/api/entraApi';\r\n\r\n// ============================================\r\n// Sync Status Card Component\r\n// ============================================\r\n\r\ninterface SyncStatusCardProps {\r\n readonly resourceType: string;\r\n readonly icon: LucideIcon;\r\n readonly status: string;\r\n readonly lastFullSyncAt: string | null;\r\n readonly lastDeltaSyncAt: string | null;\r\n readonly totalItemsSynced: number;\r\n readonly pendingConflicts: number;\r\n readonly lastError: string | null;\r\n readonly syncing: boolean;\r\n readonly canSync: boolean;\r\n readonly onSync: () => void;\r\n readonly formatDate: (date: string | null) => string;\r\n readonly t: (key: string, options?: Record<string, unknown>) => string;\r\n}\r\n\r\nfunction SyncStatusCard({\r\n resourceType,\r\n icon: Icon,\r\n status,\r\n lastFullSyncAt,\r\n lastDeltaSyncAt,\r\n totalItemsSynced,\r\n pendingConflicts,\r\n lastError,\r\n syncing,\r\n canSync,\r\n onSync,\r\n formatDate,\r\n t,\r\n}: SyncStatusCardProps) {\r\n const getStatusConfig = () => {\r\n switch (status) {\r\n case 'Success':\r\n return {\r\n icon: CheckCircle,\r\n color: 'text-[var(--success-text)]',\r\n bg: 'bg-[var(--success-bg)]',\r\n label: t('common:success'),\r\n };\r\n case 'Failed':\r\n return {\r\n icon: XCircle,\r\n color: 'text-[var(--error-text)]',\r\n bg: 'bg-[var(--error-bg)]',\r\n label: t('common:failed'),\r\n };\r\n case 'Running':\r\n return {\r\n icon: Loader2,\r\n color: 'text-[var(--color-accent-500)]',\r\n bg: 'bg-[var(--color-accent-100)]',\r\n label: t('common:running'),\r\n animate: true,\r\n };\r\n default:\r\n return {\r\n icon: Clock,\r\n color: 'text-[var(--text-tertiary)]',\r\n bg: 'bg-[var(--bg-tertiary)]',\r\n label: t('common:pending'),\r\n };\r\n }\r\n };\r\n\r\n const statusConfig = getStatusConfig();\r\n const StatusIcon = statusConfig.icon;\r\n\r\n return (\r\n <div className=\"h-full flex flex-col rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-card)] overflow-hidden shadow-sm hover:shadow-md transition-shadow\">\r\n {/* Header with gradient */}\r\n <div className=\"px-4 py-3 bg-gradient-to-r from-[var(--color-accent-500)]/10 to-[var(--color-accent-600)]/5 border-b border-[var(--border-color)]\">\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-lg bg-[var(--color-accent-500)]/20\">\r\n <Icon className=\"w-5 h-5 text-[var(--color-accent-600)]\" />\r\n </div>\r\n <h3 className=\"font-semibold text-[var(--text-primary)]\">\r\n {t(`entra:resourceTypes.${resourceType.toLowerCase()}`)}\r\n </h3>\r\n </div>\r\n <div className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium ${statusConfig.bg} ${statusConfig.color}`}>\r\n <StatusIcon className={`w-3.5 h-3.5 ${statusConfig.animate ? 'animate-spin' : ''}`} />\r\n {statusConfig.label}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Stats Grid */}\r\n <div className=\"flex-1 flex flex-col p-4\">\r\n <div className=\"grid grid-cols-3 gap-3 mb-4\">\r\n <div className=\"text-center p-3 rounded-lg bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-center gap-1 mb-1\">\r\n <Database className=\"w-3.5 h-3.5 text-[var(--text-tertiary)]\" />\r\n </div>\r\n <p className=\"text-xl font-bold text-[var(--text-primary)]\">{totalItemsSynced.toLocaleString()}</p>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{t('entra:dashboard.itemsSynced')}</p>\r\n </div>\r\n <div className=\"text-center p-3 rounded-lg bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-center gap-1 mb-1\">\r\n <Calendar className=\"w-3.5 h-3.5 text-[var(--text-tertiary)]\" />\r\n </div>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate\" title={formatDate(lastFullSyncAt)}>\r\n {lastFullSyncAt ? new Date(lastFullSyncAt).toLocaleDateString('fr-FR', { day: 'numeric', month: 'short' }) : '-'}\r\n </p>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{t('entra:dashboard.lastFullSync')}</p>\r\n </div>\r\n <div className=\"text-center p-3 rounded-lg bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-center gap-1 mb-1\">\r\n <RefreshCw className=\"w-3.5 h-3.5 text-[var(--text-tertiary)]\" />\r\n </div>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate\" title={formatDate(lastDeltaSyncAt)}>\r\n {lastDeltaSyncAt ? new Date(lastDeltaSyncAt).toLocaleDateString('fr-FR', { day: 'numeric', month: 'short' }) : '-'}\r\n </p>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{t('entra:dashboard.lastDeltaSync')}</p>\r\n </div>\r\n </div>\r\n\r\n {/* Pending Conflicts Warning */}\r\n {pendingConflicts > 0 && (\r\n <div className=\"flex items-center gap-2 p-3 mb-4 rounded-lg bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <AlertCircle className=\"w-4 h-4 text-[var(--warning-text)] flex-shrink-0\" />\r\n <span className=\"text-sm text-[var(--warning-text)] font-medium\">\r\n {pendingConflicts} {t('entra:dashboard.pendingConflicts')}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* Last Error */}\r\n {lastError && (\r\n <div className=\"p-3 mb-4 rounded-lg bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <p className=\"text-xs text-[var(--error-text)] line-clamp-2\">{lastError}</p>\r\n </div>\r\n )}\r\n\r\n {/* Action Button - Always at bottom */}\r\n <Tooltip\r\n content={!canSync ? t('entra:dashboard.noSyncPermission') : undefined}\r\n position=\"top\"\r\n variant=\"error\"\r\n disabled={canSync}\r\n >\r\n <button\r\n onClick={onSync}\r\n disabled={syncing || !canSync}\r\n className=\"mt-auto w-full inline-flex items-center justify-center gap-2 px-4 py-2.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors shadow-sm\"\r\n >\r\n {syncing ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <RefreshCw className=\"w-4 h-4\" />\r\n )}\r\n {t('entra:dashboard.syncNow')}\r\n </button>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport function EntraDashboardPage(): ReactElement {\r\n const { t } = useTranslation(['entra', 'common']);\r\n const { hasPermission } = useAuth();\r\n const [loading, setLoading] = useState(true);\r\n const [refreshing, setRefreshing] = useState(false);\r\n const [syncStatus, setSyncStatus] = useState<EntraSyncStatusDto[]>([]);\r\n const [error, setError] = useState<string | null>(null);\r\n const [syncing, setSyncing] = useState<string | null>(null);\r\n const [lastSyncResult, setLastSyncResult] = useState<EntraSyncResultDto | null>(null);\r\n\r\n // Permission check for sync operations\r\n const canSync = hasPermission('administration.entra.execute');\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n setError(null);\r\n const status = await entraApi.dashboard.getSyncStatus();\r\n setSyncStatus(Array.isArray(status) ? status : []);\r\n } catch (err: unknown) {\r\n console.error('Failed to load Entra dashboard data:', err);\r\n setSyncStatus([]);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else if (axiosError.response?.status === 403) {\r\n setError(t('common:errors.noPermission'));\r\n } else {\r\n setError(t('entra:dashboard.loadError'));\r\n }\r\n } finally {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }, [t]);\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 handleSync = async (type: 'all' | 'users' | 'groups' | 'memberships') => {\r\n setSyncing(type);\r\n setLastSyncResult(null);\r\n try {\r\n let result: EntraSyncResultDto;\r\n switch (type) {\r\n case 'users':\r\n result = await entraApi.sync.syncUsers();\r\n break;\r\n case 'groups':\r\n result = await entraApi.sync.syncGroups();\r\n break;\r\n case 'memberships':\r\n result = await entraApi.sync.syncMemberships();\r\n break;\r\n default:\r\n result = await entraApi.sync.syncAll();\r\n }\r\n setLastSyncResult(result);\r\n await loadData();\r\n } catch (err: unknown) {\r\n console.error('Sync failed:', err);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 403) {\r\n setError(t('entra:dashboard.syncPermissionDenied'));\r\n } else if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else {\r\n setError(t('entra:dashboard.syncError'));\r\n }\r\n } finally {\r\n setSyncing(null);\r\n }\r\n };\r\n\r\n const handleForceFullSync = async () => {\r\n if (!confirm(t('entra:dashboard.forceFullSyncConfirm'))) return;\r\n setSyncing('force');\r\n try {\r\n await entraApi.sync.forceFullSync();\r\n await loadData();\r\n } catch (err: unknown) {\r\n console.error('Force full sync failed:', err);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 403) {\r\n setError(t('entra:dashboard.syncPermissionDenied'));\r\n } else if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else {\r\n setError(t('entra:dashboard.syncError'));\r\n }\r\n } finally {\r\n setSyncing(null);\r\n }\r\n };\r\n\r\n const formatDate = (date: string | null) => {\r\n if (!date) return t('common:never');\r\n return new Intl.DateTimeFormat('fr-FR', {\r\n dateStyle: 'medium',\r\n timeStyle: 'short',\r\n }).format(new Date(date));\r\n };\r\n\r\n const getResourceIcon = (resourceType: string): LucideIcon => {\r\n switch (resourceType) {\r\n case 'Users':\r\n return Users;\r\n case 'Groups':\r\n return Building2;\r\n case 'Memberships':\r\n return Link2;\r\n default:\r\n return Cloud;\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-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n const totalPendingConflicts = syncStatus.reduce((sum, s) => sum + s.pendingConflicts, 0);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title'), href: '/administration' },\r\n { label: t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: t('entra.dashboard', 'Dashboard') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-[var(--color-accent-500)]/10\">\r\n <Cloud className=\"w-6 h-6 text-[var(--color-accent-500)]\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('entra:dashboard.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:dashboard.subtitle')}\r\n </p>\r\n </div>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={handleRefresh}\r\n disabled={refreshing}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-hover)] disabled:opacity-50 transition-colors\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />\r\n {t('common:refresh')}\r\n </button>\r\n <Tooltip\r\n content={!canSync ? t('entra:dashboard.noSyncPermission') : undefined}\r\n position=\"bottom\"\r\n variant=\"error\"\r\n disabled={canSync}\r\n >\r\n <button\r\n onClick={() => handleSync('all')}\r\n disabled={syncing !== null || !canSync}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\r\n >\r\n {syncing === 'all' ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <Play className=\"w-4 h-4\" />\r\n )}\r\n {t('entra:dashboard.syncAll')}\r\n </button>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <div className=\"flex items-center gap-2 text-[var(--error-text)]\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n <span>{error}</span>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Pending Conflicts Warning */}\r\n {totalPendingConflicts > 0 && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <div className=\"flex items-center gap-2 text-[var(--warning-text)]\">\r\n <AlertCircle className=\"w-5 h-5\" />\r\n <span>\r\n {t('entra:dashboard.conflictsWarning', { count: totalPendingConflicts })}\r\n </span>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Last Sync Result */}\r\n {lastSyncResult && (\r\n <div className={`p-4 rounded-[var(--radius-card)] border ${\r\n lastSyncResult.success\r\n ? 'bg-[var(--success-bg)] border-[var(--success-border)]'\r\n : 'bg-[var(--error-bg)] border-[var(--error-border)]'\r\n }`}>\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-2\">\r\n {lastSyncResult.success ? (\r\n <CheckCircle className=\"w-5 h-5 text-[var(--success-text)]\" />\r\n ) : (\r\n <XCircle className=\"w-5 h-5 text-[var(--error-text)]\" />\r\n )}\r\n <span className={lastSyncResult.success ? 'text-[var(--success-text)]' : 'text-[var(--error-text)]'}>\r\n {lastSyncResult.success\r\n ? t('entra:dashboard.syncSuccess')\r\n : t('entra:dashboard.syncFailed')}\r\n </span>\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:dashboard.syncStats', {\r\n created: lastSyncResult.created,\r\n updated: lastSyncResult.updated,\r\n deleted: lastSyncResult.deleted,\r\n })}\r\n </div>\r\n </div>\r\n {lastSyncResult.errorMessage && (\r\n <p className=\"mt-2 text-sm text-[var(--error-text)]\">\r\n {lastSyncResult.errorMessage}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Sync Status Cards */}\r\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\r\n {syncStatus.map((status) => (\r\n <SyncStatusCard\r\n key={status.resourceType}\r\n resourceType={status.resourceType}\r\n icon={getResourceIcon(status.resourceType)}\r\n status={status.status}\r\n lastFullSyncAt={status.lastFullSyncAt}\r\n lastDeltaSyncAt={status.lastDeltaSyncAt}\r\n totalItemsSynced={status.totalItemsSynced}\r\n pendingConflicts={status.pendingConflicts}\r\n lastError={status.lastError}\r\n syncing={syncing === status.resourceType.toLowerCase()}\r\n canSync={canSync}\r\n onSync={() => handleSync(status.resourceType.toLowerCase() as 'users' | 'groups' | 'memberships')}\r\n formatDate={formatDate}\r\n t={t}\r\n />\r\n ))}\r\n </div>\r\n\r\n {/* Force Full Sync */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h3 className=\"font-semibold text-[var(--text-primary)]\">\r\n {t('entra:dashboard.forceFullSync')}\r\n </h3>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:dashboard.forceFullSyncDescription')}\r\n </p>\r\n </div>\r\n <Tooltip\r\n content={!canSync ? t('entra:dashboard.noSyncPermission') : undefined}\r\n position=\"left\"\r\n variant=\"error\"\r\n disabled={canSync}\r\n >\r\n <button\r\n onClick={handleForceFullSync}\r\n disabled={syncing !== null || !canSync}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--warning-border)] bg-[var(--warning-bg)] text-[var(--warning-text)] hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\r\n >\r\n {syncing === 'force' ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <AlertTriangle className=\"w-4 h-4\" />\r\n )}\r\n {t('entra:dashboard.forceFullSync')}\r\n </button>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Link, useNavigate } from 'react-router-dom';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport {\r\n Cloud,\r\n RefreshCw,\r\n Loader2,\r\n AlertTriangle,\r\n Search,\r\n Users,\r\n Shield,\r\n Plus,\r\n X,\r\n ChevronDown,\r\n ChevronUp,\r\n LayoutGrid,\r\n List,\r\n Filter,\r\n Building2,\r\n GitBranch,\r\n} from 'lucide-react';\r\nimport {\r\n entraApi,\r\n type EntraGroupDto,\r\n type EntraGroupMemberDto,\r\n} from '@/services/api/entraApi';\r\nimport { adminApi, type RoleListDto } from '@/services/api/adminApi';\r\nimport { useAuth } from '@/contexts/AuthContext';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\n\r\ntype ViewMode = 'cards' | 'table';\r\ntype GroupTypeFilter = 'all' | 'security' | 'distribution';\r\n\r\ninterface GroupWithMembers extends EntraGroupDto {\r\n membersLoaded?: EntraGroupMemberDto[];\r\n}\r\n\r\nconst getGroupHierarchyDisplay = (group: EntraGroupDto) => {\r\n if (group.parentGroupName) {\r\n return (\r\n <span className=\"flex items-center gap-1 text-xs\">\r\n <GitBranch className=\"w-3 h-3\" />\r\n {group.parentGroupName}\r\n </span>\r\n );\r\n }\r\n if (group.childGroupCount > 0) {\r\n return (\r\n <span className=\"flex items-center gap-1 text-xs text-[var(--text-tertiary)]\">\r\n {group.childGroupCount} child groups\r\n </span>\r\n );\r\n }\r\n return <span className=\"text-xs text-[var(--text-tertiary)]\">-</span>;\r\n};\r\n\r\nexport function EntraGroupsPage(): ReactElement {\r\n const { t } = useTranslation(['entra', 'admin', 'common']);\r\n const { hasPermission } = useAuth();\r\n const { currentTenant, isGlobalView } = useTenant();\r\n const navigate = useNavigate();\r\n const [loading, setLoading] = useState(true);\r\n const [groups, setGroups] = useState<GroupWithMembers[]>([]);\r\n const [roles, setRoles] = useState<RoleListDto[]>([]);\r\n const [error, setError] = useState<string | null>(null);\r\n const [searchQuery, setSearchQuery] = useState('');\r\n const [selectedGroup, setSelectedGroup] = useState<GroupWithMembers | null>(null);\r\n const [showAssignModal, setShowAssignModal] = useState(false);\r\n const [expandedGroupId, setExpandedGroupId] = useState<string | null>(null);\r\n const [members, setMembers] = useState<Record<string, EntraGroupMemberDto[]>>({});\r\n const [loadingMembers, setLoadingMembers] = useState<string | null>(null);\r\n const [viewMode, setViewMode] = useState<ViewMode>('cards');\r\n const [groupTypeFilter, setGroupTypeFilter] = useState<GroupTypeFilter>('all');\r\n const [assigning, setAssigning] = useState(false);\r\n\r\n const canAssign = hasPermission('administration.entra.assign');\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n setError(null);\r\n const [groupsData, rolesData] = await Promise.all([\r\n entraApi.groups.getAll(),\r\n adminApi.roles.getAssignable(),\r\n ]);\r\n setGroups(Array.isArray(groupsData) ? groupsData : []);\r\n setRoles(Array.isArray(rolesData) ? rolesData : []);\r\n } catch (err: unknown) {\r\n console.error('Failed to load Entra groups:', err);\r\n setGroups([]);\r\n setRoles([]);\r\n const axiosError = err as { response?: { status?: number; data?: { code?: string } } };\r\n if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else if (axiosError.response?.status === 403) {\r\n setError(t('common:errors.noPermission'));\r\n } else if (axiosError.response?.data?.code === 'TENANT_REQUIRED') {\r\n setError(t('entra:groups.tenantRequired'));\r\n } else {\r\n setError(t('entra:groups.loadError'));\r\n }\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [t, currentTenant?.id, isGlobalView]);\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n const loadMembers = async (groupId: string) => {\r\n if (members[groupId]) {\r\n setExpandedGroupId(expandedGroupId === groupId ? null : groupId);\r\n return;\r\n }\r\n\r\n setLoadingMembers(groupId);\r\n try {\r\n const data = await entraApi.groups.getMembers(groupId);\r\n setMembers(prev => ({ ...prev, [groupId]: data }));\r\n setExpandedGroupId(groupId);\r\n } catch (err) {\r\n console.error('Failed to load members:', err);\r\n setError(t('entra:groups.loadMembersError'));\r\n } finally {\r\n setLoadingMembers(null);\r\n }\r\n };\r\n\r\n const reloadGroupsAndRoles = useCallback(async () => {\r\n const [groupsData, rolesData] = await Promise.all([\r\n entraApi.groups.getAll(),\r\n adminApi.roles.getAssignable(),\r\n ]);\r\n const safeGroupsData = Array.isArray(groupsData) ? groupsData : [];\r\n setGroups(safeGroupsData);\r\n setRoles(Array.isArray(rolesData) ? rolesData : []);\r\n return safeGroupsData;\r\n }, [currentTenant?.id]);\r\n\r\n const handleAssignRole = async (roleId: string, isInheritable: boolean = true) => {\r\n if (!selectedGroup) return;\r\n setAssigning(true);\r\n try {\r\n await entraApi.groups.assignRole(selectedGroup.id, { roleId, isInheritable });\r\n const safeGroupsData = await reloadGroupsAndRoles();\r\n const updatedGroup = safeGroupsData.find(g => g.id === selectedGroup.id);\r\n if (updatedGroup) setSelectedGroup(updatedGroup);\r\n } catch (err) {\r\n console.error('Failed to assign role:', err);\r\n setError(t('entra:groups.assignError'));\r\n } finally {\r\n setAssigning(false);\r\n }\r\n };\r\n\r\n const handleRemoveRole = async (groupId: string, roleId: string) => {\r\n if (!confirm(t('entra:groups.removeRoleConfirm'))) return;\r\n try {\r\n await entraApi.groups.removeRole(groupId, roleId);\r\n await reloadGroupsAndRoles();\r\n if (selectedGroup?.id === groupId) {\r\n const updatedGroups = await entraApi.groups.getAll();\r\n const updatedGroup = updatedGroups.find(g => g.id === groupId);\r\n if (updatedGroup) setSelectedGroup(updatedGroup);\r\n }\r\n } catch (err) {\r\n console.error('Failed to remove role:', err);\r\n setError(t('entra:groups.removeError'));\r\n }\r\n };\r\n\r\n const filteredGroups = groups.filter((g) => {\r\n const matchesSearch =\r\n g.displayName.toLowerCase().includes(searchQuery.toLowerCase()) ||\r\n g.description?.toLowerCase().includes(searchQuery.toLowerCase());\r\n\r\n const matchesType =\r\n groupTypeFilter === 'all' ||\r\n (groupTypeFilter === 'security' && g.isSecurityGroup) ||\r\n (groupTypeFilter === 'distribution' && !g.isSecurityGroup);\r\n\r\n return matchesSearch && matchesType;\r\n });\r\n\r\n const formatDate = (date: string | null) => {\r\n if (!date) return '-';\r\n return new Intl.DateTimeFormat('fr-FR', {\r\n dateStyle: 'medium',\r\n timeStyle: 'short',\r\n }).format(new Date(date));\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-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title'), href: '/administration' },\r\n { label: t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: t('entra.groups', 'Groups') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-blue-500/10\">\r\n <Cloud className=\"w-6 h-6 text-blue-500\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('entra:groups.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:groups.subtitle', { count: groups.length })}\r\n </p>\r\n </div>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={loadData}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common:refresh')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Info banner */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-blue-500/10 border border-blue-500/20\">\r\n <div className=\"flex items-start gap-3\">\r\n <Cloud className=\"w-5 h-5 text-blue-500 flex-shrink-0 mt-0.5\" />\r\n <div>\r\n <p className=\"text-sm text-[var(--text-primary)]\">\r\n {t('entra:groups.syncedInfo')}\r\n </p>\r\n <p className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n {t('entra:groups.syncedInfoDescription')}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <div className=\"flex items-center gap-2 text-[var(--error-text)]\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n <span>{error}</span>\r\n <button\r\n onClick={() => setError(null)}\r\n className=\"ml-auto p-1 hover:bg-[var(--error-text)]/10 rounded\"\r\n >\r\n <X className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Search & Filters */}\r\n <div className=\"flex flex-col sm:flex-row gap-4\">\r\n {/* Search */}\r\n <div className=\"relative flex-1\">\r\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-[var(--text-tertiary)]\" />\r\n <input\r\n type=\"text\"\r\n placeholder={t('entra:groups.searchPlaceholder')}\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n className=\"w-full pl-10 pr-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n\r\n {/* Type Filter */}\r\n <div className=\"flex items-center gap-2\">\r\n <Filter className=\"w-4 h-4 text-[var(--text-tertiary)]\" />\r\n <select\r\n value={groupTypeFilter}\r\n onChange={(e) => setGroupTypeFilter(e.target.value as GroupTypeFilter)}\r\n className=\"px-3 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('admin:groups.allTypes')}</option>\r\n <option value=\"security\">{t('admin:groups.securityGroup')}</option>\r\n <option value=\"distribution\">{t('admin:groups.distributionGroup')}</option>\r\n </select>\r\n </div>\r\n\r\n {/* View Mode Toggle */}\r\n <div className=\"flex items-center gap-1 p-1 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] border border-[var(--border-color)]\">\r\n <button\r\n onClick={() => setViewMode('cards')}\r\n className={`p-2 rounded-[var(--radius-button)] transition-colors ${\r\n viewMode === 'cards'\r\n ? 'bg-[var(--color-accent-500)] text-white'\r\n : 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n title={t('admin:groups.cardView')}\r\n >\r\n <LayoutGrid className=\"w-4 h-4\" />\r\n </button>\r\n <button\r\n onClick={() => setViewMode('table')}\r\n className={`p-2 rounded-[var(--radius-button)] transition-colors ${\r\n viewMode === 'table'\r\n ? 'bg-[var(--color-accent-500)] text-white'\r\n : 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n title={t('admin:groups.tableView')}\r\n >\r\n <List className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Groups List */}\r\n {filteredGroups.length === 0 && (\r\n <div className=\"text-center py-12 text-[var(--text-secondary)]\">\r\n {searchQuery || groupTypeFilter !== 'all'\r\n ? t('admin:groups.noResults')\r\n : t('entra:groups.noGroups')}\r\n </div>\r\n )}\r\n {filteredGroups.length > 0 && viewMode === 'table' && (\r\n /* Table View */\r\n <div className=\"rounded-[var(--radius-card)] border border-[var(--border-color)] overflow-hidden\">\r\n <table className=\"w-full\">\r\n <thead className=\"bg-[var(--bg-secondary)]\">\r\n <tr>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:groups.groupName')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('common:type')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:groups.members')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('entra:groups.hierarchy')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:groups.assignedRoles')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('entra:groups.lastSynced')}\r\n </th>\r\n {canAssign && !isGlobalView && (\r\n <th className=\"px-4 py-3 text-right text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('common:actionsColumn')}\r\n </th>\r\n )}\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--border-color)]\">\r\n {filteredGroups.map((group) => (\r\n <tr\r\n key={group.id}\r\n className=\"hover:bg-[var(--bg-hover)] cursor-pointer\"\r\n onClick={() => navigate(`/administration/users/groups/${group.id}`)}\r\n >\r\n <td className=\"px-4 py-3\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className={`w-8 h-8 rounded-full flex items-center justify-center ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-purple-500/10 text-purple-500'\r\n }`}>\r\n {group.isSecurityGroup ? (\r\n <Shield className=\"w-4 h-4\" />\r\n ) : (\r\n <Building2 className=\"w-4 h-4\" />\r\n )}\r\n </div>\r\n <div>\r\n <span className=\"font-medium text-[var(--text-primary)]\">{group.displayName}</span>\r\n {group.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] truncate max-w-xs\">\r\n {group.description}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <span className={`px-2 py-1 text-xs rounded-[var(--radius-badge)] ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-purple-500/10 text-purple-500'\r\n }`}>\r\n {group.isSecurityGroup ? t('admin:groups.securityGroup') : t('admin:groups.distributionGroup')}\r\n </span>\r\n </td>\r\n <td className=\"px-4 py-3 text-sm text-[var(--text-secondary)]\">\r\n <span className=\"flex items-center gap-1\">\r\n <Users className=\"w-4 h-4\" />\r\n {group.memberCount}\r\n </span>\r\n </td>\r\n <td className=\"px-4 py-3 text-sm text-[var(--text-secondary)]\">\r\n {getGroupHierarchyDisplay(group)}\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <div className=\"flex flex-wrap gap-1\">\r\n {group.assignedRoles.slice(0, 2).map((role) => (\r\n <span\r\n key={role.roleId}\r\n className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]\"\r\n >\r\n {role.roleName}\r\n </span>\r\n ))}\r\n {group.assignedRoles.length > 2 && (\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--bg-tertiary)] text-[var(--text-tertiary)]\">\r\n +{group.assignedRoles.length - 2}\r\n </span>\r\n )}\r\n {group.inheritedRoles.length > 0 && (\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-green-500/10 text-green-600\" title={t('entra:groups.inheritedRoles')}>\r\n +{group.inheritedRoles.length} {t('entra:groups.inherited')}\r\n </span>\r\n )}\r\n </div>\r\n </td>\r\n <td className=\"px-4 py-3 text-xs text-[var(--text-tertiary)]\">\r\n {formatDate(group.lastSyncedAt)}\r\n </td>\r\n {canAssign && !isGlobalView && (\r\n <td className=\"px-4 py-3 text-right\" onClick={(e) => e.stopPropagation()}>\r\n <button\r\n onClick={() => {\r\n setSelectedGroup(group);\r\n setShowAssignModal(true);\r\n }}\r\n className=\"p-2 rounded-[var(--radius-button)] text-[var(--text-tertiary)] hover:text-[var(--color-accent-500)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n title={t('admin:groups.assignRole')}\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n </button>\r\n </td>\r\n )}\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n )}\r\n {filteredGroups.length > 0 && viewMode !== 'table' && (\r\n /* Cards View */\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n {filteredGroups.map((group) => (\r\n <button\r\n type=\"button\"\r\n key={group.id}\r\n className=\"rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-secondary)] overflow-hidden cursor-pointer hover:border-[var(--color-accent-500)] transition-colors text-left\"\r\n onClick={() => navigate(`/administration/users/groups/${group.id}`)}\r\n >\r\n {/* Card Header */}\r\n <div className=\"p-4\">\r\n <div className=\"flex items-start justify-between gap-4\">\r\n <div className=\"flex items-start gap-3 min-w-0\">\r\n <div className={`p-2.5 rounded-[var(--radius-button)] flex-shrink-0 ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-purple-500/10 text-purple-500'\r\n }`}>\r\n {group.isSecurityGroup ? (\r\n <Shield className=\"w-5 h-5\" />\r\n ) : (\r\n <Building2 className=\"w-5 h-5\" />\r\n )}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <div className=\"flex items-center gap-2 flex-wrap\">\r\n <span className=\"font-semibold text-[var(--text-primary)] truncate\">\r\n {group.displayName}\r\n </span>\r\n <span className={`px-2 py-0.5 text-xs rounded-[var(--radius-badge)] ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500 border border-blue-500/20'\r\n : 'bg-purple-500/10 text-purple-500 border border-purple-500/20'\r\n }`}>\r\n {group.isSecurityGroup ? t('admin:groups.securityGroup') : t('admin:groups.distributionGroup')}\r\n </span>\r\n {!group.isActive && (\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--warning-bg)] text-[var(--warning-text)] border border-[var(--warning-border)]\">\r\n {t('common:inactive')}\r\n </span>\r\n )}\r\n </div>\r\n {group.description && (\r\n <p className=\"text-sm text-[var(--text-secondary)] mt-1 line-clamp-2\">\r\n {group.description}\r\n </p>\r\n )}\r\n <div className=\"flex items-center gap-4 mt-2 text-sm text-[var(--text-tertiary)] flex-wrap\">\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n loadMembers(group.id);\r\n }}\r\n className=\"flex items-center gap-1 hover:text-[var(--color-accent-500)] transition-colors\"\r\n >\r\n <Users className=\"w-4 h-4\" />\r\n {t('admin:groups.memberCount', { count: group.memberCount })}\r\n {loadingMembers === group.id && (\r\n <Loader2 className=\"w-3 h-3 animate-spin ml-1\" />\r\n )}\r\n {loadingMembers !== group.id && expandedGroupId === group.id && (\r\n <ChevronUp className=\"w-3 h-3 ml-1\" />\r\n )}\r\n {loadingMembers !== group.id && expandedGroupId !== group.id && (\r\n <ChevronDown className=\"w-3 h-3 ml-1\" />\r\n )}\r\n </button>\r\n {group.childGroupCount > 0 && (\r\n <span className=\"flex items-center gap-1 text-xs\">\r\n <GitBranch className=\"w-3 h-3\" />\r\n {group.childGroupCount} {t('entra:groups.childGroups')}\r\n </span>\r\n )}\r\n </div>\r\n {group.parentGroupName && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1 flex items-center gap-1\">\r\n <GitBranch className=\"w-3 h-3\" />\r\n {t('entra:groups.parentGroup')}: {group.parentGroupName}\r\n </p>\r\n )}\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\r\n {t('entra:groups.lastSynced')}: {formatDate(group.lastSyncedAt)}\r\n </p>\r\n </div>\r\n </div>\r\n {canAssign && !isGlobalView && (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n setSelectedGroup(group);\r\n setShowAssignModal(true);\r\n }}\r\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors flex-shrink-0\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:groups.assignRole')}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* Assigned Roles */}\r\n {(group.assignedRoles.length > 0 || group.inheritedRoles.length > 0) && (\r\n <div className=\"mt-4 pt-4 border-t border-[var(--border-color)]\">\r\n {group.assignedRoles.length > 0 && (\r\n <>\r\n <h4 className=\"text-sm font-medium text-[var(--text-primary)] mb-2\">\r\n {t('admin:groups.assignedRoles')}\r\n </h4>\r\n <div className=\"flex flex-wrap gap-2 mb-3\">\r\n {group.assignedRoles.map((role) => (\r\n <div\r\n key={role.roleId}\r\n className=\"inline-flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-badge)] bg-[var(--bg-primary)] border border-[var(--border-color)] group\"\r\n >\r\n <Shield className=\"w-4 h-4 text-[var(--color-accent-500)]\" />\r\n <span className=\"text-sm text-[var(--text-primary)]\">{role.roleName}</span>\r\n {role.isInheritable && (\r\n <span className=\"text-xs text-green-600\" title={t('entra:groups.inheritableRole')}>\r\n ↓\r\n </span>\r\n )}\r\n {canAssign && (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n handleRemoveRole(group.id, role.roleId);\r\n }}\r\n className=\"ml-1 p-0.5 rounded opacity-0 group-hover:opacity-100 hover:bg-[var(--error-bg)] text-[var(--text-tertiary)] hover:text-[var(--error-text)] transition-all\"\r\n title={t('common:remove')}\r\n >\r\n <X className=\"w-3 h-3\" />\r\n </button>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n </>\r\n )}\r\n {group.inheritedRoles.length > 0 && (\r\n <>\r\n <h4 className=\"text-xs font-medium text-[var(--text-tertiary)] mb-2 flex items-center gap-1\">\r\n <GitBranch className=\"w-3 h-3\" />\r\n {t('entra:groups.inheritedRoles')}\r\n </h4>\r\n <div className=\"flex flex-wrap gap-2\">\r\n {group.inheritedRoles.map((role) => (\r\n <div\r\n key={`${role.roleId}-${role.sourceGroupId}`}\r\n className=\"inline-flex items-center gap-2 px-2 py-1 rounded-[var(--radius-badge)] bg-green-500/5 border border-green-500/20\"\r\n title={`${t('entra:groups.inheritedFrom')} ${role.sourceGroupName}`}\r\n >\r\n <Shield className=\"w-3 h-3 text-green-600\" />\r\n <span className=\"text-xs text-green-700\">{role.roleName}</span>\r\n <span className=\"text-xs text-green-600/60\">← {role.sourceGroupName}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Members Panel */}\r\n {expandedGroupId === group.id && members[group.id] && (\r\n <div className=\"border-t border-[var(--border-color)] bg-[var(--bg-primary)]\" onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} role=\"presentation\">\r\n <div className=\"p-4\">\r\n <h4 className=\"text-sm font-medium text-[var(--text-primary)] mb-3 flex items-center gap-2\">\r\n <Users className=\"w-4 h-4\" />\r\n {t('admin:groups.members')} ({members[group.id].length})\r\n </h4>\r\n {members[group.id].length === 0 ? (\r\n <p className=\"text-sm text-[var(--text-tertiary)]\">\r\n {t('admin:groups.noMembers')}\r\n </p>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-2 max-h-64 overflow-y-auto\">\r\n {members[group.id].slice(0, 10).map((member) => (\r\n <Link\r\n key={member.userId}\r\n to={`/administration/users/${member.userId}`}\r\n className=\"flex items-center gap-3 p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <div className=\"w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]\">\r\n {member.fullName.charAt(0).toUpperCase()}\r\n </div>\r\n <div className=\"min-w-0 flex-1\">\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate\">\r\n {member.fullName}\r\n </p>\r\n <p className=\"text-xs text-[var(--text-tertiary)] truncate\">\r\n {member.email}\r\n </p>\r\n </div>\r\n {!member.isDirect && member.sourceGroupName && (\r\n <span className=\"text-xs text-[var(--text-tertiary)] flex items-center gap-1\" title={t('entra:groups.memberFromChildGroup')}>\r\n <GitBranch className=\"w-3 h-3\" />\r\n </span>\r\n )}\r\n </Link>\r\n ))}\r\n </div>\r\n )}\r\n {members[group.id].length > 10 && (\r\n <p className=\"mt-3 text-center text-sm text-[var(--text-tertiary)]\">\r\n {t('admin:groups.showingMembers', {\r\n shown: 10,\r\n total: members[group.id].length,\r\n })}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </button>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Assign Role Modal */}\r\n {showAssignModal && selectedGroup && (\r\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\r\n <div className=\"w-full max-w-md rounded-[var(--radius-card)] bg-[var(--bg-secondary)] border border-[var(--border-color)] shadow-xl\">\r\n <div className=\"flex items-center justify-between p-4 border-b border-[var(--border-color)]\">\r\n <h2 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('admin:groups.assignRoleTitle')}\r\n </h2>\r\n <button\r\n onClick={() => {\r\n setShowAssignModal(false);\r\n setSelectedGroup(null);\r\n }}\r\n className=\"p-1 rounded hover:bg-[var(--bg-hover)] text-[var(--text-tertiary)]\"\r\n >\r\n <X className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n <div className=\"p-4\">\r\n <p className=\"text-sm text-[var(--text-secondary)] mb-4\">\r\n {t('admin:groups.assignRoleDescription', { group: selectedGroup.displayName })}\r\n </p>\r\n <div className=\"space-y-2 max-h-64 overflow-y-auto\">\r\n {roles\r\n .filter((role) => !selectedGroup.assignedRoles.some(r => r.roleId === role.id))\r\n .map((role) => (\r\n <button\r\n key={role.id}\r\n onClick={() => handleAssignRole(role.id)}\r\n disabled={assigning}\r\n className=\"w-full flex items-center gap-3 p-3 rounded-[var(--radius-button)] border border-[var(--border-color)] hover:border-[var(--color-accent-500)] hover:bg-[var(--bg-hover)] transition-colors text-left disabled:opacity-50\"\r\n >\r\n <Shield className=\"w-5 h-5 text-[var(--color-accent-500)]\" />\r\n <div className=\"flex-1\">\r\n <p className=\"font-medium text-[var(--text-primary)]\">{role.name}</p>\r\n {role.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{role.description}</p>\r\n )}\r\n </div>\r\n {assigning && (\r\n <Loader2 className=\"w-4 h-4 animate-spin text-[var(--color-accent-500)]\" />\r\n )}\r\n </button>\r\n ))}\r\n {roles.filter((role) => !selectedGroup.assignedRoles.some(r => r.roleId === role.id)).length === 0 && (\r\n <p className=\"text-sm text-[var(--text-tertiary)] text-center py-4\">\r\n {t('admin:groups.allRolesAssigned')}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport {\r\n Users,\r\n RefreshCw,\r\n AlertTriangle,\r\n CheckCircle,\r\n XCircle,\r\n Mail,\r\n Calendar,\r\n ExternalLink,\r\n} from 'lucide-react';\r\nimport { adminApi, type UserListDto } from '@/services/api/adminApi';\r\nimport { DataTable, type DataTableColumn } from '@/components/ui/DataTable';\r\n\r\nexport function EntraUsersPage(): ReactElement {\r\n const { t } = useTranslation(['entra', 'common']);\r\n const navigate = useNavigate();\r\n const [loading, setLoading] = useState(true);\r\n const [users, setUsers] = useState<UserListDto[]>([]);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n setError(null);\r\n // Only fetch users synced from Entra ID (have entraObjectId)\r\n const response = await adminApi.users.getAll({ pageSize: 1000, entraOnly: true });\r\n setUsers(response?.items ?? []);\r\n } catch (err: unknown) {\r\n console.error('Failed to load users:', err);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else if (axiosError.response?.status === 403) {\r\n setError(t('common:errors.noPermission'));\r\n } else {\r\n setError(t('entra:users.loadError'));\r\n }\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [t]);\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n const formatDate = (date: string | null) => {\r\n if (!date) return t('common:never');\r\n return new Intl.DateTimeFormat('fr-FR', {\r\n dateStyle: 'medium',\r\n timeStyle: 'short',\r\n }).format(new Date(date));\r\n };\r\n\r\n // Define columns for DataTable\r\n const columns: DataTableColumn<UserListDto>[] = [\r\n {\r\n key: 'fullName',\r\n label: t('entra:users.columns.user'),\r\n sortable: true,\r\n render: (user) => (\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"w-10 h-10 rounded-full bg-[var(--color-primary-100)] dark:bg-[var(--color-primary-900)] flex items-center justify-center flex-shrink-0\">\r\n <span className=\"text-sm font-medium text-[var(--color-primary-600)]\">\r\n {user.fullName?.charAt(0).toUpperCase() || '?'}\r\n </span>\r\n </div>\r\n <span className=\"font-medium text-[var(--text-primary)]\">{user.fullName}</span>\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'email',\r\n label: t('entra:users.columns.email'),\r\n sortable: true,\r\n render: (user) => (\r\n <div className=\"flex items-center gap-1 text-sm text-[var(--text-secondary)]\">\r\n <Mail className=\"w-4 h-4\" />\r\n {user.email}\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'isActive',\r\n label: t('entra:users.columns.status'),\r\n sortable: true,\r\n render: (user) =>\r\n user.isActive ? (\r\n <span className=\"inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400\">\r\n <CheckCircle className=\"w-3 h-3\" />\r\n {t('common:active')}\r\n </span>\r\n ) : (\r\n <span className=\"inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400\">\r\n <XCircle className=\"w-3 h-3\" />\r\n {t('common:inactive')}\r\n </span>\r\n ),\r\n },\r\n {\r\n key: 'lastEntraSyncAt',\r\n label: t('entra:users.columns.lastSync'),\r\n sortable: true,\r\n render: (user) => (\r\n <div className=\"flex items-center gap-1 text-sm text-[var(--text-secondary)]\">\r\n <Calendar className=\"w-4 h-4\" />\r\n {formatDate(user.lastEntraSyncAt)}\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'actions',\r\n label: t('entra:users.columns.actions'),\r\n align: 'right',\r\n render: (user) => (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n navigate(`/administration/users/${user.id}`);\r\n }}\r\n className=\"inline-flex items-center gap-1 text-sm text-[var(--color-primary-600)] hover:underline\"\r\n >\r\n {t('common:viewDetails')}\r\n <ExternalLink className=\"w-4 h-4\" />\r\n </button>\r\n ),\r\n },\r\n ];\r\n\r\n // Custom search filter for users\r\n const searchFilter = (user: UserListDto, searchTerm: string) => {\r\n const search = searchTerm.toLowerCase();\r\n return (\r\n user.fullName?.toLowerCase().includes(search) ||\r\n user.email?.toLowerCase().includes(search) ||\r\n false\r\n );\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title'), href: '/administration' },\r\n { label: t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: t('entra.users', 'Users') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-lg bg-[var(--color-primary-100)] dark:bg-[var(--color-primary-900)]\">\r\n <Users className=\"w-6 h-6 text-[var(--color-primary-600)]\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('entra:users.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:users.subtitle', { count: users.length })}\r\n </p>\r\n </div>\r\n </div>\r\n <button\r\n onClick={loadData}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg border border-[var(--border-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] hover:bg-[var(--bg-secondary)]\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common:refresh')}\r\n </button>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"p-4 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800\">\r\n <div className=\"flex items-center gap-2 text-red-700 dark:text-red-400\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n <span>{error}</span>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* DataTable */}\r\n <DataTable\r\n data={users}\r\n columns={columns}\r\n loading={loading}\r\n searchable\r\n searchPlaceholder={t('entra:users.searchPlaceholder')}\r\n searchFilter={searchFilter}\r\n pagination={{ pageSize: 20, showSizeSelector: true }}\r\n onRowClick={(user) => navigate(`/administration/users/${user.id}`)}\r\n getRowKey={(user) => user.id}\r\n emptyMessage={t('entra:users.noUsers')}\r\n emptyIcon={<Users className=\"w-12 h-12 mx-auto text-[var(--text-secondary)] opacity-50\" />}\r\n defaultSortKey=\"fullName\"\r\n striped\r\n />\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport {\r\n AlertTriangle,\r\n RefreshCw,\r\n Loader2,\r\n CheckCircle,\r\n} from 'lucide-react';\r\nimport {\r\n entraApi,\r\n type EntraSyncConflictDto,\r\n type ResolveConflictRequest,\r\n} from '@/services/api/entraApi';\r\nimport { ConflictCard, ResolutionModal } from '@/components/platform/administration/entra';\r\n\r\n// ============================================\r\n// Main Component\r\n// ============================================\r\n\r\nexport function EntraConflictsPage(): ReactElement {\r\n const { t } = useTranslation(['entra', 'common']);\r\n const [loading, setLoading] = useState(true);\r\n const [conflicts, setConflicts] = useState<EntraSyncConflictDto[]>([]);\r\n const [error, setError] = useState<string | null>(null);\r\n const [selectedConflict, setSelectedConflict] = useState<EntraSyncConflictDto | null>(null);\r\n const [resolving, setResolving] = useState(false);\r\n\r\n // Abort controller ref for preventing race conditions\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n const isLoadingRef = useRef(false);\r\n\r\n const loadData = useCallback(async () => {\r\n // Prevent concurrent loads\r\n if (isLoadingRef.current) return;\r\n\r\n // Cancel any pending request\r\n if (abortControllerRef.current) {\r\n abortControllerRef.current.abort();\r\n }\r\n\r\n abortControllerRef.current = new AbortController();\r\n isLoadingRef.current = true;\r\n\r\n try {\r\n setError(null);\r\n const data = await entraApi.conflicts.getAll();\r\n setConflicts(Array.isArray(data) ? data : []);\r\n } catch (err: unknown) {\r\n // Ignore abort errors\r\n if (err instanceof Error && err.name === 'AbortError') {\r\n return;\r\n }\r\n // Log error type only, not the full error object (PII protection)\r\n console.error('Failed to load conflicts:', err instanceof Error ? err.message : 'Unknown error');\r\n setConflicts([]);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else if (axiosError.response?.status === 403) {\r\n setError(t('common:errors.noPermission'));\r\n } else {\r\n setError(t('entra:conflicts.loadError'));\r\n }\r\n } finally {\r\n isLoadingRef.current = false;\r\n setLoading(false);\r\n }\r\n }, [t]);\r\n\r\n useEffect(() => {\r\n loadData();\r\n\r\n // Cleanup on unmount\r\n return () => {\r\n if (abortControllerRef.current) {\r\n abortControllerRef.current.abort();\r\n }\r\n };\r\n }, [loadData]);\r\n\r\n const handleResolve = useCallback(async (resolution: ResolveConflictRequest['resolution'], notes?: string) => {\r\n if (!selectedConflict || resolving) return;\r\n\r\n setResolving(true);\r\n try {\r\n await entraApi.conflicts.resolve(selectedConflict.id, {\r\n resolution,\r\n notes: notes || undefined,\r\n });\r\n setSelectedConflict(null);\r\n await loadData();\r\n } catch (err) {\r\n // Log error type only, not the full error object (PII protection)\r\n console.error('Failed to resolve conflict:', err instanceof Error ? err.message : 'Unknown error');\r\n setError(t('entra:conflicts.resolveError'));\r\n } finally {\r\n setResolving(false);\r\n }\r\n }, [selectedConflict, resolving, loadData, t]);\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-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title'), href: '/administration' },\r\n { label: t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: t('entra.conflicts', 'Conflicts') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-[var(--color-accent-500)]/10\">\r\n <AlertTriangle className=\"w-6 h-6 text-[var(--color-accent-600)]\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('entra:conflicts.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:conflicts.subtitle', { count: conflicts.length })}\r\n </p>\r\n </div>\r\n </div>\r\n <button\r\n onClick={loadData}\r\n disabled={loading}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors disabled:opacity-50\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />\r\n {t('common:refresh')}\r\n </button>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-2 text-[var(--error-text)]\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n <span>{error}</span>\r\n </div>\r\n <button\r\n onClick={() => setError(null)}\r\n className=\"text-[var(--error-text)] hover:opacity-70\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* No Conflicts - Empty State */}\r\n {conflicts.length === 0 ? (\r\n <div className=\"text-center py-16 px-6 rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-card)]\">\r\n <div className=\"mx-auto w-16 h-16 rounded-full bg-[var(--success-bg)] flex items-center justify-center mb-4\">\r\n <CheckCircle className=\"w-8 h-8 text-[var(--success-text)]\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-[var(--text-primary)] mb-2\">\r\n {t('entra:conflicts.noConflicts')}\r\n </h2>\r\n <p className=\"text-[var(--text-secondary)] max-w-md mx-auto\">\r\n {t('entra:conflicts.noConflictsDescription')}\r\n </p>\r\n </div>\r\n ) : (\r\n /* Conflicts Grid */\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {conflicts.map((conflict) => (\r\n <ConflictCard\r\n key={conflict.id}\r\n conflict={conflict}\r\n onResolve={setSelectedConflict}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Resolve Modal */}\r\n {selectedConflict && (\r\n <ResolutionModal\r\n conflict={selectedConflict}\r\n onClose={() => setSelectedConflict(null)}\r\n onResolve={handleResolve}\r\n resolving={resolving}\r\n />\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback, type ReactNode } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport type { LucideIcon } from 'lucide-react';\r\nimport {\r\n Settings,\r\n Key,\r\n Eye,\r\n EyeOff,\r\n Save,\r\n AlertTriangle,\r\n CheckCircle,\r\n ExternalLink,\r\n Shield,\r\n Clock,\r\n Loader2,\r\n TestTube,\r\n Users,\r\n Layers,\r\n Building2,\r\n Copy,\r\n Check,\r\n GitMerge,\r\n Filter,\r\n} from 'lucide-react';\r\nimport { entraApi } from '@/services/api/entraApi';\r\nimport type { TestConnectionResult, EntraConfigurationDto } from '@/services/api/entraApi';\r\n\r\ninterface EntraCredentials {\r\n tenantId: string;\r\n clientId: string;\r\n clientSecret: string;\r\n}\r\n\r\ninterface SyncSettings {\r\n syncEnabled: boolean;\r\n syncIntervalMinutes: number;\r\n useDeltaSync: boolean;\r\n defaultConflictResolution: 'ManualReview' | 'EntraWins' | 'LocalWins';\r\n autoCreateReferences: boolean;\r\n // User sync filters\r\n syncOnlyActiveUsers: boolean;\r\n syncUserTypes: string; // comma-separated: member, guest, shared, room, equipment\r\n}\r\n\r\n// Available user types for sync\r\n// Note: shared, room, equipment require mailboxSettings which is not available in bulk user listing API\r\nconst USER_TYPES = [\r\n { id: 'member', labelKey: 'userTypes.member', descriptionKey: 'userTypes.memberDescription', supported: true },\r\n { id: 'guest', labelKey: 'userTypes.guest', descriptionKey: 'userTypes.guestDescription', supported: true },\r\n { id: 'shared', labelKey: 'userTypes.shared', descriptionKey: 'userTypes.sharedDescription', supported: false },\r\n { id: 'room', labelKey: 'userTypes.room', descriptionKey: 'userTypes.roomDescription', supported: false },\r\n { id: 'equipment', labelKey: 'userTypes.equipment', descriptionKey: 'userTypes.equipmentDescription', supported: false },\r\n];\r\n\r\n// Required permissions for Microsoft Graph API\r\nconst REQUIRED_PERMISSIONS = [\r\n { code: 'User.Read.All', descriptionKey: 'userReadAll' },\r\n { code: 'Group.Read.All', descriptionKey: 'groupReadAll' },\r\n { code: 'GroupMember.Read.All', descriptionKey: 'groupMemberReadAll' },\r\n];\r\n\r\n// ============================================\r\n// Reusable Components\r\n// ============================================\r\n\r\ninterface SectionCardProps {\r\n readonly icon: LucideIcon;\r\n readonly title: string;\r\n readonly description?: string;\r\n readonly action?: ReactNode;\r\n readonly children: ReactNode;\r\n readonly className?: string;\r\n}\r\n\r\nfunction SectionCard({ icon: Icon, title, description, action, children, className = '' }: SectionCardProps) {\r\n return (\r\n <div className={`rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-card)] shadow-sm overflow-hidden ${className}`}>\r\n {/* Header */}\r\n <div className=\"px-6 py-4 border-b border-[var(--border-subtle)] bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-[var(--color-accent-100)] dark:bg-[var(--color-accent-900)]/30\">\r\n <Icon className=\"w-5 h-5 text-[var(--color-accent-500)]\" />\r\n </div>\r\n <div>\r\n <h2 className=\"text-base font-semibold text-[var(--text-primary)]\">{title}</h2>\r\n {description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5\">{description}</p>\r\n )}\r\n </div>\r\n </div>\r\n {action}\r\n </div>\r\n </div>\r\n {/* Content */}\r\n <div className=\"p-6\">\r\n {children}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\ninterface ToggleProps {\r\n readonly checked: boolean;\r\n readonly onChange: () => void;\r\n readonly label: string;\r\n readonly description?: string;\r\n}\r\n\r\nfunction Toggle({ checked, onChange, label, description }: ToggleProps) {\r\n return (\r\n <div className=\"flex items-center justify-between py-3\">\r\n <div className=\"flex-1 min-w-0 pr-4\">\r\n <label className=\"text-sm font-medium text-[var(--text-primary)]\">{label}</label>\r\n {description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5\">{description}</p>\r\n )}\r\n </div>\r\n <button\r\n type=\"button\"\r\n role=\"switch\"\r\n aria-checked={checked}\r\n onClick={onChange}\r\n className={`relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] focus:ring-offset-2 focus:ring-offset-[var(--bg-primary)] ${\r\n checked ? 'bg-[var(--color-accent-600)]' : 'bg-[var(--bg-tertiary)]'\r\n }`}\r\n >\r\n <span\r\n className={`inline-block h-4 w-4 transform rounded-full bg-[var(--toggle-knob)] shadow-md transition-transform ${\r\n checked ? 'translate-x-6' : 'translate-x-1'\r\n }`}\r\n />\r\n </button>\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================\r\n// Validation\r\n// ============================================\r\n\r\nconst isValidGuid = (value: string): boolean => {\r\n if (!value) return true;\r\n const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\r\n return guidRegex.test(value);\r\n};\r\n\r\nconst useEntraSettings = () => {\r\n const { t } = useTranslation(['entra', 'common']);\r\n const [loading, setLoading] = useState(true);\r\n const [saving, setSaving] = useState(false);\r\n const [testing, setTesting] = useState(false);\r\n const [testResult, setTestResult] = useState<TestConnectionResult | null>(null);\r\n const [showSecret, setShowSecret] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState<string | null>(null);\r\n const [hasExistingSecret, setHasExistingSecret] = useState(false);\r\n const [copiedPermission, setCopiedPermission] = useState<string | null>(null);\r\n const [validationErrors, setValidationErrors] = useState<{\r\n tenantId?: string;\r\n clientId?: string;\r\n }>({});\r\n\r\n const [credentials, setCredentials] = useState<EntraCredentials>({\r\n tenantId: '',\r\n clientId: '',\r\n clientSecret: '',\r\n });\r\n\r\n const [syncSettings, setSyncSettings] = useState<SyncSettings>({\r\n syncEnabled: false,\r\n syncIntervalMinutes: 60,\r\n useDeltaSync: true,\r\n defaultConflictResolution: 'ManualReview',\r\n autoCreateReferences: true,\r\n syncOnlyActiveUsers: true,\r\n syncUserTypes: 'member',\r\n });\r\n\r\n return {\r\n t, loading, setLoading, saving, setSaving, testing, setTesting,\r\n testResult, setTestResult, showSecret, setShowSecret, error, setError,\r\n success, setSuccess, hasExistingSecret, setHasExistingSecret,\r\n copiedPermission, setCopiedPermission, validationErrors, setValidationErrors,\r\n credentials, setCredentials, syncSettings, setSyncSettings\r\n };\r\n};\r\n\r\n// ============================================\r\n// Helpers\r\n// ============================================\r\n\r\nfunction getCheckboxCardClass(isDisabled: boolean, isChecked: boolean): string {\r\n if (isDisabled) return 'opacity-50 cursor-not-allowed border-[var(--border-color)] bg-[var(--bg-tertiary)]';\r\n if (isChecked) return 'cursor-pointer border-[var(--color-accent-500)] bg-[var(--color-accent-50)] dark:bg-[var(--color-accent-900)]/20';\r\n return 'cursor-pointer border-[var(--border-color)] bg-[var(--bg-secondary)] hover:bg-[var(--bg-tertiary)]';\r\n}\r\n\r\n// ============================================\r\n// Main Component\r\n// ============================================\r\n\r\nexport function EntraSettingsPage(): ReactElement {\r\n const state = useEntraSettings();\r\n\r\n const loadConfiguration = useCallback(async () => {\r\n try {\r\n state.setLoading(true);\r\n const config: EntraConfigurationDto = await entraApi.settings.getConfiguration();\r\n\r\n state.setCredentials({\r\n tenantId: config.tenantId || '',\r\n clientId: config.clientId || '',\r\n clientSecret: '',\r\n });\r\n state.setHasExistingSecret(config.hasClientSecret);\r\n\r\n state.setSyncSettings({\r\n syncEnabled: config.syncEnabled,\r\n syncIntervalMinutes: config.syncIntervalMinutes,\r\n useDeltaSync: config.useDeltaSync,\r\n defaultConflictResolution: config.defaultConflictResolution as SyncSettings['defaultConflictResolution'],\r\n autoCreateReferences: config.autoCreateReferences,\r\n syncOnlyActiveUsers: config.syncOnlyActiveUsers ?? true,\r\n syncUserTypes: config.syncUserTypes ?? 'member',\r\n });\r\n } catch (err) {\r\n console.error('Failed to load configuration:', err);\r\n state.setError(state.t('entra:settings.saveError'));\r\n } finally {\r\n state.setLoading(false);\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []); // React setters are stable, no need to include them in dependencies\r\n\r\n useEffect(() => {\r\n loadConfiguration();\r\n }, [loadConfiguration]);\r\n\r\n const handleCopyPermission = async (code: string) => {\r\n try {\r\n await navigator.clipboard.writeText(code);\r\n state.setCopiedPermission(code);\r\n setTimeout(() => state.setCopiedPermission(null), 2000);\r\n } catch (err) {\r\n console.error('Failed to copy:', err);\r\n }\r\n };\r\n\r\n const validateCredentialField = (field: 'tenantId' | 'clientId', value: string) => {\r\n const errorKey = isValidGuid(value) ? undefined : state.t('entra:settings.invalidGuidFormat');\r\n state.setValidationErrors(prev => ({ ...prev, [field]: errorKey }));\r\n };\r\n\r\n const handleCredentialChange = (field: keyof EntraCredentials, value: string) => {\r\n state.setCredentials(prev => ({ ...prev, [field]: value }));\r\n if (field === 'tenantId' || field === 'clientId') {\r\n validateCredentialField(field, value);\r\n }\r\n };\r\n\r\n const hasValidationErrors = Boolean(\r\n state.validationErrors.tenantId || state.validationErrors.clientId\r\n );\r\n\r\n const handleTestConnection = async () => {\r\n state.setTesting(true);\r\n state.setTestResult(null);\r\n state.setError(null);\r\n state.setSuccess(null);\r\n try {\r\n let result: TestConnectionResult;\r\n\r\n if (state.credentials.clientSecret) {\r\n result = await entraApi.settings.testConnection({\r\n tenantId: state.credentials.tenantId,\r\n clientId: state.credentials.clientId,\r\n clientSecret: state.credentials.clientSecret,\r\n });\r\n } else if (state.hasExistingSecret) {\r\n result = await entraApi.settings.testStoredConnection();\r\n } else {\r\n state.setError(state.t('entra:settings.testFailed'));\r\n state.setTesting(false);\r\n return;\r\n }\r\n\r\n state.setTestResult(result);\r\n if (result.success) {\r\n state.setSuccess(state.t('entra:settings.testSuccess'));\r\n } else {\r\n state.setError(result.errorMessage || state.t('entra:settings.testFailed'));\r\n }\r\n } catch (err) {\r\n console.error('Connection test failed:', err);\r\n state.setTestResult({ success: false, errorMessage: state.t('entra:settings.testFailed'), tenantName: null, userCount: null, groupCount: null });\r\n state.setError(state.t('entra:settings.testFailed'));\r\n } finally {\r\n state.setTesting(false);\r\n }\r\n };\r\n\r\n const handleSaveCredentials = async () => {\r\n state.setSaving(true);\r\n state.setError(null);\r\n state.setSuccess(null);\r\n try {\r\n await entraApi.settings.saveCredentials({\r\n tenantId: state.credentials.tenantId,\r\n clientId: state.credentials.clientId,\r\n clientSecret: state.credentials.clientSecret,\r\n });\r\n state.setSuccess(state.t('entra:settings.credentialsSaved'));\r\n state.setHasExistingSecret(true);\r\n state.setCredentials((prev) => ({ ...prev, clientSecret: '' }));\r\n } catch (err) {\r\n console.error('Failed to save credentials:', err);\r\n state.setError(state.t('entra:settings.saveError'));\r\n } finally {\r\n state.setSaving(false);\r\n }\r\n };\r\n\r\n const handleSaveSettings = async () => {\r\n state.setSaving(true);\r\n state.setError(null);\r\n state.setSuccess(null);\r\n try {\r\n await entraApi.settings.saveSyncSettings({\r\n syncEnabled: state.syncSettings.syncEnabled,\r\n syncIntervalMinutes: state.syncSettings.syncIntervalMinutes,\r\n useDeltaSync: state.syncSettings.useDeltaSync,\r\n defaultConflictResolution: state.syncSettings.defaultConflictResolution,\r\n autoCreateReferences: state.syncSettings.autoCreateReferences,\r\n syncOnlyActiveUsers: state.syncSettings.syncOnlyActiveUsers,\r\n syncUserTypes: state.syncSettings.syncUserTypes,\r\n });\r\n state.setSuccess(state.t('entra:settings.settingsSaved'));\r\n } catch (err) {\r\n console.error('Failed to save settings:', err);\r\n state.setError(state.t('entra:settings.saveError'));\r\n } finally {\r\n state.setSaving(false);\r\n }\r\n };\r\n\r\n if (state.loading) {\r\n return (\r\n <div className=\"flex items-center justify-center h-64\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: state.t('header.title'), href: '/administration' },\r\n { label: state.t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: state.t('entra.settings', 'Settings') }\r\n ]}\r\n />\r\n\r\n {/* Page Header */}\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"p-3 rounded-[var(--radius-card)] bg-gradient-to-br from-[var(--color-accent-500)] to-[var(--color-accent-700)] shadow-lg\">\r\n <Settings className=\"w-7 h-7 text-white\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {state.t('entra:settings.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {state.t('entra:settings.subtitle')}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {/* Required Permissions Warning */}\r\n <div className=\"rounded-[var(--radius-card)] border-2 border-[var(--warning-border)] bg-[var(--warning-bg)] overflow-hidden\">\r\n <div className=\"px-5 py-4\">\r\n <div className=\"flex items-start gap-4\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-[var(--warning-border)]\">\r\n <Shield className=\"w-5 h-5 text-[var(--warning-text)]\" />\r\n </div>\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center justify-between gap-4 mb-2\">\r\n <h2 className=\"font-semibold text-[var(--warning-text)]\">\r\n {state.t('entra:settings.permissionsWarningTitle')}\r\n </h2>\r\n <a\r\n href=\"https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--warning-border)] text-[var(--warning-text)] hover:opacity-80 transition-opacity\"\r\n >\r\n {state.t('entra:settings.configureInAzure')}\r\n <ExternalLink className=\"w-3.5 h-3.5\" />\r\n </a>\r\n </div>\r\n <p className=\"text-sm text-[var(--warning-text)] opacity-90 mb-4\">\r\n {state.t('entra:settings.permissionsWarningDescription')}\r\n </p>\r\n\r\n {/* Copyable Permissions */}\r\n <div className=\"flex flex-wrap gap-2\">\r\n {REQUIRED_PERMISSIONS.map((perm) => (\r\n <button\r\n key={perm.code}\r\n onClick={() => handleCopyPermission(perm.code)}\r\n className=\"group inline-flex items-center gap-2 px-3 py-2 rounded-[var(--radius-button)] bg-[var(--bg-primary)] border border-[var(--warning-border)] hover:border-[var(--warning-dot)] transition-all hover:shadow-sm\"\r\n title={state.t(`entra:settings.permissions.${perm.descriptionKey}`)}\r\n >\r\n <code className=\"text-sm font-mono font-medium text-[var(--text-primary)]\">{perm.code}</code>\r\n {state.copiedPermission === perm.code ? (\r\n <Check className=\"w-4 h-4 text-[var(--success-text)]\" />\r\n ) : (\r\n <Copy className=\"w-4 h-4 text-[var(--warning-text)] group-hover:opacity-80\" />\r\n )}\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Error/Success Messages */}\r\n {state.error && (\r\n <div className=\"flex items-center gap-3 p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <AlertTriangle className=\"w-5 h-5 text-[var(--error-text)] flex-shrink-0\" />\r\n <span className=\"text-sm text-[var(--error-text)]\">{state.error}</span>\r\n </div>\r\n )}\r\n\r\n {state.success && (\r\n <div className=\"flex items-center gap-3 p-4 rounded-[var(--radius-card)] bg-[var(--success-bg)] border border-[var(--success-border)]\">\r\n <CheckCircle className=\"w-5 h-5 text-[var(--success-text)] flex-shrink-0\" />\r\n <span className=\"text-sm text-[var(--success-text)]\">{state.success}</span>\r\n </div>\r\n )}\r\n\r\n {/* Main Content Grid */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* ============================================ */}\r\n {/* Left Column - Credentials */}\r\n {/* ============================================ */}\r\n <SectionCard\r\n icon={Key}\r\n title={state.t('entra:settings.credentials')}\r\n description=\"Azure AD Application\"\r\n action={\r\n <a\r\n href=\"https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"inline-flex items-center gap-1.5 text-sm text-[var(--color-accent-500)] hover:text-[var(--color-accent-600)] transition-colors\"\r\n >\r\n {state.t('entra:settings.azurePortal')}\r\n <ExternalLink className=\"w-4 h-4\" />\r\n </a>\r\n }\r\n >\r\n <div className=\"space-y-5\">\r\n {/* Tenant ID */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-1.5\">\r\n {state.t('entra:settings.tenantId')}\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={state.credentials.tenantId}\r\n onChange={(e) => handleCredentialChange('tenantId', e.target.value)}\r\n placeholder=\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\r\n autoComplete=\"off\"\r\n className={`w-full px-3 py-2.5 rounded-[var(--radius-input)] border bg-[var(--bg-secondary)] text-[var(--text-primary)] font-mono text-sm focus:outline-none focus:ring-2 focus:border-transparent transition-shadow ${\r\n state.validationErrors.tenantId\r\n ? 'border-[var(--error-border)] focus:ring-[var(--error-border)]'\r\n : 'border-[var(--border-color)] focus:ring-[var(--color-accent-500)]'\r\n }`}\r\n />\r\n {state.validationErrors.tenantId ? (\r\n <p className=\"mt-1.5 text-xs text-[var(--error-text)]\">{state.validationErrors.tenantId}</p>\r\n ) : (\r\n <p className=\"mt-1.5 text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.tenantIdHelp')}</p>\r\n )}\r\n </div>\r\n\r\n {/* Client ID */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-1.5\">\r\n {state.t('entra:settings.clientId')}\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={state.credentials.clientId}\r\n onChange={(e) => handleCredentialChange('clientId', e.target.value)}\r\n placeholder=\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\r\n autoComplete=\"off\"\r\n className={`w-full px-3 py-2.5 rounded-[var(--radius-input)] border bg-[var(--bg-secondary)] text-[var(--text-primary)] font-mono text-sm focus:outline-none focus:ring-2 focus:border-transparent transition-shadow ${\r\n state.validationErrors.clientId\r\n ? 'border-[var(--error-border)] focus:ring-[var(--error-border)]'\r\n : 'border-[var(--border-color)] focus:ring-[var(--color-accent-500)]'\r\n }`}\r\n />\r\n {state.validationErrors.clientId ? (\r\n <p className=\"mt-1.5 text-xs text-[var(--error-text)]\">{state.validationErrors.clientId}</p>\r\n ) : (\r\n <p className=\"mt-1.5 text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.clientIdHelp')}</p>\r\n )}\r\n </div>\r\n\r\n {/* Client Secret */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-1.5\">\r\n {state.t('entra:settings.clientSecret')}\r\n {state.hasExistingSecret && (\r\n <span className=\"ml-2 inline-flex items-center gap-1 text-xs text-[var(--success-text)]\">\r\n <CheckCircle className=\"w-3 h-3\" />\r\n {state.t('common:configured')}\r\n </span>\r\n )}\r\n </label>\r\n <div className=\"relative\">\r\n <input\r\n type={state.showSecret ? 'text' : 'password'}\r\n value={state.credentials.clientSecret}\r\n onChange={(e) => handleCredentialChange('clientSecret', e.target.value)}\r\n placeholder={state.hasExistingSecret ? '••••••••••••••••••••••••••••••••••••••••' : 'OvA8Q~xxxxxxxxxxxxxxxxxxxxxxxxxxxx'}\r\n autoComplete=\"new-password\"\r\n className=\"w-full px-3 py-2.5 pr-10 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] font-mono text-sm focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] focus:border-transparent transition-shadow\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => state.setShowSecret(!state.showSecret)}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 p-1 text-[var(--text-tertiary)] hover:text-[var(--text-primary)] transition-colors\"\r\n >\r\n {state.showSecret ? <EyeOff className=\"w-4 h-4\" /> : <Eye className=\"w-4 h-4\" />}\r\n </button>\r\n </div>\r\n <p className=\"mt-1.5 text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.clientSecretHelp')}</p>\r\n </div>\r\n\r\n {/* Action Buttons */}\r\n <div className=\"flex items-center gap-3 pt-2\">\r\n <button\r\n onClick={handleTestConnection}\r\n disabled={state.testing || hasValidationErrors || !state.credentials.tenantId || !state.credentials.clientId || (!state.credentials.clientSecret && !state.hasExistingSecret)}\r\n className=\"inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\r\n >\r\n {state.testing && <Loader2 className=\"w-4 h-4 animate-spin\" />}\r\n {!state.testing && state.testResult?.success && <CheckCircle className=\"w-4 h-4 text-[var(--success-text)]\" />}\r\n {!state.testing && state.testResult && !state.testResult.success && <AlertTriangle className=\"w-4 h-4 text-[var(--error-text)]\" />}\r\n {!state.testing && !state.testResult && <TestTube className=\"w-4 h-4\" />}\r\n {state.t('entra:settings.testConnection')}\r\n </button>\r\n <button\r\n onClick={handleSaveCredentials}\r\n disabled={state.saving || hasValidationErrors || !state.credentials.tenantId || !state.credentials.clientId || !state.credentials.clientSecret}\r\n className=\"inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors shadow-sm\"\r\n >\r\n {state.saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Save className=\"w-4 h-4\" />}\r\n {state.t('common:save')}\r\n </button>\r\n </div>\r\n\r\n {/* Test Result Details */}\r\n {state.testResult?.success && (\r\n <div className=\"mt-4 p-4 rounded-[var(--radius-card)] bg-[var(--success-bg)] border border-[var(--success-border)]\">\r\n <div className=\"flex items-center gap-2 mb-3\">\r\n <CheckCircle className=\"w-5 h-5 text-[var(--success-text)]\" />\r\n <span className=\"font-medium text-[var(--success-text)]\">\r\n {state.t('entra:settings.connectionSuccessful')}\r\n </span>\r\n </div>\r\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-3\">\r\n {state.testResult.tenantName && (\r\n <div className=\"flex items-center gap-2 p-2 rounded-[var(--radius-button)] bg-[var(--bg-primary)]\">\r\n <Building2 className=\"w-4 h-4 text-[var(--success-text)]\" />\r\n <div className=\"min-w-0\">\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.tenantName')}</p>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate\">{state.testResult.tenantName}</p>\r\n </div>\r\n </div>\r\n )}\r\n {state.testResult.userCount !== null && (\r\n <div className=\"flex items-center gap-2 p-2 rounded-[var(--radius-button)] bg-[var(--bg-primary)]\">\r\n <Users className=\"w-4 h-4 text-[var(--success-text)]\" />\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.userCount')}</p>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)]\">{state.testResult.userCount}</p>\r\n </div>\r\n </div>\r\n )}\r\n {state.testResult.groupCount !== null && (\r\n <div className=\"flex items-center gap-2 p-2 rounded-[var(--radius-button)] bg-[var(--bg-primary)]\">\r\n <Layers className=\"w-4 h-4 text-[var(--success-text)]\" />\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.groupCount')}</p>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)]\">{state.testResult.groupCount}</p>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n </SectionCard>\r\n\r\n {/* ============================================ */}\r\n {/* Right Column - Sync Settings Stack */}\r\n {/* ============================================ */}\r\n <div className=\"space-y-6\">\r\n {/* Sync Configuration */}\r\n <SectionCard\r\n icon={Clock}\r\n title={state.t('entra:settings.syncSettings')}\r\n description=\"Scheduling & Performance\"\r\n >\r\n <div className=\"divide-y divide-[var(--border-subtle)]\">\r\n <Toggle\r\n checked={state.syncSettings.syncEnabled}\r\n onChange={() => state.setSyncSettings((prev) => ({ ...prev, syncEnabled: !prev.syncEnabled }))}\r\n label={state.t('entra:settings.syncEnabled')}\r\n description={state.t('entra:settings.syncEnabledHelp')}\r\n />\r\n\r\n <div className=\"py-4\">\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\">\r\n {state.t('entra:settings.syncInterval')}\r\n </label>\r\n <select\r\n value={state.syncSettings.syncIntervalMinutes}\r\n onChange={(e) => state.setSyncSettings((prev) => ({ ...prev, syncIntervalMinutes: Number(e.target.value) }))}\r\n className=\"w-full px-3 py-2.5 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] transition-shadow\"\r\n >\r\n <option value={15}>15 {state.t('common:minutes')}</option>\r\n <option value={30}>30 {state.t('common:minutes')}</option>\r\n <option value={60}>1 {state.t('common:hour')}</option>\r\n <option value={120}>2 {state.t('common:hours')}</option>\r\n <option value={360}>6 {state.t('common:hours')}</option>\r\n <option value={720}>12 {state.t('common:hours')}</option>\r\n <option value={1440}>24 {state.t('common:hours')}</option>\r\n </select>\r\n </div>\r\n\r\n <Toggle\r\n checked={state.syncSettings.useDeltaSync}\r\n onChange={() => state.setSyncSettings((prev) => ({ ...prev, useDeltaSync: !prev.useDeltaSync }))}\r\n label={state.t('entra:settings.useDeltaSync')}\r\n description={state.t('entra:settings.useDeltaSyncHelp')}\r\n />\r\n\r\n <Toggle\r\n checked={state.syncSettings.autoCreateReferences}\r\n onChange={() => state.setSyncSettings((prev) => ({ ...prev, autoCreateReferences: !prev.autoCreateReferences }))}\r\n label={state.t('entra:settings.autoCreateReferences')}\r\n description={state.t('entra:settings.autoCreateReferencesHelp')}\r\n />\r\n </div>\r\n </SectionCard>\r\n\r\n {/* Conflict Resolution */}\r\n <SectionCard\r\n icon={GitMerge}\r\n title={state.t('entra:settings.conflictResolution')}\r\n description=\"Data Priority\"\r\n >\r\n <div>\r\n <select\r\n value={state.syncSettings.defaultConflictResolution}\r\n onChange={(e) => state.setSyncSettings((prev) => ({ ...prev, defaultConflictResolution: e.target.value as SyncSettings['defaultConflictResolution'] }))}\r\n className=\"w-full px-3 py-2.5 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] transition-shadow\"\r\n >\r\n <option value=\"ManualReview\">{state.t('entra:settings.conflictResolutions.manualReview')}</option>\r\n <option value=\"EntraWins\">{state.t('entra:settings.conflictResolutions.entraWins')}</option>\r\n <option value=\"LocalWins\">{state.t('entra:settings.conflictResolutions.localWins')}</option>\r\n </select>\r\n <p className=\"mt-2 text-xs text-[var(--text-tertiary)]\">\r\n {state.t('entra:settings.conflictResolutionHelp')}\r\n </p>\r\n </div>\r\n </SectionCard>\r\n\r\n {/* User Filters */}\r\n <SectionCard\r\n icon={Filter}\r\n title={state.t('entra:settings.userSyncFilters')}\r\n description=\"User Types & Filters\"\r\n >\r\n <div className=\"space-y-4\">\r\n <Toggle\r\n checked={state.syncSettings.syncOnlyActiveUsers}\r\n onChange={() => state.setSyncSettings((prev) => ({ ...prev, syncOnlyActiveUsers: !prev.syncOnlyActiveUsers }))}\r\n label={state.t('entra:settings.syncOnlyActiveUsers')}\r\n description={state.t('entra:settings.syncOnlyActiveUsersHelp')}\r\n />\r\n\r\n <div className=\"pt-2 border-t border-[var(--border-subtle)]\">\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\">\r\n {state.t('entra:settings.syncUserTypesLabel')}\r\n </label>\r\n <p className=\"text-xs text-[var(--text-tertiary)] mb-3\">\r\n {state.t('entra:settings.syncUserTypesHelp')}\r\n </p>\r\n <div className=\"space-y-2\">\r\n {USER_TYPES.map((userType) => {\r\n const selectedTypes = state.syncSettings.syncUserTypes.split(',').map(t => t.trim()).filter(Boolean);\r\n const isChecked = selectedTypes.includes(userType.id);\r\n const isDisabled = !userType.supported;\r\n\r\n const handleToggle = () => {\r\n if (isDisabled) return;\r\n let newTypes: string[];\r\n if (isChecked) {\r\n newTypes = selectedTypes.filter(t => t !== userType.id);\r\n } else {\r\n newTypes = [...selectedTypes, userType.id];\r\n }\r\n if (newTypes.length === 0) newTypes = ['member'];\r\n state.setSyncSettings(prev => ({ ...prev, syncUserTypes: newTypes.join(',') }));\r\n };\r\n\r\n return (\r\n <label\r\n key={userType.id}\r\n className={`flex items-start gap-3 p-3 rounded-[var(--radius-button)] border transition-all ${\r\n getCheckboxCardClass(isDisabled, isChecked)\r\n }`}\r\n >\r\n <input\r\n type=\"checkbox\"\r\n checked={isChecked}\r\n onChange={handleToggle}\r\n disabled={isDisabled}\r\n className=\"mt-0.5 w-4 h-4 rounded border-[var(--border-color)] text-[var(--color-accent-600)] focus:ring-[var(--color-accent-500)] disabled:opacity-50\"\r\n />\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center gap-2\">\r\n <span className=\"text-sm font-medium text-[var(--text-primary)]\">\r\n {state.t(`entra:settings.${userType.labelKey}`)}\r\n </span>\r\n {isDisabled && (\r\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-[var(--bg-tertiary)] text-[var(--text-tertiary)]\">\r\n {state.t('common:comingSoon')}\r\n </span>\r\n )}\r\n </div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5\">\r\n {state.t(`entra:settings.${userType.descriptionKey}`)}\r\n </p>\r\n </div>\r\n </label>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n </SectionCard>\r\n\r\n {/* Save Button */}\r\n <div className=\"flex justify-end\">\r\n <button\r\n onClick={handleSaveSettings}\r\n disabled={state.saving}\r\n className=\"inline-flex items-center gap-2 px-6 py-2.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors shadow-sm\"\r\n >\r\n {state.saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Save className=\"w-4 h-4\" />}\r\n {state.t('common:save')}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["SyncStatusCard","resourceType","Icon","status","lastFullSyncAt","lastDeltaSyncAt","totalItemsSynced","pendingConflicts","lastError","syncing","canSync","onSync","formatDate","t","statusConfig","CheckCircle","XCircle","Loader2","Clock","StatusIcon","jsxs","jsx","Database","Calendar","RefreshCw","AlertCircle","Tooltip","EntraDashboardPage","useTranslation","hasPermission","useAuth","loading","setLoading","useState","refreshing","setRefreshing","syncStatus","setSyncStatus","error","setError","setSyncing","lastSyncResult","setLastSyncResult","loadData","useCallback","entraApi","err","axiosError","useEffect","handleRefresh","handleSync","type","result","handleForceFullSync","date","getResourceIcon","Users","Building2","Link2","Cloud","totalPendingConflicts","sum","s","Breadcrumb","Play","AlertTriangle","getGroupHierarchyDisplay","group","GitBranch","EntraGroupsPage","currentTenant","isGlobalView","useTenant","navigate","useNavigate","groups","setGroups","roles","setRoles","searchQuery","setSearchQuery","selectedGroup","setSelectedGroup","showAssignModal","setShowAssignModal","expandedGroupId","setExpandedGroupId","members","setMembers","loadingMembers","setLoadingMembers","viewMode","setViewMode","groupTypeFilter","setGroupTypeFilter","assigning","setAssigning","canAssign","groupsData","rolesData","adminApi","loadMembers","groupId","data","prev","reloadGroupsAndRoles","safeGroupsData","handleAssignRole","roleId","isInheritable","updatedGroup","g","handleRemoveRole","filteredGroups","matchesSearch","matchesType","X","Search","e","Filter","LayoutGrid","List","Shield","role","Plus","ChevronUp","ChevronDown","Fragment","member","Link","r","EntraUsersPage","users","setUsers","response","columns","user","Mail","ExternalLink","searchFilter","searchTerm","search","DataTable","EntraConflictsPage","conflicts","setConflicts","selectedConflict","setSelectedConflict","resolving","setResolving","abortControllerRef","useRef","isLoadingRef","handleResolve","resolution","notes","conflict","ConflictCard","ResolutionModal","USER_TYPES","REQUIRED_PERMISSIONS","SectionCard","title","description","action","children","className","Toggle","checked","onChange","label","isValidGuid","value","useEntraSettings","saving","setSaving","testing","setTesting","testResult","setTestResult","showSecret","setShowSecret","success","setSuccess","hasExistingSecret","setHasExistingSecret","copiedPermission","setCopiedPermission","validationErrors","setValidationErrors","credentials","setCredentials","syncSettings","setSyncSettings","getCheckboxCardClass","isDisabled","isChecked","EntraSettingsPage","state","loadConfiguration","config","handleCopyPermission","code","validateCredentialField","field","errorKey","handleCredentialChange","hasValidationErrors","handleTestConnection","handleSaveCredentials","handleSaveSettings","Settings","perm","Check","Copy","Key","EyeOff","Eye","TestTube","Save","Layers","GitMerge","userType","selectedTypes","handleToggle","newTypes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-DzedSLdI.js","sources":["../../src/pages/platform/administration/entra/EntraDashboardPage.tsx","../../src/pages/platform/administration/entra/EntraGroupsPage.tsx","../../src/pages/platform/administration/entra/EntraUsersPage.tsx","../../src/pages/platform/administration/entra/EntraConflictsPage.tsx","../../src/pages/platform/administration/entra/EntraSettingsPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useAuth } from '@/contexts/AuthContext';\r\nimport { Tooltip } from '@/components/ui/Tooltip';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport type { LucideIcon } from 'lucide-react';\r\nimport {\r\n Cloud,\r\n RefreshCw,\r\n Loader2,\r\n AlertTriangle,\r\n CheckCircle,\r\n XCircle,\r\n Clock,\r\n Users,\r\n Building2,\r\n Link2,\r\n Play,\r\n AlertCircle,\r\n Calendar,\r\n Database,\r\n} from 'lucide-react';\r\nimport {\r\n entraApi,\r\n type EntraSyncStatusDto,\r\n type EntraSyncResultDto,\r\n} from '@/services/api/entraApi';\r\n\r\n// ============================================\r\n// Sync Status Card Component\r\n// ============================================\r\n\r\ninterface SyncStatusCardProps {\r\n readonly resourceType: string;\r\n readonly icon: LucideIcon;\r\n readonly status: string;\r\n readonly lastFullSyncAt: string | null;\r\n readonly lastDeltaSyncAt: string | null;\r\n readonly totalItemsSynced: number;\r\n readonly pendingConflicts: number;\r\n readonly lastError: string | null;\r\n readonly syncing: boolean;\r\n readonly canSync: boolean;\r\n readonly onSync: () => void;\r\n readonly formatDate: (date: string | null) => string;\r\n readonly t: (key: string, options?: Record<string, unknown>) => string;\r\n}\r\n\r\nfunction SyncStatusCard({\r\n resourceType,\r\n icon: Icon,\r\n status,\r\n lastFullSyncAt,\r\n lastDeltaSyncAt,\r\n totalItemsSynced,\r\n pendingConflicts,\r\n lastError,\r\n syncing,\r\n canSync,\r\n onSync,\r\n formatDate,\r\n t,\r\n}: SyncStatusCardProps) {\r\n const getStatusConfig = () => {\r\n switch (status) {\r\n case 'Success':\r\n return {\r\n icon: CheckCircle,\r\n color: 'text-[var(--success-text)]',\r\n bg: 'bg-[var(--success-bg)]',\r\n label: t('common:success'),\r\n };\r\n case 'Failed':\r\n return {\r\n icon: XCircle,\r\n color: 'text-[var(--error-text)]',\r\n bg: 'bg-[var(--error-bg)]',\r\n label: t('common:failed'),\r\n };\r\n case 'Running':\r\n return {\r\n icon: Loader2,\r\n color: 'text-[var(--color-accent-500)]',\r\n bg: 'bg-[var(--color-accent-100)]',\r\n label: t('common:running'),\r\n animate: true,\r\n };\r\n default:\r\n return {\r\n icon: Clock,\r\n color: 'text-[var(--text-tertiary)]',\r\n bg: 'bg-[var(--bg-tertiary)]',\r\n label: t('common:pending'),\r\n };\r\n }\r\n };\r\n\r\n const statusConfig = getStatusConfig();\r\n const StatusIcon = statusConfig.icon;\r\n\r\n return (\r\n <div className=\"h-full flex flex-col rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-card)] overflow-hidden shadow-sm hover:shadow-md transition-shadow\">\r\n {/* Header with gradient */}\r\n <div className=\"px-4 py-3 bg-gradient-to-r from-[var(--color-accent-500)]/10 to-[var(--color-accent-600)]/5 border-b border-[var(--border-color)]\">\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-lg bg-[var(--color-accent-500)]/20\">\r\n <Icon className=\"w-5 h-5 text-[var(--color-accent-600)]\" />\r\n </div>\r\n <h3 className=\"font-semibold text-[var(--text-primary)]\">\r\n {t(`entra:resourceTypes.${resourceType.toLowerCase()}`)}\r\n </h3>\r\n </div>\r\n <div className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium ${statusConfig.bg} ${statusConfig.color}`}>\r\n <StatusIcon className={`w-3.5 h-3.5 ${statusConfig.animate ? 'animate-spin' : ''}`} />\r\n {statusConfig.label}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Stats Grid */}\r\n <div className=\"flex-1 flex flex-col p-4\">\r\n <div className=\"grid grid-cols-3 gap-3 mb-4\">\r\n <div className=\"text-center p-3 rounded-lg bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-center gap-1 mb-1\">\r\n <Database className=\"w-3.5 h-3.5 text-[var(--text-tertiary)]\" />\r\n </div>\r\n <p className=\"text-xl font-bold text-[var(--text-primary)]\">{totalItemsSynced.toLocaleString()}</p>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{t('entra:dashboard.itemsSynced')}</p>\r\n </div>\r\n <div className=\"text-center p-3 rounded-lg bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-center gap-1 mb-1\">\r\n <Calendar className=\"w-3.5 h-3.5 text-[var(--text-tertiary)]\" />\r\n </div>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate\" title={formatDate(lastFullSyncAt)}>\r\n {lastFullSyncAt ? new Date(lastFullSyncAt).toLocaleDateString('fr-FR', { day: 'numeric', month: 'short' }) : '-'}\r\n </p>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{t('entra:dashboard.lastFullSync')}</p>\r\n </div>\r\n <div className=\"text-center p-3 rounded-lg bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-center gap-1 mb-1\">\r\n <RefreshCw className=\"w-3.5 h-3.5 text-[var(--text-tertiary)]\" />\r\n </div>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate\" title={formatDate(lastDeltaSyncAt)}>\r\n {lastDeltaSyncAt ? new Date(lastDeltaSyncAt).toLocaleDateString('fr-FR', { day: 'numeric', month: 'short' }) : '-'}\r\n </p>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{t('entra:dashboard.lastDeltaSync')}</p>\r\n </div>\r\n </div>\r\n\r\n {/* Pending Conflicts Warning */}\r\n {pendingConflicts > 0 && (\r\n <div className=\"flex items-center gap-2 p-3 mb-4 rounded-lg bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <AlertCircle className=\"w-4 h-4 text-[var(--warning-text)] flex-shrink-0\" />\r\n <span className=\"text-sm text-[var(--warning-text)] font-medium\">\r\n {pendingConflicts} {t('entra:dashboard.pendingConflicts')}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* Last Error */}\r\n {lastError && (\r\n <div className=\"p-3 mb-4 rounded-lg bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <p className=\"text-xs text-[var(--error-text)] line-clamp-2\">{lastError}</p>\r\n </div>\r\n )}\r\n\r\n {/* Action Button - Always at bottom */}\r\n <Tooltip\r\n content={!canSync ? t('entra:dashboard.noSyncPermission') : undefined}\r\n position=\"top\"\r\n variant=\"error\"\r\n disabled={canSync}\r\n >\r\n <button\r\n onClick={onSync}\r\n disabled={syncing || !canSync}\r\n className=\"mt-auto w-full inline-flex items-center justify-center gap-2 px-4 py-2.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors shadow-sm\"\r\n >\r\n {syncing ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <RefreshCw className=\"w-4 h-4\" />\r\n )}\r\n {t('entra:dashboard.syncNow')}\r\n </button>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport function EntraDashboardPage(): ReactElement {\r\n const { t } = useTranslation(['entra', 'common']);\r\n const { hasPermission } = useAuth();\r\n const [loading, setLoading] = useState(true);\r\n const [refreshing, setRefreshing] = useState(false);\r\n const [syncStatus, setSyncStatus] = useState<EntraSyncStatusDto[]>([]);\r\n const [error, setError] = useState<string | null>(null);\r\n const [syncing, setSyncing] = useState<string | null>(null);\r\n const [lastSyncResult, setLastSyncResult] = useState<EntraSyncResultDto | null>(null);\r\n\r\n // Permission check for sync operations\r\n const canSync = hasPermission('administration.entra.execute');\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n setError(null);\r\n const status = await entraApi.dashboard.getSyncStatus();\r\n setSyncStatus(Array.isArray(status) ? status : []);\r\n } catch (err: unknown) {\r\n console.error('Failed to load Entra dashboard data:', err);\r\n setSyncStatus([]);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else if (axiosError.response?.status === 403) {\r\n setError(t('common:errors.noPermission'));\r\n } else {\r\n setError(t('entra:dashboard.loadError'));\r\n }\r\n } finally {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }, [t]);\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 handleSync = async (type: 'all' | 'users' | 'groups' | 'memberships') => {\r\n setSyncing(type);\r\n setLastSyncResult(null);\r\n try {\r\n let result: EntraSyncResultDto;\r\n switch (type) {\r\n case 'users':\r\n result = await entraApi.sync.syncUsers();\r\n break;\r\n case 'groups':\r\n result = await entraApi.sync.syncGroups();\r\n break;\r\n case 'memberships':\r\n result = await entraApi.sync.syncMemberships();\r\n break;\r\n default:\r\n result = await entraApi.sync.syncAll();\r\n }\r\n setLastSyncResult(result);\r\n await loadData();\r\n } catch (err: unknown) {\r\n console.error('Sync failed:', err);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 403) {\r\n setError(t('entra:dashboard.syncPermissionDenied'));\r\n } else if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else {\r\n setError(t('entra:dashboard.syncError'));\r\n }\r\n } finally {\r\n setSyncing(null);\r\n }\r\n };\r\n\r\n const handleForceFullSync = async () => {\r\n if (!confirm(t('entra:dashboard.forceFullSyncConfirm'))) return;\r\n setSyncing('force');\r\n try {\r\n await entraApi.sync.forceFullSync();\r\n await loadData();\r\n } catch (err: unknown) {\r\n console.error('Force full sync failed:', err);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 403) {\r\n setError(t('entra:dashboard.syncPermissionDenied'));\r\n } else if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else {\r\n setError(t('entra:dashboard.syncError'));\r\n }\r\n } finally {\r\n setSyncing(null);\r\n }\r\n };\r\n\r\n const formatDate = (date: string | null) => {\r\n if (!date) return t('common:never');\r\n return new Intl.DateTimeFormat('fr-FR', {\r\n dateStyle: 'medium',\r\n timeStyle: 'short',\r\n }).format(new Date(date));\r\n };\r\n\r\n const getResourceIcon = (resourceType: string): LucideIcon => {\r\n switch (resourceType) {\r\n case 'Users':\r\n return Users;\r\n case 'Groups':\r\n return Building2;\r\n case 'Memberships':\r\n return Link2;\r\n default:\r\n return Cloud;\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-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n const totalPendingConflicts = syncStatus.reduce((sum, s) => sum + s.pendingConflicts, 0);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title'), href: '/administration' },\r\n { label: t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: t('entra.dashboard', 'Dashboard') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-[var(--color-accent-500)]/10\">\r\n <Cloud className=\"w-6 h-6 text-[var(--color-accent-500)]\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('entra:dashboard.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:dashboard.subtitle')}\r\n </p>\r\n </div>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={handleRefresh}\r\n disabled={refreshing}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-hover)] disabled:opacity-50 transition-colors\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />\r\n {t('common:refresh')}\r\n </button>\r\n <Tooltip\r\n content={!canSync ? t('entra:dashboard.noSyncPermission') : undefined}\r\n position=\"bottom\"\r\n variant=\"error\"\r\n disabled={canSync}\r\n >\r\n <button\r\n onClick={() => handleSync('all')}\r\n disabled={syncing !== null || !canSync}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\r\n >\r\n {syncing === 'all' ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <Play className=\"w-4 h-4\" />\r\n )}\r\n {t('entra:dashboard.syncAll')}\r\n </button>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <div className=\"flex items-center gap-2 text-[var(--error-text)]\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n <span>{error}</span>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Pending Conflicts Warning */}\r\n {totalPendingConflicts > 0 && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <div className=\"flex items-center gap-2 text-[var(--warning-text)]\">\r\n <AlertCircle className=\"w-5 h-5\" />\r\n <span>\r\n {t('entra:dashboard.conflictsWarning', { count: totalPendingConflicts })}\r\n </span>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Last Sync Result */}\r\n {lastSyncResult && (\r\n <div className={`p-4 rounded-[var(--radius-card)] border ${\r\n lastSyncResult.success\r\n ? 'bg-[var(--success-bg)] border-[var(--success-border)]'\r\n : 'bg-[var(--error-bg)] border-[var(--error-border)]'\r\n }`}>\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-2\">\r\n {lastSyncResult.success ? (\r\n <CheckCircle className=\"w-5 h-5 text-[var(--success-text)]\" />\r\n ) : (\r\n <XCircle className=\"w-5 h-5 text-[var(--error-text)]\" />\r\n )}\r\n <span className={lastSyncResult.success ? 'text-[var(--success-text)]' : 'text-[var(--error-text)]'}>\r\n {lastSyncResult.success\r\n ? t('entra:dashboard.syncSuccess')\r\n : t('entra:dashboard.syncFailed')}\r\n </span>\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:dashboard.syncStats', {\r\n created: lastSyncResult.created,\r\n updated: lastSyncResult.updated,\r\n deleted: lastSyncResult.deleted,\r\n })}\r\n </div>\r\n </div>\r\n {lastSyncResult.errorMessage && (\r\n <p className=\"mt-2 text-sm text-[var(--error-text)]\">\r\n {lastSyncResult.errorMessage}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Sync Status Cards */}\r\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\r\n {syncStatus.map((status) => (\r\n <SyncStatusCard\r\n key={status.resourceType}\r\n resourceType={status.resourceType}\r\n icon={getResourceIcon(status.resourceType)}\r\n status={status.status}\r\n lastFullSyncAt={status.lastFullSyncAt}\r\n lastDeltaSyncAt={status.lastDeltaSyncAt}\r\n totalItemsSynced={status.totalItemsSynced}\r\n pendingConflicts={status.pendingConflicts}\r\n lastError={status.lastError}\r\n syncing={syncing === status.resourceType.toLowerCase()}\r\n canSync={canSync}\r\n onSync={() => handleSync(status.resourceType.toLowerCase() as 'users' | 'groups' | 'memberships')}\r\n formatDate={formatDate}\r\n t={t}\r\n />\r\n ))}\r\n </div>\r\n\r\n {/* Force Full Sync */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h3 className=\"font-semibold text-[var(--text-primary)]\">\r\n {t('entra:dashboard.forceFullSync')}\r\n </h3>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:dashboard.forceFullSyncDescription')}\r\n </p>\r\n </div>\r\n <Tooltip\r\n content={!canSync ? t('entra:dashboard.noSyncPermission') : undefined}\r\n position=\"left\"\r\n variant=\"error\"\r\n disabled={canSync}\r\n >\r\n <button\r\n onClick={handleForceFullSync}\r\n disabled={syncing !== null || !canSync}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--warning-border)] bg-[var(--warning-bg)] text-[var(--warning-text)] hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\r\n >\r\n {syncing === 'force' ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <AlertTriangle className=\"w-4 h-4\" />\r\n )}\r\n {t('entra:dashboard.forceFullSync')}\r\n </button>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Link, useNavigate } from 'react-router-dom';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport {\r\n Cloud,\r\n RefreshCw,\r\n Loader2,\r\n AlertTriangle,\r\n Search,\r\n Users,\r\n Shield,\r\n Plus,\r\n X,\r\n ChevronDown,\r\n ChevronUp,\r\n LayoutGrid,\r\n List,\r\n Filter,\r\n Building2,\r\n GitBranch,\r\n} from 'lucide-react';\r\nimport {\r\n entraApi,\r\n type EntraGroupDto,\r\n type EntraGroupMemberDto,\r\n} from '@/services/api/entraApi';\r\nimport { adminApi, type RoleListDto } from '@/services/api/adminApi';\r\nimport { useAuth } from '@/contexts/AuthContext';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\n\r\ntype ViewMode = 'cards' | 'table';\r\ntype GroupTypeFilter = 'all' | 'security' | 'distribution';\r\n\r\ninterface GroupWithMembers extends EntraGroupDto {\r\n membersLoaded?: EntraGroupMemberDto[];\r\n}\r\n\r\nconst getGroupHierarchyDisplay = (group: EntraGroupDto) => {\r\n if (group.parentGroupName) {\r\n return (\r\n <span className=\"flex items-center gap-1 text-xs\">\r\n <GitBranch className=\"w-3 h-3\" />\r\n {group.parentGroupName}\r\n </span>\r\n );\r\n }\r\n if (group.childGroupCount > 0) {\r\n return (\r\n <span className=\"flex items-center gap-1 text-xs text-[var(--text-tertiary)]\">\r\n {group.childGroupCount} child groups\r\n </span>\r\n );\r\n }\r\n return <span className=\"text-xs text-[var(--text-tertiary)]\">-</span>;\r\n};\r\n\r\nexport function EntraGroupsPage(): ReactElement {\r\n const { t } = useTranslation(['entra', 'admin', 'common']);\r\n const { hasPermission } = useAuth();\r\n const { currentTenant, isGlobalView } = useTenant();\r\n const navigate = useNavigate();\r\n const [loading, setLoading] = useState(true);\r\n const [groups, setGroups] = useState<GroupWithMembers[]>([]);\r\n const [roles, setRoles] = useState<RoleListDto[]>([]);\r\n const [error, setError] = useState<string | null>(null);\r\n const [searchQuery, setSearchQuery] = useState('');\r\n const [selectedGroup, setSelectedGroup] = useState<GroupWithMembers | null>(null);\r\n const [showAssignModal, setShowAssignModal] = useState(false);\r\n const [expandedGroupId, setExpandedGroupId] = useState<string | null>(null);\r\n const [members, setMembers] = useState<Record<string, EntraGroupMemberDto[]>>({});\r\n const [loadingMembers, setLoadingMembers] = useState<string | null>(null);\r\n const [viewMode, setViewMode] = useState<ViewMode>('cards');\r\n const [groupTypeFilter, setGroupTypeFilter] = useState<GroupTypeFilter>('all');\r\n const [assigning, setAssigning] = useState(false);\r\n\r\n const canAssign = hasPermission('administration.entra.assign');\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n setError(null);\r\n const [groupsData, rolesData] = await Promise.all([\r\n entraApi.groups.getAll(),\r\n adminApi.roles.getAssignable(),\r\n ]);\r\n setGroups(Array.isArray(groupsData) ? groupsData : []);\r\n setRoles(Array.isArray(rolesData) ? rolesData : []);\r\n } catch (err: unknown) {\r\n console.error('Failed to load Entra groups:', err);\r\n setGroups([]);\r\n setRoles([]);\r\n const axiosError = err as { response?: { status?: number; data?: { code?: string } } };\r\n if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else if (axiosError.response?.status === 403) {\r\n setError(t('common:errors.noPermission'));\r\n } else if (axiosError.response?.data?.code === 'TENANT_REQUIRED') {\r\n setError(t('entra:groups.tenantRequired'));\r\n } else {\r\n setError(t('entra:groups.loadError'));\r\n }\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [t, currentTenant?.id, isGlobalView]);\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n const loadMembers = async (groupId: string) => {\r\n if (members[groupId]) {\r\n setExpandedGroupId(expandedGroupId === groupId ? null : groupId);\r\n return;\r\n }\r\n\r\n setLoadingMembers(groupId);\r\n try {\r\n const data = await entraApi.groups.getMembers(groupId);\r\n setMembers(prev => ({ ...prev, [groupId]: data }));\r\n setExpandedGroupId(groupId);\r\n } catch (err) {\r\n console.error('Failed to load members:', err);\r\n setError(t('entra:groups.loadMembersError'));\r\n } finally {\r\n setLoadingMembers(null);\r\n }\r\n };\r\n\r\n const reloadGroupsAndRoles = useCallback(async () => {\r\n const [groupsData, rolesData] = await Promise.all([\r\n entraApi.groups.getAll(),\r\n adminApi.roles.getAssignable(),\r\n ]);\r\n const safeGroupsData = Array.isArray(groupsData) ? groupsData : [];\r\n setGroups(safeGroupsData);\r\n setRoles(Array.isArray(rolesData) ? rolesData : []);\r\n return safeGroupsData;\r\n }, [currentTenant?.id]);\r\n\r\n const handleAssignRole = async (roleId: string, isInheritable: boolean = true) => {\r\n if (!selectedGroup) return;\r\n setAssigning(true);\r\n try {\r\n await entraApi.groups.assignRole(selectedGroup.id, { roleId, isInheritable });\r\n const safeGroupsData = await reloadGroupsAndRoles();\r\n const updatedGroup = safeGroupsData.find(g => g.id === selectedGroup.id);\r\n if (updatedGroup) setSelectedGroup(updatedGroup);\r\n } catch (err) {\r\n console.error('Failed to assign role:', err);\r\n setError(t('entra:groups.assignError'));\r\n } finally {\r\n setAssigning(false);\r\n }\r\n };\r\n\r\n const handleRemoveRole = async (groupId: string, roleId: string) => {\r\n if (!confirm(t('entra:groups.removeRoleConfirm'))) return;\r\n try {\r\n await entraApi.groups.removeRole(groupId, roleId);\r\n await reloadGroupsAndRoles();\r\n if (selectedGroup?.id === groupId) {\r\n const updatedGroups = await entraApi.groups.getAll();\r\n const updatedGroup = updatedGroups.find(g => g.id === groupId);\r\n if (updatedGroup) setSelectedGroup(updatedGroup);\r\n }\r\n } catch (err) {\r\n console.error('Failed to remove role:', err);\r\n setError(t('entra:groups.removeError'));\r\n }\r\n };\r\n\r\n const filteredGroups = groups.filter((g) => {\r\n const matchesSearch =\r\n g.displayName.toLowerCase().includes(searchQuery.toLowerCase()) ||\r\n g.description?.toLowerCase().includes(searchQuery.toLowerCase());\r\n\r\n const matchesType =\r\n groupTypeFilter === 'all' ||\r\n (groupTypeFilter === 'security' && g.isSecurityGroup) ||\r\n (groupTypeFilter === 'distribution' && !g.isSecurityGroup);\r\n\r\n return matchesSearch && matchesType;\r\n });\r\n\r\n const formatDate = (date: string | null) => {\r\n if (!date) return '-';\r\n return new Intl.DateTimeFormat('fr-FR', {\r\n dateStyle: 'medium',\r\n timeStyle: 'short',\r\n }).format(new Date(date));\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-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title'), href: '/administration' },\r\n { label: t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: t('entra.groups', 'Groups') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-blue-500/10\">\r\n <Cloud className=\"w-6 h-6 text-blue-500\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('entra:groups.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:groups.subtitle', { count: groups.length })}\r\n </p>\r\n </div>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={loadData}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common:refresh')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Info banner */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-blue-500/10 border border-blue-500/20\">\r\n <div className=\"flex items-start gap-3\">\r\n <Cloud className=\"w-5 h-5 text-blue-500 flex-shrink-0 mt-0.5\" />\r\n <div>\r\n <p className=\"text-sm text-[var(--text-primary)]\">\r\n {t('entra:groups.syncedInfo')}\r\n </p>\r\n <p className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n {t('entra:groups.syncedInfoDescription')}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <div className=\"flex items-center gap-2 text-[var(--error-text)]\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n <span>{error}</span>\r\n <button\r\n onClick={() => setError(null)}\r\n className=\"ml-auto p-1 hover:bg-[var(--error-text)]/10 rounded\"\r\n >\r\n <X className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Search & Filters */}\r\n <div className=\"flex flex-col sm:flex-row gap-4\">\r\n {/* Search */}\r\n <div className=\"relative flex-1\">\r\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-[var(--text-tertiary)]\" />\r\n <input\r\n type=\"text\"\r\n placeholder={t('entra:groups.searchPlaceholder')}\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n className=\"w-full pl-10 pr-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n\r\n {/* Type Filter */}\r\n <div className=\"flex items-center gap-2\">\r\n <Filter className=\"w-4 h-4 text-[var(--text-tertiary)]\" />\r\n <select\r\n value={groupTypeFilter}\r\n onChange={(e) => setGroupTypeFilter(e.target.value as GroupTypeFilter)}\r\n className=\"px-3 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('admin:groups.allTypes')}</option>\r\n <option value=\"security\">{t('admin:groups.securityGroup')}</option>\r\n <option value=\"distribution\">{t('admin:groups.distributionGroup')}</option>\r\n </select>\r\n </div>\r\n\r\n {/* View Mode Toggle */}\r\n <div className=\"flex items-center gap-1 p-1 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] border border-[var(--border-color)]\">\r\n <button\r\n onClick={() => setViewMode('cards')}\r\n className={`p-2 rounded-[var(--radius-button)] transition-colors ${\r\n viewMode === 'cards'\r\n ? 'bg-[var(--color-accent-500)] text-white'\r\n : 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n title={t('admin:groups.cardView')}\r\n >\r\n <LayoutGrid className=\"w-4 h-4\" />\r\n </button>\r\n <button\r\n onClick={() => setViewMode('table')}\r\n className={`p-2 rounded-[var(--radius-button)] transition-colors ${\r\n viewMode === 'table'\r\n ? 'bg-[var(--color-accent-500)] text-white'\r\n : 'text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n title={t('admin:groups.tableView')}\r\n >\r\n <List className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Groups List */}\r\n {filteredGroups.length === 0 && (\r\n <div className=\"text-center py-12 text-[var(--text-secondary)]\">\r\n {searchQuery || groupTypeFilter !== 'all'\r\n ? t('admin:groups.noResults')\r\n : t('entra:groups.noGroups')}\r\n </div>\r\n )}\r\n {filteredGroups.length > 0 && viewMode === 'table' && (\r\n /* Table View */\r\n <div className=\"rounded-[var(--radius-card)] border border-[var(--border-color)] overflow-hidden\">\r\n <table className=\"w-full\">\r\n <thead className=\"bg-[var(--bg-secondary)]\">\r\n <tr>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:groups.groupName')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('common:type')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:groups.members')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('entra:groups.hierarchy')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:groups.assignedRoles')}\r\n </th>\r\n <th className=\"px-4 py-3 text-left text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('entra:groups.lastSynced')}\r\n </th>\r\n {canAssign && !isGlobalView && (\r\n <th className=\"px-4 py-3 text-right text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('common:actionsColumn')}\r\n </th>\r\n )}\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--border-color)]\">\r\n {filteredGroups.map((group) => (\r\n <tr\r\n key={group.id}\r\n className=\"hover:bg-[var(--bg-hover)] cursor-pointer\"\r\n onClick={() => navigate(`/administration/users/groups/${group.id}`)}\r\n >\r\n <td className=\"px-4 py-3\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className={`w-8 h-8 rounded-full flex items-center justify-center ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-purple-500/10 text-purple-500'\r\n }`}>\r\n {group.isSecurityGroup ? (\r\n <Shield className=\"w-4 h-4\" />\r\n ) : (\r\n <Building2 className=\"w-4 h-4\" />\r\n )}\r\n </div>\r\n <div>\r\n <span className=\"font-medium text-[var(--text-primary)]\">{group.displayName}</span>\r\n {group.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] truncate max-w-xs\">\r\n {group.description}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <span className={`px-2 py-1 text-xs rounded-[var(--radius-badge)] ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-purple-500/10 text-purple-500'\r\n }`}>\r\n {group.isSecurityGroup ? t('admin:groups.securityGroup') : t('admin:groups.distributionGroup')}\r\n </span>\r\n </td>\r\n <td className=\"px-4 py-3 text-sm text-[var(--text-secondary)]\">\r\n <span className=\"flex items-center gap-1\">\r\n <Users className=\"w-4 h-4\" />\r\n {group.memberCount}\r\n </span>\r\n </td>\r\n <td className=\"px-4 py-3 text-sm text-[var(--text-secondary)]\">\r\n {getGroupHierarchyDisplay(group)}\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <div className=\"flex flex-wrap gap-1\">\r\n {group.assignedRoles.slice(0, 2).map((role) => (\r\n <span\r\n key={role.roleId}\r\n className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]\"\r\n >\r\n {role.roleName}\r\n </span>\r\n ))}\r\n {group.assignedRoles.length > 2 && (\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--bg-tertiary)] text-[var(--text-tertiary)]\">\r\n +{group.assignedRoles.length - 2}\r\n </span>\r\n )}\r\n {group.inheritedRoles.length > 0 && (\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-green-500/10 text-green-600\" title={t('entra:groups.inheritedRoles')}>\r\n +{group.inheritedRoles.length} {t('entra:groups.inherited')}\r\n </span>\r\n )}\r\n </div>\r\n </td>\r\n <td className=\"px-4 py-3 text-xs text-[var(--text-tertiary)]\">\r\n {formatDate(group.lastSyncedAt)}\r\n </td>\r\n {canAssign && !isGlobalView && (\r\n <td className=\"px-4 py-3 text-right\" onClick={(e) => e.stopPropagation()}>\r\n <button\r\n onClick={() => {\r\n setSelectedGroup(group);\r\n setShowAssignModal(true);\r\n }}\r\n className=\"p-2 rounded-[var(--radius-button)] text-[var(--text-tertiary)] hover:text-[var(--color-accent-500)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n title={t('admin:groups.assignRole')}\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n </button>\r\n </td>\r\n )}\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n )}\r\n {filteredGroups.length > 0 && viewMode !== 'table' && (\r\n /* Cards View */\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n {filteredGroups.map((group) => (\r\n <button\r\n type=\"button\"\r\n key={group.id}\r\n className=\"rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-secondary)] overflow-hidden cursor-pointer hover:border-[var(--color-accent-500)] transition-colors text-left\"\r\n onClick={() => navigate(`/administration/users/groups/${group.id}`)}\r\n >\r\n {/* Card Header */}\r\n <div className=\"p-4\">\r\n <div className=\"flex items-start justify-between gap-4\">\r\n <div className=\"flex items-start gap-3 min-w-0\">\r\n <div className={`p-2.5 rounded-[var(--radius-button)] flex-shrink-0 ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-purple-500/10 text-purple-500'\r\n }`}>\r\n {group.isSecurityGroup ? (\r\n <Shield className=\"w-5 h-5\" />\r\n ) : (\r\n <Building2 className=\"w-5 h-5\" />\r\n )}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <div className=\"flex items-center gap-2 flex-wrap\">\r\n <span className=\"font-semibold text-[var(--text-primary)] truncate\">\r\n {group.displayName}\r\n </span>\r\n <span className={`px-2 py-0.5 text-xs rounded-[var(--radius-badge)] ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500 border border-blue-500/20'\r\n : 'bg-purple-500/10 text-purple-500 border border-purple-500/20'\r\n }`}>\r\n {group.isSecurityGroup ? t('admin:groups.securityGroup') : t('admin:groups.distributionGroup')}\r\n </span>\r\n {!group.isActive && (\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--warning-bg)] text-[var(--warning-text)] border border-[var(--warning-border)]\">\r\n {t('common:inactive')}\r\n </span>\r\n )}\r\n </div>\r\n {group.description && (\r\n <p className=\"text-sm text-[var(--text-secondary)] mt-1 line-clamp-2\">\r\n {group.description}\r\n </p>\r\n )}\r\n <div className=\"flex items-center gap-4 mt-2 text-sm text-[var(--text-tertiary)] flex-wrap\">\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n loadMembers(group.id);\r\n }}\r\n className=\"flex items-center gap-1 hover:text-[var(--color-accent-500)] transition-colors\"\r\n >\r\n <Users className=\"w-4 h-4\" />\r\n {t('admin:groups.memberCount', { count: group.memberCount })}\r\n {loadingMembers === group.id && (\r\n <Loader2 className=\"w-3 h-3 animate-spin ml-1\" />\r\n )}\r\n {loadingMembers !== group.id && expandedGroupId === group.id && (\r\n <ChevronUp className=\"w-3 h-3 ml-1\" />\r\n )}\r\n {loadingMembers !== group.id && expandedGroupId !== group.id && (\r\n <ChevronDown className=\"w-3 h-3 ml-1\" />\r\n )}\r\n </button>\r\n {group.childGroupCount > 0 && (\r\n <span className=\"flex items-center gap-1 text-xs\">\r\n <GitBranch className=\"w-3 h-3\" />\r\n {group.childGroupCount} {t('entra:groups.childGroups')}\r\n </span>\r\n )}\r\n </div>\r\n {group.parentGroupName && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1 flex items-center gap-1\">\r\n <GitBranch className=\"w-3 h-3\" />\r\n {t('entra:groups.parentGroup')}: {group.parentGroupName}\r\n </p>\r\n )}\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-1\">\r\n {t('entra:groups.lastSynced')}: {formatDate(group.lastSyncedAt)}\r\n </p>\r\n </div>\r\n </div>\r\n {canAssign && !isGlobalView && (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n setSelectedGroup(group);\r\n setShowAssignModal(true);\r\n }}\r\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors flex-shrink-0\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:groups.assignRole')}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* Assigned Roles */}\r\n {(group.assignedRoles.length > 0 || group.inheritedRoles.length > 0) && (\r\n <div className=\"mt-4 pt-4 border-t border-[var(--border-color)]\">\r\n {group.assignedRoles.length > 0 && (\r\n <>\r\n <h4 className=\"text-sm font-medium text-[var(--text-primary)] mb-2\">\r\n {t('admin:groups.assignedRoles')}\r\n </h4>\r\n <div className=\"flex flex-wrap gap-2 mb-3\">\r\n {group.assignedRoles.map((role) => (\r\n <div\r\n key={role.roleId}\r\n className=\"inline-flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-badge)] bg-[var(--bg-primary)] border border-[var(--border-color)] group\"\r\n >\r\n <Shield className=\"w-4 h-4 text-[var(--color-accent-500)]\" />\r\n <span className=\"text-sm text-[var(--text-primary)]\">{role.roleName}</span>\r\n {role.isInheritable && (\r\n <span className=\"text-xs text-green-600\" title={t('entra:groups.inheritableRole')}>\r\n ↓\r\n </span>\r\n )}\r\n {canAssign && (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n handleRemoveRole(group.id, role.roleId);\r\n }}\r\n className=\"ml-1 p-0.5 rounded opacity-0 group-hover:opacity-100 hover:bg-[var(--error-bg)] text-[var(--text-tertiary)] hover:text-[var(--error-text)] transition-all\"\r\n title={t('common:remove')}\r\n >\r\n <X className=\"w-3 h-3\" />\r\n </button>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n </>\r\n )}\r\n {group.inheritedRoles.length > 0 && (\r\n <>\r\n <h4 className=\"text-xs font-medium text-[var(--text-tertiary)] mb-2 flex items-center gap-1\">\r\n <GitBranch className=\"w-3 h-3\" />\r\n {t('entra:groups.inheritedRoles')}\r\n </h4>\r\n <div className=\"flex flex-wrap gap-2\">\r\n {group.inheritedRoles.map((role) => (\r\n <div\r\n key={`${role.roleId}-${role.sourceGroupId}`}\r\n className=\"inline-flex items-center gap-2 px-2 py-1 rounded-[var(--radius-badge)] bg-green-500/5 border border-green-500/20\"\r\n title={`${t('entra:groups.inheritedFrom')} ${role.sourceGroupName}`}\r\n >\r\n <Shield className=\"w-3 h-3 text-green-600\" />\r\n <span className=\"text-xs text-green-700\">{role.roleName}</span>\r\n <span className=\"text-xs text-green-600/60\">← {role.sourceGroupName}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Members Panel */}\r\n {expandedGroupId === group.id && members[group.id] && (\r\n <div className=\"border-t border-[var(--border-color)] bg-[var(--bg-primary)]\" onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} role=\"presentation\">\r\n <div className=\"p-4\">\r\n <h4 className=\"text-sm font-medium text-[var(--text-primary)] mb-3 flex items-center gap-2\">\r\n <Users className=\"w-4 h-4\" />\r\n {t('admin:groups.members')} ({members[group.id].length})\r\n </h4>\r\n {members[group.id].length === 0 ? (\r\n <p className=\"text-sm text-[var(--text-tertiary)]\">\r\n {t('admin:groups.noMembers')}\r\n </p>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-2 max-h-64 overflow-y-auto\">\r\n {members[group.id].slice(0, 10).map((member) => (\r\n <Link\r\n key={member.userId}\r\n to={`/administration/users/${member.userId}`}\r\n className=\"flex items-center gap-3 p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <div className=\"w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]\">\r\n {member.fullName.charAt(0).toUpperCase()}\r\n </div>\r\n <div className=\"min-w-0 flex-1\">\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate\">\r\n {member.fullName}\r\n </p>\r\n <p className=\"text-xs text-[var(--text-tertiary)] truncate\">\r\n {member.email}\r\n </p>\r\n </div>\r\n {!member.isDirect && member.sourceGroupName && (\r\n <span className=\"text-xs text-[var(--text-tertiary)] flex items-center gap-1\" title={t('entra:groups.memberFromChildGroup')}>\r\n <GitBranch className=\"w-3 h-3\" />\r\n </span>\r\n )}\r\n </Link>\r\n ))}\r\n </div>\r\n )}\r\n {members[group.id].length > 10 && (\r\n <p className=\"mt-3 text-center text-sm text-[var(--text-tertiary)]\">\r\n {t('admin:groups.showingMembers', {\r\n shown: 10,\r\n total: members[group.id].length,\r\n })}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </button>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Assign Role Modal */}\r\n {showAssignModal && selectedGroup && (\r\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\r\n <div className=\"w-full max-w-md rounded-[var(--radius-card)] bg-[var(--bg-secondary)] border border-[var(--border-color)] shadow-xl\">\r\n <div className=\"flex items-center justify-between p-4 border-b border-[var(--border-color)]\">\r\n <h2 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('admin:groups.assignRoleTitle')}\r\n </h2>\r\n <button\r\n onClick={() => {\r\n setShowAssignModal(false);\r\n setSelectedGroup(null);\r\n }}\r\n className=\"p-1 rounded hover:bg-[var(--bg-hover)] text-[var(--text-tertiary)]\"\r\n >\r\n <X className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n <div className=\"p-4\">\r\n <p className=\"text-sm text-[var(--text-secondary)] mb-4\">\r\n {t('admin:groups.assignRoleDescription', { group: selectedGroup.displayName })}\r\n </p>\r\n <div className=\"space-y-2 max-h-64 overflow-y-auto\">\r\n {roles\r\n .filter((role) => !selectedGroup.assignedRoles.some(r => r.roleId === role.id))\r\n .map((role) => (\r\n <button\r\n key={role.id}\r\n onClick={() => handleAssignRole(role.id)}\r\n disabled={assigning}\r\n className=\"w-full flex items-center gap-3 p-3 rounded-[var(--radius-button)] border border-[var(--border-color)] hover:border-[var(--color-accent-500)] hover:bg-[var(--bg-hover)] transition-colors text-left disabled:opacity-50\"\r\n >\r\n <Shield className=\"w-5 h-5 text-[var(--color-accent-500)]\" />\r\n <div className=\"flex-1\">\r\n <p className=\"font-medium text-[var(--text-primary)]\">{role.name}</p>\r\n {role.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{role.description}</p>\r\n )}\r\n </div>\r\n {assigning && (\r\n <Loader2 className=\"w-4 h-4 animate-spin text-[var(--color-accent-500)]\" />\r\n )}\r\n </button>\r\n ))}\r\n {roles.filter((role) => !selectedGroup.assignedRoles.some(r => r.roleId === role.id)).length === 0 && (\r\n <p className=\"text-sm text-[var(--text-tertiary)] text-center py-4\">\r\n {t('admin:groups.allRolesAssigned')}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport {\r\n Users,\r\n RefreshCw,\r\n AlertTriangle,\r\n CheckCircle,\r\n XCircle,\r\n Mail,\r\n Calendar,\r\n ExternalLink,\r\n} from 'lucide-react';\r\nimport { adminApi, type UserListDto } from '@/services/api/adminApi';\r\nimport { DataTable, type DataTableColumn } from '@/components/ui/DataTable';\r\n\r\nexport function EntraUsersPage(): ReactElement {\r\n const { t } = useTranslation(['entra', 'common']);\r\n const navigate = useNavigate();\r\n const [loading, setLoading] = useState(true);\r\n const [users, setUsers] = useState<UserListDto[]>([]);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const loadData = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n setError(null);\r\n // Only fetch users synced from Entra ID (have entraObjectId)\r\n const response = await adminApi.users.getAll({ pageSize: 1000, entraOnly: true });\r\n setUsers(response?.items ?? []);\r\n } catch (err: unknown) {\r\n console.error('Failed to load users:', err);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else if (axiosError.response?.status === 403) {\r\n setError(t('common:errors.noPermission'));\r\n } else {\r\n setError(t('entra:users.loadError'));\r\n }\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [t]);\r\n\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n const formatDate = (date: string | null) => {\r\n if (!date) return t('common:never');\r\n return new Intl.DateTimeFormat('fr-FR', {\r\n dateStyle: 'medium',\r\n timeStyle: 'short',\r\n }).format(new Date(date));\r\n };\r\n\r\n // Define columns for DataTable\r\n const columns: DataTableColumn<UserListDto>[] = [\r\n {\r\n key: 'fullName',\r\n label: t('entra:users.columns.user'),\r\n sortable: true,\r\n render: (user) => (\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"w-10 h-10 rounded-full bg-[var(--color-primary-100)] dark:bg-[var(--color-primary-900)] flex items-center justify-center flex-shrink-0\">\r\n <span className=\"text-sm font-medium text-[var(--color-primary-600)]\">\r\n {user.fullName?.charAt(0).toUpperCase() || '?'}\r\n </span>\r\n </div>\r\n <span className=\"font-medium text-[var(--text-primary)]\">{user.fullName}</span>\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'email',\r\n label: t('entra:users.columns.email'),\r\n sortable: true,\r\n render: (user) => (\r\n <div className=\"flex items-center gap-1 text-sm text-[var(--text-secondary)]\">\r\n <Mail className=\"w-4 h-4\" />\r\n {user.email}\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'isActive',\r\n label: t('entra:users.columns.status'),\r\n sortable: true,\r\n render: (user) =>\r\n user.isActive ? (\r\n <span className=\"inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400\">\r\n <CheckCircle className=\"w-3 h-3\" />\r\n {t('common:active')}\r\n </span>\r\n ) : (\r\n <span className=\"inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400\">\r\n <XCircle className=\"w-3 h-3\" />\r\n {t('common:inactive')}\r\n </span>\r\n ),\r\n },\r\n {\r\n key: 'lastEntraSyncAt',\r\n label: t('entra:users.columns.lastSync'),\r\n sortable: true,\r\n render: (user) => (\r\n <div className=\"flex items-center gap-1 text-sm text-[var(--text-secondary)]\">\r\n <Calendar className=\"w-4 h-4\" />\r\n {formatDate(user.lastEntraSyncAt)}\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'actions',\r\n label: t('entra:users.columns.actions'),\r\n align: 'right',\r\n render: (user) => (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n navigate(`/administration/users/${user.id}`);\r\n }}\r\n className=\"inline-flex items-center gap-1 text-sm text-[var(--color-primary-600)] hover:underline\"\r\n >\r\n {t('common:viewDetails')}\r\n <ExternalLink className=\"w-4 h-4\" />\r\n </button>\r\n ),\r\n },\r\n ];\r\n\r\n // Custom search filter for users\r\n const searchFilter = (user: UserListDto, searchTerm: string) => {\r\n const search = searchTerm.toLowerCase();\r\n return (\r\n user.fullName?.toLowerCase().includes(search) ||\r\n user.email?.toLowerCase().includes(search) ||\r\n false\r\n );\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title'), href: '/administration' },\r\n { label: t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: t('entra.users', 'Users') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-lg bg-[var(--color-primary-100)] dark:bg-[var(--color-primary-900)]\">\r\n <Users className=\"w-6 h-6 text-[var(--color-primary-600)]\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('entra:users.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:users.subtitle', { count: users.length })}\r\n </p>\r\n </div>\r\n </div>\r\n <button\r\n onClick={loadData}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg border border-[var(--border-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] hover:bg-[var(--bg-secondary)]\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common:refresh')}\r\n </button>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"p-4 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800\">\r\n <div className=\"flex items-center gap-2 text-red-700 dark:text-red-400\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n <span>{error}</span>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* DataTable */}\r\n <DataTable\r\n data={users}\r\n columns={columns}\r\n loading={loading}\r\n searchable\r\n searchPlaceholder={t('entra:users.searchPlaceholder')}\r\n searchFilter={searchFilter}\r\n pagination={{ pageSize: 20, showSizeSelector: true }}\r\n onRowClick={(user) => navigate(`/administration/users/${user.id}`)}\r\n getRowKey={(user) => user.id}\r\n emptyMessage={t('entra:users.noUsers')}\r\n emptyIcon={<Users className=\"w-12 h-12 mx-auto text-[var(--text-secondary)] opacity-50\" />}\r\n defaultSortKey=\"fullName\"\r\n striped\r\n />\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport {\r\n AlertTriangle,\r\n RefreshCw,\r\n Loader2,\r\n CheckCircle,\r\n} from 'lucide-react';\r\nimport {\r\n entraApi,\r\n type EntraSyncConflictDto,\r\n type ResolveConflictRequest,\r\n} from '@/services/api/entraApi';\r\nimport { ConflictCard, ResolutionModal } from '@/components/platform/administration/entra';\r\n\r\n// ============================================\r\n// Main Component\r\n// ============================================\r\n\r\nexport function EntraConflictsPage(): ReactElement {\r\n const { t } = useTranslation(['entra', 'common']);\r\n const [loading, setLoading] = useState(true);\r\n const [conflicts, setConflicts] = useState<EntraSyncConflictDto[]>([]);\r\n const [error, setError] = useState<string | null>(null);\r\n const [selectedConflict, setSelectedConflict] = useState<EntraSyncConflictDto | null>(null);\r\n const [resolving, setResolving] = useState(false);\r\n\r\n // Abort controller ref for preventing race conditions\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n const isLoadingRef = useRef(false);\r\n\r\n const loadData = useCallback(async () => {\r\n // Prevent concurrent loads\r\n if (isLoadingRef.current) return;\r\n\r\n // Cancel any pending request\r\n if (abortControllerRef.current) {\r\n abortControllerRef.current.abort();\r\n }\r\n\r\n abortControllerRef.current = new AbortController();\r\n isLoadingRef.current = true;\r\n\r\n try {\r\n setError(null);\r\n const data = await entraApi.conflicts.getAll();\r\n setConflicts(Array.isArray(data) ? data : []);\r\n } catch (err: unknown) {\r\n // Ignore abort errors\r\n if (err instanceof Error && err.name === 'AbortError') {\r\n return;\r\n }\r\n // Log error type only, not the full error object (PII protection)\r\n console.error('Failed to load conflicts:', err instanceof Error ? err.message : 'Unknown error');\r\n setConflicts([]);\r\n const axiosError = err as { response?: { status?: number } };\r\n if (axiosError.response?.status === 401) {\r\n setError(t('common:errors.sessionExpired'));\r\n } else if (axiosError.response?.status === 403) {\r\n setError(t('common:errors.noPermission'));\r\n } else {\r\n setError(t('entra:conflicts.loadError'));\r\n }\r\n } finally {\r\n isLoadingRef.current = false;\r\n setLoading(false);\r\n }\r\n }, [t]);\r\n\r\n useEffect(() => {\r\n loadData();\r\n\r\n // Cleanup on unmount\r\n return () => {\r\n if (abortControllerRef.current) {\r\n abortControllerRef.current.abort();\r\n }\r\n };\r\n }, [loadData]);\r\n\r\n const handleResolve = useCallback(async (resolution: ResolveConflictRequest['resolution'], notes?: string) => {\r\n if (!selectedConflict || resolving) return;\r\n\r\n setResolving(true);\r\n try {\r\n await entraApi.conflicts.resolve(selectedConflict.id, {\r\n resolution,\r\n notes: notes || undefined,\r\n });\r\n setSelectedConflict(null);\r\n await loadData();\r\n } catch (err) {\r\n // Log error type only, not the full error object (PII protection)\r\n console.error('Failed to resolve conflict:', err instanceof Error ? err.message : 'Unknown error');\r\n setError(t('entra:conflicts.resolveError'));\r\n } finally {\r\n setResolving(false);\r\n }\r\n }, [selectedConflict, resolving, loadData, t]);\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-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title'), href: '/administration' },\r\n { label: t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: t('entra.conflicts', 'Conflicts') }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-[var(--color-accent-500)]/10\">\r\n <AlertTriangle className=\"w-6 h-6 text-[var(--color-accent-600)]\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('entra:conflicts.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('entra:conflicts.subtitle', { count: conflicts.length })}\r\n </p>\r\n </div>\r\n </div>\r\n <button\r\n onClick={loadData}\r\n disabled={loading}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors disabled:opacity-50\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />\r\n {t('common:refresh')}\r\n </button>\r\n </div>\r\n\r\n {/* Error */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-2 text-[var(--error-text)]\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n <span>{error}</span>\r\n </div>\r\n <button\r\n onClick={() => setError(null)}\r\n className=\"text-[var(--error-text)] hover:opacity-70\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* No Conflicts - Empty State */}\r\n {conflicts.length === 0 ? (\r\n <div className=\"text-center py-16 px-6 rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-card)]\">\r\n <div className=\"mx-auto w-16 h-16 rounded-full bg-[var(--success-bg)] flex items-center justify-center mb-4\">\r\n <CheckCircle className=\"w-8 h-8 text-[var(--success-text)]\" />\r\n </div>\r\n <h2 className=\"text-xl font-semibold text-[var(--text-primary)] mb-2\">\r\n {t('entra:conflicts.noConflicts')}\r\n </h2>\r\n <p className=\"text-[var(--text-secondary)] max-w-md mx-auto\">\r\n {t('entra:conflicts.noConflictsDescription')}\r\n </p>\r\n </div>\r\n ) : (\r\n /* Conflicts Grid */\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {conflicts.map((conflict) => (\r\n <ConflictCard\r\n key={conflict.id}\r\n conflict={conflict}\r\n onResolve={setSelectedConflict}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Resolve Modal */}\r\n {selectedConflict && (\r\n <ResolutionModal\r\n conflict={selectedConflict}\r\n onClose={() => setSelectedConflict(null)}\r\n onResolve={handleResolve}\r\n resolving={resolving}\r\n />\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback, type ReactNode } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport type { LucideIcon } from 'lucide-react';\r\nimport {\r\n Settings,\r\n Key,\r\n Eye,\r\n EyeOff,\r\n Save,\r\n AlertTriangle,\r\n CheckCircle,\r\n ExternalLink,\r\n Shield,\r\n Clock,\r\n Loader2,\r\n TestTube,\r\n Users,\r\n Layers,\r\n Building2,\r\n Copy,\r\n Check,\r\n GitMerge,\r\n Filter,\r\n} from 'lucide-react';\r\nimport { entraApi } from '@/services/api/entraApi';\r\nimport type { TestConnectionResult, EntraConfigurationDto } from '@/services/api/entraApi';\r\n\r\ninterface EntraCredentials {\r\n tenantId: string;\r\n clientId: string;\r\n clientSecret: string;\r\n}\r\n\r\ninterface SyncSettings {\r\n syncEnabled: boolean;\r\n syncIntervalMinutes: number;\r\n useDeltaSync: boolean;\r\n defaultConflictResolution: 'ManualReview' | 'EntraWins' | 'LocalWins';\r\n autoCreateReferences: boolean;\r\n // User sync filters\r\n syncOnlyActiveUsers: boolean;\r\n syncUserTypes: string; // comma-separated: member, guest, shared, room, equipment\r\n}\r\n\r\n// Available user types for sync\r\n// Note: shared, room, equipment require mailboxSettings which is not available in bulk user listing API\r\nconst USER_TYPES = [\r\n { id: 'member', labelKey: 'userTypes.member', descriptionKey: 'userTypes.memberDescription', supported: true },\r\n { id: 'guest', labelKey: 'userTypes.guest', descriptionKey: 'userTypes.guestDescription', supported: true },\r\n { id: 'shared', labelKey: 'userTypes.shared', descriptionKey: 'userTypes.sharedDescription', supported: false },\r\n { id: 'room', labelKey: 'userTypes.room', descriptionKey: 'userTypes.roomDescription', supported: false },\r\n { id: 'equipment', labelKey: 'userTypes.equipment', descriptionKey: 'userTypes.equipmentDescription', supported: false },\r\n];\r\n\r\n// Required permissions for Microsoft Graph API\r\nconst REQUIRED_PERMISSIONS = [\r\n { code: 'User.Read.All', descriptionKey: 'userReadAll' },\r\n { code: 'Group.Read.All', descriptionKey: 'groupReadAll' },\r\n { code: 'GroupMember.Read.All', descriptionKey: 'groupMemberReadAll' },\r\n];\r\n\r\n// ============================================\r\n// Reusable Components\r\n// ============================================\r\n\r\ninterface SectionCardProps {\r\n readonly icon: LucideIcon;\r\n readonly title: string;\r\n readonly description?: string;\r\n readonly action?: ReactNode;\r\n readonly children: ReactNode;\r\n readonly className?: string;\r\n}\r\n\r\nfunction SectionCard({ icon: Icon, title, description, action, children, className = '' }: SectionCardProps) {\r\n return (\r\n <div className={`rounded-[var(--radius-card)] border border-[var(--border-color)] bg-[var(--bg-card)] shadow-sm overflow-hidden ${className}`}>\r\n {/* Header */}\r\n <div className=\"px-6 py-4 border-b border-[var(--border-subtle)] bg-[var(--bg-secondary)]\">\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-[var(--color-accent-100)] dark:bg-[var(--color-accent-900)]/30\">\r\n <Icon className=\"w-5 h-5 text-[var(--color-accent-500)]\" />\r\n </div>\r\n <div>\r\n <h2 className=\"text-base font-semibold text-[var(--text-primary)]\">{title}</h2>\r\n {description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5\">{description}</p>\r\n )}\r\n </div>\r\n </div>\r\n {action}\r\n </div>\r\n </div>\r\n {/* Content */}\r\n <div className=\"p-6\">\r\n {children}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\ninterface ToggleProps {\r\n readonly checked: boolean;\r\n readonly onChange: () => void;\r\n readonly label: string;\r\n readonly description?: string;\r\n}\r\n\r\nfunction Toggle({ checked, onChange, label, description }: ToggleProps) {\r\n return (\r\n <div className=\"flex items-center justify-between py-3\">\r\n <div className=\"flex-1 min-w-0 pr-4\">\r\n <label className=\"text-sm font-medium text-[var(--text-primary)]\">{label}</label>\r\n {description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5\">{description}</p>\r\n )}\r\n </div>\r\n <button\r\n type=\"button\"\r\n role=\"switch\"\r\n aria-checked={checked}\r\n onClick={onChange}\r\n className={`relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] focus:ring-offset-2 focus:ring-offset-[var(--bg-primary)] ${\r\n checked ? 'bg-[var(--color-accent-600)]' : 'bg-[var(--bg-tertiary)]'\r\n }`}\r\n >\r\n <span\r\n className={`inline-block h-4 w-4 transform rounded-full bg-[var(--toggle-knob)] shadow-md transition-transform ${\r\n checked ? 'translate-x-6' : 'translate-x-1'\r\n }`}\r\n />\r\n </button>\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================\r\n// Validation\r\n// ============================================\r\n\r\nconst isValidGuid = (value: string): boolean => {\r\n if (!value) return true;\r\n const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\r\n return guidRegex.test(value);\r\n};\r\n\r\nconst useEntraSettings = () => {\r\n const { t } = useTranslation(['entra', 'common']);\r\n const [loading, setLoading] = useState(true);\r\n const [saving, setSaving] = useState(false);\r\n const [testing, setTesting] = useState(false);\r\n const [testResult, setTestResult] = useState<TestConnectionResult | null>(null);\r\n const [showSecret, setShowSecret] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState<string | null>(null);\r\n const [hasExistingSecret, setHasExistingSecret] = useState(false);\r\n const [copiedPermission, setCopiedPermission] = useState<string | null>(null);\r\n const [validationErrors, setValidationErrors] = useState<{\r\n tenantId?: string;\r\n clientId?: string;\r\n }>({});\r\n\r\n const [credentials, setCredentials] = useState<EntraCredentials>({\r\n tenantId: '',\r\n clientId: '',\r\n clientSecret: '',\r\n });\r\n\r\n const [syncSettings, setSyncSettings] = useState<SyncSettings>({\r\n syncEnabled: false,\r\n syncIntervalMinutes: 60,\r\n useDeltaSync: true,\r\n defaultConflictResolution: 'ManualReview',\r\n autoCreateReferences: true,\r\n syncOnlyActiveUsers: true,\r\n syncUserTypes: 'member',\r\n });\r\n\r\n return {\r\n t, loading, setLoading, saving, setSaving, testing, setTesting,\r\n testResult, setTestResult, showSecret, setShowSecret, error, setError,\r\n success, setSuccess, hasExistingSecret, setHasExistingSecret,\r\n copiedPermission, setCopiedPermission, validationErrors, setValidationErrors,\r\n credentials, setCredentials, syncSettings, setSyncSettings\r\n };\r\n};\r\n\r\n// ============================================\r\n// Helpers\r\n// ============================================\r\n\r\nfunction getCheckboxCardClass(isDisabled: boolean, isChecked: boolean): string {\r\n if (isDisabled) return 'opacity-50 cursor-not-allowed border-[var(--border-color)] bg-[var(--bg-tertiary)]';\r\n if (isChecked) return 'cursor-pointer border-[var(--color-accent-500)] bg-[var(--color-accent-50)] dark:bg-[var(--color-accent-900)]/20';\r\n return 'cursor-pointer border-[var(--border-color)] bg-[var(--bg-secondary)] hover:bg-[var(--bg-tertiary)]';\r\n}\r\n\r\n// ============================================\r\n// Main Component\r\n// ============================================\r\n\r\nexport function EntraSettingsPage(): ReactElement {\r\n const state = useEntraSettings();\r\n\r\n const loadConfiguration = useCallback(async () => {\r\n try {\r\n state.setLoading(true);\r\n const config: EntraConfigurationDto = await entraApi.settings.getConfiguration();\r\n\r\n state.setCredentials({\r\n tenantId: config.tenantId || '',\r\n clientId: config.clientId || '',\r\n clientSecret: '',\r\n });\r\n state.setHasExistingSecret(config.hasClientSecret);\r\n\r\n state.setSyncSettings({\r\n syncEnabled: config.syncEnabled,\r\n syncIntervalMinutes: config.syncIntervalMinutes,\r\n useDeltaSync: config.useDeltaSync,\r\n defaultConflictResolution: config.defaultConflictResolution as SyncSettings['defaultConflictResolution'],\r\n autoCreateReferences: config.autoCreateReferences,\r\n syncOnlyActiveUsers: config.syncOnlyActiveUsers ?? true,\r\n syncUserTypes: config.syncUserTypes ?? 'member',\r\n });\r\n } catch (err) {\r\n console.error('Failed to load configuration:', err);\r\n state.setError(state.t('entra:settings.saveError'));\r\n } finally {\r\n state.setLoading(false);\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []); // React setters are stable, no need to include them in dependencies\r\n\r\n useEffect(() => {\r\n loadConfiguration();\r\n }, [loadConfiguration]);\r\n\r\n const handleCopyPermission = async (code: string) => {\r\n try {\r\n await navigator.clipboard.writeText(code);\r\n state.setCopiedPermission(code);\r\n setTimeout(() => state.setCopiedPermission(null), 2000);\r\n } catch (err) {\r\n console.error('Failed to copy:', err);\r\n }\r\n };\r\n\r\n const validateCredentialField = (field: 'tenantId' | 'clientId', value: string) => {\r\n const errorKey = isValidGuid(value) ? undefined : state.t('entra:settings.invalidGuidFormat');\r\n state.setValidationErrors(prev => ({ ...prev, [field]: errorKey }));\r\n };\r\n\r\n const handleCredentialChange = (field: keyof EntraCredentials, value: string) => {\r\n state.setCredentials(prev => ({ ...prev, [field]: value }));\r\n if (field === 'tenantId' || field === 'clientId') {\r\n validateCredentialField(field, value);\r\n }\r\n };\r\n\r\n const hasValidationErrors = Boolean(\r\n state.validationErrors.tenantId || state.validationErrors.clientId\r\n );\r\n\r\n const handleTestConnection = async () => {\r\n state.setTesting(true);\r\n state.setTestResult(null);\r\n state.setError(null);\r\n state.setSuccess(null);\r\n try {\r\n let result: TestConnectionResult;\r\n\r\n if (state.credentials.clientSecret) {\r\n result = await entraApi.settings.testConnection({\r\n tenantId: state.credentials.tenantId,\r\n clientId: state.credentials.clientId,\r\n clientSecret: state.credentials.clientSecret,\r\n });\r\n } else if (state.hasExistingSecret) {\r\n result = await entraApi.settings.testStoredConnection();\r\n } else {\r\n state.setError(state.t('entra:settings.testFailed'));\r\n state.setTesting(false);\r\n return;\r\n }\r\n\r\n state.setTestResult(result);\r\n if (result.success) {\r\n state.setSuccess(state.t('entra:settings.testSuccess'));\r\n } else {\r\n state.setError(result.errorMessage || state.t('entra:settings.testFailed'));\r\n }\r\n } catch (err) {\r\n console.error('Connection test failed:', err);\r\n state.setTestResult({ success: false, errorMessage: state.t('entra:settings.testFailed'), tenantName: null, userCount: null, groupCount: null });\r\n state.setError(state.t('entra:settings.testFailed'));\r\n } finally {\r\n state.setTesting(false);\r\n }\r\n };\r\n\r\n const handleSaveCredentials = async () => {\r\n state.setSaving(true);\r\n state.setError(null);\r\n state.setSuccess(null);\r\n try {\r\n await entraApi.settings.saveCredentials({\r\n tenantId: state.credentials.tenantId,\r\n clientId: state.credentials.clientId,\r\n clientSecret: state.credentials.clientSecret,\r\n });\r\n state.setSuccess(state.t('entra:settings.credentialsSaved'));\r\n state.setHasExistingSecret(true);\r\n state.setCredentials((prev) => ({ ...prev, clientSecret: '' }));\r\n } catch (err) {\r\n console.error('Failed to save credentials:', err);\r\n state.setError(state.t('entra:settings.saveError'));\r\n } finally {\r\n state.setSaving(false);\r\n }\r\n };\r\n\r\n const handleSaveSettings = async () => {\r\n state.setSaving(true);\r\n state.setError(null);\r\n state.setSuccess(null);\r\n try {\r\n await entraApi.settings.saveSyncSettings({\r\n syncEnabled: state.syncSettings.syncEnabled,\r\n syncIntervalMinutes: state.syncSettings.syncIntervalMinutes,\r\n useDeltaSync: state.syncSettings.useDeltaSync,\r\n defaultConflictResolution: state.syncSettings.defaultConflictResolution,\r\n autoCreateReferences: state.syncSettings.autoCreateReferences,\r\n syncOnlyActiveUsers: state.syncSettings.syncOnlyActiveUsers,\r\n syncUserTypes: state.syncSettings.syncUserTypes,\r\n });\r\n state.setSuccess(state.t('entra:settings.settingsSaved'));\r\n } catch (err) {\r\n console.error('Failed to save settings:', err);\r\n state.setError(state.t('entra:settings.saveError'));\r\n } finally {\r\n state.setSaving(false);\r\n }\r\n };\r\n\r\n if (state.loading) {\r\n return (\r\n <div className=\"flex items-center justify-center h-64\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <Breadcrumb\r\n items={[\r\n { label: state.t('header.title'), href: '/administration' },\r\n { label: state.t('entra.title', 'Microsoft Entra ID'), href: '/administration/entra' },\r\n { label: state.t('entra.settings', 'Settings') }\r\n ]}\r\n />\r\n\r\n {/* Page Header */}\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"p-3 rounded-[var(--radius-card)] bg-gradient-to-br from-[var(--color-accent-500)] to-[var(--color-accent-700)] shadow-lg\">\r\n <Settings className=\"w-7 h-7 text-white\" />\r\n </div>\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {state.t('entra:settings.title')}\r\n </h1>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {state.t('entra:settings.subtitle')}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {/* Required Permissions Warning */}\r\n <div className=\"rounded-[var(--radius-card)] border-2 border-[var(--warning-border)] bg-[var(--warning-bg)] overflow-hidden\">\r\n <div className=\"px-5 py-4\">\r\n <div className=\"flex items-start gap-4\">\r\n <div className=\"p-2 rounded-[var(--radius-button)] bg-[var(--warning-border)]\">\r\n <Shield className=\"w-5 h-5 text-[var(--warning-text)]\" />\r\n </div>\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center justify-between gap-4 mb-2\">\r\n <h2 className=\"font-semibold text-[var(--warning-text)]\">\r\n {state.t('entra:settings.permissionsWarningTitle')}\r\n </h2>\r\n <a\r\n href=\"https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--warning-border)] text-[var(--warning-text)] hover:opacity-80 transition-opacity\"\r\n >\r\n {state.t('entra:settings.configureInAzure')}\r\n <ExternalLink className=\"w-3.5 h-3.5\" />\r\n </a>\r\n </div>\r\n <p className=\"text-sm text-[var(--warning-text)] opacity-90 mb-4\">\r\n {state.t('entra:settings.permissionsWarningDescription')}\r\n </p>\r\n\r\n {/* Copyable Permissions */}\r\n <div className=\"flex flex-wrap gap-2\">\r\n {REQUIRED_PERMISSIONS.map((perm) => (\r\n <button\r\n key={perm.code}\r\n onClick={() => handleCopyPermission(perm.code)}\r\n className=\"group inline-flex items-center gap-2 px-3 py-2 rounded-[var(--radius-button)] bg-[var(--bg-primary)] border border-[var(--warning-border)] hover:border-[var(--warning-dot)] transition-all hover:shadow-sm\"\r\n title={state.t(`entra:settings.permissions.${perm.descriptionKey}`)}\r\n >\r\n <code className=\"text-sm font-mono font-medium text-[var(--text-primary)]\">{perm.code}</code>\r\n {state.copiedPermission === perm.code ? (\r\n <Check className=\"w-4 h-4 text-[var(--success-text)]\" />\r\n ) : (\r\n <Copy className=\"w-4 h-4 text-[var(--warning-text)] group-hover:opacity-80\" />\r\n )}\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Error/Success Messages */}\r\n {state.error && (\r\n <div className=\"flex items-center gap-3 p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <AlertTriangle className=\"w-5 h-5 text-[var(--error-text)] flex-shrink-0\" />\r\n <span className=\"text-sm text-[var(--error-text)]\">{state.error}</span>\r\n </div>\r\n )}\r\n\r\n {state.success && (\r\n <div className=\"flex items-center gap-3 p-4 rounded-[var(--radius-card)] bg-[var(--success-bg)] border border-[var(--success-border)]\">\r\n <CheckCircle className=\"w-5 h-5 text-[var(--success-text)] flex-shrink-0\" />\r\n <span className=\"text-sm text-[var(--success-text)]\">{state.success}</span>\r\n </div>\r\n )}\r\n\r\n {/* Main Content Grid */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* ============================================ */}\r\n {/* Left Column - Credentials */}\r\n {/* ============================================ */}\r\n <SectionCard\r\n icon={Key}\r\n title={state.t('entra:settings.credentials')}\r\n description=\"Azure AD Application\"\r\n action={\r\n <a\r\n href=\"https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"inline-flex items-center gap-1.5 text-sm text-[var(--color-accent-500)] hover:text-[var(--color-accent-600)] transition-colors\"\r\n >\r\n {state.t('entra:settings.azurePortal')}\r\n <ExternalLink className=\"w-4 h-4\" />\r\n </a>\r\n }\r\n >\r\n <div className=\"space-y-5\">\r\n {/* Tenant ID */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-1.5\">\r\n {state.t('entra:settings.tenantId')}\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={state.credentials.tenantId}\r\n onChange={(e) => handleCredentialChange('tenantId', e.target.value)}\r\n placeholder=\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\r\n autoComplete=\"off\"\r\n className={`w-full px-3 py-2.5 rounded-[var(--radius-input)] border bg-[var(--bg-secondary)] text-[var(--text-primary)] font-mono text-sm focus:outline-none focus:ring-2 focus:border-transparent transition-shadow ${\r\n state.validationErrors.tenantId\r\n ? 'border-[var(--error-border)] focus:ring-[var(--error-border)]'\r\n : 'border-[var(--border-color)] focus:ring-[var(--color-accent-500)]'\r\n }`}\r\n />\r\n {state.validationErrors.tenantId ? (\r\n <p className=\"mt-1.5 text-xs text-[var(--error-text)]\">{state.validationErrors.tenantId}</p>\r\n ) : (\r\n <p className=\"mt-1.5 text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.tenantIdHelp')}</p>\r\n )}\r\n </div>\r\n\r\n {/* Client ID */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-1.5\">\r\n {state.t('entra:settings.clientId')}\r\n </label>\r\n <input\r\n type=\"text\"\r\n value={state.credentials.clientId}\r\n onChange={(e) => handleCredentialChange('clientId', e.target.value)}\r\n placeholder=\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\r\n autoComplete=\"off\"\r\n className={`w-full px-3 py-2.5 rounded-[var(--radius-input)] border bg-[var(--bg-secondary)] text-[var(--text-primary)] font-mono text-sm focus:outline-none focus:ring-2 focus:border-transparent transition-shadow ${\r\n state.validationErrors.clientId\r\n ? 'border-[var(--error-border)] focus:ring-[var(--error-border)]'\r\n : 'border-[var(--border-color)] focus:ring-[var(--color-accent-500)]'\r\n }`}\r\n />\r\n {state.validationErrors.clientId ? (\r\n <p className=\"mt-1.5 text-xs text-[var(--error-text)]\">{state.validationErrors.clientId}</p>\r\n ) : (\r\n <p className=\"mt-1.5 text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.clientIdHelp')}</p>\r\n )}\r\n </div>\r\n\r\n {/* Client Secret */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-1.5\">\r\n {state.t('entra:settings.clientSecret')}\r\n {state.hasExistingSecret && (\r\n <span className=\"ml-2 inline-flex items-center gap-1 text-xs text-[var(--success-text)]\">\r\n <CheckCircle className=\"w-3 h-3\" />\r\n {state.t('common:configured')}\r\n </span>\r\n )}\r\n </label>\r\n <div className=\"relative\">\r\n <input\r\n type={state.showSecret ? 'text' : 'password'}\r\n value={state.credentials.clientSecret}\r\n onChange={(e) => handleCredentialChange('clientSecret', e.target.value)}\r\n placeholder={state.hasExistingSecret ? '••••••••••••••••••••••••••••••••••••••••' : 'OvA8Q~xxxxxxxxxxxxxxxxxxxxxxxxxxxx'}\r\n autoComplete=\"new-password\"\r\n className=\"w-full px-3 py-2.5 pr-10 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] font-mono text-sm focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] focus:border-transparent transition-shadow\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => state.setShowSecret(!state.showSecret)}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 p-1 text-[var(--text-tertiary)] hover:text-[var(--text-primary)] transition-colors\"\r\n >\r\n {state.showSecret ? <EyeOff className=\"w-4 h-4\" /> : <Eye className=\"w-4 h-4\" />}\r\n </button>\r\n </div>\r\n <p className=\"mt-1.5 text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.clientSecretHelp')}</p>\r\n </div>\r\n\r\n {/* Action Buttons */}\r\n <div className=\"flex items-center gap-3 pt-2\">\r\n <button\r\n onClick={handleTestConnection}\r\n disabled={state.testing || hasValidationErrors || !state.credentials.tenantId || !state.credentials.clientId || (!state.credentials.clientSecret && !state.hasExistingSecret)}\r\n className=\"inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\r\n >\r\n {state.testing && <Loader2 className=\"w-4 h-4 animate-spin\" />}\r\n {!state.testing && state.testResult?.success && <CheckCircle className=\"w-4 h-4 text-[var(--success-text)]\" />}\r\n {!state.testing && state.testResult && !state.testResult.success && <AlertTriangle className=\"w-4 h-4 text-[var(--error-text)]\" />}\r\n {!state.testing && !state.testResult && <TestTube className=\"w-4 h-4\" />}\r\n {state.t('entra:settings.testConnection')}\r\n </button>\r\n <button\r\n onClick={handleSaveCredentials}\r\n disabled={state.saving || hasValidationErrors || !state.credentials.tenantId || !state.credentials.clientId || !state.credentials.clientSecret}\r\n className=\"inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors shadow-sm\"\r\n >\r\n {state.saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Save className=\"w-4 h-4\" />}\r\n {state.t('common:save')}\r\n </button>\r\n </div>\r\n\r\n {/* Test Result Details */}\r\n {state.testResult?.success && (\r\n <div className=\"mt-4 p-4 rounded-[var(--radius-card)] bg-[var(--success-bg)] border border-[var(--success-border)]\">\r\n <div className=\"flex items-center gap-2 mb-3\">\r\n <CheckCircle className=\"w-5 h-5 text-[var(--success-text)]\" />\r\n <span className=\"font-medium text-[var(--success-text)]\">\r\n {state.t('entra:settings.connectionSuccessful')}\r\n </span>\r\n </div>\r\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-3\">\r\n {state.testResult.tenantName && (\r\n <div className=\"flex items-center gap-2 p-2 rounded-[var(--radius-button)] bg-[var(--bg-primary)]\">\r\n <Building2 className=\"w-4 h-4 text-[var(--success-text)]\" />\r\n <div className=\"min-w-0\">\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.tenantName')}</p>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate\">{state.testResult.tenantName}</p>\r\n </div>\r\n </div>\r\n )}\r\n {state.testResult.userCount !== null && (\r\n <div className=\"flex items-center gap-2 p-2 rounded-[var(--radius-button)] bg-[var(--bg-primary)]\">\r\n <Users className=\"w-4 h-4 text-[var(--success-text)]\" />\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.userCount')}</p>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)]\">{state.testResult.userCount}</p>\r\n </div>\r\n </div>\r\n )}\r\n {state.testResult.groupCount !== null && (\r\n <div className=\"flex items-center gap-2 p-2 rounded-[var(--radius-button)] bg-[var(--bg-primary)]\">\r\n <Layers className=\"w-4 h-4 text-[var(--success-text)]\" />\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">{state.t('entra:settings.groupCount')}</p>\r\n <p className=\"text-sm font-medium text-[var(--text-primary)]\">{state.testResult.groupCount}</p>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n </SectionCard>\r\n\r\n {/* ============================================ */}\r\n {/* Right Column - Sync Settings Stack */}\r\n {/* ============================================ */}\r\n <div className=\"space-y-6\">\r\n {/* Sync Configuration */}\r\n <SectionCard\r\n icon={Clock}\r\n title={state.t('entra:settings.syncSettings')}\r\n description=\"Scheduling & Performance\"\r\n >\r\n <div className=\"divide-y divide-[var(--border-subtle)]\">\r\n <Toggle\r\n checked={state.syncSettings.syncEnabled}\r\n onChange={() => state.setSyncSettings((prev) => ({ ...prev, syncEnabled: !prev.syncEnabled }))}\r\n label={state.t('entra:settings.syncEnabled')}\r\n description={state.t('entra:settings.syncEnabledHelp')}\r\n />\r\n\r\n <div className=\"py-4\">\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\">\r\n {state.t('entra:settings.syncInterval')}\r\n </label>\r\n <select\r\n value={state.syncSettings.syncIntervalMinutes}\r\n onChange={(e) => state.setSyncSettings((prev) => ({ ...prev, syncIntervalMinutes: Number(e.target.value) }))}\r\n className=\"w-full px-3 py-2.5 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] transition-shadow\"\r\n >\r\n <option value={15}>15 {state.t('common:minutes')}</option>\r\n <option value={30}>30 {state.t('common:minutes')}</option>\r\n <option value={60}>1 {state.t('common:hour')}</option>\r\n <option value={120}>2 {state.t('common:hours')}</option>\r\n <option value={360}>6 {state.t('common:hours')}</option>\r\n <option value={720}>12 {state.t('common:hours')}</option>\r\n <option value={1440}>24 {state.t('common:hours')}</option>\r\n </select>\r\n </div>\r\n\r\n <Toggle\r\n checked={state.syncSettings.useDeltaSync}\r\n onChange={() => state.setSyncSettings((prev) => ({ ...prev, useDeltaSync: !prev.useDeltaSync }))}\r\n label={state.t('entra:settings.useDeltaSync')}\r\n description={state.t('entra:settings.useDeltaSyncHelp')}\r\n />\r\n\r\n <Toggle\r\n checked={state.syncSettings.autoCreateReferences}\r\n onChange={() => state.setSyncSettings((prev) => ({ ...prev, autoCreateReferences: !prev.autoCreateReferences }))}\r\n label={state.t('entra:settings.autoCreateReferences')}\r\n description={state.t('entra:settings.autoCreateReferencesHelp')}\r\n />\r\n </div>\r\n </SectionCard>\r\n\r\n {/* Conflict Resolution */}\r\n <SectionCard\r\n icon={GitMerge}\r\n title={state.t('entra:settings.conflictResolution')}\r\n description=\"Data Priority\"\r\n >\r\n <div>\r\n <select\r\n value={state.syncSettings.defaultConflictResolution}\r\n onChange={(e) => state.setSyncSettings((prev) => ({ ...prev, defaultConflictResolution: e.target.value as SyncSettings['defaultConflictResolution'] }))}\r\n className=\"w-full px-3 py-2.5 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-secondary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] transition-shadow\"\r\n >\r\n <option value=\"ManualReview\">{state.t('entra:settings.conflictResolutions.manualReview')}</option>\r\n <option value=\"EntraWins\">{state.t('entra:settings.conflictResolutions.entraWins')}</option>\r\n <option value=\"LocalWins\">{state.t('entra:settings.conflictResolutions.localWins')}</option>\r\n </select>\r\n <p className=\"mt-2 text-xs text-[var(--text-tertiary)]\">\r\n {state.t('entra:settings.conflictResolutionHelp')}\r\n </p>\r\n </div>\r\n </SectionCard>\r\n\r\n {/* User Filters */}\r\n <SectionCard\r\n icon={Filter}\r\n title={state.t('entra:settings.userSyncFilters')}\r\n description=\"User Types & Filters\"\r\n >\r\n <div className=\"space-y-4\">\r\n <Toggle\r\n checked={state.syncSettings.syncOnlyActiveUsers}\r\n onChange={() => state.setSyncSettings((prev) => ({ ...prev, syncOnlyActiveUsers: !prev.syncOnlyActiveUsers }))}\r\n label={state.t('entra:settings.syncOnlyActiveUsers')}\r\n description={state.t('entra:settings.syncOnlyActiveUsersHelp')}\r\n />\r\n\r\n <div className=\"pt-2 border-t border-[var(--border-subtle)]\">\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\">\r\n {state.t('entra:settings.syncUserTypesLabel')}\r\n </label>\r\n <p className=\"text-xs text-[var(--text-tertiary)] mb-3\">\r\n {state.t('entra:settings.syncUserTypesHelp')}\r\n </p>\r\n <div className=\"space-y-2\">\r\n {USER_TYPES.map((userType) => {\r\n const selectedTypes = state.syncSettings.syncUserTypes.split(',').map(t => t.trim()).filter(Boolean);\r\n const isChecked = selectedTypes.includes(userType.id);\r\n const isDisabled = !userType.supported;\r\n\r\n const handleToggle = () => {\r\n if (isDisabled) return;\r\n let newTypes: string[];\r\n if (isChecked) {\r\n newTypes = selectedTypes.filter(t => t !== userType.id);\r\n } else {\r\n newTypes = [...selectedTypes, userType.id];\r\n }\r\n if (newTypes.length === 0) newTypes = ['member'];\r\n state.setSyncSettings(prev => ({ ...prev, syncUserTypes: newTypes.join(',') }));\r\n };\r\n\r\n return (\r\n <label\r\n key={userType.id}\r\n className={`flex items-start gap-3 p-3 rounded-[var(--radius-button)] border transition-all ${\r\n getCheckboxCardClass(isDisabled, isChecked)\r\n }`}\r\n >\r\n <input\r\n type=\"checkbox\"\r\n checked={isChecked}\r\n onChange={handleToggle}\r\n disabled={isDisabled}\r\n className=\"mt-0.5 w-4 h-4 rounded border-[var(--border-color)] text-[var(--color-accent-600)] focus:ring-[var(--color-accent-500)] disabled:opacity-50\"\r\n />\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center gap-2\">\r\n <span className=\"text-sm font-medium text-[var(--text-primary)]\">\r\n {state.t(`entra:settings.${userType.labelKey}`)}\r\n </span>\r\n {isDisabled && (\r\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-[var(--bg-tertiary)] text-[var(--text-tertiary)]\">\r\n {state.t('common:comingSoon')}\r\n </span>\r\n )}\r\n </div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5\">\r\n {state.t(`entra:settings.${userType.descriptionKey}`)}\r\n </p>\r\n </div>\r\n </label>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n </SectionCard>\r\n\r\n {/* Save Button */}\r\n <div className=\"flex justify-end\">\r\n <button\r\n onClick={handleSaveSettings}\r\n disabled={state.saving}\r\n className=\"inline-flex items-center gap-2 px-6 py-2.5 text-sm font-medium rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] disabled:opacity-50 disabled:cursor-not-allowed transition-colors shadow-sm\"\r\n >\r\n {state.saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Save className=\"w-4 h-4\" />}\r\n {state.t('common:save')}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["SyncStatusCard","resourceType","Icon","status","lastFullSyncAt","lastDeltaSyncAt","totalItemsSynced","pendingConflicts","lastError","syncing","canSync","onSync","formatDate","t","statusConfig","CheckCircle","XCircle","Loader2","Clock","StatusIcon","jsxs","jsx","Database","Calendar","RefreshCw","AlertCircle","Tooltip","EntraDashboardPage","useTranslation","hasPermission","useAuth","loading","setLoading","useState","refreshing","setRefreshing","syncStatus","setSyncStatus","error","setError","setSyncing","lastSyncResult","setLastSyncResult","loadData","useCallback","entraApi","err","axiosError","useEffect","handleRefresh","handleSync","type","result","handleForceFullSync","date","getResourceIcon","Users","Building2","Link2","Cloud","totalPendingConflicts","sum","s","Breadcrumb","Play","AlertTriangle","getGroupHierarchyDisplay","group","GitBranch","EntraGroupsPage","currentTenant","isGlobalView","useTenant","navigate","useNavigate","groups","setGroups","roles","setRoles","searchQuery","setSearchQuery","selectedGroup","setSelectedGroup","showAssignModal","setShowAssignModal","expandedGroupId","setExpandedGroupId","members","setMembers","loadingMembers","setLoadingMembers","viewMode","setViewMode","groupTypeFilter","setGroupTypeFilter","assigning","setAssigning","canAssign","groupsData","rolesData","adminApi","loadMembers","groupId","data","prev","reloadGroupsAndRoles","safeGroupsData","handleAssignRole","roleId","isInheritable","updatedGroup","g","handleRemoveRole","filteredGroups","matchesSearch","matchesType","X","Search","e","Filter","LayoutGrid","List","Shield","role","Plus","ChevronUp","ChevronDown","Fragment","member","Link","r","EntraUsersPage","users","setUsers","response","columns","user","Mail","ExternalLink","searchFilter","searchTerm","search","DataTable","EntraConflictsPage","conflicts","setConflicts","selectedConflict","setSelectedConflict","resolving","setResolving","abortControllerRef","useRef","isLoadingRef","handleResolve","resolution","notes","conflict","ConflictCard","ResolutionModal","USER_TYPES","REQUIRED_PERMISSIONS","SectionCard","title","description","action","children","className","Toggle","checked","onChange","label","isValidGuid","value","useEntraSettings","saving","setSaving","testing","setTesting","testResult","setTestResult","showSecret","setShowSecret","success","setSuccess","hasExistingSecret","setHasExistingSecret","copiedPermission","setCopiedPermission","validationErrors","setValidationErrors","credentials","setCredentials","syncSettings","setSyncSettings","getCheckboxCardClass","isDisabled","isChecked","EntraSettingsPage","state","loadConfiguration","config","handleCopyPermission","code","validateCredentialField","field","errorKey","handleCredentialChange","hasValidationErrors","handleTestConnection","handleSaveCredentials","handleSaveSettings","Settings","perm","Check","Copy","Key","EyeOff","Eye","TestTube","Save","Layers","GitMerge","userType","selectedTypes","handleToggle","newTypes"],"mappings":"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"}
|