@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.
Files changed (273) hide show
  1. package/dist/chunks/{AgentSkillsPage-DgqyaZwI.js → AgentSkillsPage-BS_W2KTh.js} +2 -2
  2. package/dist/chunks/{AgentSkillsPage-DgqyaZwI.js.map → AgentSkillsPage-BS_W2KTh.js.map} +1 -1
  3. package/dist/chunks/{AgentSkillsPage-ojivq0Cu.js → AgentSkillsPage-CmDFLnp7.js} +2 -2
  4. package/dist/chunks/{AgentSkillsPage-ojivq0Cu.js.map → AgentSkillsPage-CmDFLnp7.js.map} +1 -1
  5. package/dist/chunks/{AgentWorkloadPage-BGGTfOLs.js → AgentWorkloadPage-C8IvYfhT.js} +2 -2
  6. package/dist/chunks/{AgentWorkloadPage-BGGTfOLs.js.map → AgentWorkloadPage-C8IvYfhT.js.map} +1 -1
  7. package/dist/chunks/{AgentWorkloadPage-DWsC5VoS.js → AgentWorkloadPage-JXsQbwuM.js} +2 -2
  8. package/dist/chunks/{AgentWorkloadPage-DWsC5VoS.js.map → AgentWorkloadPage-JXsQbwuM.js.map} +1 -1
  9. package/dist/chunks/{ApiCatalogDetailPage-7EifQOAh.js → ApiCatalogDetailPage-CYOt34Vy.js} +2 -2
  10. package/dist/chunks/{ApiCatalogDetailPage-7EifQOAh.js.map → ApiCatalogDetailPage-CYOt34Vy.js.map} +1 -1
  11. package/dist/chunks/{ApiCatalogDetailPage-BD7XE4xK.js → ApiCatalogDetailPage-wFZDsTGy.js} +3 -3
  12. package/dist/chunks/{ApiCatalogDetailPage-BD7XE4xK.js.map → ApiCatalogDetailPage-wFZDsTGy.js.map} +1 -1
  13. package/dist/chunks/{ApiCatalogPage-BfPoZGD3.js → ApiCatalogPage-Bdm3HNGP.js} +2 -2
  14. package/dist/chunks/{ApiCatalogPage-BfPoZGD3.js.map → ApiCatalogPage-Bdm3HNGP.js.map} +1 -1
  15. package/dist/chunks/{ApiCatalogPage-BOPTnk-b.js → ApiCatalogPage-m_TWQyGv.js} +2 -2
  16. package/dist/chunks/{ApiCatalogPage-BOPTnk-b.js.map → ApiCatalogPage-m_TWQyGv.js.map} +1 -1
  17. package/dist/chunks/ApplicationDetailPage-C2BSpEoW.js +2 -0
  18. package/dist/chunks/{ApplicationDetailPage-CWdz0TS4.js.map → ApplicationDetailPage-C2BSpEoW.js.map} +1 -1
  19. package/dist/chunks/{ApplicationDetailPage-CDQqViuH.js → ApplicationDetailPage-CcgDAP-J.js} +503 -501
  20. package/dist/chunks/{ApplicationDetailPage-CDQqViuH.js.map → ApplicationDetailPage-CcgDAP-J.js.map} +1 -1
  21. package/dist/chunks/{ApplicationsDashboardPage-ZyXm2Cd1.js → ApplicationsDashboardPage-CDIjziL3.js} +3 -3
  22. package/dist/chunks/{ApplicationsDashboardPage-ZyXm2Cd1.js.map → ApplicationsDashboardPage-CDIjziL3.js.map} +1 -1
  23. package/dist/chunks/{ApplicationsDashboardPage-BH4S3qA2.js → ApplicationsDashboardPage-DslDyNzJ.js} +2 -2
  24. package/dist/chunks/{ApplicationsDashboardPage-BH4S3qA2.js.map → ApplicationsDashboardPage-DslDyNzJ.js.map} +1 -1
  25. package/dist/chunks/{ApplicationsGridPage-D0fU1_Le.js → ApplicationsGridPage-BCjsQGU0.js} +2 -2
  26. package/dist/chunks/{ApplicationsGridPage-D0fU1_Le.js.map → ApplicationsGridPage-BCjsQGU0.js.map} +1 -1
  27. package/dist/chunks/{ApplicationsGridPage-C1WF2Htv.js → ApplicationsGridPage-CIfKiCND.js} +2 -2
  28. package/dist/chunks/{ApplicationsGridPage-C1WF2Htv.js.map → ApplicationsGridPage-CIfKiCND.js.map} +1 -1
  29. package/dist/chunks/{ApplicationsListPage-Cxvt2_WQ.js → ApplicationsListPage-CT75kNcH.js} +2 -2
  30. package/dist/chunks/{ApplicationsListPage-Cxvt2_WQ.js.map → ApplicationsListPage-CT75kNcH.js.map} +1 -1
  31. package/dist/chunks/{ApplicationsListPage-B3ItaY4r.js → ApplicationsListPage-D2B4PZ5n.js} +2 -2
  32. package/dist/chunks/{ApplicationsListPage-B3ItaY4r.js.map → ApplicationsListPage-D2B4PZ5n.js.map} +1 -1
  33. package/dist/chunks/{ApplicationsPage-BqfNR-kc.js → ApplicationsPage-CaTBtduL.js} +2 -2
  34. package/dist/chunks/{ApplicationsPage-BqfNR-kc.js.map → ApplicationsPage-CaTBtduL.js.map} +1 -1
  35. package/dist/chunks/{ApplicationsPage-DuxuWfrN.js → ApplicationsPage-DW1LhL0U.js} +4 -4
  36. package/dist/chunks/{ApplicationsPage-DuxuWfrN.js.map → ApplicationsPage-DW1LhL0U.js.map} +1 -1
  37. package/dist/chunks/{AssignmentRulesPage-CR1C7V0a.js → AssignmentRulesPage-Bt9M0ki7.js} +2 -2
  38. package/dist/chunks/{AssignmentRulesPage-CR1C7V0a.js.map → AssignmentRulesPage-Bt9M0ki7.js.map} +1 -1
  39. package/dist/chunks/{AssignmentRulesPage-C4Jouh2g.js → AssignmentRulesPage-Y7xv60NY.js} +2 -2
  40. package/dist/chunks/{AssignmentRulesPage-C4Jouh2g.js.map → AssignmentRulesPage-Y7xv60NY.js.map} +1 -1
  41. package/dist/chunks/{AssignmentsPage-v8QUJkE7.js → AssignmentsPage-1eQGTjTi.js} +2 -2
  42. package/dist/chunks/{AssignmentsPage-v8QUJkE7.js.map → AssignmentsPage-1eQGTjTi.js.map} +1 -1
  43. package/dist/chunks/{AssignmentsPage-CjuGAd8n.js → AssignmentsPage-RURdPvfZ.js} +2 -2
  44. package/dist/chunks/{AssignmentsPage-CjuGAd8n.js.map → AssignmentsPage-RURdPvfZ.js.map} +1 -1
  45. package/dist/chunks/{AuthCallbackPage-BxIXPUJk.js → AuthCallbackPage-8hF0jYlK.js} +2 -2
  46. package/dist/chunks/{AuthCallbackPage-BxIXPUJk.js.map → AuthCallbackPage-8hF0jYlK.js.map} +1 -1
  47. package/dist/chunks/{AuthCallbackPage-CuS-efzY.js → AuthCallbackPage-DPL68Asu.js} +2 -2
  48. package/dist/chunks/{AuthCallbackPage-CuS-efzY.js.map → AuthCallbackPage-DPL68Asu.js.map} +1 -1
  49. package/dist/chunks/{ConfirmEmailPage-CWIqy2bT.js → ConfirmEmailPage-BKlpZkVk.js} +2 -2
  50. package/dist/chunks/{ConfirmEmailPage-CWIqy2bT.js.map → ConfirmEmailPage-BKlpZkVk.js.map} +1 -1
  51. package/dist/chunks/{ConfirmEmailPage-CkN8IfP-.js → ConfirmEmailPage-CawSZypI.js} +2 -2
  52. package/dist/chunks/{ConfirmEmailPage-CkN8IfP-.js.map → ConfirmEmailPage-CawSZypI.js.map} +1 -1
  53. package/dist/chunks/{CreateSupportTicketPage-Df0ow5ge.js → CreateSupportTicketPage-AwbMbBIH.js} +2 -2
  54. package/dist/chunks/{CreateSupportTicketPage-Df0ow5ge.js.map → CreateSupportTicketPage-AwbMbBIH.js.map} +1 -1
  55. package/dist/chunks/{CreateSupportTicketPage-CmrDfFxP.js → CreateSupportTicketPage-Dg1YW1eA.js} +2 -2
  56. package/dist/chunks/{CreateSupportTicketPage-CmrDfFxP.js.map → CreateSupportTicketPage-Dg1YW1eA.js.map} +1 -1
  57. package/dist/chunks/{DashboardPage-B4Pi5P3O.js → DashboardPage-B4YxOF-9.js} +3 -3
  58. package/dist/chunks/{DashboardPage-B4Pi5P3O.js.map → DashboardPage-B4YxOF-9.js.map} +1 -1
  59. package/dist/chunks/{DashboardPage-wEKZ_DWf.js → DashboardPage-BZxjinar.js} +2 -2
  60. package/dist/chunks/{DashboardPage-wEKZ_DWf.js.map → DashboardPage-BZxjinar.js.map} +1 -1
  61. package/dist/chunks/{DashboardPage-BAqpoxCW.js → DashboardPage-Bo09y8r7.js} +3 -3
  62. package/dist/chunks/{DashboardPage-BAqpoxCW.js.map → DashboardPage-Bo09y8r7.js.map} +1 -1
  63. package/dist/chunks/{DashboardPage-BT5kFaQA.js → DashboardPage-Cq5adDjP.js} +2 -2
  64. package/dist/chunks/{DashboardPage-BT5kFaQA.js.map → DashboardPage-Cq5adDjP.js.map} +1 -1
  65. package/dist/chunks/{EscalationConfigPage-4pF38E4N.js → EscalationConfigPage-C8Hv5naz.js} +2 -2
  66. package/dist/chunks/{EscalationConfigPage-4pF38E4N.js.map → EscalationConfigPage-C8Hv5naz.js.map} +1 -1
  67. package/dist/chunks/{EscalationConfigPage-Bcifnt_h.js → EscalationConfigPage-DNAqMRxA.js} +2 -2
  68. package/dist/chunks/{EscalationConfigPage-Bcifnt_h.js.map → EscalationConfigPage-DNAqMRxA.js.map} +1 -1
  69. package/dist/chunks/{ForceChangePasswordPage-CBaMV_PS.js → ForceChangePasswordPage-BURE_vNg.js} +2 -2
  70. package/dist/chunks/{ForceChangePasswordPage-CBaMV_PS.js.map → ForceChangePasswordPage-BURE_vNg.js.map} +1 -1
  71. package/dist/chunks/{ForceChangePasswordPage-ClDXluX1.js → ForceChangePasswordPage-C6jDZshk.js} +2 -2
  72. package/dist/chunks/{ForceChangePasswordPage-ClDXluX1.js.map → ForceChangePasswordPage-C6jDZshk.js.map} +1 -1
  73. package/dist/chunks/{ForgotPasswordPage--ueWRNSO.js → ForgotPasswordPage-C5HLYbz4.js} +2 -2
  74. package/dist/chunks/{ForgotPasswordPage--ueWRNSO.js.map → ForgotPasswordPage-C5HLYbz4.js.map} +1 -1
  75. package/dist/chunks/{ForgotPasswordPage-CzpAkP5R.js → ForgotPasswordPage-D3ZQBtjd.js} +2 -2
  76. package/dist/chunks/{ForgotPasswordPage-CzpAkP5R.js.map → ForgotPasswordPage-D3ZQBtjd.js.map} +1 -1
  77. package/dist/chunks/{GroupDetailPage-dXNOoSXE.js → GroupDetailPage-CTuzp9Vp.js} +5 -5
  78. package/dist/chunks/{GroupDetailPage-dXNOoSXE.js.map → GroupDetailPage-CTuzp9Vp.js.map} +1 -1
  79. package/dist/chunks/{GroupDetailPage-BIgBzQk0.js → GroupDetailPage-NJc2zCxC.js} +2 -2
  80. package/dist/chunks/{GroupDetailPage-BIgBzQk0.js.map → GroupDetailPage-NJc2zCxC.js.map} +1 -1
  81. package/dist/chunks/{MyAccessRequestsPage-K2NXkdy4.js → MyAccessRequestsPage-Cvr29Pnq.js} +2 -2
  82. package/dist/chunks/{MyAccessRequestsPage-K2NXkdy4.js.map → MyAccessRequestsPage-Cvr29Pnq.js.map} +1 -1
  83. package/dist/chunks/{MyAccessRequestsPage-Be8VvLhh.js → MyAccessRequestsPage-t6I24rHN.js} +2 -2
  84. package/dist/chunks/{MyAccessRequestsPage-Be8VvLhh.js.map → MyAccessRequestsPage-t6I24rHN.js.map} +1 -1
  85. package/dist/chunks/{MyTenantsPage-BXx1nPC8.js → MyTenantsPage-Dy2RZ_Ei.js} +2 -2
  86. package/dist/chunks/{MyTenantsPage-BXx1nPC8.js.map → MyTenantsPage-Dy2RZ_Ei.js.map} +1 -1
  87. package/dist/chunks/{MyTenantsPage-B9ZAUeCa.js → MyTenantsPage-SvDCQ4Wt.js} +3 -3
  88. package/dist/chunks/{MyTenantsPage-B9ZAUeCa.js.map → MyTenantsPage-SvDCQ4Wt.js.map} +1 -1
  89. package/dist/chunks/{MyTicketsPage-C9MSmmR5.js → MyTicketsPage-C3lEBFD9.js} +2 -2
  90. package/dist/chunks/{MyTicketsPage-C9MSmmR5.js.map → MyTicketsPage-C3lEBFD9.js.map} +1 -1
  91. package/dist/chunks/{MyTicketsPage-d0PoJpnX.js → MyTicketsPage-DydDgFyz.js} +2 -2
  92. package/dist/chunks/{MyTicketsPage-d0PoJpnX.js.map → MyTicketsPage-DydDgFyz.js.map} +1 -1
  93. package/dist/chunks/{NavigationAppsPage-CJ3BjLlz.js → NavigationAppsPage-Dyv767w8.js} +2 -2
  94. package/dist/chunks/{NavigationAppsPage-CJ3BjLlz.js.map → NavigationAppsPage-Dyv767w8.js.map} +1 -1
  95. package/dist/chunks/{NavigationAppsPage-8t2xbddT.js → NavigationAppsPage-WqSspaVo.js} +2 -2
  96. package/dist/chunks/{NavigationAppsPage-8t2xbddT.js.map → NavigationAppsPage-WqSspaVo.js.map} +1 -1
  97. package/dist/chunks/{NotificationsPage-_62-bmuk.js → NotificationsPage-Di4I95PM.js} +2 -2
  98. package/dist/chunks/{NotificationsPage-_62-bmuk.js.map → NotificationsPage-Di4I95PM.js.map} +1 -1
  99. package/dist/chunks/{NotificationsPage-CLHfVUxm.js → NotificationsPage-elSovpBw.js} +2 -2
  100. package/dist/chunks/{NotificationsPage-CLHfVUxm.js.map → NotificationsPage-elSovpBw.js.map} +1 -1
  101. package/dist/chunks/{OnboardingWizardPage-Dkc22Jc4.js → OnboardingWizardPage-fdWdkwiT.js} +2 -2
  102. package/dist/chunks/{OnboardingWizardPage-Dkc22Jc4.js.map → OnboardingWizardPage-fdWdkwiT.js.map} +1 -1
  103. package/dist/chunks/{OnboardingWizardPage-D1rzD6gR.js → OnboardingWizardPage-nPLe2buQ.js} +2 -2
  104. package/dist/chunks/{OnboardingWizardPage-D1rzD6gR.js.map → OnboardingWizardPage-nPLe2buQ.js.map} +1 -1
  105. package/dist/chunks/{PermissionDetailPage-BSvSe4SI.js → PermissionDetailPage-B8C7tWFP.js} +2 -2
  106. package/dist/chunks/{PermissionDetailPage-BSvSe4SI.js.map → PermissionDetailPage-B8C7tWFP.js.map} +1 -1
  107. package/dist/chunks/{PermissionDetailPage-_HhbxzlG.js → PermissionDetailPage-IUgUaTkE.js} +2 -2
  108. package/dist/chunks/{PermissionDetailPage-_HhbxzlG.js.map → PermissionDetailPage-IUgUaTkE.js.map} +1 -1
  109. package/dist/chunks/{PermissionsPage-Xb92YAHn.js → PermissionsPage-CmX5sQf2.js} +2 -2
  110. package/dist/chunks/{PermissionsPage-Xb92YAHn.js.map → PermissionsPage-CmX5sQf2.js.map} +1 -1
  111. package/dist/chunks/{PermissionsPage-B0M4gA5m.js → PermissionsPage-Kg0rduOM.js} +2 -2
  112. package/dist/chunks/{PermissionsPage-B0M4gA5m.js.map → PermissionsPage-Kg0rduOM.js.map} +1 -1
  113. package/dist/chunks/{PortalDashboardPage-DTeMESj9.js → PortalDashboardPage-CCAYuhtI.js} +2 -2
  114. package/dist/chunks/{PortalDashboardPage-DTeMESj9.js.map → PortalDashboardPage-CCAYuhtI.js.map} +1 -1
  115. package/dist/chunks/{PortalDashboardPage-pt9hipR4.js → PortalDashboardPage-Dme1XmzN.js} +2 -2
  116. package/dist/chunks/{PortalDashboardPage-pt9hipR4.js.map → PortalDashboardPage-Dme1XmzN.js.map} +1 -1
  117. package/dist/chunks/{PreferencesPage-Cy30AWIN.js → PreferencesPage-Ct6xWAFp.js} +2 -2
  118. package/dist/chunks/{PreferencesPage-Cy30AWIN.js.map → PreferencesPage-Ct6xWAFp.js.map} +1 -1
  119. package/dist/chunks/{PreferencesPage-CsHVGMgp.js → PreferencesPage-Db2RjMpm.js} +2 -2
  120. package/dist/chunks/{PreferencesPage-CsHVGMgp.js.map → PreferencesPage-Db2RjMpm.js.map} +1 -1
  121. package/dist/chunks/{ProfilePage-6Gf7igUI.js → ProfilePage-D6Xb1ALH.js} +2 -2
  122. package/dist/chunks/{ProfilePage-6Gf7igUI.js.map → ProfilePage-D6Xb1ALH.js.map} +1 -1
  123. package/dist/chunks/{ProfilePage-BzBWkztf.js → ProfilePage-DN2s-lfp.js} +2 -2
  124. package/dist/chunks/{ProfilePage-BzBWkztf.js.map → ProfilePage-DN2s-lfp.js.map} +1 -1
  125. package/dist/chunks/{ReferencesManagementPage-DEDoHrnU.js → ReferencesManagementPage-B5mcshG1.js} +2 -2
  126. package/dist/chunks/{ReferencesManagementPage-DEDoHrnU.js.map → ReferencesManagementPage-B5mcshG1.js.map} +1 -1
  127. package/dist/chunks/{ReferencesManagementPage-DD1QiFYr.js → ReferencesManagementPage-DB975ktX.js} +3 -3
  128. package/dist/chunks/{ReferencesManagementPage-DD1QiFYr.js.map → ReferencesManagementPage-DB975ktX.js.map} +1 -1
  129. package/dist/chunks/{RegisterPage-asdx33fV.js → RegisterPage-ZskZrLZH.js} +2 -2
  130. package/dist/chunks/{RegisterPage-asdx33fV.js.map → RegisterPage-ZskZrLZH.js.map} +1 -1
  131. package/dist/chunks/{RegisterPage-CIPHRYkl.js → RegisterPage-b8yIPVgh.js} +2 -2
  132. package/dist/chunks/{RegisterPage-CIPHRYkl.js.map → RegisterPage-b8yIPVgh.js.map} +1 -1
  133. package/dist/chunks/{ResetPasswordPage-B4Dj24vU.js → ResetPasswordPage-CeAvfsE-.js} +2 -2
  134. package/dist/chunks/{ResetPasswordPage-B4Dj24vU.js.map → ResetPasswordPage-CeAvfsE-.js.map} +1 -1
  135. package/dist/chunks/{ResetPasswordPage-B8MWH_Vi.js → ResetPasswordPage-Dzp5dCp8.js} +2 -2
  136. package/dist/chunks/{ResetPasswordPage-B8MWH_Vi.js.map → ResetPasswordPage-Dzp5dCp8.js.map} +1 -1
  137. package/dist/chunks/{ResolutionModal-Cs6T441o.js → ResolutionModal-CRVN7gHv.js} +2 -2
  138. package/dist/chunks/{ResolutionModal-Cs6T441o.js.map → ResolutionModal-CRVN7gHv.js.map} +1 -1
  139. package/dist/chunks/{ResolutionModal-rLoFOxm9.js → ResolutionModal-DJOw1sLT.js} +2 -2
  140. package/dist/chunks/{ResolutionModal-rLoFOxm9.js.map → ResolutionModal-DJOw1sLT.js.map} +1 -1
  141. package/dist/chunks/{RoleDetailPage-Pkw0wU5g.js → RoleDetailPage-CLVoFVF8.js} +2 -2
  142. package/dist/chunks/{RoleDetailPage-Pkw0wU5g.js.map → RoleDetailPage-CLVoFVF8.js.map} +1 -1
  143. package/dist/chunks/{RoleDetailPage-CNFG6j6P.js → RoleDetailPage-XGnPD_8C.js} +3 -3
  144. package/dist/chunks/{RoleDetailPage-CNFG6j6P.js.map → RoleDetailPage-XGnPD_8C.js.map} +1 -1
  145. package/dist/chunks/{RolesPage-BHEkMR2O.js → RolesPage-BnAMpR2b.js} +2 -2
  146. package/dist/chunks/{RolesPage-BHEkMR2O.js.map → RolesPage-BnAMpR2b.js.map} +1 -1
  147. package/dist/chunks/{RolesPage-D35jwDJU.js → RolesPage-Czj9LMkL.js} +2 -2
  148. package/dist/chunks/{RolesPage-D35jwDJU.js.map → RolesPage-Czj9LMkL.js.map} +1 -1
  149. package/dist/chunks/{SlaConfigPage-DtonDehw.js → SlaConfigPage-HM0MpIlg.js} +2 -2
  150. package/dist/chunks/{SlaConfigPage-DtonDehw.js.map → SlaConfigPage-HM0MpIlg.js.map} +1 -1
  151. package/dist/chunks/{SlaConfigPage-C5Jstix-.js → SlaConfigPage-ZRyAs8aY.js} +2 -2
  152. package/dist/chunks/{SlaConfigPage-C5Jstix-.js.map → SlaConfigPage-ZRyAs8aY.js.map} +1 -1
  153. package/dist/chunks/{SupportPermissionsPage-6pC73oCY.js → SupportPermissionsPage-CxJuGgcQ.js} +2 -2
  154. package/dist/chunks/{SupportPermissionsPage-6pC73oCY.js.map → SupportPermissionsPage-CxJuGgcQ.js.map} +1 -1
  155. package/dist/chunks/{SupportPermissionsPage-CsJKGt__.js → SupportPermissionsPage-DNd323OK.js} +2 -2
  156. package/dist/chunks/{SupportPermissionsPage-CsJKGt__.js.map → SupportPermissionsPage-DNd323OK.js.map} +1 -1
  157. package/dist/chunks/{TemplatesPage-DjmYOGEC.js → TemplatesPage-CdwPLsHj.js} +2 -2
  158. package/dist/chunks/{TemplatesPage-DjmYOGEC.js.map → TemplatesPage-CdwPLsHj.js.map} +1 -1
  159. package/dist/chunks/{TemplatesPage-DlY91VO_.js → TemplatesPage-Co3ygZvF.js} +2 -2
  160. package/dist/chunks/{TemplatesPage-DlY91VO_.js.map → TemplatesPage-Co3ygZvF.js.map} +1 -1
  161. package/dist/chunks/{TenantCard-BHLcv2gD.js → TenantCard-CmCfIK2F.js} +2 -2
  162. package/dist/chunks/{TenantCard-BHLcv2gD.js.map → TenantCard-CmCfIK2F.js.map} +1 -1
  163. package/dist/chunks/{TenantCard-DGCKVvKI.js → TenantCard-DI66acce.js} +2 -2
  164. package/dist/chunks/{TenantCard-DGCKVvKI.js.map → TenantCard-DI66acce.js.map} +1 -1
  165. package/dist/chunks/{TenantScopeSelector-dsSwnOWg.js → TenantScopeSelector-5NOwmFX2.js} +2 -2
  166. package/dist/chunks/{TenantScopeSelector-dsSwnOWg.js.map → TenantScopeSelector-5NOwmFX2.js.map} +1 -1
  167. package/dist/chunks/{TenantScopeSelector-CU5z5PJH.js → TenantScopeSelector-CEFgxiWt.js} +2 -2
  168. package/dist/chunks/{TenantScopeSelector-CU5z5PJH.js.map → TenantScopeSelector-CEFgxiWt.js.map} +1 -1
  169. package/dist/chunks/{TicketDetailPage-BQHMaRmq.js → TicketDetailPage-BhZ-mpv7.js} +2 -2
  170. package/dist/chunks/{TicketDetailPage-BQHMaRmq.js.map → TicketDetailPage-BhZ-mpv7.js.map} +1 -1
  171. package/dist/chunks/{TicketDetailPage-Bk_0uQ3B.js → TicketDetailPage-BxOiOG22.js} +2 -2
  172. package/dist/chunks/{TicketDetailPage-Bk_0uQ3B.js.map → TicketDetailPage-BxOiOG22.js.map} +1 -1
  173. package/dist/chunks/{TicketsPage-CufUJctx.js → TicketsPage-BiTvIcM8.js} +2 -2
  174. package/dist/chunks/{TicketsPage-CufUJctx.js.map → TicketsPage-BiTvIcM8.js.map} +1 -1
  175. package/dist/chunks/{TicketsPage-C8QQ4SKy.js → TicketsPage-CSiinHME.js} +2 -2
  176. package/dist/chunks/{TicketsPage-C8QQ4SKy.js.map → TicketsPage-CSiinHME.js.map} +1 -1
  177. package/dist/chunks/{UserCreateTicketPage-DoEMtJoe.js → UserCreateTicketPage-B3TW1oV7.js} +2 -2
  178. package/dist/chunks/{UserCreateTicketPage-DoEMtJoe.js.map → UserCreateTicketPage-B3TW1oV7.js.map} +1 -1
  179. package/dist/chunks/{UserCreateTicketPage-XxjNlR9K.js → UserCreateTicketPage-BszUd_WZ.js} +2 -2
  180. package/dist/chunks/{UserCreateTicketPage-XxjNlR9K.js.map → UserCreateTicketPage-BszUd_WZ.js.map} +1 -1
  181. package/dist/chunks/{UserDashboardPage-fdhZwMLg.js → UserDashboardPage-C6MvatAb.js} +2 -2
  182. package/dist/chunks/{UserDashboardPage-fdhZwMLg.js.map → UserDashboardPage-C6MvatAb.js.map} +1 -1
  183. package/dist/chunks/{UserDashboardPage-BV1d2hMG.js → UserDashboardPage-Dtt9VzG_.js} +2 -2
  184. package/dist/chunks/{UserDashboardPage-BV1d2hMG.js.map → UserDashboardPage-Dtt9VzG_.js.map} +1 -1
  185. package/dist/chunks/{UserDetailPage-C97e-Dax.js → UserDetailPage-BEEV2vlJ.js} +5 -5
  186. package/dist/chunks/{UserDetailPage-C97e-Dax.js.map → UserDetailPage-BEEV2vlJ.js.map} +1 -1
  187. package/dist/chunks/{UserDetailPage-BcA7Vhb2.js → UserDetailPage-Dw5OHheZ.js} +2 -2
  188. package/dist/chunks/{UserDetailPage-BcA7Vhb2.js.map → UserDetailPage-Dw5OHheZ.js.map} +1 -1
  189. package/dist/chunks/{UserTicketDetailPage-BA2syxXG.js → UserTicketDetailPage-B4YkzzbR.js} +2 -2
  190. package/dist/chunks/{UserTicketDetailPage-BA2syxXG.js.map → UserTicketDetailPage-B4YkzzbR.js.map} +1 -1
  191. package/dist/chunks/{UserTicketDetailPage-CXuZVAa2.js → UserTicketDetailPage-DCFV-0ny.js} +2 -2
  192. package/dist/chunks/{UserTicketDetailPage-CXuZVAa2.js.map → UserTicketDetailPage-DCFV-0ny.js.map} +1 -1
  193. package/dist/chunks/{UsersGroupsPage-CPVk31Dh.js → UsersGroupsPage-CY-l9fTp.js} +3 -3
  194. package/dist/chunks/{UsersGroupsPage-CPVk31Dh.js.map → UsersGroupsPage-CY-l9fTp.js.map} +1 -1
  195. package/dist/chunks/{UsersGroupsPage-DS2YiUE4.js → UsersGroupsPage-c28vYHN9.js} +2 -2
  196. package/dist/chunks/{UsersGroupsPage-DS2YiUE4.js.map → UsersGroupsPage-c28vYHN9.js.map} +1 -1
  197. package/dist/chunks/{UsersPage-BIXWHFmG.js → UsersPage-1sLlq9QD.js} +2 -2
  198. package/dist/chunks/{UsersPage-BIXWHFmG.js.map → UsersPage-1sLlq9QD.js.map} +1 -1
  199. package/dist/chunks/{UsersPage-DS8aWUKj.js → UsersPage-Bm-uNxh0.js} +2 -2
  200. package/dist/chunks/{UsersPage-DS8aWUKj.js.map → UsersPage-Bm-uNxh0.js.map} +1 -1
  201. package/dist/chunks/{accessRequestsApi-C-r0mrCH.js → accessRequestsApi-CJPjyEkH.js} +2 -2
  202. package/dist/chunks/{accessRequestsApi-C-r0mrCH.js.map → accessRequestsApi-CJPjyEkH.js.map} +1 -1
  203. package/dist/chunks/{accessRequestsApi-k3ZwhcFb.js → accessRequestsApi-D_pj1wl6.js} +2 -2
  204. package/dist/chunks/{accessRequestsApi-k3ZwhcFb.js.map → accessRequestsApi-D_pj1wl6.js.map} +1 -1
  205. package/dist/chunks/{aiApi-B-H-76wM.js → aiApi-ByF-oo1J.js} +2 -2
  206. package/dist/chunks/{aiApi-B-H-76wM.js.map → aiApi-ByF-oo1J.js.map} +1 -1
  207. package/dist/chunks/{aiApi-CcdrBILv.js → aiApi-Dt3fj0dU.js} +2 -2
  208. package/dist/chunks/{aiApi-CcdrBILv.js.map → aiApi-Dt3fj0dU.js.map} +1 -1
  209. package/dist/chunks/{applicationAnalyticsApi-CO3tk6Ju.js → applicationAnalyticsApi-BgG3SGJm.js} +2 -2
  210. package/dist/chunks/{applicationAnalyticsApi-CO3tk6Ju.js.map → applicationAnalyticsApi-BgG3SGJm.js.map} +1 -1
  211. package/dist/chunks/{applicationAnalyticsApi-CLVdVLDu.js → applicationAnalyticsApi-ktD65iLO.js} +2 -2
  212. package/dist/chunks/{applicationAnalyticsApi-CLVdVLDu.js.map → applicationAnalyticsApi-ktD65iLO.js.map} +1 -1
  213. package/dist/chunks/{groupsApi-DExOJZPF.js → groupsApi-C-FLWPCO.js} +2 -2
  214. package/dist/chunks/{groupsApi-DExOJZPF.js.map → groupsApi-C-FLWPCO.js.map} +1 -1
  215. package/dist/chunks/{groupsApi-CyqyYsmi.js → groupsApi-CBI5vMLa.js} +2 -2
  216. package/dist/chunks/{groupsApi-CyqyYsmi.js.map → groupsApi-CBI5vMLa.js.map} +1 -1
  217. package/dist/chunks/{index-DtAReZI6.js → index-B727-QSU.js} +2 -2
  218. package/dist/chunks/{index-DtAReZI6.js.map → index-B727-QSU.js.map} +1 -1
  219. package/dist/chunks/{index-BlOgmQzc.js → index-B9q3vx13.js} +2 -2
  220. package/dist/chunks/{index-BlOgmQzc.js.map → index-B9q3vx13.js.map} +1 -1
  221. package/dist/chunks/{index-VSQ2prtJ.js → index-BD-REzV9.js} +2 -2
  222. package/dist/chunks/{index-VSQ2prtJ.js.map → index-BD-REzV9.js.map} +1 -1
  223. package/dist/chunks/{index-XOOiD_zY.js → index-BDRogQH_.js} +3 -3
  224. package/dist/chunks/{index-XOOiD_zY.js.map → index-BDRogQH_.js.map} +1 -1
  225. package/dist/chunks/{index-DOQyf5yZ.js → index-C-DYxdvd.js} +8 -8
  226. package/dist/chunks/{index-DOQyf5yZ.js.map → index-C-DYxdvd.js.map} +1 -1
  227. package/dist/chunks/{index-Cq80YBne.js → index-CBtjGPod.js} +105 -105
  228. package/dist/chunks/{index-Cq80YBne.js.map → index-CBtjGPod.js.map} +1 -1
  229. package/dist/chunks/{index-dlXYTPWH.js → index-CF1cvNUL.js} +4 -4
  230. package/dist/chunks/{index-dlXYTPWH.js.map → index-CF1cvNUL.js.map} +1 -1
  231. package/dist/chunks/{index-COA_xJVJ.js → index-CH0pTHy1.js} +2 -2
  232. package/dist/chunks/{index-COA_xJVJ.js.map → index-CH0pTHy1.js.map} +1 -1
  233. package/dist/chunks/{index-DjZQ6ZG_.js → index-Ca88RIuT.js} +2 -2
  234. package/dist/chunks/{index-DjZQ6ZG_.js.map → index-Ca88RIuT.js.map} +1 -1
  235. package/dist/chunks/{index-Cj-9tGpd.js → index-CkWvsvKW.js} +2 -2
  236. package/dist/chunks/{index-Cj-9tGpd.js.map → index-CkWvsvKW.js.map} +1 -1
  237. package/dist/chunks/{index-EL_ZNnMH.js → index-CzYKE5fL.js} +2 -2
  238. package/dist/chunks/{index-EL_ZNnMH.js.map → index-CzYKE5fL.js.map} +1 -1
  239. package/dist/chunks/{index-qXfYaEmV.js → index-D32ol7lq.js} +2 -2
  240. package/dist/chunks/{index-qXfYaEmV.js.map → index-D32ol7lq.js.map} +1 -1
  241. package/dist/chunks/{index-DMQQ0KyA.js → index-D7hmx9IX.js} +2 -2
  242. package/dist/chunks/{index-DMQQ0KyA.js.map → index-D7hmx9IX.js.map} +1 -1
  243. package/dist/chunks/{index-BetDcNZm.js → index-DThcQmwZ.js} +2 -2
  244. package/dist/chunks/{index-BetDcNZm.js.map → index-DThcQmwZ.js.map} +1 -1
  245. package/dist/chunks/{index-C7h5yvcP.js → index-D_3J6ziZ.js} +2 -2
  246. package/dist/chunks/{index-C7h5yvcP.js.map → index-D_3J6ziZ.js.map} +1 -1
  247. package/dist/chunks/{index-C_nDTEP5.js → index-JSjfMShT.js} +2 -2
  248. package/dist/chunks/{index-C_nDTEP5.js.map → index-JSjfMShT.js.map} +1 -1
  249. package/dist/chunks/{index-COXxU0FH.js → index-gzXJw_ow.js} +3 -3
  250. package/dist/chunks/{index-COXxU0FH.js.map → index-gzXJw_ow.js.map} +1 -1
  251. package/dist/chunks/{index-jJxtz2bs.js → index-rRAbl04H.js} +2 -2
  252. package/dist/chunks/{index-jJxtz2bs.js.map → index-rRAbl04H.js.map} +1 -1
  253. package/dist/chunks/{tenantIconMap-Ddvguo0l.js → tenantIconMap-Cw-hQ9n4.js} +2 -2
  254. package/dist/chunks/{tenantIconMap-Ddvguo0l.js.map → tenantIconMap-Cw-hQ9n4.js.map} +1 -1
  255. package/dist/chunks/{tenantIconMap-DBa5MjIz.js → tenantIconMap-DinwojNW.js} +2 -2
  256. package/dist/chunks/{tenantIconMap-DBa5MjIz.js.map → tenantIconMap-DinwojNW.js.map} +1 -1
  257. package/dist/chunks/{ticketingApi-Cr6QSv0g.js → ticketingApi-CcWdebXv.js} +2 -2
  258. package/dist/chunks/{ticketingApi-Cr6QSv0g.js.map → ticketingApi-CcWdebXv.js.map} +1 -1
  259. package/dist/chunks/{ticketingApi-D6s75rOB.js → ticketingApi-x0BwZ1NH.js} +2 -2
  260. package/dist/chunks/{ticketingApi-D6s75rOB.js.map → ticketingApi-x0BwZ1NH.js.map} +1 -1
  261. package/dist/chunks/{useAccessRequests-VuQT-n-P.js → useAccessRequests-BBTIYht3.js} +2 -2
  262. package/dist/chunks/{useAccessRequests-VuQT-n-P.js.map → useAccessRequests-BBTIYht3.js.map} +1 -1
  263. package/dist/chunks/{useAccessRequests-CanI2ypo.js → useAccessRequests-BBUj9XY9.js} +71 -71
  264. package/dist/chunks/{useAccessRequests-CanI2ypo.js.map → useAccessRequests-BBUj9XY9.js.map} +1 -1
  265. package/dist/chunks/{useUserAccessRequests-BEVZLX_M.js → useUserAccessRequests-BKQxcOXH.js} +2 -2
  266. package/dist/chunks/{useUserAccessRequests-BEVZLX_M.js.map → useUserAccessRequests-BKQxcOXH.js.map} +1 -1
  267. package/dist/chunks/{useUserAccessRequests-Ba40FDLm.js → useUserAccessRequests-BPUPiP55.js} +2 -2
  268. package/dist/chunks/{useUserAccessRequests-Ba40FDLm.js.map → useUserAccessRequests-BPUPiP55.js.map} +1 -1
  269. package/dist/pages/platform/administration/applications/ApplicationDetailPage.d.ts.map +1 -1
  270. package/dist/smartstack.cjs +1 -1
  271. package/dist/smartstack.js +1 -1
  272. package/package.json +1 -1
  273. 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-Cq80YBne.js";
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-jJxtz2bs.js.map
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\">&infin;</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\">&infin;</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-XOOiD_zY.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-Ddvguo0l.js.map
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-Ddvguo0l.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
+ {"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-Cq80YBne.js";
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-DBa5MjIz.js.map
95
+ //# sourceMappingURL=tenantIconMap-DinwojNW.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tenantIconMap-DBa5MjIz.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
+ {"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-Cq80YBne.js";
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-Cr6QSv0g.js.map
11
+ //# sourceMappingURL=ticketingApi-CcWdebXv.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ticketingApi-Cr6QSv0g.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
+ {"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-XOOiD_zY.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-D6s75rOB.js.map
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-D6s75rOB.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
+ {"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-XOOiD_zY.js"),F=require("./AccessRequestStatusBadge-CNTI7EDr.js"),v=require("lucide-react"),N=require("./accessRequestsApi-C-r0mrCH.js");function $({open:d,onClose:p,onConfirm:u,request:n,action:t,processing:i}){const{t:s}=L.useTranslation("admin"),[o,m]=l.useState(""),[r,x]=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(()=>{!d||!h||(I(!0),k.adminApi.tenants.getGroups(n.tenantId).then(c=>{w(c.filter(T=>T.isActive))}).catch(()=>{w([])}).finally(()=>{I(!1)}))},[d,h,n.tenantId]),l.useEffect(()=>{!d||!h||r!=="role"||a.length>0||(C(!0),k.adminApi.roles.getByApplication(n.applicationId).then(c=>{f(c)}).catch(()=>{f([])}).finally(()=>{C(!1)}))},[d,h,r,n.applicationId,a.length]),l.useEffect(()=>{d||(m(""),x("group"),g(""),y(""),f([]),w([]))},[d]);const G=async()=>{if(R){await u({notes:o||void 0});return}await u({roleId:r==="role"?b:void 0,groupId:r==="group"?j:void 0,notes:o||void 0})};if(!d)return null;const E=h?(r==="role"&&b!==""||r==="group"&&j!=="")&&!i:o!==""&&!i;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:p,className:"p-1 hover:bg-[var(--bg-hover)] rounded",disabled:i,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:()=>x("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:()=>x("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=>m(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:p,className:"px-4 py-2 rounded-[var(--radius-button)] border border-[var(--border-color)] hover:bg-[var(--bg-hover)]",disabled:i,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:[i&&e.jsx(v.Loader2,{className:"w-4 h-4 animate-spin"}),s(`accessRequests.actions.${t}`)]})]})]})]})})}function B(d){const[p,u]=l.useState(!1),[n,t]=l.useState(null);return{approve:async(o,m)=>{u(!0),t(null);try{await N.accessRequestsApi.approveRequest(o,m),d?.()}catch(r){throw t(r instanceof Error?r.message:"Failed to approve request"),r}finally{u(!1)}},deny:async(o,m)=>{u(!0),t(null);try{await N.accessRequestsApi.denyRequest(o,m),d?.()}catch(r){throw t(r instanceof Error?r.message:"Failed to deny request"),r}finally{u(!1)}},processing:p,error:n}}function M({requests:d,loading:p,onReload:u,showTenantColumn:n=!1}){const{t}=L.useTranslation("admin"),[i,s]=l.useState(null),[o,m]=l.useState(null),{approve:r,deny:x,processing:b}=B(()=>{s(null),m(null),u()}),g=(a,f)=>{s(a),m(f)},j=async a=>{i&&(o==="approve"?await r(i.id,a):o==="deny"&&a.notes&&await x(i.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 p?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:d,columns:y,searchable:!0,searchPlaceholder:t("accessRequests.search"),getRowKey:a=>a.id,emptyMessage:t("accessRequests.empty")}),i&&o&&e.jsx($,{open:!0,onClose:()=>{s(null),m(null)},onConfirm:j,request:i,action:o,processing:b})]})}function P(d,p){const[u,n]=l.useState([]),[t,i]=l.useState(!1),[s,o]=l.useState(null);return{requests:u,loading:t,error:s,loadRequests:async r=>{i(!0),o(null);try{const x=d==="application"?await N.accessRequestsApi.getRequestsByApplication(p,r):await N.accessRequestsApi.getRequestsByTenant(p,r);n(Array.isArray(x)?x:[])}catch(x){o(x.message||"Failed to load requests"),n([])}finally{i(!1)}}}}exports.AccessRequestsListTab=M;exports.useAccessRequests=P;
2
- //# sourceMappingURL=useAccessRequests-VuQT-n-P.js.map
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