@samanhappy/mcphub 1.0.31 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/README.zh.md +12 -2
- package/dist/betterAuth.js +13 -5
- package/dist/betterAuth.js.map +1 -1
- package/dist/cli/commands/cache.js.map +1 -1
- package/dist/cli/commands/call.js +2 -2
- package/dist/cli/commands/call.js.map +1 -1
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/discover.js.map +1 -1
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/groups.js.map +1 -1
- package/dist/cli/commands/install.js +1 -1
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/keys.js.map +1 -1
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/servers.js.map +1 -1
- package/dist/cli/commands/tools.js +2 -2
- package/dist/cli/commands/tools.js.map +1 -1
- package/dist/cli/context.js +1 -1
- package/dist/cli/context.js.map +1 -1
- package/dist/cli/http.js +3 -1
- package/dist/cli/http.js.map +1 -1
- package/dist/clients/openapi.js +498 -76
- package/dist/clients/openapi.js.map +1 -1
- package/dist/config/DaoConfigService.js +3 -2
- package/dist/config/DaoConfigService.js.map +1 -1
- package/dist/config/configManager.js +9 -8
- package/dist/config/configManager.js.map +1 -1
- package/dist/config/index.js +54 -8
- package/dist/config/index.js.map +1 -1
- package/dist/config/jwt.js +2 -1
- package/dist/config/jwt.js.map +1 -1
- package/dist/config/migrationUtils.js +46 -45
- package/dist/config/migrationUtils.js.map +1 -1
- package/dist/constants/oauthServerDefaults.js +5 -0
- package/dist/constants/oauthServerDefaults.js.map +1 -1
- package/dist/controllers/activityController.js +6 -5
- package/dist/controllers/activityController.js.map +1 -1
- package/dist/controllers/authController.js +5 -4
- package/dist/controllers/authController.js.map +1 -1
- package/dist/controllers/bearerKeyController.js +7 -6
- package/dist/controllers/bearerKeyController.js.map +1 -1
- package/dist/controllers/betterAuthController.js +2 -1
- package/dist/controllers/betterAuthController.js.map +1 -1
- package/dist/controllers/builtinPromptController.js +13 -5
- package/dist/controllers/builtinPromptController.js.map +1 -1
- package/dist/controllers/builtinResourceController.js +14 -6
- package/dist/controllers/builtinResourceController.js.map +1 -1
- package/dist/controllers/changelogController.js +5 -2
- package/dist/controllers/changelogController.js.map +1 -1
- package/dist/controllers/cloudController.js +11 -10
- package/dist/controllers/cloudController.js.map +1 -1
- package/dist/controllers/configController.js +4 -3
- package/dist/controllers/configController.js.map +1 -1
- package/dist/controllers/contextCostController.js +3 -2
- package/dist/controllers/contextCostController.js.map +1 -1
- package/dist/controllers/groupController.js +2 -1
- package/dist/controllers/groupController.js.map +1 -1
- package/dist/controllers/healthController.js +2 -1
- package/dist/controllers/healthController.js.map +1 -1
- package/dist/controllers/hostedInternalController.js +2 -1
- package/dist/controllers/hostedInternalController.js.map +1 -1
- package/dist/controllers/logController.js +5 -4
- package/dist/controllers/logController.js.map +1 -1
- package/dist/controllers/mcpbController.js +23 -20
- package/dist/controllers/mcpbController.js.map +1 -1
- package/dist/controllers/oauthCallbackController.js +54 -27
- package/dist/controllers/oauthCallbackController.js.map +1 -1
- package/dist/controllers/oauthClientController.js +7 -6
- package/dist/controllers/oauthClientController.js.map +1 -1
- package/dist/controllers/oauthDynamicRegistrationController.js +22 -4
- package/dist/controllers/oauthDynamicRegistrationController.js.map +1 -1
- package/dist/controllers/oauthServerController.js +62 -15
- package/dist/controllers/oauthServerController.js.map +1 -1
- package/dist/controllers/openApiController.js +7 -6
- package/dist/controllers/openApiController.js.map +1 -1
- package/dist/controllers/promptController.js +2 -1
- package/dist/controllers/promptController.js.map +1 -1
- package/dist/controllers/registryController.js +4 -3
- package/dist/controllers/registryController.js.map +1 -1
- package/dist/controllers/serverController.js +154 -65
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/controllers/templateController.js +3 -2
- package/dist/controllers/templateController.js.map +1 -1
- package/dist/controllers/toolController.js +2 -1
- package/dist/controllers/toolController.js.map +1 -1
- package/dist/dao/DaoFactory.js +3 -2
- package/dist/dao/DaoFactory.js.map +1 -1
- package/dist/dao/ServerDao.js.map +1 -1
- package/dist/dao/UserConfigDaoDbImpl.js.map +1 -1
- package/dist/dao/UserDao.js.map +1 -1
- package/dist/dao/base/JsonFileBaseDao.js +3 -2
- package/dist/dao/base/JsonFileBaseDao.js.map +1 -1
- package/dist/dao/examples.js +35 -34
- package/dist/dao/examples.js.map +1 -1
- package/dist/db/connection.js +59 -58
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.js +2 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/repositories/ServerRepository.js +3 -3
- package/dist/db/repositories/ServerRepository.js.map +1 -1
- package/dist/db/repositories/SystemConfigRepository.js +2 -1
- package/dist/db/repositories/SystemConfigRepository.js.map +1 -1
- package/dist/db/repositories/UserConfigRepository.js.map +1 -1
- package/dist/db/repositories/VectorEmbeddingRepository.js +6 -5
- package/dist/db/repositories/VectorEmbeddingRepository.js.map +1 -1
- package/dist/index.js +28 -19
- package/dist/index.js.map +1 -1
- package/dist/middlewares/auth.js +4 -3
- package/dist/middlewares/auth.js.map +1 -1
- package/dist/middlewares/index.js +2 -1
- package/dist/middlewares/index.js.map +1 -1
- package/dist/middlewares/userContext.js +7 -6
- package/dist/middlewares/userContext.js.map +1 -1
- package/dist/models/OAuth.js +7 -6
- package/dist/models/OAuth.js.map +1 -1
- package/dist/models/User.js +13 -12
- package/dist/models/User.js.map +1 -1
- package/dist/routes/index.js +11 -10
- package/dist/routes/index.js.map +1 -1
- package/dist/scripts/dao-demo.js +28 -27
- package/dist/scripts/dao-demo.js.map +1 -1
- package/dist/server.js +36 -30
- package/dist/server.js.map +1 -1
- package/dist/services/activityLoggingService.js +3 -2
- package/dist/services/activityLoggingService.js.map +1 -1
- package/dist/services/authorizationService.js +28 -0
- package/dist/services/authorizationService.js.map +1 -0
- package/dist/services/betterAuthConfig.js +1 -4
- package/dist/services/betterAuthConfig.js.map +1 -1
- package/dist/services/betterAuthSession.js +8 -7
- package/dist/services/betterAuthSession.js.map +1 -1
- package/dist/services/changelogService.js +5 -2
- package/dist/services/changelogService.js.map +1 -1
- package/dist/services/cimdClientService.js +195 -0
- package/dist/services/cimdClientService.js.map +1 -0
- package/dist/services/cloudService.js +10 -9
- package/dist/services/cloudService.js.map +1 -1
- package/dist/services/contextCostService.js +6 -2
- package/dist/services/contextCostService.js.map +1 -1
- package/dist/services/groupService.js +8 -7
- package/dist/services/groupService.js.map +1 -1
- package/dist/services/hostedAuthService.js +3 -2
- package/dist/services/hostedAuthService.js.map +1 -1
- package/dist/services/hostedControlPlaneClient.js.map +1 -1
- package/dist/services/hostedEventSubscriber.js +9 -8
- package/dist/services/hostedEventSubscriber.js.map +1 -1
- package/dist/services/hostedRuntimeCatalogNames.js +1 -3
- package/dist/services/hostedRuntimeCatalogNames.js.map +1 -1
- package/dist/services/keepAliveService.js +7 -6
- package/dist/services/keepAliveService.js.map +1 -1
- package/dist/services/marketService.js +2 -1
- package/dist/services/marketService.js.map +1 -1
- package/dist/services/mcpOAuthProvider.js +22 -21
- package/dist/services/mcpOAuthProvider.js.map +1 -1
- package/dist/services/mcpService.js +239 -130
- package/dist/services/mcpService.js.map +1 -1
- package/dist/services/oauthClientRegistration.js +30 -29
- package/dist/services/oauthClientRegistration.js.map +1 -1
- package/dist/services/oauthServerService.js +39 -18
- package/dist/services/oauthServerService.js.map +1 -1
- package/dist/services/oauthService.js +16 -15
- package/dist/services/oauthService.js.map +1 -1
- package/dist/services/oauthSettingsStore.js +4 -3
- package/dist/services/oauthSettingsStore.js.map +1 -1
- package/dist/services/openApiGeneratorService.js +1 -3
- package/dist/services/openApiGeneratorService.js.map +1 -1
- package/dist/services/openApiToolStatsService.js +37 -0
- package/dist/services/openApiToolStatsService.js.map +1 -0
- package/dist/services/registry.js +2 -1
- package/dist/services/registry.js.map +1 -1
- package/dist/services/requestContextService.js.map +1 -1
- package/dist/services/serverConfigPresenter.js +85 -0
- package/dist/services/serverConfigPresenter.js.map +1 -0
- package/dist/services/smartRoutingService.js +6 -5
- package/dist/services/smartRoutingService.js.map +1 -1
- package/dist/services/sseService.js +52 -51
- package/dist/services/sseService.js.map +1 -1
- package/dist/services/templateService.js +105 -23
- package/dist/services/templateService.js.map +1 -1
- package/dist/services/toolResultCompressionService.js +8 -5
- package/dist/services/toolResultCompressionService.js.map +1 -1
- package/dist/services/upstreamOAuthDisconnectService.js +9 -6
- package/dist/services/upstreamOAuthDisconnectService.js.map +1 -1
- package/dist/services/userService.js +5 -4
- package/dist/services/userService.js.map +1 -1
- package/dist/services/vectorSearchService.js +126 -112
- package/dist/services/vectorSearchService.js.map +1 -1
- package/dist/utils/cacheUtils.js +5 -4
- package/dist/utils/cacheUtils.js.map +1 -1
- package/dist/utils/corsOrigin.js +42 -0
- package/dist/utils/corsOrigin.js.map +1 -0
- package/dist/utils/dbRetry.js +2 -5
- package/dist/utils/dbRetry.js.map +1 -1
- package/dist/utils/frontendShell.js +2 -1
- package/dist/utils/frontendShell.js.map +1 -1
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/logger.js +170 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/migration.js +51 -50
- package/dist/utils/migration.js.map +1 -1
- package/dist/utils/oauthIssuer.js +57 -0
- package/dist/utils/oauthIssuer.js.map +1 -0
- package/dist/utils/openApiRequestBody.js +220 -0
- package/dist/utils/openApiRequestBody.js.map +1 -0
- package/dist/utils/parameterConversion.js +2 -1
- package/dist/utils/parameterConversion.js.map +1 -1
- package/dist/utils/path.js +9 -8
- package/dist/utils/path.js.map +1 -1
- package/dist/utils/processTree.js +47 -0
- package/dist/utils/processTree.js.map +1 -0
- package/dist/utils/proxyTrust.js.map +1 -1
- package/dist/utils/rateLimit.js +8 -0
- package/dist/utils/rateLimit.js.map +1 -1
- package/dist/utils/requireAdmin.js +15 -0
- package/dist/utils/requireAdmin.js.map +1 -0
- package/dist/utils/serverConfigPersistence.js +3 -0
- package/dist/utils/serverConfigPersistence.js.map +1 -1
- package/dist/utils/serverConfigValidation.js +13 -0
- package/dist/utils/serverConfigValidation.js.map +1 -0
- package/dist/utils/serverNameValidation.js +56 -0
- package/dist/utils/serverNameValidation.js.map +1 -0
- package/dist/utils/serverShutdown.js +3 -2
- package/dist/utils/serverShutdown.js.map +1 -1
- package/dist/utils/smartRouting.js +4 -3
- package/dist/utils/smartRouting.js.map +1 -1
- package/dist/utils/ssrf.js +23 -10
- package/dist/utils/ssrf.js.map +1 -1
- package/dist/utils/systemConfigCache.js +40 -2
- package/dist/utils/systemConfigCache.js.map +1 -1
- package/dist/utils/tokenCost.js.map +1 -1
- package/dist/utils/tokenTruncation.js +9 -4
- package/dist/utils/tokenTruncation.js.map +1 -1
- package/dist/utils/version.js +3 -2
- package/dist/utils/version.js.map +1 -1
- package/frontend/dist/assets/{ActivityPage-Dx53zxEM.js → ActivityPage-Du9Nh-Jy.js} +2 -2
- package/frontend/dist/assets/{ActivityPage-Dx53zxEM.js.map → ActivityPage-Du9Nh-Jy.js.map} +1 -1
- package/frontend/dist/assets/ConfirmDialog-3APts2Y9.js +2 -0
- package/frontend/dist/assets/ConfirmDialog-3APts2Y9.js.map +1 -0
- package/frontend/dist/assets/Dashboard-J4G-AZkI.js +2 -0
- package/frontend/dist/assets/{Dashboard-ZYVsSvOw.js.map → Dashboard-J4G-AZkI.js.map} +1 -1
- package/frontend/dist/assets/{DeleteDialog-DNe-zTEl.js → DeleteDialog-D9ycSRvn.js} +2 -2
- package/frontend/dist/assets/{DeleteDialog-DNe-zTEl.js.map → DeleteDialog-D9ycSRvn.js.map} +1 -1
- package/frontend/dist/assets/{EndpointCopy-ngxLPeDF.js → EndpointCopy-DFeLcU9A.js} +2 -2
- package/frontend/dist/assets/{EndpointCopy-ngxLPeDF.js.map → EndpointCopy-DFeLcU9A.js.map} +1 -1
- package/frontend/dist/assets/GroupsPage-CGMZBiXd.js +33 -0
- package/frontend/dist/assets/{GroupsPage-JPtupGpI.js.map → GroupsPage-CGMZBiXd.js.map} +1 -1
- package/frontend/dist/assets/{LoginPage-B6rU3Ugr.js → LoginPage-g5pJLBk0.js} +2 -2
- package/frontend/dist/assets/{LoginPage-B6rU3Ugr.js.map → LoginPage-g5pJLBk0.js.map} +1 -1
- package/frontend/dist/assets/{LogsPage-CXq382fb.js → LogsPage-Bkv7xhNf.js} +2 -2
- package/frontend/dist/assets/{LogsPage-CXq382fb.js.map → LogsPage-Bkv7xhNf.js.map} +1 -1
- package/frontend/dist/assets/MarketPage-WkLrckIr.js +3 -0
- package/frontend/dist/assets/MarketPage-WkLrckIr.js.map +1 -0
- package/frontend/dist/assets/{OAuthConsentPage-C-n6tv3-.js → OAuthConsentPage-CA35XoBK.js} +2 -2
- package/frontend/dist/assets/{OAuthConsentPage-C-n6tv3-.js.map → OAuthConsentPage-CA35XoBK.js.map} +1 -1
- package/frontend/dist/assets/{Pagination-DLSuQ8hw.js → Pagination-Dwko3g48.js} +2 -2
- package/frontend/dist/assets/{Pagination-DLSuQ8hw.js.map → Pagination-Dwko3g48.js.map} +1 -1
- package/frontend/dist/assets/{PromptsPage-BLpy76K4.js → PromptsPage-BuDdW69R.js} +2 -2
- package/frontend/dist/assets/{PromptsPage-BLpy76K4.js.map → PromptsPage-BuDdW69R.js.map} +1 -1
- package/frontend/dist/assets/{ResourcesPage-C5nynRqE.js → ResourcesPage-Cu-eD5e2.js} +2 -2
- package/frontend/dist/assets/{ResourcesPage-C5nynRqE.js.map → ResourcesPage-Cu-eD5e2.js.map} +1 -1
- package/frontend/dist/assets/{ServersPage-Ca5W9cPW.js → ServersPage-B1Np5x3N.js} +8 -8
- package/frontend/dist/assets/ServersPage-B1Np5x3N.js.map +1 -0
- package/frontend/dist/assets/{SettingsPage-DgFBjp_O.js → SettingsPage-BQN8-ZQh.js} +4 -4
- package/frontend/dist/assets/SettingsPage-BQN8-ZQh.js.map +1 -0
- package/frontend/dist/assets/{StatusDot-CmSkukx0.js → StatusDot-WyvgqplP.js} +2 -2
- package/frontend/dist/assets/{StatusDot-CmSkukx0.js.map → StatusDot-WyvgqplP.js.map} +1 -1
- package/frontend/dist/assets/{ToggleGroup-sG_2LQom.js → ToggleGroup-CmeedsZU.js} +2 -2
- package/frontend/dist/assets/{ToggleGroup-sG_2LQom.js.map → ToggleGroup-CmeedsZU.js.map} +1 -1
- package/frontend/dist/assets/UsersPage-DqDFrIIW.js +2 -0
- package/frontend/dist/assets/UsersPage-DqDFrIIW.js.map +1 -0
- package/frontend/dist/assets/contextCost-CilWqGWT.js +2 -0
- package/frontend/dist/assets/contextCost-CilWqGWT.js.map +1 -0
- package/frontend/dist/assets/{framework-vendor-I9Y6AgD5.js → framework-vendor-BHAQX05P.js} +3 -3
- package/frontend/dist/assets/{framework-vendor-I9Y6AgD5.js.map → framework-vendor-BHAQX05P.js.map} +1 -1
- package/frontend/dist/assets/{i18n-vendor-y9bLzIeh.js → i18n-vendor-CMcB7XUR.js} +2 -2
- package/frontend/dist/assets/{i18n-vendor-y9bLzIeh.js.map → i18n-vendor-CMcB7XUR.js.map} +1 -1
- package/frontend/dist/assets/{icons-vendor-BFl4A9fq.js → icons-vendor-HZHHWeTa.js} +2 -2
- package/frontend/dist/assets/{icons-vendor-BFl4A9fq.js.map → icons-vendor-HZHHWeTa.js.map} +1 -1
- package/frontend/dist/assets/index-BvU2-VT8.js +3 -0
- package/frontend/dist/assets/{index-CLugsCsy.js.map → index-BvU2-VT8.js.map} +1 -1
- package/frontend/dist/assets/index-DtrCVU1h.css +1 -0
- package/frontend/dist/assets/passwordValidation-DTLWgUy9.js +2 -0
- package/frontend/dist/assets/passwordValidation-DTLWgUy9.js.map +1 -0
- package/frontend/dist/assets/{resourceService-33rS8QGJ.js → resourceService-BFH4w47h.js} +2 -2
- package/frontend/dist/assets/{resourceService-33rS8QGJ.js.map → resourceService-BFH4w47h.js.map} +1 -1
- package/frontend/dist/assets/useCostData-CoM1SxdS.js +2 -0
- package/frontend/dist/assets/useCostData-CoM1SxdS.js.map +1 -0
- package/frontend/dist/assets/useSettingsData-DKrECrG1.js +2 -0
- package/frontend/dist/assets/{useSettingsData-fK2bv9oN.js.map → useSettingsData-DKrECrG1.js.map} +1 -1
- package/frontend/dist/assets/variableDetection-CIrYDjrq.js +16 -0
- package/frontend/dist/assets/variableDetection-CIrYDjrq.js.map +1 -0
- package/frontend/dist/index.html +5 -5
- package/package.json +2 -2
- package/frontend/dist/assets/ConfirmDialog-CYfXEuyU.js +0 -2
- package/frontend/dist/assets/ConfirmDialog-CYfXEuyU.js.map +0 -1
- package/frontend/dist/assets/Dashboard-ZYVsSvOw.js +0 -2
- package/frontend/dist/assets/GroupsPage-JPtupGpI.js +0 -33
- package/frontend/dist/assets/MarketPage-BGnQQyXK.js +0 -3
- package/frontend/dist/assets/MarketPage-BGnQQyXK.js.map +0 -1
- package/frontend/dist/assets/ServersPage-Ca5W9cPW.js.map +0 -1
- package/frontend/dist/assets/SettingsPage-DgFBjp_O.js.map +0 -1
- package/frontend/dist/assets/UsersPage-PHkFXLL8.js +0 -2
- package/frontend/dist/assets/UsersPage-PHkFXLL8.js.map +0 -1
- package/frontend/dist/assets/contextCost-D_iNNbhX.js +0 -2
- package/frontend/dist/assets/contextCost-D_iNNbhX.js.map +0 -1
- package/frontend/dist/assets/index-CGvImZ3F.css +0 -1
- package/frontend/dist/assets/index-CLugsCsy.js +0 -3
- package/frontend/dist/assets/useSettingsData-fK2bv9oN.js +0 -2
- package/frontend/dist/assets/variableDetection-ByJ_cnxa.js +0 -16
- package/frontend/dist/assets/variableDetection-ByJ_cnxa.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e}from"./framework-vendor-
|
|
2
|
-
//# sourceMappingURL=StatusDot-
|
|
1
|
+
import{j as e}from"./framework-vendor-BHAQX05P.js";import{m as l}from"./index-BvU2-VT8.js";import{u}from"./i18n-vendor-CMcB7XUR.js";const h={connected:"ok",connecting:"warn",oauth_required:"warn",disconnected:"err"},p={connected:"status.online",connecting:"status.connecting",oauth_required:"status.oauthRequired",disconnected:"status.offline"},c=({kind:n,label:i,className:a,onClick:s,title:t})=>e.jsxs("span",{className:l("hub-status",n,s?"cursor-pointer hover:opacity-80":"",a),onClick:s,title:t,children:[e.jsx("span",{className:"hub-dot"}),i!=null&&e.jsx("span",{className:"hub-status-label",children:i})]}),S=({status:n,enabled:i,startOnDemand:a,onAuthClick:s,className:t})=>{const{t:r}=u();if(i===!1)return e.jsx(c,{kind:"muted",label:r("server.disable")||"Disabled",className:t});if(a&&n==="disconnected")return e.jsx(c,{kind:"muted",label:e.jsxs(e.Fragment,{children:[e.jsx("span",{"aria-hidden":!0,children:"💤"}),e.jsx("span",{children:r("status.sleeping","Sleeping")})]}),title:r("status.sleepingDescription","On-demand server — will start automatically when a tool is called"),className:t});const d=h[n]??"muted",o=n==="oauth_required";return e.jsx(c,{kind:d,label:e.jsxs(e.Fragment,{children:[o&&e.jsx("span",{"aria-hidden":!0,children:"🔐"}),e.jsx("span",{children:r(p[n]||n)})]}),onClick:o&&s?s:void 0,title:o?r("status.clickToAuthorize"):void 0,className:t})};export{S,c as a};
|
|
2
|
+
//# sourceMappingURL=StatusDot-WyvgqplP.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusDot-
|
|
1
|
+
{"version":3,"file":"StatusDot-WyvgqplP.js","sources":["../../src/components/ui/StatusDot.tsx"],"sourcesContent":["import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport type { ServerStatus } from '@/types';\nimport { cn } from '@/utils/cn';\n\nexport type DotKind = 'ok' | 'warn' | 'err' | 'muted';\n\nconst STATUS_TO_KIND: Record<ServerStatus, DotKind> = {\n connected: 'ok',\n connecting: 'warn',\n oauth_required: 'warn',\n disconnected: 'err',\n};\n\nconst STATUS_TO_KEY: Record<ServerStatus, string> = {\n connected: 'status.online',\n connecting: 'status.connecting',\n oauth_required: 'status.oauthRequired',\n disconnected: 'status.offline',\n};\n\ninterface StatusDotProps {\n kind: DotKind;\n label?: React.ReactNode;\n className?: string;\n onClick?: (e: React.MouseEvent) => void;\n title?: string;\n}\n\nexport const StatusDot: React.FC<StatusDotProps> = ({ kind, label, className, onClick, title }) => (\n <span\n className={cn('hub-status', kind, onClick ? 'cursor-pointer hover:opacity-80' : '', className)}\n onClick={onClick}\n title={title}\n >\n <span className=\"hub-dot\" />\n {label != null && <span className=\"hub-status-label\">{label}</span>}\n </span>\n);\n\ninterface ServerStatusDotProps {\n status: ServerStatus;\n enabled?: boolean;\n startOnDemand?: boolean;\n onAuthClick?: (e: React.MouseEvent) => void;\n className?: string;\n}\n\nexport const ServerStatusDot: React.FC<ServerStatusDotProps> = ({\n status,\n enabled,\n startOnDemand,\n onAuthClick,\n className,\n}) => {\n const { t } = useTranslation();\n if (enabled === false) {\n return <StatusDot kind=\"muted\" label={t('server.disable') || 'Disabled'} className={className} />;\n }\n // On-demand servers that are disconnected are \"sleeping\", not offline\n if (startOnDemand && status === 'disconnected') {\n return (\n <StatusDot\n kind=\"muted\"\n label={\n <>\n <span aria-hidden>💤</span>\n <span>{t('status.sleeping', 'Sleeping')}</span>\n </>\n }\n title={t('status.sleepingDescription', 'On-demand server — will start automatically when a tool is called')}\n className={className}\n />\n );\n }\n const kind = STATUS_TO_KIND[status] ?? 'muted';\n const isOAuth = status === 'oauth_required';\n return (\n <StatusDot\n kind={kind}\n label={\n <>\n {isOAuth && <span aria-hidden>🔐</span>}\n <span>{t(STATUS_TO_KEY[status] || status)}</span>\n </>\n }\n onClick={isOAuth && onAuthClick ? onAuthClick : undefined}\n title={isOAuth ? t('status.clickToAuthorize') : undefined}\n className={className}\n />\n );\n};\n"],"names":["STATUS_TO_KIND","STATUS_TO_KEY","StatusDot","kind","label","className","onClick","title","jsxs","cn","jsx","ServerStatusDot","status","enabled","startOnDemand","onAuthClick","t","useTranslation","Fragment","isOAuth"],"mappings":"oIAOA,MAAMA,EAAgD,CACpD,UAAW,KACX,WAAY,OACZ,eAAgB,OAChB,aAAc,KAChB,EAEMC,EAA8C,CAClD,UAAW,gBACX,WAAY,oBACZ,eAAgB,uBAChB,aAAc,gBAChB,EAUaC,EAAsC,CAAC,CAAE,KAAAC,EAAM,MAAAC,EAAO,UAAAC,EAAW,QAAAC,EAAS,MAAAC,KACrFC,EAAAA,KAAC,OAAA,CACC,UAAWC,EAAG,aAAcN,EAAMG,EAAU,kCAAoC,GAAID,CAAS,EAC7F,QAAAC,EACA,MAAAC,EAEA,SAAA,CAAAG,EAAAA,IAAC,OAAA,CAAK,UAAU,SAAA,CAAU,EACzBN,GAAS,MAAQM,EAAAA,IAAC,OAAA,CAAK,UAAU,mBAAoB,SAAAN,CAAA,CAAM,CAAA,CAAA,CAC9D,EAWWO,EAAkD,CAAC,CAC9D,OAAAC,EACA,QAAAC,EACA,cAAAC,EACA,YAAAC,EACA,UAAAV,CACF,IAAM,CACJ,KAAM,CAAE,EAAAW,CAAA,EAAMC,EAAA,EACd,GAAIJ,IAAY,GACd,OAAOH,MAACR,GAAU,KAAK,QAAQ,MAAOc,EAAE,gBAAgB,GAAK,WAAY,UAAAX,CAAA,CAAsB,EAGjG,GAAIS,GAAiBF,IAAW,eAC9B,OACEF,EAAAA,IAACR,EAAA,CACC,KAAK,QACL,MACEM,EAAAA,KAAAU,WAAA,CACE,SAAA,CAAAR,EAAAA,IAAC,OAAA,CAAK,cAAW,GAAC,SAAA,KAAE,EACpBA,EAAAA,IAAC,OAAA,CAAM,SAAAM,EAAE,kBAAmB,UAAU,CAAA,CAAE,CAAA,EAC1C,EAEF,MAAOA,EAAE,6BAA8B,mEAAmE,EAC1G,UAAAX,CAAA,CAAA,EAIN,MAAMF,EAAOH,EAAeY,CAAM,GAAK,QACjCO,EAAUP,IAAW,iBAC3B,OACEF,EAAAA,IAACR,EAAA,CACC,KAAAC,EACA,MACEK,EAAAA,KAAAU,WAAA,CACG,SAAA,CAAAC,GAAWT,EAAAA,IAAC,OAAA,CAAK,cAAW,GAAC,SAAA,KAAE,QAC/B,OAAA,CAAM,SAAAM,EAAEf,EAAcW,CAAM,GAAKA,CAAM,CAAA,CAAE,CAAA,EAC5C,EAEF,QAASO,GAAWJ,EAAcA,EAAc,OAChD,MAAOI,EAAUH,EAAE,yBAAyB,EAAI,OAChD,UAAAX,CAAA,CAAA,CAGN"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as u}from"./framework-vendor-
|
|
2
|
-
//# sourceMappingURL=ToggleGroup-
|
|
1
|
+
import{j as u}from"./framework-vendor-BHAQX05P.js";import{m as f}from"./index-BvU2-VT8.js";const n=({checked:t,onCheckedChange:m,disabled:o=!1,size:s="regular",className:p,onClick:r,...c})=>u.jsx("button",{...c,type:"button",role:"switch","aria-checked":t,disabled:o,className:f("hub-switch",t&&"on",s==="card"&&"card",s==="compact"&&"compact",p),onClick:a=>{a.stopPropagation(),r==null||r(a),!a.defaultPrevented&&!o&&m(!t)}});export{n as S};
|
|
2
|
+
//# sourceMappingURL=ToggleGroup-CmeedsZU.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToggleGroup-
|
|
1
|
+
{"version":3,"file":"ToggleGroup-CmeedsZU.js","sources":["../../src/components/ui/ToggleGroup.tsx"],"sourcesContent":["import React, { ReactNode, useId } from 'react';\nimport { cn } from '@/utils/cn';\n\ninterface ToggleGroupItemProps {\n value: string;\n isSelected: boolean;\n onClick: () => void;\n children: ReactNode;\n}\n\nexport const ToggleGroupItem: React.FC<ToggleGroupItemProps> = ({\n isSelected,\n onClick,\n children,\n}) => {\n return (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={isSelected}\n className={cn(\n 'flex w-full cursor-pointer items-center justify-between rounded p-2 transition-colors',\n isSelected\n ? 'border-l-4 border-blue-500 bg-blue-50 text-blue-700 hover:bg-blue-100'\n : 'text-gray-700 hover:bg-gray-50',\n )}\n onClick={onClick}\n >\n <span className=\"flex items-center\">{children}</span>\n {isSelected && (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" className=\"h-5 w-5 text-blue-500\">\n <path\n fillRule=\"evenodd\"\n d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )}\n </button>\n );\n};\n\ninterface ToggleGroupProps {\n label: string;\n helpText?: string;\n noOptionsText?: string;\n values: string[];\n options: { value: string; label: string }[];\n onChange: (values: string[]) => void;\n className?: string;\n}\n\nexport const ToggleGroup: React.FC<ToggleGroupProps> = ({\n label,\n helpText,\n noOptionsText = 'No options available',\n values,\n options,\n onChange,\n className,\n}) => {\n const labelId = useId();\n\n const handleToggle = (value: string) => {\n const isSelected = values.includes(value);\n if (isSelected) {\n onChange(values.filter((v) => v !== value));\n } else {\n onChange([...values, value]);\n }\n };\n\n return (\n <div className={className}>\n <div id={labelId} className=\"mb-2 block text-sm font-bold text-gray-700\">{label}</div>\n <div\n role=\"group\"\n aria-labelledby={labelId}\n className=\"max-h-60 overflow-y-auto rounded border border-gray-200 shadow dark:border-gray-700\"\n >\n {options.length === 0 ? (\n <p className=\"p-3 text-sm text-gray-500\">{noOptionsText}</p>\n ) : (\n <div className=\"space-y-1 p-1\">\n {options.map((option) => (\n <ToggleGroupItem\n key={option.value}\n value={option.value}\n isSelected={values.includes(option.value)}\n onClick={() => handleToggle(option.value)}\n >\n {option.label}\n </ToggleGroupItem>\n ))}\n </div>\n )}\n </div>\n {helpText && <p className=\"mt-1 text-xs text-gray-500\">{helpText}</p>}\n </div>\n );\n};\n\ninterface SwitchProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'onChange' | 'role' | 'type'> {\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n size?: 'regular' | 'card' | 'compact';\n}\n\nexport const Switch: React.FC<SwitchProps> = ({\n checked,\n onCheckedChange,\n disabled = false,\n size = 'regular',\n className,\n onClick,\n ...buttonProps\n}) => {\n return (\n <button\n {...buttonProps}\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={cn(\n 'hub-switch',\n checked && 'on',\n size === 'card' && 'card',\n size === 'compact' && 'compact',\n className,\n )}\n onClick={(event) => {\n event.stopPropagation();\n onClick?.(event);\n if (!event.defaultPrevented && !disabled) {\n onCheckedChange(!checked);\n }\n }}\n />\n );\n};"],"names":["Switch","checked","onCheckedChange","disabled","size","className","onClick","buttonProps","jsx","cn","event"],"mappings":"2FA4GO,MAAMA,EAAgC,CAAC,CAC5C,QAAAC,EACA,gBAAAC,EACA,SAAAC,EAAW,GACX,KAAAC,EAAO,UACP,UAAAC,EACA,QAAAC,EACA,GAAGC,CACL,IAEIC,EAAAA,IAAC,SAAA,CACE,GAAGD,EACJ,KAAK,SACL,KAAK,SACL,eAAcN,EACd,SAAAE,EACA,UAAWM,EACT,aACAR,GAAW,KACXG,IAAS,QAAU,OACnBA,IAAS,WAAa,UACtBC,CAAA,EAEF,QAAUK,GAAU,CAClBA,EAAM,gBAAA,EACNJ,GAAA,MAAAA,EAAUI,GACN,CAACA,EAAM,kBAAoB,CAACP,GAC9BD,EAAgB,CAACD,CAAO,CAE5B,CAAA,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as u,j as e}from"./framework-vendor-BHAQX05P.js";import{j as S,f as E,h as A,e as U,u as F}from"./index-BvU2-VT8.js";import{u as N}from"./i18n-vendor-CMcB7XUR.js";import{v as k,m as P}from"./passwordValidation-DTLWgUy9.js";import{D as z}from"./DeleteDialog-D9ycSRvn.js";import{a as D}from"./StatusDot-WyvgqplP.js";import{R,P as L,l as T,X as I,U as q,w as H,T as V}from"./icons-vendor-HZHHWeTa.js";const v=()=>{const{t}=N(),[w,a]=u.useState([]),[l,j]=u.useState(!0),[b,i]=u.useState(null),[f,m]=u.useState(0),h=u.useCallback(async()=>{try{j(!0);const r=await S("/users");if(!r.success){i(r.message||t("users.fetchError"));return}r&&r.success&&Array.isArray(r.data)?a(r.data):(console.error("Invalid user data format:",r),a([])),i(null)}catch(r){console.error("Error fetching users:",r),i(r instanceof Error?r.message:"Failed to fetch users"),a([])}finally{j(!1)}},[]),o=u.useCallback(()=>{m(r=>r+1)},[]),c=async r=>{try{const s=await U("/users",r);return o(),s}catch(s){return i(s instanceof Error?s.message:"Failed to create user"),null}},g=async(r,s)=>{try{const x=await A(`/users/${r}`,s);return o(),x||null}catch(x){return i(x instanceof Error?x.message:"Failed to update user"),null}},p=async r=>{try{const s=await E(`/users/${r}`);return s!=null&&s.success?(o(),s):(i((s==null?void 0:s.message)||t("users.deleteError")),s)}catch(s){return i(s instanceof Error?s.message:"Failed to delete user"),!1}};return u.useEffect(()=>{h()},[h,f]),{users:w,loading:l,error:b,setError:i,triggerRefresh:o,createUser:c,updateUser:g,deleteUser:p}},$=({onAdd:t,onCancel:w})=>{const{t:a}=N(),{createUser:l}=v(),[j,b]=u.useState(null),[i,f]=u.useState([]),[m,h]=u.useState(!1),[o,c]=u.useState({username:"",password:"",isAdmin:!1,email:""}),g=async r=>{var x;if(r.preventDefault(),b(null),f([]),!o.username.trim()){b(a("users.usernameRequired"));return}if(!o.password.trim()){b(a("users.passwordRequired"));return}const s=k(o.password);if(!s.isValid){b(a("auth.passwordStrengthError")),f(s.errors.map(n=>a(`auth.${n}`)));return}h(!0);try{const n=await l(o);n!=null&&n.success?t():(x=n==null?void 0:n.errors)!=null&&x.length?(b(n.message||a("auth.passwordStrengthError")),f(P(n.errors).map(d=>a(d)))):b((n==null?void 0:n.message)||a("users.createError"))}catch(n){b(n instanceof Error?n.message:a("users.createError"))}finally{h(!1)}},p=r=>{const{name:s,value:x,type:n,checked:d}=r.target;c(y=>({...y,[s]:n==="checkbox"?d:x}))};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsx("div",{className:"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700",children:e.jsxs("form",{onSubmit:g,children:[e.jsx("h2",{className:"text-xl font-bold text-gray-900 mb-6",children:a("users.addNew")}),j&&e.jsxs("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md",children:[e.jsx("p",{className:"text-sm font-medium",children:j}),i.length>0&&e.jsx("ul",{className:"list-disc list-inside mt-2 space-y-1 text-sm",children:i.map(r=>e.jsx("li",{children:r},r))})]}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"username",className:"block text-sm font-medium text-gray-700 mb-1",children:[a("users.username")," ",e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("input",{type:"text",id:"username",name:"username",value:o.username,onChange:p,placeholder:a("users.usernamePlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",required:!0,disabled:m})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"email",className:"block text-sm font-medium text-gray-700 mb-1",children:a("users.email")}),e.jsx("input",{type:"email",id:"email",name:"email",value:o.email||"",onChange:p,placeholder:a("users.emailPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:m})]}),e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"password",className:"block text-sm font-medium text-gray-700 mb-1",children:[a("users.password")," ",e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("input",{type:"password",id:"password",name:"password",value:o.password,onChange:p,placeholder:a("users.passwordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",required:!0,disabled:m,minLength:8}),e.jsx("p",{className:"mt-1 text-xs text-gray-500",children:a("auth.passwordStrengthHint")})]}),e.jsxs("div",{className:"flex items-center pt-2",children:[e.jsx("input",{type:"checkbox",id:"isAdmin",name:"isAdmin",checked:o.isAdmin,onChange:p,className:"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200",disabled:m}),e.jsx("label",{htmlFor:"isAdmin",className:"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none",children:a("users.adminRole")})]})]}),e.jsxs("div",{className:"flex justify-end space-x-2 mt-6",children:[e.jsx("button",{type:"button",onClick:w,className:"hub-btn",disabled:m,children:a("common.cancel")}),e.jsxs("button",{type:"submit",className:"hub-btn primary",disabled:m,children:[m&&e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),a(m?"common.creating":"users.create")]})]})]})})})},B=({user:t,onEdit:w,onCancel:a})=>{const{t:l}=N(),{updateUser:j}=v(),[b,i]=u.useState(null),[f,m]=u.useState([]),[h,o]=u.useState(!1),[c,g]=u.useState({isAdmin:t.isAdmin,email:t.email||"",newPassword:"",confirmPassword:""}),p=async s=>{var x;if(s.preventDefault(),i(null),m([]),c.newPassword&&c.newPassword!==c.confirmPassword){i(l("users.passwordMismatch"));return}if(c.newPassword){const n=k(c.newPassword);if(!n.isValid){i(l("auth.passwordStrengthError")),m(n.errors.map(d=>l(`auth.${d}`)));return}}o(!0);try{const n={isAdmin:c.isAdmin,email:c.email};c.newPassword&&(n.newPassword=c.newPassword);const d=await j(t.username,n);d!=null&&d.success?w():(x=d==null?void 0:d.errors)!=null&&x.length?(i(d.message||l("auth.passwordStrengthError")),m(P(d.errors).map(y=>l(y)))):i((d==null?void 0:d.message)||l("users.updateError"))}catch(n){i(n instanceof Error?n.message:l("users.updateError"))}finally{o(!1)}},r=s=>{const{name:x,value:n,type:d,checked:y}=s.target;g(C=>({...C,[x]:d==="checkbox"?y:n}))};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsx("div",{className:"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700",children:e.jsxs("form",{onSubmit:p,children:[e.jsxs("h2",{className:"text-xl font-bold text-gray-900 mb-6",children:[l("users.edit")," - ",e.jsx("span",{className:"text-blue-600",children:t.username})]}),b&&e.jsxs("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md",children:[e.jsx("p",{className:"text-sm font-medium",children:b}),f.length>0&&e.jsx("ul",{className:"list-disc list-inside mt-2 space-y-1 text-sm",children:f.map(s=>e.jsx("li",{children:s},s))})]}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex items-center pt-2",children:[e.jsx("input",{type:"checkbox",id:"isAdmin",name:"isAdmin",checked:c.isAdmin,onChange:r,className:"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200",disabled:h}),e.jsx("label",{htmlFor:"isAdmin",className:"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none",children:l("users.adminRole")})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"email",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.email")}),e.jsx("input",{type:"email",id:"email",name:"email",value:c.email,onChange:r,placeholder:l("users.emailPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:h})]}),e.jsxs("div",{className:"border-t border-gray-100 dark:border-gray-700 pt-4 mt-2",children:[e.jsx("p",{className:"text-xs text-gray-500 uppercase font-semibold tracking-wider mb-3",children:l("users.changePassword")}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"newPassword",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.newPassword")}),e.jsx("input",{type:"password",id:"newPassword",name:"newPassword",value:c.newPassword,onChange:r,placeholder:l("users.newPasswordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:h,minLength:8}),e.jsx("p",{className:"mt-1 text-xs text-gray-500",children:l("auth.passwordStrengthHint")})]}),c.newPassword&&e.jsxs("div",{className:"animate-fadeIn",children:[e.jsx("label",{htmlFor:"confirmPassword",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.confirmPassword")}),e.jsx("input",{type:"password",id:"confirmPassword",name:"confirmPassword",value:c.confirmPassword,onChange:r,placeholder:l("users.confirmPasswordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:h,minLength:8})]})]})]})]}),e.jsxs("div",{className:"flex justify-end space-x-2 mt-6",children:[e.jsx("button",{type:"button",onClick:a,className:"hub-btn",disabled:h,children:l("common.cancel")}),e.jsxs("button",{type:"submit",className:"hub-btn primary",disabled:h,children:[h&&e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),l(h?"common.updating":"users.update")]})]})]})})})},Q=()=>{const{t}=N(),{auth:w}=F(),a=w.user,{users:l,loading:j,error:b,setError:i,deleteUser:f,triggerRefresh:m}=v(),[h,o]=u.useState(null),[c,g]=u.useState(!1),[p,r]=u.useState(null);return a!=null&&a.isAdmin?e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-end justify-between gap-4 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"hub-h1",children:t("pages.users.title")}),e.jsxs("p",{className:"hub-sub",children:[e.jsx("span",{className:"hub-num",children:l.length})," ",t("nav.users").toLowerCase()]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("button",{className:"hub-btn",onClick:()=>m(),"aria-label":t("common.refresh"),children:[e.jsx(R,{size:13})," ",t("common.refresh")]}),e.jsxs("button",{className:"hub-btn primary",onClick:()=>g(!0),children:[e.jsx(L,{size:13})," ",t("users.add")]})]})]}),b&&e.jsxs("div",{className:"hub-card flex items-center justify-between gap-3 mb-4",style:{padding:"10px 14px",borderColor:"oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)"},children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(T,{size:14,className:"flex-shrink-0"}),e.jsx("span",{className:"truncate text-[13px]",children:b})]}),e.jsx("button",{className:"hub-icon-btn sm",onClick:()=>i(null),children:e.jsx(I,{size:13})})]}),j?e.jsx("div",{className:"hub-card p-10 text-center",style:{color:"var(--hub-ink-3)"},children:t("app.loading")}):l.length===0?e.jsx("div",{className:"hub-card p-10 text-center",style:{color:"var(--hub-ink-3)"},children:e.jsxs("div",{className:"flex flex-col items-center gap-3",children:[e.jsx("div",{className:"grid place-items-center",style:{width:40,height:40,borderRadius:10,border:"1px solid var(--hub-line)",background:"var(--hub-bg-2)"},children:e.jsx(q,{size:18})}),e.jsx("div",{className:"font-medium",style:{color:"var(--hub-ink-2)",fontSize:13},children:t("users.noUsers")}),e.jsx("button",{onClick:()=>g(!0),className:"hub-btn ghost sm",style:{color:"var(--hub-accent)"},children:t("users.addFirst")})]})}):e.jsxs("div",{className:"hub-card overflow-hidden",children:[e.jsxs("div",{className:"hub-row head hub-mono",style:{gridTemplateColumns:"1.6fr 1.2fr 100px 100px"},children:[e.jsx("div",{children:t("users.username")}),e.jsx("div",{children:t("users.email")}),e.jsx("div",{children:t("users.role")}),e.jsx("div",{className:"text-right",children:t("users.actions")})]}),l.map(s=>{const x=(a==null?void 0:a.username)===s.username;return e.jsxs("div",{className:"hub-row hover",style:{gridTemplateColumns:"1.6fr 1.2fr 100px 100px"},children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[e.jsx("div",{className:"grid place-items-center flex-shrink-0 hub-mono",style:{width:28,height:28,borderRadius:7,background:"var(--hub-bg-2)",border:"1px solid var(--hub-line)",color:"var(--hub-ink-2)",fontWeight:600,fontSize:12},children:s.username.charAt(0).toUpperCase()}),e.jsx("span",{className:"hub-mono truncate",style:{fontSize:13,color:"var(--hub-ink)"},children:s.username}),x&&e.jsx("span",{className:"hub-tag accent",style:{fontSize:10},children:t("users.currentUser")})]}),e.jsx("div",{className:"flex items-center min-w-0",children:e.jsx("span",{className:"truncate",style:{fontSize:13,color:s.email?"var(--hub-ink)":"var(--hub-ink-3)"},children:s.email||"—"})}),e.jsx("div",{children:e.jsx(D,{kind:s.isAdmin?"ok":"muted",label:s.isAdmin?t("users.admin"):t("users.user")})}),e.jsxs("div",{className:"flex justify-end gap-1",children:[e.jsx("button",{onClick:()=>o(s),className:"hub-icon-btn sm",title:t("users.edit"),children:e.jsx(H,{size:13})}),!x&&e.jsx("button",{onClick:()=>r(s.username),className:"hub-icon-btn sm",title:t("users.delete"),style:{color:"var(--hub-err)"},children:e.jsx(V,{size:13})})]})]},s.username)})]}),c&&e.jsx($,{onAdd:()=>{g(!1),m()},onCancel:()=>g(!1)}),h&&e.jsx(B,{user:h,onEdit:()=>{o(null),m()},onCancel:()=>o(null)}),e.jsx(z,{isOpen:!!p,onClose:()=>r(null),onConfirm:async()=>{if(p){const s=await f(p);s!=null&&s.success||i((s==null?void 0:s.message)||t("users.deleteError")),r(null)}},serverName:p||"",isGroup:!1,isUser:!0})]}):e.jsx("div",{className:"hub-card p-6 text-center",style:{color:"var(--hub-err)"},children:t("users.adminRequired")})};export{Q as default};
|
|
2
|
+
//# sourceMappingURL=UsersPage-DqDFrIIW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UsersPage-DqDFrIIW.js","sources":["../../src/hooks/useUserData.ts","../../src/components/AddUserForm.tsx","../../src/components/EditUserForm.tsx","../../src/pages/UsersPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { User, ApiResponse, UserFormData, UserUpdateData } from '@/types';\nimport { apiDelete, apiGet, apiPost, apiPut } from '../utils/fetchInterceptor';\n\nexport const useUserData = () => {\n const { t } = useTranslation();\n const [users, setUsers] = useState<User[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [refreshKey, setRefreshKey] = useState(0);\n\n const fetchUsers = useCallback(async () => {\n try {\n setLoading(true);\n const data: ApiResponse<User[]> = await apiGet('/users');\n if (!data.success) {\n setError(data.message || t('users.fetchError'));\n return;\n }\n\n if (data && data.success && Array.isArray(data.data)) {\n setUsers(data.data);\n } else {\n console.error('Invalid user data format:', data);\n setUsers([]);\n }\n\n setError(null);\n } catch (err) {\n console.error('Error fetching users:', err);\n setError(err instanceof Error ? err.message : 'Failed to fetch users');\n setUsers([]);\n } finally {\n setLoading(false);\n }\n }, []);\n\n // Trigger a refresh of the users data\n const triggerRefresh = useCallback(() => {\n setRefreshKey((prev) => prev + 1);\n }, []);\n\n // Create a new user\n const createUser = async (userData: UserFormData) => {\n try {\n const result: ApiResponse<User> = await apiPost('/users', userData);\n triggerRefresh();\n return result;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create user');\n return null;\n }\n };\n\n // Update an existing user\n const updateUser = async (username: string, data: UserUpdateData) => {\n try {\n const result: ApiResponse<User> = await apiPut(`/users/${username}`, data);\n triggerRefresh();\n return result || null;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update user');\n return null;\n }\n };\n\n // Delete a user\n const deleteUser = async (username: string) => {\n try {\n const result = await apiDelete(`/users/${username}`);\n if (!result?.success) {\n setError(result?.message || t('users.deleteError'));\n return result;\n }\n\n triggerRefresh();\n return result;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to delete user');\n return false;\n }\n };\n\n // Fetch users when the component mounts or refreshKey changes\n useEffect(() => {\n fetchUsers();\n }, [fetchUsers, refreshKey]);\n\n return {\n users,\n loading,\n error,\n setError,\n triggerRefresh,\n createUser,\n updateUser,\n deleteUser,\n };\n};\n","import { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useUserData } from '@/hooks/useUserData';\nimport { UserFormData } from '@/types';\nimport {\n validatePasswordStrength,\n mapBackendPasswordErrors,\n} from '../utils/passwordValidation';\n\ninterface AddUserFormProps {\n onAdd: () => void;\n onCancel: () => void;\n}\n\nconst AddUserForm = ({ onAdd, onCancel }: AddUserFormProps) => {\n const { t } = useTranslation();\n const { createUser } = useUserData();\n const [error, setError] = useState<string | null>(null);\n const [passwordErrors, setPasswordErrors] = useState<string[]>([]);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const [formData, setFormData] = useState<UserFormData>({\n username: '',\n password: '',\n isAdmin: false,\n email: '',\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setPasswordErrors([]);\n\n if (!formData.username.trim()) {\n setError(t('users.usernameRequired'));\n return;\n }\n\n if (!formData.password.trim()) {\n setError(t('users.passwordRequired'));\n return;\n }\n\n const validation = validatePasswordStrength(formData.password);\n if (!validation.isValid) {\n setError(t('auth.passwordStrengthError'));\n setPasswordErrors(validation.errors.map((key) => t(`auth.${key}`)));\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n const result = await createUser(formData);\n if (result?.success) {\n onAdd();\n } else if (result?.errors?.length) {\n setError(result.message || t('auth.passwordStrengthError'));\n setPasswordErrors(mapBackendPasswordErrors(result.errors).map((key) => t(key)));\n } else {\n setError(result?.message || t('users.createError'));\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('users.createError'));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target;\n setFormData((prev) => ({\n ...prev,\n [name]: type === 'checkbox' ? checked : value,\n }));\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700\">\n <form onSubmit={handleSubmit}>\n <h2 className=\"text-xl font-bold text-gray-900 mb-6\">{t('users.addNew')}</h2>\n\n {error && (\n <div className=\"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md\">\n <p className=\"text-sm font-medium\">{error}</p>\n {passwordErrors.length > 0 && (\n <ul className=\"list-disc list-inside mt-2 space-y-1 text-sm\">\n {passwordErrors.map((message) => (\n <li key={message}>{message}</li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n <div className=\"space-y-5\">\n <div>\n <label htmlFor=\"username\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.username')} <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"username\"\n name=\"username\"\n value={formData.username}\n onChange={handleInputChange}\n placeholder={t('users.usernamePlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n required\n disabled={isSubmitting}\n />\n </div>\n\n <div>\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.email')}\n </label>\n <input\n type=\"email\"\n id=\"email\"\n name=\"email\"\n value={formData.email || ''}\n onChange={handleInputChange}\n placeholder={t('users.emailPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n />\n </div>\n\n <div>\n <label htmlFor=\"password\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.password')} <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"password\"\n id=\"password\"\n name=\"password\"\n value={formData.password}\n onChange={handleInputChange}\n placeholder={t('users.passwordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n required\n disabled={isSubmitting}\n minLength={8}\n />\n <p className=\"mt-1 text-xs text-gray-500\">\n {t('auth.passwordStrengthHint')}\n </p>\n </div>\n\n <div className=\"flex items-center pt-2\">\n <input\n type=\"checkbox\"\n id=\"isAdmin\"\n name=\"isAdmin\"\n checked={formData.isAdmin}\n onChange={handleInputChange}\n className=\"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200\"\n disabled={isSubmitting}\n />\n <label\n htmlFor=\"isAdmin\"\n className=\"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none\"\n >\n {t('users.adminRole')}\n </label>\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-2 mt-6\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"hub-btn\"\n disabled={isSubmitting}\n >\n {t('common.cancel')}\n </button>\n <button\n type=\"submit\"\n className=\"hub-btn primary\"\n disabled={isSubmitting}\n >\n {isSubmitting && (\n <svg\n className=\"animate-spin -ml-1 mr-2 h-4 w-4 text-white\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n )}\n {isSubmitting ? t('common.creating') : t('users.create')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nexport default AddUserForm;\n","import { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useUserData } from '@/hooks/useUserData';\nimport { User, UserUpdateData } from '@/types';\nimport {\n validatePasswordStrength,\n mapBackendPasswordErrors,\n} from '../utils/passwordValidation';\n\ninterface EditUserFormProps {\n user: User;\n onEdit: () => void;\n onCancel: () => void;\n}\n\nconst EditUserForm = ({ user, onEdit, onCancel }: EditUserFormProps) => {\n const { t } = useTranslation();\n const { updateUser } = useUserData();\n const [error, setError] = useState<string | null>(null);\n const [passwordErrors, setPasswordErrors] = useState<string[]>([]);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const [formData, setFormData] = useState({\n isAdmin: user.isAdmin,\n email: user.email || '',\n newPassword: '',\n confirmPassword: '',\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setPasswordErrors([]);\n\n // Validate passwords match if changing password\n if (formData.newPassword && formData.newPassword !== formData.confirmPassword) {\n setError(t('users.passwordMismatch'));\n return;\n }\n\n if (formData.newPassword) {\n const validation = validatePasswordStrength(formData.newPassword);\n if (!validation.isValid) {\n setError(t('auth.passwordStrengthError'));\n setPasswordErrors(validation.errors.map((key) => t(`auth.${key}`)));\n return;\n }\n }\n\n setIsSubmitting(true);\n\n try {\n const updateData: UserUpdateData = {\n isAdmin: formData.isAdmin,\n email: formData.email,\n };\n\n if (formData.newPassword) {\n updateData.newPassword = formData.newPassword;\n }\n\n const result = await updateUser(user.username, updateData);\n if (result?.success) {\n onEdit();\n } else if (result?.errors?.length) {\n setError(result.message || t('auth.passwordStrengthError'));\n setPasswordErrors(mapBackendPasswordErrors(result.errors).map((key) => t(key)));\n } else {\n setError(result?.message || t('users.updateError'));\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('users.updateError'));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target;\n setFormData((prev) => ({\n ...prev,\n [name]: type === 'checkbox' ? checked : value,\n }));\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700\">\n <form onSubmit={handleSubmit}>\n <h2 className=\"text-xl font-bold text-gray-900 mb-6\">\n {t('users.edit')} - <span className=\"text-blue-600\">{user.username}</span>\n </h2>\n\n {error && (\n <div className=\"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md\">\n <p className=\"text-sm font-medium\">{error}</p>\n {passwordErrors.length > 0 && (\n <ul className=\"list-disc list-inside mt-2 space-y-1 text-sm\">\n {passwordErrors.map((message) => (\n <li key={message}>{message}</li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n <div className=\"space-y-5\">\n <div className=\"flex items-center pt-2\">\n <input\n type=\"checkbox\"\n id=\"isAdmin\"\n name=\"isAdmin\"\n checked={formData.isAdmin}\n onChange={handleInputChange}\n className=\"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200\"\n disabled={isSubmitting}\n />\n <label\n htmlFor=\"isAdmin\"\n className=\"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none\"\n >\n {t('users.adminRole')}\n </label>\n </div>\n\n <div>\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.email')}\n </label>\n <input\n type=\"email\"\n id=\"email\"\n name=\"email\"\n value={formData.email}\n onChange={handleInputChange}\n placeholder={t('users.emailPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n />\n </div>\n\n <div className=\"border-t border-gray-100 dark:border-gray-700 pt-4 mt-2\">\n <p className=\"text-xs text-gray-500 uppercase font-semibold tracking-wider mb-3\">\n {t('users.changePassword')}\n </p>\n\n <div className=\"space-y-4\">\n <div>\n <label\n htmlFor=\"newPassword\"\n className=\"block text-sm font-medium text-gray-700 mb-1\"\n >\n {t('users.newPassword')}\n </label>\n <input\n type=\"password\"\n id=\"newPassword\"\n name=\"newPassword\"\n value={formData.newPassword}\n onChange={handleInputChange}\n placeholder={t('users.newPasswordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n minLength={8}\n />\n <p className=\"mt-1 text-xs text-gray-500\">\n {t('auth.passwordStrengthHint')}\n </p>\n </div>\n\n {formData.newPassword && (\n <div className=\"animate-fadeIn\">\n <label\n htmlFor=\"confirmPassword\"\n className=\"block text-sm font-medium text-gray-700 mb-1\"\n >\n {t('users.confirmPassword')}\n </label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n value={formData.confirmPassword}\n onChange={handleInputChange}\n placeholder={t('users.confirmPasswordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n minLength={8}\n />\n </div>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-2 mt-6\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"hub-btn\"\n disabled={isSubmitting}\n >\n {t('common.cancel')}\n </button>\n <button\n type=\"submit\"\n className=\"hub-btn primary\"\n disabled={isSubmitting}\n >\n {isSubmitting && (\n <svg\n className=\"animate-spin -ml-1 mr-2 h-4 w-4 text-white\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n )}\n {isSubmitting ? t('common.updating') : t('users.update')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nexport default EditUserForm;\n","import React, { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { User } from '@/types';\nimport { useUserData } from '@/hooks/useUserData';\nimport { useAuth } from '@/contexts/AuthContext';\nimport AddUserForm from '@/components/AddUserForm';\nimport EditUserForm from '@/components/EditUserForm';\nimport { Edit3, Trash2, User as UserIcon, Plus, AlertCircle, X, RefreshCw } from 'lucide-react';\nimport DeleteDialog from '@/components/ui/DeleteDialog';\nimport { StatusDot } from '@/components/ui/StatusDot';\n\nconst UsersPage: React.FC = () => {\n const { t } = useTranslation();\n const { auth } = useAuth();\n const currentUser = auth.user;\n const {\n users,\n loading: usersLoading,\n error: userError,\n setError: setUserError,\n deleteUser,\n triggerRefresh,\n } = useUserData();\n\n const [editingUser, setEditingUser] = useState<User | null>(null);\n const [showAddForm, setShowAddForm] = useState(false);\n const [userToDelete, setUserToDelete] = useState<string | null>(null);\n\n if (!currentUser?.isAdmin) {\n return (\n <div className=\"hub-card p-6 text-center\" style={{ color: 'var(--hub-err)' }}>\n {t('users.adminRequired')}\n </div>\n );\n }\n\n return (\n <div>\n <div className=\"flex items-end justify-between gap-4 mb-6\">\n <div>\n <h1 className=\"hub-h1\">{t('pages.users.title')}</h1>\n <p className=\"hub-sub\">\n <span className=\"hub-num\">{users.length}</span> {t('nav.users').toLowerCase()}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <button\n className=\"hub-btn\"\n onClick={() => triggerRefresh()}\n aria-label={t('common.refresh')}\n >\n <RefreshCw size={13} /> {t('common.refresh')}\n </button>\n <button className=\"hub-btn primary\" onClick={() => setShowAddForm(true)}>\n <Plus size={13} /> {t('users.add')}\n </button>\n </div>\n </div>\n\n {userError && (\n <div\n className=\"hub-card flex items-center justify-between gap-3 mb-4\"\n style={{\n padding: '10px 14px',\n borderColor: 'oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n }}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n <span className=\"truncate text-[13px]\">{userError}</span>\n </div>\n <button className=\"hub-icon-btn sm\" onClick={() => setUserError(null)}>\n <X size={13} />\n </button>\n </div>\n )}\n\n {usersLoading ? (\n <div className=\"hub-card p-10 text-center\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('app.loading')}\n </div>\n ) : users.length === 0 ? (\n <div className=\"hub-card p-10 text-center\" style={{ color: 'var(--hub-ink-3)' }}>\n <div className=\"flex flex-col items-center gap-3\">\n <div\n className=\"grid place-items-center\"\n style={{\n width: 40,\n height: 40,\n borderRadius: 10,\n border: '1px solid var(--hub-line)',\n background: 'var(--hub-bg-2)',\n }}\n >\n <UserIcon size={18} />\n </div>\n <div className=\"font-medium\" style={{ color: 'var(--hub-ink-2)', fontSize: 13 }}>\n {t('users.noUsers')}\n </div>\n <button\n onClick={() => setShowAddForm(true)}\n className=\"hub-btn ghost sm\"\n style={{ color: 'var(--hub-accent)' }}\n >\n {t('users.addFirst')}\n </button>\n </div>\n </div>\n ) : (\n <div className=\"hub-card overflow-hidden\">\n <div\n className=\"hub-row head hub-mono\"\n style={{ gridTemplateColumns: '1.6fr 1.2fr 100px 100px' }}\n >\n <div>{t('users.username')}</div>\n <div>{t('users.email')}</div>\n <div>{t('users.role')}</div>\n <div className=\"text-right\">{t('users.actions')}</div>\n </div>\n {users.map((user) => {\n const isCurrentUser = currentUser?.username === user.username;\n return (\n <div\n key={user.username}\n className=\"hub-row hover\"\n style={{ gridTemplateColumns: '1.6fr 1.2fr 100px 100px' }}\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div\n className=\"grid place-items-center flex-shrink-0 hub-mono\"\n style={{\n width: 28,\n height: 28,\n borderRadius: 7,\n background: 'var(--hub-bg-2)',\n border: '1px solid var(--hub-line)',\n color: 'var(--hub-ink-2)',\n fontWeight: 600,\n fontSize: 12,\n }}\n >\n {user.username.charAt(0).toUpperCase()}\n </div>\n <span\n className=\"hub-mono truncate\"\n style={{ fontSize: 13, color: 'var(--hub-ink)' }}\n >\n {user.username}\n </span>\n {isCurrentUser && (\n <span className=\"hub-tag accent\" style={{ fontSize: 10 }}>\n {t('users.currentUser')}\n </span>\n )}\n </div>\n <div className=\"flex items-center min-w-0\">\n <span\n className=\"truncate\"\n style={{ fontSize: 13, color: user.email ? 'var(--hub-ink)' : 'var(--hub-ink-3)' }}\n >\n {user.email || '—'}\n </span>\n </div>\n <div>\n <StatusDot\n kind={user.isAdmin ? 'ok' : 'muted'}\n label={user.isAdmin ? t('users.admin') : t('users.user')}\n />\n </div>\n <div className=\"flex justify-end gap-1\">\n <button\n onClick={() => setEditingUser(user)}\n className=\"hub-icon-btn sm\"\n title={t('users.edit')}\n >\n <Edit3 size={13} />\n </button>\n {!isCurrentUser && (\n <button\n onClick={() => setUserToDelete(user.username)}\n className=\"hub-icon-btn sm\"\n title={t('users.delete')}\n style={{ color: 'var(--hub-err)' }}\n >\n <Trash2 size={13} />\n </button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {showAddForm && (\n <AddUserForm\n onAdd={() => {\n setShowAddForm(false);\n triggerRefresh();\n }}\n onCancel={() => setShowAddForm(false)}\n />\n )}\n\n {editingUser && (\n <EditUserForm\n user={editingUser}\n onEdit={() => {\n setEditingUser(null);\n triggerRefresh();\n }}\n onCancel={() => setEditingUser(null)}\n />\n )}\n\n <DeleteDialog\n isOpen={!!userToDelete}\n onClose={() => setUserToDelete(null)}\n onConfirm={async () => {\n if (userToDelete) {\n const result = await deleteUser(userToDelete);\n if (!result?.success) {\n setUserError(result?.message || t('users.deleteError'));\n }\n setUserToDelete(null);\n }\n }}\n serverName={userToDelete || ''}\n isGroup={false}\n isUser={true}\n />\n </div>\n );\n};\n\nexport default UsersPage;\n"],"names":["useUserData","useTranslation","users","setUsers","useState","loading","setLoading","error","setError","refreshKey","setRefreshKey","fetchUsers","useCallback","data","apiGet","err","triggerRefresh","prev","createUser","userData","result","apiPost","updateUser","username","apiPut","deleteUser","apiDelete","useEffect","AddUserForm","onAdd","onCancel","t","passwordErrors","setPasswordErrors","isSubmitting","setIsSubmitting","formData","setFormData","handleSubmit","e","validation","validatePasswordStrength","key","_a","mapBackendPasswordErrors","handleInputChange","name","value","type","checked","jsx","jsxs","message","EditUserForm","user","onEdit","updateData","UsersPage","auth","useAuth","currentUser","usersLoading","userError","setUserError","editingUser","setEditingUser","showAddForm","setShowAddForm","userToDelete","setUserToDelete","RefreshCw","Plus","AlertCircle","X","UserIcon","isCurrentUser","StatusDot","Edit3","Trash2","DeleteDialog"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function n(t){return t<1e3?String(t):`${(t/1e3).toFixed(1)}k`}function o(t,r){if(t<=0)return 0;const e=Math.round((t-r)/t*100);return Math.max(0,Math.min(100,e))}const a=1e5;function u(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(1)} MB`}export{a as O,u as a,n as f,o as p};
|
|
2
|
+
//# sourceMappingURL=contextCost-CilWqGWT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextCost-CilWqGWT.js","sources":["../../src/utils/contextCost.ts"],"sourcesContent":["/** Display helpers for the Context Footprint feature. */\n\n/** Compact token formatting: 940 -> \"940\", 4200 -> \"4.2k\". */\nexport function formatTokens(n: number): string {\n if (n < 1000) return String(n);\n return `${(n / 1000).toFixed(1)}k`;\n}\n\n/** Integer percent reduction from `direct` to `smart`, clamped to [0, 100]. */\nexport function percentSaved(direct: number, smart: number): number {\n if (direct <= 0) return 0;\n const pct = Math.round(((direct - smart) / direct) * 100);\n return Math.max(0, Math.min(100, pct));\n}\n\n/**\n * Threshold above which an OpenAPI import preview warns that the generated\n * tool list may not fit a model's context window (#1082). ~100k tokens of\n * tool definitions leaves little room in common 128k–200k windows once the\n * system prompt and conversation are counted.\n */\nexport const OPENAPI_STATS_WARN_TOKENS = 100_000;\n\n/** Human-readable byte size: 366457 -> \"357.9 KB\". */\nexport function formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n return `${(n / (1024 * 1024)).toFixed(1)} MB`;\n}\n"],"names":["formatTokens","n","percentSaved","direct","smart","pct","OPENAPI_STATS_WARN_TOKENS","formatBytes"],"mappings":"AAGO,SAASA,EAAaC,EAAmB,CAC9C,OAAIA,EAAI,IAAa,OAAOA,CAAC,EACtB,IAAIA,EAAI,KAAM,QAAQ,CAAC,CAAC,GACjC,CAGO,SAASC,EAAaC,EAAgBC,EAAuB,CAClE,GAAID,GAAU,EAAG,MAAO,GACxB,MAAME,EAAM,KAAK,OAAQF,EAASC,GAASD,EAAU,GAAG,EACxD,OAAO,KAAK,IAAI,EAAG,KAAK,IAAI,IAAKE,CAAG,CAAC,CACvC,CAQO,MAAMC,EAA4B,IAGlC,SAASC,EAAYN,EAAmB,CAC7C,OAAIA,EAAI,KAAa,GAAGA,CAAC,KACrBA,EAAI,KAAO,KAAa,IAAIA,EAAI,MAAM,QAAQ,CAAC,CAAC,MAC7C,IAAIA,GAAK,KAAO,OAAO,QAAQ,CAAC,CAAC,KAC1C"}
|