@jheavenknows/bluerouter 2.0.10 → 2.0.12
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/app/.next-cli-build/BUILD_ID +1 -1
- package/app/.next-cli-build/app-path-routes-manifest.json +7 -7
- package/app/.next-cli-build/build-manifest.json +3 -3
- package/app/.next-cli-build/prerender-manifest.json +3 -3
- package/app/.next-cli-build/required-server-files.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/analytics/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/analytics/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/api-keys/page.js +3 -3
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/api-keys/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/prompt-logs/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/prompt-logs/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/provider-health/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/provider-health/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/skills/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/skills/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page.js +1 -1
- package/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/_global-error.html +1 -1
- package/app/.next-cli-build/server/app/_global-error.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_not-found/page.js +1 -1
- package/app/.next-cli-build/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/_not-found.html +1 -1
- package/app/.next-cli-build/server/app/_not-found.rsc +3 -3
- package/app/.next-cli-build/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/api/auth/ldap/test/route.js +1 -1
- package/app/.next-cli-build/server/app/api/auth/ldap/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/ldap/users/route.js +1 -1
- package/app/.next-cli-build/server/app/api/auth/ldap/users/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/login/route.js +3 -3
- package/app/.next-cli-build/server/app/api/auth/login/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/callback/route.js +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/callback/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/start/route.js +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/start/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/test/route.js +1 -1
- package/app/.next-cli-build/server/app/api/auth/oidc/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/auth/status/route.js +1 -1
- package/app/.next-cli-build/server/app/api/auth/status/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js +4 -4
- package/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/alias/route.js +2 -2
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/alias/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/autostart/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/autostart/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/prompt-log-db/route.js +2 -2
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/prompt-log-db/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/root-ca/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/claude-settings/route.js +2 -2
- package/app/.next-cli-build/server/app/api/cli-tools/cline-settings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/codex-settings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/copilot-settings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/copilot-settings/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-registry/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-tools/route.js +2 -2
- package/app/.next-cli-build/server/app/api/cli-tools/cowork-settings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/cowork-settings/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/deepseek-tui-settings/route.js +2 -2
- package/app/.next-cli-build/server/app/api/cli-tools/droid-settings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/hermes-settings/route.js +3 -3
- package/app/.next-cli-build/server/app/api/cli-tools/jcode-settings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/cli-tools/kilo-settings/route.js +2 -2
- package/app/.next-cli-build/server/app/api/cli-tools/openclaw-settings/route.js +2 -2
- package/app/.next-cli-build/server/app/api/cli-tools/opencode-settings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/combos/[id]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/combos/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/combos/route.js +1 -1
- package/app/.next-cli-build/server/app/api/combos/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/analytics/route.js +65 -34
- package/app/.next-cli-build/server/app/api/dashboard/analytics/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/combos/route.js +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/combos/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/endpoint/route.js +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/endpoint/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/[id]/route.js +2 -2
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/options/route.js +2 -2
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/options/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/route.js +2 -2
- package/app/.next-cli-build/server/app/api/dashboard/prompt-logs/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/keys/[id]/rotate/route.js +1 -1
- package/app/.next-cli-build/server/app/api/keys/[id]/rotate/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/keys/[id]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/keys/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/keys/route.js +2 -2
- package/app/.next-cli-build/server/app/api/keys/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/mcp/[plugin]/message/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/mcp/[plugin]/sse/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/deepgram/voices/route.js +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/deepgram/voices/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/elevenlabs/voices/route.js +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/elevenlabs/voices/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/inworld/voices/route.js +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/inworld/voices/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/minimax/voices/route.js +1 -1
- package/app/.next-cli-build/server/app/api/media-providers/tts/minimax/voices/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/alias/route.js +1 -1
- package/app/.next-cli-build/server/app/api/models/alias/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/availability/route.js +1 -1
- package/app/.next-cli-build/server/app/api/models/availability/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/custom/route.js +1 -1
- package/app/.next-cli-build/server/app/api/models/custom/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/disabled/route.js +1 -1
- package/app/.next-cli-build/server/app/api/models/disabled/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/route.js +1 -1
- package/app/.next-cli-build/server/app/api/models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/models/test/route.js +1 -1
- package/app/.next-cli-build/server/app/api/models/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/[provider]/[action]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/oauth/[provider]/[action]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/codex/import-token/route.js +1 -1
- package/app/.next-cli-build/server/app/api/oauth/codex/import-token/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/cursor/auto-import/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/cursor/import/route.js +1 -1
- package/app/.next-cli-build/server/app/api/oauth/cursor/import/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/gitlab/pat/route.js +1 -1
- package/app/.next-cli-build/server/app/api/oauth/gitlab/pat/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/iflow/cookie/route.js +1 -1
- package/app/.next-cli-build/server/app/api/oauth/iflow/cookie/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/kiro/import/route.js +1 -1
- package/app/.next-cli-build/server/app/api/oauth/kiro/import/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/oauth/kiro/social-exchange/route.js +1 -1
- package/app/.next-cli-build/server/app/api/oauth/kiro/social-exchange/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/pricing/route.js +1 -1
- package/app/.next-cli-build/server/app/api/pricing/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/provider-health/route.js +1 -1
- package/app/.next-cli-build/server/app/api/provider-health/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/provider-nodes/[id]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/provider-nodes/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/provider-nodes/route.js +1 -1
- package/app/.next-cli-build/server/app/api/provider-nodes/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/models/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/test/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/client/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/client/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/test-batch/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/test-batch/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/providers/validate/route.js +1 -1
- package/app/.next-cli-build/server/app/api/providers/validate/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/[id]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/[id]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/[id]/test/route.js +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/[id]/test/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/cloudflare-deploy/route.js +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/cloudflare-deploy/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/deno-deploy/route.js +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/deno-deploy/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/route.js +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/vercel-deploy/route.js +1 -1
- package/app/.next-cli-build/server/app/api/proxy-pools/vercel-deploy/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/settings/database/route.js +1 -1
- package/app/.next-cli-build/server/app/api/settings/database/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/settings/proxy-test/route.js +1 -1
- package/app/.next-cli-build/server/app/api/settings/require-login/route.js +1 -1
- package/app/.next-cli-build/server/app/api/settings/require-login/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/settings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/settings/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/translator/console-logs/route.js +1 -1
- package/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js +1 -1
- package/app/.next-cli-build/server/app/api/translator/send/route.js +1 -1
- package/app/.next-cli-build/server/app/api/translator/send/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/translator/translate/route.js +1 -1
- package/app/.next-cli-build/server/app/api/translator/translate/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/disable/route.js +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/disable/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/enable/route.js +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/enable/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/status/route.js +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/status/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-check/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-disable/route.js +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-disable/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-enable/route.js +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-enable/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-install/route.js +2 -2
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-install/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-login/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-start-daemon/route.js +1 -1
- package/app/.next-cli-build/server/app/api/tunnel/tailscale-start-daemon/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/[connectionId]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/[connectionId]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/chart/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/chart/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/history/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/history/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/providers/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/providers/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/request-details/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/request-details/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/request-logs/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/request-logs/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/stats/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/stats/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/usage/stream/route.js +1 -1
- package/app/.next-cli-build/server/app/api/usage/stream/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/api/chat/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/api/chat/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/audio/speech/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/audio/speech/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/audio/transcriptions/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/audio/transcriptions/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/chat/completions/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/chat/completions/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/embeddings/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/embeddings/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/images/generations/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/images/generations/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/messages/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/messages/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/models/[kind]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/models/[kind]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/models/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/responses/compact/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/responses/compact/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/responses/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/responses/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/search/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/search/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1/web/fetch/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1/web/fetch/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1beta/models/[...path]/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1beta/models/[...path]/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/v1beta/models/route.js +1 -1
- package/app/.next-cli-build/server/app/api/v1beta/models/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/version/route.js +1 -1
- package/app/.next-cli-build/server/app/api/version/shutdown/route.js +1 -1
- package/app/.next-cli-build/server/app/api/version/shutdown/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/api/version/update/route.js +1 -1
- package/app/.next-cli-build/server/app/api/version/update/route.js.nft.json +1 -1
- package/app/.next-cli-build/server/app/callback/page.js +1 -1
- package/app/.next-cli-build/server/app/callback/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/callback.html +1 -1
- package/app/.next-cli-build/server/app/callback.rsc +3 -3
- package/app/.next-cli-build/server/app/callback.segments/_full.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/callback.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/callback.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/callback.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/callback.segments/callback.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/analytics.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/analytics.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/analytics.segments/!KGRhc2hib2FyZCk/dashboard/analytics/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/analytics.segments/!KGRhc2hib2FyZCk/dashboard/analytics.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/analytics.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/analytics.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/analytics.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/analytics.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/analytics.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/analytics.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/api-keys.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/api-keys.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/!KGRhc2hib2FyZCk/dashboard/api-keys/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/!KGRhc2hib2FyZCk/dashboard/api-keys.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/api-keys.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/basic-chat.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/basic-chat.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/combos.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/combos.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/endpoint.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/endpoint.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/mitm.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/mitm.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/profile.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/profile.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.rsc +4 -4
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/!KGRhc2hib2FyZCk/dashboard/prompt-logs/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/!KGRhc2hib2FyZCk/dashboard/prompt-logs.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/_full.segment.rsc +4 -4
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/prompt-logs.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/provider-health.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/provider-health.rsc +4 -4
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/!KGRhc2hib2FyZCk/dashboard/provider-health/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/!KGRhc2hib2FyZCk/dashboard/provider-health.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/_full.segment.rsc +4 -4
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/provider-health.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/new.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/new.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/quota.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/quota.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/quota.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing/page.js +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/skills.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/skills.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard/skills/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard/skills.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/skills.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/skills.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/skills.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/skills.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/translator.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/translator.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/usage.html +1 -1
- package/app/.next-cli-build/server/app/dashboard/usage.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
- package/app/.next-cli-build/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard.html +1 -1
- package/app/.next-cli-build/server/app/dashboard.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next-cli-build/server/app/dashboard.segments/_full.segment.rsc +6 -6
- package/app/.next-cli-build/server/app/dashboard.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/dashboard.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/dashboard.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/index.html +1 -1
- package/app/.next-cli-build/server/app/index.rsc +3 -3
- package/app/.next-cli-build/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/index.segments/_full.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/index.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/index.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/index.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/landing/page.js +1 -1
- package/app/.next-cli-build/server/app/landing/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/landing.html +1 -1
- package/app/.next-cli-build/server/app/landing.rsc +3 -3
- package/app/.next-cli-build/server/app/landing.segments/_full.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/landing.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/landing.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/landing.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/landing.segments/landing/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/landing.segments/landing.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/login/page.js +1 -1
- package/app/.next-cli-build/server/app/login/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app/login.html +1 -1
- package/app/.next-cli-build/server/app/login.rsc +3 -3
- package/app/.next-cli-build/server/app/login.segments/_full.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/login.segments/_head.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/login.segments/_index.segment.rsc +3 -3
- package/app/.next-cli-build/server/app/login.segments/_tree.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/login.segments/login.segment.rsc +1 -1
- package/app/.next-cli-build/server/app/page.js +1 -1
- package/app/.next-cli-build/server/app/page_client-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/app-paths-manifest.json +7 -7
- package/app/.next-cli-build/server/chunks/1336.js +1 -1
- package/app/.next-cli-build/server/chunks/3110.js +1 -1
- package/app/.next-cli-build/server/chunks/4746.js +1 -1
- package/app/.next-cli-build/server/chunks/4803.js +1 -1
- package/app/.next-cli-build/server/chunks/5087.js +6 -6
- package/app/.next-cli-build/server/chunks/5742.js +1 -1
- package/app/.next-cli-build/server/chunks/5901.js +5 -5
- package/app/.next-cli-build/server/chunks/6604.js +2 -2
- package/app/.next-cli-build/server/chunks/6663.js +1 -1
- package/app/.next-cli-build/server/chunks/7130.js +1 -1
- package/app/.next-cli-build/server/chunks/7153.js +1 -1
- package/app/.next-cli-build/server/chunks/7774.js +2 -2
- package/app/.next-cli-build/server/chunks/7795.js +2 -2
- package/app/.next-cli-build/server/chunks/7812.js +1 -1
- package/app/.next-cli-build/server/chunks/7965.js +1 -1
- package/app/.next-cli-build/server/chunks/8520.js +1 -1
- package/app/.next-cli-build/server/instrumentation.js +1 -1
- package/app/.next-cli-build/server/middleware-build-manifest.js +1 -1
- package/app/.next-cli-build/server/middleware.js +3 -3
- package/app/.next-cli-build/server/pages/404.html +1 -1
- package/app/.next-cli-build/server/pages/500.html +1 -1
- package/app/.next-cli-build/server/server-reference-manifest.js +1 -1
- package/app/.next-cli-build/server/server-reference-manifest.json +1 -1
- package/app/.next-cli-build/static/chunks/{1321-1f4ff214c801cf92.js → 1321-1eb30b95160ff9ac.js} +1 -1
- package/app/.next-cli-build/static/chunks/{3794-cef5038dc7aa126a.js → 3794-e569667691edc8f7.js} +1 -1
- package/app/.next-cli-build/static/chunks/5497-c995aab658f44c45.js +7 -0
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/analytics/page-a6702121748c2962.js +1 -0
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/api-keys/{page-07cd63714f309a7b.js → page-fd7ce7daf54db2e8.js} +3 -3
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/profile/page-aaec4486b982a13a.js +1 -0
- package/app/.next-cli-build/static/chunks/{main-80a34745801ef1a2.js → main-eb1b86e4183e86c5.js} +1 -1
- package/app/cli/.build-home/AppData/Roaming/bluerouter/db/data.sqlite-shm +0 -0
- package/app/cli/.build-home/AppData/Roaming/bluerouter/db/data.sqlite-wal +0 -0
- package/app/cli/.build-home/AppData/Roaming/bluerouter/jwt-secret +1 -1
- package/app/cli/.build-home/AppData/Roaming/bluerouter/machine-id +1 -1
- package/app/cli/.build-home/AppData/Roaming/nextjs-nodejs/Config/config.json +3 -3
- package/app/node_modules/@next/env/package.json +2 -2
- package/app/node_modules/baseline-browser-mapping/dist/index.cjs +1 -1
- package/app/node_modules/baseline-browser-mapping/package.json +1 -1
- package/app/node_modules/next/dist/build/swc/index.js +1 -1
- package/app/node_modules/next/dist/build/webpack-config.js +3 -3
- package/app/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +1 -1
- package/app/node_modules/next/dist/compiled/next-server/pages.runtime.prod.js +1 -1
- package/app/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/app/node_modules/next/dist/server/config.js +1 -1
- package/app/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/app/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/app/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/app/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/app/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
- package/app/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/app/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/app/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/app/node_modules/next/package.json +15 -15
- package/app/package.json +1 -1
- package/app/server.js +1 -1
- package/package.json +1 -1
- package/app/.next-cli-build/static/chunks/5497-b46e6c8b6b86176e.js +0 -7
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/analytics/page-7fe4d6bafdbceb0a.js +0 -1
- package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/profile/page-0c206714b76b0dd2.js +0 -1
- /package/app/.next-cli-build/static/{LET3IDrPitPOeavSGayl2 → sZzj1qMoS46-peH1yhf6k}/_buildManifest.js +0 -0
- /package/app/.next-cli-build/static/{LET3IDrPitPOeavSGayl2 → sZzj1qMoS46-peH1yhf6k}/_ssgManifest.js +0 -0
- /package/app/cli/.build-home/AppData/Roaming/bluerouter/db/backups/{upgrade-2.0.5-to-2.0.6-2.0.6-20260610-224649 → upgrade-1.0.134-to-1.0.135-1.0.135-20260610-122700}/data.sqlite +0 -0
- /package/app/cli/.build-home/AppData/Roaming/bluerouter/db/backups/{upgrade-2.0.6-to-2.0.7-2.0.7-20260610-230913 → upgrade-1.0.135-to-2.0.1-2.0.1-20260610-123810}/data.sqlite +0 -0
- /package/app/cli/.build-home/AppData/Roaming/bluerouter/db/backups/{upgrade-2.0.7-to-2.0.8-2.0.8-20260610-233557 → upgrade-2.0.1-to-2.0.2-2.0.2-20260610-134032}/data.sqlite +0 -0
- /package/app/cli/.build-home/AppData/Roaming/bluerouter/db/backups/{upgrade-2.0.8-to-2.0.9-2.0.9-20260610-235420 → upgrade-2.0.11-to-2.0.12-2.0.12-20260611-174316}/data.sqlite +0 -0
- /package/app/cli/.build-home/AppData/Roaming/bluerouter/db/backups/{upgrade-2.0.9-to-2.0.10-2.0.10-20260611-000353 → upgrade-2.0.2-to-2.0.11-2.0.11-20260611-115523}/data.sqlite +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8978],{39944:(e,t,s)=>{Promise.resolve().then(s.bind(s,70959))},70959:(e,t,s)=>{"use strict";s.d(t,{default:()=>F});var r=s(95155),l=s(12115);let n=[{value:"today",label:"H\xf4m nay"},{value:"24h",label:"24 giờ"},{value:"7d",label:"7 ng\xe0y"},{value:"30d",label:"30 ng\xe0y"},{value:"60d",label:"60 ng\xe0y"},{value:"all",label:"Tất cả"},{value:"custom",label:"T\xf9y chọn"}],a=[{value:"overview",label:"Tổng quan",icon:"dashboard"},{value:"apiKeys",label:"API keys",icon:"vpn_key"},{value:"sources",label:"Source IP / Tool",icon:"hub"},{value:"providers",label:"Provider / Model",icon:"dns"},{value:"errors",label:"Lỗi & bất thường",icon:"warning"},{value:"raw",label:"Raw usage",icon:"table"}];function o(e,t=0){return Number(e||0).toLocaleString("vi-VN",{maximumFractionDigits:t})}function i(e){let t=Number(e||0);return Intl.NumberFormat("vi-VN",{notation:"compact",maximumFractionDigits:1}).format(t)}function d(e){let t=100*Number(e||0);return`${t.toLocaleString("vi-VN",{maximumFractionDigits:1})}%`}function c(e){let t=Number(e||0);return t?`$${t.toLocaleString("vi-VN",{minimumFractionDigits:4,maximumFractionDigits:6})}`:"$0"}function x(e){if(null==e||Number.isNaN(Number(e)))return"-";let t=Number(e);return t>=1e3?`${(t/1e3).toLocaleString("vi-VN",{maximumFractionDigits:2})}s`:`${t.toLocaleString("vi-VN",{maximumFractionDigits:0})}ms`}function m(e){if(!e)return"-";try{let t=new Date(e);if(Number.isNaN(t.getTime()))return String(e);return t.toLocaleString("vi-VN",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})}catch{return String(e)}}function u(e){if(!e)return"";try{let t=new Date(e);if(Number.isNaN(t.getTime()))return String(e);return t.toLocaleString("vi-VN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1})}catch{return String(e)}}function p(...e){return e.filter(Boolean).join(" ")}function h(e,t={}){let s=new URLSearchParams;return Object.entries({...e,...t}).forEach(([e,t])=>{let r=String(t??"").trim();r&&s.set(e,r)}),s.toString()}function b({children:e,className:t=""}){return(0,r.jsx)("div",{className:p("rounded-2xl border border-border bg-surface p-5 shadow-sm",t),children:e})}function j({icon:e,label:t,value:s,hint:l,tone:n="blue"}){return(0,r.jsx)(b,{className:"min-h-[126px]",children:(0,r.jsxs)("div",{className:"flex items-start justify-between gap-3",children:[(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{className:"text-sm font-medium text-text-muted",children:t}),(0,r.jsx)("div",{className:"mt-2 text-2xl font-semibold text-text-main",children:s}),l?(0,r.jsx)("div",{className:"mt-2 text-xs text-text-muted",children:l}):null]}),(0,r.jsx)("div",{className:p("flex h-10 w-10 items-center justify-center rounded-xl",{blue:"bg-blue-500/10 text-blue-600 dark:text-blue-300",green:"bg-green-500/10 text-green-600 dark:text-green-300",red:"bg-red-500/10 text-red-600 dark:text-red-300",amber:"bg-amber-500/10 text-amber-600 dark:text-amber-300",purple:"bg-purple-500/10 text-purple-600 dark:text-purple-300",slate:"bg-slate-500/10 text-slate-600 dark:text-slate-300"}[n]||"bg-blue-500/10 text-blue-600 dark:text-blue-300"),children:(0,r.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:e})})]})})}function g({label:e,children:t}){return(0,r.jsxs)("label",{className:"space-y-1.5 text-xs font-medium text-text-muted",children:[(0,r.jsx)("span",{children:e}),t]})}function v({value:e,onChange:t,children:s}){return(0,r.jsx)("select",{value:e||"",onChange:e=>t(e.target.value),className:"h-10 w-full rounded-xl border border-border bg-background px-3 text-sm text-text-main outline-none transition focus:border-primary/60 focus:ring-2 focus:ring-primary/20",children:s})}function y({value:e,onChange:t,placeholder:s="",type:l="text"}){return(0,r.jsx)("input",{value:e||"",type:l,onChange:e=>t(e.target.value),placeholder:s,className:"h-10 w-full rounded-xl border border-border bg-background px-3 text-sm text-text-main outline-none transition placeholder:text-text-muted/60 focus:border-primary/60 focus:ring-2 focus:ring-primary/20"})}function k(){return(0,r.jsxs)("div",{className:"space-y-4",children:[(0,r.jsx)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-4",children:Array.from({length:8}).map((e,t)=>(0,r.jsx)("div",{className:"h-32 animate-pulse rounded-2xl border border-border bg-surface"},t))}),(0,r.jsx)("div",{className:"h-80 animate-pulse rounded-2xl border border-border bg-surface"})]})}function f({title:e="Kh\xf4ng c\xf3 dữ liệu",description:t="Kh\xf4ng t\xecm thấy dữ liệu theo bộ lọc hiện tại."}){return(0,r.jsxs)("div",{className:"flex min-h-[180px] flex-col items-center justify-center rounded-2xl border border-dashed border-border bg-surface/60 p-8 text-center",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-4xl text-text-muted",children:"database_off"}),(0,r.jsx)("div",{className:"mt-3 text-sm font-semibold text-text-main",children:e}),(0,r.jsx)("div",{className:"mt-1 max-w-xl text-sm text-text-muted",children:t})]})}function N({data:e=[],valueKey:t="totalTokens",secondaryKey:s="requests",height:l=220}){let n=e||[],a=Math.max(...n.map(e=>Number(e[t]||0)),1),i=Math.max(...n.map(e=>Number(e[s]||0)),1);return 0===n.length?(0,r.jsx)(f,{description:"Chưa c\xf3 time-series trong khoảng thời gian n\xe0y."}):(0,r.jsx)("div",{className:"overflow-x-auto",children:(0,r.jsxs)("div",{className:"min-w-[720px]",children:[(0,r.jsx)("div",{className:"flex items-end gap-1",style:{height:l},children:n.map((e,n)=>{let d=Math.max(2,Number(e[t]||0)/a*(l-42)),c=Math.max(2,Number(e[s]||0)/i*(l-42));return(0,r.jsx)("div",{className:"group flex flex-1 flex-col items-center justify-end gap-1",children:(0,r.jsxs)("div",{className:"relative flex h-full w-full max-w-[34px] items-end justify-center gap-0.5",children:[(0,r.jsx)("div",{className:"w-2 rounded-t bg-primary/70",style:{height:d}}),(0,r.jsx)("div",{className:"w-2 rounded-t bg-amber-500/70",style:{height:c}}),(0,r.jsxs)("div",{className:"pointer-events-none absolute bottom-full left-1/2 z-20 hidden w-56 -translate-x-1/2 rounded-xl border border-border bg-surface p-3 text-left text-xs shadow-xl group-hover:block",children:[(0,r.jsx)("div",{className:"font-semibold text-text-main",children:u(e.label)}),(0,r.jsxs)("div",{className:"mt-1 text-text-muted",children:["Request: ",o(e.requests)]}),(0,r.jsxs)("div",{className:"text-text-muted",children:["Input token: ",o(e.promptTokens)]}),(0,r.jsxs)("div",{className:"text-text-muted",children:["Output token: ",o(e.completionTokens)]}),(0,r.jsxs)("div",{className:"text-text-muted",children:["Tổng token: ",o(e.totalTokens)]}),(0,r.jsxs)("div",{className:"text-text-muted",children:["Lỗi: ",o(e.errors)]})]})]})},`${e.label}-${n}`)})}),(0,r.jsxs)("div",{className:"mt-3 flex justify-between gap-2 text-[11px] text-text-muted",children:[(0,r.jsx)("span",{children:u(n[0]?.label)}),(0,r.jsx)("span",{children:u(n[Math.floor(n.length/2)]?.label)}),(0,r.jsx)("span",{children:u(n[n.length-1]?.label)})]})]})})}function w(){return(0,r.jsxs)("div",{className:"flex flex-wrap gap-3 text-xs text-text-muted",children:[(0,r.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,r.jsx)("span",{className:"h-2.5 w-2.5 rounded-sm bg-primary/70"}),"Token"]}),(0,r.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,r.jsx)("span",{className:"h-2.5 w-2.5 rounded-sm bg-amber-500/70"}),"Request"]})]})}function T({columns:e,rows:t,empty:s="Kh\xf4ng c\xf3 dữ liệu"}){return t&&0!==t.length?(0,r.jsx)("div",{className:"overflow-x-auto rounded-2xl border border-border",children:(0,r.jsxs)("table",{className:"min-w-full divide-y divide-border text-sm",children:[(0,r.jsx)("thead",{className:"bg-background/70",children:(0,r.jsx)("tr",{children:e.map(e=>(0,r.jsx)("th",{className:p("whitespace-nowrap px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-text-muted",e.className),children:e.label},e.key))})}),(0,r.jsx)("tbody",{className:"divide-y divide-border bg-surface",children:t.map((t,s)=>(0,r.jsx)("tr",{className:"hover:bg-background/60",children:e.map(e=>(0,r.jsx)("td",{className:p("whitespace-nowrap px-4 py-3 align-top text-text-main",e.className),children:e.render?e.render(t,s):t[e.key]??"-"},e.key))},t.key||t.id||`${t.label}-${s}`))})]})}):(0,r.jsx)(f,{title:s})}function S({items:e=[]}){return e&&0!==e.length?(0,r.jsx)("div",{className:"flex max-w-[360px] flex-wrap gap-1.5",children:e.slice(0,3).map(e=>(0,r.jsxs)("span",{className:"rounded-full bg-primary/10 px-2 py-0.5 text-xs text-primary",children:[e.label||e.key," \xb7 ",o(e.count)]},e.key))}):(0,r.jsx)("span",{className:"text-text-muted",children:"-"})}function q({row:e}){return(0,r.jsxs)("div",{className:"space-y-1 text-xs",children:[(0,r.jsxs)("div",{className:"font-semibold text-text-main",children:[i(e.totalTokens)," token"]}),(0,r.jsxs)("div",{className:"text-text-muted",children:["In ",i(e.promptTokens)," / Out ",i(e.completionTokens)]})]})}function I({value:e}){let t=Number(e||0);return(0,r.jsx)("span",{className:p("rounded-full px-2 py-1 text-xs font-semibold",t>=.2?"bg-red-500/10 text-red-600 dark:text-red-300":t>=.05?"bg-amber-500/10 text-amber-600 dark:text-amber-300":"bg-green-500/10 text-green-600 dark:text-green-300"),children:d(t)})}function P({anomaly:e}){let t="danger"===e.level?"border-red-500/30 bg-red-500/10 text-red-700 dark:text-red-300":"border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300",s="danger"===e.level?"error":"warning";return(0,r.jsx)("div",{className:p("rounded-2xl border p-4",t),children:(0,r.jsxs)("div",{className:"flex gap-3",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[22px]",children:s}),(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{className:"font-semibold",children:e.title}),(0,r.jsx)("div",{className:"mt-1 text-sm opacity-90",children:e.detail})]})]})})}function L({notes:e=[]}){return e.length?(0,r.jsx)("div",{className:"space-y-2 rounded-2xl border border-blue-500/20 bg-blue-500/10 p-4 text-sm text-blue-700 dark:text-blue-300",children:e.map((e,t)=>(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[18px]",children:"info"}),(0,r.jsx)("span",{children:e})]},t))}):null}function R({filters:e,setFilters:t,options:s,onRefresh:l,onExportCsv:a,loading:o}){let i=(e,s)=>t(t=>({...t,[e]:s}));return(0,r.jsxs)(b,{children:[(0,r.jsxs)("div",{className:"grid gap-3 md:grid-cols-2 xl:grid-cols-6",children:[(0,r.jsx)(g,{label:"Khoảng thời gian",children:(0,r.jsx)(v,{value:e.period,onChange:e=>i("period",e),children:n.map(e=>(0,r.jsx)("option",{value:e.value,children:e.label},e.value))})}),(0,r.jsx)(g,{label:"Từ ng\xe0y",children:(0,r.jsx)(y,{type:"datetime-local",value:e.dateFrom,onChange:e=>i("dateFrom",e)})}),(0,r.jsx)(g,{label:"Đến ng\xe0y",children:(0,r.jsx)(y,{type:"datetime-local",value:e.dateTo,onChange:e=>i("dateTo",e)})}),(0,r.jsx)(g,{label:"Provider",children:(0,r.jsxs)(v,{value:e.provider,onChange:e=>i("provider",e),children:[(0,r.jsx)("option",{value:"",children:"Tất cả provider"}),(s.providers||[]).map(e=>{let t="string"==typeof e?e:e.value,s="string"==typeof e?e:e.label||e.value;return(0,r.jsx)("option",{value:t,children:s},t)})]})}),(0,r.jsx)(g,{label:"Model",children:(0,r.jsxs)(v,{value:e.model,onChange:e=>i("model",e),children:[(0,r.jsx)("option",{value:"",children:"Tất cả model"}),(s.models||[]).map(e=>(0,r.jsx)("option",{value:e,children:e},e))]})}),(0,r.jsx)(g,{label:"Provider account",children:(0,r.jsxs)(v,{value:e.connectionId,onChange:e=>i("connectionId",e),children:[(0,r.jsx)("option",{value:"",children:"Tất cả account"}),(s.connections||[]).map(e=>(0,r.jsx)("option",{value:e.value,children:e.label},e.value))]})}),(0,r.jsx)(g,{label:"API key",children:(0,r.jsxs)(v,{value:e.apiKey,onChange:e=>i("apiKey",e),children:[(0,r.jsx)("option",{value:"",children:"Tất cả API key"}),(s.apiKeys||[]).map(e=>(0,r.jsx)("option",{value:e.value,children:e.label},e.value))]})}),(0,r.jsx)(g,{label:"Source IP",children:(0,r.jsx)(y,{value:e.clientIp,onChange:e=>i("clientIp",e),placeholder:"172.16.253.1"})}),(0,r.jsx)(g,{label:"Source tool",children:(0,r.jsx)(y,{value:e.sourceTool,onChange:e=>i("sourceTool",e),placeholder:"copilot, antigravity..."})}),(0,r.jsx)(g,{label:"Endpoint",children:(0,r.jsxs)(v,{value:e.endpoint,onChange:e=>i("endpoint",e),children:[(0,r.jsx)("option",{value:"",children:"Tất cả endpoint"}),(s.endpoints||[]).map(e=>(0,r.jsx)("option",{value:e,children:e},e))]})}),(0,r.jsx)(g,{label:"Status",children:(0,r.jsxs)(v,{value:e.status,onChange:e=>i("status",e),children:[(0,r.jsx)("option",{value:"",children:"Tất cả status"}),(s.statuses||[]).map(e=>(0,r.jsx)("option",{value:e,children:e},e))]})}),(0,r.jsx)(g,{label:"Session / keyword",children:(0,r.jsx)(y,{value:e.sessionId||e.keyword,onChange:e=>i("keyword",e),placeholder:"session, prompt, error..."})})]}),(0,r.jsxs)("div",{className:"mt-4 flex flex-wrap items-center justify-between gap-3",children:[(0,r.jsx)("div",{className:"text-xs text-text-muted",children:"Token/cost lấy từ UsageHistory. Source IP/tool/session lấy từ Prompt Logs."}),(0,r.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,r.jsx)("button",{onClick:()=>t({period:"24h",dateFrom:"",dateTo:"",provider:"",model:"",connectionId:"",status:"",endpoint:"",apiKey:"",clientIp:"",sourceTool:"",sessionId:"",keyword:""}),className:"rounded-xl border border-border px-3 py-2 text-sm font-medium text-text-main hover:bg-background",children:"Reset"}),(0,r.jsxs)("button",{onClick:a,className:"rounded-xl border border-border px-3 py-2 text-sm font-medium text-text-main hover:bg-background",children:[(0,r.jsx)("span",{className:"material-symbols-outlined mr-1 align-[-4px] text-[18px]",children:"download"}),"Export CSV"]}),(0,r.jsxs)("button",{onClick:l,disabled:o,className:"rounded-xl bg-primary px-4 py-2 text-sm font-semibold text-white shadow-sm disabled:opacity-60",children:[(0,r.jsx)("span",{className:"material-symbols-outlined mr-1 align-[-4px] text-[18px]",children:"refresh"}),o?"Đang tải...":"Refresh"]})]})]})]})}function C({data:e}){let t=e.overview||{},s=e.latency||{};return(0,r.jsxs)("div",{className:"space-y-5",children:[(0,r.jsxs)("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-4",children:[(0,r.jsx)(j,{icon:"call_made",label:"Tổng request",value:o(t.requests),hint:`${o(t.requestsPerMinute,2)} request/ph\xfat`}),(0,r.jsx)(j,{icon:"check_circle",label:"Th\xe0nh c\xf4ng",value:o(t.success),hint:`Tỷ lệ lỗi ${d(t.errorRate)}`,tone:"green"}),(0,r.jsx)(j,{icon:"error",label:"Request lỗi",value:o(t.errors),hint:"Theo status trong usage log",tone:t.errors?"red":"green"}),(0,r.jsx)(j,{icon:"speed",label:"Latency P95",value:x(s.p95Ms),hint:`${o(s.samples)} mẫu requestDetails`,tone:"purple"}),(0,r.jsx)(j,{icon:"input",label:"Input tokens",value:i(t.promptTokens),hint:`Avg ${o(t.avgPromptTokens,1)} / request`}),(0,r.jsx)(j,{icon:"output",label:"Output tokens",value:i(t.completionTokens),hint:`Avg ${o(t.avgCompletionTokens,1)} / request`}),(0,r.jsx)(j,{icon:"token",label:"Tổng tokens",value:i(t.totalTokens),hint:`${i(t.tokensPerMinute)} token/ph\xfat`,tone:"amber"}),(0,r.jsx)(j,{icon:"payments",label:"Cost ước t\xednh",value:c(t.cost),hint:"Dựa tr\xean pricing đ\xe3 cấu h\xecnh",tone:"green"})]}),(0,r.jsxs)("div",{className:"grid gap-5 xl:grid-cols-[2fr_1fr]",children:[(0,r.jsxs)(b,{children:[(0,r.jsxs)("div",{className:"mb-4 flex flex-wrap items-center justify-between gap-3",children:[(0,r.jsxs)("div",{children:[(0,r.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Tần suất request & token theo thời gian"}),(0,r.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Cột xanh l\xe0 token, cột v\xe0ng l\xe0 số request trong từng bucket thời gian."})]}),(0,r.jsx)(w,{})]}),(0,r.jsx)(N,{data:e.timeSeries||[]})]}),(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"T\xf3m tắt active"}),(0,r.jsx)("div",{className:"mt-4 space-y-3",children:[["API key đang d\xf9ng",t.activeApiKeys],["Provider active",t.activeProviders],["Model active",t.activeModels],["Endpoint active",t.activeEndpoints],["Cached tokens",t.cachedTokens],["Reasoning tokens",t.reasoningTokens],["Latency P50",x(s.p50Ms)],["Latency P99",x(s.p99Ms)]].map(([e,t])=>(0,r.jsxs)("div",{className:"flex items-center justify-between rounded-xl bg-background px-3 py-2",children:[(0,r.jsx)("span",{className:"text-sm text-text-muted",children:e}),(0,r.jsx)("span",{className:"font-semibold text-text-main",children:"number"==typeof t?o(t):t})]},e))})]})]}),(0,r.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Top API key d\xf9ng nhiều token"}),(0,r.jsx)(T,{rows:(e.groups?.apiKeys||[]).slice(0,8),columns:[{key:"name",label:"API key",render:e=>(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{className:"font-semibold",children:e.name}),(0,r.jsxs)("div",{className:"text-xs text-text-muted",children:[e.fingerprint,e.ownerUser?` \xb7 ${e.ownerUser}`:""]})]})},{key:"requests",label:"Req",render:e=>o(e.requests)},{key:"tokens",label:"Token",render:e=>(0,r.jsx)(q,{row:e})},{key:"errorRate",label:"Lỗi",render:e=>(0,r.jsx)(I,{value:e.errorRate})}]})]}),(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Top Source IP từ Prompt Logs"}),(0,r.jsx)(T,{rows:(e.promptLogs?.topClientIps||[]).slice(0,8),columns:[{key:"label",label:"Source IP",render:e=>(0,r.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Logs",render:e=>o(e.requests)},{key:"errorRate",label:"Lỗi",render:e=>(0,r.jsx)(I,{value:e.errorRate})},{key:"topTools",label:"Tools",render:e=>(0,r.jsx)(S,{items:e.topTools})}]})]})]})]})}function M({data:e}){return(0,r.jsxs)(b,{children:[(0,r.jsxs)("div",{className:"mb-4",children:[(0,r.jsx)("h2",{className:"text-lg font-semibold text-text-main",children:"Thống k\xea theo API key"}),(0,r.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"Kh\xf4ng hiển thị full bearer token. Dashboard chỉ d\xf9ng fingerprint/masked key."})]}),(0,r.jsx)(T,{rows:e.groups?.apiKeys||[],columns:[{key:"name",label:"API key",render:e=>(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{className:"font-semibold",children:e.name}),(0,r.jsxs)("div",{className:"text-xs text-text-muted",children:[e.fingerprint,e.ownerUser?` \xb7 Owner: ${e.ownerUser}`:""]})]})},{key:"requests",label:"Requests",render:e=>o(e.requests)},{key:"success",label:"OK/Lỗi",render:e=>(0,r.jsxs)("div",{className:"text-xs",children:[(0,r.jsxs)("div",{className:"text-green-600",children:["OK ",o(e.success)]}),(0,r.jsxs)("div",{className:"text-red-600",children:["Lỗi ",o(e.errors)]})]})},{key:"tokens",label:"In/Out token",render:e=>(0,r.jsx)(q,{row:e})},{key:"cost",label:"Cost",render:e=>c(e.cost)},{key:"errorRate",label:"Error %",render:e=>(0,r.jsx)(I,{value:e.errorRate})},{key:"topModels",label:"Top model",render:e=>(0,r.jsx)(S,{items:e.topModels})},{key:"topProviders",label:"Top provider",render:e=>(0,r.jsx)(S,{items:e.topProviders})},{key:"lastSeen",label:"Last seen",render:e=>m(e.lastSeen)}]})]})}function K({data:e}){return(0,r.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Source IP"}),(0,r.jsx)(T,{rows:e.promptLogs?.topClientIps||[],columns:[{key:"label",label:"IP",render:e=>(0,r.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Logs",render:e=>o(e.requests)},{key:"errors",label:"Lỗi",render:e=>o(e.errors)},{key:"errorRate",label:"Error %",render:e=>(0,r.jsx)(I,{value:e.errorRate})},{key:"topTools",label:"Tools",render:e=>(0,r.jsx)(S,{items:e.topTools})},{key:"topModels",label:"Models",render:e=>(0,r.jsx)(S,{items:e.topModels})},{key:"lastSeen",label:"Last seen",render:e=>m(e.lastSeen)}]})]}),(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Source tool"}),(0,r.jsx)(T,{rows:e.promptLogs?.topSourceTools||[],columns:[{key:"label",label:"Tool",render:e=>(0,r.jsx)("span",{className:"font-semibold",children:e.label})},{key:"requests",label:"Logs",render:e=>o(e.requests)},{key:"errors",label:"Lỗi",render:e=>o(e.errors)},{key:"errorRate",label:"Error %",render:e=>(0,r.jsx)(I,{value:e.errorRate})},{key:"topIps",label:"Top IP",render:e=>(0,r.jsx)(S,{items:e.topIps})},{key:"topModels",label:"Top model",render:e=>(0,r.jsx)(S,{items:e.topModels})},{key:"lastSeen",label:"Last seen",render:e=>m(e.lastSeen)}]})]}),(0,r.jsxs)(b,{className:"xl:col-span-2",children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Session nhiều hoạt động"}),(0,r.jsx)(T,{rows:e.promptLogs?.topSessions||[],columns:[{key:"label",label:"Session",render:e=>(0,r.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Logs",render:e=>o(e.requests)},{key:"errors",label:"Lỗi",render:e=>o(e.errors)},{key:"topIps",label:"IP",render:e=>(0,r.jsx)(S,{items:e.topIps})},{key:"topTools",label:"Tool",render:e=>(0,r.jsx)(S,{items:e.topTools})},{key:"topModels",label:"Model",render:e=>(0,r.jsx)(S,{items:e.topModels})},{key:"lastSeen",label:"Last seen",render:e=>m(e.lastSeen)}]})]})]})}function A({data:e}){return(0,r.jsxs)("div",{className:"space-y-5",children:[(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Provider"}),(0,r.jsx)(T,{rows:e.groups?.providers||[],columns:[{key:"label",label:"Provider",render:e=>(0,r.jsx)("span",{className:"font-semibold",children:e.label})},{key:"requests",label:"Requests",render:e=>o(e.requests)},{key:"tokens",label:"Token",render:e=>(0,r.jsx)(q,{row:e})},{key:"cost",label:"Cost",render:e=>c(e.cost)},{key:"errorRate",label:"Error %",render:e=>(0,r.jsx)(I,{value:e.errorRate})},{key:"topModels",label:"Top model",render:e=>(0,r.jsx)(S,{items:e.topModels})},{key:"lastSeen",label:"Last seen",render:e=>m(e.lastSeen)}]})]}),(0,r.jsxs)("div",{className:"grid gap-5 xl:grid-cols-2",children:[(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Model"}),(0,r.jsx)(T,{rows:e.groups?.models||[],columns:[{key:"label",label:"Model",render:e=>(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{className:"font-semibold",children:e.model}),(0,r.jsx)("div",{className:"text-xs text-text-muted",children:e.providerLabel||e.provider})]})},{key:"requests",label:"Req",render:e=>o(e.requests)},{key:"tokens",label:"Token",render:e=>(0,r.jsx)(q,{row:e})},{key:"errorRate",label:"Lỗi",render:e=>(0,r.jsx)(I,{value:e.errorRate})}]})]}),(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Provider account / connection"}),(0,r.jsx)(T,{rows:e.groups?.providerAccounts||[],columns:[{key:"label",label:"Account",render:e=>(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{className:"font-semibold",children:e.label}),(0,r.jsx)("div",{className:"text-xs text-text-muted",children:e.provider||e.connectionId})]})},{key:"requests",label:"Req",render:e=>o(e.requests)},{key:"tokens",label:"Token",render:e=>(0,r.jsx)(q,{row:e})},{key:"errorRate",label:"Lỗi",render:e=>(0,r.jsx)(I,{value:e.errorRate})}]})]})]}),(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Endpoint"}),(0,r.jsx)(T,{rows:e.groups?.endpoints||[],columns:[{key:"label",label:"Endpoint",render:e=>(0,r.jsx)("span",{className:"font-mono text-xs",children:e.label})},{key:"requests",label:"Requests",render:e=>o(e.requests)},{key:"tokens",label:"Token",render:e=>(0,r.jsx)(q,{row:e})},{key:"cost",label:"Cost",render:e=>c(e.cost)},{key:"errorRate",label:"Error %",render:e=>(0,r.jsx)(I,{value:e.errorRate})},{key:"lastSeen",label:"Last seen",render:e=>m(e.lastSeen)}]})]})]})}function E({data:e}){return(0,r.jsxs)("div",{className:"space-y-5",children:[e.anomalies?.length?(0,r.jsx)("div",{className:"grid gap-4 xl:grid-cols-2",children:e.anomalies.map((e,t)=>(0,r.jsx)(P,{anomaly:e},t))}):(0,r.jsxs)("div",{className:"rounded-2xl border border-green-500/20 bg-green-500/10 p-4 text-sm text-green-700 dark:text-green-300",children:[(0,r.jsx)("span",{className:"material-symbols-outlined mr-2 align-[-5px]",children:"check_circle"}),"Chưa ph\xe1t hiện bất thường r\xf5 r\xe0ng theo bộ lọc hiện tại."]}),(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Nh\xf3m lỗi theo status/provider/model/endpoint"}),(0,r.jsx)(T,{rows:e.groups?.errors||[],columns:[{key:"status",label:"Status",render:e=>(0,r.jsx)("span",{className:"rounded-full bg-red-500/10 px-2 py-1 text-xs font-semibold text-red-600 dark:text-red-300",children:e.status})},{key:"provider",label:"Provider"},{key:"model",label:"Model"},{key:"endpoint",label:"Endpoint",render:e=>(0,r.jsx)("span",{className:"font-mono text-xs",children:e.endpoint})},{key:"requests",label:"Lỗi",render:e=>o(e.errors||e.requests)},{key:"apiKey",label:"API key",render:e=>(0,r.jsx)("span",{className:"font-mono text-xs",children:e.apiKey})},{key:"lastSeen",label:"Last seen",render:e=>m(e.lastSeen)}]})]}),(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Status distribution"}),(0,r.jsx)(T,{rows:e.groups?.statuses||[],columns:[{key:"label",label:"Status"},{key:"requests",label:"Requests",render:e=>o(e.requests)},{key:"tokens",label:"Token",render:e=>(0,r.jsx)(q,{row:e})},{key:"errorRate",label:"Error %",render:e=>(0,r.jsx)(I,{value:e.errorRate})}]})]})]})}function $({data:e}){return(0,r.jsxs)("div",{className:"space-y-5",children:[(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Top request nặng token"}),(0,r.jsx)(T,{rows:e.heavyRequests||[],columns:[{key:"timestamp",label:"Time",render:e=>m(e.timestamp)},{key:"model",label:"Model",render:e=>(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{className:"font-semibold",children:e.model}),(0,r.jsx)("div",{className:"text-xs text-text-muted",children:e.provider})]})},{key:"apiKeyName",label:"API key",render:e=>(0,r.jsxs)("div",{children:[(0,r.jsx)("div",{children:e.apiKeyName}),(0,r.jsx)("div",{className:"font-mono text-xs text-text-muted",children:e.apiKeyFingerprint})]})},{key:"accountName",label:"Account"},{key:"endpoint",label:"Endpoint",render:e=>(0,r.jsx)("span",{className:"font-mono text-xs",children:e.endpoint})},{key:"tokens",label:"Token",render:e=>(0,r.jsx)(q,{row:e})},{key:"status",label:"Status"}]})]}),(0,r.jsxs)(b,{children:[(0,r.jsx)("h2",{className:"mb-4 text-lg font-semibold text-text-main",children:"Recent usage"}),(0,r.jsx)(T,{rows:e.recentUsage||[],columns:[{key:"timestamp",label:"Time",render:e=>m(e.timestamp)},{key:"provider",label:"Provider"},{key:"model",label:"Model"},{key:"apiKeyName",label:"API key"},{key:"tokens",label:"Token",render:e=>(0,r.jsx)(q,{row:e})},{key:"cost",label:"Cost",render:e=>c(e.cost)},{key:"status",label:"Status"}]})]})]})}function F(){let[e,t]=(0,l.useState)({period:"24h",dateFrom:"",dateTo:"",provider:"",model:"",connectionId:"",status:"",endpoint:"",apiKey:"",clientIp:"",sourceTool:"",sessionId:"",keyword:""}),[s,n]=(0,l.useState)(null),[o,i]=(0,l.useState)(!0),[d,c]=(0,l.useState)(""),[x,u]=(0,l.useState)("overview"),[b,j]=(0,l.useState)(!1),g=function(e,t=450){let[s,r]=(0,l.useState)(e);return(0,l.useEffect)(()=>{let s=setTimeout(()=>r(e),t);return()=>clearTimeout(s)},[e,t]),s}(e,450),v=(0,l.useCallback)(async()=>{i(!0),c("");try{let e=h(g),t=await fetch(`/api/dashboard/analytics?${e}`,{cache:"no-store"}),s=await t.json().catch(()=>({}));if(!t.ok)throw Error(s.error||"Kh\xf4ng tải được dữ liệu analytics");n(s)}catch(e){c(e.message||"Kh\xf4ng tải được dữ liệu analytics")}finally{i(!1)}},[g]);(0,l.useEffect)(()=>{v()},[v]),(0,l.useEffect)(()=>{if(!b)return;let e=setInterval(()=>v(),1e4);return()=>clearInterval(e)},[b,v]);let y=s?.options||{},N=(0,l.useMemo)(()=>s?.generatedAt?m(s.generatedAt):"-",[s]);return(0,r.jsxs)("div",{className:"space-y-5 p-4 md:p-6",children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-4",children:[(0,r.jsxs)("div",{children:[(0,r.jsxs)("div",{className:"flex items-center gap-2 text-primary",children:[(0,r.jsx)("span",{className:"material-symbols-outlined",children:"monitoring"}),(0,r.jsx)("span",{className:"text-sm font-semibold uppercase tracking-wide",children:"BlueRouter Analytics"})]}),(0,r.jsx)("h1",{className:"mt-2 text-2xl font-bold text-text-main",children:"Thống k\xea sử dụng Gateway"}),(0,r.jsx)("p",{className:"mt-1 max-w-3xl text-sm text-text-muted",children:"Theo d\xf5i tần suất request, input/output token, API key, provider, model, endpoint, Source IP, source tool v\xe0 lỗi vận h\xe0nh."})]}),(0,r.jsxs)("div",{className:"flex items-center gap-3 rounded-2xl border border-border bg-surface px-4 py-3 text-sm text-text-muted",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[20px]",children:"schedule"}),(0,r.jsxs)("div",{children:[(0,r.jsxs)("div",{children:["Generated: ",N]}),(0,r.jsxs)("label",{className:"mt-1 flex cursor-pointer items-center gap-2 text-xs",children:[(0,r.jsx)("input",{type:"checkbox",checked:b,onChange:e=>j(e.target.checked)}),"Auto refresh 10s"]})]})]})]}),(0,r.jsx)(R,{filters:e,setFilters:t,options:y,onRefresh:v,onExportCsv:()=>{let e=h(g,{format:"csv"});window.open(`/api/dashboard/analytics?${e}`,"_blank","noopener,noreferrer")},loading:o}),d?(0,r.jsxs)("div",{className:"rounded-2xl border border-red-500/30 bg-red-500/10 p-4 text-sm text-red-700 dark:text-red-300",children:[(0,r.jsx)("span",{className:"material-symbols-outlined mr-2 align-[-5px]",children:"error"}),d]}):null,s?.qualityNotes?.length?(0,r.jsx)(L,{notes:s.qualityNotes}):null,(0,r.jsx)("div",{className:"flex flex-wrap gap-2 rounded-2xl border border-border bg-surface p-2",children:a.map(e=>(0,r.jsxs)("button",{onClick:()=>u(e.value),className:p("flex items-center gap-2 rounded-xl px-3 py-2 text-sm font-medium transition",x===e.value?"bg-primary text-white shadow-sm":"text-text-muted hover:bg-background hover:text-text-main"),children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[18px]",children:e.icon}),e.label]},e.value))}),o&&!s?(0,r.jsx)(k,{}):null,!o&&s&&s.overview?.requests===0&&0===(s.promptLogs?.total||0)?(0,r.jsx)(f,{title:"Chưa c\xf3 dữ liệu analytics",description:"Kh\xf4ng c\xf3 UsageHistory hoặc Prompt Logs theo bộ lọc hiện tại."}):null,s?(0,r.jsxs)(r.Fragment,{children:["overview"===x?(0,r.jsx)(C,{data:s}):null,"apiKeys"===x?(0,r.jsx)(M,{data:s}):null,"sources"===x?(0,r.jsx)(K,{data:s}):null,"providers"===x?(0,r.jsx)(A,{data:s}):null,"errors"===x?(0,r.jsx)(E,{data:s}):null,"raw"===x?(0,r.jsx)($,{data:s}):null]}):null]})}}},e=>{e.O(0,[8441,3794,7358],()=>e(e.s=39944)),_N_E=e.O()}]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7593],{56484:(e,t,s)=>{"use strict";s.d(t,{default:()=>w});var n=s(95155),r=s(12115),a=s(35497),l=s(94027),i=s(11059);let d=Object.freeze({enabled:!0,requestsPerMinute:20,promptCharsMax:12e4,forceThinkingOff:!0,allowedIpCidrs:[],expiresAt:""});function o(e){return String(e||"").trim().toLowerCase()}function c(e){return Array.isArray(e)?[...new Set(e.map(e=>String(e||"").trim()).filter(Boolean))]:[]}function x(e,t=0){let s=Number(e);return Number.isFinite(s)?Math.max(0,Math.floor(s)):t}function m(e,t=!0){return null==e||""===e?t:!0===e||"true"===e||1===e||"1"===e}function h(e){return Array.isArray(e)?[...new Set(e.map(e=>String(e||"").trim()).filter(Boolean))]:[]}function u(e){return e&&"object"==typeof e&&!Array.isArray(e)&&Object.keys(e).length>0}function p(e={},t={}){let s={...t},n=e&&"object"==typeof e&&!Array.isArray(e)?e:{};return{enabled:m(n.enabled??s.enabled,!0),requestsPerMinute:x(n.requestsPerMinute??s.requestsPerMinute,0),promptCharsMax:x(n.promptCharsMax??s.promptCharsMax,0),forceThinkingOff:m(n.forceThinkingOff??s.forceThinkingOff,!0),allowedIpCidrs:h(n.allowedIpCidrs??s.allowedIpCidrs),expiresAt:String(n.expiresAt??s.expiresAt??"").trim()}}function b({limits:e}){if(!u(e))return(0,n.jsx)("div",{className:"mt-2 flex flex-wrap gap-2 text-xs text-text-muted",children:(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:"policy: chưa set, kh\xf4ng giới hạn"})});let t=p(e);return(0,n.jsxs)("div",{className:"mt-2 flex flex-wrap gap-2 text-xs text-text-muted",children:[(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:["policy: ",t.enabled?"bật":"tắt"]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:[t.requestsPerMinute||"∞"," req/ph\xfat"]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:[t.promptCharsMax||"∞"," chars prompt"]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:["thinking: ",t.forceThinkingOff?"force off":"client tự quyết"]}),t.allowedIpCidrs.length>0?(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:"IP locked"}):null]})}function g({label:e,value:t,onChange:s,hint:r}){return(0,n.jsxs)("label",{className:"block",children:[(0,n.jsx)("span",{className:"mb-1 block text-xs font-medium text-text-muted",children:e}),(0,n.jsx)("input",{type:"number",min:"0",value:t,onChange:e=>s(x(e.target.value,0)),className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary"}),r?(0,n.jsx)("span",{className:"mt-1 block text-xs text-text-muted",children:r}):null]})}function f({isOpen:e,keyName:t,policy:s,setPolicy:r,onClose:l,onSave:i,onClear:o,saving:c,clearLabel:x="X\xf3a policy / kh\xf4ng limit"}){let m=p(s,d),u=(e,t)=>r(s=>p({...s,[e]:t},d));return(0,n.jsx)(a.aF,{isOpen:e,onClose:l,title:`Policy API key: ${t||"API Key"}`,size:"xl",children:(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface/60 p-3 text-sm text-text-muted",children:["Key mới tự c\xf3 ",(0,n.jsx)("b",{children:"default policy"}),". Chỉ admin được sửa policy. Request/ph\xfat = 0 nghĩa l\xe0 kh\xf4ng giới hạn tần suất. Policy n\xe0y kh\xf4ng \xe9p max_tokens/output tokens."]}),(0,n.jsxs)("label",{className:"flex items-center justify-between gap-3 rounded-xl border border-border p-3 text-sm",children:[(0,n.jsxs)("span",{children:[(0,n.jsx)("b",{children:"Bật policy"}),(0,n.jsx)("br",{}),(0,n.jsx)("span",{className:"text-xs text-text-muted",children:"Tắt mục n\xe0y th\xec policy được lưu nhưng kh\xf4ng \xe1p limit."})]}),(0,n.jsx)("input",{type:"checkbox",checked:m.enabled,onChange:e=>u("enabled",e.target.checked)})]}),(0,n.jsx)("div",{className:"grid gap-3 md:grid-cols-2",children:(0,n.jsx)(g,{label:"Request / ph\xfat",value:m.requestsPerMinute,onChange:e=>u("requestsPerMinute",e),hint:"0 = kh\xf4ng giới hạn tần suất. Khuyến nghị user thường: 10–20 req/ph\xfat."})}),(0,n.jsx)(g,{label:"Prompt chars tối đa",value:m.promptCharsMax,onChange:e=>u("promptCharsMax",e),hint:"0 = kh\xf4ng giới hạn. Policy kh\xf4ng can thiệp max_tokens/output tokens của client."}),(0,n.jsxs)("label",{className:"flex items-center justify-between gap-3 rounded-xl border border-border p-3 text-sm",children:[(0,n.jsxs)("span",{children:[(0,n.jsx)("b",{children:"Force Thinking Off"}),(0,n.jsx)("br",{}),(0,n.jsx)("span",{className:"text-xs text-text-muted",children:"Khi bật, gateway \xe9p request c\xf3 chat_template_kwargs.enable_thinking=false theo chuẩn llama.cpp."})]}),(0,n.jsx)("input",{type:"checkbox",checked:m.forceThinkingOff,onChange:e=>u("forceThinkingOff",e.target.checked)})]}),(0,n.jsxs)("label",{className:"block",children:[(0,n.jsx)("span",{className:"mb-1 block text-xs font-medium text-text-muted",children:"IP/CIDR được ph\xe9p"}),(0,n.jsx)("textarea",{value:h(m.allowedIpCidrs).join("\n"),onChange:e=>u("allowedIpCidrs",[...new Set(String(e.target.value||"").split(/[\n,]+/).map(e=>e.trim()).filter(Boolean))]),rows:3,className:"w-full rounded-xl border border-border bg-background px-3 py-2 font-mono text-sm text-text-main outline-none focus:border-primary",placeholder:"10.0.0.0/8\n192.168.0.0/16"}),(0,n.jsx)("span",{className:"mt-1 block text-xs text-text-muted",children:"Để trống = mọi IP. Hỗ trợ IPv4 exact hoặc CIDR."})]}),(0,n.jsxs)("label",{className:"block",children:[(0,n.jsx)("span",{className:"mb-1 block text-xs font-medium text-text-muted",children:"Hết hạn l\xfac"}),(0,n.jsx)("input",{value:m.expiresAt,onChange:e=>u("expiresAt",e.target.value),className:"w-full rounded-xl border border-border bg-background px-3 py-2 font-mono text-sm text-text-main outline-none focus:border-primary",placeholder:"2026-12-31T23:59:59+07:00 hoặc để trống"})]}),(0,n.jsxs)("div",{className:"flex flex-wrap justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"ghost",onClick:l,children:"Hủy"}),o?(0,n.jsx)(a.$n,{variant:"outline",onClick:o,disabled:c,children:x}):null,(0,n.jsx)(a.$n,{onClick:()=>i(m),disabled:c,children:c?"Đang lưu...":"Lưu policy"})]})]})})}function y({open:e,keyName:t,models:s,setModels:l,activeProviders:i,modelAliases:d,onClose:o,onSave:x,saving:m}){let[h,u]=(0,r.useState)(!1),p=c(s),b=e=>{let t=e?.value||e?.name||e;l(e=>c(e).filter(e=>e!==t))};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(a.aF,{isOpen:e,onClose:o,title:`Model access: ${t||"API Key"}`,size:"xl",children:(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"Chọn một hoặc nhiều model m\xe0 API key n\xe0y được ph\xe9p sử dụng. Trang n\xe0y kh\xf4ng cho lưu danh s\xe1ch model rỗng."}),(0,n.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,n.jsx)("span",{className:"text-sm font-medium",children:"Model được ph\xe9p d\xf9ng"}),(0,n.jsx)(a.$n,{size:"sm",variant:"outline",onClick:()=>u(!0),children:"Th\xeam model"})]}),0===p.length?(0,n.jsx)("div",{className:"rounded-xl border border-dashed border-border p-4 text-sm text-text-muted",children:"Chưa chọn model n\xe0o. H\xe3y th\xeam \xedt nhất một model trước khi lưu."}):(0,n.jsx)("div",{className:"flex flex-wrap gap-2",children:p.map(e=>(0,n.jsxs)("button",{type:"button",onClick:()=>b(e),className:"rounded-full border border-primary/30 bg-primary/10 px-2 py-1 font-mono text-xs text-primary transition hover:bg-red-500/10 hover:text-red-600",title:"Bấm để gỡ model n\xe0y",children:[e," \xd7"]},e))}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"ghost",onClick:o,children:"Hủy"}),(0,n.jsx)(a.$n,{onClick:x,disabled:m||0===p.length,children:m?"Đang lưu...":"Lưu danh s\xe1ch model"})]})]})}),(0,n.jsx)(a.rq,{isOpen:h,onClose:()=>u(!1),onSelect:e=>{let t=e?.value||e?.name||e;t&&l(e=>c([...e,t]))},onDeselect:b,activeProviders:i,modelAliases:d,title:"Chọn model được ph\xe9p d\xf9ng",addedModelValues:p,closeOnSelect:!1})]})}function j({active:e}){return e?(0,n.jsx)("span",{className:"inline-flex items-center rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2 py-1 text-xs font-medium text-emerald-700 dark:text-emerald-300",children:"Đang bật"}):(0,n.jsx)("span",{className:"inline-flex items-center rounded-full border border-red-500/30 bg-red-500/10 px-2 py-1 text-xs font-medium text-red-700 dark:text-red-300",children:"Đ\xe3 tắt"})}function k({label:e,value:t,hint:s}){return(0,n.jsxs)("div",{className:"rounded-2xl border border-border bg-surface/70 p-4",children:[(0,n.jsx)("div",{className:"text-xs font-medium uppercase tracking-wide text-text-muted",children:e}),(0,n.jsx)("div",{className:"mt-2 text-2xl font-semibold text-text-main",children:t}),s?(0,n.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:s}):null]})}function v({pagination:e,pageSize:t,onPageChange:s,onPageSizeChange:r,loading:l}){let i=Number(e?.page||1),d=Number(e?.totalPages||1),o=Number(e?.total||0),c=0===o?0:(i-1)*t+1,x=Math.min(o,i*t);return(0,n.jsxs)("div",{className:"flex flex-col gap-3 border-t border-border px-4 py-3 md:flex-row md:items-center md:justify-between",children:[(0,n.jsxs)("div",{className:"text-sm text-text-muted",children:["Hiển thị ",(0,n.jsx)("b",{children:c}),"–",(0,n.jsx)("b",{children:x})," / ",(0,n.jsx)("b",{children:o})," API keys"]}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,n.jsxs)("select",{value:t,onChange:e=>r(Number(e.target.value)),className:"rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary",disabled:l,children:[(0,n.jsx)("option",{value:25,children:"25 / trang"}),(0,n.jsx)("option",{value:50,children:"50 / trang"}),(0,n.jsx)("option",{value:100,children:"100 / trang"})]}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>s(1),disabled:l||i<=1,children:"Đầu"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>s(Math.max(1,i-1)),disabled:l||i<=1,children:"Trước"}),(0,n.jsxs)("span",{className:"rounded-xl border border-border bg-surface px-3 py-2 text-sm",children:["Trang ",i,"/",d]}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>s(Math.min(d,i+1)),disabled:l||i>=d,children:"Sau"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>s(d),disabled:l||i>=d,children:"Cuối"})]})]})}function N({keys:e,visibleKeys:t,copied:s,copy:r,isAdmin:l,onToggleVisible:i,onToggleActive:d,onApiTest:o,onRename:x,onRotate:m,onEditModels:h,onEditPolicy:b,onAssignOwner:g,onDelete:f}){return(0,n.jsx)("div",{className:"overflow-hidden rounded-2xl border border-border",children:(0,n.jsx)("div",{className:"overflow-x-auto",children:(0,n.jsxs)("table",{className:"min-w-full divide-y divide-border text-sm",children:[(0,n.jsx)("thead",{className:"bg-surface/80 text-left text-xs uppercase tracking-wide text-text-muted",children:(0,n.jsxs)("tr",{children:[(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"T\xean / Key"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Trạng th\xe1i"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Owner"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Model"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Policy"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Ng\xe0y tạo"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 text-right font-medium",children:"Thao t\xe1c"})]})}),(0,n.jsx)("tbody",{className:"divide-y divide-border bg-background",children:e.map(e=>{var y;let k=t.has(e.id),v=e.ownerUser||e.createdByUser||"chưa g\xe1n",N=c(e.allowedModels),w=u(e.limits),C=p(e.limits||{});return(0,n.jsxs)("tr",{className:"align-top transition hover:bg-surface/50",children:[(0,n.jsxs)("td",{className:"min-w-[280px] px-4 py-4",children:[(0,n.jsx)("div",{className:"font-medium text-text-main",children:e.name||"API Key"}),(0,n.jsxs)("div",{className:"mt-2 flex max-w-[380px] items-center gap-2 rounded-xl border border-border bg-surface px-3 py-2 font-mono text-xs text-text-main",children:[(0,n.jsx)("span",{className:"min-w-0 flex-1 truncate",children:k?e.key:(y=e.key)?y.length>12?`${y.slice(0,8)}...${y.slice(-4)}`:y:""}),(0,n.jsx)("button",{type:"button",className:"text-primary hover:underline",onClick:()=>i(e.id),children:k?"Ẩn":"Hiện"})]}),e.createdByUser?(0,n.jsxs)("div",{className:"mt-2 text-xs text-text-muted",children:["Tạo bởi: ",e.createdByUser]}):null]}),(0,n.jsx)("td",{className:"whitespace-nowrap px-4 py-4",children:(0,n.jsxs)("div",{className:"flex items-center gap-3",children:[(0,n.jsx)(j,{active:!!e.isActive}),(0,n.jsx)(a.lM,{checked:!!e.isActive,onChange:t=>d(e.id,t)})]})}),(0,n.jsx)("td",{className:"min-w-[160px] px-4 py-4",children:(0,n.jsx)("div",{className:"break-all text-sm text-text-main",children:v})}),(0,n.jsx)("td",{className:"min-w-[220px] px-4 py-4",children:N.length>0?(0,n.jsxs)("div",{className:"flex flex-wrap gap-1.5",children:[N.slice(0,3).map(e=>(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1 font-mono text-xs",children:e},e)),N.length>3?(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1 text-xs",children:["+",N.length-3]}):null]}):(0,n.jsx)("span",{className:"rounded-full border border-amber-500/30 bg-amber-500/10 px-2 py-1 text-xs text-amber-700 dark:text-amber-300",children:"Legacy full access"})}),(0,n.jsx)("td",{className:"min-w-[220px] px-4 py-4",children:w?(0,n.jsxs)("div",{className:"flex flex-wrap gap-1.5 text-xs",children:[(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:C.enabled?"bật":"tắt"}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:[C.requestsPerMinute||"∞","/ph\xfat"]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:[C.promptCharsMax||"∞"," chars"]}),C.forceThinkingOff?(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:"thinking off"}):null,C.allowedIpCidrs.length>0?(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:"IP locked"}):null]}):(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1 text-xs text-text-muted",children:"chưa set"})}),(0,n.jsx)("td",{className:"min-w-[150px] px-4 py-4 text-xs text-text-muted",children:function(e){if(!e)return"kh\xf4ng r\xf5";try{return new Date(e).toLocaleString()}catch{return String(e)}}(e.createdAt)}),(0,n.jsx)("td",{className:"min-w-[260px] px-4 py-4",children:(0,n.jsxs)("div",{className:"flex flex-wrap justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>r(e.key,e.id),children:s===e.id?"Đ\xe3 copy":"Copy"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>o(e),children:"Test"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>x(e.id,e.name),children:"Đổi t\xean"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>m(e),children:"Đổi key"}),l?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>h(e),children:"Models"}):null,l?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>b(e),children:"Policy"}):null,l?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>g(e.id,v),children:"Owner"}):null,(0,n.jsx)(a.$n,{variant:"danger",size:"sm",onClick:()=>f(e.id),children:"X\xf3a"})]})})]},e.id)})})]})})})}function w(){let e,t,[s,x]=(0,r.useState)([]),[m,h]=(0,r.useState)(!0),[g,j]=(0,r.useState)(""),[w,C]=(0,r.useState)(!1),[P,A]=(0,r.useState)(""),[S,I]=(0,r.useState)(""),[T,$]=(0,r.useState)(""),[M,K]=(0,r.useState)(""),[O,z]=(0,r.useState)(new Set),[D,q]=(0,r.useState)(null),[E,L]=(0,r.useState)([]),[B,H]=(0,r.useState)(""),[R,U]=(0,r.useState)(!1),[_,F]=(0,r.useState)(!1),[X,Z]=(0,r.useState)(""),[J,V]=(0,r.useState)(""),[Y,G]=(0,r.useState)(!1),[W,Q]=(0,r.useState)(d),[ee,et]=(0,r.useState)(d),[es,en]=(0,r.useState)(!1),[er,ea]=(0,r.useState)(!1),[el,ei]=(0,r.useState)(!1),[ed,eo]=(0,r.useState)([]),[ec,ex]=(0,r.useState)({}),[em,eh]=(0,r.useState)(!1),[eu,ep]=(0,r.useState)(!1),[eb,eg]=(0,r.useState)(null),[ef,ey]=(0,r.useState)([]),[ej,ek]=(0,r.useState)(!1),[ev,eN]=(0,r.useState)(null),[ew,eC]=(0,r.useState)(d),[eP,eA]=(0,r.useState)(!1),[eS,eI]=(0,r.useState)(2),[eT,e$]=(0,r.useState)(0),[eM,eK]=(0,r.useState)(0),[eO,ez]=(0,r.useState)(""),[eD,eq]=(0,r.useState)(null),[eE,eL]=(0,r.useState)(""),[eB,eH]=(0,r.useState)(""),[eR,eU]=(0,r.useState)("all"),[e_,eF]=(0,r.useState)(1),[eX,eZ]=(0,r.useState)(25),[eJ,eV]=(0,r.useState)({page:1,pageSize:25,total:0,totalAll:0,totalPages:1,status:"all",search:""}),{copied:eY,copy:eG}=(0,i.C)(),{isAdmin:eW,userId:eQ}=(0,l.s)(),e0=Number.isFinite(Number(eS))?Number(eS):2,e1=Number.isFinite(Number(eT))?Number(eT):s.length,e2=Number.isFinite(Number(eM))?Number(eM):Number(eJ.totalAll||eJ.total||0),e3=Number(eJ.total||0),e4=!eW&&e1>=e0,e5=eO?`${eO}/v1`:"/v1",e8=eO?`${eO}/v1/chat/completions`:"/v1/chat/completions",e6=(e=c(eD?.allowedModels)[0],t=String(X||"").trim(),e||t||"YOUR_MODEL"),e7=eD?function({endpoint:e,apiKey:t,model:s}){let n=String(e||"/v1/chat/completions").replace(/"/g,""),r=String(t||"YOUR_API_KEY").replace(/"/g,""),a=JSON.stringify({model:String(s||"YOUR_MODEL"),messages:[{role:"user",content:"Say hi.\nReply in one short sentence."}],temperature:.2,stream:!1}).replace(/"/g,'\\"');return`curl.exe -X POST "${n}" ^
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7593],{56484:(e,t,s)=>{"use strict";s.d(t,{default:()=>w});var n=s(95155),r=s(12115),a=s(35497),l=s(94027),i=s(11059);let d=Object.freeze({enabled:!0,requestsPerMinute:20,promptCharsMax:12e4,forceThinkingOff:!0,allowedIpCidrs:[],expiresAt:""});function o(e){return String(e||"").trim().toLowerCase()}function c(e){return Array.isArray(e)?[...new Set(e.map(e=>String(e||"").trim()).filter(Boolean))]:[]}function x(e,t=0){let s=Number(e);return Number.isFinite(s)?Math.max(0,Math.floor(s)):t}function m(e,t=!0){return null==e||""===e?t:!0===e||"true"===e||1===e||"1"===e}function h(e){return Array.isArray(e)?[...new Set(e.map(e=>String(e||"").trim()).filter(Boolean))]:[]}function u(e){return e&&"object"==typeof e&&!Array.isArray(e)&&Object.keys(e).length>0}function p(e={},t={}){let s={...t},n=e&&"object"==typeof e&&!Array.isArray(e)?e:{};return{enabled:m(n.enabled??s.enabled,!0),requestsPerMinute:x(n.requestsPerMinute??s.requestsPerMinute,0),promptCharsMax:x(n.promptCharsMax??s.promptCharsMax,0),forceThinkingOff:m(n.forceThinkingOff??s.forceThinkingOff,!0),allowedIpCidrs:h(n.allowedIpCidrs??s.allowedIpCidrs),expiresAt:String(n.expiresAt??s.expiresAt??"").trim()}}function b({limits:e}){if(!u(e))return(0,n.jsx)("div",{className:"mt-2 flex flex-wrap gap-2 text-xs text-text-muted",children:(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:"policy: chưa set, kh\xf4ng giới hạn"})});let t=p(e);return(0,n.jsxs)("div",{className:"mt-2 flex flex-wrap gap-2 text-xs text-text-muted",children:[(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:["policy: ",t.enabled?"bật":"tắt"]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:[t.requestsPerMinute||"∞"," req/ph\xfat"]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:[t.promptCharsMax||"∞"," chars prompt"]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:["thinking: ",t.forceThinkingOff?"force off":"client tự quyết"]}),t.allowedIpCidrs.length>0?(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:"IP locked"}):null]})}function g({label:e,value:t,onChange:s,hint:r}){return(0,n.jsxs)("label",{className:"block",children:[(0,n.jsx)("span",{className:"mb-1 block text-xs font-medium text-text-muted",children:e}),(0,n.jsx)("input",{type:"number",min:"0",value:t,onChange:e=>s(x(e.target.value,0)),className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary"}),r?(0,n.jsx)("span",{className:"mt-1 block text-xs text-text-muted",children:r}):null]})}function f({isOpen:e,keyName:t,policy:s,setPolicy:r,onClose:l,onSave:i,onClear:o,saving:c,clearLabel:x="X\xf3a policy / kh\xf4ng limit"}){let m=p(s,d),u=(e,t)=>r(s=>p({...s,[e]:t},d));return(0,n.jsx)(a.aF,{isOpen:e,onClose:l,title:`Policy API key: ${t||"API Key"}`,size:"xl",children:(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface/60 p-3 text-sm text-text-muted",children:["Key mới tự c\xf3 ",(0,n.jsx)("b",{children:"default policy"}),". Chỉ admin được sửa policy. Request/ph\xfat = 0 nghĩa l\xe0 kh\xf4ng giới hạn tần suất. Policy n\xe0y kh\xf4ng \xe9p max_tokens/output tokens."]}),(0,n.jsxs)("label",{className:"flex items-center justify-between gap-3 rounded-xl border border-border p-3 text-sm",children:[(0,n.jsxs)("span",{children:[(0,n.jsx)("b",{children:"Bật policy"}),(0,n.jsx)("br",{}),(0,n.jsx)("span",{className:"text-xs text-text-muted",children:"Tắt mục n\xe0y th\xec policy được lưu nhưng kh\xf4ng \xe1p limit."})]}),(0,n.jsx)("input",{type:"checkbox",checked:m.enabled,onChange:e=>u("enabled",e.target.checked)})]}),(0,n.jsx)("div",{className:"grid gap-3 md:grid-cols-2",children:(0,n.jsx)(g,{label:"Request / ph\xfat",value:m.requestsPerMinute,onChange:e=>u("requestsPerMinute",e),hint:"0 = kh\xf4ng giới hạn tần suất. Khuyến nghị user thường: 10–20 req/ph\xfat."})}),(0,n.jsx)(g,{label:"Prompt chars tối đa",value:m.promptCharsMax,onChange:e=>u("promptCharsMax",e),hint:"0 = kh\xf4ng giới hạn. Policy kh\xf4ng can thiệp max_tokens/output tokens của client."}),(0,n.jsxs)("label",{className:"flex items-center justify-between gap-3 rounded-xl border border-border p-3 text-sm",children:[(0,n.jsxs)("span",{children:[(0,n.jsx)("b",{children:"Force Thinking Off"}),(0,n.jsx)("br",{}),(0,n.jsx)("span",{className:"text-xs text-text-muted",children:"Khi bật, gateway \xe9p request c\xf3 chat_template_kwargs.enable_thinking=false theo chuẩn llama.cpp."})]}),(0,n.jsx)("input",{type:"checkbox",checked:m.forceThinkingOff,onChange:e=>u("forceThinkingOff",e.target.checked)})]}),(0,n.jsxs)("label",{className:"block",children:[(0,n.jsx)("span",{className:"mb-1 block text-xs font-medium text-text-muted",children:"IP/CIDR được ph\xe9p"}),(0,n.jsx)("textarea",{value:h(m.allowedIpCidrs).join("\n"),onChange:e=>u("allowedIpCidrs",[...new Set(String(e.target.value||"").split(/[\n,]+/).map(e=>e.trim()).filter(Boolean))]),rows:3,className:"w-full rounded-xl border border-border bg-background px-3 py-2 font-mono text-sm text-text-main outline-none focus:border-primary",placeholder:"10.0.0.0/8\n192.168.0.0/16"}),(0,n.jsx)("span",{className:"mt-1 block text-xs text-text-muted",children:"Để trống = mọi IP. Hỗ trợ IPv4 exact hoặc CIDR."})]}),(0,n.jsxs)("label",{className:"block",children:[(0,n.jsx)("span",{className:"mb-1 block text-xs font-medium text-text-muted",children:"Hết hạn l\xfac"}),(0,n.jsx)("input",{value:m.expiresAt,onChange:e=>u("expiresAt",e.target.value),className:"w-full rounded-xl border border-border bg-background px-3 py-2 font-mono text-sm text-text-main outline-none focus:border-primary",placeholder:"2026-12-31T23:59:59+07:00 hoặc để trống"})]}),(0,n.jsxs)("div",{className:"flex flex-wrap justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"ghost",onClick:l,children:"Hủy"}),o?(0,n.jsx)(a.$n,{variant:"outline",onClick:o,disabled:c,children:x}):null,(0,n.jsx)(a.$n,{onClick:()=>i(m),disabled:c,children:c?"Đang lưu...":"Lưu policy"})]})]})})}function y({open:e,keyName:t,models:s,setModels:l,activeProviders:i,modelAliases:d,onClose:o,onSave:x,saving:m}){let[h,u]=(0,r.useState)(!1),p=c(s),b=e=>{let t=e?.value||e?.name||e;l(e=>c(e).filter(e=>e!==t))};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(a.aF,{isOpen:e,onClose:o,title:`Model access: ${t||"API Key"}`,size:"xl",children:(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"Chọn một hoặc nhiều model m\xe0 API key n\xe0y được ph\xe9p sử dụng. Trang n\xe0y kh\xf4ng cho lưu danh s\xe1ch model rỗng."}),(0,n.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,n.jsx)("span",{className:"text-sm font-medium",children:"Model được ph\xe9p d\xf9ng"}),(0,n.jsx)(a.$n,{size:"sm",variant:"outline",onClick:()=>u(!0),children:"Th\xeam model"})]}),0===p.length?(0,n.jsx)("div",{className:"rounded-xl border border-dashed border-border p-4 text-sm text-text-muted",children:"Chưa chọn model n\xe0o. H\xe3y th\xeam \xedt nhất một model trước khi lưu."}):(0,n.jsx)("div",{className:"flex flex-wrap gap-2",children:p.map(e=>(0,n.jsxs)("button",{type:"button",onClick:()=>b(e),className:"rounded-full border border-primary/30 bg-primary/10 px-2 py-1 font-mono text-xs text-primary transition hover:bg-red-500/10 hover:text-red-600",title:"Bấm để gỡ model n\xe0y",children:[e," \xd7"]},e))}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"ghost",onClick:o,children:"Hủy"}),(0,n.jsx)(a.$n,{onClick:x,disabled:m||0===p.length,children:m?"Đang lưu...":"Lưu danh s\xe1ch model"})]})]})}),(0,n.jsx)(a.rq,{isOpen:h,onClose:()=>u(!1),onSelect:e=>{let t=e?.value||e?.name||e;t&&l(e=>c([...e,t]))},onDeselect:b,activeProviders:i,modelAliases:d,title:"Chọn model được ph\xe9p d\xf9ng",addedModelValues:p,closeOnSelect:!1})]})}function j({active:e}){return e?(0,n.jsx)("span",{className:"inline-flex items-center rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2 py-1 text-xs font-medium text-emerald-700 dark:text-emerald-300",children:"Đang bật"}):(0,n.jsx)("span",{className:"inline-flex items-center rounded-full border border-red-500/30 bg-red-500/10 px-2 py-1 text-xs font-medium text-red-700 dark:text-red-300",children:"Đ\xe3 tắt"})}function k({label:e,value:t,hint:s}){return(0,n.jsxs)("div",{className:"rounded-2xl border border-border bg-surface/70 p-4",children:[(0,n.jsx)("div",{className:"text-xs font-medium uppercase tracking-wide text-text-muted",children:e}),(0,n.jsx)("div",{className:"mt-2 text-2xl font-semibold text-text-main",children:t}),s?(0,n.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:s}):null]})}function v({pagination:e,pageSize:t,onPageChange:s,onPageSizeChange:r,loading:l}){let i=Number(e?.page||1),d=Number(e?.totalPages||1),o=Number(e?.total||0),c=0===o?0:(i-1)*t+1,x=Math.min(o,i*t);return(0,n.jsxs)("div",{className:"flex flex-col gap-3 border-t border-border px-4 py-3 md:flex-row md:items-center md:justify-between",children:[(0,n.jsxs)("div",{className:"text-sm text-text-muted",children:["Hiển thị ",(0,n.jsx)("b",{children:c}),"–",(0,n.jsx)("b",{children:x})," / ",(0,n.jsx)("b",{children:o})," API keys"]}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,n.jsxs)("select",{value:t,onChange:e=>r(Number(e.target.value)),className:"rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary",disabled:l,children:[(0,n.jsx)("option",{value:25,children:"25 / trang"}),(0,n.jsx)("option",{value:50,children:"50 / trang"}),(0,n.jsx)("option",{value:100,children:"100 / trang"})]}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>s(1),disabled:l||i<=1,children:"Đầu"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>s(Math.max(1,i-1)),disabled:l||i<=1,children:"Trước"}),(0,n.jsxs)("span",{className:"rounded-xl border border-border bg-surface px-3 py-2 text-sm",children:["Trang ",i,"/",d]}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>s(Math.min(d,i+1)),disabled:l||i>=d,children:"Sau"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>s(d),disabled:l||i>=d,children:"Cuối"})]})]})}function N({keys:e,visibleKeys:t,copied:s,copy:r,isAdmin:l,onToggleVisible:i,onToggleActive:d,onApiTest:o,onRename:x,onRotate:m,onEditModels:h,onEditPolicy:b,onAssignOwner:g,onDelete:f}){return(0,n.jsx)("div",{className:"overflow-hidden rounded-2xl border border-border",children:(0,n.jsx)("div",{className:"overflow-x-auto",children:(0,n.jsxs)("table",{className:"min-w-full divide-y divide-border text-sm",children:[(0,n.jsx)("thead",{className:"bg-surface/80 text-left text-xs uppercase tracking-wide text-text-muted",children:(0,n.jsxs)("tr",{children:[(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"T\xean / Key"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Trạng th\xe1i"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Owner"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Model"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Policy"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 font-medium",children:"Ng\xe0y tạo"}),(0,n.jsx)("th",{className:"whitespace-nowrap px-4 py-3 text-right font-medium",children:"Thao t\xe1c"})]})}),(0,n.jsx)("tbody",{className:"divide-y divide-border bg-background",children:e.map(e=>{var y;let k=t.has(e.id),v=e.ownerUser||e.createdByUser||"chưa g\xe1n",N=c(e.allowedModels),w=u(e.limits),C=p(e.limits||{});return(0,n.jsxs)("tr",{className:"align-top transition hover:bg-surface/50",children:[(0,n.jsxs)("td",{className:"min-w-[280px] px-4 py-4",children:[(0,n.jsx)("div",{className:"font-medium text-text-main",children:e.name||"API Key"}),(0,n.jsxs)("div",{className:"mt-2 flex max-w-[380px] items-center gap-2 rounded-xl border border-border bg-surface px-3 py-2 font-mono text-xs text-text-main",children:[(0,n.jsx)("span",{className:"min-w-0 flex-1 truncate",children:k?e.key:(y=e.key)?y.length>12?`${y.slice(0,8)}...${y.slice(-4)}`:y:""}),(0,n.jsx)("button",{type:"button",className:"text-primary hover:underline",onClick:()=>i(e.id),children:k?"Ẩn":"Hiện"})]}),e.createdByUser?(0,n.jsxs)("div",{className:"mt-2 text-xs text-text-muted",children:["Tạo bởi: ",e.createdByUser]}):null]}),(0,n.jsx)("td",{className:"whitespace-nowrap px-4 py-4",children:(0,n.jsxs)("div",{className:"flex items-center gap-3",children:[(0,n.jsx)(j,{active:!!e.isActive}),(0,n.jsx)(a.lM,{checked:!!e.isActive,onChange:t=>d(e.id,t)})]})}),(0,n.jsx)("td",{className:"min-w-[160px] px-4 py-4",children:(0,n.jsx)("div",{className:"break-all text-sm text-text-main",children:v})}),(0,n.jsx)("td",{className:"min-w-[220px] px-4 py-4",children:N.length>0?(0,n.jsxs)("div",{className:"flex flex-wrap gap-1.5",children:[N.slice(0,3).map(e=>(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1 font-mono text-xs",children:e},e)),N.length>3?(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1 text-xs",children:["+",N.length-3]}):null]}):(0,n.jsx)("span",{className:"rounded-full border border-amber-500/30 bg-amber-500/10 px-2 py-1 text-xs text-amber-700 dark:text-amber-300",children:"Legacy full access"})}),(0,n.jsx)("td",{className:"min-w-[220px] px-4 py-4",children:w?(0,n.jsxs)("div",{className:"flex flex-wrap gap-1.5 text-xs",children:[(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:C.enabled?"bật":"tắt"}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:[C.requestsPerMinute||"∞","/ph\xfat"]}),(0,n.jsxs)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:[C.promptCharsMax||"∞"," chars"]}),C.forceThinkingOff?(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:"thinking off"}):null,C.allowedIpCidrs.length>0?(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1",children:"IP locked"}):null]}):(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-2 py-1 text-xs text-text-muted",children:"chưa set"})}),(0,n.jsx)("td",{className:"min-w-[150px] px-4 py-4 text-xs text-text-muted",children:function(e){if(!e)return"kh\xf4ng r\xf5";try{return new Date(e).toLocaleString()}catch{return String(e)}}(e.createdAt)}),(0,n.jsx)("td",{className:"min-w-[260px] px-4 py-4",children:(0,n.jsxs)("div",{className:"flex flex-wrap justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>r(e.key,e.id),children:s===e.id?"Đ\xe3 copy":"Copy"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>o(e),children:"Test"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>x(e.id,e.name),children:"Đổi t\xean"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>m(e),children:"Đổi key"}),l?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>h(e),children:"Models"}):null,l?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>b(e),children:"Policy"}):null,l?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>g(e.id,v),children:"Owner"}):null,(0,n.jsx)(a.$n,{variant:"danger",size:"sm",onClick:()=>f(e.id),children:"X\xf3a"})]})})]},e.id)})})]})})})}function w(){let e,t,[s,x]=(0,r.useState)([]),[m,h]=(0,r.useState)(!0),[g,j]=(0,r.useState)(""),[w,C]=(0,r.useState)(!1),[P,A]=(0,r.useState)(""),[S,I]=(0,r.useState)(""),[T,$]=(0,r.useState)(""),[M,K]=(0,r.useState)(""),[O,z]=(0,r.useState)(new Set),[D,q]=(0,r.useState)(null),[E,L]=(0,r.useState)([]),[B,H]=(0,r.useState)(""),[R,U]=(0,r.useState)(!1),[_,F]=(0,r.useState)(!1),[X,Z]=(0,r.useState)(""),[J,V]=(0,r.useState)(""),[Y,G]=(0,r.useState)(!1),[W,Q]=(0,r.useState)(d),[ee,et]=(0,r.useState)(d),[es,en]=(0,r.useState)(!1),[er,ea]=(0,r.useState)(!1),[el,ei]=(0,r.useState)(!1),[ed,eo]=(0,r.useState)([]),[ec,ex]=(0,r.useState)({}),[em,eh]=(0,r.useState)(!1),[eu,ep]=(0,r.useState)(!1),[eb,eg]=(0,r.useState)(null),[ef,ey]=(0,r.useState)([]),[ej,ek]=(0,r.useState)(!1),[ev,eN]=(0,r.useState)(null),[ew,eC]=(0,r.useState)(d),[eP,eA]=(0,r.useState)(!1),[eS,eI]=(0,r.useState)(2),[eT,e$]=(0,r.useState)(0),[eM,eK]=(0,r.useState)(0),[eO,ez]=(0,r.useState)(""),[eD,eq]=(0,r.useState)(null),[eE,eL]=(0,r.useState)(""),[eB,eH]=(0,r.useState)(""),[eR,eU]=(0,r.useState)("all"),[e_,eF]=(0,r.useState)(1),[eX,eZ]=(0,r.useState)(25),[eJ,eV]=(0,r.useState)({page:1,pageSize:25,total:0,totalAll:0,totalPages:1,status:"all",search:""}),{copied:eY,copy:eG}=(0,i.C)(),{isAdmin:eW,isMonitorAdmin:eQ,canManageApiKeys:e0,userId:e1}=(0,l.s)(),e2=eW||eQ||e0,e3=Number.isFinite(Number(eS))?Number(eS):2,e4=Number.isFinite(Number(eT))?Number(eT):s.length,e5=Number.isFinite(Number(eM))?Number(eM):Number(eJ.totalAll||eJ.total||0),e8=Number(eJ.total||0),e6=!e2&&e4>=e3,e7=eO?`${eO}/v1`:"/v1",e9=eO?`${eO}/v1/chat/completions`:"/v1/chat/completions",te=(e=c(eD?.allowedModels)[0],t=String(X||"").trim(),e||t||"YOUR_MODEL"),tt=eD?function({endpoint:e,apiKey:t,model:s}){let n=String(e||"/v1/chat/completions").replace(/"/g,""),r=String(t||"YOUR_API_KEY").replace(/"/g,""),a=JSON.stringify({model:String(s||"YOUR_MODEL"),messages:[{role:"user",content:"Say hi.\nReply in one short sentence."}],temperature:.2,stream:!1}).replace(/"/g,'\\"');return`curl.exe -X POST "${n}" ^
|
|
2
2
|
-H "Authorization: Bearer ${r}" ^
|
|
3
3
|
-H "Content-Type: application/json" ^
|
|
4
|
-
-d "${a}"`}({endpoint:
|
|
5
|
-
C\xf3 thể d\xf9ng n\xfat Đổi key để xoay sang key mới m\xe0 kh\xf4ng cần x\xf3a/tạo lại.`);F(!0),j("");try{let e=eW?o(T||S||eQ):void 0,t=await fetch("/api/keys",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:P.trim(),ownerUser:e})}),s=await t.json().catch(()=>({}));if(!t.ok)throw Error(s.error||"Kh\xf4ng tạo được API key");K(s.key),A(""),$(""),C(!1),eF(1),await tn()}catch(e){j(e.message||"Kh\xf4ng tạo được API key")}finally{F(!1)}}},to=async(e,t)=>{let s=await fetch(`/api/keys/${e}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),n=await s.json().catch(()=>({}));return s.ok?(await tn(),!0):(j(n.error||"Kh\xf4ng cập nhật được API key"),!1)},tc=async()=>{if(!eb)return;let e=c(ef);if(0===e.length)return void j("H\xe3y chọn \xedt nhất một model trước khi lưu quyền truy cập API key.");ek(!0),j("");try{await to(eb.id,{allowedModels:e})&&(eg(null),ey([]))}finally{ek(!1)}},tx=async e=>{if(ev){eA(!0),j("");try{await to(ev.id,{limits:p(e)})&&(eN(null),eC(d))}finally{eA(!1)}}},tm=async()=>{if(ev){eA(!0),j("");try{await to(ev.id,{limits:{}})&&(eN(null),eC(d))}finally{eA(!1)}}};return(0,n.jsxs)("div",{className:"space-y-6",children:[(0,n.jsxs)("div",{className:"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h1",{className:"text-2xl font-semibold text-text-main",children:"Quản l\xfd API Keys"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:eW?"Bảng quản trị API key c\xf3 t\xecm kiếm, lọc trạng th\xe1i v\xe0 ph\xe2n trang để kh\xf4ng render qu\xe1 nhiều key c\xf9ng l\xfac.":`Bạn c\xf3 thể quản l\xfd API key của t\xe0i khoản m\xecnh. Mỗi user thường sở hữu tối đa ${e0} API keys. D\xf9ng n\xfat Đổi key để xoay sang key mới m\xe0 kh\xf4ng cần x\xf3a/tạo lại.`})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)(a.$n,{variant:"outline",onClick:tn,disabled:m,children:m?"Đang tải...":"Refresh"}),(0,n.jsx)(a.$n,{onClick:()=>{C(!0),!S&&eQ&&I(eQ)},disabled:e4,children:"Tạo API Key"})]})]}),g?(0,n.jsx)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 p-3 text-sm text-red-600 whitespace-pre-line",children:g}):null,(0,n.jsxs)("div",{className:"grid gap-3 md:grid-cols-3",children:[(0,n.jsx)(k,{label:"Tổng API keys",value:e2,hint:eW?"To\xe0n hệ thống":`${e1}/${e0} key của bạn`}),(0,n.jsx)(k,{label:"Đang hiển thị",value:e3,hint:ts?"Theo bộ lọc hiện tại":"Kh\xf4ng filter"}),(0,n.jsx)(k,{label:"Page size",value:eX,hint:"Chỉ tải số d\xf2ng của trang hiện tại"})]}),eW?null:(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-medium",children:"Giới hạn API key theo user"}),(0,n.jsxs)("p",{className:"text-sm text-text-muted",children:["T\xe0i khoản của bạn đang c\xf3 ",e1,"/",e0," API keys. Key bị disabled vẫn được t\xednh v\xe0o giới hạn."]})]}),(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-3 py-1 text-sm",children:e4?"Đ\xe3 đạt giới hạn":"C\xf2n c\xf3 thể tạo th\xeam"})]})}),(0,n.jsxs)("div",{className:"grid gap-4 xl:grid-cols-2",children:[(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-medium",children:"Default model cho API key mới"}),(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"API key mới sẽ mặc định chỉ được d\xf9ng model n\xe0y. Cần cấu h\xecnh default model trước khi tạo API key."})]}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[X?(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-3 py-1 font-mono text-sm",children:X}):(0,n.jsx)("span",{className:"text-sm text-red-600",children:"Chưa cấu h\xecnh default model"}),eW?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>{ei(!0),tr()},children:J||"Chọn default model..."}),(0,n.jsx)(a.$n,{size:"sm",onClick:tl,disabled:!te||Y||!J.trim(),children:Y?"Đang lưu...":"Lưu"})]}):null]}),eW?(0,n.jsx)("p",{className:"text-xs text-text-muted",children:eu?"Đang tải danh s\xe1ch model...":"Danh s\xe1ch model chỉ tải khi mở bộ chọn để trang load nhanh hơn."}):null]})}),(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsxs)("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-medium",children:"Default policy cho API key mới"}),(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"Policy n\xe0y được tự động g\xe1n cho key mới. Policy ri\xeang từng key vẫn c\xf3 thể override sau khi tạo."})]}),eW?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>{et(p(W||d,d)),ea(!0)},children:"Chỉnh default policy"}):null]}),(0,n.jsx)(b,{limits:W})]})})]}),(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-medium",children:"Th\xf4ng tin API endpoint"}),(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"D\xf9ng API key b\xean dưới để gọi gateway theo chuẩn OpenAI-compatible. Endpoint lấy theo domain hiện tại của dashboard."})]}),(0,n.jsxs)("div",{className:"grid gap-3 md:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Base URL"}),(0,n.jsx)("div",{className:"mt-1 break-all font-mono text-sm",children:e5})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Chat Completions"}),(0,n.jsx)("div",{className:"mt-1 break-all font-mono text-sm",children:e8})]})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>eG(e5,"api-base-url"),children:"api-base-url"===eY?"Đ\xe3 copy Base URL":"Copy Base URL"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>eG(e8,"api-chat-endpoint"),children:"api-chat-endpoint"===eY?"Đ\xe3 copy Endpoint":"Copy Endpoint"})]})]})}),M?(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsx)("h3",{className:"font-medium",children:"Đ\xe3 tạo API key"}),(0,n.jsx)("pre",{className:"overflow-auto rounded-xl border border-border bg-surface p-3 text-sm",children:M}),(0,n.jsxs)("p",{className:"text-sm text-text-muted",children:["H\xe3y copy ngay. Key mới mặc định chỉ được d\xf9ng ",X||"default model"," v\xe0 default policy đang cấu h\xecnh trong Dashboard, trừ khi admin chỉnh quyền model/policy."]}),(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsx)(a.$n,{size:"sm",onClick:()=>eG(M,"created"),children:"created"===eY?"Đ\xe3 copy":"Copy"}),(0,n.jsx)(a.$n,{size:"sm",variant:"ghost",onClick:()=>K(""),children:"Đ\xf3ng"})]})]})}):null,(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsxs)("div",{className:"flex flex-col gap-3 xl:flex-row xl:items-end xl:justify-between",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-lg font-semibold text-text-main",children:"Danh s\xe1ch API keys"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"T\xecm theo t\xean key, owner, model, id hoặc một phần API key. Backend chỉ trả về page hiện tại."})]}),(0,n.jsxs)("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-center",children:[(0,n.jsx)("input",{value:eE,onChange:e=>eL(e.target.value),placeholder:"T\xecm API key, owner, model...",className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary sm:w-80"}),(0,n.jsxs)("select",{value:eR,onChange:e=>{eU(e.target.value),eF(1)},className:"rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary",children:[(0,n.jsx)("option",{value:"all",children:"Tất cả trạng th\xe1i"}),(0,n.jsx)("option",{value:"active",children:"Chỉ key đang bật"}),(0,n.jsx)("option",{value:"inactive",children:"Chỉ key đ\xe3 tắt"})]}),ts?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>{eL(""),eH(""),eU("all"),eF(1)},children:"X\xf3a lọc"}):null]})]}),m?(0,n.jsx)("div",{className:"rounded-2xl border border-dashed border-border p-8 text-center text-sm text-text-muted",children:"Đang tải API keys..."}):0===s.length?(0,n.jsx)("div",{className:"rounded-2xl border border-dashed border-border p-8 text-center text-sm text-text-muted",children:ts?"Kh\xf4ng t\xecm thấy API key ph\xf9 hợp bộ lọc.":"Chưa c\xf3 API key n\xe0o."}):(0,n.jsx)(N,{keys:s,visibleKeys:O,copied:eY,copy:eG,isAdmin:eW,onToggleVisible:e=>{z(t=>{let s=new Set(t);return s.has(e)?s.delete(e):s.add(e),s})},onToggleActive:(e,t)=>to(e,{isActive:t}),onApiTest:eq,onRename:(e,t)=>{let s=prompt("T\xean API key mới",t||"");s?.trim()&&to(e,{name:s.trim()})},onRotate:e=>{e?.id&&q({title:"Đổi API key",message:"Hệ thống sẽ tạo chuỗi API key mới cho record n\xe0y v\xe0 giữ nguy\xean t\xean, owner, model, policy. Key cũ sẽ hết hiệu lực ngay sau khi đổi.",onConfirm:async()=>{q(null),j("");let t=await fetch(`/api/keys/${e.id}/rotate`,{method:"POST"}),s=await t.json().catch(()=>({}));if(!t.ok)return void j(s.error||"Kh\xf4ng đổi được API key");let n=s.rotatedKey||s.key?.key||"";n&&K(n),await tn()}})},onEditModels:e=>{eW&&(eg(e),ey(c(e.allowedModels)),tr())},onEditPolicy:e=>{eW&&(eN(e),eC(u(e.limits)?p(e.limits):d))},onAssignOwner:(e,t)=>{if(!eW)return;let s=prompt("G\xe1n owner username/email",t||eQ||"");null!==s&&to(e,{ownerUser:o(s)})},onDelete:e=>{q({title:"X\xf3a API Key",message:"Bạn chắc chắn muốn x\xf3a API key n\xe0y? Thao t\xe1c n\xe0y kh\xf4ng thể ho\xe0n t\xe1c.",onConfirm:async()=>{q(null),(await fetch(`/api/keys/${e}`,{method:"DELETE"})).ok&&await tn()}})}}),(0,n.jsx)(v,{pagination:eJ,pageSize:eX,onPageChange:eF,onPageSizeChange:e=>{eZ(e),eF(1)},loading:m})]})}),(0,n.jsx)(a.aF,{isOpen:w,onClose:()=>C(!1),title:"Tạo API Key",size:"lg",children:(0,n.jsxs)("div",{className:"space-y-4",children:[X.trim()?e4?(0,n.jsxs)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 p-3 text-sm text-red-600",children:["Bạn đ\xe3 đạt giới hạn ",e0," API keys. H\xe3y x\xf3a bớt key cũ trước khi tạo key mới."]}):(0,n.jsxs)("p",{className:"text-sm text-text-muted",children:["Key n\xe0y sẽ được tạo với quyền d\xf9ng default model: ",(0,n.jsx)("b",{children:X})," v\xe0 default policy đang cấu h\xecnh trong Dashboard."]}):(0,n.jsx)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 p-3 text-sm text-red-600",children:"Admin cần cấu h\xecnh default model trước khi tạo API key."}),(0,n.jsxs)("label",{className:"block",children:[(0,n.jsx)("span",{className:"mb-1 block text-xs font-medium text-text-muted",children:"T\xean API key"}),(0,n.jsx)("input",{value:P,onChange:e=>A(e.target.value),placeholder:"VD: VSCode, LibreChat, team-user",className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none focus:border-primary"})]}),eW?(0,n.jsxs)("div",{className:"space-y-3 rounded-xl border border-border p-3",children:[(0,n.jsx)("div",{className:"text-sm font-medium",children:"Owner user"}),(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsx)("input",{value:B,onChange:e=>H(e.target.value),placeholder:"Nhập từ kh\xf3a rồi bấm Tải",className:"min-w-0 flex-1 rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none focus:border-primary"}),(0,n.jsx)(a.$n,{variant:"outline",onClick:()=>ta(B),disabled:R,children:R?"Đang tải":"Tải LDAP"})]}),(0,n.jsxs)("select",{value:S,onChange:e=>I(e.target.value),className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary",children:[(0,n.jsxs)("option",{value:eQ||"",children:["G\xe1n cho t\xf4i (",eQ||"local",")"]}),e9.map(e=>(0,n.jsx)("option",{value:e.id,children:e.label},e.id))]}),(0,n.jsx)("input",{value:T,onChange:e=>$(e.target.value),placeholder:"username hoặc email, kh\xf4ng bắt buộc",className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none focus:border-primary"}),(0,n.jsx)("p",{className:"text-xs text-text-muted",children:"LDAP kh\xf4ng tự tải khi mở trang để giảm thời gian load. C\xf3 thể nhập owner thủ c\xf4ng hoặc nhập từ kh\xf3a rồi bấm Tải LDAP."})]}):(0,n.jsxs)("p",{className:"rounded-xl border border-border bg-surface p-3 text-sm text-text-muted",children:["Owner: ",eQ||"user hiện tại"]}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"ghost",onClick:()=>C(!1),children:"Hủy"}),(0,n.jsx)(a.$n,{onClick:td,disabled:tt,children:_?"Đang tạo...":"Tạo"})]})]})}),(0,n.jsx)(a.aF,{isOpen:!!eD,onClose:()=>eq(null),title:"API Test bằng curl Windows",size:"xl",children:(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"Lệnh dưới đ\xe2y gọi thử endpoint Chat Completions bằng API key đang chọn v\xe0 đ\xe3 nh\xfang sẵn Bearer token."}),(0,n.jsxs)("div",{className:"grid gap-3 md:grid-cols-3",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"API Key"}),(0,n.jsx)("div",{className:"mt-1 text-sm",children:eD?.name||"API Key"})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Endpoint"}),(0,n.jsx)("div",{className:"mt-1 break-all font-mono text-sm",children:e8})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Model test"}),(0,n.jsx)("div",{className:"mt-1 break-all font-mono text-sm",children:e6})]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"mb-1 text-xs font-medium text-text-muted",children:"Lệnh curl cho Windows CMD"}),(0,n.jsx)("pre",{className:"overflow-auto rounded-xl border border-border bg-surface p-3 text-xs",children:e7})]}),(0,n.jsx)("p",{className:"text-xs text-text-muted",children:"D\xe1n lệnh v\xe0o CMD hoặc Windows Terminal để test nhanh. Nếu domain dashboard chạy sau reverse proxy, endpoint sẽ d\xf9ng đ\xfang domain đang mở tr\xean tr\xecnh duyệt."}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"ghost",onClick:()=>eq(null),children:"Đ\xf3ng"}),(0,n.jsx)(a.$n,{onClick:()=>eG(e7,`api-test-curl-${eD?.id||"current"}`),children:eY===`api-test-curl-${eD?.id||"current"}`?"Đ\xe3 copy":"Copy lệnh curl"})]})]})}),(0,n.jsx)(y,{open:!!eb,keyName:eb?.name,models:ef,setModels:ey,activeProviders:ed,modelAliases:ec,onClose:()=>{eg(null),ey([])},onSave:tc,saving:ej}),(0,n.jsx)(f,{isOpen:er,keyName:"Default cho API key mới",policy:ee,setPolicy:et,onClose:()=>{ea(!1),et(W||d)},onSave:ti,saving:es}),(0,n.jsx)(f,{isOpen:!!ev,keyName:ev?.name,policy:ew,setPolicy:eC,onClose:()=>{eN(null),eC(d)},onSave:tx,onClear:tm,saving:eP}),(0,n.jsx)(a.rq,{isOpen:el,onClose:()=>ei(!1),onSelect:e=>{let t=String(e?.value||e?.name||e||"").trim();t&&(V(t),ei(!1))},activeProviders:ed,modelAliases:ec,title:"Chọn default model cho API key",selectedModel:J,addedModelValues:J?[J]:[]}),D?(0,n.jsx)(a.uo,{isOpen:!!D,onClose:()=>q(null),onConfirm:D.onConfirm,title:D.title,message:D.message,confirmText:"X\xf3a",cancelText:"Hủy",variant:"danger"}):null]})}},84223:(e,t,s)=>{Promise.resolve().then(s.bind(s,56484))}},e=>{e.O(0,[2574,3862,1051,1321,5497,8441,3794,7358],()=>e(e.s=84223)),_N_E=e.O()}]);
|
|
4
|
+
-d "${a}"`}({endpoint:e9,apiKey:eD.key,model:te}):"",ts=(0,r.useMemo)(()=>{let e=new Map;for(let t of E){let s=o(t.username||t.email||t.userPrincipalName||t.sAMAccountName);s&&e.set(s,{id:s,label:`${t.displayName||t.username||s}${t.email?` \xb7 ${t.email}`:""}`})}for(let t of s){let s=o(t.ownerUser||t.createdByUser);s&&!e.has(s)&&e.set(s,{id:s,label:s})}return e1&&!e.has(e1)&&e.set(e1,{id:e1,label:`${e1} (t\xf4i)`}),[...e.values()].sort((e,t)=>e.label.localeCompare(t.label))},[E,s,e1]),tn=J!==X,tr=_||!P.trim()||!X.trim()||e6,ta=!!eB||"all"!==eR,tl=async()=>{h(!0),j("");try{let e=new URLSearchParams;e.set("page",String(e_)),e.set("pageSize",String(eX)),eB&&e.set("q",eB),"all"!==eR&&e.set("status",eR);let t=await fetch(`/api/keys?${e.toString()}`,{cache:"no-store"}),s=await t.json().catch(()=>({}));if(!t.ok)throw Error(s.error||"Kh\xf4ng tải được danh s\xe1ch API keys");let n=s.keys||[],r=s.pagination||{page:e_,pageSize:eX,total:n.length,totalAll:n.length,totalPages:1,search:eB,status:eR};if(0===n.length&&Number(r.total||0)>0&&e_>1)return void eF(Math.max(1,Number(r.totalPages||1)));let a=String(s.apiKeyDefaultModel||"").trim();x(n),eV(r),eK(s.apiKeyTotal??r.totalAll??r.total??n.length);let l=p(s.apiKeyDefaultPolicy||d,d);Z(a),V(a),Q(l),et(l),eI(s.apiKeyLimit??2),e$(s.apiKeyCount??r.totalAll??n.length)}catch(e){j(e.message||"Kh\xf4ng tải được danh s\xe1ch API keys")}finally{h(!1)}};(0,r.useEffect)(()=>{ez(window.location.origin)},[]),(0,r.useEffect)(()=>{let e=setTimeout(()=>{eF(1),eH(eE.trim())},350);return()=>clearTimeout(e)},[eE]),(0,r.useEffect)(()=>{tl()},[e_,eX,eB,eR]),(0,r.useEffect)(()=>{!S&&e1&&I(e1)},[e1,S]);let ti=async()=>{if(!em&&!eu){ep(!0);try{let[e,t]=await Promise.allSettled([fetch("/api/providers",{cache:"no-store"}),fetch("/api/models/alias",{cache:"no-store"})]);if("fulfilled"===e.status&&e.value.ok){let t=await e.value.json().catch(()=>({}));eo(t.connections||[])}if("fulfilled"===t.status&&t.value.ok){let e=await t.value.json().catch(()=>({}));ex(e.aliases||{})}eh(!0)}catch{}finally{ep(!1)}}},td=async(e=B)=>{if(e2){U(!0);try{let t=await fetch(`/api/auth/ldap/users?q=${encodeURIComponent(e||"")}`,{cache:"no-store"}),s=await t.json().catch(()=>({}));t.ok&&L(s.users||[])}catch{}finally{U(!1)}}},to=async()=>{if(e2&&J.trim()){G(!0),j("");try{let e=await fetch("/api/keys",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKeyDefaultModel:J.trim()})}),t=await e.json().catch(()=>({}));if(!e.ok)throw Error(t.error||"Kh\xf4ng lưu được default model");let s=String(t.apiKeyDefaultModel||"").trim(),n=p(t.apiKeyDefaultPolicy||d,d);Z(s),V(s),Q(n),et(n)}catch(e){j(e.message||"Kh\xf4ng lưu được default model")}finally{G(!1)}}},tc=async e=>{if(!e2)return;let t=p(e,d);en(!0),j("");try{let e=await fetch("/api/keys",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKeyDefaultPolicy:t})}),s=await e.json().catch(()=>({}));if(!e.ok)throw Error(s.error||"Kh\xf4ng lưu được default policy");let n=p(s.apiKeyDefaultPolicy||t,d);Q(n),et(n),ea(!1)}catch(e){j(e.message||"Kh\xf4ng lưu được default policy")}finally{en(!1)}},tx=async()=>{if(P.trim()){if(!X.trim())return void j("Admin cần cấu h\xecnh default model trước khi tạo API key.");if(e6)return void j(`Mỗi user chỉ được tạo tối đa ${e3} API keys.
|
|
5
|
+
C\xf3 thể d\xf9ng n\xfat Đổi key để xoay sang key mới m\xe0 kh\xf4ng cần x\xf3a/tạo lại.`);F(!0),j("");try{let e=e2?o(T||S||e1):void 0,t=await fetch("/api/keys",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:P.trim(),ownerUser:e})}),s=await t.json().catch(()=>({}));if(!t.ok)throw Error(s.error||"Kh\xf4ng tạo được API key");K(s.key),A(""),$(""),C(!1),eF(1),await tl()}catch(e){j(e.message||"Kh\xf4ng tạo được API key")}finally{F(!1)}}},tm=async(e,t)=>{let s=await fetch(`/api/keys/${e}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),n=await s.json().catch(()=>({}));return s.ok?(await tl(),!0):(j(n.error||"Kh\xf4ng cập nhật được API key"),!1)},th=async()=>{if(!eb)return;let e=c(ef);if(0===e.length)return void j("H\xe3y chọn \xedt nhất một model trước khi lưu quyền truy cập API key.");ek(!0),j("");try{await tm(eb.id,{allowedModels:e})&&(eg(null),ey([]))}finally{ek(!1)}},tu=async e=>{if(ev){eA(!0),j("");try{await tm(ev.id,{limits:p(e)})&&(eN(null),eC(d))}finally{eA(!1)}}},tp=async()=>{if(ev){eA(!0),j("");try{await tm(ev.id,{limits:{}})&&(eN(null),eC(d))}finally{eA(!1)}}};return(0,n.jsxs)("div",{className:"space-y-6",children:[(0,n.jsxs)("div",{className:"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h1",{className:"text-2xl font-semibold text-text-main",children:"Quản l\xfd API Keys"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:e2?"Bảng quản trị API key c\xf3 t\xecm kiếm, lọc trạng th\xe1i v\xe0 ph\xe2n trang để kh\xf4ng render qu\xe1 nhiều key c\xf9ng l\xfac.":`Bạn c\xf3 thể quản l\xfd API key của t\xe0i khoản m\xecnh. Mỗi user thường sở hữu tối đa ${e3} API keys. D\xf9ng n\xfat Đổi key để xoay sang key mới m\xe0 kh\xf4ng cần x\xf3a/tạo lại.`})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)(a.$n,{variant:"outline",onClick:tl,disabled:m,children:m?"Đang tải...":"Refresh"}),(0,n.jsx)(a.$n,{onClick:()=>{C(!0),!S&&e1&&I(e1)},disabled:e6,children:"Tạo API Key"})]})]}),g?(0,n.jsx)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 p-3 text-sm text-red-600 whitespace-pre-line",children:g}):null,(0,n.jsxs)("div",{className:"grid gap-3 md:grid-cols-3",children:[(0,n.jsx)(k,{label:"Tổng API keys",value:e5,hint:e2?"To\xe0n hệ thống":`${e4}/${e3} key của bạn`}),(0,n.jsx)(k,{label:"Đang hiển thị",value:e8,hint:ta?"Theo bộ lọc hiện tại":"Kh\xf4ng filter"}),(0,n.jsx)(k,{label:"Page size",value:eX,hint:"Chỉ tải số d\xf2ng của trang hiện tại"})]}),e2?null:(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-medium",children:"Giới hạn API key theo user"}),(0,n.jsxs)("p",{className:"text-sm text-text-muted",children:["T\xe0i khoản của bạn đang c\xf3 ",e4,"/",e3," API keys. Key bị disabled vẫn được t\xednh v\xe0o giới hạn."]})]}),(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-3 py-1 text-sm",children:e6?"Đ\xe3 đạt giới hạn":"C\xf2n c\xf3 thể tạo th\xeam"})]})}),(0,n.jsxs)("div",{className:"grid gap-4 xl:grid-cols-2",children:[(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-medium",children:"Default model cho API key mới"}),(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"API key mới sẽ mặc định chỉ được d\xf9ng model n\xe0y. Cần cấu h\xecnh default model trước khi tạo API key."})]}),(0,n.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[X?(0,n.jsx)("span",{className:"rounded-full border border-border bg-surface px-3 py-1 font-mono text-sm",children:X}):(0,n.jsx)("span",{className:"text-sm text-red-600",children:"Chưa cấu h\xecnh default model"}),e2?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>{ei(!0),ti()},children:J||"Chọn default model..."}),(0,n.jsx)(a.$n,{size:"sm",onClick:to,disabled:!tn||Y||!J.trim(),children:Y?"Đang lưu...":"Lưu"})]}):null]}),e2?(0,n.jsx)("p",{className:"text-xs text-text-muted",children:eu?"Đang tải danh s\xe1ch model...":"Danh s\xe1ch model chỉ tải khi mở bộ chọn để trang load nhanh hơn."}):null]})}),(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsxs)("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-medium",children:"Default policy cho API key mới"}),(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"Policy n\xe0y được tự động g\xe1n cho key mới. Policy ri\xeang từng key vẫn c\xf3 thể override sau khi tạo."})]}),e2?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>{et(p(W||d,d)),ea(!0)},children:"Chỉnh default policy"}):null]}),(0,n.jsx)(b,{limits:W})]})})]}),(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"font-medium",children:"Th\xf4ng tin API endpoint"}),(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"D\xf9ng API key b\xean dưới để gọi gateway theo chuẩn OpenAI-compatible. Endpoint lấy theo domain hiện tại của dashboard."})]}),(0,n.jsxs)("div",{className:"grid gap-3 md:grid-cols-2",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Base URL"}),(0,n.jsx)("div",{className:"mt-1 break-all font-mono text-sm",children:e7})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Chat Completions"}),(0,n.jsx)("div",{className:"mt-1 break-all font-mono text-sm",children:e9})]})]}),(0,n.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>eG(e7,"api-base-url"),children:"api-base-url"===eY?"Đ\xe3 copy Base URL":"Copy Base URL"}),(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>eG(e9,"api-chat-endpoint"),children:"api-chat-endpoint"===eY?"Đ\xe3 copy Endpoint":"Copy Endpoint"})]})]})}),M?(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsx)("h3",{className:"font-medium",children:"Đ\xe3 tạo API key"}),(0,n.jsx)("pre",{className:"overflow-auto rounded-xl border border-border bg-surface p-3 text-sm",children:M}),(0,n.jsxs)("p",{className:"text-sm text-text-muted",children:["H\xe3y copy ngay. Key mới mặc định chỉ được d\xf9ng ",X||"default model"," v\xe0 default policy đang cấu h\xecnh trong Dashboard, trừ khi admin chỉnh quyền model/policy."]}),(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsx)(a.$n,{size:"sm",onClick:()=>eG(M,"created"),children:"created"===eY?"Đ\xe3 copy":"Copy"}),(0,n.jsx)(a.$n,{size:"sm",variant:"ghost",onClick:()=>K(""),children:"Đ\xf3ng"})]})]})}):null,(0,n.jsx)(a.Zp,{children:(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsxs)("div",{className:"flex flex-col gap-3 xl:flex-row xl:items-end xl:justify-between",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("h3",{className:"text-lg font-semibold text-text-main",children:"Danh s\xe1ch API keys"}),(0,n.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:"T\xecm theo t\xean key, owner, model, id hoặc một phần API key. Backend chỉ trả về page hiện tại."})]}),(0,n.jsxs)("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-center",children:[(0,n.jsx)("input",{value:eE,onChange:e=>eL(e.target.value),placeholder:"T\xecm API key, owner, model...",className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary sm:w-80"}),(0,n.jsxs)("select",{value:eR,onChange:e=>{eU(e.target.value),eF(1)},className:"rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary",children:[(0,n.jsx)("option",{value:"all",children:"Tất cả trạng th\xe1i"}),(0,n.jsx)("option",{value:"active",children:"Chỉ key đang bật"}),(0,n.jsx)("option",{value:"inactive",children:"Chỉ key đ\xe3 tắt"})]}),ta?(0,n.jsx)(a.$n,{variant:"outline",size:"sm",onClick:()=>{eL(""),eH(""),eU("all"),eF(1)},children:"X\xf3a lọc"}):null]})]}),m?(0,n.jsx)("div",{className:"rounded-2xl border border-dashed border-border p-8 text-center text-sm text-text-muted",children:"Đang tải API keys..."}):0===s.length?(0,n.jsx)("div",{className:"rounded-2xl border border-dashed border-border p-8 text-center text-sm text-text-muted",children:ta?"Kh\xf4ng t\xecm thấy API key ph\xf9 hợp bộ lọc.":"Chưa c\xf3 API key n\xe0o."}):(0,n.jsx)(N,{keys:s,visibleKeys:O,copied:eY,copy:eG,isAdmin:e2,onToggleVisible:e=>{z(t=>{let s=new Set(t);return s.has(e)?s.delete(e):s.add(e),s})},onToggleActive:(e,t)=>tm(e,{isActive:t}),onApiTest:eq,onRename:(e,t)=>{let s=prompt("T\xean API key mới",t||"");s?.trim()&&tm(e,{name:s.trim()})},onRotate:e=>{e?.id&&q({title:"Đổi API key",message:"Hệ thống sẽ tạo chuỗi API key mới cho record n\xe0y v\xe0 giữ nguy\xean t\xean, owner, model, policy. Key cũ sẽ hết hiệu lực ngay sau khi đổi.",onConfirm:async()=>{q(null),j("");let t=await fetch(`/api/keys/${e.id}/rotate`,{method:"POST"}),s=await t.json().catch(()=>({}));if(!t.ok)return void j(s.error||"Kh\xf4ng đổi được API key");let n=s.rotatedKey||s.key?.key||"";n&&K(n),await tl()}})},onEditModels:e=>{e2&&(eg(e),ey(c(e.allowedModels)),ti())},onEditPolicy:e=>{e2&&(eN(e),eC(u(e.limits)?p(e.limits):d))},onAssignOwner:(e,t)=>{if(!e2)return;let s=prompt("G\xe1n owner username/email",t||e1||"");null!==s&&tm(e,{ownerUser:o(s)})},onDelete:e=>{q({title:"X\xf3a API Key",message:"Bạn chắc chắn muốn x\xf3a API key n\xe0y? Thao t\xe1c n\xe0y kh\xf4ng thể ho\xe0n t\xe1c.",onConfirm:async()=>{q(null),(await fetch(`/api/keys/${e}`,{method:"DELETE"})).ok&&await tl()}})}}),(0,n.jsx)(v,{pagination:eJ,pageSize:eX,onPageChange:eF,onPageSizeChange:e=>{eZ(e),eF(1)},loading:m})]})}),(0,n.jsx)(a.aF,{isOpen:w,onClose:()=>C(!1),title:"Tạo API Key",size:"lg",children:(0,n.jsxs)("div",{className:"space-y-4",children:[X.trim()?e6?(0,n.jsxs)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 p-3 text-sm text-red-600",children:["Bạn đ\xe3 đạt giới hạn ",e3," API keys. H\xe3y x\xf3a bớt key cũ trước khi tạo key mới."]}):(0,n.jsxs)("p",{className:"text-sm text-text-muted",children:["Key n\xe0y sẽ được tạo với quyền d\xf9ng default model: ",(0,n.jsx)("b",{children:X})," v\xe0 default policy đang cấu h\xecnh trong Dashboard."]}):(0,n.jsx)("div",{className:"rounded-xl border border-red-500/30 bg-red-500/10 p-3 text-sm text-red-600",children:"Admin cần cấu h\xecnh default model trước khi tạo API key."}),(0,n.jsxs)("label",{className:"block",children:[(0,n.jsx)("span",{className:"mb-1 block text-xs font-medium text-text-muted",children:"T\xean API key"}),(0,n.jsx)("input",{value:P,onChange:e=>A(e.target.value),placeholder:"VD: VSCode, LibreChat, team-user",className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none focus:border-primary"})]}),e2?(0,n.jsxs)("div",{className:"space-y-3 rounded-xl border border-border p-3",children:[(0,n.jsx)("div",{className:"text-sm font-medium",children:"Owner user"}),(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsx)("input",{value:B,onChange:e=>H(e.target.value),placeholder:"Nhập từ kh\xf3a rồi bấm Tải",className:"min-w-0 flex-1 rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none focus:border-primary"}),(0,n.jsx)(a.$n,{variant:"outline",onClick:()=>td(B),disabled:R,children:R?"Đang tải":"Tải LDAP"})]}),(0,n.jsxs)("select",{value:S,onChange:e=>I(e.target.value),className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm text-text-main outline-none focus:border-primary",children:[(0,n.jsxs)("option",{value:e1||"",children:["G\xe1n cho t\xf4i (",e1||"local",")"]}),ts.map(e=>(0,n.jsx)("option",{value:e.id,children:e.label},e.id))]}),(0,n.jsx)("input",{value:T,onChange:e=>$(e.target.value),placeholder:"username hoặc email, kh\xf4ng bắt buộc",className:"w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none focus:border-primary"}),(0,n.jsx)("p",{className:"text-xs text-text-muted",children:"LDAP kh\xf4ng tự tải khi mở trang để giảm thời gian load. C\xf3 thể nhập owner thủ c\xf4ng hoặc nhập từ kh\xf3a rồi bấm Tải LDAP."})]}):(0,n.jsxs)("p",{className:"rounded-xl border border-border bg-surface p-3 text-sm text-text-muted",children:["Owner: ",e1||"user hiện tại"]}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"ghost",onClick:()=>C(!1),children:"Hủy"}),(0,n.jsx)(a.$n,{onClick:tx,disabled:tr,children:_?"Đang tạo...":"Tạo"})]})]})}),(0,n.jsx)(a.aF,{isOpen:!!eD,onClose:()=>eq(null),title:"API Test bằng curl Windows",size:"xl",children:(0,n.jsxs)("div",{className:"space-y-4",children:[(0,n.jsx)("p",{className:"text-sm text-text-muted",children:"Lệnh dưới đ\xe2y gọi thử endpoint Chat Completions bằng API key đang chọn v\xe0 đ\xe3 nh\xfang sẵn Bearer token."}),(0,n.jsxs)("div",{className:"grid gap-3 md:grid-cols-3",children:[(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"API Key"}),(0,n.jsx)("div",{className:"mt-1 text-sm",children:eD?.name||"API Key"})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Endpoint"}),(0,n.jsx)("div",{className:"mt-1 break-all font-mono text-sm",children:e9})]}),(0,n.jsxs)("div",{className:"rounded-xl border border-border bg-surface p-3",children:[(0,n.jsx)("div",{className:"text-xs text-text-muted",children:"Model test"}),(0,n.jsx)("div",{className:"mt-1 break-all font-mono text-sm",children:te})]})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"mb-1 text-xs font-medium text-text-muted",children:"Lệnh curl cho Windows CMD"}),(0,n.jsx)("pre",{className:"overflow-auto rounded-xl border border-border bg-surface p-3 text-xs",children:tt})]}),(0,n.jsx)("p",{className:"text-xs text-text-muted",children:"D\xe1n lệnh v\xe0o CMD hoặc Windows Terminal để test nhanh. Nếu domain dashboard chạy sau reverse proxy, endpoint sẽ d\xf9ng đ\xfang domain đang mở tr\xean tr\xecnh duyệt."}),(0,n.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,n.jsx)(a.$n,{variant:"ghost",onClick:()=>eq(null),children:"Đ\xf3ng"}),(0,n.jsx)(a.$n,{onClick:()=>eG(tt,`api-test-curl-${eD?.id||"current"}`),children:eY===`api-test-curl-${eD?.id||"current"}`?"Đ\xe3 copy":"Copy lệnh curl"})]})]})}),(0,n.jsx)(y,{open:!!eb,keyName:eb?.name,models:ef,setModels:ey,activeProviders:ed,modelAliases:ec,onClose:()=>{eg(null),ey([])},onSave:th,saving:ej}),(0,n.jsx)(f,{isOpen:er,keyName:"Default cho API key mới",policy:ee,setPolicy:et,onClose:()=>{ea(!1),et(W||d)},onSave:tc,saving:es}),(0,n.jsx)(f,{isOpen:!!ev,keyName:ev?.name,policy:ew,setPolicy:eC,onClose:()=>{eN(null),eC(d)},onSave:tu,onClear:tp,saving:eP}),(0,n.jsx)(a.rq,{isOpen:el,onClose:()=>ei(!1),onSelect:e=>{let t=String(e?.value||e?.name||e||"").trim();t&&(V(t),ei(!1))},activeProviders:ed,modelAliases:ec,title:"Chọn default model cho API key",selectedModel:J,addedModelValues:J?[J]:[]}),D?(0,n.jsx)(a.uo,{isOpen:!!D,onClose:()=>q(null),onConfirm:D.onConfirm,title:D.title,message:D.message,confirmText:"X\xf3a",cancelText:"Hủy",variant:"danger"}):null]})}},84223:(e,t,s)=>{Promise.resolve().then(s.bind(s,56484))}},e=>{e.O(0,[2574,3862,1051,1321,5497,8441,3794,7358],()=>e(e.s=84223)),_N_E=e.O()}]);
|
package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/profile/page-aaec4486b982a13a.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3471],{7973:(e,a,s)=>{Promise.resolve().then(s.bind(s,64561))},64561:(e,a,s)=>{"use strict";s.r(a),s.d(a,{default:()=>p});var t=s(95155),l=s(12115);let r="(|(sAMAccountName={{username}})(userPrincipalName={{username}})(mail={{username}}))";function d({status:e}){if(!e?.message)return null;let a="error"===e.type?"text-red-600 bg-red-50 border-red-200":"text-green-700 bg-green-50 border-green-200";return(0,t.jsx)("div",{className:`mt-3 rounded-xl border px-4 py-3 text-sm ${a}`,children:e.message})}function o({icon:e,title:a,desc:s,children:l}){return(0,t.jsxs)("section",{className:"rounded-2xl border border-border bg-surface p-6 shadow-sm",children:[(0,t.jsxs)("div",{className:"mb-5 flex items-start gap-3",children:[e&&(0,t.jsx)("span",{className:"material-symbols-outlined text-primary",children:e}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h2",{className:"text-xl font-bold text-text-main",children:a}),s&&(0,t.jsx)("p",{className:"mt-1 text-sm text-text-muted",children:s})]})]}),l]})}function n({label:e,hint:a,children:s}){return(0,t.jsxs)("label",{className:"block",children:[(0,t.jsx)("span",{className:"mb-1 block text-sm font-semibold text-text-main",children:e}),s,a&&(0,t.jsx)("span",{className:"mt-1 block text-xs text-text-muted",children:a})]})}function i(e){return(0,t.jsx)("input",{...e,className:`w-full rounded-xl border border-border bg-background px-3 py-2 text-sm outline-none focus:border-primary ${e.className||""}`})}function c({title:e,desc:a,checked:s,onChange:l,disabled:r}){return(0,t.jsxs)("div",{className:"flex items-start justify-between gap-4 rounded-xl border border-border bg-background px-4 py-3",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("div",{className:"text-sm font-semibold text-text-main",children:e}),a&&(0,t.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:a})]}),(0,t.jsx)("button",{type:"button",disabled:r,onClick:()=>l(!s),className:`relative mt-0.5 h-6 w-11 rounded-full transition disabled:opacity-50 ${s?"bg-primary":"bg-border"}`,children:(0,t.jsx)("span",{className:`absolute top-0.5 h-5 w-5 rounded-full bg-white transition ${s?"left-5":"left-0.5"}`})})]})}function p(){let[e,a]=(0,l.useState)({}),[s,p]=(0,l.useState)(!0),[u,m]=(0,l.useState)({current:"",new:"",confirm:""}),[x,b]=(0,l.useState)({type:"",message:""}),[h,g]=(0,l.useState)(!1),[y,j]=(0,l.useState)(!1),[w,v]=(0,l.useState)({type:"",message:""}),D=(0,l.useRef)(null),[f,A]=(0,l.useState)("admin"),[N,C]=(0,l.useState)({type:"",message:""}),[U,L]=(0,l.useState)({ldapEnabled:!1,ldapUrl:"",ldapBindDn:"",ldapBindPassword:"",ldapUserBaseDn:"",ldapUserSearchFilter:r,ldapUserNameAttribute:"sAMAccountName",ldapUserDisplayAttribute:"displayName",ldapUserEmailAttribute:"mail",ldapLoginAllowedGroupDn:"",ldapAdminGroupDn:"",ldapMonitorAdminGroupDn:"",ldapNestedGroups:!0,ldapAllowedUsers:[],ldapTlsRejectUnauthorized:!0,ldapConnectTimeoutMs:8e3}),[S,k]=(0,l.useState)({type:"",message:""}),[P,I]=(0,l.useState)(!1),[O,G]=(0,l.useState)(!1),[B,M]=(0,l.useState)(""),[E,T]=(0,l.useState)([]),[R,F]=(0,l.useState)(!1),[_,$]=(0,l.useState)({authMode:"password",oidcIssuerUrl:"",oidcClientId:"",oidcScopes:"openid profile email",oidcLoginLabel:"Sign in with OIDC"}),[q,z]=(0,l.useState)(""),[J,K]=(0,l.useState)({type:"",message:""}),[H,Q]=(0,l.useState)(!1),[V,W]=(0,l.useState)(!1),X=async()=>{p(!0);try{let e=await fetch("/api/settings",{cache:"no-store"}),s=await e.json();a(s),A(s.localLoginUsername||"admin"),L({ldapEnabled:!0===s.ldapEnabled,ldapUrl:s.ldapUrl||"",ldapBindDn:s.ldapBindDn||"",ldapBindPassword:"",ldapUserBaseDn:s.ldapUserBaseDn||s.ldapBaseDn||"",ldapUserSearchFilter:s.ldapUserSearchFilter||r,ldapUserNameAttribute:s.ldapUserNameAttribute||"sAMAccountName",ldapUserDisplayAttribute:s.ldapUserDisplayAttribute||"displayName",ldapUserEmailAttribute:s.ldapUserEmailAttribute||"mail",ldapLoginAllowedGroupDn:s.ldapLoginAllowedGroupDn||"",ldapAdminGroupDn:s.ldapAdminGroupDn||"",ldapMonitorAdminGroupDn:s.ldapMonitorAdminGroupDn||"",ldapNestedGroups:!1!==s.ldapNestedGroups,ldapAllowedUsers:Array.isArray(s.ldapAllowedUsers)?s.ldapAllowedUsers:[],ldapTlsRejectUnauthorized:!1!==s.ldapTlsRejectUnauthorized,ldapConnectTimeoutMs:s.ldapConnectTimeoutMs||8e3}),$({authMode:s.authMode||"password",oidcIssuerUrl:s.oidcIssuerUrl||"",oidcClientId:s.oidcClientId||"",oidcScopes:s.oidcScopes||"openid profile email",oidcLoginLabel:s.oidcLoginLabel||"Sign in with OIDC"}),("oidc"===s.authMode||"both"===s.authMode)&&W(!0)}catch(e){console.log("Failed to fetch settings:",e)}finally{p(!1)}};(0,l.useEffect)(()=>{X()},[]);let Y=async e=>{let s=await fetch("/api/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),t=await s.json().catch(()=>({}));if(!s.ok)throw Error(t.error||"Failed to save settings");return a(e=>({...e,...t})),t},Z=async e=>{e.preventDefault(),C({type:"",message:""});try{let e=await Y({localLoginUsername:f});A(e.localLoginUsername||f||"admin"),C({type:"success",message:"Local account name saved."})}catch(e){C({type:"error",message:e.message})}},ee=async e=>{if(e.preventDefault(),u.new!==u.confirm)return void b({type:"error",message:"Passwords do not match"});g(!0),b({type:"",message:""});try{await Y({currentPassword:u.current,newPassword:u.new}),b({type:"success",message:"Password updated successfully"}),m({current:"",new:"",confirm:""})}catch(e){b({type:"error",message:e.message||"Failed to update password"})}finally{g(!1)}},ea=async()=>{j(!0),v({type:"",message:""});try{let e=await fetch("/api/settings/database");if(!e.ok){let a=await e.json().catch(()=>({}));throw Error(a.error||"Failed to export database")}let a=await e.json(),s=JSON.stringify(a,null,2),t=new Blob([s],{type:"application/json"}),l=URL.createObjectURL(t),r=document.createElement("a"),d=new Date().toISOString().replace(/[.:]/g,"-");r.href=l,r.download=`bluerouter-backup-${d}.json`,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(l),v({type:"success",message:"Database backup downloaded."})}catch(e){v({type:"error",message:e.message||"Failed to export database."})}finally{j(!1)}},es=async e=>{let a=e.target.files?.[0];if(a){j(!0),v({type:"",message:""});try{let e=await a.text(),s=JSON.parse(e),t=await fetch("/api/settings/database",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),l=await t.json().catch(()=>({}));if(!t.ok)throw Error(l.error||"Failed to import database");await X(),v({type:"success",message:"Database imported successfully."})}catch(e){v({type:"error",message:e.message||"Invalid backup file."})}finally{D.current&&(D.current.value=""),j(!1)}}},et=(e,a)=>L(s=>({...s,[e]:a})),el=async e=>{e?.preventDefault?.(),I(!0),k({type:"",message:""});try{let e={...U,ldapBaseDn:U.ldapUserBaseDn,ldapAllowedUsers:U.ldapAllowedUsers};e.ldapBindPassword||delete e.ldapBindPassword;let a=await Y(e);L(e=>({...e,ldapBindPassword:"",ldapEnabled:!0===a.ldapEnabled,ldapUserBaseDn:a.ldapUserBaseDn||a.ldapBaseDn||e.ldapUserBaseDn,ldapLoginAllowedGroupDn:a.ldapLoginAllowedGroupDn||"",ldapAdminGroupDn:a.ldapAdminGroupDn||"",ldapMonitorAdminGroupDn:a.ldapMonitorAdminGroupDn||"",ldapNestedGroups:!1!==a.ldapNestedGroups,ldapAllowedUsers:Array.isArray(a.ldapAllowedUsers)?a.ldapAllowedUsers:e.ldapAllowedUsers})),k({type:"success",message:"LDAP settings saved."})}catch(e){k({type:"error",message:e.message||"Failed to save LDAP settings"})}finally{I(!1)}},er=async()=>{G(!0),k({type:"",message:""});try{await el();let e=await fetch("/api/auth/ldap/test",{method:"POST"}),a=await e.json().catch(()=>({}));e.ok&&a.ok?k({type:"success",message:a.message||"LDAP connection OK."}):k({type:"error",message:a.error||"LDAP test failed."})}catch(e){k({type:"error",message:e.message||"LDAP test failed."})}finally{G(!1)}},ed=async()=>{F(!0),k({type:"",message:""});try{await el();let e=await fetch(`/api/auth/ldap/users?q=${encodeURIComponent(B)}`,{cache:"no-store"}),a=await e.json().catch(()=>({}));e.ok?(T(a.users||[]),k({type:"success",message:`Loaded ${(a.users||[]).length} LDAP user(s).`})):k({type:"error",message:a.error||"Failed to load LDAP users."})}catch(e){k({type:"error",message:e.message||"Failed to load LDAP users."})}finally{F(!1)}},eo=e=>{let a=String(e||"").trim();a&&L(e=>{let s=new Set(e.ldapAllowedUsers||[]);return s.has(a)?s.delete(a):s.add(a),{...e,ldapAllowedUsers:[...s]}})},en=async(a=_.authMode||"password")=>{let s=_.oidcIssuerUrl.trim(),t=_.oidcClientId.trim(),l=_.oidcScopes.trim(),r=_.oidcLoginLabel.trim(),d=q.trim();if("password"!==a&&(!s||!t||!d)&&!e.oidcConfigured)return void K({type:"error",message:"Issuer URL, client ID, and client secret are required to enable OIDC."});Q(!0),K({type:"",message:""});try{let e={authMode:a,oidcIssuerUrl:s,oidcClientId:t,oidcScopes:l||"openid profile email",oidcLoginLabel:r||"Sign in with OIDC"};d&&(e.oidcClientSecret=d);let o=await Y(e);$({authMode:o.authMode||a,oidcIssuerUrl:o.oidcIssuerUrl||s,oidcClientId:o.oidcClientId||t,oidcScopes:o.oidcScopes||l||"openid profile email",oidcLoginLabel:o.oidcLoginLabel||r||"Sign in with OIDC"}),z(""),K({type:"success",message:"OIDC settings saved."})}catch(e){K({type:"error",message:e.message||"Failed to save OIDC settings"})}finally{Q(!1)}};return s?(0,t.jsx)("div",{className:"p-8 text-text-muted",children:"Loading settings..."}):(0,t.jsxs)("div",{className:"mx-auto max-w-6xl space-y-6 p-6",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("h1",{className:"text-3xl font-bold text-text-main",children:"Settings"}),(0,t.jsx)("p",{className:"mt-1 text-text-muted",children:"Configure local dashboard login, LDAP/Active Directory login, and OIDC login."})]}),(0,t.jsx)(o,{icon:"shield",title:"Dashboard Login",desc:"Local account remains available even when LDAP is enabled.",children:(0,t.jsxs)("div",{className:"grid gap-6 lg:grid-cols-2",children:[(0,t.jsxs)("form",{onSubmit:Z,className:"space-y-3",children:[(0,t.jsx)("h3",{className:"font-semibold text-text-main",children:"Local account"}),(0,t.jsx)(n,{label:"Local username",children:(0,t.jsx)(i,{value:f,onChange:e=>A(e.target.value)})}),(0,t.jsx)("button",{className:"rounded-xl bg-primary px-4 py-2 text-sm font-semibold text-white",children:"Save account"}),(0,t.jsx)(d,{status:N})]}),!1!==e.requireLogin&&(0,t.jsxs)("form",{onSubmit:ee,className:"space-y-3",children:[(0,t.jsx)("h3",{className:"font-semibold text-text-main",children:"Local password"}),e.hasPassword&&(0,t.jsx)(n,{label:"Current password",children:(0,t.jsx)(i,{type:"password",value:u.current,onChange:e=>m({...u,current:e.target.value}),required:!0})}),(0,t.jsx)(n,{label:"New password",children:(0,t.jsx)(i,{type:"password",value:u.new,onChange:e=>m({...u,new:e.target.value}),required:!0})}),(0,t.jsx)(n,{label:"Confirm password",children:(0,t.jsx)(i,{type:"password",value:u.confirm,onChange:e=>m({...u,confirm:e.target.value}),required:!0})}),(0,t.jsx)("button",{disabled:h,className:"rounded-xl bg-primary px-4 py-2 text-sm font-semibold text-white disabled:opacity-50",children:e.hasPassword?"Update Password":"Set Password"}),(0,t.jsx)(d,{status:x})]})]})}),(0,t.jsxs)(o,{icon:"database",title:"Database Backup",desc:"Export or restore the local bluerouter configuration database.",children:[(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,t.jsx)("button",{onClick:ea,disabled:y,className:"rounded-xl bg-primary px-4 py-2 text-sm font-semibold text-white disabled:opacity-50",children:"Download Backup"}),(0,t.jsx)("button",{onClick:()=>D.current?.click(),disabled:y,className:"rounded-xl border border-border px-4 py-2 text-sm font-semibold text-text-main hover:border-primary/50 disabled:opacity-50",children:"Import Backup"}),(0,t.jsx)("input",{ref:D,type:"file",accept:"application/json",className:"hidden",onChange:es})]}),(0,t.jsx)(d,{status:w})]}),(0,t.jsx)(o,{icon:"corporate_fare",title:"LDAP / Active Directory Login",desc:"Search users from a User Base DN, restrict login by group DN, and grant admin by group DN. The old Selected LDAP users list is kept as a manual admin list.",children:(0,t.jsxs)("form",{onSubmit:el,className:"space-y-5",children:[(0,t.jsx)("div",{className:"flex flex-wrap gap-3",children:(0,t.jsx)("button",{type:"button",onClick:()=>et("ldapEnabled",!U.ldapEnabled),className:`rounded-xl px-3 py-2 text-sm font-semibold ${U.ldapEnabled?"bg-primary text-white":"border border-border text-text-muted"}`,children:U.ldapEnabled?"Enabled":"Disabled"})}),(0,t.jsxs)("div",{className:"grid gap-4 lg:grid-cols-2",children:[(0,t.jsx)(n,{label:"LDAP URL",children:(0,t.jsx)(i,{value:U.ldapUrl,onChange:e=>et("ldapUrl",e.target.value),placeholder:"ldap://dc01.company.local:389"})}),(0,t.jsx)(n,{label:"LDAP User Base DN",hint:"OU/container/domain where user objects are searched. Do not use a group DN here.",children:(0,t.jsx)(i,{value:U.ldapUserBaseDn,onChange:e=>et("ldapUserBaseDn",e.target.value),placeholder:"OU=Users,OU=xxx,DC=xx,DC=vn"})}),(0,t.jsx)(n,{label:"LDAP Bind DN",children:(0,t.jsx)(i,{value:U.ldapBindDn,onChange:e=>et("ldapBindDn",e.target.value),placeholder:"CN=svc-bluerouter,OU=Service Accounts,DC=company,DC=local"})}),(0,t.jsx)(n,{label:"LDAP Bind Password",children:(0,t.jsx)(i,{type:"password",value:U.ldapBindPassword,onChange:e=>et("ldapBindPassword",e.target.value),placeholder:e.ldapHasBindPassword?"Saved — leave blank to keep":"Service account password"})}),(0,t.jsx)(n,{label:"LDAP Login Allowed Group DN",hint:"Only members of this group can log in. Leave blank to allow any valid LDAP user.",children:(0,t.jsx)(i,{value:U.ldapLoginAllowedGroupDn,onChange:e=>et("ldapLoginAllowedGroupDn",e.target.value),placeholder:"CN=Apikeys_Groups,OU=AppGroups,OU=xxx,DC=xx,DC=vn"})}),(0,t.jsx)(n,{label:"LDAP Admin Group DN",hint:"Members of this group get full admin dashboard access.",children:(0,t.jsx)(i,{value:U.ldapAdminGroupDn,onChange:e=>et("ldapAdminGroupDn",e.target.value),placeholder:"CN=BlueRouter_Admins,OU=AppGroups,OU=xxx,DC=xx,DC=vn"})}),(0,t.jsx)(n,{label:"LDAP Monitor Admin Group DN",hint:"Members can use only Endpoint, API Keys, Usage, Analytics, Quota Tracker and Prompt Logs with admin-like permissions inside those tabs.",children:(0,t.jsx)(i,{value:U.ldapMonitorAdminGroupDn,onChange:e=>et("ldapMonitorAdminGroupDn",e.target.value),placeholder:"CN=BlueRouter_Monitor_Admins,OU=AppGroups,OU=xxx,DC=xx,DC=vn"})})]}),(0,t.jsxs)("div",{className:"grid gap-4 lg:grid-cols-2",children:[(0,t.jsx)(n,{label:"User search filter",hint:"Use {{username}} placeholder.",children:(0,t.jsx)(i,{value:U.ldapUserSearchFilter,onChange:e=>et("ldapUserSearchFilter",e.target.value)})}),(0,t.jsx)(n,{label:"Login group mode",hint:"Nested groups uses AD matching rule 1.2.840.113556.1.4.1941.",children:(0,t.jsx)(c,{title:"Nested group membership",desc:"Recommended for Active Directory nested groups.",checked:U.ldapNestedGroups,onChange:e=>et("ldapNestedGroups",e)})}),(0,t.jsx)(n,{label:"Username attribute",children:(0,t.jsx)(i,{value:U.ldapUserNameAttribute,onChange:e=>et("ldapUserNameAttribute",e.target.value)})}),(0,t.jsx)(n,{label:"Display attribute",children:(0,t.jsx)(i,{value:U.ldapUserDisplayAttribute,onChange:e=>et("ldapUserDisplayAttribute",e.target.value)})}),(0,t.jsx)(n,{label:"Email attribute",children:(0,t.jsx)(i,{value:U.ldapUserEmailAttribute,onChange:e=>et("ldapUserEmailAttribute",e.target.value)})}),(0,t.jsx)(n,{label:"Connect timeout ms",children:(0,t.jsx)(i,{type:"number",value:U.ldapConnectTimeoutMs,onChange:e=>et("ldapConnectTimeoutMs",e.target.value)})})]}),(0,t.jsx)(c,{title:"Reject invalid TLS certificates",desc:"Disable only for test/self-signed LDAP TLS.",checked:U.ldapTlsRejectUnauthorized,onChange:e=>et("ldapTlsRejectUnauthorized",e)}),(0,t.jsxs)("div",{className:"rounded-2xl border border-border bg-background p-4",children:[(0,t.jsxs)("div",{className:"mb-3",children:[(0,t.jsx)("h3",{className:"font-semibold text-text-main",children:"Manual admin users / LDAP owner list"}),(0,t.jsx)("p",{className:"mt-1 text-xs text-text-muted",children:"Users loaded here come from Login Allowed Group DN when set. Selected users are also treated as manual admins for backward compatibility."})]}),(0,t.jsxs)("div",{className:"mb-3 flex gap-2",children:[(0,t.jsx)(i,{value:B,onChange:e=>M(e.target.value),placeholder:"Search users..."}),(0,t.jsx)("button",{type:"button",onClick:ed,disabled:R,className:"rounded-xl border border-border px-4 py-2 text-sm font-semibold text-text-main disabled:opacity-50",children:R?"Loading...":"Load users"})]}),E.length>0&&(0,t.jsx)("div",{className:"max-h-72 overflow-auto rounded-xl border border-border",children:E.map(e=>{let a=U.ldapAllowedUsers.includes(e.username);return(0,t.jsxs)("button",{type:"button",onClick:()=>eo(e.username),className:`flex w-full items-center justify-between gap-3 border-b border-border px-3 py-2 text-left text-sm last:border-b-0 ${a?"bg-primary/10":"bg-background hover:bg-surface"}`,children:[(0,t.jsxs)("span",{children:[(0,t.jsx)("span",{className:"font-semibold text-text-main",children:e.displayName||e.username}),(0,t.jsxs)("span",{className:"ml-2 text-text-muted",children:[e.username,e.email?` \xb7 ${e.email}`:""]})]}),(0,t.jsx)("span",{className:"material-symbols-outlined text-primary",children:a?"check_circle":"radio_button_unchecked"})]},e.dn||e.username)})}),(0,t.jsxs)("div",{className:"mt-3",children:[(0,t.jsxs)("div",{className:"mb-2 text-sm font-semibold text-text-main",children:["Selected manual admin users (",U.ldapAllowedUsers.length,")"]}),0===U.ldapAllowedUsers.length?(0,t.jsx)("div",{className:"text-sm text-text-muted",children:"No users selected."}):(0,t.jsx)("div",{className:"flex flex-wrap gap-2",children:U.ldapAllowedUsers.map(e=>(0,t.jsxs)("button",{type:"button",onClick:()=>eo(e),className:"rounded-full border border-primary/30 bg-primary/10 px-3 py-1 text-xs text-primary",children:[e," \xd7"]},e))})]})]}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-3",children:[(0,t.jsx)("button",{type:"button",onClick:er,disabled:O,className:"rounded-xl border border-border px-4 py-2 text-sm font-semibold text-text-main disabled:opacity-50",children:O?"Testing...":"Save & test LDAP"}),(0,t.jsx)("button",{type:"submit",disabled:P,className:"rounded-xl bg-primary px-4 py-2 text-sm font-semibold text-white disabled:opacity-50",children:P?"Saving...":"Save LDAP settings"})]}),(0,t.jsx)(d,{status:S})]})}),(0,t.jsxs)(o,{icon:"lock_open",title:"OIDC Dashboard Login",desc:"oidc"===e.authMode?"OIDC active":"both"===e.authMode?"Password + OIDC active":"Optional SSO via Authentik/Keycloak/Google",children:[(0,t.jsx)("button",{type:"button",onClick:()=>W(e=>!e),className:"mb-4 rounded-xl border border-border px-4 py-2 text-sm font-semibold text-text-main",children:V?"Hide OIDC settings":"Show OIDC settings"}),V&&(0,t.jsxs)("div",{className:"space-y-4",children:[(0,t.jsx)("div",{className:"grid gap-3 md:grid-cols-3",children:[{value:"password",title:"Password/LDAP",desc:"Keep local and LDAP login."},{value:"oidc",title:"OIDC only",desc:"Disable local/LDAP login when configured."},{value:"both",title:"Both",desc:"Allow either OIDC or local/LDAP."}].map(e=>{let a=_.authMode===e.value;return(0,t.jsxs)("button",{type:"button",onClick:()=>$(a=>({...a,authMode:e.value})),className:`rounded-xl border p-3 text-left ${a?"border-primary bg-primary/10":"border-border bg-background hover:border-primary/40"}`,children:[(0,t.jsx)("div",{className:"font-semibold text-text-main",children:e.title}),(0,t.jsx)("div",{className:"mt-1 text-xs text-text-muted",children:e.desc})]},e.value)})}),(0,t.jsxs)("div",{className:"grid gap-4 lg:grid-cols-2",children:[(0,t.jsx)(n,{label:"Issuer URL",children:(0,t.jsx)(i,{value:_.oidcIssuerUrl,onChange:e=>$({..._,oidcIssuerUrl:e.target.value})})}),(0,t.jsx)(n,{label:"Client ID",children:(0,t.jsx)(i,{value:_.oidcClientId,onChange:e=>$({..._,oidcClientId:e.target.value})})}),(0,t.jsx)(n,{label:"Client Secret",children:(0,t.jsx)(i,{type:"password",value:q,onChange:e=>z(e.target.value),placeholder:e.oidcConfigured?"Saved — leave blank to keep":"Client secret"})}),(0,t.jsx)(n,{label:"Scopes",children:(0,t.jsx)(i,{value:_.oidcScopes,onChange:e=>$({..._,oidcScopes:e.target.value})})}),(0,t.jsx)(n,{label:"Login label",children:(0,t.jsx)(i,{value:_.oidcLoginLabel,onChange:e=>$({..._,oidcLoginLabel:e.target.value})})})]}),(0,t.jsx)("button",{type:"button",onClick:()=>en(),disabled:H,className:"rounded-xl bg-primary px-4 py-2 text-sm font-semibold text-white disabled:opacity-50",children:H?"Saving...":"Save OIDC settings"}),(0,t.jsx)(d,{status:J})]})]})]})}}},e=>{e.O(0,[8441,3794,7358],()=>e(e.s=7973)),_N_E=e.O()}]);
|