@atlashub/smartstack 3.39.0-preview.1049 → 3.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{AgentSkillsPage-DgqyaZwI.js → AgentSkillsPage-BS_W2KTh.js} +2 -2
- package/dist/chunks/{AgentSkillsPage-DgqyaZwI.js.map → AgentSkillsPage-BS_W2KTh.js.map} +1 -1
- package/dist/chunks/{AgentSkillsPage-ojivq0Cu.js → AgentSkillsPage-CmDFLnp7.js} +2 -2
- package/dist/chunks/{AgentSkillsPage-ojivq0Cu.js.map → AgentSkillsPage-CmDFLnp7.js.map} +1 -1
- package/dist/chunks/{AgentWorkloadPage-BGGTfOLs.js → AgentWorkloadPage-C8IvYfhT.js} +2 -2
- package/dist/chunks/{AgentWorkloadPage-BGGTfOLs.js.map → AgentWorkloadPage-C8IvYfhT.js.map} +1 -1
- package/dist/chunks/{AgentWorkloadPage-DWsC5VoS.js → AgentWorkloadPage-JXsQbwuM.js} +2 -2
- package/dist/chunks/{AgentWorkloadPage-DWsC5VoS.js.map → AgentWorkloadPage-JXsQbwuM.js.map} +1 -1
- package/dist/chunks/{ApiCatalogDetailPage-7EifQOAh.js → ApiCatalogDetailPage-CYOt34Vy.js} +2 -2
- package/dist/chunks/{ApiCatalogDetailPage-7EifQOAh.js.map → ApiCatalogDetailPage-CYOt34Vy.js.map} +1 -1
- package/dist/chunks/{ApiCatalogDetailPage-BD7XE4xK.js → ApiCatalogDetailPage-wFZDsTGy.js} +3 -3
- package/dist/chunks/{ApiCatalogDetailPage-BD7XE4xK.js.map → ApiCatalogDetailPage-wFZDsTGy.js.map} +1 -1
- package/dist/chunks/{ApiCatalogPage-BfPoZGD3.js → ApiCatalogPage-Bdm3HNGP.js} +2 -2
- package/dist/chunks/{ApiCatalogPage-BfPoZGD3.js.map → ApiCatalogPage-Bdm3HNGP.js.map} +1 -1
- package/dist/chunks/{ApiCatalogPage-BOPTnk-b.js → ApiCatalogPage-m_TWQyGv.js} +2 -2
- package/dist/chunks/{ApiCatalogPage-BOPTnk-b.js.map → ApiCatalogPage-m_TWQyGv.js.map} +1 -1
- package/dist/chunks/ApplicationDetailPage-C2BSpEoW.js +2 -0
- package/dist/chunks/{ApplicationDetailPage-CWdz0TS4.js.map → ApplicationDetailPage-C2BSpEoW.js.map} +1 -1
- package/dist/chunks/{ApplicationDetailPage-CDQqViuH.js → ApplicationDetailPage-CcgDAP-J.js} +503 -501
- package/dist/chunks/{ApplicationDetailPage-CDQqViuH.js.map → ApplicationDetailPage-CcgDAP-J.js.map} +1 -1
- package/dist/chunks/{ApplicationsDashboardPage-ZyXm2Cd1.js → ApplicationsDashboardPage-CDIjziL3.js} +3 -3
- package/dist/chunks/{ApplicationsDashboardPage-ZyXm2Cd1.js.map → ApplicationsDashboardPage-CDIjziL3.js.map} +1 -1
- package/dist/chunks/{ApplicationsDashboardPage-BH4S3qA2.js → ApplicationsDashboardPage-DslDyNzJ.js} +2 -2
- package/dist/chunks/{ApplicationsDashboardPage-BH4S3qA2.js.map → ApplicationsDashboardPage-DslDyNzJ.js.map} +1 -1
- package/dist/chunks/{ApplicationsGridPage-D0fU1_Le.js → ApplicationsGridPage-BCjsQGU0.js} +2 -2
- package/dist/chunks/{ApplicationsGridPage-D0fU1_Le.js.map → ApplicationsGridPage-BCjsQGU0.js.map} +1 -1
- package/dist/chunks/{ApplicationsGridPage-C1WF2Htv.js → ApplicationsGridPage-CIfKiCND.js} +2 -2
- package/dist/chunks/{ApplicationsGridPage-C1WF2Htv.js.map → ApplicationsGridPage-CIfKiCND.js.map} +1 -1
- package/dist/chunks/{ApplicationsListPage-Cxvt2_WQ.js → ApplicationsListPage-CT75kNcH.js} +2 -2
- package/dist/chunks/{ApplicationsListPage-Cxvt2_WQ.js.map → ApplicationsListPage-CT75kNcH.js.map} +1 -1
- package/dist/chunks/{ApplicationsListPage-B3ItaY4r.js → ApplicationsListPage-D2B4PZ5n.js} +2 -2
- package/dist/chunks/{ApplicationsListPage-B3ItaY4r.js.map → ApplicationsListPage-D2B4PZ5n.js.map} +1 -1
- package/dist/chunks/{ApplicationsPage-BqfNR-kc.js → ApplicationsPage-CaTBtduL.js} +2 -2
- package/dist/chunks/{ApplicationsPage-BqfNR-kc.js.map → ApplicationsPage-CaTBtduL.js.map} +1 -1
- package/dist/chunks/{ApplicationsPage-DuxuWfrN.js → ApplicationsPage-DW1LhL0U.js} +4 -4
- package/dist/chunks/{ApplicationsPage-DuxuWfrN.js.map → ApplicationsPage-DW1LhL0U.js.map} +1 -1
- package/dist/chunks/{AssignmentRulesPage-CR1C7V0a.js → AssignmentRulesPage-Bt9M0ki7.js} +2 -2
- package/dist/chunks/{AssignmentRulesPage-CR1C7V0a.js.map → AssignmentRulesPage-Bt9M0ki7.js.map} +1 -1
- package/dist/chunks/{AssignmentRulesPage-C4Jouh2g.js → AssignmentRulesPage-Y7xv60NY.js} +2 -2
- package/dist/chunks/{AssignmentRulesPage-C4Jouh2g.js.map → AssignmentRulesPage-Y7xv60NY.js.map} +1 -1
- package/dist/chunks/{AssignmentsPage-v8QUJkE7.js → AssignmentsPage-1eQGTjTi.js} +2 -2
- package/dist/chunks/{AssignmentsPage-v8QUJkE7.js.map → AssignmentsPage-1eQGTjTi.js.map} +1 -1
- package/dist/chunks/{AssignmentsPage-CjuGAd8n.js → AssignmentsPage-RURdPvfZ.js} +2 -2
- package/dist/chunks/{AssignmentsPage-CjuGAd8n.js.map → AssignmentsPage-RURdPvfZ.js.map} +1 -1
- package/dist/chunks/{AuthCallbackPage-BxIXPUJk.js → AuthCallbackPage-8hF0jYlK.js} +2 -2
- package/dist/chunks/{AuthCallbackPage-BxIXPUJk.js.map → AuthCallbackPage-8hF0jYlK.js.map} +1 -1
- package/dist/chunks/{AuthCallbackPage-CuS-efzY.js → AuthCallbackPage-DPL68Asu.js} +2 -2
- package/dist/chunks/{AuthCallbackPage-CuS-efzY.js.map → AuthCallbackPage-DPL68Asu.js.map} +1 -1
- package/dist/chunks/{ConfirmEmailPage-CWIqy2bT.js → ConfirmEmailPage-BKlpZkVk.js} +2 -2
- package/dist/chunks/{ConfirmEmailPage-CWIqy2bT.js.map → ConfirmEmailPage-BKlpZkVk.js.map} +1 -1
- package/dist/chunks/{ConfirmEmailPage-CkN8IfP-.js → ConfirmEmailPage-CawSZypI.js} +2 -2
- package/dist/chunks/{ConfirmEmailPage-CkN8IfP-.js.map → ConfirmEmailPage-CawSZypI.js.map} +1 -1
- package/dist/chunks/{CreateSupportTicketPage-Df0ow5ge.js → CreateSupportTicketPage-AwbMbBIH.js} +2 -2
- package/dist/chunks/{CreateSupportTicketPage-Df0ow5ge.js.map → CreateSupportTicketPage-AwbMbBIH.js.map} +1 -1
- package/dist/chunks/{CreateSupportTicketPage-CmrDfFxP.js → CreateSupportTicketPage-Dg1YW1eA.js} +2 -2
- package/dist/chunks/{CreateSupportTicketPage-CmrDfFxP.js.map → CreateSupportTicketPage-Dg1YW1eA.js.map} +1 -1
- package/dist/chunks/{DashboardPage-B4Pi5P3O.js → DashboardPage-B4YxOF-9.js} +3 -3
- package/dist/chunks/{DashboardPage-B4Pi5P3O.js.map → DashboardPage-B4YxOF-9.js.map} +1 -1
- package/dist/chunks/{DashboardPage-wEKZ_DWf.js → DashboardPage-BZxjinar.js} +2 -2
- package/dist/chunks/{DashboardPage-wEKZ_DWf.js.map → DashboardPage-BZxjinar.js.map} +1 -1
- package/dist/chunks/{DashboardPage-BAqpoxCW.js → DashboardPage-Bo09y8r7.js} +3 -3
- package/dist/chunks/{DashboardPage-BAqpoxCW.js.map → DashboardPage-Bo09y8r7.js.map} +1 -1
- package/dist/chunks/{DashboardPage-BT5kFaQA.js → DashboardPage-Cq5adDjP.js} +2 -2
- package/dist/chunks/{DashboardPage-BT5kFaQA.js.map → DashboardPage-Cq5adDjP.js.map} +1 -1
- package/dist/chunks/{EscalationConfigPage-4pF38E4N.js → EscalationConfigPage-C8Hv5naz.js} +2 -2
- package/dist/chunks/{EscalationConfigPage-4pF38E4N.js.map → EscalationConfigPage-C8Hv5naz.js.map} +1 -1
- package/dist/chunks/{EscalationConfigPage-Bcifnt_h.js → EscalationConfigPage-DNAqMRxA.js} +2 -2
- package/dist/chunks/{EscalationConfigPage-Bcifnt_h.js.map → EscalationConfigPage-DNAqMRxA.js.map} +1 -1
- package/dist/chunks/{ForceChangePasswordPage-CBaMV_PS.js → ForceChangePasswordPage-BURE_vNg.js} +2 -2
- package/dist/chunks/{ForceChangePasswordPage-CBaMV_PS.js.map → ForceChangePasswordPage-BURE_vNg.js.map} +1 -1
- package/dist/chunks/{ForceChangePasswordPage-ClDXluX1.js → ForceChangePasswordPage-C6jDZshk.js} +2 -2
- package/dist/chunks/{ForceChangePasswordPage-ClDXluX1.js.map → ForceChangePasswordPage-C6jDZshk.js.map} +1 -1
- package/dist/chunks/{ForgotPasswordPage--ueWRNSO.js → ForgotPasswordPage-C5HLYbz4.js} +2 -2
- package/dist/chunks/{ForgotPasswordPage--ueWRNSO.js.map → ForgotPasswordPage-C5HLYbz4.js.map} +1 -1
- package/dist/chunks/{ForgotPasswordPage-CzpAkP5R.js → ForgotPasswordPage-D3ZQBtjd.js} +2 -2
- package/dist/chunks/{ForgotPasswordPage-CzpAkP5R.js.map → ForgotPasswordPage-D3ZQBtjd.js.map} +1 -1
- package/dist/chunks/{GroupDetailPage-dXNOoSXE.js → GroupDetailPage-CTuzp9Vp.js} +5 -5
- package/dist/chunks/{GroupDetailPage-dXNOoSXE.js.map → GroupDetailPage-CTuzp9Vp.js.map} +1 -1
- package/dist/chunks/{GroupDetailPage-BIgBzQk0.js → GroupDetailPage-NJc2zCxC.js} +2 -2
- package/dist/chunks/{GroupDetailPage-BIgBzQk0.js.map → GroupDetailPage-NJc2zCxC.js.map} +1 -1
- package/dist/chunks/{MyAccessRequestsPage-K2NXkdy4.js → MyAccessRequestsPage-Cvr29Pnq.js} +2 -2
- package/dist/chunks/{MyAccessRequestsPage-K2NXkdy4.js.map → MyAccessRequestsPage-Cvr29Pnq.js.map} +1 -1
- package/dist/chunks/{MyAccessRequestsPage-Be8VvLhh.js → MyAccessRequestsPage-t6I24rHN.js} +2 -2
- package/dist/chunks/{MyAccessRequestsPage-Be8VvLhh.js.map → MyAccessRequestsPage-t6I24rHN.js.map} +1 -1
- package/dist/chunks/{MyTenantsPage-BXx1nPC8.js → MyTenantsPage-Dy2RZ_Ei.js} +2 -2
- package/dist/chunks/{MyTenantsPage-BXx1nPC8.js.map → MyTenantsPage-Dy2RZ_Ei.js.map} +1 -1
- package/dist/chunks/{MyTenantsPage-B9ZAUeCa.js → MyTenantsPage-SvDCQ4Wt.js} +3 -3
- package/dist/chunks/{MyTenantsPage-B9ZAUeCa.js.map → MyTenantsPage-SvDCQ4Wt.js.map} +1 -1
- package/dist/chunks/{MyTicketsPage-C9MSmmR5.js → MyTicketsPage-C3lEBFD9.js} +2 -2
- package/dist/chunks/{MyTicketsPage-C9MSmmR5.js.map → MyTicketsPage-C3lEBFD9.js.map} +1 -1
- package/dist/chunks/{MyTicketsPage-d0PoJpnX.js → MyTicketsPage-DydDgFyz.js} +2 -2
- package/dist/chunks/{MyTicketsPage-d0PoJpnX.js.map → MyTicketsPage-DydDgFyz.js.map} +1 -1
- package/dist/chunks/{NavigationAppsPage-CJ3BjLlz.js → NavigationAppsPage-Dyv767w8.js} +2 -2
- package/dist/chunks/{NavigationAppsPage-CJ3BjLlz.js.map → NavigationAppsPage-Dyv767w8.js.map} +1 -1
- package/dist/chunks/{NavigationAppsPage-8t2xbddT.js → NavigationAppsPage-WqSspaVo.js} +2 -2
- package/dist/chunks/{NavigationAppsPage-8t2xbddT.js.map → NavigationAppsPage-WqSspaVo.js.map} +1 -1
- package/dist/chunks/{NotificationsPage-_62-bmuk.js → NotificationsPage-Di4I95PM.js} +2 -2
- package/dist/chunks/{NotificationsPage-_62-bmuk.js.map → NotificationsPage-Di4I95PM.js.map} +1 -1
- package/dist/chunks/{NotificationsPage-CLHfVUxm.js → NotificationsPage-elSovpBw.js} +2 -2
- package/dist/chunks/{NotificationsPage-CLHfVUxm.js.map → NotificationsPage-elSovpBw.js.map} +1 -1
- package/dist/chunks/{OnboardingWizardPage-Dkc22Jc4.js → OnboardingWizardPage-fdWdkwiT.js} +2 -2
- package/dist/chunks/{OnboardingWizardPage-Dkc22Jc4.js.map → OnboardingWizardPage-fdWdkwiT.js.map} +1 -1
- package/dist/chunks/{OnboardingWizardPage-D1rzD6gR.js → OnboardingWizardPage-nPLe2buQ.js} +2 -2
- package/dist/chunks/{OnboardingWizardPage-D1rzD6gR.js.map → OnboardingWizardPage-nPLe2buQ.js.map} +1 -1
- package/dist/chunks/{PermissionDetailPage-BSvSe4SI.js → PermissionDetailPage-B8C7tWFP.js} +2 -2
- package/dist/chunks/{PermissionDetailPage-BSvSe4SI.js.map → PermissionDetailPage-B8C7tWFP.js.map} +1 -1
- package/dist/chunks/{PermissionDetailPage-_HhbxzlG.js → PermissionDetailPage-IUgUaTkE.js} +2 -2
- package/dist/chunks/{PermissionDetailPage-_HhbxzlG.js.map → PermissionDetailPage-IUgUaTkE.js.map} +1 -1
- package/dist/chunks/{PermissionsPage-Xb92YAHn.js → PermissionsPage-CmX5sQf2.js} +2 -2
- package/dist/chunks/{PermissionsPage-Xb92YAHn.js.map → PermissionsPage-CmX5sQf2.js.map} +1 -1
- package/dist/chunks/{PermissionsPage-B0M4gA5m.js → PermissionsPage-Kg0rduOM.js} +2 -2
- package/dist/chunks/{PermissionsPage-B0M4gA5m.js.map → PermissionsPage-Kg0rduOM.js.map} +1 -1
- package/dist/chunks/{PortalDashboardPage-DTeMESj9.js → PortalDashboardPage-CCAYuhtI.js} +2 -2
- package/dist/chunks/{PortalDashboardPage-DTeMESj9.js.map → PortalDashboardPage-CCAYuhtI.js.map} +1 -1
- package/dist/chunks/{PortalDashboardPage-pt9hipR4.js → PortalDashboardPage-Dme1XmzN.js} +2 -2
- package/dist/chunks/{PortalDashboardPage-pt9hipR4.js.map → PortalDashboardPage-Dme1XmzN.js.map} +1 -1
- package/dist/chunks/{PreferencesPage-Cy30AWIN.js → PreferencesPage-Ct6xWAFp.js} +2 -2
- package/dist/chunks/{PreferencesPage-Cy30AWIN.js.map → PreferencesPage-Ct6xWAFp.js.map} +1 -1
- package/dist/chunks/{PreferencesPage-CsHVGMgp.js → PreferencesPage-Db2RjMpm.js} +2 -2
- package/dist/chunks/{PreferencesPage-CsHVGMgp.js.map → PreferencesPage-Db2RjMpm.js.map} +1 -1
- package/dist/chunks/{ProfilePage-6Gf7igUI.js → ProfilePage-D6Xb1ALH.js} +2 -2
- package/dist/chunks/{ProfilePage-6Gf7igUI.js.map → ProfilePage-D6Xb1ALH.js.map} +1 -1
- package/dist/chunks/{ProfilePage-BzBWkztf.js → ProfilePage-DN2s-lfp.js} +2 -2
- package/dist/chunks/{ProfilePage-BzBWkztf.js.map → ProfilePage-DN2s-lfp.js.map} +1 -1
- package/dist/chunks/{ReferencesManagementPage-DEDoHrnU.js → ReferencesManagementPage-B5mcshG1.js} +2 -2
- package/dist/chunks/{ReferencesManagementPage-DEDoHrnU.js.map → ReferencesManagementPage-B5mcshG1.js.map} +1 -1
- package/dist/chunks/{ReferencesManagementPage-DD1QiFYr.js → ReferencesManagementPage-DB975ktX.js} +3 -3
- package/dist/chunks/{ReferencesManagementPage-DD1QiFYr.js.map → ReferencesManagementPage-DB975ktX.js.map} +1 -1
- package/dist/chunks/{RegisterPage-asdx33fV.js → RegisterPage-ZskZrLZH.js} +2 -2
- package/dist/chunks/{RegisterPage-asdx33fV.js.map → RegisterPage-ZskZrLZH.js.map} +1 -1
- package/dist/chunks/{RegisterPage-CIPHRYkl.js → RegisterPage-b8yIPVgh.js} +2 -2
- package/dist/chunks/{RegisterPage-CIPHRYkl.js.map → RegisterPage-b8yIPVgh.js.map} +1 -1
- package/dist/chunks/{ResetPasswordPage-B4Dj24vU.js → ResetPasswordPage-CeAvfsE-.js} +2 -2
- package/dist/chunks/{ResetPasswordPage-B4Dj24vU.js.map → ResetPasswordPage-CeAvfsE-.js.map} +1 -1
- package/dist/chunks/{ResetPasswordPage-B8MWH_Vi.js → ResetPasswordPage-Dzp5dCp8.js} +2 -2
- package/dist/chunks/{ResetPasswordPage-B8MWH_Vi.js.map → ResetPasswordPage-Dzp5dCp8.js.map} +1 -1
- package/dist/chunks/{ResolutionModal-Cs6T441o.js → ResolutionModal-CRVN7gHv.js} +2 -2
- package/dist/chunks/{ResolutionModal-Cs6T441o.js.map → ResolutionModal-CRVN7gHv.js.map} +1 -1
- package/dist/chunks/{ResolutionModal-rLoFOxm9.js → ResolutionModal-DJOw1sLT.js} +2 -2
- package/dist/chunks/{ResolutionModal-rLoFOxm9.js.map → ResolutionModal-DJOw1sLT.js.map} +1 -1
- package/dist/chunks/{RoleDetailPage-Pkw0wU5g.js → RoleDetailPage-CLVoFVF8.js} +2 -2
- package/dist/chunks/{RoleDetailPage-Pkw0wU5g.js.map → RoleDetailPage-CLVoFVF8.js.map} +1 -1
- package/dist/chunks/{RoleDetailPage-CNFG6j6P.js → RoleDetailPage-XGnPD_8C.js} +3 -3
- package/dist/chunks/{RoleDetailPage-CNFG6j6P.js.map → RoleDetailPage-XGnPD_8C.js.map} +1 -1
- package/dist/chunks/{RolesPage-BHEkMR2O.js → RolesPage-BnAMpR2b.js} +2 -2
- package/dist/chunks/{RolesPage-BHEkMR2O.js.map → RolesPage-BnAMpR2b.js.map} +1 -1
- package/dist/chunks/{RolesPage-D35jwDJU.js → RolesPage-Czj9LMkL.js} +2 -2
- package/dist/chunks/{RolesPage-D35jwDJU.js.map → RolesPage-Czj9LMkL.js.map} +1 -1
- package/dist/chunks/{SlaConfigPage-DtonDehw.js → SlaConfigPage-HM0MpIlg.js} +2 -2
- package/dist/chunks/{SlaConfigPage-DtonDehw.js.map → SlaConfigPage-HM0MpIlg.js.map} +1 -1
- package/dist/chunks/{SlaConfigPage-C5Jstix-.js → SlaConfigPage-ZRyAs8aY.js} +2 -2
- package/dist/chunks/{SlaConfigPage-C5Jstix-.js.map → SlaConfigPage-ZRyAs8aY.js.map} +1 -1
- package/dist/chunks/{SupportPermissionsPage-6pC73oCY.js → SupportPermissionsPage-CxJuGgcQ.js} +2 -2
- package/dist/chunks/{SupportPermissionsPage-6pC73oCY.js.map → SupportPermissionsPage-CxJuGgcQ.js.map} +1 -1
- package/dist/chunks/{SupportPermissionsPage-CsJKGt__.js → SupportPermissionsPage-DNd323OK.js} +2 -2
- package/dist/chunks/{SupportPermissionsPage-CsJKGt__.js.map → SupportPermissionsPage-DNd323OK.js.map} +1 -1
- package/dist/chunks/{TemplatesPage-DjmYOGEC.js → TemplatesPage-CdwPLsHj.js} +2 -2
- package/dist/chunks/{TemplatesPage-DjmYOGEC.js.map → TemplatesPage-CdwPLsHj.js.map} +1 -1
- package/dist/chunks/{TemplatesPage-DlY91VO_.js → TemplatesPage-Co3ygZvF.js} +2 -2
- package/dist/chunks/{TemplatesPage-DlY91VO_.js.map → TemplatesPage-Co3ygZvF.js.map} +1 -1
- package/dist/chunks/{TenantCard-BHLcv2gD.js → TenantCard-CmCfIK2F.js} +2 -2
- package/dist/chunks/{TenantCard-BHLcv2gD.js.map → TenantCard-CmCfIK2F.js.map} +1 -1
- package/dist/chunks/{TenantCard-DGCKVvKI.js → TenantCard-DI66acce.js} +2 -2
- package/dist/chunks/{TenantCard-DGCKVvKI.js.map → TenantCard-DI66acce.js.map} +1 -1
- package/dist/chunks/{TenantScopeSelector-dsSwnOWg.js → TenantScopeSelector-5NOwmFX2.js} +2 -2
- package/dist/chunks/{TenantScopeSelector-dsSwnOWg.js.map → TenantScopeSelector-5NOwmFX2.js.map} +1 -1
- package/dist/chunks/{TenantScopeSelector-CU5z5PJH.js → TenantScopeSelector-CEFgxiWt.js} +2 -2
- package/dist/chunks/{TenantScopeSelector-CU5z5PJH.js.map → TenantScopeSelector-CEFgxiWt.js.map} +1 -1
- package/dist/chunks/{TicketDetailPage-BQHMaRmq.js → TicketDetailPage-BhZ-mpv7.js} +2 -2
- package/dist/chunks/{TicketDetailPage-BQHMaRmq.js.map → TicketDetailPage-BhZ-mpv7.js.map} +1 -1
- package/dist/chunks/{TicketDetailPage-Bk_0uQ3B.js → TicketDetailPage-BxOiOG22.js} +2 -2
- package/dist/chunks/{TicketDetailPage-Bk_0uQ3B.js.map → TicketDetailPage-BxOiOG22.js.map} +1 -1
- package/dist/chunks/{TicketsPage-CufUJctx.js → TicketsPage-BiTvIcM8.js} +2 -2
- package/dist/chunks/{TicketsPage-CufUJctx.js.map → TicketsPage-BiTvIcM8.js.map} +1 -1
- package/dist/chunks/{TicketsPage-C8QQ4SKy.js → TicketsPage-CSiinHME.js} +2 -2
- package/dist/chunks/{TicketsPage-C8QQ4SKy.js.map → TicketsPage-CSiinHME.js.map} +1 -1
- package/dist/chunks/{UserCreateTicketPage-DoEMtJoe.js → UserCreateTicketPage-B3TW1oV7.js} +2 -2
- package/dist/chunks/{UserCreateTicketPage-DoEMtJoe.js.map → UserCreateTicketPage-B3TW1oV7.js.map} +1 -1
- package/dist/chunks/{UserCreateTicketPage-XxjNlR9K.js → UserCreateTicketPage-BszUd_WZ.js} +2 -2
- package/dist/chunks/{UserCreateTicketPage-XxjNlR9K.js.map → UserCreateTicketPage-BszUd_WZ.js.map} +1 -1
- package/dist/chunks/{UserDashboardPage-fdhZwMLg.js → UserDashboardPage-C6MvatAb.js} +2 -2
- package/dist/chunks/{UserDashboardPage-fdhZwMLg.js.map → UserDashboardPage-C6MvatAb.js.map} +1 -1
- package/dist/chunks/{UserDashboardPage-BV1d2hMG.js → UserDashboardPage-Dtt9VzG_.js} +2 -2
- package/dist/chunks/{UserDashboardPage-BV1d2hMG.js.map → UserDashboardPage-Dtt9VzG_.js.map} +1 -1
- package/dist/chunks/{UserDetailPage-C97e-Dax.js → UserDetailPage-BEEV2vlJ.js} +5 -5
- package/dist/chunks/{UserDetailPage-C97e-Dax.js.map → UserDetailPage-BEEV2vlJ.js.map} +1 -1
- package/dist/chunks/{UserDetailPage-BcA7Vhb2.js → UserDetailPage-Dw5OHheZ.js} +2 -2
- package/dist/chunks/{UserDetailPage-BcA7Vhb2.js.map → UserDetailPage-Dw5OHheZ.js.map} +1 -1
- package/dist/chunks/{UserTicketDetailPage-BA2syxXG.js → UserTicketDetailPage-B4YkzzbR.js} +2 -2
- package/dist/chunks/{UserTicketDetailPage-BA2syxXG.js.map → UserTicketDetailPage-B4YkzzbR.js.map} +1 -1
- package/dist/chunks/{UserTicketDetailPage-CXuZVAa2.js → UserTicketDetailPage-DCFV-0ny.js} +2 -2
- package/dist/chunks/{UserTicketDetailPage-CXuZVAa2.js.map → UserTicketDetailPage-DCFV-0ny.js.map} +1 -1
- package/dist/chunks/{UsersGroupsPage-CPVk31Dh.js → UsersGroupsPage-CY-l9fTp.js} +3 -3
- package/dist/chunks/{UsersGroupsPage-CPVk31Dh.js.map → UsersGroupsPage-CY-l9fTp.js.map} +1 -1
- package/dist/chunks/{UsersGroupsPage-DS2YiUE4.js → UsersGroupsPage-c28vYHN9.js} +2 -2
- package/dist/chunks/{UsersGroupsPage-DS2YiUE4.js.map → UsersGroupsPage-c28vYHN9.js.map} +1 -1
- package/dist/chunks/{UsersPage-BIXWHFmG.js → UsersPage-1sLlq9QD.js} +2 -2
- package/dist/chunks/{UsersPage-BIXWHFmG.js.map → UsersPage-1sLlq9QD.js.map} +1 -1
- package/dist/chunks/{UsersPage-DS8aWUKj.js → UsersPage-Bm-uNxh0.js} +2 -2
- package/dist/chunks/{UsersPage-DS8aWUKj.js.map → UsersPage-Bm-uNxh0.js.map} +1 -1
- package/dist/chunks/{accessRequestsApi-C-r0mrCH.js → accessRequestsApi-CJPjyEkH.js} +2 -2
- package/dist/chunks/{accessRequestsApi-C-r0mrCH.js.map → accessRequestsApi-CJPjyEkH.js.map} +1 -1
- package/dist/chunks/{accessRequestsApi-k3ZwhcFb.js → accessRequestsApi-D_pj1wl6.js} +2 -2
- package/dist/chunks/{accessRequestsApi-k3ZwhcFb.js.map → accessRequestsApi-D_pj1wl6.js.map} +1 -1
- package/dist/chunks/{aiApi-B-H-76wM.js → aiApi-ByF-oo1J.js} +2 -2
- package/dist/chunks/{aiApi-B-H-76wM.js.map → aiApi-ByF-oo1J.js.map} +1 -1
- package/dist/chunks/{aiApi-CcdrBILv.js → aiApi-Dt3fj0dU.js} +2 -2
- package/dist/chunks/{aiApi-CcdrBILv.js.map → aiApi-Dt3fj0dU.js.map} +1 -1
- package/dist/chunks/{applicationAnalyticsApi-CO3tk6Ju.js → applicationAnalyticsApi-BgG3SGJm.js} +2 -2
- package/dist/chunks/{applicationAnalyticsApi-CO3tk6Ju.js.map → applicationAnalyticsApi-BgG3SGJm.js.map} +1 -1
- package/dist/chunks/{applicationAnalyticsApi-CLVdVLDu.js → applicationAnalyticsApi-ktD65iLO.js} +2 -2
- package/dist/chunks/{applicationAnalyticsApi-CLVdVLDu.js.map → applicationAnalyticsApi-ktD65iLO.js.map} +1 -1
- package/dist/chunks/{groupsApi-DExOJZPF.js → groupsApi-C-FLWPCO.js} +2 -2
- package/dist/chunks/{groupsApi-DExOJZPF.js.map → groupsApi-C-FLWPCO.js.map} +1 -1
- package/dist/chunks/{groupsApi-CyqyYsmi.js → groupsApi-CBI5vMLa.js} +2 -2
- package/dist/chunks/{groupsApi-CyqyYsmi.js.map → groupsApi-CBI5vMLa.js.map} +1 -1
- package/dist/chunks/{index-DtAReZI6.js → index-B727-QSU.js} +2 -2
- package/dist/chunks/{index-DtAReZI6.js.map → index-B727-QSU.js.map} +1 -1
- package/dist/chunks/{index-BlOgmQzc.js → index-B9q3vx13.js} +2 -2
- package/dist/chunks/{index-BlOgmQzc.js.map → index-B9q3vx13.js.map} +1 -1
- package/dist/chunks/{index-VSQ2prtJ.js → index-BD-REzV9.js} +2 -2
- package/dist/chunks/{index-VSQ2prtJ.js.map → index-BD-REzV9.js.map} +1 -1
- package/dist/chunks/{index-XOOiD_zY.js → index-BDRogQH_.js} +3 -3
- package/dist/chunks/{index-XOOiD_zY.js.map → index-BDRogQH_.js.map} +1 -1
- package/dist/chunks/{index-DOQyf5yZ.js → index-C-DYxdvd.js} +8 -8
- package/dist/chunks/{index-DOQyf5yZ.js.map → index-C-DYxdvd.js.map} +1 -1
- package/dist/chunks/{index-Cq80YBne.js → index-CBtjGPod.js} +105 -105
- package/dist/chunks/{index-Cq80YBne.js.map → index-CBtjGPod.js.map} +1 -1
- package/dist/chunks/{index-dlXYTPWH.js → index-CF1cvNUL.js} +4 -4
- package/dist/chunks/{index-dlXYTPWH.js.map → index-CF1cvNUL.js.map} +1 -1
- package/dist/chunks/{index-COA_xJVJ.js → index-CH0pTHy1.js} +2 -2
- package/dist/chunks/{index-COA_xJVJ.js.map → index-CH0pTHy1.js.map} +1 -1
- package/dist/chunks/{index-DjZQ6ZG_.js → index-Ca88RIuT.js} +2 -2
- package/dist/chunks/{index-DjZQ6ZG_.js.map → index-Ca88RIuT.js.map} +1 -1
- package/dist/chunks/{index-Cj-9tGpd.js → index-CkWvsvKW.js} +2 -2
- package/dist/chunks/{index-Cj-9tGpd.js.map → index-CkWvsvKW.js.map} +1 -1
- package/dist/chunks/{index-EL_ZNnMH.js → index-CzYKE5fL.js} +2 -2
- package/dist/chunks/{index-EL_ZNnMH.js.map → index-CzYKE5fL.js.map} +1 -1
- package/dist/chunks/{index-qXfYaEmV.js → index-D32ol7lq.js} +2 -2
- package/dist/chunks/{index-qXfYaEmV.js.map → index-D32ol7lq.js.map} +1 -1
- package/dist/chunks/{index-DMQQ0KyA.js → index-D7hmx9IX.js} +2 -2
- package/dist/chunks/{index-DMQQ0KyA.js.map → index-D7hmx9IX.js.map} +1 -1
- package/dist/chunks/{index-BetDcNZm.js → index-DThcQmwZ.js} +2 -2
- package/dist/chunks/{index-BetDcNZm.js.map → index-DThcQmwZ.js.map} +1 -1
- package/dist/chunks/{index-C7h5yvcP.js → index-D_3J6ziZ.js} +2 -2
- package/dist/chunks/{index-C7h5yvcP.js.map → index-D_3J6ziZ.js.map} +1 -1
- package/dist/chunks/{index-C_nDTEP5.js → index-JSjfMShT.js} +2 -2
- package/dist/chunks/{index-C_nDTEP5.js.map → index-JSjfMShT.js.map} +1 -1
- package/dist/chunks/{index-COXxU0FH.js → index-gzXJw_ow.js} +3 -3
- package/dist/chunks/{index-COXxU0FH.js.map → index-gzXJw_ow.js.map} +1 -1
- package/dist/chunks/{index-jJxtz2bs.js → index-rRAbl04H.js} +2 -2
- package/dist/chunks/{index-jJxtz2bs.js.map → index-rRAbl04H.js.map} +1 -1
- package/dist/chunks/{tenantIconMap-Ddvguo0l.js → tenantIconMap-Cw-hQ9n4.js} +2 -2
- package/dist/chunks/{tenantIconMap-Ddvguo0l.js.map → tenantIconMap-Cw-hQ9n4.js.map} +1 -1
- package/dist/chunks/{tenantIconMap-DBa5MjIz.js → tenantIconMap-DinwojNW.js} +2 -2
- package/dist/chunks/{tenantIconMap-DBa5MjIz.js.map → tenantIconMap-DinwojNW.js.map} +1 -1
- package/dist/chunks/{ticketingApi-Cr6QSv0g.js → ticketingApi-CcWdebXv.js} +2 -2
- package/dist/chunks/{ticketingApi-Cr6QSv0g.js.map → ticketingApi-CcWdebXv.js.map} +1 -1
- package/dist/chunks/{ticketingApi-D6s75rOB.js → ticketingApi-x0BwZ1NH.js} +2 -2
- package/dist/chunks/{ticketingApi-D6s75rOB.js.map → ticketingApi-x0BwZ1NH.js.map} +1 -1
- package/dist/chunks/{useAccessRequests-VuQT-n-P.js → useAccessRequests-BBTIYht3.js} +2 -2
- package/dist/chunks/{useAccessRequests-VuQT-n-P.js.map → useAccessRequests-BBTIYht3.js.map} +1 -1
- package/dist/chunks/{useAccessRequests-CanI2ypo.js → useAccessRequests-BBUj9XY9.js} +71 -71
- package/dist/chunks/{useAccessRequests-CanI2ypo.js.map → useAccessRequests-BBUj9XY9.js.map} +1 -1
- package/dist/chunks/{useUserAccessRequests-BEVZLX_M.js → useUserAccessRequests-BKQxcOXH.js} +2 -2
- package/dist/chunks/{useUserAccessRequests-BEVZLX_M.js.map → useUserAccessRequests-BKQxcOXH.js.map} +1 -1
- package/dist/chunks/{useUserAccessRequests-Ba40FDLm.js → useUserAccessRequests-BPUPiP55.js} +2 -2
- package/dist/chunks/{useUserAccessRequests-Ba40FDLm.js.map → useUserAccessRequests-BPUPiP55.js.map} +1 -1
- package/dist/pages/platform/administration/applications/ApplicationDetailPage.d.ts.map +1 -1
- package/dist/smartstack.cjs +1 -1
- package/dist/smartstack.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/ApplicationDetailPage-CWdz0TS4.js +0 -2
|
@@ -2,7 +2,7 @@ import { jsx as t, jsxs as r, Fragment as B } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState as T, useEffect as G, useCallback as V } from "react";
|
|
3
3
|
import { useTranslation as Y } from "react-i18next";
|
|
4
4
|
import { useSearchParams as W } from "react-router-dom";
|
|
5
|
-
import { L as Z, M as _, O as z, Q as H, i as Q } from "./index-
|
|
5
|
+
import { L as Z, M as _, O as z, Q as H, i as Q } from "./index-CBtjGPod.js";
|
|
6
6
|
import { Loader2 as j, AlertTriangle as A, ShieldCheck as X, Key as q, Zap as J, Users as O, Building as ee, Calendar as te, Server as ae, Monitor as re, Layers as se, Shield as ne, CheckCircle as I, Infinity as ie, Clock as le, X as E, Unlock as ce, Lock as de } from "lucide-react";
|
|
7
7
|
const oe = {
|
|
8
8
|
blue: "bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]",
|
|
@@ -535,4 +535,4 @@ function F({ icon: e, label: a, max: s, current: n, margin: i = 0, t: l }) {
|
|
|
535
535
|
export {
|
|
536
536
|
Ce as LicenseManagementPage
|
|
537
537
|
};
|
|
538
|
-
//# sourceMappingURL=index-
|
|
538
|
+
//# sourceMappingURL=index-rRAbl04H.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-jJxtz2bs.js","sources":["../../src/pages/platform/administration/configuration/license/LicenseManagementPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport type { TFunction } from 'i18next';\r\nimport { useSearchParams } from 'react-router-dom';\r\nimport { useLicense } from '@/contexts/LicenseContext';\r\nimport { api } from '@/services/api/apiClient';\r\nimport { hasAllLicenseFeatures } from '@/utils/licenseUtils';\r\nimport { LicenseStatusBadge } from '@/components/license/LicenseStatusBadge';\r\nimport { LicenseActivationDialog } from '@/components/license/LicenseActivationDialog';\r\nimport type { LicenseFeatureGroup } from '@/contexts/LicenseContext';\r\nimport {\r\n Shield, Calendar, Key, Layers, Users, Building, Zap, Server,\r\n CheckCircle, Clock, AlertTriangle, Loader2, X, Infinity as InfinityIcon,\r\n Lock, Unlock, ShieldCheck, Monitor\r\n} from 'lucide-react';\r\n\r\nconst colorClasses = {\r\n blue: 'bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]',\r\n green: 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]',\r\n yellow: 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]',\r\n red: 'bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]',\r\n neutral: 'bg-[var(--bg-secondary)] text-[var(--text-primary)] border-[var(--border-color)]',\r\n};\r\n\r\ninterface License {\r\n isReadOnlyMode: boolean;\r\n isInTrial: boolean;\r\n trialDaysRemaining: number;\r\n status: string;\r\n daysUntilExpiration: number;\r\n isInGracePeriod: boolean;\r\n isPerpetual: boolean;\r\n edition: string;\r\n limits: { users: number };\r\n gracePeriodDays: number;\r\n enabledFeatures: string[];\r\n}\r\n\r\nfunction getStatusColor(license: License) {\r\n if (license.status === 'NoLicense') return 'red' as const;\r\n if (license.isReadOnlyMode) return 'red' as const;\r\n if (license.isInGracePeriod) return 'yellow' as const;\r\n if (license.isInTrial && license.trialDaysRemaining <= 7) return 'yellow' as const;\r\n if (license.status === 'Active' && license.daysUntilExpiration <= 30) return 'yellow' as const;\r\n if (license.status === 'Active') return 'green' as const;\r\n return 'red' as const;\r\n}\r\n\r\nfunction getLicenseDaysColor(license: { isPerpetual: boolean; isInTrial: boolean; trialDaysRemaining: number; daysUntilExpiration: number }): 'red' | 'yellow' | 'green' | 'blue' {\r\n if (license.isPerpetual) return 'green';\r\n const daysRemaining = license.isInTrial ? license.trialDaysRemaining : license.daysUntilExpiration;\r\n if (daysRemaining <= 15) return 'red';\r\n if (daysRemaining <= 30) return 'yellow';\r\n return 'green';\r\n}\r\n\r\nfunction formatDate(dateStr: string | null): string {\r\n if (!dateStr) return '-';\r\n return new Date(dateStr).toLocaleDateString(undefined, {\r\n year: 'numeric',\r\n month: 'long',\r\n day: 'numeric',\r\n });\r\n}\r\n\r\nfunction buildKpiCards(license: License, t: TFunction) {\r\n const statusColor = getStatusColor(license);\r\n const daysRemaining = license.isInTrial ? license.trialDaysRemaining : license.daysUntilExpiration;\r\n const daysColor = getLicenseDaysColor(license);\r\n\r\n return [\r\n {\r\n label: t('license.info.edition', 'Edition'),\r\n value: t(`license.edition.${license.edition.toLowerCase()}`, license.edition),\r\n icon: Shield,\r\n color: 'blue' as const,\r\n },\r\n {\r\n label: t('license.info.status', 'Status'),\r\n value: license.isInGracePeriod\r\n ? t('license.page.gracePeriod', 'Grace Period')\r\n : t(`license.status.${license.status.toLowerCase()}`, license.status),\r\n icon: license.isReadOnlyMode ? AlertTriangle : CheckCircle,\r\n color: statusColor,\r\n },\r\n {\r\n label: t('license.page.daysRemaining', 'Days remaining'),\r\n value: license.isPerpetual ? '\\u221E' : daysRemaining.toString(),\r\n icon: license.isPerpetual ? InfinityIcon : Clock,\r\n color: daysColor,\r\n },\r\n {\r\n label: t('license.page.maxUsers', 'Max Users'),\r\n value: license.limits.users > 0 ? license.limits.users.toString() : t('license.page.unlimited', 'Unlimited'),\r\n icon: Users,\r\n color: 'blue' as const,\r\n },\r\n ];\r\n}\r\n\r\n// Sub-component: Status Banners\r\ninterface StatusBannersProps {\r\n readonly showTrialSuccess: boolean;\r\n readonly isInGracePeriod: boolean;\r\n readonly validationResult: { type: 'success' | 'revoked' | 'error'; message: string } | null;\r\n readonly gracePeriodDays: number;\r\n readonly onTrialSuccessClose: () => void;\r\n readonly onValidationResultClear: () => void;\r\n readonly t: TFunction;\r\n}\r\n\r\nfunction StatusBanners({\r\n showTrialSuccess, isInGracePeriod, validationResult, gracePeriodDays,\r\n onTrialSuccessClose, onValidationResultClear, t\r\n}: StatusBannersProps) {\r\n return (\r\n <>\r\n {showTrialSuccess && (\r\n <div className=\"flex items-center gap-3 p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg animate-in fade-in slide-in-from-top\">\r\n <CheckCircle className=\"w-5 h-5 text-green-600 dark:text-green-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-sm font-medium text-green-900 dark:text-green-300\">\r\n {t('license.trial.successBanner', 'Your 30-day trial is activated!')}\r\n </p>\r\n </div>\r\n <button\r\n onClick={onTrialSuccessClose}\r\n className=\"text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300\"\r\n >\r\n <X className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {isInGracePeriod && (\r\n <div className=\"flex items-center gap-3 p-4 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg\">\r\n <AlertTriangle className=\"w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-sm font-medium text-amber-900 dark:text-amber-300\">\r\n {t('license.page.gracePeriodBanner', 'Your license has expired. You are in a {{days}}-day grace period. Renew to avoid service interruption.', { days: gracePeriodDays })}\r\n </p>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {validationResult && (\r\n <div className={`flex items-center gap-3 p-4 rounded-lg border ${\r\n validationResult.type === 'success'\r\n ? 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800'\r\n : validationResult.type === 'revoked'\r\n ? 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800'\r\n : 'bg-amber-50 dark:bg-amber-900/20 border-amber-200 dark:border-amber-800'\r\n }`}>\r\n {validationResult.type === 'success'\r\n ? <CheckCircle className=\"w-5 h-5 text-green-600 dark:text-green-400 flex-shrink-0\" />\r\n : <AlertTriangle className={`w-5 h-5 flex-shrink-0 ${\r\n validationResult.type === 'revoked'\r\n ? 'text-red-600 dark:text-red-400'\r\n : 'text-amber-600 dark:text-amber-400'\r\n }`} />\r\n }\r\n <p className={`text-sm font-medium flex-1 ${\r\n validationResult.type === 'success'\r\n ? 'text-green-900 dark:text-green-300'\r\n : validationResult.type === 'revoked'\r\n ? 'text-red-900 dark:text-red-300'\r\n : 'text-amber-900 dark:text-amber-300'\r\n }`}>\r\n {validationResult.message}\r\n </p>\r\n <button\r\n onClick={onValidationResultClear}\r\n className={\r\n validationResult.type === 'success'\r\n ? 'text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300'\r\n : validationResult.type === 'revoked'\r\n ? 'text-red-600 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300'\r\n : 'text-amber-600 dark:text-amber-400 hover:text-amber-700 dark:hover:text-amber-400'\r\n }\r\n >\r\n <X className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n )}\r\n </>\r\n );\r\n}\r\n\r\n// Sub-component: Features Grid\r\ninterface FeaturesGridProps {\r\n readonly hasAllFeatures: boolean;\r\n readonly enabledFeatures: string[];\r\n readonly availableFeatures?: LicenseFeatureGroup[];\r\n readonly t: TFunction;\r\n}\r\n\r\nfunction FeaturesGrid({ hasAllFeatures, enabledFeatures, availableFeatures, t }: FeaturesGridProps) {\r\n if (!availableFeatures || availableFeatures.length === 0) {\r\n return (\r\n <p className=\"text-[var(--text-secondary)] text-sm italic\">\r\n {t('license.page.noFeatures', 'No features enabled')}\r\n </p>\r\n );\r\n }\r\n\r\n return (\r\n <>\r\n {hasAllFeatures && (\r\n <div className=\"flex items-center gap-2 p-3 mb-4 bg-[var(--success-bg)] text-[var(--success-text)] rounded-lg border border-[var(--success-border)]\">\r\n <CheckCircle className=\"w-5 h-5\" />\r\n <span className=\"font-medium\">{t('license.page.allFeatures', 'All features enabled')}</span>\r\n </div>\r\n )}\r\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\r\n {availableFeatures.map(({ group, features }) => (\r\n <div key={group}>\r\n <h3 className=\"text-sm font-semibold text-[var(--text-secondary)] uppercase tracking-wider mb-3\">\r\n {t(`license.group.${group}`, group)}\r\n </h3>\r\n <div className=\"space-y-2\">\r\n {features.map((code) => {\r\n const enabled = hasAllFeatures || enabledFeatures.some(\r\n f => f.toLowerCase() === code.toLowerCase()\r\n );\r\n return (\r\n <div\r\n key={code}\r\n className={`flex items-center gap-2 px-3 py-2 rounded-lg border ${\r\n enabled\r\n ? 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]'\r\n : 'bg-[var(--bg-secondary)] text-[var(--text-secondary)] border-[var(--border-color)] opacity-60'\r\n }`}\r\n >\r\n {enabled\r\n ? <Unlock className=\"w-4 h-4 flex-shrink-0\" />\r\n : <Lock className=\"w-4 h-4 flex-shrink-0\" />\r\n }\r\n <span className=\"text-sm font-medium\">{t(`license.module.${code}`, code)}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n {!hasAllFeatures && enabledFeatures.length === 0 && (\r\n <p className=\"text-[var(--text-secondary)] text-sm italic mt-3\">\r\n {t('license.page.noFeatures', 'No features enabled')}\r\n </p>\r\n )}\r\n </>\r\n );\r\n}\r\n\r\nfunction useValidateLicense(refreshLicense: () => Promise<void>, t: (key: string, fallback: string, opts?: Record<string, unknown>) => string) {\r\n const [isValidating, setIsValidating] = useState(false);\r\n const [validationResult, setValidationResult] = useState<{ type: 'success' | 'revoked' | 'error'; message: string } | null>(null);\r\n\r\n const handleValidate = useCallback(async () => {\r\n setIsValidating(true);\r\n setValidationResult(null);\r\n try {\r\n const result = await api.post<{ valid: boolean; revoked: boolean; error?: string }>(\r\n '/api/administration/license/validate-server'\r\n );\r\n if (result.revoked) {\r\n setValidationResult({ type: 'revoked', message: t('license.validationRevoked', 'The license has been revoked by the server.') });\r\n await refreshLicense();\r\n } else if (result.valid) {\r\n setValidationResult({ type: 'success', message: t('license.validationSuccess', 'License is valid') });\r\n await refreshLicense();\r\n } else {\r\n setValidationResult({ type: 'error', message: result.error || t('license.validationError', 'Unable to validate the license with the server.') });\r\n }\r\n } catch {\r\n setValidationResult({ type: 'error', message: t('license.validationError', 'Unable to validate the license with the server.') });\r\n } finally {\r\n setIsValidating(false);\r\n setTimeout(() => setValidationResult(null), 5000);\r\n }\r\n }, [t, refreshLicense]);\r\n\r\n const clearValidationResult = useCallback(() => setValidationResult(null), []);\r\n\r\n return { isValidating, validationResult, handleValidate, clearValidationResult };\r\n}\r\n\r\nexport function LicenseManagementPage(): ReactElement | null {\r\n const { t } = useTranslation('admin');\r\n const { license, usage, isLoading, error, refreshLicense, isHalted, haltReason } = useLicense();\r\n const [showActivation, setShowActivation] = useState(false);\r\n const [searchParams, setSearchParams] = useSearchParams();\r\n const [showTrialSuccess, setShowTrialSuccess] = useState(false);\r\n const { isValidating, validationResult, handleValidate, clearValidationResult } = useValidateLicense(refreshLicense, t);\r\n\r\n // Refresh license data when the page is displayed (e.g. after creating a tenant)\r\n useEffect(() => {\r\n refreshLicense();\r\n }, [refreshLicense]);\r\n\r\n useEffect(() => {\r\n if (searchParams.get('trial') === 'success') {\r\n setShowTrialSuccess(true); // eslint-disable-line react-hooks/set-state-in-effect -- conditional URL param check\r\n const timer = setTimeout(() => {\r\n setShowTrialSuccess(false);\r\n searchParams.delete('trial');\r\n setSearchParams(searchParams, { replace: true });\r\n }, 5000);\r\n return () => clearTimeout(timer);\r\n }\r\n }, [searchParams, setSearchParams]);\r\n\r\n if (isLoading) {\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(--text-secondary)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n if (error || !license) {\r\n return (\r\n <div className=\"p-6\">\r\n <div className=\"card p-6 text-center\">\r\n <AlertTriangle className=\"w-12 h-12 mx-auto mb-4 text-[var(--warning-text)]\" />\r\n <h2 className=\"text-lg font-semibold mb-2\">{t('license.page.errorTitle', 'Unable to load license')}</h2>\r\n <p className=\"text-[var(--text-secondary)] mb-4\">{error || t('license.page.errorDesc', 'License information is not available.')}</p>\r\n <button\r\n onClick={() => refreshLicense()}\r\n className=\"btn-primary px-4 py-2\"\r\n >\r\n {t('common.retry', 'Retry')}\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n const hasAllFeatures = hasAllLicenseFeatures(license.enabledFeatures);\r\n const kpiCards = buildKpiCards(license, t);\r\n\r\n return (\r\n <div className=\"p-6 space-y-6\">\r\n {isHalted && (\r\n <div className=\"flex items-center gap-3 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-sm font-medium text-red-900 dark:text-red-300\">\r\n {t('license.halted.warning', 'Licence suspendue')}\r\n </p>\r\n {haltReason && (\r\n <p className=\"text-sm text-red-800 dark:text-red-200 mt-1\">\r\n {haltReason}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n <StatusBanners\r\n showTrialSuccess={showTrialSuccess}\r\n isInGracePeriod={license.isInGracePeriod}\r\n validationResult={validationResult}\r\n gracePeriodDays={license.gracePeriodDays}\r\n onTrialSuccessClose={() => setShowTrialSuccess(false)}\r\n onValidationResultClear={clearValidationResult}\r\n t={t}\r\n />\r\n\r\n {/* Banners handled by StatusBanners component above */}\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('license.page.title', 'License Management')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)] mt-1\">\r\n {t('license.page.subtitle', 'View and manage your platform license')}\r\n </p>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <LicenseStatusBadge showDetails />\r\n <button\r\n onClick={handleValidate}\r\n disabled={isValidating}\r\n className=\"btn-secondary px-4 py-2 flex items-center gap-2\"\r\n >\r\n {isValidating\r\n ? <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n : <ShieldCheck className=\"w-4 h-4\" />\r\n }\r\n {isValidating\r\n ? t('license.validating', 'Validating...')\r\n : t('license.validate', 'Validate')}\r\n </button>\r\n <button\r\n onClick={() => setShowActivation(true)}\r\n className=\"btn-primary px-4 py-2 flex items-center gap-2\"\r\n >\r\n <Key className=\"w-4 h-4\" />\r\n {t('license.activate', 'Activate')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* KPI Cards */}\r\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\r\n {kpiCards.map((card) => (\r\n <div key={card.label} className={`card p-4 border ${colorClasses[card.color]}`}>\r\n <div className=\"flex items-center gap-2 mb-2\">\r\n <card.icon className=\"w-5 h-5 opacity-80\" />\r\n <span className=\"text-sm opacity-80\">{card.label}</span>\r\n </div>\r\n <div className=\"text-2xl font-bold\">{card.value}</div>\r\n </div>\r\n ))}\r\n </div>\r\n\r\n {/* Limits Section */}\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Zap className=\"w-5 h-5\" />\r\n {t('license.info.limits', 'Limits')}\r\n </h2>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n <CircularGauge\r\n icon={Users}\r\n label={t('license.page.usersLimit', 'Users')}\r\n max={license.limits.users}\r\n current={usage?.activeUsers ?? 0}\r\n margin={10}\r\n t={t}\r\n />\r\n <CircularGauge\r\n icon={Building}\r\n label={t('license.page.tenantsLimit', 'Tenants (B2B)')}\r\n max={license.limits.tenants}\r\n current={usage?.activeTenants ?? 0}\r\n margin={2}\r\n t={t}\r\n />\r\n </div>\r\n {/* Custom limits from JWT */}\r\n {(() => {\r\n const standardKeys = ['users', 'tenants', 'max_instances', 'max_users'];\r\n const customEntries = Object.entries(license.limits.custom ?? {}).filter(\r\n ([key]) => !standardKeys.includes(key)\r\n );\r\n if (customEntries.length === 0) return null;\r\n return (\r\n <div className=\"mt-4 pt-4 border-t border-[var(--border-color)]\">\r\n <h3 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n {t('license.page.customLimits', 'Custom Limits')}\r\n </h3>\r\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-3\">\r\n {customEntries.map(([key, value]) => (\r\n <div key={key} className=\"flex justify-between items-center py-1.5 px-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{key}</span>\r\n <span className=\"text-sm font-medium\">{value}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n })()}\r\n </div>\r\n\r\n {/* Details + Subscription + Machine Section */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\r\n {/* License Details */}\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Calendar className=\"w-5 h-5\" />\r\n {t('license.page.details', 'License Details')}\r\n </h2>\r\n <div className=\"space-y-3\">\r\n <DetailRow label={t('license.info.productId', 'Product')} value={license.productId} />\r\n <DetailRow label={t('license.info.company', 'Company')} value={license.companyName || '-'} />\r\n <DetailRow\r\n label={t('license.info.edition', 'Edition')}\r\n value={t(`license.edition.${license.edition.toLowerCase()}`, license.edition)}\r\n />\r\n <DetailRow\r\n label={t('license.info.status', 'Status')}\r\n value={t(`license.status.${license.status.toLowerCase()}`, license.status)}\r\n />\r\n <DetailRow\r\n label={t('license.info.activatedAt', 'Activated At')}\r\n value={formatDate(license.activatedAt)}\r\n />\r\n <DetailRow\r\n label={t('license.info.expiresAt', 'Expires At')}\r\n value={license.isPerpetual\r\n ? t('license.page.never', 'Never (Perpetual)')\r\n : formatDate(license.expiresAt)}\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Subscription Info */}\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Server className=\"w-5 h-5\" />\r\n {t('license.page.subscription', 'Subscription')}\r\n </h2>\r\n <div className=\"space-y-3\">\r\n <DetailRow\r\n label={t('license.page.licenseType', 'License Type')}\r\n value={license.isPerpetual\r\n ? t('license.page.perpetual', 'Perpetual')\r\n : license.isInTrial\r\n ? t('license.edition.trial', 'Trial')\r\n : t('license.page.subscription', 'Subscription')}\r\n />\r\n <DetailRow\r\n label={t('license.page.maxUsers', 'Max Users')}\r\n value={license.limits.users > 0 ? license.limits.users.toString() : t('license.page.unlimited', 'Unlimited')}\r\n />\r\n <DetailRow\r\n label={t('license.page.gracePeriodDays', 'Grace Period')}\r\n value={license.gracePeriodDays > 0\r\n ? t('license.page.gracePeriodValue', '{{days}} days', { days: license.gracePeriodDays })\r\n : t('license.page.noGracePeriod', 'None')}\r\n />\r\n <DetailRow\r\n label={t('license.page.renewalDate', 'Renewal Date')}\r\n value={formatDate(license.renewalDate)}\r\n />\r\n <DetailRow\r\n label={t('license.page.mode', 'Mode')}\r\n value={license.isReadOnlyMode\r\n ? t('license.page.readOnly', 'Read-only')\r\n : license.isInTrial\r\n ? t('license.edition.trial', 'Trial')\r\n : t('license.page.licensed', 'Licensed')}\r\n />\r\n {license.isInGracePeriod && (\r\n <DetailRow\r\n label={t('license.page.gracePeriodStatus', 'Grace Period Status')}\r\n value={t('license.page.inGracePeriod', 'Active')}\r\n highlight=\"yellow\"\r\n />\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Machine Info */}\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n {t('license.page.machineInfo', 'Machine')}\r\n </h2>\r\n <div className=\"space-y-3\">\r\n <div className=\"py-2 border-b border-[var(--border-color)] last:border-b-0\">\r\n <div className=\"flex justify-between items-center mb-1\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{t('license.page.machineName', 'Machine Name')}</span>\r\n </div>\r\n <span className=\"text-xs font-mono text-[var(--text-primary)] break-all\">\r\n {license.machineName || '-'}\r\n </span>\r\n </div>\r\n <div className=\"py-2 border-b border-[var(--border-color)] last:border-b-0\">\r\n <div className=\"flex justify-between items-center mb-1\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{t('license.page.instanceId', 'Instance ID')}</span>\r\n </div>\r\n <span className=\"text-xs font-mono text-[var(--text-primary)] break-all\">\r\n {license.instanceId || '-'}\r\n </span>\r\n </div>\r\n <div className=\"py-2 border-b border-[var(--border-color)] last:border-b-0\">\r\n <div className=\"flex justify-between items-center mb-1\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{t('license.page.licenseId', 'License ID')}</span>\r\n </div>\r\n <span className=\"text-xs font-mono text-[var(--text-primary)] break-all\">\r\n {license.licenseServerId || '-'}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Layers className=\"w-5 h-5\" />\r\n {t('license.info.features', 'Features')}\r\n </h2>\r\n <FeaturesGrid\r\n hasAllFeatures={hasAllFeatures}\r\n enabledFeatures={license.enabledFeatures}\r\n availableFeatures={license.availableFeatures}\r\n t={t}\r\n />\r\n </div>\r\n\r\n <LicenseActivationDialog open={showActivation} onOpenChange={setShowActivation} />\r\n </div>\r\n );\r\n}\r\n\r\nfunction DetailRow({ label, value, highlight }: { label: string; value: string; highlight?: 'yellow' | 'red' | 'green' }) {\r\n const highlightClass = highlight === 'yellow'\r\n ? 'text-amber-600 dark:text-amber-400 font-semibold'\r\n : highlight === 'red'\r\n ? 'text-red-600 dark:text-red-400 font-semibold'\r\n : highlight === 'green'\r\n ? 'text-green-600 dark:text-green-400 font-semibold'\r\n : 'text-[var(--text-primary)]';\r\n\r\n return (\r\n <div className=\"flex justify-between items-center py-2 border-b border-[var(--border-color)] last:border-b-0\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{label}</span>\r\n <span className={`text-sm font-medium ${highlightClass}`}>{value}</span>\r\n </div>\r\n );\r\n}\r\n\r\nfunction getGaugeIconColor(exceededEffective: boolean, inToleranceZone: boolean): string {\r\n if (exceededEffective) return 'text-red-500';\r\n if (inToleranceZone) return 'text-amber-500';\r\n return 'text-blue-500';\r\n}\r\n\r\nfunction getGaugeTextColor(exceededEffective: boolean, inToleranceZone: boolean): string {\r\n if (exceededEffective) return 'text-red-500';\r\n if (inToleranceZone) return 'text-amber-500';\r\n return 'text-[var(--text-primary)]';\r\n}\r\n\r\nfunction CircularGauge({ icon: Icon, label, max, current, margin = 0, t }: {\r\n icon: typeof Users;\r\n label: string;\r\n max: number;\r\n current: number;\r\n margin?: number;\r\n t: (key: string, fallback: string, opts?: Record<string, unknown>) => string;\r\n}) {\r\n const unlimited = max <= 0;\r\n // `max` is the licensed contractual limit (from JWT, e.g. 50 users).\r\n // The tolerance `margin` is ADDED on top to form the hard upper bound.\r\n // Example: licensed=50 + margin=10 → total=60.\r\n const licensedLimit = max;\r\n const total = max + margin;\r\n\r\n // SVG arc parameters\r\n const size = 140;\r\n const strokeWidth = 12;\r\n const radius = (size - strokeWidth) / 2;\r\n const center = size / 2;\r\n // Arc spans 270 degrees (from 135° to 405°)\r\n const startAngle = 135;\r\n const totalArc = 270;\r\n\r\n // Percentages\r\n const usagePercent = total > 0 ? Math.min(1, current / total) : 0;\r\n const licensedPercent = total > 0 ? licensedLimit / total : 1;\r\n\r\n // Zone detection\r\n const inToleranceZone = margin > 0 && current > licensedLimit && current <= total;\r\n const exceededEffective = current > total;\r\n\r\n // Colors\r\n let usageColor = '#3b82f6'; // blue-500\r\n if (exceededEffective) usageColor = '#ef4444'; // red-500\r\n else if (inToleranceZone) usageColor = '#f59e0b'; // amber-500\r\n\r\n const toleranceTrackColor = 'rgba(245, 158, 11, 0.25)'; // amber with opacity\r\n\r\n // Helper to compute SVG arc endpoint\r\n const polarToCartesian = (angleDeg: number) => {\r\n const rad = (angleDeg * Math.PI) / 180;\r\n return {\r\n x: center + radius * Math.cos(rad),\r\n y: center + radius * Math.sin(rad),\r\n };\r\n };\r\n\r\n // Build an arc path from startAngle spanning `sweep` degrees\r\n const describeArc = (sweep: number) => {\r\n if (sweep <= 0) return '';\r\n const endAngle = startAngle + sweep;\r\n const start = polarToCartesian(startAngle);\r\n const end = polarToCartesian(endAngle);\r\n const largeArc = sweep > 180 ? 1 : 0;\r\n return `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArc} 1 ${end.x} ${end.y}`;\r\n };\r\n\r\n // Percentage display\r\n const displayPercent = total > 0 ? Math.round((current / licensedLimit) * 100) : 0;\r\n\r\n if (unlimited) {\r\n return (\r\n <div className=\"flex flex-col items-center gap-3 py-4\">\r\n <div className=\"relative\" style={{ width: size, height: size }}>\r\n <svg width={size} height={size}>\r\n {/* Background track */}\r\n <path\r\n d={describeArc(totalArc)}\r\n fill=\"none\"\r\n stroke=\"var(--bg-tertiary)\"\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n />\r\n {/* Full green arc for unlimited */}\r\n <path\r\n d={describeArc(totalArc)}\r\n fill=\"none\"\r\n stroke=\"#22c55e\"\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n opacity={0.5}\r\n />\r\n </svg>\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\r\n <Icon className=\"w-6 h-6 text-green-500 mb-1\" />\r\n <span className=\"text-lg font-bold text-green-500\">∞</span>\r\n </div>\r\n </div>\r\n <span className=\"text-sm font-medium text-[var(--text-primary)]\">{label}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">{t('license.page.unlimited', 'Unlimited')}</span>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"flex flex-col items-center gap-3 py-4\">\r\n <div className=\"relative\" style={{ width: size, height: size }}>\r\n <svg width={size} height={size}>\r\n {/* Background track */}\r\n <path\r\n d={describeArc(totalArc)}\r\n fill=\"none\"\r\n stroke=\"var(--bg-tertiary)\"\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n />\r\n {/* Tolerance zone: arc from licensed limit to effective limit */}\r\n {margin > 0 && (() => {\r\n const toleranceSweep = totalArc * (1 - licensedPercent);\r\n const toleranceStartAngle = startAngle + totalArc * licensedPercent;\r\n const tStart = polarToCartesian(toleranceStartAngle);\r\n const tEnd = polarToCartesian(startAngle + totalArc);\r\n const largeArc = toleranceSweep > 180 ? 1 : 0;\r\n const tolerancePath = `M ${tStart.x} ${tStart.y} A ${radius} ${radius} 0 ${largeArc} 1 ${tEnd.x} ${tEnd.y}`;\r\n return (\r\n <path\r\n d={tolerancePath}\r\n fill=\"none\"\r\n stroke={toleranceTrackColor}\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n />\r\n );\r\n })()}\r\n {/* Usage arc */}\r\n <path\r\n d={describeArc(totalArc * usagePercent)}\r\n fill=\"none\"\r\n stroke={usageColor}\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n style={{ transition: 'stroke 0.3s, d 0.3s' }}\r\n />\r\n {/* Licensed limit tick mark */}\r\n {margin > 0 && (() => {\r\n const tickAngle = startAngle + totalArc * licensedPercent;\r\n const innerR = radius - strokeWidth / 2 - 2;\r\n const outerR = radius + strokeWidth / 2 + 2;\r\n const rad = (tickAngle * Math.PI) / 180;\r\n return (\r\n <line\r\n x1={center + innerR * Math.cos(rad)}\r\n y1={center + innerR * Math.sin(rad)}\r\n x2={center + outerR * Math.cos(rad)}\r\n y2={center + outerR * Math.sin(rad)}\r\n stroke=\"var(--text-secondary)\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n />\r\n );\r\n })()}\r\n </svg>\r\n {/* Center content */}\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\r\n <Icon className={`w-5 h-5 mb-0.5 ${getGaugeIconColor(exceededEffective, inToleranceZone)}`} />\r\n <span className={`text-2xl font-bold ${getGaugeTextColor(exceededEffective, inToleranceZone)}`}>\r\n {displayPercent}%\r\n </span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {current} / {licensedLimit}\r\n </span>\r\n </div>\r\n </div>\r\n <span className=\"text-sm font-medium text-[var(--text-primary)]\">{label}</span>\r\n {margin > 0 && (\r\n <span className={`text-xs ${inToleranceZone || exceededEffective ? 'text-amber-600 dark:text-amber-400' : 'text-[var(--text-secondary)]'}`}>\r\n +{margin} {t('license.page.tolerance', 'tolerance')}\r\n </span>\r\n )}\r\n </div>\r\n );\r\n}\r\n"],"names":["colorClasses","getStatusColor","license","getLicenseDaysColor","daysRemaining","formatDate","dateStr","buildKpiCards","t","statusColor","daysColor","Shield","AlertTriangle","CheckCircle","InfinityIcon","Clock","Users","StatusBanners","showTrialSuccess","isInGracePeriod","validationResult","gracePeriodDays","onTrialSuccessClose","onValidationResultClear","jsxs","Fragment","jsx","X","FeaturesGrid","hasAllFeatures","enabledFeatures","availableFeatures","group","features","code","enabled","f","Unlock","Lock","useValidateLicense","refreshLicense","isValidating","setIsValidating","useState","setValidationResult","handleValidate","useCallback","result","api","clearValidationResult","LicenseManagementPage","useTranslation","usage","isLoading","error","isHalted","haltReason","useLicense","showActivation","setShowActivation","searchParams","setSearchParams","useSearchParams","setShowTrialSuccess","useEffect","timer","Loader2","hasAllLicenseFeatures","kpiCards","LicenseStatusBadge","ShieldCheck","Key","card","Zap","CircularGauge","Building","standardKeys","customEntries","key","value","Calendar","DetailRow","Server","Monitor","Layers","LicenseActivationDialog","label","highlight","getGaugeIconColor","exceededEffective","inToleranceZone","getGaugeTextColor","Icon","max","current","margin","unlimited","licensedLimit","total","size","strokeWidth","radius","center","startAngle","totalArc","usagePercent","licensedPercent","usageColor","toleranceTrackColor","polarToCartesian","angleDeg","rad","describeArc","sweep","endAngle","start","end","largeArc","displayPercent","toleranceSweep","toleranceStartAngle","tStart","tEnd","tolerancePath","tickAngle","innerR","outerR"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-rRAbl04H.js","sources":["../../src/pages/platform/administration/configuration/license/LicenseManagementPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport type { TFunction } from 'i18next';\r\nimport { useSearchParams } from 'react-router-dom';\r\nimport { useLicense } from '@/contexts/LicenseContext';\r\nimport { api } from '@/services/api/apiClient';\r\nimport { hasAllLicenseFeatures } from '@/utils/licenseUtils';\r\nimport { LicenseStatusBadge } from '@/components/license/LicenseStatusBadge';\r\nimport { LicenseActivationDialog } from '@/components/license/LicenseActivationDialog';\r\nimport type { LicenseFeatureGroup } from '@/contexts/LicenseContext';\r\nimport {\r\n Shield, Calendar, Key, Layers, Users, Building, Zap, Server,\r\n CheckCircle, Clock, AlertTriangle, Loader2, X, Infinity as InfinityIcon,\r\n Lock, Unlock, ShieldCheck, Monitor\r\n} from 'lucide-react';\r\n\r\nconst colorClasses = {\r\n blue: 'bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]',\r\n green: 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]',\r\n yellow: 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]',\r\n red: 'bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]',\r\n neutral: 'bg-[var(--bg-secondary)] text-[var(--text-primary)] border-[var(--border-color)]',\r\n};\r\n\r\ninterface License {\r\n isReadOnlyMode: boolean;\r\n isInTrial: boolean;\r\n trialDaysRemaining: number;\r\n status: string;\r\n daysUntilExpiration: number;\r\n isInGracePeriod: boolean;\r\n isPerpetual: boolean;\r\n edition: string;\r\n limits: { users: number };\r\n gracePeriodDays: number;\r\n enabledFeatures: string[];\r\n}\r\n\r\nfunction getStatusColor(license: License) {\r\n if (license.status === 'NoLicense') return 'red' as const;\r\n if (license.isReadOnlyMode) return 'red' as const;\r\n if (license.isInGracePeriod) return 'yellow' as const;\r\n if (license.isInTrial && license.trialDaysRemaining <= 7) return 'yellow' as const;\r\n if (license.status === 'Active' && license.daysUntilExpiration <= 30) return 'yellow' as const;\r\n if (license.status === 'Active') return 'green' as const;\r\n return 'red' as const;\r\n}\r\n\r\nfunction getLicenseDaysColor(license: { isPerpetual: boolean; isInTrial: boolean; trialDaysRemaining: number; daysUntilExpiration: number }): 'red' | 'yellow' | 'green' | 'blue' {\r\n if (license.isPerpetual) return 'green';\r\n const daysRemaining = license.isInTrial ? license.trialDaysRemaining : license.daysUntilExpiration;\r\n if (daysRemaining <= 15) return 'red';\r\n if (daysRemaining <= 30) return 'yellow';\r\n return 'green';\r\n}\r\n\r\nfunction formatDate(dateStr: string | null): string {\r\n if (!dateStr) return '-';\r\n return new Date(dateStr).toLocaleDateString(undefined, {\r\n year: 'numeric',\r\n month: 'long',\r\n day: 'numeric',\r\n });\r\n}\r\n\r\nfunction buildKpiCards(license: License, t: TFunction) {\r\n const statusColor = getStatusColor(license);\r\n const daysRemaining = license.isInTrial ? license.trialDaysRemaining : license.daysUntilExpiration;\r\n const daysColor = getLicenseDaysColor(license);\r\n\r\n return [\r\n {\r\n label: t('license.info.edition', 'Edition'),\r\n value: t(`license.edition.${license.edition.toLowerCase()}`, license.edition),\r\n icon: Shield,\r\n color: 'blue' as const,\r\n },\r\n {\r\n label: t('license.info.status', 'Status'),\r\n value: license.isInGracePeriod\r\n ? t('license.page.gracePeriod', 'Grace Period')\r\n : t(`license.status.${license.status.toLowerCase()}`, license.status),\r\n icon: license.isReadOnlyMode ? AlertTriangle : CheckCircle,\r\n color: statusColor,\r\n },\r\n {\r\n label: t('license.page.daysRemaining', 'Days remaining'),\r\n value: license.isPerpetual ? '\\u221E' : daysRemaining.toString(),\r\n icon: license.isPerpetual ? InfinityIcon : Clock,\r\n color: daysColor,\r\n },\r\n {\r\n label: t('license.page.maxUsers', 'Max Users'),\r\n value: license.limits.users > 0 ? license.limits.users.toString() : t('license.page.unlimited', 'Unlimited'),\r\n icon: Users,\r\n color: 'blue' as const,\r\n },\r\n ];\r\n}\r\n\r\n// Sub-component: Status Banners\r\ninterface StatusBannersProps {\r\n readonly showTrialSuccess: boolean;\r\n readonly isInGracePeriod: boolean;\r\n readonly validationResult: { type: 'success' | 'revoked' | 'error'; message: string } | null;\r\n readonly gracePeriodDays: number;\r\n readonly onTrialSuccessClose: () => void;\r\n readonly onValidationResultClear: () => void;\r\n readonly t: TFunction;\r\n}\r\n\r\nfunction StatusBanners({\r\n showTrialSuccess, isInGracePeriod, validationResult, gracePeriodDays,\r\n onTrialSuccessClose, onValidationResultClear, t\r\n}: StatusBannersProps) {\r\n return (\r\n <>\r\n {showTrialSuccess && (\r\n <div className=\"flex items-center gap-3 p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg animate-in fade-in slide-in-from-top\">\r\n <CheckCircle className=\"w-5 h-5 text-green-600 dark:text-green-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-sm font-medium text-green-900 dark:text-green-300\">\r\n {t('license.trial.successBanner', 'Your 30-day trial is activated!')}\r\n </p>\r\n </div>\r\n <button\r\n onClick={onTrialSuccessClose}\r\n className=\"text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300\"\r\n >\r\n <X className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {isInGracePeriod && (\r\n <div className=\"flex items-center gap-3 p-4 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg\">\r\n <AlertTriangle className=\"w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-sm font-medium text-amber-900 dark:text-amber-300\">\r\n {t('license.page.gracePeriodBanner', 'Your license has expired. You are in a {{days}}-day grace period. Renew to avoid service interruption.', { days: gracePeriodDays })}\r\n </p>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {validationResult && (\r\n <div className={`flex items-center gap-3 p-4 rounded-lg border ${\r\n validationResult.type === 'success'\r\n ? 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800'\r\n : validationResult.type === 'revoked'\r\n ? 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800'\r\n : 'bg-amber-50 dark:bg-amber-900/20 border-amber-200 dark:border-amber-800'\r\n }`}>\r\n {validationResult.type === 'success'\r\n ? <CheckCircle className=\"w-5 h-5 text-green-600 dark:text-green-400 flex-shrink-0\" />\r\n : <AlertTriangle className={`w-5 h-5 flex-shrink-0 ${\r\n validationResult.type === 'revoked'\r\n ? 'text-red-600 dark:text-red-400'\r\n : 'text-amber-600 dark:text-amber-400'\r\n }`} />\r\n }\r\n <p className={`text-sm font-medium flex-1 ${\r\n validationResult.type === 'success'\r\n ? 'text-green-900 dark:text-green-300'\r\n : validationResult.type === 'revoked'\r\n ? 'text-red-900 dark:text-red-300'\r\n : 'text-amber-900 dark:text-amber-300'\r\n }`}>\r\n {validationResult.message}\r\n </p>\r\n <button\r\n onClick={onValidationResultClear}\r\n className={\r\n validationResult.type === 'success'\r\n ? 'text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300'\r\n : validationResult.type === 'revoked'\r\n ? 'text-red-600 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300'\r\n : 'text-amber-600 dark:text-amber-400 hover:text-amber-700 dark:hover:text-amber-400'\r\n }\r\n >\r\n <X className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n )}\r\n </>\r\n );\r\n}\r\n\r\n// Sub-component: Features Grid\r\ninterface FeaturesGridProps {\r\n readonly hasAllFeatures: boolean;\r\n readonly enabledFeatures: string[];\r\n readonly availableFeatures?: LicenseFeatureGroup[];\r\n readonly t: TFunction;\r\n}\r\n\r\nfunction FeaturesGrid({ hasAllFeatures, enabledFeatures, availableFeatures, t }: FeaturesGridProps) {\r\n if (!availableFeatures || availableFeatures.length === 0) {\r\n return (\r\n <p className=\"text-[var(--text-secondary)] text-sm italic\">\r\n {t('license.page.noFeatures', 'No features enabled')}\r\n </p>\r\n );\r\n }\r\n\r\n return (\r\n <>\r\n {hasAllFeatures && (\r\n <div className=\"flex items-center gap-2 p-3 mb-4 bg-[var(--success-bg)] text-[var(--success-text)] rounded-lg border border-[var(--success-border)]\">\r\n <CheckCircle className=\"w-5 h-5\" />\r\n <span className=\"font-medium\">{t('license.page.allFeatures', 'All features enabled')}</span>\r\n </div>\r\n )}\r\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\r\n {availableFeatures.map(({ group, features }) => (\r\n <div key={group}>\r\n <h3 className=\"text-sm font-semibold text-[var(--text-secondary)] uppercase tracking-wider mb-3\">\r\n {t(`license.group.${group}`, group)}\r\n </h3>\r\n <div className=\"space-y-2\">\r\n {features.map((code) => {\r\n const enabled = hasAllFeatures || enabledFeatures.some(\r\n f => f.toLowerCase() === code.toLowerCase()\r\n );\r\n return (\r\n <div\r\n key={code}\r\n className={`flex items-center gap-2 px-3 py-2 rounded-lg border ${\r\n enabled\r\n ? 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]'\r\n : 'bg-[var(--bg-secondary)] text-[var(--text-secondary)] border-[var(--border-color)] opacity-60'\r\n }`}\r\n >\r\n {enabled\r\n ? <Unlock className=\"w-4 h-4 flex-shrink-0\" />\r\n : <Lock className=\"w-4 h-4 flex-shrink-0\" />\r\n }\r\n <span className=\"text-sm font-medium\">{t(`license.module.${code}`, code)}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n {!hasAllFeatures && enabledFeatures.length === 0 && (\r\n <p className=\"text-[var(--text-secondary)] text-sm italic mt-3\">\r\n {t('license.page.noFeatures', 'No features enabled')}\r\n </p>\r\n )}\r\n </>\r\n );\r\n}\r\n\r\nfunction useValidateLicense(refreshLicense: () => Promise<void>, t: (key: string, fallback: string, opts?: Record<string, unknown>) => string) {\r\n const [isValidating, setIsValidating] = useState(false);\r\n const [validationResult, setValidationResult] = useState<{ type: 'success' | 'revoked' | 'error'; message: string } | null>(null);\r\n\r\n const handleValidate = useCallback(async () => {\r\n setIsValidating(true);\r\n setValidationResult(null);\r\n try {\r\n const result = await api.post<{ valid: boolean; revoked: boolean; error?: string }>(\r\n '/api/administration/license/validate-server'\r\n );\r\n if (result.revoked) {\r\n setValidationResult({ type: 'revoked', message: t('license.validationRevoked', 'The license has been revoked by the server.') });\r\n await refreshLicense();\r\n } else if (result.valid) {\r\n setValidationResult({ type: 'success', message: t('license.validationSuccess', 'License is valid') });\r\n await refreshLicense();\r\n } else {\r\n setValidationResult({ type: 'error', message: result.error || t('license.validationError', 'Unable to validate the license with the server.') });\r\n }\r\n } catch {\r\n setValidationResult({ type: 'error', message: t('license.validationError', 'Unable to validate the license with the server.') });\r\n } finally {\r\n setIsValidating(false);\r\n setTimeout(() => setValidationResult(null), 5000);\r\n }\r\n }, [t, refreshLicense]);\r\n\r\n const clearValidationResult = useCallback(() => setValidationResult(null), []);\r\n\r\n return { isValidating, validationResult, handleValidate, clearValidationResult };\r\n}\r\n\r\nexport function LicenseManagementPage(): ReactElement | null {\r\n const { t } = useTranslation('admin');\r\n const { license, usage, isLoading, error, refreshLicense, isHalted, haltReason } = useLicense();\r\n const [showActivation, setShowActivation] = useState(false);\r\n const [searchParams, setSearchParams] = useSearchParams();\r\n const [showTrialSuccess, setShowTrialSuccess] = useState(false);\r\n const { isValidating, validationResult, handleValidate, clearValidationResult } = useValidateLicense(refreshLicense, t);\r\n\r\n // Refresh license data when the page is displayed (e.g. after creating a tenant)\r\n useEffect(() => {\r\n refreshLicense();\r\n }, [refreshLicense]);\r\n\r\n useEffect(() => {\r\n if (searchParams.get('trial') === 'success') {\r\n setShowTrialSuccess(true); // eslint-disable-line react-hooks/set-state-in-effect -- conditional URL param check\r\n const timer = setTimeout(() => {\r\n setShowTrialSuccess(false);\r\n searchParams.delete('trial');\r\n setSearchParams(searchParams, { replace: true });\r\n }, 5000);\r\n return () => clearTimeout(timer);\r\n }\r\n }, [searchParams, setSearchParams]);\r\n\r\n if (isLoading) {\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(--text-secondary)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n if (error || !license) {\r\n return (\r\n <div className=\"p-6\">\r\n <div className=\"card p-6 text-center\">\r\n <AlertTriangle className=\"w-12 h-12 mx-auto mb-4 text-[var(--warning-text)]\" />\r\n <h2 className=\"text-lg font-semibold mb-2\">{t('license.page.errorTitle', 'Unable to load license')}</h2>\r\n <p className=\"text-[var(--text-secondary)] mb-4\">{error || t('license.page.errorDesc', 'License information is not available.')}</p>\r\n <button\r\n onClick={() => refreshLicense()}\r\n className=\"btn-primary px-4 py-2\"\r\n >\r\n {t('common.retry', 'Retry')}\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n const hasAllFeatures = hasAllLicenseFeatures(license.enabledFeatures);\r\n const kpiCards = buildKpiCards(license, t);\r\n\r\n return (\r\n <div className=\"p-6 space-y-6\">\r\n {isHalted && (\r\n <div className=\"flex items-center gap-3 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-sm font-medium text-red-900 dark:text-red-300\">\r\n {t('license.halted.warning', 'Licence suspendue')}\r\n </p>\r\n {haltReason && (\r\n <p className=\"text-sm text-red-800 dark:text-red-200 mt-1\">\r\n {haltReason}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n <StatusBanners\r\n showTrialSuccess={showTrialSuccess}\r\n isInGracePeriod={license.isInGracePeriod}\r\n validationResult={validationResult}\r\n gracePeriodDays={license.gracePeriodDays}\r\n onTrialSuccessClose={() => setShowTrialSuccess(false)}\r\n onValidationResultClear={clearValidationResult}\r\n t={t}\r\n />\r\n\r\n {/* Banners handled by StatusBanners component above */}\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)]\">\r\n {t('license.page.title', 'License Management')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)] mt-1\">\r\n {t('license.page.subtitle', 'View and manage your platform license')}\r\n </p>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <LicenseStatusBadge showDetails />\r\n <button\r\n onClick={handleValidate}\r\n disabled={isValidating}\r\n className=\"btn-secondary px-4 py-2 flex items-center gap-2\"\r\n >\r\n {isValidating\r\n ? <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n : <ShieldCheck className=\"w-4 h-4\" />\r\n }\r\n {isValidating\r\n ? t('license.validating', 'Validating...')\r\n : t('license.validate', 'Validate')}\r\n </button>\r\n <button\r\n onClick={() => setShowActivation(true)}\r\n className=\"btn-primary px-4 py-2 flex items-center gap-2\"\r\n >\r\n <Key className=\"w-4 h-4\" />\r\n {t('license.activate', 'Activate')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* KPI Cards */}\r\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\r\n {kpiCards.map((card) => (\r\n <div key={card.label} className={`card p-4 border ${colorClasses[card.color]}`}>\r\n <div className=\"flex items-center gap-2 mb-2\">\r\n <card.icon className=\"w-5 h-5 opacity-80\" />\r\n <span className=\"text-sm opacity-80\">{card.label}</span>\r\n </div>\r\n <div className=\"text-2xl font-bold\">{card.value}</div>\r\n </div>\r\n ))}\r\n </div>\r\n\r\n {/* Limits Section */}\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Zap className=\"w-5 h-5\" />\r\n {t('license.info.limits', 'Limits')}\r\n </h2>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n <CircularGauge\r\n icon={Users}\r\n label={t('license.page.usersLimit', 'Users')}\r\n max={license.limits.users}\r\n current={usage?.activeUsers ?? 0}\r\n margin={10}\r\n t={t}\r\n />\r\n <CircularGauge\r\n icon={Building}\r\n label={t('license.page.tenantsLimit', 'Tenants (B2B)')}\r\n max={license.limits.tenants}\r\n current={usage?.activeTenants ?? 0}\r\n margin={2}\r\n t={t}\r\n />\r\n </div>\r\n {/* Custom limits from JWT */}\r\n {(() => {\r\n const standardKeys = ['users', 'tenants', 'max_instances', 'max_users'];\r\n const customEntries = Object.entries(license.limits.custom ?? {}).filter(\r\n ([key]) => !standardKeys.includes(key)\r\n );\r\n if (customEntries.length === 0) return null;\r\n return (\r\n <div className=\"mt-4 pt-4 border-t border-[var(--border-color)]\">\r\n <h3 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n {t('license.page.customLimits', 'Custom Limits')}\r\n </h3>\r\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-3\">\r\n {customEntries.map(([key, value]) => (\r\n <div key={key} className=\"flex justify-between items-center py-1.5 px-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{key}</span>\r\n <span className=\"text-sm font-medium\">{value}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n })()}\r\n </div>\r\n\r\n {/* Details + Subscription + Machine Section */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\r\n {/* License Details */}\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Calendar className=\"w-5 h-5\" />\r\n {t('license.page.details', 'License Details')}\r\n </h2>\r\n <div className=\"space-y-3\">\r\n <DetailRow label={t('license.info.productId', 'Product')} value={license.productId} />\r\n <DetailRow label={t('license.info.company', 'Company')} value={license.companyName || '-'} />\r\n <DetailRow\r\n label={t('license.info.edition', 'Edition')}\r\n value={t(`license.edition.${license.edition.toLowerCase()}`, license.edition)}\r\n />\r\n <DetailRow\r\n label={t('license.info.status', 'Status')}\r\n value={t(`license.status.${license.status.toLowerCase()}`, license.status)}\r\n />\r\n <DetailRow\r\n label={t('license.info.activatedAt', 'Activated At')}\r\n value={formatDate(license.activatedAt)}\r\n />\r\n <DetailRow\r\n label={t('license.info.expiresAt', 'Expires At')}\r\n value={license.isPerpetual\r\n ? t('license.page.never', 'Never (Perpetual)')\r\n : formatDate(license.expiresAt)}\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Subscription Info */}\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Server className=\"w-5 h-5\" />\r\n {t('license.page.subscription', 'Subscription')}\r\n </h2>\r\n <div className=\"space-y-3\">\r\n <DetailRow\r\n label={t('license.page.licenseType', 'License Type')}\r\n value={license.isPerpetual\r\n ? t('license.page.perpetual', 'Perpetual')\r\n : license.isInTrial\r\n ? t('license.edition.trial', 'Trial')\r\n : t('license.page.subscription', 'Subscription')}\r\n />\r\n <DetailRow\r\n label={t('license.page.maxUsers', 'Max Users')}\r\n value={license.limits.users > 0 ? license.limits.users.toString() : t('license.page.unlimited', 'Unlimited')}\r\n />\r\n <DetailRow\r\n label={t('license.page.gracePeriodDays', 'Grace Period')}\r\n value={license.gracePeriodDays > 0\r\n ? t('license.page.gracePeriodValue', '{{days}} days', { days: license.gracePeriodDays })\r\n : t('license.page.noGracePeriod', 'None')}\r\n />\r\n <DetailRow\r\n label={t('license.page.renewalDate', 'Renewal Date')}\r\n value={formatDate(license.renewalDate)}\r\n />\r\n <DetailRow\r\n label={t('license.page.mode', 'Mode')}\r\n value={license.isReadOnlyMode\r\n ? t('license.page.readOnly', 'Read-only')\r\n : license.isInTrial\r\n ? t('license.edition.trial', 'Trial')\r\n : t('license.page.licensed', 'Licensed')}\r\n />\r\n {license.isInGracePeriod && (\r\n <DetailRow\r\n label={t('license.page.gracePeriodStatus', 'Grace Period Status')}\r\n value={t('license.page.inGracePeriod', 'Active')}\r\n highlight=\"yellow\"\r\n />\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Machine Info */}\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n {t('license.page.machineInfo', 'Machine')}\r\n </h2>\r\n <div className=\"space-y-3\">\r\n <div className=\"py-2 border-b border-[var(--border-color)] last:border-b-0\">\r\n <div className=\"flex justify-between items-center mb-1\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{t('license.page.machineName', 'Machine Name')}</span>\r\n </div>\r\n <span className=\"text-xs font-mono text-[var(--text-primary)] break-all\">\r\n {license.machineName || '-'}\r\n </span>\r\n </div>\r\n <div className=\"py-2 border-b border-[var(--border-color)] last:border-b-0\">\r\n <div className=\"flex justify-between items-center mb-1\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{t('license.page.instanceId', 'Instance ID')}</span>\r\n </div>\r\n <span className=\"text-xs font-mono text-[var(--text-primary)] break-all\">\r\n {license.instanceId || '-'}\r\n </span>\r\n </div>\r\n <div className=\"py-2 border-b border-[var(--border-color)] last:border-b-0\">\r\n <div className=\"flex justify-between items-center mb-1\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{t('license.page.licenseId', 'License ID')}</span>\r\n </div>\r\n <span className=\"text-xs font-mono text-[var(--text-primary)] break-all\">\r\n {license.licenseServerId || '-'}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div className=\"card p-6\">\r\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\r\n <Layers className=\"w-5 h-5\" />\r\n {t('license.info.features', 'Features')}\r\n </h2>\r\n <FeaturesGrid\r\n hasAllFeatures={hasAllFeatures}\r\n enabledFeatures={license.enabledFeatures}\r\n availableFeatures={license.availableFeatures}\r\n t={t}\r\n />\r\n </div>\r\n\r\n <LicenseActivationDialog open={showActivation} onOpenChange={setShowActivation} />\r\n </div>\r\n );\r\n}\r\n\r\nfunction DetailRow({ label, value, highlight }: { label: string; value: string; highlight?: 'yellow' | 'red' | 'green' }) {\r\n const highlightClass = highlight === 'yellow'\r\n ? 'text-amber-600 dark:text-amber-400 font-semibold'\r\n : highlight === 'red'\r\n ? 'text-red-600 dark:text-red-400 font-semibold'\r\n : highlight === 'green'\r\n ? 'text-green-600 dark:text-green-400 font-semibold'\r\n : 'text-[var(--text-primary)]';\r\n\r\n return (\r\n <div className=\"flex justify-between items-center py-2 border-b border-[var(--border-color)] last:border-b-0\">\r\n <span className=\"text-sm text-[var(--text-secondary)]\">{label}</span>\r\n <span className={`text-sm font-medium ${highlightClass}`}>{value}</span>\r\n </div>\r\n );\r\n}\r\n\r\nfunction getGaugeIconColor(exceededEffective: boolean, inToleranceZone: boolean): string {\r\n if (exceededEffective) return 'text-red-500';\r\n if (inToleranceZone) return 'text-amber-500';\r\n return 'text-blue-500';\r\n}\r\n\r\nfunction getGaugeTextColor(exceededEffective: boolean, inToleranceZone: boolean): string {\r\n if (exceededEffective) return 'text-red-500';\r\n if (inToleranceZone) return 'text-amber-500';\r\n return 'text-[var(--text-primary)]';\r\n}\r\n\r\nfunction CircularGauge({ icon: Icon, label, max, current, margin = 0, t }: {\r\n icon: typeof Users;\r\n label: string;\r\n max: number;\r\n current: number;\r\n margin?: number;\r\n t: (key: string, fallback: string, opts?: Record<string, unknown>) => string;\r\n}) {\r\n const unlimited = max <= 0;\r\n // `max` is the licensed contractual limit (from JWT, e.g. 50 users).\r\n // The tolerance `margin` is ADDED on top to form the hard upper bound.\r\n // Example: licensed=50 + margin=10 → total=60.\r\n const licensedLimit = max;\r\n const total = max + margin;\r\n\r\n // SVG arc parameters\r\n const size = 140;\r\n const strokeWidth = 12;\r\n const radius = (size - strokeWidth) / 2;\r\n const center = size / 2;\r\n // Arc spans 270 degrees (from 135° to 405°)\r\n const startAngle = 135;\r\n const totalArc = 270;\r\n\r\n // Percentages\r\n const usagePercent = total > 0 ? Math.min(1, current / total) : 0;\r\n const licensedPercent = total > 0 ? licensedLimit / total : 1;\r\n\r\n // Zone detection\r\n const inToleranceZone = margin > 0 && current > licensedLimit && current <= total;\r\n const exceededEffective = current > total;\r\n\r\n // Colors\r\n let usageColor = '#3b82f6'; // blue-500\r\n if (exceededEffective) usageColor = '#ef4444'; // red-500\r\n else if (inToleranceZone) usageColor = '#f59e0b'; // amber-500\r\n\r\n const toleranceTrackColor = 'rgba(245, 158, 11, 0.25)'; // amber with opacity\r\n\r\n // Helper to compute SVG arc endpoint\r\n const polarToCartesian = (angleDeg: number) => {\r\n const rad = (angleDeg * Math.PI) / 180;\r\n return {\r\n x: center + radius * Math.cos(rad),\r\n y: center + radius * Math.sin(rad),\r\n };\r\n };\r\n\r\n // Build an arc path from startAngle spanning `sweep` degrees\r\n const describeArc = (sweep: number) => {\r\n if (sweep <= 0) return '';\r\n const endAngle = startAngle + sweep;\r\n const start = polarToCartesian(startAngle);\r\n const end = polarToCartesian(endAngle);\r\n const largeArc = sweep > 180 ? 1 : 0;\r\n return `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArc} 1 ${end.x} ${end.y}`;\r\n };\r\n\r\n // Percentage display\r\n const displayPercent = total > 0 ? Math.round((current / licensedLimit) * 100) : 0;\r\n\r\n if (unlimited) {\r\n return (\r\n <div className=\"flex flex-col items-center gap-3 py-4\">\r\n <div className=\"relative\" style={{ width: size, height: size }}>\r\n <svg width={size} height={size}>\r\n {/* Background track */}\r\n <path\r\n d={describeArc(totalArc)}\r\n fill=\"none\"\r\n stroke=\"var(--bg-tertiary)\"\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n />\r\n {/* Full green arc for unlimited */}\r\n <path\r\n d={describeArc(totalArc)}\r\n fill=\"none\"\r\n stroke=\"#22c55e\"\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n opacity={0.5}\r\n />\r\n </svg>\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\r\n <Icon className=\"w-6 h-6 text-green-500 mb-1\" />\r\n <span className=\"text-lg font-bold text-green-500\">∞</span>\r\n </div>\r\n </div>\r\n <span className=\"text-sm font-medium text-[var(--text-primary)]\">{label}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">{t('license.page.unlimited', 'Unlimited')}</span>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"flex flex-col items-center gap-3 py-4\">\r\n <div className=\"relative\" style={{ width: size, height: size }}>\r\n <svg width={size} height={size}>\r\n {/* Background track */}\r\n <path\r\n d={describeArc(totalArc)}\r\n fill=\"none\"\r\n stroke=\"var(--bg-tertiary)\"\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n />\r\n {/* Tolerance zone: arc from licensed limit to effective limit */}\r\n {margin > 0 && (() => {\r\n const toleranceSweep = totalArc * (1 - licensedPercent);\r\n const toleranceStartAngle = startAngle + totalArc * licensedPercent;\r\n const tStart = polarToCartesian(toleranceStartAngle);\r\n const tEnd = polarToCartesian(startAngle + totalArc);\r\n const largeArc = toleranceSweep > 180 ? 1 : 0;\r\n const tolerancePath = `M ${tStart.x} ${tStart.y} A ${radius} ${radius} 0 ${largeArc} 1 ${tEnd.x} ${tEnd.y}`;\r\n return (\r\n <path\r\n d={tolerancePath}\r\n fill=\"none\"\r\n stroke={toleranceTrackColor}\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n />\r\n );\r\n })()}\r\n {/* Usage arc */}\r\n <path\r\n d={describeArc(totalArc * usagePercent)}\r\n fill=\"none\"\r\n stroke={usageColor}\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n style={{ transition: 'stroke 0.3s, d 0.3s' }}\r\n />\r\n {/* Licensed limit tick mark */}\r\n {margin > 0 && (() => {\r\n const tickAngle = startAngle + totalArc * licensedPercent;\r\n const innerR = radius - strokeWidth / 2 - 2;\r\n const outerR = radius + strokeWidth / 2 + 2;\r\n const rad = (tickAngle * Math.PI) / 180;\r\n return (\r\n <line\r\n x1={center + innerR * Math.cos(rad)}\r\n y1={center + innerR * Math.sin(rad)}\r\n x2={center + outerR * Math.cos(rad)}\r\n y2={center + outerR * Math.sin(rad)}\r\n stroke=\"var(--text-secondary)\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n />\r\n );\r\n })()}\r\n </svg>\r\n {/* Center content */}\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\r\n <Icon className={`w-5 h-5 mb-0.5 ${getGaugeIconColor(exceededEffective, inToleranceZone)}`} />\r\n <span className={`text-2xl font-bold ${getGaugeTextColor(exceededEffective, inToleranceZone)}`}>\r\n {displayPercent}%\r\n </span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {current} / {licensedLimit}\r\n </span>\r\n </div>\r\n </div>\r\n <span className=\"text-sm font-medium text-[var(--text-primary)]\">{label}</span>\r\n {margin > 0 && (\r\n <span className={`text-xs ${inToleranceZone || exceededEffective ? 'text-amber-600 dark:text-amber-400' : 'text-[var(--text-secondary)]'}`}>\r\n +{margin} {t('license.page.tolerance', 'tolerance')}\r\n </span>\r\n )}\r\n </div>\r\n );\r\n}\r\n"],"names":["colorClasses","getStatusColor","license","getLicenseDaysColor","daysRemaining","formatDate","dateStr","buildKpiCards","t","statusColor","daysColor","Shield","AlertTriangle","CheckCircle","InfinityIcon","Clock","Users","StatusBanners","showTrialSuccess","isInGracePeriod","validationResult","gracePeriodDays","onTrialSuccessClose","onValidationResultClear","jsxs","Fragment","jsx","X","FeaturesGrid","hasAllFeatures","enabledFeatures","availableFeatures","group","features","code","enabled","f","Unlock","Lock","useValidateLicense","refreshLicense","isValidating","setIsValidating","useState","setValidationResult","handleValidate","useCallback","result","api","clearValidationResult","LicenseManagementPage","useTranslation","usage","isLoading","error","isHalted","haltReason","useLicense","showActivation","setShowActivation","searchParams","setSearchParams","useSearchParams","setShowTrialSuccess","useEffect","timer","Loader2","hasAllLicenseFeatures","kpiCards","LicenseStatusBadge","ShieldCheck","Key","card","Zap","CircularGauge","Building","standardKeys","customEntries","key","value","Calendar","DetailRow","Server","Monitor","Layers","LicenseActivationDialog","label","highlight","getGaugeIconColor","exceededEffective","inToleranceZone","getGaugeTextColor","Icon","max","current","margin","unlimited","licensedLimit","total","size","strokeWidth","radius","center","startAngle","totalArc","usagePercent","licensedPercent","usageColor","toleranceTrackColor","polarToCartesian","angleDeg","rad","describeArc","sweep","endAngle","start","end","largeArc","displayPercent","toleranceSweep","toleranceStartAngle","tStart","tEnd","tolerancePath","tickAngle","innerR","outerR"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const o=require("react"),u=require("./index-
|
|
2
|
-
//# sourceMappingURL=tenantIconMap-
|
|
1
|
+
"use strict";const o=require("react"),u=require("./index-BDRogQH_.js"),e=require("lucide-react"),d={getAll:()=>u.api.get("/administration/tenants/type-settings"),update:(t,s)=>u.api.put(`/administration/tenants/type-settings/${t}`,s)};let i=null,r=null;const b={Personal:{icon:"User",iconType:"Lucide",color:"violet"},Business:{icon:"Building2",iconType:"Lucide",color:"blue"},System:{icon:"Server",iconType:"Lucide",color:"gray"}};function v(){const[t,s]=o.useState(i??[]),[y,g]=o.useState(!i),[x,c]=o.useState(null),l=o.useCallback(async()=>{try{g(!0),c(null),r||(r=d.getAll());const a=await r,n=Array.isArray(a)?a:[];i=n,r=null,s(n)}catch{r=null,c("Failed to load tenant type settings")}finally{g(!1)}},[]);o.useEffect(()=>{i||l()},[l]);const m=o.useCallback(a=>{const n=(t??[]).find(C=>C.type===a);return n?{icon:n.icon,iconType:n.iconType,color:n.color}:b[a]??b.Business},[t]),S=o.useCallback(async()=>{i=null,r=null,await l()},[l]);return{settings:t,loading:y,error:x,getIconForType:m,reload:S}}const p={Building2:e.Building2,User:e.User,Server:e.Server,Building:e.Building,Home:e.Home,Briefcase:e.Briefcase,Globe:e.Globe,Shield:e.Shield,Users:e.Users,Crown:e.Crown,Warehouse:e.Warehouse,Store:e.Store,Factory:e.Factory,Landmark:e.Landmark,HardDrive:e.HardDrive,Cloud:e.Cloud,Database:e.Database,Monitor:e.Monitor,Laptop:e.Laptop},A=t=>p[t]??e.Building2,L=()=>Object.keys(p),T=t=>({blue:{bg:"bg-blue-500/10",text:"text-blue-500"},violet:{bg:"bg-violet-500/10",text:"text-violet-500"},gray:{bg:"bg-gray-500/10",text:"text-gray-500"},green:{bg:"bg-green-500/10",text:"text-green-500"},red:{bg:"bg-red-500/10",text:"text-red-500"},amber:{bg:"bg-amber-500/10",text:"text-amber-500"},purple:{bg:"bg-purple-500/10",text:"text-purple-500"},cyan:{bg:"bg-cyan-500/10",text:"text-cyan-500"},pink:{bg:"bg-pink-500/10",text:"text-pink-500"},emerald:{bg:"bg-emerald-500/10",text:"text-emerald-500"},orange:{bg:"bg-orange-500/10",text:"text-orange-500"},indigo:{bg:"bg-indigo-500/10",text:"text-indigo-500"}})[t]??{bg:"bg-gray-500/10",text:"text-gray-500"},f=()=>["blue","violet","gray","green","red","amber","purple","cyan","pink","emerald","orange","indigo"];exports.getAvailableColors=f;exports.getAvailableIconNames=L;exports.getColorClasses=T;exports.getLucideIcon=A;exports.tenantTypeSettingsApi=d;exports.useTenantTypeSettings=v;
|
|
2
|
+
//# sourceMappingURL=tenantIconMap-Cw-hQ9n4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenantIconMap-
|
|
1
|
+
{"version":3,"file":"tenantIconMap-Cw-hQ9n4.js","sources":["../../src/services/api/tenantTypeSettingsApi.ts","../../src/hooks/useTenantTypeSettings.ts","../../src/utils/tenantIconMap.ts"],"sourcesContent":["import { api } from './apiClient';\r\nimport type { TenantType } from './adminApi';\r\n\r\nexport interface TenantTypeSettingsDto {\r\n id: string;\r\n type: TenantType;\r\n icon: string;\r\n iconType: 'Lucide' | 'Url' | 'Svg';\r\n color: string;\r\n displayName: string;\r\n description: string | null;\r\n}\r\n\r\nexport interface UpdateTenantTypeSettingsRequest {\r\n icon: string;\r\n iconType: 'Lucide' | 'Url' | 'Svg';\r\n color: string;\r\n displayName: string;\r\n description: string | null;\r\n}\r\n\r\nexport const tenantTypeSettingsApi = {\r\n getAll: () =>\r\n api.get<TenantTypeSettingsDto[]>('/administration/tenants/type-settings'),\r\n\r\n update: (type: TenantType, data: UpdateTenantTypeSettingsRequest) =>\r\n api.put<TenantTypeSettingsDto>(`/administration/tenants/type-settings/${type}`, data),\r\n};\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport { tenantTypeSettingsApi, type TenantTypeSettingsDto } from '@/services/api/tenantTypeSettingsApi';\r\nimport type { TenantType } from '@/services/api/adminApi';\r\n\r\ninterface TenantTypeIcon {\r\n icon: string;\r\n iconType: string;\r\n color: string;\r\n}\r\n\r\ninterface UseTenantTypeSettingsReturn {\r\n settings: TenantTypeSettingsDto[];\r\n loading: boolean;\r\n error: string | null;\r\n getIconForType: (type: TenantType | string) => TenantTypeIcon;\r\n reload: () => Promise<void>;\r\n}\r\n\r\n// Module-level cache to avoid refetching on every mount\r\nlet cachedSettings: TenantTypeSettingsDto[] | null = null;\r\nlet cachePromise: Promise<TenantTypeSettingsDto[]> | null = null;\r\n\r\nconst DEFAULT_ICONS: Record<string, TenantTypeIcon> = {\r\n Personal: { icon: 'User', iconType: 'Lucide', color: 'violet' },\r\n Business: { icon: 'Building2', iconType: 'Lucide', color: 'blue' },\r\n System: { icon: 'Server', iconType: 'Lucide', color: 'gray' },\r\n};\r\n\r\nexport function useTenantTypeSettings(): UseTenantTypeSettingsReturn {\r\n const [settings, setSettings] = useState<TenantTypeSettingsDto[]>(cachedSettings ?? []);\r\n const [loading, setLoading] = useState(!cachedSettings);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const load = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n setError(null);\r\n\r\n // Deduplicate concurrent fetches\r\n if (!cachePromise) {\r\n cachePromise = tenantTypeSettingsApi.getAll();\r\n }\r\n\r\n const data = await cachePromise;\r\n const items = Array.isArray(data) ? data : [];\r\n cachedSettings = items;\r\n cachePromise = null;\r\n setSettings(items);\r\n } catch {\r\n cachePromise = null;\r\n setError('Failed to load tenant type settings');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!cachedSettings) {\r\n load();\r\n }\r\n }, [load]);\r\n\r\n const getIconForType = useCallback(\r\n (type: TenantType | string): TenantTypeIcon => {\r\n const found = (settings ?? []).find((s) => s.type === type);\r\n if (found) {\r\n return { icon: found.icon, iconType: found.iconType, color: found.color };\r\n }\r\n return DEFAULT_ICONS[type] ?? DEFAULT_ICONS.Business;\r\n },\r\n [settings]\r\n );\r\n\r\n const reload = useCallback(async () => {\r\n cachedSettings = null;\r\n cachePromise = null;\r\n await load();\r\n }, [load]);\r\n\r\n return { settings, loading, error, getIconForType, reload };\r\n}\r\n","import {\r\n Building2,\r\n User,\r\n Server,\r\n Building,\r\n Home,\r\n Briefcase,\r\n Globe,\r\n Shield,\r\n Users,\r\n Crown,\r\n Warehouse,\r\n Store,\r\n Factory,\r\n Landmark,\r\n HardDrive,\r\n Cloud,\r\n Database,\r\n Monitor,\r\n Laptop,\r\n type LucideIcon,\r\n} from 'lucide-react';\r\n\r\nconst ICON_MAP: Record<string, LucideIcon> = {\r\n Building2,\r\n User,\r\n Server,\r\n Building,\r\n Home,\r\n Briefcase,\r\n Globe,\r\n Shield,\r\n Users,\r\n Crown,\r\n Warehouse,\r\n Store,\r\n Factory,\r\n Landmark,\r\n HardDrive,\r\n Cloud,\r\n Database,\r\n Monitor,\r\n Laptop,\r\n};\r\n\r\n/**\r\n * Resolves a Lucide icon name (string) to its React component.\r\n * Falls back to Building2 if the name is unknown.\r\n */\r\nexport const getLucideIcon = (name: string): LucideIcon =>\r\n ICON_MAP[name] ?? Building2;\r\n\r\n/**\r\n * Returns a list of all available icon names for the admin UI picker.\r\n */\r\nexport const getAvailableIconNames = (): string[] => Object.keys(ICON_MAP);\r\n\r\n/**\r\n * Maps a color name to Tailwind background and text classes.\r\n */\r\nexport const getColorClasses = (color: string): { bg: string; text: string } => {\r\n const COLOR_MAP: Record<string, { bg: string; text: string }> = {\r\n blue: { bg: 'bg-blue-500/10', text: 'text-blue-500' },\r\n violet: { bg: 'bg-violet-500/10', text: 'text-violet-500' },\r\n gray: { bg: 'bg-gray-500/10', text: 'text-gray-500' },\r\n green: { bg: 'bg-green-500/10', text: 'text-green-500' },\r\n red: { bg: 'bg-red-500/10', text: 'text-red-500' },\r\n amber: { bg: 'bg-amber-500/10', text: 'text-amber-500' },\r\n purple: { bg: 'bg-purple-500/10', text: 'text-purple-500' },\r\n cyan: { bg: 'bg-cyan-500/10', text: 'text-cyan-500' },\r\n pink: { bg: 'bg-pink-500/10', text: 'text-pink-500' },\r\n emerald: { bg: 'bg-emerald-500/10', text: 'text-emerald-500' },\r\n orange: { bg: 'bg-orange-500/10', text: 'text-orange-500' },\r\n indigo: { bg: 'bg-indigo-500/10', text: 'text-indigo-500' },\r\n };\r\n\r\n return COLOR_MAP[color] ?? { bg: 'bg-gray-500/10', text: 'text-gray-500' };\r\n};\r\n\r\n/**\r\n * Returns a list of all available color names for the admin UI picker.\r\n */\r\nexport const getAvailableColors = (): string[] => [\r\n 'blue', 'violet', 'gray', 'green', 'red', 'amber',\r\n 'purple', 'cyan', 'pink', 'emerald', 'orange', 'indigo',\r\n];\r\n"],"names":["tenantTypeSettingsApi","api","type","data","cachedSettings","cachePromise","DEFAULT_ICONS","useTenantTypeSettings","settings","setSettings","useState","loading","setLoading","error","setError","load","useCallback","items","useEffect","getIconForType","found","s","reload","ICON_MAP","Building2","User","Server","Building","Home","Briefcase","Globe","Shield","Users","Crown","Warehouse","Store","Factory","Landmark","HardDrive","Cloud","Database","Monitor","Laptop","getLucideIcon","name","getAvailableIconNames","getColorClasses","color","getAvailableColors"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState as s, useCallback as l, useEffect as S } from "react";
|
|
2
|
-
import { i as b } from "./index-
|
|
2
|
+
import { i as b } from "./index-CBtjGPod.js";
|
|
3
3
|
import { Laptop as v, Monitor as C, Database as L, Cloud as T, HardDrive as k, Landmark as O, Factory as B, Store as h, Warehouse as I, Crown as P, Users as F, Shield as M, Globe as U, Briefcase as _, Home as w, Building as D, Server as E, User as N, Building2 as d } from "lucide-react";
|
|
4
4
|
const H = {
|
|
5
5
|
getAll: () => b.get("/administration/tenants/type-settings"),
|
|
@@ -92,4 +92,4 @@ export {
|
|
|
92
92
|
H as t,
|
|
93
93
|
W as u
|
|
94
94
|
};
|
|
95
|
-
//# sourceMappingURL=tenantIconMap-
|
|
95
|
+
//# sourceMappingURL=tenantIconMap-DinwojNW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenantIconMap-
|
|
1
|
+
{"version":3,"file":"tenantIconMap-DinwojNW.js","sources":["../../src/services/api/tenantTypeSettingsApi.ts","../../src/hooks/useTenantTypeSettings.ts","../../src/utils/tenantIconMap.ts"],"sourcesContent":["import { api } from './apiClient';\r\nimport type { TenantType } from './adminApi';\r\n\r\nexport interface TenantTypeSettingsDto {\r\n id: string;\r\n type: TenantType;\r\n icon: string;\r\n iconType: 'Lucide' | 'Url' | 'Svg';\r\n color: string;\r\n displayName: string;\r\n description: string | null;\r\n}\r\n\r\nexport interface UpdateTenantTypeSettingsRequest {\r\n icon: string;\r\n iconType: 'Lucide' | 'Url' | 'Svg';\r\n color: string;\r\n displayName: string;\r\n description: string | null;\r\n}\r\n\r\nexport const tenantTypeSettingsApi = {\r\n getAll: () =>\r\n api.get<TenantTypeSettingsDto[]>('/administration/tenants/type-settings'),\r\n\r\n update: (type: TenantType, data: UpdateTenantTypeSettingsRequest) =>\r\n api.put<TenantTypeSettingsDto>(`/administration/tenants/type-settings/${type}`, data),\r\n};\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport { tenantTypeSettingsApi, type TenantTypeSettingsDto } from '@/services/api/tenantTypeSettingsApi';\r\nimport type { TenantType } from '@/services/api/adminApi';\r\n\r\ninterface TenantTypeIcon {\r\n icon: string;\r\n iconType: string;\r\n color: string;\r\n}\r\n\r\ninterface UseTenantTypeSettingsReturn {\r\n settings: TenantTypeSettingsDto[];\r\n loading: boolean;\r\n error: string | null;\r\n getIconForType: (type: TenantType | string) => TenantTypeIcon;\r\n reload: () => Promise<void>;\r\n}\r\n\r\n// Module-level cache to avoid refetching on every mount\r\nlet cachedSettings: TenantTypeSettingsDto[] | null = null;\r\nlet cachePromise: Promise<TenantTypeSettingsDto[]> | null = null;\r\n\r\nconst DEFAULT_ICONS: Record<string, TenantTypeIcon> = {\r\n Personal: { icon: 'User', iconType: 'Lucide', color: 'violet' },\r\n Business: { icon: 'Building2', iconType: 'Lucide', color: 'blue' },\r\n System: { icon: 'Server', iconType: 'Lucide', color: 'gray' },\r\n};\r\n\r\nexport function useTenantTypeSettings(): UseTenantTypeSettingsReturn {\r\n const [settings, setSettings] = useState<TenantTypeSettingsDto[]>(cachedSettings ?? []);\r\n const [loading, setLoading] = useState(!cachedSettings);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const load = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n setError(null);\r\n\r\n // Deduplicate concurrent fetches\r\n if (!cachePromise) {\r\n cachePromise = tenantTypeSettingsApi.getAll();\r\n }\r\n\r\n const data = await cachePromise;\r\n const items = Array.isArray(data) ? data : [];\r\n cachedSettings = items;\r\n cachePromise = null;\r\n setSettings(items);\r\n } catch {\r\n cachePromise = null;\r\n setError('Failed to load tenant type settings');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!cachedSettings) {\r\n load();\r\n }\r\n }, [load]);\r\n\r\n const getIconForType = useCallback(\r\n (type: TenantType | string): TenantTypeIcon => {\r\n const found = (settings ?? []).find((s) => s.type === type);\r\n if (found) {\r\n return { icon: found.icon, iconType: found.iconType, color: found.color };\r\n }\r\n return DEFAULT_ICONS[type] ?? DEFAULT_ICONS.Business;\r\n },\r\n [settings]\r\n );\r\n\r\n const reload = useCallback(async () => {\r\n cachedSettings = null;\r\n cachePromise = null;\r\n await load();\r\n }, [load]);\r\n\r\n return { settings, loading, error, getIconForType, reload };\r\n}\r\n","import {\r\n Building2,\r\n User,\r\n Server,\r\n Building,\r\n Home,\r\n Briefcase,\r\n Globe,\r\n Shield,\r\n Users,\r\n Crown,\r\n Warehouse,\r\n Store,\r\n Factory,\r\n Landmark,\r\n HardDrive,\r\n Cloud,\r\n Database,\r\n Monitor,\r\n Laptop,\r\n type LucideIcon,\r\n} from 'lucide-react';\r\n\r\nconst ICON_MAP: Record<string, LucideIcon> = {\r\n Building2,\r\n User,\r\n Server,\r\n Building,\r\n Home,\r\n Briefcase,\r\n Globe,\r\n Shield,\r\n Users,\r\n Crown,\r\n Warehouse,\r\n Store,\r\n Factory,\r\n Landmark,\r\n HardDrive,\r\n Cloud,\r\n Database,\r\n Monitor,\r\n Laptop,\r\n};\r\n\r\n/**\r\n * Resolves a Lucide icon name (string) to its React component.\r\n * Falls back to Building2 if the name is unknown.\r\n */\r\nexport const getLucideIcon = (name: string): LucideIcon =>\r\n ICON_MAP[name] ?? Building2;\r\n\r\n/**\r\n * Returns a list of all available icon names for the admin UI picker.\r\n */\r\nexport const getAvailableIconNames = (): string[] => Object.keys(ICON_MAP);\r\n\r\n/**\r\n * Maps a color name to Tailwind background and text classes.\r\n */\r\nexport const getColorClasses = (color: string): { bg: string; text: string } => {\r\n const COLOR_MAP: Record<string, { bg: string; text: string }> = {\r\n blue: { bg: 'bg-blue-500/10', text: 'text-blue-500' },\r\n violet: { bg: 'bg-violet-500/10', text: 'text-violet-500' },\r\n gray: { bg: 'bg-gray-500/10', text: 'text-gray-500' },\r\n green: { bg: 'bg-green-500/10', text: 'text-green-500' },\r\n red: { bg: 'bg-red-500/10', text: 'text-red-500' },\r\n amber: { bg: 'bg-amber-500/10', text: 'text-amber-500' },\r\n purple: { bg: 'bg-purple-500/10', text: 'text-purple-500' },\r\n cyan: { bg: 'bg-cyan-500/10', text: 'text-cyan-500' },\r\n pink: { bg: 'bg-pink-500/10', text: 'text-pink-500' },\r\n emerald: { bg: 'bg-emerald-500/10', text: 'text-emerald-500' },\r\n orange: { bg: 'bg-orange-500/10', text: 'text-orange-500' },\r\n indigo: { bg: 'bg-indigo-500/10', text: 'text-indigo-500' },\r\n };\r\n\r\n return COLOR_MAP[color] ?? { bg: 'bg-gray-500/10', text: 'text-gray-500' };\r\n};\r\n\r\n/**\r\n * Returns a list of all available color names for the admin UI picker.\r\n */\r\nexport const getAvailableColors = (): string[] => [\r\n 'blue', 'violet', 'gray', 'green', 'red', 'amber',\r\n 'purple', 'cyan', 'pink', 'emerald', 'orange', 'indigo',\r\n];\r\n"],"names":["tenantTypeSettingsApi","api","type","data","cachedSettings","cachePromise","DEFAULT_ICONS","useTenantTypeSettings","settings","setSettings","useState","loading","setLoading","error","setError","load","useCallback","items","useEffect","getIconForType","found","s","reload","ICON_MAP","Building2","User","Server","Building","Home","Briefcase","Globe","Shield","Users","Crown","Warehouse","Store","Factory","Landmark","HardDrive","Cloud","Database","Monitor","Laptop","getLucideIcon","name","getAvailableIconNames","getColorClasses","color","getAvailableColors"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i } from "./index-
|
|
1
|
+
import { i } from "./index-CBtjGPod.js";
|
|
2
2
|
const o = {
|
|
3
3
|
getConfiguration: (t) => i.get(`/api/administration/tenants/${t}/ticketing/configuration`),
|
|
4
4
|
saveConfiguration: (t, n) => i.put(`/api/administration/tenants/${t}/ticketing/configuration`, n),
|
|
@@ -8,4 +8,4 @@ const o = {
|
|
|
8
8
|
export {
|
|
9
9
|
o as t
|
|
10
10
|
};
|
|
11
|
-
//# sourceMappingURL=ticketingApi-
|
|
11
|
+
//# sourceMappingURL=ticketingApi-CcWdebXv.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ticketingApi-
|
|
1
|
+
{"version":3,"file":"ticketingApi-CcWdebXv.js","sources":["../../src/services/api/ticketingApi.ts"],"sourcesContent":["import { api } from './apiClient';\r\n\r\n// DTOs\r\n\r\nexport interface TenantTicketingConfigurationDto {\r\n id: string;\r\n tenantId: string;\r\n provider: string;\r\n glpiBaseUrl: string | null;\r\n glpiClientId: string | null;\r\n hasGlpiClientSecret: boolean;\r\n glpiUsername: string | null;\r\n hasGlpiPassword: boolean;\r\n glpiEntityId: number | null;\r\n glpiRequestTypeId: number | null;\r\n syncEnabled: boolean;\r\n syncIntervalMinutes: number;\r\n lastSyncAt: string | null;\r\n lastSyncError: string | null;\r\n isConfigured: boolean;\r\n createdAt: string;\r\n updatedAt: string | null;\r\n}\r\n\r\nexport interface SaveTicketingConfigurationRequest {\r\n provider: string;\r\n glpiBaseUrl?: string;\r\n glpiClientId?: string;\r\n glpiClientSecret?: string;\r\n glpiUsername?: string;\r\n glpiPassword?: string;\r\n glpiEntityId?: number;\r\n glpiRequestTypeId?: number;\r\n syncEnabled: boolean;\r\n syncIntervalMinutes: number;\r\n}\r\n\r\nexport interface TicketingSyncResultDto {\r\n success: boolean;\r\n ticketsUpdated: number;\r\n ticketsFailed: number;\r\n errorMessage: string | null;\r\n}\r\n\r\n// API\r\n\r\nexport const ticketingApi = {\r\n getConfiguration: (tenantId: string) =>\r\n api.get<TenantTicketingConfigurationDto>(`/api/administration/tenants/${tenantId}/ticketing/configuration`),\r\n\r\n saveConfiguration: (tenantId: string, data: SaveTicketingConfigurationRequest) =>\r\n api.put<TenantTicketingConfigurationDto>(`/api/administration/tenants/${tenantId}/ticketing/configuration`, data),\r\n\r\n testConnection: (tenantId: string, data: {\r\n glpiBaseUrl: string;\r\n glpiClientId: string;\r\n glpiClientSecret?: string;\r\n glpiUsername: string;\r\n glpiPassword?: string;\r\n }) =>\r\n api.post<{ success: boolean; errorMessage: string | null }>(`/api/administration/tenants/${tenantId}/ticketing/test-connection`, data),\r\n\r\n triggerSync: (tenantId: string) =>\r\n api.post<TicketingSyncResultDto>(`/api/administration/tenants/${tenantId}/ticketing/sync`),\r\n};\r\n"],"names":["ticketingApi","tenantId","api","data"],"mappings":";AA8CO,MAAMA,IAAe;AAAA,EAC1B,kBAAkB,CAACC,MACjBC,EAAI,IAAqC,+BAA+BD,CAAQ,0BAA0B;AAAA,EAE5G,mBAAmB,CAACA,GAAkBE,MACpCD,EAAI,IAAqC,+BAA+BD,CAAQ,4BAA4BE,CAAI;AAAA,EAElH,gBAAgB,CAACF,GAAkBE,MAOjCD,EAAI,KAAwD,+BAA+BD,CAAQ,8BAA8BE,CAAI;AAAA,EAEvI,aAAa,CAACF,MACZC,EAAI,KAA6B,+BAA+BD,CAAQ,iBAAiB;AAC7F;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const t=require("./index-
|
|
2
|
-
//# sourceMappingURL=ticketingApi-
|
|
1
|
+
"use strict";const t=require("./index-BDRogQH_.js"),a={getConfiguration:i=>t.api.get(`/api/administration/tenants/${i}/ticketing/configuration`),saveConfiguration:(i,n)=>t.api.put(`/api/administration/tenants/${i}/ticketing/configuration`,n),testConnection:(i,n)=>t.api.post(`/api/administration/tenants/${i}/ticketing/test-connection`,n),triggerSync:i=>t.api.post(`/api/administration/tenants/${i}/ticketing/sync`)};exports.ticketingApi=a;
|
|
2
|
+
//# sourceMappingURL=ticketingApi-x0BwZ1NH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ticketingApi-
|
|
1
|
+
{"version":3,"file":"ticketingApi-x0BwZ1NH.js","sources":["../../src/services/api/ticketingApi.ts"],"sourcesContent":["import { api } from './apiClient';\r\n\r\n// DTOs\r\n\r\nexport interface TenantTicketingConfigurationDto {\r\n id: string;\r\n tenantId: string;\r\n provider: string;\r\n glpiBaseUrl: string | null;\r\n glpiClientId: string | null;\r\n hasGlpiClientSecret: boolean;\r\n glpiUsername: string | null;\r\n hasGlpiPassword: boolean;\r\n glpiEntityId: number | null;\r\n glpiRequestTypeId: number | null;\r\n syncEnabled: boolean;\r\n syncIntervalMinutes: number;\r\n lastSyncAt: string | null;\r\n lastSyncError: string | null;\r\n isConfigured: boolean;\r\n createdAt: string;\r\n updatedAt: string | null;\r\n}\r\n\r\nexport interface SaveTicketingConfigurationRequest {\r\n provider: string;\r\n glpiBaseUrl?: string;\r\n glpiClientId?: string;\r\n glpiClientSecret?: string;\r\n glpiUsername?: string;\r\n glpiPassword?: string;\r\n glpiEntityId?: number;\r\n glpiRequestTypeId?: number;\r\n syncEnabled: boolean;\r\n syncIntervalMinutes: number;\r\n}\r\n\r\nexport interface TicketingSyncResultDto {\r\n success: boolean;\r\n ticketsUpdated: number;\r\n ticketsFailed: number;\r\n errorMessage: string | null;\r\n}\r\n\r\n// API\r\n\r\nexport const ticketingApi = {\r\n getConfiguration: (tenantId: string) =>\r\n api.get<TenantTicketingConfigurationDto>(`/api/administration/tenants/${tenantId}/ticketing/configuration`),\r\n\r\n saveConfiguration: (tenantId: string, data: SaveTicketingConfigurationRequest) =>\r\n api.put<TenantTicketingConfigurationDto>(`/api/administration/tenants/${tenantId}/ticketing/configuration`, data),\r\n\r\n testConnection: (tenantId: string, data: {\r\n glpiBaseUrl: string;\r\n glpiClientId: string;\r\n glpiClientSecret?: string;\r\n glpiUsername: string;\r\n glpiPassword?: string;\r\n }) =>\r\n api.post<{ success: boolean; errorMessage: string | null }>(`/api/administration/tenants/${tenantId}/ticketing/test-connection`, data),\r\n\r\n triggerSync: (tenantId: string) =>\r\n api.post<TicketingSyncResultDto>(`/api/administration/tenants/${tenantId}/ticketing/sync`),\r\n};\r\n"],"names":["ticketingApi","tenantId","api","data"],"mappings":"oDA8CaA,EAAe,CAC1B,iBAAmBC,GACjBC,MAAI,IAAqC,+BAA+BD,CAAQ,0BAA0B,EAE5G,kBAAmB,CAACA,EAAkBE,IACpCD,MAAI,IAAqC,+BAA+BD,CAAQ,2BAA4BE,CAAI,EAElH,eAAgB,CAACF,EAAkBE,IAOjCD,MAAI,KAAwD,+BAA+BD,CAAQ,6BAA8BE,CAAI,EAEvI,YAAcF,GACZC,EAAAA,IAAI,KAA6B,+BAA+BD,CAAQ,iBAAiB,CAC7F"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const e=require("react/jsx-runtime"),l=require("react"),L=require("react-i18next"),k=require("./index-
|
|
2
|
-
//# sourceMappingURL=useAccessRequests-
|
|
1
|
+
"use strict";const e=require("react/jsx-runtime"),l=require("react"),L=require("react-i18next"),k=require("./index-BDRogQH_.js"),F=require("./AccessRequestStatusBadge-CNTI7EDr.js"),v=require("lucide-react"),N=require("./accessRequestsApi-CJPjyEkH.js");function $({open:i,onClose:x,onConfirm:m,request:n,action:t,processing:d}){const{t:s}=L.useTranslation("admin"),[o,u]=l.useState(""),[r,p]=l.useState("group"),[b,g]=l.useState(""),[j,y]=l.useState(""),[a,f]=l.useState([]),[q,w]=l.useState([]),[A,C]=l.useState(!1),[S,I]=l.useState(!1),R=t==="deny",h=t==="approve";l.useEffect(()=>{!i||!h||(I(!0),k.adminApi.tenants.getGroups(n.tenantId).then(c=>{w(c.filter(T=>T.isActive))}).catch(()=>{w([])}).finally(()=>{I(!1)}))},[i,h,n.tenantId]),l.useEffect(()=>{!i||!h||r!=="role"||a.length>0||(C(!0),k.adminApi.roles.getByApplication(n.applicationId).then(c=>{f(c)}).catch(()=>{f([])}).finally(()=>{C(!1)}))},[i,h,r,n.applicationId,a.length]),l.useEffect(()=>{i||(u(""),p("group"),g(""),y(""),f([]),w([]))},[i]);const G=async()=>{if(R){await m({notes:o||void 0});return}await m({roleId:r==="role"?b:void 0,groupId:r==="group"?j:void 0,notes:o||void 0})};if(!i)return null;const E=h?(r==="role"&&b!==""||r==="group"&&j!=="")&&!d:o!==""&&!d;return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm",children:e.jsxs("div",{className:"bg-[var(--bg-primary)] rounded-[var(--radius-card)] p-6 max-w-md w-full max-h-[90vh] overflow-y-auto",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsx("h3",{className:"text-lg font-semibold",children:s(`accessRequests.modal.${t}Title`)}),e.jsx("button",{onClick:x,className:"p-1 hover:bg-[var(--bg-hover)] rounded",disabled:d,children:e.jsx(v.X,{className:"w-5 h-5"})})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"font-medium mb-1",children:s("accessRequests.modal.user")}),e.jsxs("div",{children:[n.userFullName," (",n.userEmail,")"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"font-medium mb-1",children:s("accessRequests.modal.application")}),e.jsx("div",{children:n.applicationLabel})]}),n.reason&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium mb-1",children:s("accessRequests.modal.userReason")}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:n.reason})]}),h&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{children:[e.jsxs("label",{className:"block font-medium mb-2",children:[s("accessRequests.modal.assignmentMethod"),e.jsx("span",{className:"text-[var(--error-text)] ml-1",children:"*"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("button",{type:"button",onClick:()=>p("group"),className:`flex items-center gap-2 px-3 py-2.5 rounded-[var(--radius-input)] border text-sm font-medium transition-colors ${r==="group"?"border-[var(--color-accent-500)] bg-[var(--color-accent-50)] text-[var(--color-accent-700)]":"border-[var(--border-color)] hover:bg-[var(--bg-hover)]"}`,children:[e.jsx(v.Users,{className:"w-4 h-4"}),s("accessRequests.modal.addToGroup")]}),e.jsxs("button",{type:"button",onClick:()=>p("role"),className:`flex items-center gap-2 px-3 py-2.5 rounded-[var(--radius-input)] border text-sm font-medium transition-colors ${r==="role"?"border-[var(--color-accent-500)] bg-[var(--color-accent-50)] text-[var(--color-accent-700)]":"border-[var(--border-color)] hover:bg-[var(--bg-hover)]"}`,children:[e.jsx(v.Shield,{className:"w-4 h-4"}),s("accessRequests.modal.assignRole")]})]}),e.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1.5",children:s(r==="group"?"accessRequests.modal.groupHint":"accessRequests.modal.roleHint")})]}),r==="group"&&e.jsxs("div",{children:[e.jsxs("label",{className:"block font-medium mb-2",children:[s("accessRequests.modal.selectGroup"),e.jsx("span",{className:"text-[var(--error-text)] ml-1",children:"*"})]}),S&&e.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[e.jsx(v.Loader2,{className:"w-4 h-4 animate-spin"}),s("accessRequests.modal.loadingGroups")]}),!S&&q.length===0&&e.jsx("div",{className:"text-sm text-[var(--warning-text)]",children:s("accessRequests.modal.noGroupsAvailable")}),!S&&q.length>0&&e.jsxs("select",{value:j,onChange:c=>y(c.target.value),className:"w-full px-3 py-2 border rounded-[var(--radius-input)] bg-[var(--bg-primary)] border-[var(--border-color)]",children:[e.jsx("option",{value:"",children:s("accessRequests.modal.selectGroupPlaceholder")}),q.map(c=>e.jsxs("option",{value:c.groupId,children:[c.name," (",c.memberCount," ",s("accessRequests.modal.members"),")"]},c.groupId))]})]}),r==="role"&&e.jsxs("div",{children:[e.jsxs("label",{className:"block font-medium mb-2",children:[s("accessRequests.modal.selectRole"),e.jsx("span",{className:"text-[var(--error-text)] ml-1",children:"*"})]}),A&&e.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[e.jsx(v.Loader2,{className:"w-4 h-4 animate-spin"}),s("accessRequests.modal.loadingRoles")]}),!A&&a.length===0&&e.jsx("div",{className:"text-sm text-[var(--warning-text)]",children:s("accessRequests.modal.noRolesAvailable")}),!A&&a.length>0&&e.jsxs("select",{value:b,onChange:c=>g(c.target.value),className:"w-full px-3 py-2 border rounded-[var(--radius-input)] bg-[var(--bg-primary)] border-[var(--border-color)]",children:[e.jsx("option",{value:"",children:s("accessRequests.modal.selectRolePlaceholder")}),a.map(c=>e.jsxs("option",{value:c.id,children:[c.name," (",c.shortName,")"]},c.id))]})]})]}),e.jsxs("div",{children:[e.jsxs("label",{className:"block font-medium mb-2",children:[s(`accessRequests.modal.${t}Notes`),R&&e.jsx("span",{className:"text-[var(--error-text)] ml-1",children:"*"})]}),e.jsx("textarea",{value:o,onChange:c=>u(c.target.value),className:"w-full px-3 py-2 border rounded-[var(--radius-input)] bg-[var(--bg-primary)] border-[var(--border-color)]",rows:3,placeholder:s(`accessRequests.modal.${t}NotesPlaceholder`),required:R})]}),e.jsxs("div",{className:"flex justify-end gap-2 pt-2",children:[e.jsx("button",{onClick:x,className:"px-4 py-2 rounded-[var(--radius-button)] border border-[var(--border-color)] hover:bg-[var(--bg-hover)]",disabled:d,children:s("common:cancel")}),e.jsxs("button",{onClick:G,disabled:!E,className:`px-4 py-2 rounded-[var(--radius-button)] text-white disabled:opacity-50 flex items-center gap-2 ${R?"bg-[var(--error-text)]":"bg-[var(--success-text)]"}`,children:[d&&e.jsx(v.Loader2,{className:"w-4 h-4 animate-spin"}),s(`accessRequests.actions.${t}`)]})]})]})]})})}function B(i){const[x,m]=l.useState(!1),[n,t]=l.useState(null);return{approve:async(o,u)=>{m(!0),t(null);try{await N.accessRequestsApi.approveRequest(o,u),i?.()}catch(r){throw t(r instanceof Error?r.message:"Failed to approve request"),r}finally{m(!1)}},deny:async(o,u)=>{m(!0),t(null);try{await N.accessRequestsApi.denyRequest(o,u),i?.()}catch(r){throw t(r instanceof Error?r.message:"Failed to deny request"),r}finally{m(!1)}},processing:x,error:n}}function M({requests:i,loading:x,onReload:m,showTenantColumn:n=!1}){const{t}=L.useTranslation("admin"),[d,s]=l.useState(null),[o,u]=l.useState(null),{approve:r,deny:p,processing:b}=B(()=>{s(null),u(null),m()}),g=(a,f)=>{s(a),u(f)},j=async a=>{d&&(o==="approve"?await r(d.id,a):o==="deny"&&a.notes&&await p(d.id,a.notes))},y=[{key:"userFullName",label:t("accessRequests.table.user"),render:a=>e.jsxs("div",{children:[e.jsx("div",{className:"font-medium",children:a.userFullName}),e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:a.userEmail})]})},...n?[{key:"tenantName",label:t("accessRequests.table.tenant"),render:a=>a.tenantName}]:[],{key:"applicationLabel",label:t("accessRequests.table.application")},{key:"reason",label:t("accessRequests.table.reason"),render:a=>a.reason||"-"},{key:"requestedAt",label:t("accessRequests.table.requestedAt"),render:a=>new Date(a.requestedAt).toLocaleString()},{key:"status",label:t("accessRequests.table.status"),render:a=>e.jsx(F.AccessRequestStatusBadge,{status:a.status})},{key:"actions",label:t("common:actionsColumn"),align:"right",render:a=>a.status==="Pending"?e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:()=>g(a,"approve"),className:"p-1 rounded hover:bg-[var(--success-bg)] text-[var(--success-text)]",title:t("accessRequests.actions.approve"),children:e.jsx(v.CheckCircle,{className:"w-4 h-4"})}),e.jsx("button",{onClick:()=>g(a,"deny"),className:"p-1 rounded hover:bg-[var(--error-bg)] text-[var(--error-text)]",title:t("accessRequests.actions.deny"),children:e.jsx(v.XCircle,{className:"w-4 h-4"})})]}):e.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:a.processedBy})}];return x?e.jsx("div",{className:"flex items-center justify-center py-8",children:e.jsx(v.Loader2,{className:"w-6 h-6 animate-spin text-[var(--color-accent-500)]"})}):e.jsxs("div",{className:"space-y-4",children:[e.jsx(k.DataTable,{data:i,columns:y,searchable:!0,searchPlaceholder:t("accessRequests.search"),getRowKey:a=>a.id,emptyMessage:t("accessRequests.empty")}),d&&o&&e.jsx($,{open:!0,onClose:()=>{s(null),u(null)},onConfirm:j,request:d,action:o,processing:b})]})}function P(i,x){const[m,n]=l.useState([]),[t,d]=l.useState(!1),[s,o]=l.useState(null),u=l.useCallback(async r=>{d(!0),o(null);try{const p=i==="application"?await N.accessRequestsApi.getRequestsByApplication(x,r):await N.accessRequestsApi.getRequestsByTenant(x,r);n(Array.isArray(p)?p:[])}catch(p){o(p.message||"Failed to load requests"),n([])}finally{d(!1)}},[i,x]);return{requests:m,loading:t,error:s,loadRequests:u}}exports.AccessRequestsListTab=M;exports.useAccessRequests=P;
|
|
2
|
+
//# sourceMappingURL=useAccessRequests-BBTIYht3.js.map
|