Compare commits
561 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0caa17ef9 | |||
| 71348f45b2 | |||
| 664b7d52af | |||
| fb6f9c91c6 | |||
| 051c873fdf | |||
| 12224458e7 | |||
| b6719d2a3e | |||
| 7843b56f39 | |||
| 19be6c4b3b | |||
| 4a283710ad | |||
| 1af7c5ee73 | |||
| 77dd47fa8a | |||
| ccfe91f08d | |||
| 624fb8322f | |||
| 6bc3242a29 | |||
| 33f528ef79 | |||
| 6c1afc4453 | |||
| 2a14447f8c | |||
| ad50f7473a | |||
| 5f1218f7b1 | |||
| e377afe9f6 | |||
| 21eb4d2876 | |||
| bb824a7070 | |||
| f98de98288 | |||
| 350de6ad2e | |||
| dc8e724482 | |||
| fb5b564c00 | |||
| 18270381c1 | |||
| b32dc30050 | |||
| 667804043c | |||
| 3fd3d90c10 | |||
| 6e3619fb1a | |||
| 987c0e992b | |||
| bdd7f40688 | |||
| 809bc662e0 | |||
| a74e1e765a | |||
| c356af3eda | |||
| a4c7121b93 | |||
| 2a3c00045f | |||
| 8e938a2723 | |||
| 197f8f7ba5 | |||
| 10b528642d | |||
| 60d6fff085 | |||
| c664b3da91 | |||
| 492282e758 | |||
| 47f4aefc25 | |||
| 7c0ff9ede7 | |||
| 44e81ea979 | |||
| 56dc10330a | |||
| 6c6e5c0fdf | |||
| 4be73558d5 | |||
| 87ff7650a1 | |||
| ae5af013b4 | |||
| 5adfe65aba | |||
| d3ae06deeb | |||
| ee4a72bcb7 | |||
| f941c23927 | |||
| 3ae6a08b71 | |||
| 620eeaed4c | |||
| 9b08228398 | |||
| eb102a0d23 | |||
| 18317e0028 | |||
| 2ec93c6710 | |||
| 5933eeb05f | |||
| 3fae2d687f | |||
| 285d7c6030 | |||
| 0fd57f5843 | |||
| a296460124 | |||
| 35104f7b29 | |||
| 51375ed8b7 | |||
| 1bb4f604e9 | |||
| 8fd990df93 | |||
| 1f390cabc6 | |||
| 7f1f8c54c1 | |||
| b1515db229 | |||
| d78c226734 | |||
| 52865bc1f5 | |||
| efbb6c9814 | |||
| 1e3dea3dad | |||
| 25f84482ba | |||
| 3f2a116fdb | |||
| dce002c6cc | |||
| dcfbbdc79d | |||
| f8cac37eef | |||
| cb37713c4c | |||
| 7ae4082d7e | |||
| aa8d339d35 | |||
| 7a61b182e0 | |||
| 91b697b80b | |||
| 7d10b63dc5 | |||
| 92916cd9db | |||
| 075d112861 | |||
| 7e9407fbc7 | |||
| 313f777e44 | |||
| 3ba9eb7ad7 | |||
| 328a2d52da | |||
| 697bea814e | |||
| 83cda218b7 | |||
| 76435440af | |||
| 0a8b5e46ca | |||
| a74b0934fc | |||
| c05d2aeafb | |||
| 87a3e5ceea | |||
| 555b36e13e | |||
| 021866011f | |||
| 749abdcb56 | |||
| 7d6f3a2925 | |||
| af515f1072 | |||
| c90c67eab3 | |||
| 51c9507d08 | |||
| 11daf4f927 | |||
| 58195b5959 | |||
| b51aecf45a | |||
| eb8ad6a181 | |||
| 4edd2e4d32 | |||
| 813c3abe54 | |||
| ca7ea72ff1 | |||
| 53b1d8a9f3 | |||
| a3dfb30a42 | |||
| 111d4b1b8c | |||
| 32d76ee2ac | |||
| 98ad6fb31b | |||
| 3a18a3994f | |||
| 6d35b20880 | |||
| 173d4a536f | |||
| ea740e12d1 | |||
| d7bff686c0 | |||
| 193f6da8d1 | |||
| 954dc8d1d9 | |||
| 234819f8f2 | |||
| b34a8d116b | |||
| 7375b9efae | |||
| c8f170d197 | |||
| 4989d1e31a | |||
| c568251d8d | |||
| db2de4af89 | |||
| 574ae8f5f9 | |||
| 125091d719 | |||
| 5d37f44241 | |||
| f0f5e9219b | |||
| ee75a09f8c | |||
| c49c6f5837 | |||
| 03118f1ede | |||
| 0ff5ea4f6a | |||
| 978fa8bfc6 | |||
| 36c7c5dc34 | |||
| 8f3628d4ec | |||
| fcd3c72cac | |||
| 3f0be4a39d | |||
| f9ff3a5715 | |||
| ed71c90d73 | |||
| e580c7db7c | |||
| 4a9b0117a2 | |||
| 9b10292e02 | |||
| d9a9ae14fd | |||
| db716f781e | |||
| 46f341f7fd | |||
| 9bb413bb1e | |||
| 2878d5690c | |||
| 1143404a65 | |||
| e92bb9043b | |||
| a2f5d830d6 | |||
| 77e3422e88 | |||
| 9a551c91e5 | |||
| c35ac493ed | |||
| e100645a00 | |||
| 96bfc66a94 | |||
| e21c9eec31 | |||
| a9f32102b5 | |||
| 7291628f86 | |||
| 5fbb205044 | |||
| 02ab24d01e | |||
| 3cfbd66a80 | |||
| 048e4fc73c | |||
| 860fa47b7c | |||
| 71d9d8f010 | |||
| cc58e28e54 | |||
| 653dd920ad | |||
| 49b4fcf063 | |||
| dd78c2cc08 | |||
| 47ae017f94 | |||
| 4b61e12ca6 | |||
| c6bd657ee6 | |||
| c33fa8782b | |||
| 93cba1d098 | |||
| d3a1f9798d | |||
| 115c3cbf07 | |||
| bed5817da3 | |||
| 83035753af | |||
| 379b53bcca | |||
| 355294a2d4 | |||
| 833b27ab4a | |||
| 8a04f13dd4 | |||
| 49020fa6ea | |||
| ac3402a8b3 | |||
| 9369e60695 | |||
| 295e38d2af | |||
| 923371e5b4 | |||
| 81430ba3d3 | |||
| 11595f5f96 | |||
| b08e875b37 | |||
| 0016b8fce7 | |||
| f5b10df7cf | |||
| 1782f31075 | |||
| 21032bc22b | |||
| e4aaadc9f9 | |||
| f7aca85417 | |||
| c42df737b0 | |||
| 75c6af3b11 | |||
| e734cc93a1 | |||
| e3ccc4f8d4 | |||
| 896c362dce | |||
| 864ab97293 | |||
| 899c47e9a3 | |||
| bc2f291352 | |||
| 98f5e39a7f | |||
| e0a66e79bb | |||
| c781be4e70 | |||
| 48c4b44f72 | |||
| 68a84181d9 | |||
| b60390d805 | |||
| b33e776072 | |||
| 2187f23588 | |||
| 732fd4eba1 | |||
| 495c772d6b | |||
| 02e4fe8b48 | |||
| 6d45486bb5 | |||
| 4c1f7f6243 | |||
| 1e3a9fb921 | |||
| 8b8e7913dc | |||
| 88515a7dad | |||
| e012063f5b | |||
| e76377d3c7 | |||
| a357f42c48 | |||
| 2becb15916 | |||
| 186eeed784 | |||
| 216c932cb9 | |||
| 52de5eb539 | |||
| eec3119297 | |||
| f2e7f83b3d | |||
| 93dea0525e | |||
| 7e6e0a8a9c | |||
| 211d3a53f5 | |||
| 187936e5dd | |||
| b180d064d1 | |||
| ed46afd81a | |||
| 0050fad70d | |||
| 3dc9c100e9 | |||
| 969e7c9296 | |||
| 591caab45a | |||
| 02e97d6ae4 | |||
| 996160fadc | |||
| dc1923ab1f | |||
| fe5831eb48 | |||
| ca79abc9d4 | |||
| 9eafa067b9 | |||
| 403b8a12e4 | |||
| 3f305e4d5c | |||
| 5e5e172d39 | |||
| bc7a883f6c | |||
| 12056aebc6 | |||
| 6689a8d93e | |||
| 297cb9c8f2 | |||
| d699455b38 | |||
| 9e7b4afaec | |||
| e91c344e64 | |||
| 07f628b928 | |||
| 184e1425a4 | |||
| 22f2990f56 | |||
| 6c28c5f383 | |||
| e9f9cf54f4 | |||
| 751d1b083d | |||
| a4d77a4fd3 | |||
| f72252552f | |||
| c5d68675c9 | |||
| d04740fede | |||
| 36b8ef5fba | |||
| 6cca5e0472 | |||
| 4048fa274a | |||
| b4d2974e19 | |||
| fb896d6c0f | |||
| 82b86263dc | |||
| 6564bfe8ae | |||
| 75ce7e91d7 | |||
| 656eea5bb1 | |||
| aba27a7bbf | |||
| 3d7e322bf9 | |||
| 1f3fff4a9d | |||
| 39e06f2b6d | |||
| b775c5b674 | |||
| 796bf37141 | |||
| c5b0e1e876 | |||
| 2e8bd7a8c7 | |||
| 790daba796 | |||
| bcf6b86b84 | |||
| 2e9bd50172 | |||
| 4677a0d501 | |||
| c673dce484 | |||
| e1dd8965dc | |||
| 346a0bdc98 | |||
| 8c1169738e | |||
| bc80f91a45 | |||
| 3d062389e9 | |||
| 7afddb5eb5 | |||
| 425a99e5ee | |||
| a5e9339af9 | |||
| b4463f0e1a | |||
| b7c0669c38 | |||
| 835a30cffe | |||
| 83e20c2dfa | |||
| f85d41945a | |||
| 149eb17b27 | |||
| 18b90da6ab | |||
| 72d469b19c | |||
| 6526d7f225 | |||
| 36c0edc62e | |||
| aad26b9ae4 | |||
| 80dcdfe251 | |||
| 1696fc37a8 | |||
| 7759d87835 | |||
| c085de1e9e | |||
| e99cd52e99 | |||
| e38359c74f | |||
| 2cfd7e867b | |||
| ec5a2b0cbe | |||
| 2bf426bc22 | |||
| ed8545f8a2 | |||
| 9811492a0b | |||
| 973925b35d | |||
| 0b30cfc341 | |||
| a7e44944fb | |||
| 9b25ebd6cd | |||
| 33b775e263 | |||
| b0edc6302e | |||
| 1a644b131d | |||
| f7689b7a5a | |||
| 1073011a2a | |||
| 6fa0009ebf | |||
| 42c0abedb7 | |||
| 56e59a93f3 | |||
| 9d581f3897 | |||
| e5ac6ec7cd | |||
| 694fe98131 | |||
| 730078597e | |||
| 32ac8db803 | |||
| aad2ed2719 | |||
| a790fed297 | |||
| deb2d5ce2a | |||
| 093097c619 | |||
| 2cdeb7c104 | |||
| 4dbb04bfb8 | |||
| fa8b921635 | |||
| 33dd10c670 | |||
| ba24e1c4f5 | |||
| f079714caf | |||
| 152d2fb1d6 | |||
| d374b4f66e | |||
| efd2792197 | |||
| efe22c889c | |||
| 7f2b3eb481 | |||
| 81be4a35d9 | |||
| e84da6a8df | |||
| 3ef3ede7df | |||
| 1e521b0b54 | |||
| 59ea701304 | |||
| 7d7c54107d | |||
| f0f6673d69 | |||
| 71561d0e65 | |||
| af87edf3a6 | |||
| 13caad18c7 | |||
| 47522b7e3a | |||
| c8c8d74452 | |||
| e7098963d6 | |||
| f015fb592b | |||
| c099167905 | |||
| b0e274f5a9 | |||
| 146c287aba | |||
| 95ee56217c | |||
| 7625cc208d | |||
| f2dfd939bc | |||
| 699bc8ddb4 | |||
| e658e007e1 | |||
| 3103265450 | |||
| 97789d9e2e | |||
| a1aa3d96d4 | |||
| ae39bc0ecd | |||
| e4d81aa610 | |||
| f59b524266 | |||
| 58c499acae | |||
| f22301a1eb | |||
| d6264fb39a | |||
| 08b5a9b34b | |||
| 263976bf41 | |||
| 0e4cd3a5ba | |||
| 192542629f | |||
| aeed271f3e | |||
| d41e9bbe68 | |||
| 904a5520b8 | |||
| 0f43ae4871 | |||
| bd0cf98319 | |||
| fc7d6bbaf9 | |||
| 1b89c328de | |||
| e7f147d4ca | |||
| 41dbc7d5ed | |||
| 9f297317f2 | |||
| e0a8721207 | |||
| a69b310109 | |||
| 864a6a39cd | |||
| 1882d4df88 | |||
| ef3f71e9b5 | |||
| 9981c4c035 | |||
| bc267b7107 | |||
| 5cbb767e5f | |||
| ac79621cae | |||
| f47c94d05b | |||
| 10773432bb | |||
| d5a56fb71d | |||
| b5518d029e | |||
| 9a9ae649ef | |||
| aa6dc67015 | |||
| 0da96b06ea | |||
| 6649f15498 | |||
| 49854f31a5 | |||
| 762c79511b | |||
| 6e29ebd649 | |||
| e128b8c282 | |||
| 832e382888 | |||
| 8a68b899f5 | |||
| 71f45b8a80 | |||
| ecf008a8d9 | |||
| b3880e5c02 | |||
| 58004a8ec9 | |||
| b0ff7d2707 | |||
| 262f7bd090 | |||
| b1558b09b1 | |||
| a33de8268b | |||
| c92d5096c4 | |||
| 9867d3c876 | |||
| 70bddba55b | |||
| 23181f4019 | |||
| 19c1c2042b | |||
| 9cc3190e3a | |||
| 72f179578b | |||
| 4c873e7c48 | |||
| 56fcb80b23 | |||
| 41c68148a9 | |||
| 5d38059b95 | |||
| df0198df9c | |||
| 26713b53f6 | |||
| 2bc6b28978 | |||
| f1ed4da8a4 | |||
| adeefb9dbd | |||
| bf1cc705a5 | |||
| 0b82dae01e | |||
| 75afe6ece2 | |||
| 70e2fe1e4e | |||
| 17e03457e1 | |||
| 4d8cb7e231 | |||
| 9561d23f1e | |||
| 0275f44056 | |||
| a2e1c7b751 | |||
| 9e2ec72ced | |||
| 02fe1f3abd | |||
| c30fe5b574 | |||
| a0b9ea76a3 | |||
| eb3a3eac98 | |||
| 02d2e09709 | |||
| 6e8283957c | |||
| bb9b94a983 | |||
| 36f807ddbc | |||
| cb31546c6b | |||
| 2d48adc9f9 | |||
| 113b7a0b84 | |||
| ca279ee3e0 | |||
| a5808200f0 | |||
| aa9de4d2ac | |||
| 50821e972d | |||
| e5b9dfee66 | |||
| 8e09070bc1 | |||
| 3d9c413bbb | |||
| 86670c1d60 | |||
| 5f2ee77a73 | |||
| 714e3a8fb1 | |||
| 672555f051 | |||
| 7853f2b096 | |||
| 61a7dda29a | |||
| f9bcb25eaa | |||
| 6df804ab32 | |||
| 9e50735800 | |||
| a30119f5e8 | |||
| 3c9f0946d2 | |||
| 21861a6dcd | |||
| 6135f2b727 | |||
| 3a616cc804 | |||
| d5eb67a8fc | |||
| 3ac7ef23ae | |||
| 08c5ec2be7 | |||
| a88b79e066 | |||
| a48ef77ee5 | |||
| 55f3807491 | |||
| dbfb8e83e8 | |||
| 515afc14a5 | |||
| 903e8c0fa1 | |||
| 7f9c760380 | |||
| 530a1a5350 | |||
| 3fb36c1434 | |||
| 5d20956a0e | |||
| 29f91e8276 | |||
| 4d9e38d022 | |||
| d7d31b78f0 | |||
| e8ed8fc7e9 | |||
| 5ee406c92e | |||
| 89f4f4ba6f | |||
| 4e5fd2f2b0 | |||
| 22a5743817 | |||
| 40e05f903a | |||
| 6c1e1bc0ca | |||
| cebbf9ca65 | |||
| e6646e5833 | |||
| 00f7510195 | |||
| 8d1f5e1096 | |||
| e497fcc3b9 | |||
| a7010b2788 | |||
| abf58a70ee | |||
| d4c602cf91 | |||
| d1b0bbb6d9 | |||
| ae0be3a4bc | |||
| a8f3f71021 | |||
| 933ca71c16 | |||
| 591cb9cdc1 | |||
| 34b18bdb53 | |||
| 7d475f5e91 | |||
| 39c35fa539 | |||
| bada1fdb97 | |||
| e1bc0b7efd | |||
| 5ef068c8dc | |||
| 14680df160 | |||
| 94c01a23a9 | |||
| 609fb357bb | |||
| cf9a17cc2e | |||
| 538b57941c | |||
| f4bee6406a | |||
| 0b2693a317 | |||
| 1580b7abff | |||
| 3be2d928f6 | |||
| e5398d441e | |||
| d38f9ac2bb | |||
| 8d018fe47d | |||
| d4138e2141 | |||
| 09d5d9082e | |||
| bb5547a157 | |||
| 5cb316f4e9 | |||
| 6b6c9cf4d8 | |||
| 05617c63c0 | |||
| d4c52bbf2f | |||
| 87f50bf0cc | |||
| 2c66da1b19 | |||
| ab19955502 | |||
| 1db9dcec81 | |||
| 49c2d3163e | |||
| 45b9e13a13 |
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: crud-endpoints
|
||||||
|
description: Use whenever asked to add, create, or scaffold a CRUD endpoint, router, or entity in this repo's server (create/list/get/update/delete handlers, new `server/routers/<entity>/` or `server/private/routers/<entity>/` folder). Points to the established file layout, middleware, ActionsEnum, and route-registration conventions before writing any code.
|
||||||
|
---
|
||||||
|
|
||||||
|
Before writing any router/handler/middleware code for a new entity, read
|
||||||
|
`docs/crud-endpoints.md` in full. It documents, with real examples from
|
||||||
|
`server/routers/aiProvider/` (public) and `server/private/routers/alertRule/`
|
||||||
|
(enterprise-only), how this repo structures CRUD endpoints:
|
||||||
|
|
||||||
|
- Directory/file layout per entity (`index.ts`, `types.ts`, `validation.ts`,
|
||||||
|
one file per operation).
|
||||||
|
- The standard handler anatomy (zod parsing, OpenAPI registry, response
|
||||||
|
envelope, error handling).
|
||||||
|
- Where access-control middleware (`verify<Entity>Access`) lives and when
|
||||||
|
it's needed vs. plain `verifyOrgAccess`.
|
||||||
|
- How to wire up `ActionsEnum` entries, `verifyUserHasAction`, and
|
||||||
|
`logActionAudit`.
|
||||||
|
- Which of the four router files (`server/routers/external.ts`,
|
||||||
|
`server/routers/internal.ts`, `server/private/routers/external.ts`,
|
||||||
|
`server/private/routers/internal.ts`) to register routes in, and the
|
||||||
|
middleware chain template per HTTP verb.
|
||||||
|
- The repo's non-standard verb convention: **`PUT` = create, `POST` =
|
||||||
|
update** (backwards from typical REST) — don't "fix" this to standard
|
||||||
|
REST verbs, match the existing convention.
|
||||||
|
- The `#dynamic` import alias, for the rare case of a hook needing different
|
||||||
|
implementations in OSS vs. enterprise builds.
|
||||||
|
|
||||||
|
Follow that doc's checklist (§8) step by step rather than improvising a
|
||||||
|
structure. If the doc and the actual code in `aiProvider`/`alertRule` ever
|
||||||
|
disagree, trust the code and flag the doc as stale.
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Monitor storage space
|
- name: Monitor storage space
|
||||||
run: |
|
run: |
|
||||||
@@ -77,7 +77,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||||
with:
|
with:
|
||||||
registry: docker.io
|
registry: docker.io
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
@@ -134,7 +134,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Monitor storage space
|
- name: Monitor storage space
|
||||||
run: |
|
run: |
|
||||||
@@ -149,7 +149,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||||
with:
|
with:
|
||||||
registry: docker.io
|
registry: docker.io
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
@@ -201,10 +201,10 @@ jobs:
|
|||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||||
with:
|
with:
|
||||||
registry: docker.io
|
registry: docker.io
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
@@ -256,7 +256,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Extract tag name
|
- name: Extract tag name
|
||||||
id: get-tag
|
id: get-tag
|
||||||
@@ -264,7 +264,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||||
with:
|
with:
|
||||||
go-version: 1.25
|
go-version: 1.25
|
||||||
|
|
||||||
@@ -407,7 +407,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry (for cosign)
|
- name: Login to GitHub Container Registry (for cosign)
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version: '24'
|
node-version: '24'
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
|
- uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
|
||||||
with:
|
with:
|
||||||
days-before-stale: 14
|
days-before-stale: 14
|
||||||
days-before-close: 14
|
days-before-close: 14
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version: '24'
|
node-version: '24'
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Build Docker image sqlite
|
- name: Build Docker image sqlite
|
||||||
run: make dev-build-sqlite
|
run: make dev-build-sqlite
|
||||||
@@ -71,7 +71,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Build Docker image pg
|
- name: Build Docker image pg
|
||||||
run: make dev-build-pg
|
run: make dev-build-pg
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# FROM node:24-slim AS base
|
# FROM node:24.18.1-slim AS base
|
||||||
FROM public.ecr.aws/docker/library/node:24-slim AS base
|
FROM public.ecr.aws/docker/library/node:24.18.1-slim AS base
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ FROM base AS builder
|
|||||||
|
|
||||||
RUN npm ci --omit=dev
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
# FROM node:24-slim AS runner
|
# FROM node:24.18.1-slim AS runner
|
||||||
FROM public.ecr.aws/docker/library/node:24-slim AS runner
|
FROM public.ecr.aws/docker/library/node:24.18.1-slim AS runner
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:24-alpine
|
FROM node:26.7.0-alpine
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
</strong>
|
</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Pangolin is an open-source, identity-based remote access platform built on WireGuard® that enables secure, seamless connectivity to private and public resources. Pangolin combines reverse proxy and VPN capabilities into one platform, providing browser-based access to web applications and client-based access to any private resources with NAT traversal, all with granular access controls.
|
Pangolin is an open-source, identity-based remote access platform built on WireGuard® that enables secure connectivity to infrastructure anywhere. It combines reverse-proxy and VPN capabilities into one platform, providing browser-based access to web applications and client-based access to private resources with NAT traversal, all with granular access control.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -63,11 +63,26 @@ Pangolin is an open-source, identity-based remote access platform built on WireG
|
|||||||
|
|
||||||
Pangolin's site connectors provide gateways into networks so you can access any networked resources. Sites use outbound tunnels and intelligent NAT traversal to make networks behind restrictive firewalls available for authorized access without public IPs or open ports. Easily deploy a site as a binary or container on any platform.
|
Pangolin's site connectors provide gateways into networks so you can access any networked resources. Sites use outbound tunnels and intelligent NAT traversal to make networks behind restrictive firewalls available for authorized access without public IPs or open ports. Easily deploy a site as a binary or container on any platform.
|
||||||
|
|
||||||
|
* Lightweight user-space connector runs anywhere
|
||||||
|
* Punches through any firewall
|
||||||
|
* Doesn't require open ports or a public IP
|
||||||
|
* Strict network segmentation
|
||||||
|
* WireGuard-based
|
||||||
|
* Get alerts when a device or network resource goes down
|
||||||
|
|
||||||
<img src="public/screenshots/sites.png" alt="Sites" width="100%" />
|
<img src="public/screenshots/sites.png" alt="Sites" width="100%" />
|
||||||
|
|
||||||
### Browser-based reverse proxy access
|
### Browser-based reverse proxy access
|
||||||
|
|
||||||
Expose web applications through identity and context-aware tunneled reverse proxies. Users access applications through any web browser with authentication and granular access control without installing a client. Pangolin handles routing, load balancing, health checking, and automatic SSL certificates without exposing your network directly to the internet.
|
Expose HTTPS web applications and connect to VNC, RDP, and SSH entirely in the browser through identity and context-aware tunneled reverse proxies. Users access resources with authentication and granular access control without installing a client. Pangolin handles routing, load balancing, health checking, and automatic SSL certificates without exposing your network directly to the internet.
|
||||||
|
|
||||||
|
* Expose a web panel anywhere
|
||||||
|
* Access via any web browser
|
||||||
|
* Single sign-on across all resources
|
||||||
|
* HTTPS resources
|
||||||
|
* Remote desktop in the browser with VNC and RDP
|
||||||
|
* In-browser SSH terminal with privileged access management (PAM)
|
||||||
|
* PIN codes, passcodes, email OTP, geoblocking, allow-lists, and more
|
||||||
|
|
||||||
<img src="public/clip.gif" alt="Reverse proxy access" width="100%" />
|
<img src="public/clip.gif" alt="Reverse proxy access" width="100%" />
|
||||||
|
|
||||||
@@ -75,14 +90,35 @@ Expose web applications through identity and context-aware tunneled reverse prox
|
|||||||
|
|
||||||
Access private resources like SSH servers, databases, RDP, and entire network ranges through Pangolin clients. Intelligent NAT traversal enables connections even through restrictive firewalls, while DNS aliases provide friendly names and fast connections to resources across all your sites. Add redundancy by routing traffic through multiple connectors in your network.
|
Access private resources like SSH servers, databases, RDP, and entire network ranges through Pangolin clients. Intelligent NAT traversal enables connections even through restrictive firewalls, while DNS aliases provide friendly names and fast connections to resources across all your sites. Add redundancy by routing traffic through multiple connectors in your network.
|
||||||
|
|
||||||
|
* Peer-to-peer with intelligent NAT traversal
|
||||||
|
* Hosts/IPs and port ranges
|
||||||
|
* Network ranges/CIDRs
|
||||||
|
* Friendly DNS aliases for network addresses
|
||||||
|
* Privileged access management (PAM) with SSH resources
|
||||||
|
* Private HTTPS resources only accessible on the private network
|
||||||
|
|
||||||
<img src="public/screenshots/private-resources.png" alt="Private resources" width="100%" />
|
<img src="public/screenshots/private-resources.png" alt="Private resources" width="100%" />
|
||||||
|
|
||||||
### Give users and roles access to resources
|
### Give users and roles access to resources
|
||||||
|
|
||||||
Use Pangolin's built in users or bring your own identity provider and set up role based access control (RBAC). Grant users access to specific resources, not entire networks. Unlike traditional VPNs that expose full network access, Pangolin's zero-trust model ensures users can only reach the applications, services, and routes you explicitly define.
|
Use Pangolin's built-in users or bring your own identity provider and set up role-based access control (RBAC). Grant users access to specific resources, not entire networks. Unlike traditional VPNs that expose full network access, Pangolin's zero-trust model ensures users can only reach the applications, services, and routes you explicitly define.
|
||||||
|
|
||||||
|
* Bring your existing identity provider (IdP) or use Pangolin identities
|
||||||
|
* Sync users and roles from your IdP
|
||||||
|
* User- and role-based access control
|
||||||
|
* Full network audit and access logs
|
||||||
|
|
||||||
<img src="public/screenshots/users.png" alt="Users from identity provider with roles" width="100%" />
|
<img src="public/screenshots/users.png" alt="Users from identity provider with roles" width="100%" />
|
||||||
|
|
||||||
|
### Find and launch resources from a personalized home page
|
||||||
|
|
||||||
|
Give users a landing page to quickly find and open the resources they can access. Resources are grouped by site or label, searchable, and filterable, with grid or list views. Saved views capture filters, grouping, and layout as personal or organization-wide defaults.
|
||||||
|
|
||||||
|
* Single place for admins and non-admins to see accessible resources
|
||||||
|
* Create reusable views for common access patterns
|
||||||
|
|
||||||
|
<img src="public/screenshots/resource-launcher.png" alt="Resource Launcher" width="100%" />
|
||||||
|
|
||||||
## Download Clients
|
## Download Clients
|
||||||
|
|
||||||
Download the Pangolin client for your platform:
|
Download the Pangolin client for your platform:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CommandModule } from "yargs";
|
import { CommandModule } from "yargs";
|
||||||
import { db, idpOidcConfig, licenseKey, certificates, eventStreamingDestinations, alertWebhookActions } from "@server/db";
|
import { db, idpOidcConfig, licenseKey, certificates, eventStreamingDestinations, alertWebhookActions, aiProviders, virtualApiKeys } from "@server/db";
|
||||||
import { encrypt, decrypt } from "@server/lib/crypto";
|
import { encrypt, decrypt } from "@server/lib/crypto";
|
||||||
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
@@ -132,12 +132,16 @@ export const rotateServerSecret: CommandModule<
|
|||||||
const certs = await db.select().from(certificates);
|
const certs = await db.select().from(certificates);
|
||||||
const streamingDestinations = await db.select().from(eventStreamingDestinations);
|
const streamingDestinations = await db.select().from(eventStreamingDestinations);
|
||||||
const webhookActions = await db.select().from(alertWebhookActions);
|
const webhookActions = await db.select().from(alertWebhookActions);
|
||||||
|
const providers = await db.select().from(aiProviders);
|
||||||
|
const virtualKeys = await db.select().from(virtualApiKeys);
|
||||||
|
|
||||||
console.log(`Found ${idpConfigs.length} OIDC IdP configuration(s)`);
|
console.log(`Found ${idpConfigs.length} OIDC IdP configuration(s)`);
|
||||||
console.log(`Found ${licenseKeys.length} license key(s)`);
|
console.log(`Found ${licenseKeys.length} license key(s)`);
|
||||||
console.log(`Found ${certs.length} certificate(s)`);
|
console.log(`Found ${certs.length} certificate(s)`);
|
||||||
console.log(`Found ${streamingDestinations.length} event streaming destination(s)`);
|
console.log(`Found ${streamingDestinations.length} event streaming destination(s)`);
|
||||||
console.log(`Found ${webhookActions.length} alert webhook action(s)`);
|
console.log(`Found ${webhookActions.length} alert webhook action(s)`);
|
||||||
|
console.log(`Found ${providers.length} AI provider(s)`);
|
||||||
|
console.log(`Found ${virtualKeys.length} virtual API key(s)`);
|
||||||
|
|
||||||
// Prepare all decrypted and re-encrypted values
|
// Prepare all decrypted and re-encrypted values
|
||||||
console.log("\nDecrypting and re-encrypting values...");
|
console.log("\nDecrypting and re-encrypting values...");
|
||||||
@@ -171,11 +175,24 @@ export const rotateServerSecret: CommandModule<
|
|||||||
encryptedConfig: string;
|
encryptedConfig: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type AiProviderUpdate = {
|
||||||
|
providerId: number;
|
||||||
|
encryptedApiKey: string | null;
|
||||||
|
encryptedHeaders: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type VirtualApiKeyUpdate = {
|
||||||
|
virtualApiKeyId: string;
|
||||||
|
encryptedToken: string;
|
||||||
|
};
|
||||||
|
|
||||||
const idpUpdates: IdpUpdate[] = [];
|
const idpUpdates: IdpUpdate[] = [];
|
||||||
const licenseKeyUpdates: LicenseKeyUpdate[] = [];
|
const licenseKeyUpdates: LicenseKeyUpdate[] = [];
|
||||||
const certUpdates: CertUpdate[] = [];
|
const certUpdates: CertUpdate[] = [];
|
||||||
const streamingDestinationUpdates: StreamingDestinationUpdate[] = [];
|
const streamingDestinationUpdates: StreamingDestinationUpdate[] = [];
|
||||||
const webhookActionUpdates: WebhookActionUpdate[] = [];
|
const webhookActionUpdates: WebhookActionUpdate[] = [];
|
||||||
|
const aiProviderUpdates: AiProviderUpdate[] = [];
|
||||||
|
const virtualApiKeyUpdates: VirtualApiKeyUpdate[] = [];
|
||||||
|
|
||||||
// Process idpOidcConfig entries
|
// Process idpOidcConfig entries
|
||||||
for (const idpConfig of idpConfigs) {
|
for (const idpConfig of idpConfigs) {
|
||||||
@@ -306,6 +323,60 @@ export const rotateServerSecret: CommandModule<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process aiProviders entries (apiKey + headers)
|
||||||
|
for (const provider of providers) {
|
||||||
|
try {
|
||||||
|
if (!provider.apiKey && !provider.headers) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptedApiKey = provider.apiKey
|
||||||
|
? encrypt(decrypt(provider.apiKey, oldSecret), newSecret)
|
||||||
|
: null;
|
||||||
|
const encryptedHeaders = provider.headers
|
||||||
|
? encrypt(
|
||||||
|
decrypt(provider.headers, oldSecret),
|
||||||
|
newSecret
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
aiProviderUpdates.push({
|
||||||
|
providerId: provider.providerId,
|
||||||
|
encryptedApiKey,
|
||||||
|
encryptedHeaders
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Error processing AI provider ${provider.providerId}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process virtualApiKeys entries (token)
|
||||||
|
for (const key of virtualKeys) {
|
||||||
|
try {
|
||||||
|
if (!key.token) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtualApiKeyUpdates.push({
|
||||||
|
virtualApiKeyId: key.virtualApiKeyId,
|
||||||
|
encryptedToken: encrypt(
|
||||||
|
decrypt(key.token, oldSecret),
|
||||||
|
newSecret
|
||||||
|
)
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Error processing virtual API key ${key.virtualApiKeyId}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Perform all database updates in a single transaction
|
// Perform all database updates in a single transaction
|
||||||
console.log("\nUpdating database in transaction...");
|
console.log("\nUpdating database in transaction...");
|
||||||
await db.transaction(async (trx) => {
|
await db.transaction(async (trx) => {
|
||||||
@@ -376,6 +447,32 @@ export const rotateServerSecret: CommandModule<
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update AI provider entries
|
||||||
|
for (const update of aiProviderUpdates) {
|
||||||
|
await trx
|
||||||
|
.update(aiProviders)
|
||||||
|
.set({
|
||||||
|
apiKey: update.encryptedApiKey,
|
||||||
|
headers: update.encryptedHeaders
|
||||||
|
})
|
||||||
|
.where(eq(aiProviders.providerId, update.providerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update virtual API key entries
|
||||||
|
for (const update of virtualApiKeyUpdates) {
|
||||||
|
await trx
|
||||||
|
.update(virtualApiKeys)
|
||||||
|
.set({
|
||||||
|
token: update.encryptedToken
|
||||||
|
})
|
||||||
|
.where(
|
||||||
|
eq(
|
||||||
|
virtualApiKeys.virtualApiKeyId,
|
||||||
|
update.virtualApiKeyId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Rotated ${idpUpdates.length} OIDC IdP configuration(s)`);
|
console.log(`Rotated ${idpUpdates.length} OIDC IdP configuration(s)`);
|
||||||
@@ -383,6 +480,8 @@ export const rotateServerSecret: CommandModule<
|
|||||||
console.log(`Rotated ${certUpdates.length} certificate(s)`);
|
console.log(`Rotated ${certUpdates.length} certificate(s)`);
|
||||||
console.log(`Rotated ${streamingDestinationUpdates.length} event streaming destination(s)`);
|
console.log(`Rotated ${streamingDestinationUpdates.length} event streaming destination(s)`);
|
||||||
console.log(`Rotated ${webhookActionUpdates.length} alert webhook action(s)`);
|
console.log(`Rotated ${webhookActionUpdates.length} alert webhook action(s)`);
|
||||||
|
console.log(`Rotated ${aiProviderUpdates.length} AI provider(s)`);
|
||||||
|
console.log(`Rotated ${virtualApiKeyUpdates.length} virtual API key(s)`);
|
||||||
|
|
||||||
// Update config file with new secret
|
// Update config file with new secret
|
||||||
console.log("\nUpdating config file...");
|
console.log("\nUpdating config file...");
|
||||||
@@ -402,6 +501,7 @@ export const rotateServerSecret: CommandModule<
|
|||||||
console.log(` - Certificates: ${certUpdates.length}`);
|
console.log(` - Certificates: ${certUpdates.length}`);
|
||||||
console.log(` - Event streaming destinations: ${streamingDestinationUpdates.length}`);
|
console.log(` - Event streaming destinations: ${streamingDestinationUpdates.length}`);
|
||||||
console.log(` - Alert webhook actions: ${webhookActionUpdates.length}`);
|
console.log(` - Alert webhook actions: ${webhookActionUpdates.length}`);
|
||||||
|
console.log(` - AI providers: ${aiProviderUpdates.length}`);
|
||||||
console.log(
|
console.log(
|
||||||
`\n IMPORTANT: Restart the server for the new secret to take effect.`
|
`\n IMPORTANT: Restart the server for the new secret to take effect.`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ services:
|
|||||||
- 80:80 # Port for traefik because of the network_mode
|
- 80:80 # Port for traefik because of the network_mode
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:v3.6
|
image: traefik:v3.7
|
||||||
container_name: traefik
|
container_name: traefik
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
network_mode: service:gerbil # Ports appear on the gerbil service
|
network_mode: service:gerbil # Ports appear on the gerbil service
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ services:
|
|||||||
POSTGRES_USER: postgres # Default user
|
POSTGRES_USER: postgres # Default user
|
||||||
POSTGRES_PASSWORD: password # Default password (change for production!)
|
POSTGRES_PASSWORD: password # Default password (change for production!)
|
||||||
volumes:
|
volumes:
|
||||||
- ./config/postgres:/var/lib/postgresql/data
|
- ${HOME}/.local/share/pangolin-dev/postgres:/var/lib/postgresql/data
|
||||||
ports:
|
ports:
|
||||||
- "5432:5432" # Map host port 5432 to container port 5432
|
- "5432:5432" # Map host port 5432 to container port 5432
|
||||||
restart: no
|
restart: no
|
||||||
|
|||||||
@@ -0,0 +1,285 @@
|
|||||||
|
# AI Gateway Provider Selection
|
||||||
|
|
||||||
|
How the AI gateway picks which attached provider handles a request when an
|
||||||
|
inference resource has more than one AI provider.
|
||||||
|
|
||||||
|
**Code:**
|
||||||
|
|
||||||
|
- Route → capability binding: `server/routers/aiGateway/createAiGatewayRouter.ts`
|
||||||
|
- Request pipeline: `server/routers/aiGateway/pipeline.ts` (`selectProvider`)
|
||||||
|
- Tie-break scoring: `server/lib/aiProviderSelection.ts`
|
||||||
|
- Allow/block matching: `server/lib/aiModelKeyMatch.ts`
|
||||||
|
- Model catalog: `server/lib/aiModelCatalog.ts`
|
||||||
|
- Default capabilities per provider type: `server/lib/aiProviderDefaults.ts`
|
||||||
|
|
||||||
|
Overlapping model allows are permitted at save time. Selection happens at
|
||||||
|
request time. If the algorithm cannot confidently pick one provider, the
|
||||||
|
gateway returns `403` with an ambiguous-provider error.
|
||||||
|
|
||||||
|
## Selection Pipeline
|
||||||
|
|
||||||
|
Every gateway request runs through these steps in order. Each step narrows
|
||||||
|
the candidate set. Later steps only run when more than one provider remains.
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Capability filter
|
||||||
|
2. Allow / block lists
|
||||||
|
3. Most specific allow pattern
|
||||||
|
4. Catalog ownership
|
||||||
|
5. Provider class preference
|
||||||
|
6. Ambiguous → error
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1. Capability Filter
|
||||||
|
|
||||||
|
The incoming path selects a capability before any provider logic runs.
|
||||||
|
|
||||||
|
| Path | Capability |
|
||||||
|
|------|------------|
|
||||||
|
| `POST /v1/chat/completions` | `openai_chat` |
|
||||||
|
| `POST /v1/responses` | `openai_responses` |
|
||||||
|
| `POST /v1/messages` | `anthropic_messages` |
|
||||||
|
| Gemini / Vertex / Bedrock routes | their respective capability ids |
|
||||||
|
|
||||||
|
Only attached providers that advertise that capability stay in the candidate
|
||||||
|
set. Default capabilities do not overlap for native OpenAI vs Anthropic:
|
||||||
|
|
||||||
|
| Provider type | Default capabilities |
|
||||||
|
|---------------|----------------------|
|
||||||
|
| `openai` | `openai_chat`, `openai_responses` |
|
||||||
|
| `anthropic` | `anthropic_messages` |
|
||||||
|
| `openRouter` | `openai_chat` |
|
||||||
|
| `vercelAiGateway` | `openai_chat`, `openai_responses` |
|
||||||
|
| `microsoftFoundry` | `openai_chat`, `openai_responses`, `anthropic_messages` |
|
||||||
|
| `custom` | whatever was configured |
|
||||||
|
|
||||||
|
### 2. Allow / Block Lists
|
||||||
|
|
||||||
|
For each remaining provider, the gateway resolves the effective allow and
|
||||||
|
block patterns:
|
||||||
|
|
||||||
|
- **`inherit`**: use the provider's own model lists
|
||||||
|
- **`select`**: use the resource-selected subset of those lists
|
||||||
|
|
||||||
|
A candidate is kept only if `isAllowedByLists(requestedModel, allows, blocks)`
|
||||||
|
passes:
|
||||||
|
|
||||||
|
1. At least one allow pattern must match
|
||||||
|
2. No block pattern may match
|
||||||
|
|
||||||
|
Patterns support `*` and `?` globs (`gpt-*`, `claude-3-5-sonnet-?`).
|
||||||
|
|
||||||
|
### 3. Most Specific Allow Pattern
|
||||||
|
|
||||||
|
Among providers that allow the model, keep those whose matching allow
|
||||||
|
pattern is most specific:
|
||||||
|
|
||||||
|
1. Exact keys beat patterns
|
||||||
|
2. Fewer wildcard characters win
|
||||||
|
3. Longer literal length wins
|
||||||
|
|
||||||
|
Example: `gpt-4o` beats `gpt-*` beats `*`.
|
||||||
|
|
||||||
|
### 4. Catalog Ownership
|
||||||
|
|
||||||
|
When specificity is tied (common with multiple `*` allows), score each
|
||||||
|
provider against the known model catalog:
|
||||||
|
|
||||||
|
| Score | Meaning |
|
||||||
|
|------:|---------|
|
||||||
|
| 2 | Typed provider whose catalog contains the model (`openai` → openai catalog, `anthropic` → anthropic, etc.) |
|
||||||
|
| 1 | Aggregator or custom (`openRouter`, `vercelAiGateway`, `custom`) and the model exists somewhere in the catalog |
|
||||||
|
| 0 | No ownership signal (typed catalog miss, or unknown model on aggregator/custom) |
|
||||||
|
|
||||||
|
Model id lookup tries the raw id, then a stripped `vendor/model` form
|
||||||
|
(e.g. `openai/gpt-4o` → also try `gpt-4o`).
|
||||||
|
|
||||||
|
Typed providers map to catalog providers as:
|
||||||
|
|
||||||
|
| Provider type | Catalog |
|
||||||
|
|---------------|---------|
|
||||||
|
| `openai` | `openai` |
|
||||||
|
| `anthropic` | `anthropic` |
|
||||||
|
| `googleGemini` | `gemini` |
|
||||||
|
| `vertexAi` | `vertex` |
|
||||||
|
| `bedrock` | `bedrock` |
|
||||||
|
| `microsoftFoundry` | `azure` |
|
||||||
|
| `openRouter` / `vercelAiGateway` / `custom` | none (aggregator/custom path) |
|
||||||
|
|
||||||
|
### 5. Provider Class Preference
|
||||||
|
|
||||||
|
If catalog ownership is still tied, prefer:
|
||||||
|
|
||||||
|
| Rank | Class |
|
||||||
|
|-----:|-------|
|
||||||
|
| 2 | Native typed provider (`openai`, `anthropic`, `googleGemini`, …) |
|
||||||
|
| 1 | Aggregator (`openRouter`, `vercelAiGateway`) |
|
||||||
|
| 0 | `custom` |
|
||||||
|
|
||||||
|
### 6. Ambiguous Error
|
||||||
|
|
||||||
|
If more than one distinct provider remains after all steps, the gateway
|
||||||
|
rejects the request:
|
||||||
|
|
||||||
|
```
|
||||||
|
Model "<id>" is ambiguous across multiple AI providers on this resource
|
||||||
|
```
|
||||||
|
|
||||||
|
Typical remaining ties: two OpenAI-type providers both with `*`, or two
|
||||||
|
customs advertising the same capability for an unknown model.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Assume each provider below is attached and enabled on the same inference
|
||||||
|
resource.
|
||||||
|
|
||||||
|
### Example A: OpenAI + Anthropic, Both `*`
|
||||||
|
|
||||||
|
| Provider | Allow | Capabilities |
|
||||||
|
|----------|-------|--------------|
|
||||||
|
| OpenAI | `*` | `openai_chat`, `openai_responses` |
|
||||||
|
| Anthropic | `*` | `anthropic_messages` |
|
||||||
|
|
||||||
|
**Request:** `POST /v1/chat/completions` with `model: "gpt-4o"`
|
||||||
|
|
||||||
|
1. Capability → only OpenAI remains
|
||||||
|
2. Allow → OpenAI matches `*`
|
||||||
|
3. Result → **OpenAI**
|
||||||
|
|
||||||
|
Anthropic never reaches pattern or catalog scoring. Capability alone decides.
|
||||||
|
|
||||||
|
**Request:** `POST /v1/messages` with `model: "claude-3-5-sonnet-latest"`
|
||||||
|
|
||||||
|
1. Capability → only Anthropic remains
|
||||||
|
2. Result → **Anthropic**
|
||||||
|
|
||||||
|
### Example B: OpenAI + OpenRouter, Both `*`
|
||||||
|
|
||||||
|
| Provider | Allow | Capabilities |
|
||||||
|
|----------|-------|--------------|
|
||||||
|
| OpenAI | `*` | `openai_chat`, … |
|
||||||
|
| OpenRouter | `*` | `openai_chat` |
|
||||||
|
|
||||||
|
**Request:** `POST /v1/chat/completions` with `model: "gpt-4o"`
|
||||||
|
|
||||||
|
1. Capability → both remain (`openai_chat`)
|
||||||
|
2. Allow → both match `*`
|
||||||
|
3. Specificity → tie (`*` vs `*`)
|
||||||
|
4. Catalog → OpenAI scores `2` (owns `gpt-4o`); OpenRouter scores `1`
|
||||||
|
5. Result → **OpenAI**
|
||||||
|
|
||||||
|
### Example C: OpenRouter Only Serving a Claude Model Over OpenAI Chat
|
||||||
|
|
||||||
|
| Provider | Allow | Capabilities |
|
||||||
|
|----------|-------|--------------|
|
||||||
|
| OpenRouter | `*` | `openai_chat` |
|
||||||
|
|
||||||
|
**Request:** `POST /v1/chat/completions` with `model: "anthropic/claude-3.5-sonnet"`
|
||||||
|
|
||||||
|
1. Capability → OpenRouter remains
|
||||||
|
2. Only one candidate → **OpenRouter**
|
||||||
|
|
||||||
|
No tie-breaking needed.
|
||||||
|
|
||||||
|
### Example D: OpenAI (`gpt-*`) + OpenRouter (`*`)
|
||||||
|
|
||||||
|
| Provider | Allow |
|
||||||
|
|----------|-------|
|
||||||
|
| OpenAI | `gpt-*` |
|
||||||
|
| OpenRouter | `*` |
|
||||||
|
|
||||||
|
**Request:** `model: "gpt-4o"` on `openai_chat`
|
||||||
|
|
||||||
|
1. Capability → both
|
||||||
|
2. Allow → both match
|
||||||
|
3. Specificity → OpenAI's `gpt-*` beats OpenRouter's `*`
|
||||||
|
4. Result → **OpenAI**
|
||||||
|
|
||||||
|
Catalog scoring is not needed because specificity already unique'd the set.
|
||||||
|
|
||||||
|
### Example E: OpenAI + Anthropic With Overlapping Custom Capabilities
|
||||||
|
|
||||||
|
Someone grants Anthropic `openai_chat` as well (non-default).
|
||||||
|
|
||||||
|
| Provider | Allow | Capabilities |
|
||||||
|
|----------|-------|--------------|
|
||||||
|
| OpenAI | `*` | `openai_chat`, … |
|
||||||
|
| Anthropic | `*` | `anthropic_messages`, `openai_chat` |
|
||||||
|
|
||||||
|
**Request:** `POST /v1/chat/completions` with `model: "gpt-4o"`
|
||||||
|
|
||||||
|
1. Capability → both remain
|
||||||
|
2. Allow → both match `*`
|
||||||
|
3. Specificity → tie
|
||||||
|
4. Catalog → OpenAI `2`, Anthropic `0` (`gpt-4o` is not in the anthropic catalog)
|
||||||
|
5. Result → **OpenAI**
|
||||||
|
|
||||||
|
### Example F: Two Aggregators, Known Model
|
||||||
|
|
||||||
|
| Provider | Allow |
|
||||||
|
|----------|-------|
|
||||||
|
| OpenRouter | `*` |
|
||||||
|
| Vercel AI Gateway | `*` |
|
||||||
|
|
||||||
|
**Request:** `model: "gpt-4o"` on `openai_chat`
|
||||||
|
|
||||||
|
1. Capability → both
|
||||||
|
2. Allow / specificity → tie
|
||||||
|
3. Catalog → both score `1` (known model, no typed owner in the set)
|
||||||
|
4. Class → both aggregators (rank `1`) → still tied
|
||||||
|
5. Result → **ambiguous error**
|
||||||
|
|
||||||
|
Attach a native OpenAI provider (or narrow one aggregator's allow list) to
|
||||||
|
make this determinable.
|
||||||
|
|
||||||
|
### Example G: Two OpenAI Providers, Both `*`
|
||||||
|
|
||||||
|
| Provider | Type | Allow |
|
||||||
|
|----------|------|-------|
|
||||||
|
| OpenAI Prod | `openai` | `*` |
|
||||||
|
| OpenAI Staging | `openai` | `*` |
|
||||||
|
|
||||||
|
**Request:** `model: "gpt-4o"`
|
||||||
|
|
||||||
|
1–5 all leave both candidates (same capability, same specificity, same
|
||||||
|
catalog ownership, same class).
|
||||||
|
|
||||||
|
Result → **ambiguous error**
|
||||||
|
|
||||||
|
Disambiguate with different allow patterns, disable one attachment, or
|
||||||
|
split across resources.
|
||||||
|
|
||||||
|
### Example H: Unknown Model Across Native + Aggregator
|
||||||
|
|
||||||
|
| Provider | Allow |
|
||||||
|
|----------|-------|
|
||||||
|
| OpenAI | `*` |
|
||||||
|
| OpenRouter | `*` |
|
||||||
|
|
||||||
|
**Request:** `model: "my-fine-tune-v3"` (not in catalog)
|
||||||
|
|
||||||
|
1. Capability → both
|
||||||
|
2. Allow / specificity → tie
|
||||||
|
3. Catalog → both score `0` (typed miss + unknown aggregator model)
|
||||||
|
4. Class → OpenAI (`2`) beats OpenRouter (`1`)
|
||||||
|
5. Result → **OpenAI**
|
||||||
|
|
||||||
|
## Practical Guidance
|
||||||
|
|
||||||
|
- Native OpenAI + Anthropic with `*` is safe. Different default APIs never
|
||||||
|
collide.
|
||||||
|
- OpenAI + OpenRouter with `*` is usually fine for catalog-known OpenAI
|
||||||
|
models. Native wins.
|
||||||
|
- Prefer specific allow patterns (`gpt-4o`, `gpt-*`) when two providers share
|
||||||
|
a capability.
|
||||||
|
- Two providers of the same type both using `*` will stay ambiguous. Narrow
|
||||||
|
at least one allow list.
|
||||||
|
- Custom providers only win ties when no stronger native/aggregator signal
|
||||||
|
remains.
|
||||||
|
|
||||||
|
## Related Behavior
|
||||||
|
|
||||||
|
- **Saving providers on a resource does not reject overlapping allows.**
|
||||||
|
Collisions are resolved (or rejected) per request.
|
||||||
|
- Budgets, auth, and upstream URL / target routing run after a single
|
||||||
|
provider has been selected.
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
# How to build a CRUD endpoint in this repo
|
||||||
|
|
||||||
|
Reference for adding a new CRUD entity to the server. Based on two real
|
||||||
|
examples already in the codebase — read them side by side with this doc:
|
||||||
|
|
||||||
|
- **Public / open-source (Community Edition) pattern**: `server/routers/aiProvider/`
|
||||||
|
- **Enterprise-only pattern**: `server/private/routers/alertRule/`
|
||||||
|
|
||||||
|
The two are structurally identical. The only difference is *where the files
|
||||||
|
live* and *which router they get wired into*.
|
||||||
|
|
||||||
|
## 1. Decide: public or private?
|
||||||
|
|
||||||
|
- `server/routers/<entity>/` — ships in the open-source Community Edition.
|
||||||
|
Anyone running Pangolin gets this.
|
||||||
|
- `server/private/routers/<entity>/` — Enterprise/SaaS only. Gated behind
|
||||||
|
`verifyValidLicense` (and often `verifyValidSubscription(tierMatrix.x)`).
|
||||||
|
Every file here starts with the Fossorial Commercial License header block
|
||||||
|
(copy it verbatim from an existing private file).
|
||||||
|
|
||||||
|
Everything below applies to both — swap `@server/...` for `#private/...`
|
||||||
|
import paths and add license headers when building the private version.
|
||||||
|
|
||||||
|
## 2. Directory layout
|
||||||
|
|
||||||
|
One folder per entity, one file per operation, a barrel `index.ts`:
|
||||||
|
|
||||||
|
```
|
||||||
|
server/routers/<entity>/
|
||||||
|
index.ts # export * from each operation file + ./types
|
||||||
|
types.ts # response payload types + row->public mapper
|
||||||
|
validation.ts # zod schemas/refinements shared by create + update (optional)
|
||||||
|
create<Entity>.ts
|
||||||
|
list<Entities>.ts
|
||||||
|
get<Entity>.ts
|
||||||
|
update<Entity>.ts
|
||||||
|
delete<Entity>.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
`index.ts` is a flat barrel:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export * from "./createAiProvider";
|
||||||
|
export * from "./listAiProviders";
|
||||||
|
export * from "./getAiProvider";
|
||||||
|
export * from "./updateAiProvider";
|
||||||
|
export * from "./deleteAiProvider";
|
||||||
|
export * from "./types";
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Anatomy of a single handler
|
||||||
|
|
||||||
|
Every handler file (`create<Entity>.ts`, etc.) follows the same shape:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { <table>, db } from "@server/db";
|
||||||
|
import response from "@server/lib/response";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import type { GetXResponse } from "@server/routers/<entity>/types";
|
||||||
|
|
||||||
|
const paramsSchema = z.strictObject({
|
||||||
|
orgId: z.string().nonempty() // or entityId: z.coerce.number().int().positive()
|
||||||
|
});
|
||||||
|
|
||||||
|
const bodySchema = z.strictObject({ /* ... */ }); // create/update only
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get", // put | post | delete
|
||||||
|
path: "/org/{orgId}/x",
|
||||||
|
description: "...",
|
||||||
|
tags: [OpenAPITags.<Entity>],
|
||||||
|
request: { params: paramsSchema, /* body: {...} for write ops, query: for list */ },
|
||||||
|
responses: { 200: { description: "Successful response" } }
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function getX(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
|
try {
|
||||||
|
const parsedParams = paramsSchema.safeParse(req.params);
|
||||||
|
if (!parsedParams.success) {
|
||||||
|
return next(createHttpError(HttpCode.BAD_REQUEST, fromError(parsedParams.error).toString()));
|
||||||
|
}
|
||||||
|
// parse body too, if present, same pattern
|
||||||
|
|
||||||
|
// ...business logic against db...
|
||||||
|
|
||||||
|
if (!row) {
|
||||||
|
return next(createHttpError(HttpCode.NOT_FOUND, `X with ID ${id} not found`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return response<GetXResponse>(res, {
|
||||||
|
data: { /* ... */ },
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "X retrieved successfully",
|
||||||
|
status: HttpCode.OK
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Rules to keep consistent with the rest of the codebase:
|
||||||
|
|
||||||
|
- `z.strictObject` for params/body — rejects unknown keys.
|
||||||
|
- Params parsed first, then body; each on its own `safeParse` + early
|
||||||
|
`next(createHttpError(...))` — never throw raw errors.
|
||||||
|
- Every handler registers itself with the OpenAPI `registry` even if nobody
|
||||||
|
reads the spec directly — it's how `/api/v1/docs` stays accurate.
|
||||||
|
- Catch-all `try/catch` at the bottom: `logger.error(error)` +
|
||||||
|
generic `500` message. Never leak internal error details to the client.
|
||||||
|
- Use `response<T>(res, { data, success, error, message, status })` from
|
||||||
|
`@server/lib/response` for every response, success or otherwise (errors go
|
||||||
|
through `next(createHttpError(...))` instead, not through `response`).
|
||||||
|
- If the route already ran an access-control middleware that fetched the row
|
||||||
|
(see §5), reuse it instead of re-querying:
|
||||||
|
`req.aiProvider && req.aiProvider.providerId === providerId ? [req.aiProvider] : await db.select()...`
|
||||||
|
|
||||||
|
### List handler specifics
|
||||||
|
|
||||||
|
Pagination is a fixed shape (`page`, `pageSize`, optional `query` for
|
||||||
|
search). See `listAiProviders.ts`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const listSchema = z.object({
|
||||||
|
pageSize: z.coerce.number<string>().int().positive().optional().catch(20).default(20),
|
||||||
|
page: z.coerce.number<string>().int().min(0).optional().catch(1).default(1),
|
||||||
|
query: z.string().optional()
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the count query and the page query in `Promise.all`, and return
|
||||||
|
`PaginatedResponse<{ items: T[] }>` (`@server/types/Pagination`) with
|
||||||
|
`{ total, pageSize, page }`.
|
||||||
|
|
||||||
|
### types.ts specifics
|
||||||
|
|
||||||
|
- Define one response type per operation: `List<Entities>Response`,
|
||||||
|
`Get<Entity>Response`, `CreateOrEdit<Entity>Response` (create and update
|
||||||
|
commonly share a response shape).
|
||||||
|
- If the raw DB row needs to be shaped for clients (decrypting secrets,
|
||||||
|
parsing a serialized column, hiding a column), put a `toPublic<Entity>()`
|
||||||
|
mapper here — see `toPublicAiProvider` for the pattern of stripping
|
||||||
|
`apiKey`/serialized columns and re-adding decrypted/parsed versions.
|
||||||
|
|
||||||
|
### validation.ts specifics
|
||||||
|
|
||||||
|
Only needed when create and update share non-trivial zod pieces (enums,
|
||||||
|
`superRefine` cross-field rules). Export the raw schemas (`z.enum([...])`)
|
||||||
|
and refinement functions, and import them into both `createX.ts` and
|
||||||
|
`updateX.ts` — see `aiProvider/validation.ts`'s
|
||||||
|
`refineProviderUpstreamFields`.
|
||||||
|
|
||||||
|
## 4. Wire up an access-control middleware (for id-scoped routes)
|
||||||
|
|
||||||
|
For routes scoped to a single row (`/x/:xId`, as opposed to
|
||||||
|
`/org/:orgId/x` create/list), add a `verify<Entity>Access` middleware in
|
||||||
|
`server/middlewares/` (or `server/private/middlewares/` for enterprise-only
|
||||||
|
entities) and export it from that directory's `index.ts`.
|
||||||
|
|
||||||
|
Pattern (`verifyAiProviderAccess.ts`):
|
||||||
|
|
||||||
|
1. Read the id param, `Number.parseInt`/validate it.
|
||||||
|
2. Load the row by id.
|
||||||
|
3. `404` if it doesn't exist.
|
||||||
|
4. Resolve the row's `orgId`, then check/attach `req.userOrg` (query
|
||||||
|
`userOrgs` if not already on the request), `403` if the user isn't in
|
||||||
|
that org.
|
||||||
|
5. Run `checkOrgAccessPolicy` if `req.orgPolicyAllowed` hasn't been resolved
|
||||||
|
yet.
|
||||||
|
6. Set `req.userOrgId`, `req.userOrgRoleIds`, and stash the row on the
|
||||||
|
request (e.g. `req.aiProvider = provider`) so downstream handlers and
|
||||||
|
`verifyUserHasAction` don't have to refetch it.
|
||||||
|
|
||||||
|
Org-scoped create/list routes (`/org/:orgId/x`) don't need a bespoke
|
||||||
|
middleware — they use the existing generic `verifyOrgAccess` from
|
||||||
|
`@server/middlewares`.
|
||||||
|
|
||||||
|
## 5. Register an action + permission check
|
||||||
|
|
||||||
|
Add one `ActionsEnum` entry per operation in `server/auth/actions.ts`,
|
||||||
|
grouped near the entity's other actions, named `create<Entity>`,
|
||||||
|
`get<Entity>`, `update<Entity>`, `delete<Entity>`, `list<Entities>`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
createAiProvider = "createAiProvider",
|
||||||
|
deleteAiProvider = "deleteAiProvider",
|
||||||
|
getAiProvider = "getAiProvider",
|
||||||
|
listAiProviders = "listAiProviders",
|
||||||
|
updateAiProvider = "updateAiProvider",
|
||||||
|
```
|
||||||
|
|
||||||
|
Every route uses `verifyUserHasAction(ActionsEnum.x)` to check the caller's
|
||||||
|
role/permissions for that action, and mutating routes (create/update/delete)
|
||||||
|
follow it with `logActionAudit(ActionsEnum.x)` to record the action in the
|
||||||
|
audit log.
|
||||||
|
|
||||||
|
## 6. Register the routes
|
||||||
|
|
||||||
|
There are four router files; which one(s) you touch depends on public vs.
|
||||||
|
private and user-facing vs. service-to-service:
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `server/routers/external.ts` | Public, user-facing API. Exports `authenticated`, `unauthenticated`, `authRouter` Express routers. |
|
||||||
|
| `server/routers/internal.ts` | Public, internal service-to-service API (gerbil, badger, traefik-config) — no user auth, exports `internalRouter`. |
|
||||||
|
| `server/private/routers/external.ts` | Enterprise-only, user-facing. Imports `authenticated`/`unauthenticated`/`authRouter` **from the public `external.ts`** and re-exports them, then adds more routes on top. |
|
||||||
|
| `server/private/routers/internal.ts` | Enterprise-only, service-to-service. Same re-export trick with `internalRouter`. |
|
||||||
|
|
||||||
|
Private router files always start:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {
|
||||||
|
unauthenticated as ua,
|
||||||
|
authenticated as a,
|
||||||
|
authRouter as aa
|
||||||
|
} from "@server/routers/external";
|
||||||
|
|
||||||
|
export const authenticated = a;
|
||||||
|
export const unauthenticated = ua;
|
||||||
|
export const authRouter = aa;
|
||||||
|
```
|
||||||
|
|
||||||
|
...and then call `authenticated.get/put/post/delete(...)` to bolt on
|
||||||
|
additional, enterprise-only routes on the *same* router instances the public
|
||||||
|
build uses. This is why the private build has strictly more routes than the
|
||||||
|
public build, not a divergent copy.
|
||||||
|
|
||||||
|
### Route registration order (mutating vs read)
|
||||||
|
|
||||||
|
Standard middleware chain per verb, using `alertRule`'s registrations as the
|
||||||
|
template:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Create — org-scoped, no row exists yet
|
||||||
|
authenticated.put(
|
||||||
|
"/org/:orgId/x",
|
||||||
|
verifyValidLicense, // private/enterprise routes only
|
||||||
|
verifyOrgAccess,
|
||||||
|
verifyLimits, // if the entity counts against a plan limit
|
||||||
|
verifyUserHasAction(ActionsEnum.createX),
|
||||||
|
logActionAudit(ActionsEnum.createX),
|
||||||
|
x.createX
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update — row-scoped
|
||||||
|
authenticated.post(
|
||||||
|
"/org/:orgId/x/:xId", // or "/x/:xId" if id is globally unique
|
||||||
|
verifyValidLicense,
|
||||||
|
verifyOrgAccess, // or verifyXAccess if globally-keyed
|
||||||
|
verifyUserHasAction(ActionsEnum.updateX),
|
||||||
|
logActionAudit(ActionsEnum.updateX),
|
||||||
|
x.updateX
|
||||||
|
);
|
||||||
|
|
||||||
|
// Delete — row-scoped
|
||||||
|
authenticated.delete(
|
||||||
|
"/org/:orgId/x/:xId",
|
||||||
|
verifyValidLicense,
|
||||||
|
verifyOrgAccess,
|
||||||
|
verifyUserHasAction(ActionsEnum.deleteX),
|
||||||
|
logActionAudit(ActionsEnum.deleteX),
|
||||||
|
x.deleteX
|
||||||
|
);
|
||||||
|
|
||||||
|
// List — org-scoped, read-only, no audit log
|
||||||
|
authenticated.get(
|
||||||
|
"/org/:orgId/xs",
|
||||||
|
verifyValidLicense,
|
||||||
|
verifyOrgAccess,
|
||||||
|
verifyUserHasAction(ActionsEnum.listXs),
|
||||||
|
x.listXs
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get one — row-scoped, read-only, no audit log
|
||||||
|
authenticated.get(
|
||||||
|
"/org/:orgId/x/:xId",
|
||||||
|
verifyValidLicense,
|
||||||
|
verifyOrgAccess,
|
||||||
|
verifyUserHasAction(ActionsEnum.getX),
|
||||||
|
x.getX
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- HTTP verbs: `PUT` = create, `POST` = update, `GET` = read, `DELETE` =
|
||||||
|
delete. This repo does not use `PATCH` for entity updates (site
|
||||||
|
provisioning keys are the one exception, using `PATCH`).
|
||||||
|
- `verifyValidLicense` is only needed on private/enterprise routes; public
|
||||||
|
OSS routes skip it.
|
||||||
|
- Use `verifyValidSubscription(tierMatrix.someFeature)` right after
|
||||||
|
`verifyValidLicense` when a feature is gated to specific SaaS tiers (see
|
||||||
|
`tierMatrix` usages in `server/private/routers/external.ts`).
|
||||||
|
- `verifyLimits` goes on create routes for entities that count against a
|
||||||
|
plan/seat limit.
|
||||||
|
- For entities keyed by a globally-unique id (not nested under `/org/:orgId`),
|
||||||
|
use the dedicated `verify<Entity>Access` middleware from §4 instead of
|
||||||
|
`verifyOrgAccess` on the row-scoped routes (see how `/ai-provider/:providerId`
|
||||||
|
uses `verifyAiProviderAccess`, while `/org/:orgId/ai-provider` create/list
|
||||||
|
use plain `verifyOrgAccess`).
|
||||||
|
- Read-only routes (`get`, `list`) skip `logActionAudit` — only mutations are
|
||||||
|
audited.
|
||||||
|
- `internal*.ts` routes are for trusted internal callers (gerbil/badger
|
||||||
|
sidecars) and generally skip user-facing auth entirely, using
|
||||||
|
`verifySessionUserMiddleware` / `verifyUserFromResourceSessionMiddleware`
|
||||||
|
instead of `verifyOrgAccess`/`verifyUserHasAction`. CRUD entities almost
|
||||||
|
never need internal router entries — only add one if a sidecar process
|
||||||
|
needs direct access to the resource.
|
||||||
|
|
||||||
|
## 7. The `#dynamic` alias (advanced — most CRUD work can ignore this)
|
||||||
|
|
||||||
|
Some middleware (e.g. `logActionAudit`) needs a real implementation in the
|
||||||
|
enterprise/SaaS build but a no-op stub in the open-source build, while
|
||||||
|
being imported by identical code in `server/routers/external.ts` in both
|
||||||
|
builds. That's done via the `#dynamic/*` import alias, which
|
||||||
|
`tsconfig.oss.json` points at `./server/*` and `tsconfig.enterprise.json` /
|
||||||
|
`tsconfig.saas.json` point at `./server/private/*`. You only need this
|
||||||
|
pattern if you're adding a genuinely dual-implementation hook; a normal
|
||||||
|
private-only CRUD entity (like `alertRule`) never touches `#dynamic` — it
|
||||||
|
just lives entirely under `server/private/` and is imported with `#private/*`
|
||||||
|
directly from `server/private/routers/external.ts`.
|
||||||
|
|
||||||
|
## 8. Checklist for a new entity
|
||||||
|
|
||||||
|
1. Add the DB table to `server/db/pg/schema/schema.ts` (and sqlite schema if
|
||||||
|
applicable).
|
||||||
|
2. Add `ActionsEnum` entries in `server/auth/actions.ts`.
|
||||||
|
3. Create `server/routers/<entity>/` (or `server/private/routers/<entity>/`):
|
||||||
|
`types.ts`, optional `validation.ts`, one file per operation, `index.ts`
|
||||||
|
barrel.
|
||||||
|
4. If routes are row-scoped by a global id, add
|
||||||
|
`verify<Entity>Access.ts` to `server/middlewares/` or
|
||||||
|
`server/private/middlewares/`, and export it from that directory's
|
||||||
|
`index.ts`.
|
||||||
|
5. Wire routes into `external.ts` (public or private) following the verb/
|
||||||
|
middleware table in §6. Add to `internal.ts` only if a sidecar needs
|
||||||
|
direct access.
|
||||||
|
6. Add license header block to every new file if it's under `server/private/`.
|
||||||
@@ -50,7 +50,7 @@ services:
|
|||||||
- 80:80{{end}}
|
- 80:80{{end}}
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
image: docker.io/traefik:v3.6
|
image: docker.io/traefik:v3.7
|
||||||
container_name: traefik
|
container_name: traefik
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
{{if .InstallGerbil}}network_mode: service:gerbil # Ports appear on the gerbil service{{end}}{{if not .InstallGerbil}}
|
{{if .InstallGerbil}}network_mode: service:gerbil # Ports appear on the gerbil service{{end}}{{if not .InstallGerbil}}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ go 1.25.0
|
|||||||
require (
|
require (
|
||||||
github.com/charmbracelet/huh v1.0.0
|
github.com/charmbracelet/huh v1.0.0
|
||||||
github.com/charmbracelet/lipgloss v1.1.0
|
github.com/charmbracelet/lipgloss v1.1.0
|
||||||
golang.org/x/term v0.44.0
|
golang.org/x/term v0.45.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,6 +33,6 @@ require (
|
|||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
golang.org/x/sync v0.15.0 // indirect
|
golang.org/x/sync v0.15.0 // indirect
|
||||||
golang.org/x/sys v0.46.0 // indirect
|
golang.org/x/sys v0.47.0 // indirect
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
|||||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
|
||||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ var redisFlag *bool
|
|||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
crowdsecFlag := flag.Bool("crowdsec", false, "Enable the CrowdSec installation prompt")
|
crowdsecFlag := flag.Bool("crowdsec", false, "Enable the CrowdSec installation prompt")
|
||||||
redisFlag = flag.Bool("redis", false, "Install Redis as cacheing solution. Required for HA. Not required for the Enterprise version.")
|
redisFlag = flag.Bool("redis", false, "Install Redis as caching solution. Required for HA. Not required for the Enterprise version.")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// print a banner about prerequisites - opening port 80, 443, 51820, and 21820 on the VPS and firewall and pointing your domain to the VPS IP with a records. Docs are at http://localhost:3000/Getting%20Started/dns-networking
|
// print a banner about prerequisites - opening port 80, 443, 51820, and 21820 on the VPS and firewall and pointing your domain to the VPS IP with a records. Docs are at http://localhost:3000/Getting%20Started/dns-networking
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Моля, уверете се, че сте влезли като правилния потребител.",
|
"inviteLoginUser": "Моля, уверете се, че сте влезли като правилния потребител.",
|
||||||
"inviteErrorNoUser": "Съжаляваме, но изглежда, че поканата, до която се опитвате да получите достъп, не е за съществуващ потребител.",
|
"inviteErrorNoUser": "Съжаляваме, но изглежда, че поканата, до която се опитвате да получите достъп, не е за съществуващ потребител.",
|
||||||
"inviteCreateUser": "Моля, първо създайте акаунт.",
|
"inviteCreateUser": "Моля, първо създайте акаунт.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Поканите могат да се приемат само от вътрешни акаунти. Отпишете се и влезте с вашата парола за този имейл.",
|
||||||
|
"inviteLoginInternalOnly": "Поканите изискват вътрешен акаунт с парола. Създайте акаунт или влезте с вашата парола.",
|
||||||
"goHome": "Отиди вкъщи",
|
"goHome": "Отиди вкъщи",
|
||||||
"inviteLogInOtherUser": "Влезте като друг потребител",
|
"inviteLogInOtherUser": "Влезте като друг потребител",
|
||||||
"createAnAccount": "Създайте профил",
|
"createAnAccount": "Създайте профил",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Потвърдете изтриването на споделима връзка",
|
"shareDeleteConfirm": "Потвърдете изтриването на споделима връзка",
|
||||||
"shareQuestionRemove": "Сигурни ли сте, че искате да изтриете тази споделена връзка?",
|
"shareQuestionRemove": "Сигурни ли сте, че искате да изтриете тази споделена връзка?",
|
||||||
"shareMessageRemove": "След изтриване връзката вече няма да работи и всеки, който я използва, ще загуби достъп до ресурса.",
|
"shareMessageRemove": "След изтриване връзката вече няма да работи и всеки, който я използва, ще загуби достъп до ресурса.",
|
||||||
"shareTokenDescription": "Достъпният токен може да бъде предаван по два начина: като параметър или в хедърите на заявките. Те трябва да бъдат предавани от клиента при всяка заявка за удостоверен достъп.",
|
"shareTokenDescription": "Токен за достъп може да бъде предаден като параметър на заявка или в хедърите на заявката. По подразбиране трябва да се изпраща при всяка заявка. Ако е активирано задържане на сесията, първата заявка го заменя за сесийна бисквитка.",
|
||||||
"accessToken": "Достъп Токен",
|
"accessToken": "Достъп Токен",
|
||||||
"usageExamples": "Примери за използване",
|
"usageExamples": "Примери за използване",
|
||||||
"tokenId": "Токен ID",
|
"tokenId": "Токен ID",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Заглавие (по избор)",
|
"shareTitleOptional": "Заглавие (по избор)",
|
||||||
"sharePathOptional": "Път (по избор)",
|
"sharePathOptional": "Път (по избор)",
|
||||||
"sharePathDescription": "След удостоверяване, линкът ще препрати потребителите на този път.",
|
"sharePathDescription": "След удостоверяване, линкът ще препрати потребителите на този път.",
|
||||||
|
"shareAssociateUserOptional": "Асоцииране на потребител (по избор)",
|
||||||
|
"shareAssociateUserDescription": "Когато е настроен, заявките използващи този линк се свързват с потребителя в достъпните логове и заглавия за идентичност. Линкът се премахва, ако потребителят напусне организацията.",
|
||||||
|
"userSelect": "Изберете потребител",
|
||||||
|
"usersNotFound": "Няма намерени потребители",
|
||||||
"expireIn": "Изтече",
|
"expireIn": "Изтече",
|
||||||
"neverExpire": "Никога не изтича",
|
"neverExpire": "Никога не изтича",
|
||||||
|
"sharePersistSession": "Задръж сесия след първо използване",
|
||||||
|
"sharePersistSessionDescription": "Когато е активирано, първата заявка с този токен чрез параметър на заявка или хедър създава сесийна бисквитка, така че следващите заявки не се нуждаят от токена. Оставете го изключено за клиенти на API, които трябва да изпращат токена при всяка заявка.",
|
||||||
"shareExpireDescription": "Времето на изтичане е колко дълго връзката ще бъде използваема и ще предоставя достъп до ресурса. След това време, връзката няма да работи и потребителите, които са я използвали, ще загубят достъп до ресурса.",
|
"shareExpireDescription": "Времето на изтичане е колко дълго връзката ще бъде използваема и ще предоставя достъп до ресурса. След това време, връзката няма да работи и потребителите, които са я използвали, ще загубят достъп до ресурса.",
|
||||||
"shareSeeOnce": "Ще можете да видите този линк само веднъж. Уверете се, че го копирате.",
|
"shareSeeOnce": "Ще можете да видите този линк само веднъж. Уверете се, че го копирате.",
|
||||||
"shareAccessHint": "Всеки с тази връзка може да има достъп до ресурса. Споделяйте я с внимание.",
|
"shareAccessHint": "Всеки с тази връзка може да има достъп до ресурса. Споделяйте я с внимание.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Не е намерена държава.",
|
"noCountryFound": "Не е намерена държава.",
|
||||||
"siteSelectionDescription": "Този сайт ще осигури свързаност до целта.",
|
"siteSelectionDescription": "Този сайт ще осигури свързаност до целта.",
|
||||||
"resourceType": "Тип ресурс",
|
"resourceType": "Тип ресурс",
|
||||||
"resourceTypeDescription": "Това контролира протокола на ресурса и как той ще се визуализира в браузъра. Това не може да бъде променено по-късно.",
|
"resourceTypeDescription": "Това контролира протокола на ресурса и не може да се промени по-късно.",
|
||||||
|
"resourceTypeSearch": "Търсене на типове ресурси...",
|
||||||
|
"resourceTypeNotFound": "Не е намерен тип ресурс",
|
||||||
|
"resourceTypeHttpDescription": "Прокси на уеб трафик през HTTPS, използвайки име на домейн",
|
||||||
|
"resourceTypeInferenceDescription": "Направа на AI заявки чрез прикрепени доставчици",
|
||||||
|
"resourceTypeSshDescription": "Достъп до SSH сървър от уеб браузъра",
|
||||||
|
"resourceTypeRdpDescription": "Достъп до отдалечен работен плот от уеб браузъра",
|
||||||
|
"resourceTypeVncDescription": "Достъп до VNC десктоп от уеб браузъра",
|
||||||
|
"resourceTypeTcpDescription": "Прокси на суров TCP трафик, използвайки номер на порт",
|
||||||
|
"resourceTypeUdpDescription": "Прокси на суров UDP трафик, използвайки номер на порт",
|
||||||
|
"privateResourceTypeDescription": "Това контролира как клиентите достигат до ресурса. Това не може да бъде променено по-късно.",
|
||||||
|
"privateResourceTypeHostDescription": "Излагане на единичен хост в мрежата на сайта към свързани клиенти",
|
||||||
|
"privateResourceTypeCidrDescription": "Излагане на CIDR обхват в мрежата на сайта към свързани клиенти",
|
||||||
|
"privateResourceTypeHttpDescription": "Достъп до HTTP или HTTPS услуга чрез домейн",
|
||||||
|
"privateResourceTypeSshDescription": "Достъп до SSH сървър от свързани клиенти",
|
||||||
"resourceDomainDescription": "Ресурсът ще се обслужва на това напълно квалифицирано име на домейн.",
|
"resourceDomainDescription": "Ресурсът ще се обслужва на това напълно квалифицирано име на домейн.",
|
||||||
"resourceHTTPSSettings": "HTTPS настройки",
|
"resourceHTTPSSettings": "HTTPS настройки",
|
||||||
"resourceHTTPSSettingsDescription": "Конфигурирайте как ресурсът ще бъде достъпен по HTTPS",
|
"resourceHTTPSSettingsDescription": "Конфигурирайте как ресурсът ще бъде достъпен по HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Осигуряване",
|
"provisioningManage": "Осигуряване",
|
||||||
"provisioningDescription": "Управление на ключовете за осигуряване и преглед на чаканещите сайтове за одобрение.",
|
"provisioningDescription": "Управление на ключовете за осигуряване и преглед на чаканещите сайтове за одобрение.",
|
||||||
"pendingSites": "Чаканещи сайтове",
|
"pendingSites": "Чаканещи сайтове",
|
||||||
"siteApproveSuccess": "Сайтът е одобрен успешно",
|
"siteApproveSuccess": "Сайтът и свързаните ресурси са одобрени успешно",
|
||||||
"siteApproveError": "Грешка при одобряването на сайта",
|
"siteApproveError": "Грешка при одобряването на сайта",
|
||||||
|
"siteReject": "Отказ на сайт",
|
||||||
|
"siteQuestionReject": "Сигурни ли сте, че искате да откажете този сайт?",
|
||||||
|
"siteMessageReject": "Това ще изтрие окончателно сайта и всички свързани ресурси, които все още са на изчакване.",
|
||||||
|
"siteConfirmReject": "Потвърдете отказ на сайт",
|
||||||
|
"siteRejectSuccess": "Сайтът беше успешно отхвърлен",
|
||||||
|
"siteRejectError": "Грешка при отхвърляне на сайта",
|
||||||
"provisioningKeys": "Ключове за осигуряване",
|
"provisioningKeys": "Ключове за осигуряване",
|
||||||
"searchProvisioningKeys": "Търсене на ключове за осигуряване...",
|
"searchProvisioningKeys": "Търсене на ключове за осигуряване...",
|
||||||
"provisioningKeysAdd": "Генериране на ключ за осигуряване",
|
"provisioningKeysAdd": "Генериране на ключ за осигуряване",
|
||||||
@@ -466,8 +494,8 @@
|
|||||||
"provisioningKeysSave": "Запазете ключа за осигуряване",
|
"provisioningKeysSave": "Запазете ключа за осигуряване",
|
||||||
"provisioningKeysSaveDescription": "Ще можете да видите това само веднъж. Копирайте го на сигурно място.",
|
"provisioningKeysSaveDescription": "Ще можете да видите това само веднъж. Копирайте го на сигурно място.",
|
||||||
"provisioningKeysErrorCreate": "Грешка при създаване на ключ за осигуряване",
|
"provisioningKeysErrorCreate": "Грешка при създаване на ключ за осигуряване",
|
||||||
"provisioningKeysList": "Нов ключ за осигуряване",
|
"provisioningKeysList": "Нов ключ за разпределяне",
|
||||||
"provisioningKeysMaxBatchSize": "Максимален размер на пакет",
|
"provisioningKeysMaxBatchSize": "Максимален размер на пакета",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Неограничен размер на партида (без лимит)",
|
"provisioningKeysUnlimitedBatchSize": "Неограничен размер на партида (без лимит)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Неограничено",
|
"provisioningKeysMaxBatchUnlimited": "Неограничено",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Въведете валиден максимален размер на партида (1–1,000,000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Въведете валиден максимален размер на партида (1–1,000,000).",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "Никога",
|
"provisioningKeysNeverUsed": "Никога",
|
||||||
"provisioningKeysEdit": "Редактиране на ключ за осигуряване",
|
"provisioningKeysEdit": "Редактиране на ключ за осигуряване",
|
||||||
"provisioningKeysEditDescription": "Актуализирайте максималния размер на партида и времето на изтичане за този ключ.",
|
"provisioningKeysEditDescription": "Актуализирайте максималния размер на партида и времето на изтичане за този ключ.",
|
||||||
"provisioningKeysApproveNewSites": "Одобрете нови сайтове",
|
"provisioningKeysApproveNewSites": "Одобряване на нови сайтове",
|
||||||
"provisioningKeysApproveNewSitesDescription": "Автоматично одобряване на сайтове, които се регистрират с този ключ.",
|
"provisioningKeysApproveNewSitesDescription": "Автоматично одобряване на сайтове, които се регистрират с този ключ.",
|
||||||
"provisioningKeysUpdateError": "Грешка при актуализирането на ключа за осигуряване",
|
"provisioningKeysUpdateError": "Грешка при актуализирането на ключа за осигуряване",
|
||||||
"provisioningKeysUpdated": "Ключът за осигуряване е актуализиран",
|
"provisioningKeysUpdated": "Ключът за осигуряване е актуализиран",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Запази Настройки",
|
"authMethodsSave": "Запази Настройки",
|
||||||
"policyAuthStackTitle": "Удостоверяване",
|
"policyAuthStackTitle": "Удостоверяване",
|
||||||
"policyAuthStackDescription": "Контролирайте кои методи за удостоверяване са необходими за достъп до този ресурс",
|
"policyAuthStackDescription": "Контролирайте кои методи за удостоверяване са необходими за достъп до този ресурс",
|
||||||
|
"policyAuthInferenceStackDescription": "Изберете кои потребители и роли могат да се удостоверят с този AI шлюз",
|
||||||
"policyAuthOrLogicTitle": "Множество активни методи за удостоверяване",
|
"policyAuthOrLogicTitle": "Множество активни методи за удостоверяване",
|
||||||
"policyAuthOrLogicBanner": "Посетителите могат да се удостоверяват чрез който и да е от активните методи по-долу. Не е необходимо да преминават през всичките.",
|
"policyAuthOrLogicBanner": "Посетителите могат да се удостоверяват чрез който и да е от активните методи по-долу. Не е необходимо да преминават през всичките.",
|
||||||
"policyAuthMethodActive": "Активен",
|
"policyAuthMethodActive": "Активен",
|
||||||
"policyAuthMethodOff": "Изключено",
|
"policyAuthMethodOff": "Изключено",
|
||||||
"policyAuthSsoTitle": "Платформено SSO",
|
"policyAuthSsoTitle": "Платформено SSO",
|
||||||
"policyAuthSsoDescription": "Изисква вход чрез удостоверител на вашата организация",
|
"policyAuthSsoDescription": "Изисква вход чрез удостоверител на вашата организация",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "URL за вход",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Всеки потребител вече има клавиш за API идентичност, така че трябва да създадете виртуални API ключове само за клиенти, които не са потребители или за споделен достъп. Потребителите могат да получат своя ключ, като влязат с доставчик на идентичност на URL адреса на този ресурс, където ще бъде показан след вход.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Всеки потребител вече има клавиш за API идентичност, така че трябва да създадете виртуални API ключове само за клиенти, които не са потребители или за споделен достъп. Потребителите получават своя ключ тук след влизане с доставчик на идентичност.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} потребители, {roles} роли",
|
"policyAuthSsoSummary": "{idp} · {users} потребители, {roles} роли",
|
||||||
"policyAuthSsoDefaultIdp": "По подразбиране удостоверител",
|
"policyAuthSsoDefaultIdp": "По подразбиране удостоверител",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Добавете удостоверител по подразбиране",
|
"policyAuthAddDefaultIdentityProvider": "Добавете удостоверител по подразбиране",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Версия",
|
"newtVersion": "Версия",
|
||||||
"architecture": "Архитектура",
|
"architecture": "Архитектура",
|
||||||
"sites": "Сайтове",
|
"sites": "Сайтове",
|
||||||
"siteWgAnyClients": "Използвайте клиент на WireGuard, за да се свържете. Ще трябва да използвате вътрешните ресурси чрез IP адреса на връстника.",
|
"siteWgAnyClients": "Използвайте всеки WireGuard клиент, за да се свържете. Ще трябва да адресирате частни ресурси, използвайки IP на връстника.",
|
||||||
"siteWgCompatibleAllClients": "Съвместим с всички WireGuard клиенти",
|
"siteWgCompatibleAllClients": "Съвместим с всички WireGuard клиенти",
|
||||||
"siteWgManualConfigurationRequired": "Необходима е ръчна конфигурация",
|
"siteWgManualConfigurationRequired": "Необходима е ръчна конфигурация",
|
||||||
"userErrorNotAdminOrOwner": "Потребителят не е администратор или собственик",
|
"userErrorNotAdminOrOwner": "Потребителят не е администратор или собственик",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Нова роля е необходима",
|
"accessRoleErrorNewRequired": "Нова роля е необходима",
|
||||||
"accessRoleErrorRemove": "Неуспешно премахване на роля",
|
"accessRoleErrorRemove": "Неуспешно премахване на роля",
|
||||||
"accessRoleErrorRemoveDescription": "Възникна грешка при премахването на роля.",
|
"accessRoleErrorRemoveDescription": "Възникна грешка при премахването на роля.",
|
||||||
|
"accessRoleInferenceBudget": "AI Бюджет",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Конфигурирайте как членовете на тази роля ограничават използването на AI въз основа на лимити на разходи или жетони",
|
||||||
"accessRoleName": "Име на роля",
|
"accessRoleName": "Име на роля",
|
||||||
"accessRoleQuestionRemove": "Ще изтриете ролята `{name}`. Не можете да отмените това действие.",
|
"accessRoleQuestionRemove": "Ще изтриете ролята `{name}`. Не можете да отмените това действие.",
|
||||||
"accessRoleRemove": "Премахни роля",
|
"accessRoleRemove": "Премахни роля",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Създаване на Организационна Потребител",
|
"createOrgUser": "Създаване на Организационна Потребител",
|
||||||
"actionUpdateOrg": "Актуализиране на организацията",
|
"actionUpdateOrg": "Актуализиране на организацията",
|
||||||
"actionRemoveInvitation": "Премахване на поканата.",
|
"actionRemoveInvitation": "Премахване на поканата.",
|
||||||
|
"actionRemoveUserRole": "Премахване на роля на потребител",
|
||||||
"actionUpdateUser": "Актуализиране на потребител",
|
"actionUpdateUser": "Актуализиране на потребител",
|
||||||
"actionGetUser": "Получаване на потребител",
|
"actionGetUser": "Получаване на потребител",
|
||||||
"actionGetOrgUser": "Вземете потребител на организация",
|
"actionGetOrgUser": "Вземете потребител на организация",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Изтриване на сайта",
|
"actionDeleteSite": "Изтриване на сайта",
|
||||||
"actionGetSite": "Вземете сайт",
|
"actionGetSite": "Вземете сайт",
|
||||||
"actionListSites": "Изброяване на сайтове",
|
"actionListSites": "Изброяване на сайтове",
|
||||||
|
"actionCreateAiProvider": "Създаване на AI Доставчик",
|
||||||
|
"actionDeleteAiProvider": "Изтриване на AI Доставчик",
|
||||||
|
"actionGetAiProvider": "Получаване на AI Доставчик",
|
||||||
|
"actionListAiProviders": "Списък на AI Доставчици",
|
||||||
|
"actionUpdateAiProvider": "Актуализиране на AI Доставчик",
|
||||||
|
"actionCreateAiModel": "Създаване на AI Модел",
|
||||||
|
"actionDeleteAiModel": "Изтриване на AI Модел",
|
||||||
|
"actionGetAiModel": "Получаване на AI Модел",
|
||||||
|
"actionListAiModels": "Списък на AI Модели",
|
||||||
|
"actionUpdateAiModel": "Актуализиране на AI Модел",
|
||||||
|
"actionCreateAiBudget": "Създаване на AI Бюджет",
|
||||||
|
"actionDeleteAiBudget": "Изтриване на AI Бюджет",
|
||||||
|
"actionGetAiBudget": "Получаване на AI Бюджет",
|
||||||
|
"actionListAiBudgets": "Списък на AI Бюджети",
|
||||||
|
"actionUpdateAiBudget": "Актуализиране на AI Бюджет",
|
||||||
|
"actionListResourceAiModels": "Списък на модели на AI ресурс",
|
||||||
|
"actionSetResourceAiModels": "Задаване на модели на AI ресурс",
|
||||||
|
"actionCreateVirtualApiKey": "Създаване на Виртуален API Ключ",
|
||||||
|
"actionDeleteVirtualApiKey": "Изтриване на Виртуален API Ключ",
|
||||||
|
"actionGetVirtualApiKey": "Получаване на Виртуален API Ключ",
|
||||||
|
"actionListVirtualApiKeys": "Списък на Виртуални API Ключове",
|
||||||
|
"actionUpdateVirtualApiKey": "Актуализиране на Виртуален API Ключ",
|
||||||
"actionApplyBlueprint": "Приложи Чернова",
|
"actionApplyBlueprint": "Приложи Чернова",
|
||||||
"actionListBlueprints": "Списък с планове.",
|
"actionListBlueprints": "Списък с планове.",
|
||||||
"actionGetBlueprint": "Вземи план.",
|
"actionGetBlueprint": "Вземи план.",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Въведете конфигурационния токен от сървърната конзола.",
|
"setupTokenDescription": "Въведете конфигурационния токен от сървърната конзола.",
|
||||||
"setupTokenRequired": "Необходим е конфигурационен токен",
|
"setupTokenRequired": "Необходим е конфигурационен токен",
|
||||||
"actionUpdateSite": "Актуализиране на сайт",
|
"actionUpdateSite": "Актуализиране на сайт",
|
||||||
|
"actionApproveSite": "Одобряване на сайт",
|
||||||
|
"actionRejectSite": "Отказ на сайт",
|
||||||
"actionResetSiteBandwidth": "Нулиране на честотната лента на организацията",
|
"actionResetSiteBandwidth": "Нулиране на честотната лента на организацията",
|
||||||
"actionListSiteRoles": "Изброяване на позволените роли за сайта",
|
"actionListSiteRoles": "Изброяване на позволените роли за сайта",
|
||||||
"actionCreateResource": "Създаване на ресурс",
|
"actionCreateResource": "Създаване на ресурс",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Задайте ПИН код на ресурса",
|
"actionSetResourcePincode": "Задайте ПИН код на ресурса",
|
||||||
"actionSetResourceEmailWhitelist": "Задайте списък на одобрените имейл адреси за ресурса",
|
"actionSetResourceEmailWhitelist": "Задайте списък на одобрените имейл адреси за ресурса",
|
||||||
"actionGetResourceEmailWhitelist": "Вземете списък на одобрените имейл адреси за ресурса",
|
"actionGetResourceEmailWhitelist": "Вземете списък на одобрените имейл адреси за ресурса",
|
||||||
|
"actionListResourcePolicies": "Списък на ресурсни политики",
|
||||||
|
"actionCreateResourcePolicy": "Създаване на ресурсна политика",
|
||||||
"actionGetResourcePolicy": "Получете политика за ресурси",
|
"actionGetResourcePolicy": "Получете политика за ресурси",
|
||||||
"actionUpdateResourcePolicy": "Актуализирайте политика за ресурси",
|
"actionUpdateResourcePolicy": "Актуализирайте политика за ресурси",
|
||||||
|
"actionDeleteResourcePolicy": "Изтриване на ресурсна политика",
|
||||||
"actionSetResourcePolicyUsers": "Задайте потребители на ресурсна политика",
|
"actionSetResourcePolicyUsers": "Задайте потребители на ресурсна политика",
|
||||||
"actionSetResourcePolicyRoles": "Задайте роли на ресурсна политика",
|
"actionSetResourcePolicyRoles": "Задайте роли на ресурсна политика",
|
||||||
"actionSetResourcePolicyPassword": "Задайте парола на ресурсна политика",
|
"actionSetResourcePolicyPassword": "Задайте парола на ресурсна политика",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Списък с покани",
|
"actionListInvitations": "Списък с покани",
|
||||||
"actionExportLogs": "Експортиране на дневници",
|
"actionExportLogs": "Експортиране на дневници",
|
||||||
"actionViewLogs": "Преглед на дневници",
|
"actionViewLogs": "Преглед на дневници",
|
||||||
|
"actionCreateSiteProvisioningKey": "Създаване на ключ за предоставяне на сайт",
|
||||||
|
"actionListSiteProvisioningKeys": "Списък на ключовете за предоставяне на сайт",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Актуализиране на ключ за предоставяне на сайт",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Изтриване на ключ за предоставяне на сайт",
|
||||||
"noneSelected": "Нищо не е избрано",
|
"noneSelected": "Нищо не е избрано",
|
||||||
"orgNotFound2": "Няма намерени организации.",
|
"orgNotFound2": "Няма намерени организации.",
|
||||||
"search": "Търси…",
|
"search": "Търси…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Въведете кода от приложението за удостоверяване или един от вашите резервни кодове за еднократна употреба.",
|
"otpAuthDescription": "Въведете кода от приложението за удостоверяване или един от вашите резервни кодове за еднократна употреба.",
|
||||||
"otpAuthSubmit": "Изпрати код",
|
"otpAuthSubmit": "Изпрати код",
|
||||||
"idpContinue": "Или продължете със",
|
"idpContinue": "Или продължете със",
|
||||||
|
"idpLastUsed": "Последно използвано",
|
||||||
"otpAuthBack": "Назад към парола",
|
"otpAuthBack": "Назад към парола",
|
||||||
"navbar": "Навигационно меню",
|
"navbar": "Навигационно меню",
|
||||||
"navbarDescription": "Главно навигационно меню за приложението",
|
"navbarDescription": "Главно навигационно меню за приложението",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Създаване на машинен клиент",
|
"commandPaletteCreateMachineClient": "Създаване на машинен клиент",
|
||||||
"commandPaletteCreateAlertRule": "Създаване на правила за известия",
|
"commandPaletteCreateAlertRule": "Създаване на правила за известия",
|
||||||
"commandPaletteCreateIdentityProvider": "Създаване на доставчик на идентичност",
|
"commandPaletteCreateIdentityProvider": "Създаване на доставчик на идентичност",
|
||||||
|
"commandPaletteCreateAiProvider": "Създайте AI доставчик",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Създайте виртуален API ключ",
|
||||||
"commandPaletteToggleTheme": "Смяна на темата",
|
"commandPaletteToggleTheme": "Смяна на темата",
|
||||||
"commandPaletteChooseOrganization": "Изберете организация",
|
"commandPaletteChooseOrganization": "Изберете организация",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Покани",
|
"sidebarInvitations": "Покани",
|
||||||
"sidebarRoles": "Роли",
|
"sidebarRoles": "Роли",
|
||||||
"sidebarShareableLinks": "Споделими връзки",
|
"sidebarShareableLinks": "Споделими връзки",
|
||||||
|
"sidebarAiGateway": "AI Шлюз",
|
||||||
|
"sidebarAiProviders": "Доставчици",
|
||||||
|
"commandAiProviders": "AI Доставчици",
|
||||||
|
"sidebarVirtualApiKeys": "Виртуални API Ключове",
|
||||||
|
"sidebarMyApiKeys": "Вашите API Ключове",
|
||||||
|
"sidebarAccount": "Стартер",
|
||||||
|
"commandVirtualApiKeys": "Виртуални API Ключове",
|
||||||
|
"virtualApiKeysTitle": "Управление на Виртуални API Ключове",
|
||||||
|
"virtualApiKeysDescription": "Създаване и управление на ръчни API ключове за достъп до AI шлюза до публични AI шлюзове",
|
||||||
|
"virtualApiKeysTabIdentity": "Идентификационни ключове",
|
||||||
|
"virtualApiKeysTabVirtual": "Виртуални ключове",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Идентификационни ключове за всеки потребител",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Всеки потребител вече има клавиш за идентичност Pangolin за тази организация. Той е уникален за неговия профил и го удостоверява при достъп до AI шлюзове.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Пример",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Как получават своя ключ потребителите",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Посетете публичен AI шлюз URL адрес в браузъра и влезте с профила си.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Или отидете на <url></url> докато сте влезли.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Можете да създадете допълнителни виртуални API ключове в таба Виртуални ключове. Тези ключове могат да бъдат обхванати до конкретни публични AI шлюзове и при необходимост свързани с потребител. Създаването на ключ веднага предоставя достъп до избраните публични AI шлюзове.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Ръчно създаване на ключ",
|
||||||
|
"virtualApiKeysEmailIdentity": "Имейл идентификационни ключове",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Изпратете на всеки избран потребител или роля неговия ключ за идентичност Pangolin.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Изпратете на всички потребители",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Изпратете имейл на всеки член на организацията, който има акаунт имейл.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Потребители",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Роли",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Изпращане на имейли",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Идентификационни ключове изпратени",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Изпратени {sent} имейли.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} потребители бяха прескочени, защото нямат имейл адрес.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Изберете поне един потребител или роля, или изпратете на всички потребители.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Грешка при изпращането на идентификационни ключове",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Неуспех при изпращането на идентификационни ключове",
|
||||||
|
"virtualApiKeysBannerTitle": "Идентификационни ключове за всеки потребител",
|
||||||
|
"virtualApiKeysBannerDescription": "Всеки потребител вече има наличен идентификационен ключ на {keysUrl}. Можете също така да генерирате ръчно ключове тук, които предоставят директен достъп до публични AI шлюзове.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Преглеждане на идентификационни ключове",
|
||||||
|
"virtualApiKeys": "Виртуални API Ключове",
|
||||||
|
"virtualApiKeysSearch": "Търсене на ключове...",
|
||||||
|
"virtualApiKeysCreate": "Създаване на Виртуален API Ключ",
|
||||||
|
"virtualApiKeysCreateDescription": "Секретен ключ за всички публични AI шлюзове в тази организация",
|
||||||
|
"virtualApiKeysCreateButton": "Създаване на ключ",
|
||||||
|
"virtualApiKeysEmpty": "Все още няма Виртуални API Ключове",
|
||||||
|
"virtualApiKeysName": "Име",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Описание (по избор)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Свързване на потребител (по избор)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Свържете този ключ с потребител, за да проследя появата. След създаването този ключ веднага предоставя достъп до избраните публични AI шлюзове. Не е необходимо да свързвате потребител ръчно, за да бъде видим ресурсът. Ключът ще се появи и в профила на потребителя.",
|
||||||
|
"virtualApiKeysAllResources": "Всички публични AI шлюзове",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Позволете на този ключ да има достъп до всеки публичен AI шлюз в организацията",
|
||||||
|
"virtualApiKeysSelectResources": "Публични AI шлюзове",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Избор на ресурси",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Изберете кои публични AI шлюзове този ключ може да има достъп",
|
||||||
|
"virtualApiKeysNoResources": "Няма ресурси",
|
||||||
|
"virtualApiKeysSecret": "Ключ",
|
||||||
|
"virtualApiKeysCopyKey": "Копирайте този ключ. Можете да го видите отново по-късно от таблицата или при редактиране.",
|
||||||
|
"virtualApiKeysViewSecret": "Преглед на секрет",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Секрет за Виртуален API Ключ",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Този секрет предоставя достъп до публичните AI шлюзове, присвоени на този ключ",
|
||||||
|
"virtualApiKeysEdit": "Редактиране на Виртуален API Ключ",
|
||||||
|
"virtualApiKeysEditDescription": "Актуализирайте свързвания потребител и достъпа до публичния AI шлюз за този ключ",
|
||||||
|
"virtualApiKeysSaveButton": "Запазване на промените",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Изберете поне един публичен AI шлюз, или активирайте всички публични AI шлюзове",
|
||||||
|
"virtualApiKeysUpdated": "Виртуален API ключ е актуализиран",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Виртуалният API ключ е актуализиран",
|
||||||
|
"virtualApiKeysErrorUpdate": "Грешка при актуализация на виртуален API ключ",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Неуспех при актуализация на виртуален API ключ",
|
||||||
|
"virtualApiKeysErrorCreate": "Грешка при създаване на виртуален API ключ",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Неуспех при създаване на виртуален API ключ",
|
||||||
|
"virtualApiKeysErrorDelete": "Грешка при изтриване на виртуален API ключ",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Неуспех при изтриването на виртуален API ключ",
|
||||||
|
"virtualApiKeysDeleted": "Виртуален API ключ е изтрит",
|
||||||
|
"virtualApiKeysDeletedDescription": "Виртуалният API ключ е изтрит",
|
||||||
|
"virtualApiKeysDelete": "Изтриване на Виртуален API Ключ",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Изтриване на ключ",
|
||||||
|
"virtualApiKeysQuestionRemove": "Сигурни ли сте, че искате да изтриете този виртуален API ключ?",
|
||||||
|
"virtualApiKeysMessageRemove": "Клиентите, които използват този ключ, ще загубят достъп веднага.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Грешка при зареждане на секрет",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Неуспех при зареждането на секрета на виртуалния API ключ",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Неопределен",
|
||||||
|
"virtualApiKeysInferenceBudget": "Бюджет",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Конфигуриране как този ключ ограничава използването на AI въз основа на лимити на разходи или жетони",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Имейл ключ при генериране",
|
||||||
|
"virtualApiKeysEmailThisKey": "Имейл този ключ",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Изпратете ключа на свързания потребител и допълнителни адреси след създаването му",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Изпратете текущия ключ на свързания потребител и допълнителни адреси",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "Имейлът не е конфигуриран на този сървър",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Конфигурирайте SMTP за изпращане на виртуални API ключове.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Изпратете на свързан потребител",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Изпратете ключът на акаунтния имейл на свързания потребител",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Свържете потребител за изпращане на ключа на този потребител",
|
||||||
|
"virtualApiKeysEmailAdditional": "Допълнителни имейли",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Добавете имейл и натиснете Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Изберете свързания потребител или добавете поне един имейл адрес",
|
||||||
|
"myVirtualApiKeysTitle": "Вашите API Ключове",
|
||||||
|
"myVirtualApiKeysDescription": "Прегледайте вашия идентификационен ключ и всички виртуални API ключове, които ви се отнасят в тази организация",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Вашите API Ключове за {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Прегледайте вашия идентификационен ключ и виртуални API ключове, които ви се отнасят и могат да достъпят {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Идентификационен ключ",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Вашият Личен API Ключ",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Вашият личен ключ за тази организация. Той е уникален за вашия акаунт и се използва за идентификация при обаждания на AI Gateway ресурси.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Вашият Личен API Ключ за {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Вашият личен ключ за тази организация. Използвайте го, за да извикате {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Свързани ключове",
|
||||||
|
"myVirtualApiKeysManualDescription": "Ръчни виртуални API ключове, свързани от администратор към вашия акаунт",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Ръчни виртуални API ключове, свързани с вашия акаунт, които могат да достъпят {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Все още няма приписани ключове",
|
||||||
|
"myVirtualApiKeysKindUser": "Идентичност",
|
||||||
|
"myVirtualApiKeysKindManual": "Ръчен",
|
||||||
|
"myVirtualApiKeysUnnamed": "Неназован ключ",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Разкриване на секрет",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Този секрет ви идентифицира за AI Gateway ресурси",
|
||||||
|
"aiClientConfigTitle": "Конфигуриране на кодиращи агенти",
|
||||||
|
"aiClientConfigDescription": "Копирайте конфигурацията за популярни кодиращи агенти или оставете Pangolin CLI да я настрои автоматично за вас.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Инструментът за кодиране на Anthropic за терминала.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Инструментът за кодиране на OpenAI за терминала.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Отворен кодиращ агент за терминал.",
|
||||||
|
"aiClientConfigDescriptionCursor": "AI редактор на код, базиран на VS Code.",
|
||||||
|
"aiClientConfigSetup": "Настройка",
|
||||||
|
"aiClientConfigTabCli": "Автоматичен (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Ръчна конфигурация",
|
||||||
|
"aiClientConfigPreset": "Конфигурация",
|
||||||
|
"aiClientConfigStep": "Стъпка {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Този фрагмент включва примерни стойности, като име на модел или URL адрес на ресурс. Заменете ги със собствени, преди да го използвате.",
|
||||||
|
"aiClientConfigRevealError": "Не можа да зареди вашия API ключ.",
|
||||||
|
"aiClientConfigRevealRetry": "Опитайте отново",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Този ресурс може да се използва от общи клиенти като Claude Code и OpenCode. <configLink>Научете повече</configLink>",
|
||||||
|
"aiProvidersTitle": "AI Доставчици",
|
||||||
|
"aiProvidersDescription": "Свързване на модели доставчици за AI задачи в тази организация",
|
||||||
|
"aiProvidersBannerTitle": "Свързване на модели доставчици",
|
||||||
|
"aiProvidersBannerDescription": "Доставчиците са бекендите на модела, които Pangolin използва за AI задачи. Свържете OpenAI, Anthropic и други доставчици тук, след това ги прикачете към публични AI шлюзове, така че потребителите да могат да извикват модели с идентичност-назнаван достъп, бюджети и логиране.",
|
||||||
|
"aiProvidersAdd": "Добавяне на Доставчик",
|
||||||
|
"aiProvidersSearch": "Търсене на доставчици...",
|
||||||
|
"aiProvidersEmpty": "Все още няма AI доставчици",
|
||||||
|
"aiProviderCreate": "Създаване на AI Доставчик",
|
||||||
|
"aiProviderCreateDescription": "Добавяне на модел доставчик за тази организация",
|
||||||
|
"aiProviderSeeAll": "Преглед на всички доставчици",
|
||||||
|
"aiProviderSetting": "Настройки на доставчика за {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Конфигурирайте този AI доставчик",
|
||||||
|
"aiProviderGeneral": "Общи",
|
||||||
|
"aiProviderGeneralDescription": "Основни настройки за този доставчик",
|
||||||
|
"aiProviderConfiguration": "Конфигурация",
|
||||||
|
"aiProviderConfigurationDescription": "Мрежов маршрутизация и удостоверяване за този доставчик",
|
||||||
|
"aiProviderNetworkSettings": "Мрежови настройки",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Избор как трафикът достига до този доставчик",
|
||||||
|
"aiProviderAuthSettings": "Удостоверяване",
|
||||||
|
"aiProviderAuthSettingsDescription": "Конфигурирайте как този доставчик удостоверява заявки до своя URL",
|
||||||
|
"aiProviderBudgetSettings": "Бюджет",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Конфигурирайте как този доставчик ограничава използването въз основа на разходи или жетонни лимити",
|
||||||
|
"aiBudgetAdd": "Добавяне на Бюджет",
|
||||||
|
"aiBudgetEmpty": "Все още няма конфигурирани бюджети. Щракнете върху Добавяне на Бюджет, за да настроите лимит на разходи или жетони.",
|
||||||
|
"aiBudgetUnit": "Вид на разхода",
|
||||||
|
"aiBudgetPeriod": "Период на нулиране",
|
||||||
|
"aiBudgetAmount": "Максимален разход",
|
||||||
|
"aiBudgetAmountPlaceholder": "Максимален разход",
|
||||||
|
"aiBudgetPeriodHourly": "Часов",
|
||||||
|
"aiBudgetPeriodDaily": "Дневен",
|
||||||
|
"aiBudgetPeriodWeekly": "Седмичен",
|
||||||
|
"aiBudgetPeriodMonthly": "Месечен",
|
||||||
|
"aiBudgetPeriodYearly": "Годишен",
|
||||||
|
"aiBudgetPeriodLifetime": "Пожизнен",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Жетони",
|
||||||
|
"aiBudgetConflictError": "Бюджет за този период на нулиране и вид на разхода вече съществува",
|
||||||
|
"aiBudgetInvalidAmountError": "Въведете максимален разход, по-голям от 0",
|
||||||
|
"aiBudgetUpdated": "Актуализирани бюджети",
|
||||||
|
"aiBudgetErrorSave": "Неуспех при актуализация на бюджети",
|
||||||
|
"aiProviderType": "Вид на доставчика",
|
||||||
|
"aiProviderTypeSearch": "Търсене на доставчици...",
|
||||||
|
"aiProviderTypeNotFound": "Не е намерен вид доставчик",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "Персонализиран",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Рунтайм API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "Използвайте собствена крайна точка или маршрутирайте чрез цели на сайта",
|
||||||
|
"aiProviderUpstreamUrl": "Възходящ URL адрес",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Основен URL за API на доставчика",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Оставете празно, за да използвате стандартния възходящ URL за този доставчик",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Ефективен възходящ URL адрес",
|
||||||
|
"aiProviderApiKey": "API ключ",
|
||||||
|
"aiProviderApiKeyDescription": "API ключ, използван за удостоверяване на заявки към този доставчик",
|
||||||
|
"aiProviderCustomHeadersDescription": "Заглавки, изпратени при всяка заявка към този доставчик. Отделени със нов ред: Име-на-заглавие: стойност",
|
||||||
|
"aiProviderApiKeyLastChars": "API ключ",
|
||||||
|
"aiProviderAuthType": "Тип удостоверяване",
|
||||||
|
"aiProviderAuthTypeSearch": "Търсене на типове удостоверяване...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Не е намерен тип удостоверяване",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Удостоверяване: Bearer ключ. Използва се от OpenAI и повечето доставчици",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-key заглавие. Използва се от Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-key заглавие. Използва се от Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Удостоверяване: Splunk ключ. Използва се от Splunk HTTP Event Collector",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Bearer ключ. Използва се от Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeNone": "Без удостоверяване",
|
||||||
|
"aiProviderAuthTypePassthrough": "Премини",
|
||||||
|
"aiProviderAuthTypeDescription": "Как възходящото API удостоверява заявките",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Препрати заглавките на API ключа на повикващия към възходящото",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Не изпращайте заглавки за удостоверяване към възходящото",
|
||||||
|
"aiProviderRoutingMode": "Режим на маршрутиране",
|
||||||
|
"aiProviderRoutingModeDescription": "Изпрати трафик към възходящ URL или HTTP цели на вашите сайтове",
|
||||||
|
"aiProviderRoutingModeUrl": "Възходящ URL адрес",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Обадете се на публичен или частен API основен URL",
|
||||||
|
"aiProviderRoutingModeTarget": "Цели на сайта",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Маршрутиране чрез цели на вашите сайтове",
|
||||||
|
"aiProviderRoutingModeTargetNote": "След създаването на този доставчик, конфигурирайте целите на сайта в раздела Настройки на мрежата.",
|
||||||
|
"aiProviderTargetNoOne": "Този доставчик няма цели. Добавете цел за маршрутиране на заявки чрез вашите сайтове.",
|
||||||
|
"aiProviderSkipTlsVerification": "Пропуснете проверката на TLS",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Деактивирайте проверката на TLS сертификат за възходящото свързване",
|
||||||
|
"aiProviderBudget": "Бюджет",
|
||||||
|
"aiProviderBudgetDescription": "Факултативен лимит за разходи или маркер за този доставчик",
|
||||||
|
"aiProviderBudgetAmount": "Сума на бюджета",
|
||||||
|
"aiProviderBudgetUnit": "Единица на бюджета",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Токени",
|
||||||
|
"aiProviderEnabled": "Активиран",
|
||||||
|
"aiProviderEnabledDescription": "Напълно деактивирайте този доставчик за всички ресурси",
|
||||||
|
"aiProviderErrorCreate": "Неуспешно създаване на AI доставчик",
|
||||||
|
"aiProviderErrorUpdate": "Неуспешно актуализиране на AI доставчик",
|
||||||
|
"aiProviderErrorDelete": "Неуспешно изтриване на AI доставчик",
|
||||||
|
"aiProviderErrorLoad": "Неуспешно зареждане на AI доставчик",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Въведете валиден възходящ URL адрес",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Възходящ URL адрес е задължителен за този доставчик",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Необходим е тип за удостоверяване",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API ключът е задължителен",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Маршрутизацията на целите на сайта е налична само за персонализирани доставчици",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Изберете поне една възможност на API",
|
||||||
|
"aiProviderCapabilities": "Възможности на API",
|
||||||
|
"aiProviderCapabilitiesDescription": "Изберете, които API формати може да управлява този доставчик. Известни доставчици започват с препоръчани настройки по подразбиране.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Изберете кои формати на API този персонализиран доставчик може да обработва",
|
||||||
|
"aiProviderCapabilitiesSelect": "Изберете възможности",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Няма намерени възможности",
|
||||||
|
"aiProviderCapabilitiesSearch": "Търсене на възможности...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Чат Завършвания",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Поддържа /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI Отговори",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Поддържа /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic Съобщения",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Поддържа /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini Генериране на Съдържание",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Поддържа директния Gemini API",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Бедрок Модел Активирай",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Поддържа Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex Генериране на Съдържание",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Поддържа Vertex AI Gemini формат",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex Сурово Предсказване",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Поддържа Vertex AI rawPredict за Anthropic модели",
|
||||||
|
"aiCapabilityBedrockConverse": "Бедрок Разговор",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Поддържа Amazon Bedrock Converse API",
|
||||||
|
"aiProviderCreated": "AI доставчикът е създаден",
|
||||||
|
"aiProviderUpdated": "AI доставчикът е обновен",
|
||||||
|
"aiProviderDeleted": "AI доставчикът е изтрит",
|
||||||
|
"aiProviderDelete": "Изтриване на Доставчик",
|
||||||
|
"aiProviderDeleteConfirm": "Изтриване на Доставчик",
|
||||||
|
"aiProviderQuestionRemove": "Сигурни ли сте, че искате да изтриете този AI доставчик?",
|
||||||
|
"aiProviderMessageRemove": "Това ще изтрие постоянно доставчика и неговите модели и цели. Това не може да бъде отменено.",
|
||||||
|
"aiProviderErrorNoUpdate": "AI доставчикът не е наличен за обновяване",
|
||||||
|
"aiProviderModels": "Модели",
|
||||||
|
"aiProviderModelsDescription": "Определете позволителните и блокиращите списъци за този доставчик. Заявките трябва да съвпадат с позволителен запис и да не съвпадат с блокиращ запис.",
|
||||||
|
"aiProviderCreateModelsDescription": "Изберете кои модели този доставчик може да обслужва. Празен позволителен списък осъжда целия трафик. Можете да добавите или промените модели по-късно.",
|
||||||
|
"aiProviderModelsPlaceholder": "Търсене на модели или въведете персонален ключ",
|
||||||
|
"aiProviderModelsAllow": "Позволителен Списък",
|
||||||
|
"aiProviderModelsAllowDescription": "Модели, които могат да бъдат използвани чрез този доставчик. Празно означава отричане на всички.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Въведете ключ на модела",
|
||||||
|
"aiProviderModelsAllowEmpty": "Все още няма добавени модели.",
|
||||||
|
"aiProviderModelsBlock": "Блокиращ Списък",
|
||||||
|
"aiProviderModelsBlockDescription": "Модели за отричане, дори ако съвпадат с позволителен запис.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Въведете ключ на модела",
|
||||||
|
"aiProviderModelsBlockEmpty": "Все още няма добавени модели.",
|
||||||
|
"aiProviderModelsAdd": "Добавяне на Модели",
|
||||||
|
"aiProviderModelsClearAll": "Изчистване на Всички",
|
||||||
|
"aiProviderModelsAddCustom": "Добавяне \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Натиснете Enter, за да добавите този персонален ключ на модел.",
|
||||||
|
"aiProviderModelsAddBulk": "Добавяне на {count} персонални ключове",
|
||||||
|
"aiProviderModelsAddBulkHint": "Натиснете Enter, за да добавите {count} персонални ключове.",
|
||||||
|
"aiProviderModelsAddOne": "Добавяне {key} сега",
|
||||||
|
"aiProviderModelsAddSelected": "Добавяне на Избраните",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} избрани",
|
||||||
|
"aiProviderModelsSelectAll": "Избери всички",
|
||||||
|
"aiProviderModelsClearSelected": "Изчистване",
|
||||||
|
"aiProviderModelsBulkHint": "Изберете известни модели или въведете персонален ключ.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Няма съвпадение с каталога на модели.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Известни Модели",
|
||||||
|
"aiProviderModelsAllLabel": "Всички модели",
|
||||||
|
"aiProviderModelsAllPatternHint": "Joker: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Позволете всички модели",
|
||||||
|
"aiProviderModelsAddAllBlock": "Блокирайте всички модели",
|
||||||
|
"aiProviderModelsAddAllDescription": "Използва * joker, така че всеки ключ на модел съвпада.",
|
||||||
|
"aiProviderModelsViewMore": "Вижте още ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Вижте по-малко",
|
||||||
|
"aiProviderModelsRemove": "Премахване на модел",
|
||||||
|
"aiProviderModelsEditHint": "Натиснете, за да редактирате настройките на модела",
|
||||||
|
"aiProviderModelsSourceCatalog": "Известен каталогов модел",
|
||||||
|
"aiProviderModelsSourceCustom": "Персонализиран ключ на модел",
|
||||||
|
"aiProviderModelsSourcePattern": "Модел за съвпадение",
|
||||||
|
"aiProviderModelsSourceAll": "Съвпада с всеки ключ на модел",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Конфигуриран бюджет",
|
||||||
|
"aiProviderModelsEditTitle": "Редактиране на Модел",
|
||||||
|
"aiProviderModelsEditDescription": "Обновете ключа на модела или конфигурирайте бюджета му.",
|
||||||
|
"aiProviderModelsBudgetTab": "Бюджет",
|
||||||
|
"aiProviderModelsKeyLabel": "Ключ на модел",
|
||||||
|
"aiProviderModelsKeyRequired": "Въведете ключ на модел",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Този ключ на модел вече е в списък",
|
||||||
|
"aiProviderModelsOverlapError": "Тези образци не могат да бъдат в двата списъка: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Моделите са обновени",
|
||||||
|
"aiProviderModelsErrorUpdate": "Неуспешно обновяване на модели",
|
||||||
|
"aiResourceProviders": "Доставчици",
|
||||||
|
"aiResourceProvidersDescription": "Изберете кои AI доставчици този AI портал може да използва",
|
||||||
|
"aiResourceProvidersHelp": "Добавете доставчици и изберете наследяване (използване на списъците на всеки доставчик) или избор (изберете разрешителен списък за този ресурс). Разрешителните образци, които се конфликтират между прикрепени доставчици, не са разрешени.",
|
||||||
|
"aiResourceProvidersSelect": "Изберете доставчици",
|
||||||
|
"aiResourceProvidersEmpty": "Не са намерени AI доставчици",
|
||||||
|
"aiResourceProvidersNoneAttached": "Все още няма прикрепени доставчици.",
|
||||||
|
"aiResourceProvidersAdd": "Добавяне на доставчик",
|
||||||
|
"aiResourceProvidersRemove": "Премахване на доставчик",
|
||||||
|
"aiResourceProviderToggleEnabled": "Разрешете или забранете този доставчик на ресурса",
|
||||||
|
"aiResourceProviderDisabled": "Деактивиран",
|
||||||
|
"aiResourceProvidersUpdated": "Доставчиците са обновени",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Неуспешно обновяване на доставчици",
|
||||||
|
"aiResourceProviderEditDescription": "Изберете как да се изложат моделите на този доставчик върху този ресурс.",
|
||||||
|
"viewProviderSettings": "Преглед на настройки на доставчик",
|
||||||
|
"aiResourceProviderMode": "Режим на достъп",
|
||||||
|
"aiResourceProviderModeInherit": "Наследяване",
|
||||||
|
"aiResourceProviderModeSelect": "Изберете",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Изберете · {count} модели",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Използвайте разрешителните и блокиращите списъци на този доставчик според конфигурацията.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Изберете подмножество на моделите с разрешителния списък на този доставчик за този ресурс.",
|
||||||
|
"aiResourceProviderAllowModels": "Разрешителен списък",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Изберете модели",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Търсене на модели...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Няма намерени модели",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Само модели от разрешителния списък на този доставчик могат да бъдат избрани.",
|
||||||
|
"aiResourceAliasRequired": "Псевдоним е необходим за AI портали",
|
||||||
|
"aiResourceDomainConfiguration": "Конфигурация на Домейн",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Изберете домейна, който клиентите ще използват, за да достигнат до този AI портал.",
|
||||||
|
"aiUsageAnalyticsTitle": "Аналитика на AI Използването",
|
||||||
|
"aiUsageAnalyticsDescription": "Анализирайте разходите, употребата на токени и активността на AI портал през доставчици, ресурси, роли и потребители",
|
||||||
|
"aiUsageTabOverview": "Общ поглед",
|
||||||
|
"aiUsageTabProviders": "Доставчици",
|
||||||
|
"aiUsageTabResources": "Ресурси",
|
||||||
|
"aiUsageFilterProvider": "Доставчик",
|
||||||
|
"aiUsageFilterModel": "Модел",
|
||||||
|
"aiUsageFilterResource": "Ресурс",
|
||||||
|
"aiUsageFilterRole": "Роля",
|
||||||
|
"aiUsageFilterUser": "Потребител",
|
||||||
|
"aiUsageFilterAllProviders": "Всички Доставчици",
|
||||||
|
"aiUsageFilterAllModels": "Всички Модели",
|
||||||
|
"aiUsageFilterAllResources": "Всички Ресурси",
|
||||||
|
"aiUsageFilterAllRoles": "Всички Роли",
|
||||||
|
"aiUsageFilterAllUsers": "Всички Потребители",
|
||||||
|
"aiUsageFilterSearch": "Търсене...",
|
||||||
|
"aiUsageFilterNotFound": "Не са намерени опции",
|
||||||
|
"aiUsageResetFilters": "Възстановяване на Филтрите",
|
||||||
|
"aiUsageRefresh": "Обновяване",
|
||||||
|
"aiUsageTokenTypePrompt": "Подканя",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Четене от кеш",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Писане в кеш",
|
||||||
|
"aiUsageTokenTypeCompletion": "Завършване",
|
||||||
|
"aiUsageTokenTypeReasoning": "Разсъждение",
|
||||||
|
"aiUsageRequests": "Запитвания",
|
||||||
|
"aiUsageCost": "Разход",
|
||||||
|
"aiUsageTokens": "Токени",
|
||||||
|
"aiUsageOther": "Друго",
|
||||||
|
"aiUsageTotalRequests": "Общо Запитвания",
|
||||||
|
"aiUsageTotalTokens": "Общо Токени",
|
||||||
|
"aiUsageTotalCost": "Общ Разход",
|
||||||
|
"aiUsageEstimated": "Оценени",
|
||||||
|
"aiUsageRequestVolume": "Обем на Запитване",
|
||||||
|
"aiUsageTokenUsage": "Употреба на Токени",
|
||||||
|
"aiUsageModelCost": "Модел Разход",
|
||||||
|
"aiUsageModelTokens": "Модел Токени",
|
||||||
|
"aiUsageTopModels": "Топ Модели",
|
||||||
|
"aiUsageTopProviders": "Топ Доставчици",
|
||||||
|
"aiUsageProviderCost": "Разход на Доставчик",
|
||||||
|
"aiUsageProviderTokenUsage": "Употреба на Доставчик на Токени",
|
||||||
|
"aiUsageTopResources": "Топ Ресурси",
|
||||||
|
"aiUsageResourceCost": "Разход на Ресурс",
|
||||||
|
"aiUsageResourceTokenUsage": "Употреба на Токени на Ресурс",
|
||||||
|
"aiUsageResourceTypePublic": "Публичен Ресурс",
|
||||||
|
"aiUsageResourceTypeSite": "Частен Ресурс",
|
||||||
|
"aiUsageNoResource": "Няма ресурс",
|
||||||
|
"aiUsageRolesTab": "Роли",
|
||||||
|
"aiUsageUsersTab": "Потребители",
|
||||||
|
"aiUsageTopRoles": "Топ Роли",
|
||||||
|
"aiUsageRoleCost": "Разход на Роля",
|
||||||
|
"aiUsageRoleTokenUsage": "Употреба на Токени на Роля",
|
||||||
|
"aiUsageTopUsers": "Топ Потребители",
|
||||||
|
"aiUsageUserCost": "Разход на Потребител",
|
||||||
|
"aiUsageUserTokenUsage": "Употреба на Токени на Потребител",
|
||||||
|
"aiUsageUnknownUser": "Непознат потребител",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Виртуални API Ключове",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Виртуален API Ключ",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Всички Виртуални API Ключове",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Топ Виртуални API Ключове",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Разход на Виртуален API Ключ",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Употреба на Токени на Виртуален API Ключ",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Няма виртуален API ключ",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Неназован ключ",
|
||||||
|
"aiUsageLoading": "Зареждане...",
|
||||||
|
"aiUsageNoData": "Няма данни",
|
||||||
|
"resourceBudgetSettings": "Бюджет",
|
||||||
|
"resourceBudgetSettingsDescription": "Конфигурирайте как AI порталът ограничава употребата, основавайки се на разходи или лимити на токени",
|
||||||
"sidebarApiKeys": "API ключове",
|
"sidebarApiKeys": "API ключове",
|
||||||
"sidebarProvisioning": "Осигуряване",
|
"sidebarProvisioning": "Осигуряване",
|
||||||
"sidebarSettings": "Настройки",
|
"sidebarSettings": "Настройки",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Правилото за предупреждение е запазено",
|
"alertingRuleSaved": "Правилото за предупреждение е запазено",
|
||||||
"alertingRuleSavedCreatedDescription": "Вашето ново правило за предупреждение беше създадено. Все още можете да го редактирате на тази страница.",
|
"alertingRuleSavedCreatedDescription": "Вашето ново правило за предупреждение беше създадено. Все още можете да го редактирате на тази страница.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Промените, направени по това правило за предупреждение, бяха запазени.",
|
"alertingRuleSavedUpdatedDescription": "Промените, направени по това правило за предупреждение, бяха запазени.",
|
||||||
|
"alertingTestAlertSent": "Изпратено е тестово предупреждение",
|
||||||
|
"alertingTestAlertSentDescription": "Тестово предупреждение беше изпратено до действията, конфигурирани по това правило.",
|
||||||
"alertingEditRule": "Редактиране на правило за предупреждение",
|
"alertingEditRule": "Редактиране на правило за предупреждение",
|
||||||
"alertingCreateRule": "Създаване на правило за предупреждение",
|
"alertingCreateRule": "Създаване на правило за предупреждение",
|
||||||
"alertingRuleCredenzaDescription": "Изберете какво да наблюдавате, кога да се активира и как да уведомите",
|
"alertingRuleCredenzaDescription": "Изберете какво да наблюдавате, кога да се активира и как да уведомите",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Всяко правило свързва това, което да се наблюдава (сайт, проверка на състоянието или ресурс), кога да се активира (например офлайн или нездраве) и как да уведомите екипа чрез имейл, уеб куки или интеграции. Използвайте този списък, за да създавате, активирате и управлявате тези правила.",
|
"alertingRulesBannerDescription": "Всяко правило свързва това, което да се наблюдава (сайт, проверка на състоянието или ресурс), кога да се активира (например офлайн или нездраве) и как да уведомите екипа чрез имейл, уеб куки или интеграции. Използвайте този списък, за да създавате, активирате и управлявате тези правила.",
|
||||||
"alertingHealthChecksBannerTitle": "Наблюдавайте здравето и ресурсите",
|
"alertingHealthChecksBannerTitle": "Наблюдавайте здравето и ресурсите",
|
||||||
"alertingHealthChecksBannerDescription": "Проверките на състоянието са HTTP или TCP монитори, които определяте веднъж. След това можете да ги използвате като източници в правила за предупреждения, така че да бъдете уведомени, когато целта стане здраве или нездраве. Проверките на състоянието на ресурсите също се появяват тук.",
|
"alertingHealthChecksBannerDescription": "Проверките на състоянието са HTTP или TCP монитори, които определяте веднъж. След това можете да ги използвате като източници в правила за предупреждения, така че да бъдете уведомени, когато целта стане здраве или нездраве. Проверките на състоянието на ресурсите също се появяват тук.",
|
||||||
|
"alertingTestRule": "Правило за тестово предупреждение",
|
||||||
|
"alertingAddActionHeading": "Добавете ново действие",
|
||||||
|
"alertingSelectActionType": "Изберете действие",
|
||||||
|
"alertingNoActionsTitle": "Не са конфигурирани действия",
|
||||||
|
"alertingNoActionsSaveDescription": "Добавете поне едно действие, за да може това правило да уведоми някого, когато се изпълни.",
|
||||||
|
"alertingNoActionsTestDescription": "Добавете поне едно действие, преди да можете да тествате това правило.",
|
||||||
"standaloneHcTableTitle": "Проверки на състоянието",
|
"standaloneHcTableTitle": "Проверки на състоянието",
|
||||||
"standaloneHcSearchPlaceholder": "Търсене на проверки на състоянието…",
|
"standaloneHcSearchPlaceholder": "Търсене на проверки на състоянието…",
|
||||||
"standaloneHcAddButton": "Създаване на проверка на състоянието",
|
"standaloneHcAddButton": "Създаване на проверка на състоянието",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Поддомейн: {subdomain}",
|
"domainPickerSubdomain": "Поддомейн: {subdomain}",
|
||||||
"domainPickerNamespace": "Име на пространство: {namespace}",
|
"domainPickerNamespace": "Име на пространство: {namespace}",
|
||||||
"domainPickerShowMore": "Покажи повече",
|
"domainPickerShowMore": "Покажи повече",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Няма налични домейни",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Все още нямате конфигурирани домейни. Създайте домейн, за да продължите.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Отидете на Домейни",
|
||||||
"regionSelectorTitle": "Избор на регион",
|
"regionSelectorTitle": "Избор на регион",
|
||||||
"domainPickerRemoteExitNodeWarning": "Предоставените домейни не се поддържат, когато сайтовете се свързват към отдалечени крайни възли. За да бъдат ресурсите налични на отдалечени възли, използвайте персонализиран домейн вместо това.",
|
"domainPickerRemoteExitNodeWarning": "Предоставените домейни не се поддържат, когато сайтовете се свързват към отдалечени крайни възли. За да бъдат ресурсите налични на отдалечени възли, използвайте персонализиран домейн вместо това.",
|
||||||
"regionSelectorInfo": "Изборът на регион ни помага да предоставим по-добра производителност за вашето местоположение. Не е необходимо да сте в същия регион като сървъра.",
|
"regionSelectorInfo": "Изборът на регион ни помага да предоставим по-добра производителност за вашето местоположение. Не е необходимо да сте в същия регион като сървъра.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Мрежа",
|
"subnetPlaceholder": "Мрежа",
|
||||||
"addressDescription": "Вътрешният адрес на клиента. Трябва да пада в подмрежата на организацията.",
|
"addressDescription": "Вътрешният адрес на клиента. Трябва да пада в подмрежата на организацията.",
|
||||||
"selectSites": "Избор на сайтове",
|
"selectSites": "Избор на сайтове",
|
||||||
|
"selectResources": "Изберете ресурси",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# ресурс} other {# ресурси}}",
|
||||||
"selectLabels": "Изберете етикети",
|
"selectLabels": "Изберете етикети",
|
||||||
"sitesDescription": "Клиентът ще има връзка с избраните сайтове",
|
"sitesDescription": "Клиентът ще има връзка с избраните сайтове",
|
||||||
"clientInstallOlm": "Инсталиране на Olm",
|
"clientInstallOlm": "Инсталиране на Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Времето е в секунди",
|
"timeIsInSeconds": "Времето е в секунди",
|
||||||
"requireDeviceApproval": "Изискват одобрение на устройства",
|
"requireDeviceApproval": "Изискват одобрение на устройства",
|
||||||
"requireDeviceApprovalDescription": "Потребители с тази роля трябва да имат нови устройства одобрени от администратор преди да могат да се свържат и да имат достъп до ресурси.",
|
"requireDeviceApprovalDescription": "Потребители с тази роля трябва да имат нови устройства одобрени от администратор преди да могат да се свържат и да имат достъп до ресурси.",
|
||||||
"sshSettings": "Настройки за SSH",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI Портал",
|
||||||
"sshAccess": "SSH Достъп",
|
"sshAccess": "SSH Достъп",
|
||||||
"rdpSettings": "Настройки за RDP",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "Настройки за VNC",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH сървър",
|
"sshServer": "SSH сървър",
|
||||||
"rdpServer": "RDP сървър",
|
"rdpServer": "RDP сървър",
|
||||||
"vncServer": "VNC сървър",
|
"vncServer": "VNC сървър",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Публичен",
|
"resourcesTableProxyResources": "Публичен",
|
||||||
"resourcesTableClientResources": "Частен",
|
"resourcesTableClientResources": "Частен",
|
||||||
"resourcesTableNoProxyResourcesFound": "Не са намерени ресурсни проксита.",
|
"resourcesTableNoProxyResourcesFound": "Не са намерени ресурсни проксита.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Не са намерени вътрешни ресурси.",
|
"resourcesTableNoInternalResourcesFound": "Не са намерени частни ресурси.",
|
||||||
"resourcesTableDestination": "Дестинация",
|
"resourcesTableDestination": "Дестинация",
|
||||||
"resourcesTableAlias": "Псевдоним",
|
"resourcesTableAlias": "Псевдоним",
|
||||||
"resourcesTableAliasAddress": "Адрес на псевдоним.",
|
"resourcesTableAliasAddress": "Адрес на псевдоним.",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Отмяна",
|
"editInternalResourceDialogCancel": "Отмяна",
|
||||||
"editInternalResourceDialogSaveResource": "Запазване на ресурс",
|
"editInternalResourceDialogSaveResource": "Запазване на ресурс",
|
||||||
"editInternalResourceDialogSuccess": "Успех",
|
"editInternalResourceDialogSuccess": "Успех",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Вътрешният ресурс успешно актуализиран",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Частният ресурс е успешно обновен",
|
||||||
"editInternalResourceDialogError": "Грешка",
|
"editInternalResourceDialogError": "Грешка",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Неуспешно актуализиране на вътрешен ресурс",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Неуспешен опит за обновяване на частен ресурс",
|
||||||
"editInternalResourceDialogNameRequired": "Името е задължително",
|
"editInternalResourceDialogNameRequired": "Името е задължително",
|
||||||
"editInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа",
|
"editInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа",
|
||||||
"editInternalResourceDialogProxyPortMin": "Прокси портът трябва да бъде поне 1",
|
"editInternalResourceDialogProxyPortMin": "Прокси портът трябва да бъде поне 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI Портал",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Метод",
|
"editInternalResourceDialogScheme": "Метод",
|
||||||
"editInternalResourceDialogEnableSsl": "Активиране на TLS",
|
"editInternalResourceDialogEnableSsl": "Активиране на TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Псевдоним",
|
"editInternalResourceDialogAlias": "Псевдоним",
|
||||||
"editInternalResourceDialogAliasDescription": "По избор вътрешен DNS псевдоним за този ресурс.",
|
"editInternalResourceDialogAliasDescription": "По избор вътрешен DNS псевдоним за този ресурс.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Няма достъпни сайтове",
|
"createInternalResourceDialogNoSitesAvailable": "Няма достъпни сайтове",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Трябва да имате поне един сайт на Newt с конфигурирана мрежа, за да създадете вътрешни ресурси.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Трябва да имате поне един Newt сайт с конфигуриран сабнет, за да създадете частни ресурси.",
|
||||||
"createInternalResourceDialogClose": "Затвори",
|
"createInternalResourceDialogClose": "Затвори",
|
||||||
"createInternalResourceDialogCreateClientResource": "Създаване на частен ресурс",
|
"createInternalResourceDialogCreateClientResource": "Създаване на частен ресурс",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Създайте нов ресурс, който ще бъде достъпен само за клиенти, свързани към организацията",
|
"createInternalResourceDialogCreateClientResourceDescription": "Създайте нов ресурс, който ще бъде достъпен само за клиенти, свързани към организацията",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Разрешете ICMP Ping",
|
"privateResourceAllowIcmpPing": "Разрешете ICMP Ping",
|
||||||
"privateResourceNetworkAccess": "Достъп до мрежата",
|
"privateResourceNetworkAccess": "Достъп до мрежата",
|
||||||
"privateResourceNetworkAccessDescription": "Контролирайте достъпа до TCP/UDP портовете и дали ICMP пинг е разрешен за този ресурс.",
|
"privateResourceNetworkAccessDescription": "Контролирайте достъпа до TCP/UDP портовете и дали ICMP пинг е разрешен за този ресурс.",
|
||||||
"hostSettings": "Настройки на хоста",
|
"hostSettings": "Хост",
|
||||||
"cidrSettings": "Настройки на CIDR",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Свойства на ресурса",
|
"createInternalResourceDialogResourceProperties": "Свойства на ресурса",
|
||||||
"createInternalResourceDialogName": "Име",
|
"createInternalResourceDialogName": "Име",
|
||||||
"createInternalResourceDialogSite": "Сайт",
|
"createInternalResourceDialogSite": "Сайт",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Отмяна",
|
"createInternalResourceDialogCancel": "Отмяна",
|
||||||
"createInternalResourceDialogCreateResource": "Създаване на ресурс",
|
"createInternalResourceDialogCreateResource": "Създаване на ресурс",
|
||||||
"createInternalResourceDialogSuccess": "Успех",
|
"createInternalResourceDialogSuccess": "Успех",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Вътрешният ресурс създаден успешно",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Частният ресурс е създаден успешно",
|
||||||
"createInternalResourceDialogError": "Грешка",
|
"createInternalResourceDialogError": "Грешка",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Неуспешно създаване на вътрешен ресурс",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Неуспешен опит за създаване на частен ресурс",
|
||||||
"createInternalResourceDialogNameRequired": "Името е задължително",
|
"createInternalResourceDialogNameRequired": "Името е задължително",
|
||||||
"createInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа",
|
"createInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Моля, изберете сайт",
|
"createInternalResourceDialogPleaseSelectSite": "Моля, изберете сайт",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI Портал",
|
||||||
"scheme": "Метод",
|
"scheme": "Метод",
|
||||||
"createInternalResourceDialogScheme": "Метод",
|
"createInternalResourceDialogScheme": "Метод",
|
||||||
"createInternalResourceDialogEnableSsl": "Активиране на TLS",
|
"createInternalResourceDialogEnableSsl": "Активиране на TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Валидна парола",
|
"validPassword": "Валидна парола",
|
||||||
"validEmail": "Валиден имейл",
|
"validEmail": "Валиден имейл",
|
||||||
"validSSO": "Валидно SSO",
|
"validSSO": "Валидно SSO",
|
||||||
|
"validVirtualAPIKey": "Валиден Виртуален API Ключ",
|
||||||
"view": "Преглед",
|
"view": "Преглед",
|
||||||
"configManaged": "Управлявана конфигурация",
|
"configManaged": "Управлявана конфигурация",
|
||||||
"connectedClient": "Свързан клиент",
|
"connectedClient": "Свързан клиент",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Задържане на логове",
|
"logRetention": "Задържане на логове",
|
||||||
"logRetentionDescription": "Управлявайте времето за задържане на различни видове логове за тази организация или ги деактивирайте",
|
"logRetentionDescription": "Управлявайте времето за задържане на различни видове логове за тази организация или ги деактивирайте",
|
||||||
"requestLogsDescription": "Прегледайте подробни логове на заявки за ресурси в тази организация",
|
"requestLogsDescription": "Прегледайте подробни логове на заявки за ресурси в тази организация",
|
||||||
|
"aiSessionLogs": "Журнали на AI Портал Сесиите",
|
||||||
|
"aiSessionLogsDescription": "Прегледайте подканянета и транскрипции на отговори за запитванията към AI портал в тази организация",
|
||||||
|
"sidebarLogsAi": "Журнали на Сесиите",
|
||||||
|
"commandLogsAi": "Журнали на Сесиите",
|
||||||
|
"sidebarLogsAiUsage": "Анализ на Използване",
|
||||||
|
"commandLogsAiUsage": "Анализ на Използване",
|
||||||
|
"provider": "Доставчик",
|
||||||
|
"capability": "Способност",
|
||||||
|
"model": "Модел",
|
||||||
|
"virtualApiKey": "Виртуален API Ключ",
|
||||||
|
"noVirtualApiKey": "Няма виртуален API ключ",
|
||||||
|
"stream": "Поток",
|
||||||
|
"streaming": "Стрийминг",
|
||||||
|
"nonStreaming": "Нестрийминг",
|
||||||
|
"statusCode": "Код на Статуса",
|
||||||
|
"aiSessionId": "ID на Сесията",
|
||||||
|
"aiSessionRequest": "Запитване",
|
||||||
|
"aiSessionResponse": "Отговор",
|
||||||
|
"aiSessionNoData": "Няма събрани данни",
|
||||||
|
"aiSessionCouldNotParse": "(суров, не може да се парсира транскрипт)",
|
||||||
|
"aiSessionLogTruncated": "Тази сесия беше прекъсната преди съхранение и може да е непълна.",
|
||||||
|
"aiSessionViewRaw": "Преглед на Суров JSON",
|
||||||
|
"aiSessionViewChat": "Преглед на Чат",
|
||||||
|
"cost": "Разход",
|
||||||
|
"estimated": "Оценени",
|
||||||
|
"tokenUsage": "Употреба на Токени",
|
||||||
|
"promptTokens": "Подканящи Токени",
|
||||||
|
"cacheReadTokens": "Кеш Прочитане на Токени",
|
||||||
|
"cacheWriteTokens": "Кеш Писане на Токени",
|
||||||
|
"completionTokens": "Токени за Завършване",
|
||||||
|
"reasoningTokens": "Токени за Разсъждение",
|
||||||
|
"totalTokens": "Общо Токени",
|
||||||
"requestAnalyticsDescription": "Вижте подробни анализи на заявки за ресурсите в тази организация",
|
"requestAnalyticsDescription": "Вижте подробни анализи на заявки за ресурсите в тази организация",
|
||||||
"logRetentionRequestLabel": "Задържане на логове за HTTP заявки",
|
"logRetentionRequestLabel": "Задържане на логове за HTTP заявки",
|
||||||
"logRetentionRequestDescription": "Колко дълго да се задържат логовете на заявките",
|
"logRetentionRequestDescription": "Колко дълго да се задържат логовете на заявките",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Колко дълго да се задържат логовете за действия",
|
"logRetentionActionDescription": "Колко дълго да се задържат логовете за действия",
|
||||||
"logRetentionConnectionLabel": "Запазване на дневниците на връзките",
|
"logRetentionConnectionLabel": "Запазване на дневниците на връзките",
|
||||||
"logRetentionConnectionDescription": "Колко дълго да се съхраняват дневниците на връзките",
|
"logRetentionConnectionDescription": "Колко дълго да се съхраняват дневниците на връзките",
|
||||||
|
"logRetentionAISessionsLabel": "Съхранение на Журнали на AI Портал Сесиите",
|
||||||
|
"logRetentionAISessionsDescription": "Колко време да съхраняваме подканящите/отговоряващите журнали на AI портал сесии",
|
||||||
"logRetentionDisabled": "Деактивирано",
|
"logRetentionDisabled": "Деактивирано",
|
||||||
"logRetention3Days": "3 дни",
|
"logRetention3Days": "3 дни",
|
||||||
"logRetention7Days": "7 дни",
|
"logRetention7Days": "7 дни",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Източен адрес",
|
"sourceAddress": "Източен адрес",
|
||||||
"destinationAddress": "Адрес на дестинация",
|
"destinationAddress": "Адрес на дестинация",
|
||||||
"duration": "Продължителност",
|
"duration": "Продължителност",
|
||||||
"licenseRequiredToUse": "Изисква се лиценз за <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> или <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> за използване на тази функция. <bookADemoLink>Резервирайте демонстрация или пробен POC</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Ентерпрайз Едишън лиценз</enterpriseEditionLink> е необходим. <bookADemoLink>Резервирайте демо или проба</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> е необходим за използване на тази функция. Тази функция също е налична в <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Резервирайте демонстрация или пробен POC</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Ентерпрайз Едишън лиценз</enterpriseEditionLink> е необходим. <bookADemoLink>Резервирайте демо или проба</bookADemoLink>",
|
||||||
"certResolver": "Решавач на сертификати",
|
"certResolver": "Решавач на сертификати",
|
||||||
"certResolverDescription": "Изберете решавач на сертификати за използване за този ресурс.",
|
"certResolverDescription": "Изберете решавач на сертификати за използване за този ресурс.",
|
||||||
"selectCertResolver": "Изберете решавач на сертификати",
|
"selectCertResolver": "Изберете решавач на сертификати",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Избирайки няколко сайта, се осигурява сигурен път и пренасочване при висока достъпност.",
|
"internalResourceFormMultiSiteRoutingHelp": "Избирайки няколко сайта, се осигурява сигурен път и пренасочване при висока достъпност.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Научете повече",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Научете повече",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Ограничете достъпа до конкретни TCP/UDP портове или позволете/блокирайте всички портове.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Ограничете достъпа до конкретни TCP/UDP портове или позволете/блокирайте всички портове.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "Конфигурация HTTP",
|
"createInternalResourceDialogHttpConfiguration": "Конфигурация на Домейн",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Изберете домейна, който клиентите ще използват, за да достигнат този ресурс чрез HTTP или HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Изберете домейна, който клиентите ще използват, за да достигнат този ресурс чрез HTTP или HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "Конфигурация HTTP",
|
"editInternalResourceDialogHttpConfiguration": "Конфигурация на Домейн",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Изберете домейна, който клиентите ще използват, за да достигнат този ресурс чрез HTTP или HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Изберете домейна, който клиентите ще използват, за да достигнат този ресурс чрез HTTP или HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP.",
|
"editInternalResourceDialogTcp": "TCP.",
|
||||||
"editInternalResourceDialogUdp": "UDP.",
|
"editInternalResourceDialogUdp": "UDP.",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Без Етикет",
|
"resourceLauncherUnlabeled": "Без Етикет",
|
||||||
|
"resourceLauncherAiGateway": "AI Портал",
|
||||||
"resourceLauncherNoSite": "Няма Сайт",
|
"resourceLauncherNoSite": "Няма Сайт",
|
||||||
|
"resourceLauncherAvailableModels": "Налични Модели",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Модели, които можете да използвате с този AI портал.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Няма налични модели за този ресурс.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Не можа да се заредят наличните модели.",
|
||||||
|
"resourceLauncherApiKeys": "API Ключове",
|
||||||
|
"resourceLauncherApiKeysDescription": "Използвайте вашия ключ за идентичност или атрибутиран ключ за удостоверяване с този ресурс.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Ключ за Идентичност",
|
||||||
|
"resourceLauncherApiKeysManual": "Атрибуте Ключове",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Няма налични API ключове за този ресурс.",
|
||||||
|
"resourceLauncherApiKeysError": "Не можа да се заредят API ключовете.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Няма ресурси в тази група",
|
"resourceLauncherNoResourcesInGroup": "Няма ресурси в тази група",
|
||||||
"resourceLauncherEmptyStateTitle": "Няма Налични Ресурси",
|
"resourceLauncherEmptyStateTitle": "Няма Налични Ресурси",
|
||||||
"resourceLauncherEmptyStateDescription": "Все още нямате достъп до никакви ресурси. Свържете се с вашия администратор, за да поискате достъп.",
|
"resourceLauncherEmptyStateDescription": "Все още нямате достъп до никакви ресурси. Свържете се с вашия администратор, за да поискате достъп.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Не можахте да изтриете изгледа на стартер. Моля, опитайте отново.",
|
"resourceLauncherViewDeleteFailedDescription": "Не можахте да изтриете изгледа на стартер. Моля, опитайте отново.",
|
||||||
"memberPortalPrevious": "Предишен",
|
"memberPortalPrevious": "Предишен",
|
||||||
"memberPortalNext": "Следващ",
|
"memberPortalNext": "Следващ",
|
||||||
"httpSettings": "HTTP настройки",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "TCP настройки",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "UDP настройки",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Установяване на защитена връзка…",
|
"sshConnectingDescription": "Установяване на защитена връзка…",
|
||||||
"sshConnecting": "Свързване…",
|
"sshConnecting": "Свързване…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Качването неуспешно",
|
"rdpUploadFailed": "Качването неуспешно",
|
||||||
"rdpUnicodeKeyboardMode": "Режим на unicode клавиатура",
|
"rdpUnicodeKeyboardMode": "Режим на unicode клавиатура",
|
||||||
"sessionToolbarShow": "Показване на лентата с инструменти",
|
"sessionToolbarShow": "Показване на лентата с инструменти",
|
||||||
"sessionToolbarHide": "Скриване на лентата с инструменти"
|
"sessionToolbarHide": "Скриване на лентата с инструменти",
|
||||||
|
"actionUpdateSiteApprovals": "Обновяване на одобренията на сайта"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Prosím ujistěte se, že jste přihlášeni jako správný uživatel.",
|
"inviteLoginUser": "Prosím ujistěte se, že jste přihlášeni jako správný uživatel.",
|
||||||
"inviteErrorNoUser": "Je nám líto, ale vypadá to, že pozvánka, ke které se snažíte získat přístup, není pro existujícího uživatele.",
|
"inviteErrorNoUser": "Je nám líto, ale vypadá to, že pozvánka, ke které se snažíte získat přístup, není pro existujícího uživatele.",
|
||||||
"inviteCreateUser": "Nejprve si prosím vytvořte účet.",
|
"inviteCreateUser": "Nejprve si prosím vytvořte účet.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Pozvánky mohou být přijaty pouze vnitřními účty. Odhlaste se a přihlaste se pomocí hesla k tomuto e-mailu.",
|
||||||
|
"inviteLoginInternalOnly": "Pozvánky vyžadují vnitřní účet s heslem. Vytvořte si účet nebo se přihlaste pomocí hesla.",
|
||||||
"goHome": "Přejít na hlavní stránku",
|
"goHome": "Přejít na hlavní stránku",
|
||||||
"inviteLogInOtherUser": "Přihlásit se jako jiný uživatel",
|
"inviteLogInOtherUser": "Přihlásit se jako jiný uživatel",
|
||||||
"createAnAccount": "Vytvořit účet",
|
"createAnAccount": "Vytvořit účet",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Potvrdit odstranění sdílného odkazu",
|
"shareDeleteConfirm": "Potvrdit odstranění sdílného odkazu",
|
||||||
"shareQuestionRemove": "Jste si jisti, že chcete smazat tento odkaz ke sdílení?",
|
"shareQuestionRemove": "Jste si jisti, že chcete smazat tento odkaz ke sdílení?",
|
||||||
"shareMessageRemove": "Jakmile bude smazán, odkaz přestane fungovat a všichni, kdo jej používají, ztratí přístup k prostředku.",
|
"shareMessageRemove": "Jakmile bude smazán, odkaz přestane fungovat a všichni, kdo jej používají, ztratí přístup k prostředku.",
|
||||||
"shareTokenDescription": "Přístupový token může být předán dvěma způsoby: jako parametr dotazu nebo v záhlaví požadavku. Tyto údaje musí být předány klientovi na každé žádosti o ověřený přístup.",
|
"shareTokenDescription": "Přístupový token může být předán jako dotazový parametr nebo v hlavičkách žádostí. Ve výchozím nastavení musí být odesílán s každou žádostí. Pokud je povolena perzistence relace, první žádost jej vymění za relaci cookie.",
|
||||||
"accessToken": "Přístupový token",
|
"accessToken": "Přístupový token",
|
||||||
"usageExamples": "Příklady použití",
|
"usageExamples": "Příklady použití",
|
||||||
"tokenId": "ID tokenu",
|
"tokenId": "ID tokenu",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Název (volitelné)",
|
"shareTitleOptional": "Název (volitelné)",
|
||||||
"sharePathOptional": "Cesta (volitelně)",
|
"sharePathOptional": "Cesta (volitelně)",
|
||||||
"sharePathDescription": "Odkaz přesměruje uživatele na tuto cestu po autentikaci.",
|
"sharePathDescription": "Odkaz přesměruje uživatele na tuto cestu po autentikaci.",
|
||||||
|
"shareAssociateUserOptional": "Přiřadit uživatele (volitelné)",
|
||||||
|
"shareAssociateUserDescription": "Pokud je nastaveno, žádosti pomocí tohoto odkazu jsou v přístupových protokolech a hlavičkách identity přidružené k uživateli. Odkaz je odstraněn, pokud uživatel opustí organizaci.",
|
||||||
|
"userSelect": "Vyberte uživatele",
|
||||||
|
"usersNotFound": "Nebyl nalezen žádný uživatel",
|
||||||
"expireIn": "Platnost vyprší za",
|
"expireIn": "Platnost vyprší za",
|
||||||
"neverExpire": "Nikdy nevyprší",
|
"neverExpire": "Nikdy nevyprší",
|
||||||
|
"sharePersistSession": "Udržet relaci po prvním použití",
|
||||||
|
"sharePersistSessionDescription": "Pokud je povoleno, první žádost s tímto tokenem prostřednictvím dotazu nebo hlavičky nastaví relaci cookie, takže pozdější žádosti nepotřebují token. Nechcete-li, aby API klienti posílali token s každou žádostí, vypněte to.",
|
||||||
"shareExpireDescription": "Doba platnosti určuje, jak dlouho bude odkaz použitelný a bude poskytovat přístup ke zdroji. Po této době odkaz již nebude fungovat a uživatelé kteří tento odkaz používali ztratí přístup ke zdroji.",
|
"shareExpireDescription": "Doba platnosti určuje, jak dlouho bude odkaz použitelný a bude poskytovat přístup ke zdroji. Po této době odkaz již nebude fungovat a uživatelé kteří tento odkaz používali ztratí přístup ke zdroji.",
|
||||||
"shareSeeOnce": "Tento odkaz uvidíte pouze jednou. Nezapomeňte jej zkopírovat.",
|
"shareSeeOnce": "Tento odkaz uvidíte pouze jednou. Nezapomeňte jej zkopírovat.",
|
||||||
"shareAccessHint": "Kdokoli s tímto odkazem může přistupovat ke zdroji. Sdílejte jej s rozvahou.",
|
"shareAccessHint": "Kdokoli s tímto odkazem může přistupovat ke zdroji. Sdílejte jej s rozvahou.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Nebyla nalezena žádná země.",
|
"noCountryFound": "Nebyla nalezena žádná země.",
|
||||||
"siteSelectionDescription": "Tato lokalita poskytne připojení k cíli.",
|
"siteSelectionDescription": "Tato lokalita poskytne připojení k cíli.",
|
||||||
"resourceType": "Typ zdroje",
|
"resourceType": "Typ zdroje",
|
||||||
"resourceTypeDescription": "Toto určuje protokol zdroje a jak bude zobrazen v prohlížeči. Později to nelze změnit.",
|
"resourceTypeDescription": "Toto řídí protokol zdroje a nelze to později změnit.",
|
||||||
|
"resourceTypeSearch": "Hledat typy zdrojů...",
|
||||||
|
"resourceTypeNotFound": "Typ zdroje nenalezen",
|
||||||
|
"resourceTypeHttpDescription": "Proxy webový provoz přes HTTPS pomocí názvu domény",
|
||||||
|
"resourceTypeInferenceDescription": "Směřujte žádosti o AI přes připojené poskytovatele",
|
||||||
|
"resourceTypeSshDescription": "Přístup k SSH serveru z prohlížeče",
|
||||||
|
"resourceTypeRdpDescription": "Přístup k vzdálené ploše z prohlížeče",
|
||||||
|
"resourceTypeVncDescription": "Přístup k VNC ploše z prohlížeče",
|
||||||
|
"resourceTypeTcpDescription": "Proxy surový TCP provoz pomocí čísla portu",
|
||||||
|
"resourceTypeUdpDescription": "Proxy hrubý UDP provoz pomocí čísla portu",
|
||||||
|
"privateResourceTypeDescription": "Toto řídí, jak se klienti dostávají ke zdroji. Toto nelze později změnit.",
|
||||||
|
"privateResourceTypeHostDescription": "Vystavit jeden hostitel na síti stránky propojeným klientům",
|
||||||
|
"privateResourceTypeCidrDescription": "Vystavit CIDR rozsah na síti stránky propojeným klientům",
|
||||||
|
"privateResourceTypeHttpDescription": "Přístup ke službě HTTP nebo HTTPS pomocí domény",
|
||||||
|
"privateResourceTypeSshDescription": "Přístup k SSH serveru připojenými klienty",
|
||||||
"resourceDomainDescription": "Zdroji bude obsluhován tento plně kvalifikovaný doménový název.",
|
"resourceDomainDescription": "Zdroji bude obsluhován tento plně kvalifikovaný doménový název.",
|
||||||
"resourceHTTPSSettings": "Nastavení HTTPS",
|
"resourceHTTPSSettings": "Nastavení HTTPS",
|
||||||
"resourceHTTPSSettingsDescription": "Nakonfigurujte, jak bude dokument přístupný přes HTTPS",
|
"resourceHTTPSSettingsDescription": "Nakonfigurujte, jak bude dokument přístupný přes HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Zajištění",
|
"provisioningManage": "Zajištění",
|
||||||
"provisioningDescription": "Spravovat klíče pro nastavení a zkontrolovat čekající stránky čekající na schválení.",
|
"provisioningDescription": "Spravovat klíče pro nastavení a zkontrolovat čekající stránky čekající na schválení.",
|
||||||
"pendingSites": "Nevyřízené weby",
|
"pendingSites": "Nevyřízené weby",
|
||||||
"siteApproveSuccess": "Web byl úspěšně schválen",
|
"siteApproveSuccess": "Stránka a přidružené zdroje byly úspěšně schváleny",
|
||||||
"siteApproveError": "Chyba při schvalování webu",
|
"siteApproveError": "Chyba při schvalování webu",
|
||||||
|
"siteReject": "Odmítnout stránku",
|
||||||
|
"siteQuestionReject": "Opravdu chcete tuto stránku odmítnout?",
|
||||||
|
"siteMessageReject": "Toto trvale odstraní stránku a všechny přidružené zdroje, které jsou stále nevyřízené.",
|
||||||
|
"siteConfirmReject": "Potvrdit odmítnutí stránky",
|
||||||
|
"siteRejectSuccess": "Stránka byla úspěšně odmítnuta",
|
||||||
|
"siteRejectError": "Chyba při odmítání stránky",
|
||||||
"provisioningKeys": "Poskytovací klíče",
|
"provisioningKeys": "Poskytovací klíče",
|
||||||
"searchProvisioningKeys": "Hledat klíče k zajišťování...",
|
"searchProvisioningKeys": "Hledat klíče k zajišťování...",
|
||||||
"provisioningKeysAdd": "Generovat zajišťovací klíč",
|
"provisioningKeysAdd": "Generovat zajišťovací klíč",
|
||||||
@@ -466,12 +494,12 @@
|
|||||||
"provisioningKeysSave": "Uložit konfigurační klíč",
|
"provisioningKeysSave": "Uložit konfigurační klíč",
|
||||||
"provisioningKeysSaveDescription": "Toto můžete vidět pouze jednou. Zkopírujte ho na bezpečné místo.",
|
"provisioningKeysSaveDescription": "Toto můžete vidět pouze jednou. Zkopírujte ho na bezpečné místo.",
|
||||||
"provisioningKeysErrorCreate": "Chyba při vytváření doplňovacího klíče",
|
"provisioningKeysErrorCreate": "Chyba při vytváření doplňovacího klíče",
|
||||||
"provisioningKeysList": "Nový klíč pro poskytování informací",
|
"provisioningKeysList": "Nový provisioning klíč",
|
||||||
"provisioningKeysMaxBatchSize": "Maximální velikost dávky",
|
"provisioningKeysMaxBatchSize": "Maximální velikost dávky",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Neomezená velikost šarže (bez omezení)",
|
"provisioningKeysUnlimitedBatchSize": "Neomezená velikost šarže (bez omezení)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Bez omezení",
|
"provisioningKeysMaxBatchUnlimited": "Bez omezení",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Zadejte platnou maximální velikost šarže (1–1,000,000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Zadejte platnou maximální velikost šarže (1–1,000,000).",
|
||||||
"provisioningKeysValidUntil": "Platné do",
|
"provisioningKeysValidUntil": "Platná do",
|
||||||
"provisioningKeysValidUntilHint": "Ponechte prázdné, pokud vyprší platnost.",
|
"provisioningKeysValidUntilHint": "Ponechte prázdné, pokud vyprší platnost.",
|
||||||
"provisioningKeysValidUntilInvalid": "Zadejte platné datum a čas.",
|
"provisioningKeysValidUntilInvalid": "Zadejte platné datum a čas.",
|
||||||
"provisioningKeysNumUsed": "Časy použití",
|
"provisioningKeysNumUsed": "Časy použití",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Uložit nastavení",
|
"authMethodsSave": "Uložit nastavení",
|
||||||
"policyAuthStackTitle": "Autentifikace",
|
"policyAuthStackTitle": "Autentifikace",
|
||||||
"policyAuthStackDescription": "Určete, které metody autentifikace jsou požadovány pro přístup k tomuto zdroji",
|
"policyAuthStackDescription": "Určete, které metody autentifikace jsou požadovány pro přístup k tomuto zdroji",
|
||||||
|
"policyAuthInferenceStackDescription": "Zvolte, kteří uživatelé a role se mohou autentifikovat k této AI bráně",
|
||||||
"policyAuthOrLogicTitle": "Více metod autentifikace je aktivních",
|
"policyAuthOrLogicTitle": "Více metod autentifikace je aktivních",
|
||||||
"policyAuthOrLogicBanner": "Návštěvníci mohou použít jakoukoli aktivní metodu uvedenou níže. Nemusí splnit všechny z nich.",
|
"policyAuthOrLogicBanner": "Návštěvníci mohou použít jakoukoli aktivní metodu uvedenou níže. Nemusí splnit všechny z nich.",
|
||||||
"policyAuthMethodActive": "Aktivní",
|
"policyAuthMethodActive": "Aktivní",
|
||||||
"policyAuthMethodOff": "Vypnuto",
|
"policyAuthMethodOff": "Vypnuto",
|
||||||
"policyAuthSsoTitle": "Platformové SSO",
|
"policyAuthSsoTitle": "Platformové SSO",
|
||||||
"policyAuthSsoDescription": "Požadujte přihlášení prostřednictvím identifikačního poskytovatele vaší organizace",
|
"policyAuthSsoDescription": "Požadujte přihlášení prostřednictvím identifikačního poskytovatele vaší organizace",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "Přihlašovací URL",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Každý uživatel již má identitu API klíč, takže stačí vytvořit virtuální API klíče pro ne-uživatelské klienty nebo sdílený přístup. Uživatelé mohou svůj klíč získat přihlášením pomocí svého poskytovatele identity na URL této zdroje, kde bude zobrazen po přihlášení.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Každý uživatel již má identitu API klíč, takže stačí vytvořit virtuální API klíče pro ne-uživatelské klienty nebo sdílený přístup. Uživatelé získávají svůj klíč zde po přihlášení s poskytovatelem identity.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} uživatelé, {roles} role",
|
"policyAuthSsoSummary": "{idp} · {users} uživatelé, {roles} role",
|
||||||
"policyAuthSsoDefaultIdp": "Výchozí poskytovatel",
|
"policyAuthSsoDefaultIdp": "Výchozí poskytovatel",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Přidat výchozího identifikačního poskytovatele",
|
"policyAuthAddDefaultIdentityProvider": "Přidat výchozího identifikačního poskytovatele",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Verze",
|
"newtVersion": "Verze",
|
||||||
"architecture": "Architektura",
|
"architecture": "Architektura",
|
||||||
"sites": "Stránky",
|
"sites": "Stránky",
|
||||||
"siteWgAnyClients": "K připojení použijte jakéhokoli klienta WireGuard. Budete muset řešit interní zdroje pomocí klientské IP adresy.",
|
"siteWgAnyClients": "Pro připojení použijte jakéhokoli klienta WireGuard. Budete muset adresovat privátní zdroje pomocí IP protějšku.",
|
||||||
"siteWgCompatibleAllClients": "Kompatibilní se všemi klienty aplikace WireGuard",
|
"siteWgCompatibleAllClients": "Kompatibilní se všemi klienty aplikace WireGuard",
|
||||||
"siteWgManualConfigurationRequired": "Je vyžadována ruční konfigurace",
|
"siteWgManualConfigurationRequired": "Je vyžadována ruční konfigurace",
|
||||||
"userErrorNotAdminOrOwner": "Uživatel není administrátor nebo vlastník",
|
"userErrorNotAdminOrOwner": "Uživatel není administrátor nebo vlastník",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Je vyžadována nová role",
|
"accessRoleErrorNewRequired": "Je vyžadována nová role",
|
||||||
"accessRoleErrorRemove": "Nepodařilo se odstranit roli",
|
"accessRoleErrorRemove": "Nepodařilo se odstranit roli",
|
||||||
"accessRoleErrorRemoveDescription": "Došlo k chybě při odstraňování role.",
|
"accessRoleErrorRemoveDescription": "Došlo k chybě při odstraňování role.",
|
||||||
|
"accessRoleInferenceBudget": "AI Rozpočet",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Konfigurace, jak se členové této role omezují AI spotřebu podle výdajů nebo limitů tokenů",
|
||||||
"accessRoleName": "Název role",
|
"accessRoleName": "Název role",
|
||||||
"accessRoleQuestionRemove": "Chystáte se odstranit roli `{name}`. Tuto akci nelze vrátit zpět.",
|
"accessRoleQuestionRemove": "Chystáte se odstranit roli `{name}`. Tuto akci nelze vrátit zpět.",
|
||||||
"accessRoleRemove": "Odstranit roli",
|
"accessRoleRemove": "Odstranit roli",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Vytvořit Org uživatele",
|
"createOrgUser": "Vytvořit Org uživatele",
|
||||||
"actionUpdateOrg": "Aktualizovat organizaci",
|
"actionUpdateOrg": "Aktualizovat organizaci",
|
||||||
"actionRemoveInvitation": "Odstranit pozvání",
|
"actionRemoveInvitation": "Odstranit pozvání",
|
||||||
|
"actionRemoveUserRole": "Odstranit uživatelskou roli",
|
||||||
"actionUpdateUser": "Aktualizovat uživatele",
|
"actionUpdateUser": "Aktualizovat uživatele",
|
||||||
"actionGetUser": "Získat uživatele",
|
"actionGetUser": "Získat uživatele",
|
||||||
"actionGetOrgUser": "Získat uživatele organizace",
|
"actionGetOrgUser": "Získat uživatele organizace",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Odstranění lokality",
|
"actionDeleteSite": "Odstranění lokality",
|
||||||
"actionGetSite": "Získat web",
|
"actionGetSite": "Získat web",
|
||||||
"actionListSites": "Seznam stránek",
|
"actionListSites": "Seznam stránek",
|
||||||
|
"actionCreateAiProvider": "Vytvořit poskytovatele AI",
|
||||||
|
"actionDeleteAiProvider": "Smazat poskytovatele AI",
|
||||||
|
"actionGetAiProvider": "Získat poskytovatele AI",
|
||||||
|
"actionListAiProviders": "Seznam poskytovatelů AI",
|
||||||
|
"actionUpdateAiProvider": "Aktualizovat poskytovatele AI",
|
||||||
|
"actionCreateAiModel": "Vytvořit AI model",
|
||||||
|
"actionDeleteAiModel": "Smazat AI model",
|
||||||
|
"actionGetAiModel": "Získat AI model",
|
||||||
|
"actionListAiModels": "Seznam AI modelů",
|
||||||
|
"actionUpdateAiModel": "Aktualizovat AI model",
|
||||||
|
"actionCreateAiBudget": "Vytvořit AI rozpočet",
|
||||||
|
"actionDeleteAiBudget": "Smazat AI rozpočet",
|
||||||
|
"actionGetAiBudget": "Získat AI rozpočet",
|
||||||
|
"actionListAiBudgets": "Seznam AI rozpočtů",
|
||||||
|
"actionUpdateAiBudget": "Aktualizovat AI rozpočet",
|
||||||
|
"actionListResourceAiModels": "Seznam AI modelů zdroje",
|
||||||
|
"actionSetResourceAiModels": "Nastavit AI modely zdroje",
|
||||||
|
"actionCreateVirtualApiKey": "Vytvořit virtuální API klíč",
|
||||||
|
"actionDeleteVirtualApiKey": "Smazat virtuální API klíč",
|
||||||
|
"actionGetVirtualApiKey": "Získat virtuální API klíč",
|
||||||
|
"actionListVirtualApiKeys": "Seznam virtuálních API klíčů",
|
||||||
|
"actionUpdateVirtualApiKey": "Aktualizovat virtuální API klíč",
|
||||||
"actionApplyBlueprint": "Použít plán",
|
"actionApplyBlueprint": "Použít plán",
|
||||||
"actionListBlueprints": "Seznam šablon",
|
"actionListBlueprints": "Seznam šablon",
|
||||||
"actionGetBlueprint": "Získat šablonu",
|
"actionGetBlueprint": "Získat šablonu",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Zadejte nastavovací token z konzole serveru.",
|
"setupTokenDescription": "Zadejte nastavovací token z konzole serveru.",
|
||||||
"setupTokenRequired": "Je vyžadován token nastavení",
|
"setupTokenRequired": "Je vyžadován token nastavení",
|
||||||
"actionUpdateSite": "Aktualizovat stránku",
|
"actionUpdateSite": "Aktualizovat stránku",
|
||||||
|
"actionApproveSite": "Schválit stránku",
|
||||||
|
"actionRejectSite": "Odmítnout stránku",
|
||||||
"actionResetSiteBandwidth": "Resetovat šířku pásma organizace",
|
"actionResetSiteBandwidth": "Resetovat šířku pásma organizace",
|
||||||
"actionListSiteRoles": "Seznam povolených rolí webu",
|
"actionListSiteRoles": "Seznam povolených rolí webu",
|
||||||
"actionCreateResource": "Vytvořit zdroj",
|
"actionCreateResource": "Vytvořit zdroj",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Nastavit zdrojový kód",
|
"actionSetResourcePincode": "Nastavit zdrojový kód",
|
||||||
"actionSetResourceEmailWhitelist": "Nastavit seznam povolených dokumentů",
|
"actionSetResourceEmailWhitelist": "Nastavit seznam povolených dokumentů",
|
||||||
"actionGetResourceEmailWhitelist": "Získat seznam povolených dokumentů",
|
"actionGetResourceEmailWhitelist": "Získat seznam povolených dokumentů",
|
||||||
|
"actionListResourcePolicies": "Seznam zásad zdrojů",
|
||||||
|
"actionCreateResourcePolicy": "Vytvořit zásadu zdrojů",
|
||||||
"actionGetResourcePolicy": "Získat zásady zdroje",
|
"actionGetResourcePolicy": "Získat zásady zdroje",
|
||||||
"actionUpdateResourcePolicy": "Aktualizovat zásady zdroje",
|
"actionUpdateResourcePolicy": "Aktualizovat zásady zdroje",
|
||||||
|
"actionDeleteResourcePolicy": "Smazat zásadu zdrojů",
|
||||||
"actionSetResourcePolicyUsers": "Nastavte uživatele pro zásady zdroje",
|
"actionSetResourcePolicyUsers": "Nastavte uživatele pro zásady zdroje",
|
||||||
"actionSetResourcePolicyRoles": "Nastavte role pro zásady zdroje",
|
"actionSetResourcePolicyRoles": "Nastavte role pro zásady zdroje",
|
||||||
"actionSetResourcePolicyPassword": "Nastavte heslo pro zásady zdroje",
|
"actionSetResourcePolicyPassword": "Nastavte heslo pro zásady zdroje",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Seznam pozvánek",
|
"actionListInvitations": "Seznam pozvánek",
|
||||||
"actionExportLogs": "Exportovat protokoly",
|
"actionExportLogs": "Exportovat protokoly",
|
||||||
"actionViewLogs": "Zobrazit logy",
|
"actionViewLogs": "Zobrazit logy",
|
||||||
|
"actionCreateSiteProvisioningKey": "Vytvořit klíč pro zřízení webu",
|
||||||
|
"actionListSiteProvisioningKeys": "Seznam klíčů pro zřízení webu",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Aktualizovat klíč pro zřízení webu",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Smazat klíč pro zřízení webu",
|
||||||
"noneSelected": "Není vybráno",
|
"noneSelected": "Není vybráno",
|
||||||
"orgNotFound2": "Nebyly nalezeny žádné organizace.",
|
"orgNotFound2": "Nebyly nalezeny žádné organizace.",
|
||||||
"search": "Vyhledávání…",
|
"search": "Vyhledávání…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Zadejte kód z vaší autentizační aplikace nebo jeden z vlastních záložních kódů.",
|
"otpAuthDescription": "Zadejte kód z vaší autentizační aplikace nebo jeden z vlastních záložních kódů.",
|
||||||
"otpAuthSubmit": "Odeslat kód",
|
"otpAuthSubmit": "Odeslat kód",
|
||||||
"idpContinue": "Nebo pokračovat s",
|
"idpContinue": "Nebo pokračovat s",
|
||||||
|
"idpLastUsed": "Naposled použito",
|
||||||
"otpAuthBack": "Zpět na heslo",
|
"otpAuthBack": "Zpět na heslo",
|
||||||
"navbar": "Navigation Menu",
|
"navbar": "Navigation Menu",
|
||||||
"navbarDescription": "Hlavní navigační menu aplikace",
|
"navbarDescription": "Hlavní navigační menu aplikace",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Vytvořit strojového klienta",
|
"commandPaletteCreateMachineClient": "Vytvořit strojového klienta",
|
||||||
"commandPaletteCreateAlertRule": "Vytvořit pravidlo upozornění",
|
"commandPaletteCreateAlertRule": "Vytvořit pravidlo upozornění",
|
||||||
"commandPaletteCreateIdentityProvider": "Vytvořit poskytovatele identity",
|
"commandPaletteCreateIdentityProvider": "Vytvořit poskytovatele identity",
|
||||||
|
"commandPaletteCreateAiProvider": "Vytvořit AI poskytovatele",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Vytvořit virtuální API klíč",
|
||||||
"commandPaletteToggleTheme": "Přepnout téma",
|
"commandPaletteToggleTheme": "Přepnout téma",
|
||||||
"commandPaletteChooseOrganization": "Vybrat organizaci",
|
"commandPaletteChooseOrganization": "Vybrat organizaci",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Pozvánky",
|
"sidebarInvitations": "Pozvánky",
|
||||||
"sidebarRoles": "Role",
|
"sidebarRoles": "Role",
|
||||||
"sidebarShareableLinks": "Sdílené Odkazy",
|
"sidebarShareableLinks": "Sdílené Odkazy",
|
||||||
|
"sidebarAiGateway": "AI Brána",
|
||||||
|
"sidebarAiProviders": "Poskytovatelé",
|
||||||
|
"commandAiProviders": "AI Poskytovatelé",
|
||||||
|
"sidebarVirtualApiKeys": "Virtuální API Klíče",
|
||||||
|
"sidebarMyApiKeys": "Vaše API Klíče",
|
||||||
|
"sidebarAccount": "Spouštěč",
|
||||||
|
"commandVirtualApiKeys": "Virtuální API Klíče",
|
||||||
|
"virtualApiKeysTitle": "Spravovat virtuální API Klíče",
|
||||||
|
"virtualApiKeysDescription": "Vytvořit a spravovat manuální API klíče pro přístup k AI bráně veřejných AI brán",
|
||||||
|
"virtualApiKeysTabIdentity": "Klíče Identity",
|
||||||
|
"virtualApiKeysTabVirtual": "Virtuální Klíče",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Klíče Identity pro každého uživatele",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Každý uživatel již má klíč identity Pangolin pro tuto organizaci. Je jedinečný pro jejich účet a autentifikuje je k AI bránám, ke kterým mohou přistupovat.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Příklad",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Jak uživatelé získávají svůj klíč",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Navštivte URL veřejné AI brány v prohlížeči a přihlaste se pomocí svého účtu.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Nebo jděte na <url></url> pokud jste přihlášeni.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Můžete vytvořit další virtuální API klíče na kartě Virtuální Klíče. Tyto klíče mohou být zaměřeny na specifické veřejné AI brány a volitelně spojeny s uživatelem. Vytvoření klíče okamžitě poskytne přístup k vybraným veřejným AI bránám.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Manuálně vytvořte klíč",
|
||||||
|
"virtualApiKeysEmailIdentity": "Emailové klíče Identity",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Poslat každý vybraný uživatel nebo role jejich klíč identity Pangolin.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Odeslat všem uživatelům",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Odeslat každému členovi organizace, který má e-mail pro účet.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Uživatelé",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Role",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Odeslat e-maily",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Klíče identity zaslané e-mailem",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Bylo odesláno {sent} e-mailů.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} uživatelů bylo přeskočeno, protože nemají e-mailovou adresu.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Vyberte alespoň jednoho uživatele nebo roli, nebo odešlete všem uživatelům.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Chyba při odesílání klíčů identity",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Nepodařilo se odeslat e-mailem klíče identity",
|
||||||
|
"virtualApiKeysBannerTitle": "Klíče Identity pro každého uživatele",
|
||||||
|
"virtualApiKeysBannerDescription": "Každý uživatel již má klíč identity k dispozici na {keysUrl}. Můžete také ručně generovat klíče zde, které poskytují přímý přístup k veřejným AI bránám.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Zobrazit klíče Identity",
|
||||||
|
"virtualApiKeys": "Virtuální API Klíče",
|
||||||
|
"virtualApiKeysSearch": "Hledat klíče...",
|
||||||
|
"virtualApiKeysCreate": "Vytvořit Virtuální API Klíč",
|
||||||
|
"virtualApiKeysCreateDescription": "Ražte manuální klíč, který může volat veřejné AI brány v této organizaci",
|
||||||
|
"virtualApiKeysCreateButton": "Vytvořit Klíč",
|
||||||
|
"virtualApiKeysEmpty": "Žádné virtuální API klíče zatím nejsou",
|
||||||
|
"virtualApiKeysName": "Jméno",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Popis (nepovinné)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Přidružit uživatele (nepovinné)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Přidružte tento klíč k uživateli pro sledování použití. Jakmile je vytvořen, tento klíč okamžitě poskytne přístup k vybraným veřejným AI bránám. Nemusíte ručně přidružovat uživatele ke zdroji. Klíč se také zobrazí v profilu uživatele.",
|
||||||
|
"virtualApiKeysAllResources": "Všechny veřejné AI brány",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Povolte tento klíč pro přístup ke všem veřejným AI branám v organizaci",
|
||||||
|
"virtualApiKeysSelectResources": "Veřejné AI Brány",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Vybrat zdroje",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Zvolte, které veřejné AI brány tento klíč může přistupovat",
|
||||||
|
"virtualApiKeysNoResources": "Žádné zdroje",
|
||||||
|
"virtualApiKeysSecret": "Klíč",
|
||||||
|
"virtualApiKeysCopyKey": "Zkopírujte tento klíč. Později ho můžete znovu zobrazit z tabulky nebo při úpravě.",
|
||||||
|
"virtualApiKeysViewSecret": "Zobrazit tajemství",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Tajemství virtuálního API Klíče",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Toto tajemství poskytuje přístup ke veřejným AI branám přiřazeným k tomuto klíči",
|
||||||
|
"virtualApiKeysEdit": "Upravit Virtuální API Klíč",
|
||||||
|
"virtualApiKeysEditDescription": "Aktualizace spojeného uživatele a přístup k veřejným AI branám pro tento klíč",
|
||||||
|
"virtualApiKeysSaveButton": "Uložit změny",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Zvolte alespoň jednu veřejnou AI bránu, nebo povolte všechny veřejné AI brány",
|
||||||
|
"virtualApiKeysUpdated": "Aktualizován virtuální API klíč",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Virtuální API klíč byl aktualizován",
|
||||||
|
"virtualApiKeysErrorUpdate": "Chyba při aktualizaci virtuálního API klíče",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Nepodařilo se aktualizovat virtuální API klíč",
|
||||||
|
"virtualApiKeysErrorCreate": "Chyba při vytváření virtuálního API klíče",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Nepodařilo se vytvořit virtuální API klíč",
|
||||||
|
"virtualApiKeysErrorDelete": "Chyba při mazání virtuálního API klíče",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Nepodařilo se smazat virtuální API klíč",
|
||||||
|
"virtualApiKeysDeleted": "Virtuální API klíč smazán",
|
||||||
|
"virtualApiKeysDeletedDescription": "Virtuální API klíč byl smazán",
|
||||||
|
"virtualApiKeysDelete": "Smazat virtuální API klíč",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Smazat klíč",
|
||||||
|
"virtualApiKeysQuestionRemove": "Jste si jisti, že chcete smazat tento virtuální API klíč?",
|
||||||
|
"virtualApiKeysMessageRemove": "Klienti používající tento klíč ztratí přístup okamžitě.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Chyba při načítání tajemství",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Nepodařilo se načíst tajemství virtuálního API klíče",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Nepřidělené",
|
||||||
|
"virtualApiKeysInferenceBudget": "Rozpočet",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Konfigurace, jak tento klíč omezí použití AI na základě výdajů nebo limitů tokenů",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Email klíče při generování",
|
||||||
|
"virtualApiKeysEmailThisKey": "Email tohoto klíče",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Odeslat klíč na spojeného uživatele a další adresy po jeho vytvoření",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Odeslat aktuální klíč spojenému uživateli a dalším adresám",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "Email není na tomto serveru nastaven",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Nastavit SMTP pro posílání virtuálních API klíčů.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Odeslat spojenému uživateli",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Email klíč na emailovou adresu spojeného uživatele",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Spojte uživatele pro poslání klíče uživateli",
|
||||||
|
"virtualApiKeysEmailAdditional": "Další e-maily",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Přidat e-mail a stiskněte Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Vyberte spojeného uživatele nebo přidejte alespoň jednu e-mailovou adresu",
|
||||||
|
"myVirtualApiKeysTitle": "Vaše API Klíče",
|
||||||
|
"myVirtualApiKeysDescription": "Zobrazte váš klíč identity a jakékoliv virtuální API klíče přiřazené k vám v této organizaci",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Vaše API klíče pro {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Zobrazte váš klíč identity a virtuální API klíče přiřazené k vám, které mohou přistupovat k {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Klíč identity",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Váš osobní API klíč",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Váš osobní klíč pro tuto organizaci. Je jedinečný pro váš účet a používá se k identifikaci, když využíváte AI brány.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Váš osobní API klíč pro {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Váš osobní klíč pro tuto organizaci. Použijte jej k volání {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Přiřazené klíče",
|
||||||
|
"myVirtualApiKeysManualDescription": "Manuální virtuální API klíče, které administrátor přiřadil k vašemu účtu",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Manuální virtuální API klíče spojené s vaším účtem, které mohou přistupovat k {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Zatím žádné přiřazené klíče",
|
||||||
|
"myVirtualApiKeysKindUser": "Identita",
|
||||||
|
"myVirtualApiKeysKindManual": "Manuální",
|
||||||
|
"myVirtualApiKeysUnnamed": "Nepojmenovaný klíč",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Odhalit tajemství",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Toto tajemství vás autentizuje k AI bránovým zdrojům",
|
||||||
|
"aiClientConfigTitle": "Konfigurovat kódovací agenty",
|
||||||
|
"aiClientConfigDescription": "Zkopírujte konfiguraci pro oblíbené kódovací agenty, nebo nechte Pangolin CLI ji nastavit automaticky.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Antropický agentický kódovací nástroj pro terminál.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Agentický kódovací nástroj OpenAI pro terminál.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Open source terminální kódovací agent.",
|
||||||
|
"aiClientConfigDescriptionCursor": "AI editor kódu postavený na VS Code.",
|
||||||
|
"aiClientConfigSetup": "Nastavení",
|
||||||
|
"aiClientConfigTabCli": "Automatické (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Ruční konfigurace",
|
||||||
|
"aiClientConfigPreset": "Konfigurace",
|
||||||
|
"aiClientConfigStep": "Krok {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Tento snippet obsahuje ukázkové hodnoty, například název modelu nebo URL zdroje. Nahraďte je vlastními hodnotami před použitím.",
|
||||||
|
"aiClientConfigRevealError": "Nepodařilo se načíst váš API klíč.",
|
||||||
|
"aiClientConfigRevealRetry": "Zkusit znovu",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Tento zdroj může být použit z běžných klientů jako Claude Code a OpenCode. <configLink>Další informace</configLink>",
|
||||||
|
"aiProvidersTitle": "AI Poskytovatelé",
|
||||||
|
"aiProvidersDescription": "Připojení poskytovatelů modelů pro AI úkoly v této organizaci",
|
||||||
|
"aiProvidersBannerTitle": "Připojit poskytovatele modelů",
|
||||||
|
"aiProvidersBannerDescription": "Poskytovatelé jsou modelové backendy, které Pangolin používá pro AI úkoly. Připojte sem OpenAI, Anthropic a další dodavatele, poté je připojte k veřejným AI branám, aby uživatelé mohli volat modely s přístupem podmíněným na základě identity, rozpočtů a protokolování.",
|
||||||
|
"aiProvidersAdd": "Přidat poskytovatele",
|
||||||
|
"aiProvidersSearch": "Hledat poskytovatele...",
|
||||||
|
"aiProvidersEmpty": "Zatím žádní poskytovatelé AI nejsou",
|
||||||
|
"aiProviderCreate": "Vytvořit poskytovatele AI",
|
||||||
|
"aiProviderCreateDescription": "Přidat modelového poskytovatele pro tuto organizaci",
|
||||||
|
"aiProviderSeeAll": "Zobrazit všechny poskytovatele",
|
||||||
|
"aiProviderSetting": "Nastavení poskytovatele pro {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Konfigurace tohoto AI poskytovatele",
|
||||||
|
"aiProviderGeneral": "Obecný",
|
||||||
|
"aiProviderGeneralDescription": "Základní nastavení pro tohoto poskytovatele",
|
||||||
|
"aiProviderConfiguration": "Konfigurace",
|
||||||
|
"aiProviderConfigurationDescription": "Síťové směrování a autentizace pro tohoto poskytovatele",
|
||||||
|
"aiProviderNetworkSettings": "Síťové nastavení",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Vyberte, jak dosáhne provoz tohoto poskytovatele",
|
||||||
|
"aiProviderAuthSettings": "Autentifikace",
|
||||||
|
"aiProviderAuthSettingsDescription": "Nastavte, jak tento poskytovatel ověřuje požadavky na svou upstream URL",
|
||||||
|
"aiProviderBudgetSettings": "Rozpočet",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Konfigurace, jak tento poskytovatel omezuje použití na základě výdajů nebo limitů tokenů",
|
||||||
|
"aiBudgetAdd": "Přidat rozpočet",
|
||||||
|
"aiBudgetEmpty": "Zatím nebyly nakonfigurovány žádné rozpočty. Kliknutím na Přidat rozpočet nastavíte limit výdajů nebo tokenů.",
|
||||||
|
"aiBudgetUnit": "Typ výdajů",
|
||||||
|
"aiBudgetPeriod": "Období resetování",
|
||||||
|
"aiBudgetAmount": "Maximální výdaje",
|
||||||
|
"aiBudgetAmountPlaceholder": "Maximální výdaje",
|
||||||
|
"aiBudgetPeriodHourly": "Hodinově",
|
||||||
|
"aiBudgetPeriodDaily": "Denně",
|
||||||
|
"aiBudgetPeriodWeekly": "Týdně",
|
||||||
|
"aiBudgetPeriodMonthly": "Měsíčně",
|
||||||
|
"aiBudgetPeriodYearly": "Ročně",
|
||||||
|
"aiBudgetPeriodLifetime": "Po celou dobu",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Tokeny",
|
||||||
|
"aiBudgetConflictError": "Rozpočet pro toto období resetu a typ výdajů již existuje",
|
||||||
|
"aiBudgetInvalidAmountError": "Zadejte maximální výdaje větší než 0",
|
||||||
|
"aiBudgetUpdated": "Rozpočty aktualizovány",
|
||||||
|
"aiBudgetErrorSave": "Nepodařilo se aktualizovat rozpočty",
|
||||||
|
"aiProviderType": "Typ poskytovatele",
|
||||||
|
"aiProviderTypeSearch": "Hledat poskytovatele...",
|
||||||
|
"aiProviderTypeNotFound": "Typ poskytovatele nenalezen",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "Vlastní",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Runtime API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "Přineste si svůj vlastní koncový bod nebo směrujte prostřednictvím cílů stránek",
|
||||||
|
"aiProviderUpstreamUrl": "Upstream URL",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Základní URL pro API poskytovatele",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Nechte prázdné pro použití výchozí upstream URL pro tohoto poskytovatele",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Efektivní upstream URL",
|
||||||
|
"aiProviderApiKey": "API Klíč",
|
||||||
|
"aiProviderApiKeyDescription": "API klíč používaný k ověření požadavků tohoto poskytovatele",
|
||||||
|
"aiProviderCustomHeadersDescription": "Záhlaví poslaná v každém požadavku k tomuto poskytovateli. Nové řádky: Název-Záhlaví: hodnota",
|
||||||
|
"aiProviderApiKeyLastChars": "API Klíč",
|
||||||
|
"aiProviderAuthType": "Typ ověření",
|
||||||
|
"aiProviderAuthTypeSearch": "Vyhledat typy ověření...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Nebyl nalezen žádný typ ověření",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Oprávnění: Bearer klíč. Používá OpenAI a většina poskytovatelů",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-key záhlaví. Používá Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-key záhlaví. Používá Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Oprávnění: Splunk klíč. Používá Splunk HTTP Event Collector",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Bearer klíč. Používá Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeNone": "Bez ověření",
|
||||||
|
"aiProviderAuthTypePassthrough": "Průchod",
|
||||||
|
"aiProviderAuthTypeDescription": "Jak upstream API ověřuje požadavky",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Přepošlete API klíče volajícího na upstream",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Neodesílejte autentizační záhlaví na upstream",
|
||||||
|
"aiProviderRoutingMode": "Režim směrování",
|
||||||
|
"aiProviderRoutingModeDescription": "Odesílejte provoz na upstream URL nebo na HTTP cíle na vašich stránkách",
|
||||||
|
"aiProviderRoutingModeUrl": "Upstream URL",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Zavolejte veřejný nebo soukromý základní URL API",
|
||||||
|
"aiProviderRoutingModeTarget": "Cíle stránek",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Směrujte přes cíle na svých stránkách",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Po vytvoření tohoto poskytovatele, nakonfigurujte cíle stránek na záložce Nastavení sítě.",
|
||||||
|
"aiProviderTargetNoOne": "Tento poskytovatel nemá žádné cíle. Přidejte cíl pro směrování požadavků přes vaše stránky.",
|
||||||
|
"aiProviderSkipTlsVerification": "Přeskočit ověření TLS",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Zakázat ověření certifikátu TLS pro upstream připojení",
|
||||||
|
"aiProviderBudget": "Rozpočet",
|
||||||
|
"aiProviderBudgetDescription": "Volitelný rozpočet na výdaje nebo tokeny pro tohoto poskytovatele",
|
||||||
|
"aiProviderBudgetAmount": "Částka rozpočtu",
|
||||||
|
"aiProviderBudgetUnit": "Jednotka rozpočtu",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Tokeny",
|
||||||
|
"aiProviderEnabled": "Povoleno",
|
||||||
|
"aiProviderEnabledDescription": "Plně deaktivujte tohoto poskytovatele u všech zdrojů",
|
||||||
|
"aiProviderErrorCreate": "Nepodařilo se vytvořit poskytovatele AI",
|
||||||
|
"aiProviderErrorUpdate": "Nepodařilo se aktualizovat poskytovatele AI",
|
||||||
|
"aiProviderErrorDelete": "Nepodařilo se smazat poskytovatele AI",
|
||||||
|
"aiProviderErrorLoad": "Nepodařilo se načíst poskytovatele AI",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Zadejte platnou upstream URL",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Upstream URL je vyžadováno pro tohoto poskytovatele",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Typ ověření je povinný",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API klíč je povinný",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Směrování cílů stránek je k dispozici pouze pro vlastní poskytovatele",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Vyberte alespoň jednu schopnost API",
|
||||||
|
"aiProviderCapabilities": "Schopnosti API",
|
||||||
|
"aiProviderCapabilitiesDescription": "Vyberte, které formáty API tento poskytovatel zvládne. Známí poskytovatelé začínají s doporučenými výchozími hodnotami.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Vyberte, které formáty API tento vlastní poskytovatel zvládne",
|
||||||
|
"aiProviderCapabilitiesSelect": "Vyberte možnosti",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Žádné možnosti nenalezeny",
|
||||||
|
"aiProviderCapabilitiesSearch": "Hledat možnosti...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Chat Completion",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Podporuje /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "Odpovědi OpenAI",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Podporuje /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Zprávy Anthropic",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Podporuje /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Generování obsahu Gemini",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Podporuje přímé API Gemini",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Vyvolání modelu Bedrock",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Podporuje Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex generate content",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Podporuje Vertex AI Gemini formát",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Předpověď z Vertex Raw",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Podporuje Vertex AI rawPredict pro Anthropic modely",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock Konverzace",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Podporuje Amazon Bedrock Converse API",
|
||||||
|
"aiProviderCreated": "AI poskytovatel vytvořen",
|
||||||
|
"aiProviderUpdated": "AI poskytovatel aktualizován",
|
||||||
|
"aiProviderDeleted": "AI poskytovatel odstraněn",
|
||||||
|
"aiProviderDelete": "Odstranit poskytovatele",
|
||||||
|
"aiProviderDeleteConfirm": "Odstranit poskytovatele",
|
||||||
|
"aiProviderQuestionRemove": "Opravdu chcete odstranit tohoto AI poskytovatele?",
|
||||||
|
"aiProviderMessageRemove": "Tímto bude trvale odstraněn poskytovatel a jeho modely a cíle. To nelze vrátit zpět.",
|
||||||
|
"aiProviderErrorNoUpdate": "AI poskytovatele nelze aktualizovat",
|
||||||
|
"aiProviderModels": "Modely",
|
||||||
|
"aiProviderModelsDescription": "Definujte seznamy pro povolení a blokování pro tohoto poskytovatele. Požadavky musí odpovídat seznamu povolení a nesmí odpovídat seznamu blokací.",
|
||||||
|
"aiProviderCreateModelsDescription": "Vyberte, které modely tento poskytovatel může nabízet. Prázdný seznam povolení zamítá veškerý provoz. Modely můžete přidat nebo změnit později.",
|
||||||
|
"aiProviderModelsPlaceholder": "Hledat modely nebo zadat vlastní klíč",
|
||||||
|
"aiProviderModelsAllow": "Seznam povolení",
|
||||||
|
"aiProviderModelsAllowDescription": "Modely, které lze použít prostřednictvím tohoto poskytovatele. Prázdný znamená zamítnout vše.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Zadejte klíč modelu",
|
||||||
|
"aiProviderModelsAllowEmpty": "Ještě nebyly přidány žádné modely.",
|
||||||
|
"aiProviderModelsBlock": "Seznam blokací",
|
||||||
|
"aiProviderModelsBlockDescription": "Modely zamítnuté i když odpovídají záznamům ze seznamu povolení.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Zadejte klíč modelu",
|
||||||
|
"aiProviderModelsBlockEmpty": "Ještě nebyly přidány žádné modely.",
|
||||||
|
"aiProviderModelsAdd": "Přidat modely",
|
||||||
|
"aiProviderModelsClearAll": "Vymazat vše",
|
||||||
|
"aiProviderModelsAddCustom": "Přidat \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Stiskněte Enter pro přidání tohoto vlastního klíče modelu.",
|
||||||
|
"aiProviderModelsAddBulk": "Přidat {count} vlastních klíčů",
|
||||||
|
"aiProviderModelsAddBulkHint": "Stiskněte Enter pro přidání {count} vlastních klíčů.",
|
||||||
|
"aiProviderModelsAddOne": "Přidat {key} nyní",
|
||||||
|
"aiProviderModelsAddSelected": "Přidat vybrané",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} vybráno",
|
||||||
|
"aiProviderModelsSelectAll": "Vybrat vše",
|
||||||
|
"aiProviderModelsClearSelected": "Smazat",
|
||||||
|
"aiProviderModelsBulkHint": "Vyberte známé modely nebo zadejte vlastní klíč.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Žádné odpovídající modely v katalogu.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Známé modely",
|
||||||
|
"aiProviderModelsAllLabel": "Všechny modely",
|
||||||
|
"aiProviderModelsAllPatternHint": "Zástupný znak: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Povolit všechny modely",
|
||||||
|
"aiProviderModelsAddAllBlock": "Blokovat všechny modely",
|
||||||
|
"aiProviderModelsAddAllDescription": "Používá * wildcard tak, aby odpovídal na všechny klíče modelů.",
|
||||||
|
"aiProviderModelsViewMore": "Zobrazit více ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Zobrazit méně",
|
||||||
|
"aiProviderModelsRemove": "Odstranit model",
|
||||||
|
"aiProviderModelsEditHint": "Klikněte pro úpravu nastavení modelu",
|
||||||
|
"aiProviderModelsSourceCatalog": "Známý model katalogu",
|
||||||
|
"aiProviderModelsSourceCustom": "Vlastní klíč modelu",
|
||||||
|
"aiProviderModelsSourcePattern": "Vzorek wildcard",
|
||||||
|
"aiProviderModelsSourceAll": "Odpovídá každému klíči modelu",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Rozpočet nakonfigurován",
|
||||||
|
"aiProviderModelsEditTitle": "Upravit model",
|
||||||
|
"aiProviderModelsEditDescription": "Aktualizujte klíč modelu nebo nakonfigurujte jeho rozpočet.",
|
||||||
|
"aiProviderModelsBudgetTab": "Rozpočet",
|
||||||
|
"aiProviderModelsKeyLabel": "Klíč modelu",
|
||||||
|
"aiProviderModelsKeyRequired": "Zadejte klíč modelu",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Tento klíč modelu je již na seznamu",
|
||||||
|
"aiProviderModelsOverlapError": "Tyto vzory nemohou být na obou seznamech: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modely aktualizovány",
|
||||||
|
"aiProviderModelsErrorUpdate": "Nepodařilo se aktualizovat modely",
|
||||||
|
"aiResourceProviders": "Poskytovatelé",
|
||||||
|
"aiResourceProvidersDescription": "Zvolte, jaké AI poskytovatelé mohou tento AI gateway použít",
|
||||||
|
"aiResourceProvidersHelp": "Přidejte poskytovatele a zvolte dědění (použijte seznamy každého z nich) nebo vyberte (zvolte seznam povolení pro tento zdroj). Povolené vzory, které se střetávají mezi přidanými poskytovateli nejsou povoleny.",
|
||||||
|
"aiResourceProvidersSelect": "Vyberte poskytovatele",
|
||||||
|
"aiResourceProvidersEmpty": "AI poskytovatelé nenalezeni",
|
||||||
|
"aiResourceProvidersNoneAttached": "Žádný poskytovatel nebyl zatím připojen.",
|
||||||
|
"aiResourceProvidersAdd": "Přidat poskytovatele",
|
||||||
|
"aiResourceProvidersRemove": "Odstranit poskytovatele",
|
||||||
|
"aiResourceProviderToggleEnabled": "Povolit nebo zakázat tohoto poskytovatele na zdroji",
|
||||||
|
"aiResourceProviderDisabled": "Zakázáno",
|
||||||
|
"aiResourceProvidersUpdated": "Poskytovatelé aktualizováni",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Nepodařilo se aktualizovat poskytovatele",
|
||||||
|
"aiResourceProviderEditDescription": "Zvolte, jak bude tento poskytovatelův model vystaven na tomto zdroji.",
|
||||||
|
"viewProviderSettings": "Zobrazit nastavení poskytovatele",
|
||||||
|
"aiResourceProviderMode": "Režim přístupu",
|
||||||
|
"aiResourceProviderModeInherit": "Dědit",
|
||||||
|
"aiResourceProviderModeSelect": "Vybrat",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Vyberte · {count} modely",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Použít seznamy povolení a blokací poskytovatele, jak byly konfigurovány.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Vyberte podmnožinu modelů povolených pro tento zdroj.",
|
||||||
|
"aiResourceProviderAllowModels": "Seznam povolení",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Vybrat modely",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Hledat modely...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Žádné modely nenalezeny",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Lze vybrat pouze modely ze seznamu povolení poskytovatele.",
|
||||||
|
"aiResourceAliasRequired": "Alias je povinný pro AI brány",
|
||||||
|
"aiResourceDomainConfiguration": "Konfigurace domény",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Vyberte doménu, kterou klienti použijí k přístupu ke této AI bráně.",
|
||||||
|
"aiUsageAnalyticsTitle": "AI analytika využití",
|
||||||
|
"aiUsageAnalyticsDescription": "Analyzujte náklady na AI brány, použití tokenů a aktivitu napříč poskytovateli, zdroji, rolemi a uživateli",
|
||||||
|
"aiUsageTabOverview": "Přehled",
|
||||||
|
"aiUsageTabProviders": "Poskytovatelé",
|
||||||
|
"aiUsageTabResources": "Zdroje",
|
||||||
|
"aiUsageFilterProvider": "Poskytovatel",
|
||||||
|
"aiUsageFilterModel": "Model",
|
||||||
|
"aiUsageFilterResource": "Zdroj",
|
||||||
|
"aiUsageFilterRole": "Role",
|
||||||
|
"aiUsageFilterUser": "Uživatel",
|
||||||
|
"aiUsageFilterAllProviders": "Všichni poskytovatelé",
|
||||||
|
"aiUsageFilterAllModels": "Všechny modely",
|
||||||
|
"aiUsageFilterAllResources": "Všechny zdroje",
|
||||||
|
"aiUsageFilterAllRoles": "Všechny role",
|
||||||
|
"aiUsageFilterAllUsers": "Všichni uživatelé",
|
||||||
|
"aiUsageFilterSearch": "Hledat...",
|
||||||
|
"aiUsageFilterNotFound": "Žádné možnosti nenalezeny",
|
||||||
|
"aiUsageResetFilters": "Resetovat filtry",
|
||||||
|
"aiUsageRefresh": "Obnovit",
|
||||||
|
"aiUsageTokenTypePrompt": "Výzvy",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Čtení z vyrovnávací paměti",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Zápis do vyrovnávací paměti",
|
||||||
|
"aiUsageTokenTypeCompletion": "Doplňování",
|
||||||
|
"aiUsageTokenTypeReasoning": "Odůvodnění",
|
||||||
|
"aiUsageRequests": "Požadavky",
|
||||||
|
"aiUsageCost": "Náklady",
|
||||||
|
"aiUsageTokens": "Tokeny",
|
||||||
|
"aiUsageOther": "Ostatní",
|
||||||
|
"aiUsageTotalRequests": "Celkové požadavky",
|
||||||
|
"aiUsageTotalTokens": "Celkem tokenů",
|
||||||
|
"aiUsageTotalCost": "Celkové náklady",
|
||||||
|
"aiUsageEstimated": "Odhadováno",
|
||||||
|
"aiUsageRequestVolume": "Objem požadavků",
|
||||||
|
"aiUsageTokenUsage": "Použití tokenu",
|
||||||
|
"aiUsageModelCost": "Náklady na model",
|
||||||
|
"aiUsageModelTokens": "Modelové tokeny",
|
||||||
|
"aiUsageTopModels": "Nejoblíbenější modely",
|
||||||
|
"aiUsageTopProviders": "Nejoblíbenější poskytovatelé",
|
||||||
|
"aiUsageProviderCost": "Náklady poskytovatele",
|
||||||
|
"aiUsageProviderTokenUsage": "Použití tokenů poskytovatele",
|
||||||
|
"aiUsageTopResources": "Nejoblíbenější zdroje",
|
||||||
|
"aiUsageResourceCost": "Náklady na zdroje",
|
||||||
|
"aiUsageResourceTokenUsage": "Použití tokenů zdroje",
|
||||||
|
"aiUsageResourceTypePublic": "Veřejný zdroj",
|
||||||
|
"aiUsageResourceTypeSite": "Soukromý zdroj",
|
||||||
|
"aiUsageNoResource": "Žádný zdroj",
|
||||||
|
"aiUsageRolesTab": "Role",
|
||||||
|
"aiUsageUsersTab": "Uživatelé",
|
||||||
|
"aiUsageTopRoles": "Nejoblíbenější role",
|
||||||
|
"aiUsageRoleCost": "Náklady role",
|
||||||
|
"aiUsageRoleTokenUsage": "Použití tokenů role",
|
||||||
|
"aiUsageTopUsers": "Nejoblíbenější uživatelé",
|
||||||
|
"aiUsageUserCost": "Náklady uživatele",
|
||||||
|
"aiUsageUserTokenUsage": "Použití tokenů uživatelem",
|
||||||
|
"aiUsageUnknownUser": "Neznámý uživatel",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Virtuální API klíče",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Virtuální API klíč",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Všechny virtuální API klíče",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Nejoblíbenější virtuální API klíče",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Náklady na virtuální API klíč",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Použití tokenů virtuálního API klíče",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Žádný virtuální API klíč",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Nepojmenovaný klíč",
|
||||||
|
"aiUsageLoading": "Nahrávání...",
|
||||||
|
"aiUsageNoData": "Žádná data",
|
||||||
|
"resourceBudgetSettings": "Rozpočet",
|
||||||
|
"resourceBudgetSettingsDescription": "Zjistěte, jak tato AI brána omezuje užívání na základě výdajů nebo limitů tokenů",
|
||||||
"sidebarApiKeys": "API klíče",
|
"sidebarApiKeys": "API klíče",
|
||||||
"sidebarProvisioning": "Zajištění",
|
"sidebarProvisioning": "Zajištění",
|
||||||
"sidebarSettings": "Nastavení",
|
"sidebarSettings": "Nastavení",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Pravidlo upozornění bylo uloženo",
|
"alertingRuleSaved": "Pravidlo upozornění bylo uloženo",
|
||||||
"alertingRuleSavedCreatedDescription": "Vaše nové pravidlo upozornění bylo vytvořeno. Můžete ho dál upravovat na této stránce.",
|
"alertingRuleSavedCreatedDescription": "Vaše nové pravidlo upozornění bylo vytvořeno. Můžete ho dál upravovat na této stránce.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Vaše změny pro toto pravidlo upozornění byly uloženy.",
|
"alertingRuleSavedUpdatedDescription": "Vaše změny pro toto pravidlo upozornění byly uloženy.",
|
||||||
|
"alertingTestAlertSent": "Testovací upozornění odesláno",
|
||||||
|
"alertingTestAlertSentDescription": "Testovací upozornění bylo odesláno na akce nakonfigurované v tomto pravidle.",
|
||||||
"alertingEditRule": "Upravit pravidlo upozornění",
|
"alertingEditRule": "Upravit pravidlo upozornění",
|
||||||
"alertingCreateRule": "Vytvořit pravidlo upozornění",
|
"alertingCreateRule": "Vytvořit pravidlo upozornění",
|
||||||
"alertingRuleCredenzaDescription": "Vyberte, co sledovat, kdy ho spustit a jak oznamovat",
|
"alertingRuleCredenzaDescription": "Vyberte, co sledovat, kdy ho spustit a jak oznamovat",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Každé pravidlo spojuje, co sledovat (lokalita, kontrola stavu nebo zdroj), kdy ho spustit (například offline nebo nezdravé), a jak informovat váš tým emailem, webhookem nebo integracemi. Použijte tento seznam k vytvoření, povolení a správě těchto pravidel.",
|
"alertingRulesBannerDescription": "Každé pravidlo spojuje, co sledovat (lokalita, kontrola stavu nebo zdroj), kdy ho spustit (například offline nebo nezdravé), a jak informovat váš tým emailem, webhookem nebo integracemi. Použijte tento seznam k vytvoření, povolení a správě těchto pravidel.",
|
||||||
"alertingHealthChecksBannerTitle": "Monitorujte zdraví a zdroje",
|
"alertingHealthChecksBannerTitle": "Monitorujte zdraví a zdroje",
|
||||||
"alertingHealthChecksBannerDescription": "Kontroly stavu jsou HTTP nebo TCP monitory, které nastavíte jednou. Poté je můžete použít jako zdroje v pravidlech upozornění, takže budete informováni, když se cíl stane zdravým nebo nezdravým. Kontroly stavu také zde se objeví.",
|
"alertingHealthChecksBannerDescription": "Kontroly stavu jsou HTTP nebo TCP monitory, které nastavíte jednou. Poté je můžete použít jako zdroje v pravidlech upozornění, takže budete informováni, když se cíl stane zdravým nebo nezdravým. Kontroly stavu také zde se objeví.",
|
||||||
|
"alertingTestRule": "Testovací pravidlo upozornění",
|
||||||
|
"alertingAddActionHeading": "Přidat novou akci",
|
||||||
|
"alertingSelectActionType": "Vyberte akci",
|
||||||
|
"alertingNoActionsTitle": "Žádné akce neodkonfigurovány",
|
||||||
|
"alertingNoActionsSaveDescription": "Přidejte alespoň jednu akci, aby toto pravidlo mohlo někoho upozornit, když se spustí.",
|
||||||
|
"alertingNoActionsTestDescription": "Přidejte alespoň jednu akci, než budete moci toto pravidlo otestovat.",
|
||||||
"standaloneHcTableTitle": "Kontroly stavu",
|
"standaloneHcTableTitle": "Kontroly stavu",
|
||||||
"standaloneHcSearchPlaceholder": "Hledat kontroly stavu…",
|
"standaloneHcSearchPlaceholder": "Hledat kontroly stavu…",
|
||||||
"standaloneHcAddButton": "Vytvořit kontrolu stavu",
|
"standaloneHcAddButton": "Vytvořit kontrolu stavu",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Subdoména: {subdomain}",
|
"domainPickerSubdomain": "Subdoména: {subdomain}",
|
||||||
"domainPickerNamespace": "Jmenný prostor: {namespace}",
|
"domainPickerNamespace": "Jmenný prostor: {namespace}",
|
||||||
"domainPickerShowMore": "Zobrazit více",
|
"domainPickerShowMore": "Zobrazit více",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Nejsou k dispozici žádné domény",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Zatím nemáte žádné nastavené domény. Vytvořte doménu, abyste mohli pokračovat.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Přejít na domény",
|
||||||
"regionSelectorTitle": "Vybrat region",
|
"regionSelectorTitle": "Vybrat region",
|
||||||
"domainPickerRemoteExitNodeWarning": "Poskytnuté domény nejsou podporovány, když se stránky připojují k vzdáleným výstupním uzlům. Pro dostupné zdroje na vzdálených uzlech použijte vlastní doménu.",
|
"domainPickerRemoteExitNodeWarning": "Poskytnuté domény nejsou podporovány, když se stránky připojují k vzdáleným výstupním uzlům. Pro dostupné zdroje na vzdálených uzlech použijte vlastní doménu.",
|
||||||
"regionSelectorInfo": "Výběr regionu nám pomáhá poskytovat lepší výkon pro vaši polohu. Nemusíte být ve stejném regionu jako váš server.",
|
"regionSelectorInfo": "Výběr regionu nám pomáhá poskytovat lepší výkon pro vaši polohu. Nemusíte být ve stejném regionu jako váš server.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Podsíť",
|
"subnetPlaceholder": "Podsíť",
|
||||||
"addressDescription": "Interní adresa klienta. Musí spadat do podsítě organizace.",
|
"addressDescription": "Interní adresa klienta. Musí spadat do podsítě organizace.",
|
||||||
"selectSites": "Vyberte stránky",
|
"selectSites": "Vyberte stránky",
|
||||||
|
"selectResources": "Vyberte zdroje",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# zdroj} few {# zdroje} many {# zdrojů} other {# zdroje}}",
|
||||||
"selectLabels": "Vyberte názvy",
|
"selectLabels": "Vyberte názvy",
|
||||||
"sitesDescription": "Klient bude mít připojení k vybraným webům",
|
"sitesDescription": "Klient bude mít připojení k vybraným webům",
|
||||||
"clientInstallOlm": "Nainstalovat Olm",
|
"clientInstallOlm": "Nainstalovat Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Čas je v sekundách",
|
"timeIsInSeconds": "Čas je v sekundách",
|
||||||
"requireDeviceApproval": "Vyžadovat schválení zařízení",
|
"requireDeviceApproval": "Vyžadovat schválení zařízení",
|
||||||
"requireDeviceApprovalDescription": "Uživatelé s touto rolí potřebují nová zařízení schválená správcem, než se mohou připojit a přistupovat ke zdrojům.",
|
"requireDeviceApprovalDescription": "Uživatelé s touto rolí potřebují nová zařízení schválená správcem, než se mohou připojit a přistupovat ke zdrojům.",
|
||||||
"sshSettings": "Nastavení SSH",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI brána",
|
||||||
"sshAccess": "SSH Přístup",
|
"sshAccess": "SSH Přístup",
|
||||||
"rdpSettings": "Nastavení RDP",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "Nastavení VNC",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH server",
|
"sshServer": "SSH server",
|
||||||
"rdpServer": "RDP server",
|
"rdpServer": "RDP server",
|
||||||
"vncServer": "VNC server",
|
"vncServer": "VNC server",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Veřejnost",
|
"resourcesTableProxyResources": "Veřejnost",
|
||||||
"resourcesTableClientResources": "Soukromé",
|
"resourcesTableClientResources": "Soukromé",
|
||||||
"resourcesTableNoProxyResourcesFound": "Nebyly nalezeny žádné zdroje proxy",
|
"resourcesTableNoProxyResourcesFound": "Nebyly nalezeny žádné zdroje proxy",
|
||||||
"resourcesTableNoInternalResourcesFound": "Nebyly nalezeny žádné vnitřní zdroje.",
|
"resourcesTableNoInternalResourcesFound": "Nebyly nalezeny žádné privátní zdroje.",
|
||||||
"resourcesTableDestination": "Místo určení",
|
"resourcesTableDestination": "Místo určení",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Adresa aliasu",
|
"resourcesTableAliasAddress": "Adresa aliasu",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Zrušit",
|
"editInternalResourceDialogCancel": "Zrušit",
|
||||||
"editInternalResourceDialogSaveResource": "Uložit dokument",
|
"editInternalResourceDialogSaveResource": "Uložit dokument",
|
||||||
"editInternalResourceDialogSuccess": "Úspěšně",
|
"editInternalResourceDialogSuccess": "Úspěšně",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interní zdroj byl úspěšně aktualizován",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Privátní zdroj byl úspěšně aktualizován",
|
||||||
"editInternalResourceDialogError": "Chyba",
|
"editInternalResourceDialogError": "Chyba",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Aktualizace interního zdroje se nezdařila",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Nepodařilo se aktualizovat privátní zdroj",
|
||||||
"editInternalResourceDialogNameRequired": "Název je povinný",
|
"editInternalResourceDialogNameRequired": "Název je povinný",
|
||||||
"editInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků",
|
"editInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků",
|
||||||
"editInternalResourceDialogProxyPortMin": "Port proxy serveru musí být alespoň 1",
|
"editInternalResourceDialogProxyPortMin": "Port proxy serveru musí být alespoň 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI brána",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Schéma",
|
"editInternalResourceDialogScheme": "Schéma",
|
||||||
"editInternalResourceDialogEnableSsl": "Povolit TLS",
|
"editInternalResourceDialogEnableSsl": "Povolit TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Volitelný interní DNS alias pro tento dokument.",
|
"editInternalResourceDialogAliasDescription": "Volitelný interní DNS alias pro tento dokument.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Nejsou k dispozici žádné weby",
|
"createInternalResourceDialogNoSitesAvailable": "Nejsou k dispozici žádné weby",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Musíte mít alespoň jeden Newt web s podsítí nakonfigurovanou pro vytvoření vnitřních zdrojů.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "K vytvoření privátních zdrojů potřebujete mít alespoň jednu lokalitu Newt s nastavenou podsítí.",
|
||||||
"createInternalResourceDialogClose": "Zavřít",
|
"createInternalResourceDialogClose": "Zavřít",
|
||||||
"createInternalResourceDialogCreateClientResource": "Vytvořit soukromý zdroj",
|
"createInternalResourceDialogCreateClientResource": "Vytvořit soukromý zdroj",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Vytvořte nový zdroj, který bude přístupný pouze klientům připojeným k organizaci",
|
"createInternalResourceDialogCreateClientResourceDescription": "Vytvořte nový zdroj, který bude přístupný pouze klientům připojeným k organizaci",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Povolit ICMP ping",
|
"privateResourceAllowIcmpPing": "Povolit ICMP ping",
|
||||||
"privateResourceNetworkAccess": "Přístup k síti",
|
"privateResourceNetworkAccess": "Přístup k síti",
|
||||||
"privateResourceNetworkAccessDescription": "Ovládejte přístup k TCP/UDP portům a zda je pro tento zdroj povolen ICMP ping.",
|
"privateResourceNetworkAccessDescription": "Ovládejte přístup k TCP/UDP portům a zda je pro tento zdroj povolen ICMP ping.",
|
||||||
"hostSettings": "Nastavení hostitele",
|
"hostSettings": "Hostitel",
|
||||||
"cidrSettings": "Nastavení CIDR",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Vlastnosti zdroje",
|
"createInternalResourceDialogResourceProperties": "Vlastnosti zdroje",
|
||||||
"createInternalResourceDialogName": "Jméno",
|
"createInternalResourceDialogName": "Jméno",
|
||||||
"createInternalResourceDialogSite": "Lokalita",
|
"createInternalResourceDialogSite": "Lokalita",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Zrušit",
|
"createInternalResourceDialogCancel": "Zrušit",
|
||||||
"createInternalResourceDialogCreateResource": "Vytvořit zdroj",
|
"createInternalResourceDialogCreateResource": "Vytvořit zdroj",
|
||||||
"createInternalResourceDialogSuccess": "Úspěšně",
|
"createInternalResourceDialogSuccess": "Úspěšně",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interní zdroj byl úspěšně vytvořen",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Privátní zdroj byl úspěšně vytvořen",
|
||||||
"createInternalResourceDialogError": "Chyba",
|
"createInternalResourceDialogError": "Chyba",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Nepodařilo se vytvořit interní zdroj",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Nepodařilo se vytvořit privátní zdroj",
|
||||||
"createInternalResourceDialogNameRequired": "Název je povinný",
|
"createInternalResourceDialogNameRequired": "Název je povinný",
|
||||||
"createInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků",
|
"createInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Vyberte prosím web",
|
"createInternalResourceDialogPleaseSelectSite": "Vyberte prosím web",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI brána",
|
||||||
"scheme": "Schéma",
|
"scheme": "Schéma",
|
||||||
"createInternalResourceDialogScheme": "Schéma",
|
"createInternalResourceDialogScheme": "Schéma",
|
||||||
"createInternalResourceDialogEnableSsl": "Povolit TLS",
|
"createInternalResourceDialogEnableSsl": "Povolit TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Platné heslo",
|
"validPassword": "Platné heslo",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Platný virtuální API klíč",
|
||||||
"view": "Zobrazit",
|
"view": "Zobrazit",
|
||||||
"configManaged": "Správa konfigurace",
|
"configManaged": "Správa konfigurace",
|
||||||
"connectedClient": "Připojený klient",
|
"connectedClient": "Připojený klient",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Zaznamenávání záznamu",
|
"logRetention": "Zaznamenávání záznamu",
|
||||||
"logRetentionDescription": "Spravovat, jak dlouho jsou různé typy logů uloženy pro tuto organizaci nebo je zakázat",
|
"logRetentionDescription": "Spravovat, jak dlouho jsou různé typy logů uloženy pro tuto organizaci nebo je zakázat",
|
||||||
"requestLogsDescription": "Zobrazit podrobné protokoly požadavků pro zdroje v této organizaci",
|
"requestLogsDescription": "Zobrazit podrobné protokoly požadavků pro zdroje v této organizaci",
|
||||||
|
"aiSessionLogs": "Protokoly AI Gateway Session",
|
||||||
|
"aiSessionLogsDescription": "Zobrazit uložené výzvy a odpovědi na žádosti AI brány v této organizaci",
|
||||||
|
"sidebarLogsAi": "Protokoly relací",
|
||||||
|
"commandLogsAi": "Protokoly relací",
|
||||||
|
"sidebarLogsAiUsage": "Analýza využití",
|
||||||
|
"commandLogsAiUsage": "Analýza využití",
|
||||||
|
"provider": "Poskytovatel",
|
||||||
|
"capability": "Funkce",
|
||||||
|
"model": "Model",
|
||||||
|
"virtualApiKey": "Virtuální API klíč",
|
||||||
|
"noVirtualApiKey": "Žádný virtuální API klíč",
|
||||||
|
"stream": "Proud",
|
||||||
|
"streaming": "Streamování",
|
||||||
|
"nonStreaming": "Nestreamování",
|
||||||
|
"statusCode": "Kód stavu",
|
||||||
|
"aiSessionId": "ID relace",
|
||||||
|
"aiSessionRequest": "Požadavek",
|
||||||
|
"aiSessionResponse": "Odpověď",
|
||||||
|
"aiSessionNoData": "Žádná data nezachycena",
|
||||||
|
"aiSessionCouldNotParse": "(surové, nelze parse protokol)",
|
||||||
|
"aiSessionLogTruncated": "Tato relace byla oříznuta před uložením a může být neúplná.",
|
||||||
|
"aiSessionViewRaw": "Zobrazit syrové JSON",
|
||||||
|
"aiSessionViewChat": "Zobrazit chat",
|
||||||
|
"cost": "Náklady",
|
||||||
|
"estimated": "Odhadovaný",
|
||||||
|
"tokenUsage": "Použití tokenu",
|
||||||
|
"promptTokens": "Výzvy tokenů",
|
||||||
|
"cacheReadTokens": "Číst tokeny z vyrovnávací paměti",
|
||||||
|
"cacheWriteTokens": "Zapisovat tokeny do vyrovnávací paměti",
|
||||||
|
"completionTokens": "Doplňovací tokeny",
|
||||||
|
"reasoningTokens": "Odůvodňující tokeny",
|
||||||
|
"totalTokens": "Celkem tokenů",
|
||||||
"requestAnalyticsDescription": "Zobrazit podrobnou analýzu požadavků pro zdroje v této organizaci",
|
"requestAnalyticsDescription": "Zobrazit podrobnou analýzu požadavků pro zdroje v této organizaci",
|
||||||
"logRetentionRequestLabel": "Zachování logu HTTP požadavků",
|
"logRetentionRequestLabel": "Zachování logu HTTP požadavků",
|
||||||
"logRetentionRequestDescription": "Jak dlouho uchovávat záznamy požadavků",
|
"logRetentionRequestDescription": "Jak dlouho uchovávat záznamy požadavků",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Jak dlouho uchovávat záznamy akcí",
|
"logRetentionActionDescription": "Jak dlouho uchovávat záznamy akcí",
|
||||||
"logRetentionConnectionLabel": "Uchovávání protokolu připojení",
|
"logRetentionConnectionLabel": "Uchovávání protokolu připojení",
|
||||||
"logRetentionConnectionDescription": "Jak dlouho uchovávat protokoly připojení",
|
"logRetentionConnectionDescription": "Jak dlouho uchovávat protokoly připojení",
|
||||||
|
"logRetentionAISessionsLabel": "Retence protokolu AI Gateway Session",
|
||||||
|
"logRetentionAISessionsDescription": "Jak dlouho zachovávat protokoly relací výzev/odpovědí AI brány",
|
||||||
"logRetentionDisabled": "Zakázáno",
|
"logRetentionDisabled": "Zakázáno",
|
||||||
"logRetention3Days": "3 dny",
|
"logRetention3Days": "3 dny",
|
||||||
"logRetention7Days": "7 dní",
|
"logRetention7Days": "7 dní",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Zdrojová adresa",
|
"sourceAddress": "Zdrojová adresa",
|
||||||
"destinationAddress": "Cílová adresa",
|
"destinationAddress": "Cílová adresa",
|
||||||
"duration": "Doba trvání",
|
"duration": "Doba trvání",
|
||||||
"licenseRequiredToUse": "Pro použití této funkce je vyžadována licence <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> nebo <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> . <bookADemoLink>Zarezervujte si demo nebo POC zkušební verzi</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Licence Enterprise Edition</enterpriseEditionLink> je nutná. <bookADemoLink>Zarezervujte si ukázku nebo vyzkoušení</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> je vyžadována pro použití této funkce. Tato funkce je také k dispozici v <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Rezervujte si demo nebo POC zkušební verzi</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Licence Enterprise Edition</enterpriseEditionLink> je nutná. <bookADemoLink>Zarezervujte si ukázku nebo vyzkoušení</bookADemoLink>",
|
||||||
"certResolver": "Oddělovač certifikátů",
|
"certResolver": "Oddělovač certifikátů",
|
||||||
"certResolverDescription": "Vyberte řešitele certifikátů pro tento dokument.",
|
"certResolverDescription": "Vyberte řešitele certifikátů pro tento dokument.",
|
||||||
"selectCertResolver": "Vyberte řešič certifikátů",
|
"selectCertResolver": "Vyberte řešič certifikátů",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Výběrem více webů se povolí odolné směrování a přepojení pro vysokou dostupnost.",
|
"internalResourceFormMultiSiteRoutingHelp": "Výběrem více webů se povolí odolné směrování a přepojení pro vysokou dostupnost.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Zjistit více",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Zjistit více",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Omezte přístup na specifické TCP/UDP porty nebo povolte/blokujte všechny porty.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Omezte přístup na specifické TCP/UDP porty nebo povolte/blokujte všechny porty.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "Konfigurace HTTP",
|
"createInternalResourceDialogHttpConfiguration": "Konfigurace domény",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Zvolte doménu, kterou klienti použijí k dosažení tohoto zdroje přes HTTP nebo HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Zvolte doménu, kterou klienti použijí k dosažení tohoto zdroje přes HTTP nebo HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "Konfigurace HTTP",
|
"editInternalResourceDialogHttpConfiguration": "Konfigurace domény",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Zvolte doménu, kterou klienti použijí k dosažení tohoto zdroje přes HTTP nebo HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Zvolte doménu, kterou klienti použijí k dosažení tohoto zdroje přes HTTP nebo HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Bez nálepky",
|
"resourceLauncherUnlabeled": "Bez nálepky",
|
||||||
|
"resourceLauncherAiGateway": "AI brána",
|
||||||
"resourceLauncherNoSite": "Žádná lokalita",
|
"resourceLauncherNoSite": "Žádná lokalita",
|
||||||
|
"resourceLauncherAvailableModels": "Dostupné modely",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modely, které můžete použít s touto AI bránou.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Pro tuto službu nejsou k dispozici žádné modely.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Nelze načíst dostupné modely.",
|
||||||
|
"resourceLauncherApiKeys": "API klíče",
|
||||||
|
"resourceLauncherApiKeysDescription": "Použijte svůj klíč identity nebo přidělený klíč k autentizaci s tímto zdrojem.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Klíč identity",
|
||||||
|
"resourceLauncherApiKeysManual": "Přidělené klíče",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Pro tuto službu nejsou k dispozici žádné klíče API.",
|
||||||
|
"resourceLauncherApiKeysError": "Nelze načíst API klíče.",
|
||||||
"resourceLauncherNoResourcesInGroup": "V této skupině nejsou žádné zdroje",
|
"resourceLauncherNoResourcesInGroup": "V této skupině nejsou žádné zdroje",
|
||||||
"resourceLauncherEmptyStateTitle": "Žádné dostupné zdroje",
|
"resourceLauncherEmptyStateTitle": "Žádné dostupné zdroje",
|
||||||
"resourceLauncherEmptyStateDescription": "Zatím nemáte přístup k žádným zdrojům. Kontaktujte svého administrátora, abyste požádali o přístup.",
|
"resourceLauncherEmptyStateDescription": "Zatím nemáte přístup k žádným zdrojům. Kontaktujte svého administrátora, abyste požádali o přístup.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Nepodařilo se smazat spouštěcí pohled. Prosím zkuste to znovu.",
|
"resourceLauncherViewDeleteFailedDescription": "Nepodařilo se smazat spouštěcí pohled. Prosím zkuste to znovu.",
|
||||||
"memberPortalPrevious": "Předchozí",
|
"memberPortalPrevious": "Předchozí",
|
||||||
"memberPortalNext": "Následující",
|
"memberPortalNext": "Následující",
|
||||||
"httpSettings": "Nastavení HTTP",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "Nastavení TCP",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "Nastavení UDP",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Zřizování bezpečného připojení…",
|
"sshConnectingDescription": "Zřizování bezpečného připojení…",
|
||||||
"sshConnecting": "Připojení…",
|
"sshConnecting": "Připojení…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Nahrání selhalo",
|
"rdpUploadFailed": "Nahrání selhalo",
|
||||||
"rdpUnicodeKeyboardMode": "Režim Unicode klávesnice",
|
"rdpUnicodeKeyboardMode": "Režim Unicode klávesnice",
|
||||||
"sessionToolbarShow": "Zobrazit panel nástrojů",
|
"sessionToolbarShow": "Zobrazit panel nástrojů",
|
||||||
"sessionToolbarHide": "Skrýt panel nástrojů"
|
"sessionToolbarHide": "Skrýt panel nástrojů",
|
||||||
|
"actionUpdateSiteApprovals": "Aktualizovat schválení webu"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Venligst tjek at du er loget ind som korrekt bruger.",
|
"inviteLoginUser": "Venligst tjek at du er loget ind som korrekt bruger.",
|
||||||
"inviteErrorNoUser": "Beklager, men det ser ud til, at invitationen du prøver at få adgang til, ikke er til en eksisterende bruger.",
|
"inviteErrorNoUser": "Beklager, men det ser ud til, at invitationen du prøver at få adgang til, ikke er til en eksisterende bruger.",
|
||||||
"inviteCreateUser": "Opret venligst en konto først.",
|
"inviteCreateUser": "Opret venligst en konto først.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Invitationer kan kun accepteres af interne konti. Log ud og log ind med din adgangskode til denne e-mail.",
|
||||||
|
"inviteLoginInternalOnly": "Invitationer kræver en intern konto med en adgangskode. Opret en konto eller log ind med din adgangskode.",
|
||||||
"goHome": "Gå hjem",
|
"goHome": "Gå hjem",
|
||||||
"inviteLogInOtherUser": "Log ind som en anden bruger",
|
"inviteLogInOtherUser": "Log ind som en anden bruger",
|
||||||
"createAnAccount": "Opret konto",
|
"createAnAccount": "Opret konto",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Bekræft sletning af delbar link",
|
"shareDeleteConfirm": "Bekræft sletning af delbar link",
|
||||||
"shareQuestionRemove": "Er du sikker på, at du vil slette dette delingslink?",
|
"shareQuestionRemove": "Er du sikker på, at du vil slette dette delingslink?",
|
||||||
"shareMessageRemove": "Når linket er slettet, vil det ikke længere fungere, og alle, der bruger det, mister adgang til ressourcen.",
|
"shareMessageRemove": "Når linket er slettet, vil det ikke længere fungere, og alle, der bruger det, mister adgang til ressourcen.",
|
||||||
"shareTokenDescription": "Adgangstoken kan sendes på to måter: som en queryparameter eller i request-headers. Disse skal sendes fra klienten på hver forespørgsel om autentificeret adgang.",
|
"shareTokenDescription": "Adgangstokenet kan sendes som en forespørgselsparameter eller i anmodningsoverskrifter. Som standard skal det sendes ved hver anmodning. Hvis sessionsvedholdelse er aktiveret, byttes den første anmodning for en sessionscookie.",
|
||||||
"accessToken": "Adgangstoken",
|
"accessToken": "Adgangstoken",
|
||||||
"usageExamples": "Brukseksempler",
|
"usageExamples": "Brukseksempler",
|
||||||
"tokenId": "Token-ID",
|
"tokenId": "Token-ID",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Titel (valgfrit)",
|
"shareTitleOptional": "Titel (valgfrit)",
|
||||||
"sharePathOptional": "Sti (valgfrit)",
|
"sharePathOptional": "Sti (valgfrit)",
|
||||||
"sharePathDescription": "Linket vil videresende brugere til denne stien efter autentificering.",
|
"sharePathDescription": "Linket vil videresende brugere til denne stien efter autentificering.",
|
||||||
|
"shareAssociateUserOptional": "Tilknyt brugeren (valgfrit)",
|
||||||
|
"shareAssociateUserDescription": "Når det er indstillet, tilskrives anmodninger ved hjælp af dette link brugeren i adgangslogfiler og identitetsoverskrifter. Linket fjernes, hvis brugeren forlader organisationen.",
|
||||||
|
"userSelect": "Vælg bruger",
|
||||||
|
"usersNotFound": "Ingen brugere fundet",
|
||||||
"expireIn": "Udløber om",
|
"expireIn": "Udløber om",
|
||||||
"neverExpire": "Udløber aldrig",
|
"neverExpire": "Udløber aldrig",
|
||||||
|
"sharePersistSession": "Bevar session efter første brug",
|
||||||
|
"sharePersistSessionDescription": "Når det er aktiveret, sætter den første anmodning med dette token via en forespørgselsparameter eller overskrift en sessionscookie, så senere anmodninger ikke behøver tokenet. Lad være med det til API-klienter, der ønsker at sende tokenet ved hver anmodning.",
|
||||||
"shareExpireDescription": "Udløbstid er hvor længe linket vil være brukbar og give adgang til ressourcen. Efter denne tiden vil linket ikke længere fungere, og brugere som brugte denne linket vil miste adgangen til ressourcen.",
|
"shareExpireDescription": "Udløbstid er hvor længe linket vil være brukbar og give adgang til ressourcen. Efter denne tiden vil linket ikke længere fungere, og brugere som brugte denne linket vil miste adgangen til ressourcen.",
|
||||||
"shareSeeOnce": "Du vil kun kunne se dette link én gang. Sørg for at kopiere det.",
|
"shareSeeOnce": "Du vil kun kunne se dette link én gang. Sørg for at kopiere det.",
|
||||||
"shareAccessHint": "Alle med denne linket kan få adgang til ressourcen. Del forsiktig.",
|
"shareAccessHint": "Alle med denne linket kan få adgang til ressourcen. Del forsiktig.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Ingen land fundet.",
|
"noCountryFound": "Ingen land fundet.",
|
||||||
"siteSelectionDescription": "Dette site vil give forbindelse til målet.",
|
"siteSelectionDescription": "Dette site vil give forbindelse til målet.",
|
||||||
"resourceType": "Ressourcetype",
|
"resourceType": "Ressourcetype",
|
||||||
"resourceTypeDescription": "Dette styrer ressourceprotokolen, og hvordan den vises i browseren. Dette kan ikke ændres senere.",
|
"resourceTypeDescription": "Dette styrer ressourceprotokollen og kan ikke ændres senere.",
|
||||||
|
"resourceTypeSearch": "Søg ressource typer...",
|
||||||
|
"resourceTypeNotFound": "Ingen ressource type fundet",
|
||||||
|
"resourceTypeHttpDescription": "Proxy webtrafik over HTTPS ved brug af et domænenavn",
|
||||||
|
"resourceTypeInferenceDescription": "Rute AI-anmodninger gennem vedhæftede udbydere",
|
||||||
|
"resourceTypeSshDescription": "Adgang til en SSH-server fra browseren",
|
||||||
|
"resourceTypeRdpDescription": "Adgang til et fjernskrivebord fra browseren",
|
||||||
|
"resourceTypeVncDescription": "Adgang til et VNC-skrivebord fra browseren",
|
||||||
|
"resourceTypeTcpDescription": "Proxy rå TCP-trafik ved at bruge et portnummer",
|
||||||
|
"resourceTypeUdpDescription": "Proxy rå UDP-trafik ved at bruge et portnummer",
|
||||||
|
"privateResourceTypeDescription": "Dette styrer, hvordan klienter når ressourcen. Dette kan ikke ændres senere.",
|
||||||
|
"privateResourceTypeHostDescription": "Eksponer en enkelt vært på sitenettet mod tilkoblede klienter",
|
||||||
|
"privateResourceTypeCidrDescription": "Eksponer et CIDR-område på sitenettet mod tilkoblede klienter",
|
||||||
|
"privateResourceTypeHttpDescription": "Adgang til en HTTP eller HTTPS service gennem et domæne",
|
||||||
|
"privateResourceTypeSshDescription": "Adgang til en SSH-server fra tilkoblede klienter",
|
||||||
"resourceDomainDescription": "Ressourcen vil blive serveret på dette fuldstændigt kvalificerede domænenavnet.",
|
"resourceDomainDescription": "Ressourcen vil blive serveret på dette fuldstændigt kvalificerede domænenavnet.",
|
||||||
"resourceHTTPSSettings": "HTTPS-indstillinger",
|
"resourceHTTPSSettings": "HTTPS-indstillinger",
|
||||||
"resourceHTTPSSettingsDescription": "Konfigurer hvordan ressourcen skal nås over HTTPS",
|
"resourceHTTPSSettingsDescription": "Konfigurer hvordan ressourcen skal nås over HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Provisionering",
|
"provisioningManage": "Provisionering",
|
||||||
"provisioningDescription": "Administrer provisioneringsnøgler og gennemgå ventende sites som venter på godkendelse.",
|
"provisioningDescription": "Administrer provisioneringsnøgler og gennemgå ventende sites som venter på godkendelse.",
|
||||||
"pendingSites": "Ventende sites",
|
"pendingSites": "Ventende sites",
|
||||||
"siteApproveSuccess": "Med succes godkendelse af site",
|
"siteApproveSuccess": "Site og tilknyttede ressourcer godkendt med succes",
|
||||||
"siteApproveError": "Fejl ved godkendelse af side",
|
"siteApproveError": "Fejl ved godkendelse af side",
|
||||||
|
"siteReject": "Afvis Site",
|
||||||
|
"siteQuestionReject": "Er du sikker på, at du vil afvise dette site?",
|
||||||
|
"siteMessageReject": "Dette vil permanent slette sitet og enhver tilknyttet ressource, der stadig er i afventning.",
|
||||||
|
"siteConfirmReject": "Bekræft Afvis Site",
|
||||||
|
"siteRejectSuccess": "Site afvist med succes",
|
||||||
|
"siteRejectError": "Fejl ved afvisning af sitet",
|
||||||
"provisioningKeys": "Provisioneringsnøgler",
|
"provisioningKeys": "Provisioneringsnøgler",
|
||||||
"searchProvisioningKeys": "Søg varer i provisioneringsnøgler...",
|
"searchProvisioningKeys": "Søg varer i provisioneringsnøgler...",
|
||||||
"provisioningKeysAdd": "Generer provisioneringsnøgle",
|
"provisioningKeysAdd": "Generer provisioneringsnøgle",
|
||||||
@@ -467,7 +495,7 @@
|
|||||||
"provisioningKeysSaveDescription": "Du kan kun se denne én gang. Kopiér det til et sikkert sted.",
|
"provisioningKeysSaveDescription": "Du kan kun se denne én gang. Kopiér det til et sikkert sted.",
|
||||||
"provisioningKeysErrorCreate": "Fejl under oprettelse af provisioneringsnøgle",
|
"provisioningKeysErrorCreate": "Fejl under oprettelse af provisioneringsnøgle",
|
||||||
"provisioningKeysList": "Ny provisioneringsnøgle",
|
"provisioningKeysList": "Ny provisioneringsnøgle",
|
||||||
"provisioningKeysMaxBatchSize": "Maks størrelse på bunt",
|
"provisioningKeysMaxBatchSize": "Maksimum Batch Størrelse",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Ubegrænset mengde bunt (ingen begrænsning)",
|
"provisioningKeysUnlimitedBatchSize": "Ubegrænset mengde bunt (ingen begrænsning)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Ubegrænset",
|
"provisioningKeysMaxBatchUnlimited": "Ubegrænset",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Angiv en gyldig sjakkstørrelse (1–1 000.000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Angiv en gyldig sjakkstørrelse (1–1 000.000).",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Gem indstillinger",
|
"authMethodsSave": "Gem indstillinger",
|
||||||
"policyAuthStackTitle": "Autentificering",
|
"policyAuthStackTitle": "Autentificering",
|
||||||
"policyAuthStackDescription": "Kontroller hvilke autentificeringsmetoder som kræves for at få adgang til denne ressource",
|
"policyAuthStackDescription": "Kontroller hvilke autentificeringsmetoder som kræves for at få adgang til denne ressource",
|
||||||
|
"policyAuthInferenceStackDescription": "Vælg hvilke brugere og roller der kan autentificere til denne AI-gateway",
|
||||||
"policyAuthOrLogicTitle": "Flere autentificeringsmetoder aktive",
|
"policyAuthOrLogicTitle": "Flere autentificeringsmetoder aktive",
|
||||||
"policyAuthOrLogicBanner": "Besøgende kan autentificere sig med en hvilken som helst af de aktive metoder nedenfor. De behøver ikke at fuldføre dem alle.",
|
"policyAuthOrLogicBanner": "Besøgende kan autentificere sig med en hvilken som helst af de aktive metoder nedenfor. De behøver ikke at fuldføre dem alle.",
|
||||||
"policyAuthMethodActive": "Aktiv",
|
"policyAuthMethodActive": "Aktiv",
|
||||||
"policyAuthMethodOff": "Af",
|
"policyAuthMethodOff": "Af",
|
||||||
"policyAuthSsoTitle": "Platform-SSO",
|
"policyAuthSsoTitle": "Platform-SSO",
|
||||||
"policyAuthSsoDescription": "Kræv påloging gennem din organisations identitetsudbyder",
|
"policyAuthSsoDescription": "Kræv påloging gennem din organisations identitetsudbyder",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "Log-in URL",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Hver bruger har allerede en identitets-API-nøgle, du behøver kun at oprette virtuelle API-nøgler til ikke-brugerklienter eller delt adgang. Brugere kan hente deres nøgle ved at logge ind med deres identitetsudbyder på denne ressourcens URL, hvor den vil blive vist efter login.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Hver bruger har allerede en identitets-API-nøgle, du behøver kun at oprette virtuelle API-nøgler til ikke-brugerklienter eller delt adgang. Brugere henter deres nøgle her efter at have logget ind med deres identitetsudbyder.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} brugere, {roles} roller",
|
"policyAuthSsoSummary": "{idp} · {users} brugere, {roles} roller",
|
||||||
"policyAuthSsoDefaultIdp": "Standardudbyder",
|
"policyAuthSsoDefaultIdp": "Standardudbyder",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Tilføj standardidentitetsudbyder",
|
"policyAuthAddDefaultIdentityProvider": "Tilføj standardidentitetsudbyder",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Version",
|
"newtVersion": "Version",
|
||||||
"architecture": "Arkitektur",
|
"architecture": "Arkitektur",
|
||||||
"sites": "Websteder",
|
"sites": "Websteder",
|
||||||
"siteWgAnyClients": "Brug hvilken som helst WireGuard klient til at oprette forbindelse til. Du skal adressere interne ressourcer ved hjælp af peer IP.",
|
"siteWgAnyClients": "Brug enhver WireGuard-klient til at oprette forbindelse. Du skal adressere private ressourcer ved hjælp af peer IP.",
|
||||||
"siteWgCompatibleAllClients": "Kompatibel med alle WireGuard-klienter",
|
"siteWgCompatibleAllClients": "Kompatibel med alle WireGuard-klienter",
|
||||||
"siteWgManualConfigurationRequired": "Manuel konfiguration påkrævet",
|
"siteWgManualConfigurationRequired": "Manuel konfiguration påkrævet",
|
||||||
"userErrorNotAdminOrOwner": "Bruger er ikke administrator eller ejer",
|
"userErrorNotAdminOrOwner": "Bruger er ikke administrator eller ejer",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Ny rolle kræves",
|
"accessRoleErrorNewRequired": "Ny rolle kræves",
|
||||||
"accessRoleErrorRemove": "Kunne ikke fjerne rolle",
|
"accessRoleErrorRemove": "Kunne ikke fjerne rolle",
|
||||||
"accessRoleErrorRemoveDescription": "Det opstod en fejl under fjernelse af rollen.",
|
"accessRoleErrorRemoveDescription": "Det opstod en fejl under fjernelse af rollen.",
|
||||||
|
"accessRoleInferenceBudget": "AI-budget",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Konfigurer hvordan medlemmer af denne rolle begrænser AI-brug baseret på forbrug eller token-grænser",
|
||||||
"accessRoleName": "Rollenavn",
|
"accessRoleName": "Rollenavn",
|
||||||
"accessRoleQuestionRemove": "Du er ved at slette rollen `{name}`. Du kan ikke fortryde denne handling.",
|
"accessRoleQuestionRemove": "Du er ved at slette rollen `{name}`. Du kan ikke fortryde denne handling.",
|
||||||
"accessRoleRemove": "Fjern Rolle",
|
"accessRoleRemove": "Fjern Rolle",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Opret organisationsbruger",
|
"createOrgUser": "Opret organisationsbruger",
|
||||||
"actionUpdateOrg": "Opdater organisation",
|
"actionUpdateOrg": "Opdater organisation",
|
||||||
"actionRemoveInvitation": "Fjern invitation",
|
"actionRemoveInvitation": "Fjern invitation",
|
||||||
|
"actionRemoveUserRole": "Fjern Brugers Rolle",
|
||||||
"actionUpdateUser": "Opdater bruger",
|
"actionUpdateUser": "Opdater bruger",
|
||||||
"actionGetUser": "Hent bruger",
|
"actionGetUser": "Hent bruger",
|
||||||
"actionGetOrgUser": "Hent organisationsbruger",
|
"actionGetOrgUser": "Hent organisationsbruger",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Slet site",
|
"actionDeleteSite": "Slet site",
|
||||||
"actionGetSite": "Hent site",
|
"actionGetSite": "Hent site",
|
||||||
"actionListSites": "Vis sites",
|
"actionListSites": "Vis sites",
|
||||||
|
"actionCreateAiProvider": "Opret AI-udbyder",
|
||||||
|
"actionDeleteAiProvider": "Slet AI-udbyder",
|
||||||
|
"actionGetAiProvider": "Få AI-udbyder",
|
||||||
|
"actionListAiProviders": "Vis AI-udbydere",
|
||||||
|
"actionUpdateAiProvider": "Opdater AI-udbyder",
|
||||||
|
"actionCreateAiModel": "Opret AI-model",
|
||||||
|
"actionDeleteAiModel": "Slet AI-model",
|
||||||
|
"actionGetAiModel": "Hent AI-model",
|
||||||
|
"actionListAiModels": "Vis AI-modeller",
|
||||||
|
"actionUpdateAiModel": "Opdater AI-model",
|
||||||
|
"actionCreateAiBudget": "Opret AI Budget",
|
||||||
|
"actionDeleteAiBudget": "Slet AI Budget",
|
||||||
|
"actionGetAiBudget": "Hent AI-budget",
|
||||||
|
"actionListAiBudgets": "Vis AI Budgetter",
|
||||||
|
"actionUpdateAiBudget": "Opdater AI Budget",
|
||||||
|
"actionListResourceAiModels": "Vis Resource AI Modeller",
|
||||||
|
"actionSetResourceAiModels": "Angiv Resource AI Modeller",
|
||||||
|
"actionCreateVirtualApiKey": "Opret Virtuel API-nøgle",
|
||||||
|
"actionDeleteVirtualApiKey": "Slet Virtuel API-nøgle",
|
||||||
|
"actionGetVirtualApiKey": "Hent virtuel API-nøgle",
|
||||||
|
"actionListVirtualApiKeys": "Vis Virtuelle API-nøgler",
|
||||||
|
"actionUpdateVirtualApiKey": "Opdater Virtuel API-nøgle",
|
||||||
"actionApplyBlueprint": "Brug blueprint",
|
"actionApplyBlueprint": "Brug blueprint",
|
||||||
"actionListBlueprints": "Vis blueprints",
|
"actionListBlueprints": "Vis blueprints",
|
||||||
"actionGetBlueprint": "Hent blueprint",
|
"actionGetBlueprint": "Hent blueprint",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Indtast opsætningstoken fra serverkonsollen.",
|
"setupTokenDescription": "Indtast opsætningstoken fra serverkonsollen.",
|
||||||
"setupTokenRequired": "Opsætningstoken er nødvendig",
|
"setupTokenRequired": "Opsætningstoken er nødvendig",
|
||||||
"actionUpdateSite": "Opdater site",
|
"actionUpdateSite": "Opdater site",
|
||||||
|
"actionApproveSite": "Godkend Site",
|
||||||
|
"actionRejectSite": "Afvis Site",
|
||||||
"actionResetSiteBandwidth": "Nulstil organisationsbåndbredde",
|
"actionResetSiteBandwidth": "Nulstil organisationsbåndbredde",
|
||||||
"actionListSiteRoles": "Vis tilladte områderoller",
|
"actionListSiteRoles": "Vis tilladte områderoller",
|
||||||
"actionCreateResource": "Opret ressource",
|
"actionCreateResource": "Opret ressource",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Angiv ressource-PIN-kode",
|
"actionSetResourcePincode": "Angiv ressource-PIN-kode",
|
||||||
"actionSetResourceEmailWhitelist": "Angiv e-mailwhitelist for ressource",
|
"actionSetResourceEmailWhitelist": "Angiv e-mailwhitelist for ressource",
|
||||||
"actionGetResourceEmailWhitelist": "Hent e-mailwhitelist for ressource",
|
"actionGetResourceEmailWhitelist": "Hent e-mailwhitelist for ressource",
|
||||||
|
"actionListResourcePolicies": "Vis ressourcepolitikker",
|
||||||
|
"actionCreateResourcePolicy": "Opret ressourcepolitik",
|
||||||
"actionGetResourcePolicy": "Få ressourceretningslinjen",
|
"actionGetResourcePolicy": "Få ressourceretningslinjen",
|
||||||
"actionUpdateResourcePolicy": "Opdater ressourceretningslinjen",
|
"actionUpdateResourcePolicy": "Opdater ressourceretningslinjen",
|
||||||
|
"actionDeleteResourcePolicy": "Slet ressourcepolitik",
|
||||||
"actionSetResourcePolicyUsers": "Angiv ressourceretningslinjens brugere",
|
"actionSetResourcePolicyUsers": "Angiv ressourceretningslinjens brugere",
|
||||||
"actionSetResourcePolicyRoles": "Angiv ressourceretningslinjens roller",
|
"actionSetResourcePolicyRoles": "Angiv ressourceretningslinjens roller",
|
||||||
"actionSetResourcePolicyPassword": "Angiv ressourceretningslinjen for adgangskode",
|
"actionSetResourcePolicyPassword": "Angiv ressourceretningslinjen for adgangskode",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Vis invitationer",
|
"actionListInvitations": "Vis invitationer",
|
||||||
"actionExportLogs": "Eksportér logs",
|
"actionExportLogs": "Eksportér logs",
|
||||||
"actionViewLogs": "Vis logs",
|
"actionViewLogs": "Vis logs",
|
||||||
|
"actionCreateSiteProvisioningKey": "Opret provisioneringsnøgle til site",
|
||||||
|
"actionListSiteProvisioningKeys": "Vis provisioneringsnøgler til site",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Opdater provisioneringsnøgle til site",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Slet provisioneringsnøgle til site",
|
||||||
"noneSelected": "Ingen valgt",
|
"noneSelected": "Ingen valgt",
|
||||||
"orgNotFound2": "Ingen organisationer fundet.",
|
"orgNotFound2": "Ingen organisationer fundet.",
|
||||||
"search": "Søg…",
|
"search": "Søg…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Indtast koden fra autentiseringsappen din eller en af dine engangs reservekoder.",
|
"otpAuthDescription": "Indtast koden fra autentiseringsappen din eller en af dine engangs reservekoder.",
|
||||||
"otpAuthSubmit": "Send kode",
|
"otpAuthSubmit": "Send kode",
|
||||||
"idpContinue": "Eller fortsæt med",
|
"idpContinue": "Eller fortsæt med",
|
||||||
|
"idpLastUsed": "Sidst brugt",
|
||||||
"otpAuthBack": "Tilbage til adgangskode",
|
"otpAuthBack": "Tilbage til adgangskode",
|
||||||
"navbar": "Navigationsmenu",
|
"navbar": "Navigationsmenu",
|
||||||
"navbarDescription": "Hovednavigasjonsmeny for applikationen",
|
"navbarDescription": "Hovednavigasjonsmeny for applikationen",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Opret maskinklient",
|
"commandPaletteCreateMachineClient": "Opret maskinklient",
|
||||||
"commandPaletteCreateAlertRule": "Opret varslingsregel",
|
"commandPaletteCreateAlertRule": "Opret varslingsregel",
|
||||||
"commandPaletteCreateIdentityProvider": "Opret identitetsudbyder",
|
"commandPaletteCreateIdentityProvider": "Opret identitetsudbyder",
|
||||||
|
"commandPaletteCreateAiProvider": "Opret AI-udbyder",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Opret Virtuel API-nøgle",
|
||||||
"commandPaletteToggleTheme": "Skift tema",
|
"commandPaletteToggleTheme": "Skift tema",
|
||||||
"commandPaletteChooseOrganization": "Vælg organisation",
|
"commandPaletteChooseOrganization": "Vælg organisation",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Invitationer",
|
"sidebarInvitations": "Invitationer",
|
||||||
"sidebarRoles": "Roller",
|
"sidebarRoles": "Roller",
|
||||||
"sidebarShareableLinks": "Delbare links",
|
"sidebarShareableLinks": "Delbare links",
|
||||||
|
"sidebarAiGateway": "AI-gateway",
|
||||||
|
"sidebarAiProviders": "Udbydere",
|
||||||
|
"commandAiProviders": "AI-udbydere",
|
||||||
|
"sidebarVirtualApiKeys": "Virtuelle API-nøgler",
|
||||||
|
"sidebarMyApiKeys": "Dine API-nøgler",
|
||||||
|
"sidebarAccount": "Startprogram",
|
||||||
|
"commandVirtualApiKeys": "Virtuelle API-nøgler",
|
||||||
|
"virtualApiKeysTitle": "Administrer Virtuelle API-nøgler",
|
||||||
|
"virtualApiKeysDescription": "Opret og administrer manuelle API-nøgler til adgang til AI Gateway for offentlige AI-gateways",
|
||||||
|
"virtualApiKeysTabIdentity": "Identitetsnøgler",
|
||||||
|
"virtualApiKeysTabVirtual": "Virtuelle nøgler",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Identitetsnøgler for hver bruger",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Hver bruger har allerede en Pangolin-identitetsnøgle til denne organisation. Den er unik for deres konto og autentificerer dem til AI-gateways, de kan få adgang til.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Eksempel",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Sådan får brugere deres nøgle",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Besøg en offentlig AI-gateway URL i browseren og log ind med deres konto.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Eller gå til <url></url> mens du er logget ind.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Du kan oprette yderligere virtuelle API-nøgler på Virtuelle nøgler fanen. Disse nøgler kan være omfangsbegrænsede til specifikke offentlige AI-gateways og valgfrit være forbundet med en bruger. Oprettelse af en nøgle giver straks adgang til de valgte offentlige AI-gateways.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Opret en nøgle manuelt",
|
||||||
|
"virtualApiKeysEmailIdentity": "E-maile Identitetsnøgler",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Send hver udvalgt bruger eller rolle deres Pangolin-identitetsnøgle.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Send til alle brugere",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "E-maile hvert organisationmedlem, der har en konto-e-mail.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Brugere",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Roller",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Send e-mails",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Identitetsnøgler er sendt",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Sendte {sent} e-mails.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} brugere blev sprunget over, fordi de ikke har en e-mail adresse.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Vælg mindst en bruger eller rolle, eller send til alle brugere.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Fejl ved sending af identitetsnøgler",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Kunne ikke e-maile identitetsnøgler",
|
||||||
|
"virtualApiKeysBannerTitle": "Identitetsnøgler til hver bruger",
|
||||||
|
"virtualApiKeysBannerDescription": "Hver bruger har allerede en identitetsnøgle tilgængelig på {keysUrl}. Du kan også manuelt generere nøgler her, der giver direkte adgang til offentlige AI-gateways.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Vis Identitetsnøgler",
|
||||||
|
"virtualApiKeys": "Virtuelle API-nøgler",
|
||||||
|
"virtualApiKeysSearch": "Søg nøgler...",
|
||||||
|
"virtualApiKeysCreate": "Opret Virtuel API-nøgle",
|
||||||
|
"virtualApiKeysCreateDescription": "Opret en manuel nøgle, der kan kalde offentlige AI-gateways i denne organisation",
|
||||||
|
"virtualApiKeysCreateButton": "Opret nøgle",
|
||||||
|
"virtualApiKeysEmpty": "Ingen Virtuelle API-nøgler endnu",
|
||||||
|
"virtualApiKeysName": "Navn",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Beskrivelse (valgfri)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Associer Bruger (valgfri)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Associer denne nøgle med en bruger for at spore brugen. Når denne nøgle er oprettet, giver den straks adgang til de valgte offentlige AI-gateways. Du behøver ikke associere en bruger manuelt til ressourcen. Nøglen vil også blive vist i brugerens profil.",
|
||||||
|
"virtualApiKeysAllResources": "Alle offentlige AI-gateways",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Tillad denne nøgle at få adgang til hver offentlig AI-gateway i organisationen",
|
||||||
|
"virtualApiKeysSelectResources": "Offentlige AI Gateways",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Vælg ressourcer",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Vælg hvilke offentlige AI-gateways denne nøgle kan få adgang til",
|
||||||
|
"virtualApiKeysNoResources": "Ingen ressourcer",
|
||||||
|
"virtualApiKeysSecret": "Nøgle",
|
||||||
|
"virtualApiKeysCopyKey": "Kopier denne nøgle. Du kan se den senere igen fra tabellen eller når du redigerer.",
|
||||||
|
"virtualApiKeysViewSecret": "Vis hemmelighed",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Virtuel API Nøglehemmelighed",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Denne hemmelighed giver adgang til de offentlige AI-gateways til denne nøgle",
|
||||||
|
"virtualApiKeysEdit": "Rediger Virtuel API-nøgle",
|
||||||
|
"virtualApiKeysEditDescription": "Opdater den associerede bruger og offentlige AI-gateway adgang for denne nøgle",
|
||||||
|
"virtualApiKeysSaveButton": "Gem ændringer",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Vælg mindst en offentlig AI-gateway, eller aktiver alle offentlige AI-gateways",
|
||||||
|
"virtualApiKeysUpdated": "Virtuel API nøgle opdateret",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Den Virtuelle API nøgle er blevet opdateret",
|
||||||
|
"virtualApiKeysErrorUpdate": "Fejl ved opdatering af virtuel API nøgle",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Kunne ikke opdatere virtuel API nøgle",
|
||||||
|
"virtualApiKeysErrorCreate": "Fejl ved oprettelse af virtuel API nøgle",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Kunne ikke oprette virtuel API nøgle",
|
||||||
|
"virtualApiKeysErrorDelete": "Fejl ved sletning af virtuel API nøgle",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Kunne ikke slette virtuel API nøgle",
|
||||||
|
"virtualApiKeysDeleted": "Virtuel API nøgle slettet",
|
||||||
|
"virtualApiKeysDeletedDescription": "Den Virtuelle API nøgle er blevet slettet",
|
||||||
|
"virtualApiKeysDelete": "Slet Virtuel API-nøgle",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Slet nøgle",
|
||||||
|
"virtualApiKeysQuestionRemove": "Er du sikker på, at du vil slette denne virtuelle API-nøgle?",
|
||||||
|
"virtualApiKeysMessageRemove": "Klienter, der bruger denne nøgle, vil miste adgang med det samme.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Fejl ved indlæsning af hemmelighed",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Kunne ikke indlæse den virtuelle API nøglehemmelighed",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Ikke tildelt",
|
||||||
|
"virtualApiKeysInferenceBudget": "Budget",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Konfigurer hvordan denne nøgle begrænser AI-brug baseret på forbrug eller token-grænser",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Email nøgle ved generering",
|
||||||
|
"virtualApiKeysEmailThisKey": "Email denne nøgle",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Send nøglen til den associerede bruger og yderligere adresser efter oprettelsen",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Send den aktuelle nøgle til den associerede bruger og yderligere adresser",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "Email er ikke konfigureret på denne server",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Konfigurer SMTP for at emaile Virtuelle API-nøgler.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Send til associeret bruger",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Email nøglen til den associerede brugers konto-email",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Associer en bruger for at sende nøglen til den bruger",
|
||||||
|
"virtualApiKeysEmailAdditional": "Yderligere e-mails",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Tilføj email og tryk Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Vælg den associerede bruger eller tilføj mindst én email-adresse",
|
||||||
|
"myVirtualApiKeysTitle": "Dine API-nøgler",
|
||||||
|
"myVirtualApiKeysDescription": "Se din identitetsnøgle og eventuelle Virtuelle API-nøgler tilskrevet dig i denne organisation",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Dine API-nøgler til {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Se din identitetsnøgle og Virtuelle API-nøgler tilskrevet dig, der kan få adgang til {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Identitetsnøgle",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Din Personlige API Nøgle",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Din personlige nøgle til denne organisation. Den er unik for din konto og bruges til at identificere dig ved kald til AI Gateway ressourcer.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Din Personlige API Nøgle til {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Din personlige nøgle til denne organisation. Brug den til at kalde {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Tildelte Nøgler",
|
||||||
|
"myVirtualApiKeysManualDescription": "Manuelle Virtuelle API-nøgler, en admin har tilknyttet din konto",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Manuelle Virtuelle API-nøgler tilknyttet din konto, der kan få adgang til {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Ingen tildelte nøgler endnu",
|
||||||
|
"myVirtualApiKeysKindUser": "Identitet",
|
||||||
|
"myVirtualApiKeysKindManual": "Manuel",
|
||||||
|
"myVirtualApiKeysUnnamed": "Navnløs nøgle",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Vis hemmelighed",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Denne hemmelighed autentificerer dig til AI Gateway ressourcer",
|
||||||
|
"aiClientConfigTitle": "Konfigurer Kodningsagenter",
|
||||||
|
"aiClientConfigDescription": "Kopiér konfiguration for populære kodningsagenter, eller lad Pangolin CLI opsætte det automatisk for dig.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Anthropics agentikodningsværktøj til terminalen.",
|
||||||
|
"aiClientConfigDescriptionCodex": "OpenAIs agentikodningsværktøj til terminalen.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Open source terminal kodningsagent.",
|
||||||
|
"aiClientConfigDescriptionCursor": "AI-kodeeditor bygget på VS Code.",
|
||||||
|
"aiClientConfigSetup": "Opsætning",
|
||||||
|
"aiClientConfigTabCli": "Automatisk (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Manuel Konfiguration",
|
||||||
|
"aiClientConfigPreset": "Konfiguration",
|
||||||
|
"aiClientConfigStep": "Trin {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Dette udsnit indeholder eksempelværdier, såsom et modelnavn eller en ressource-URL. Udskift dem med dine egne, før du bruger det.",
|
||||||
|
"aiClientConfigRevealError": "Kunne ikke indlæse din API-nøgle.",
|
||||||
|
"aiClientConfigRevealRetry": "Prøv igen",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Denne ressource kan bruges fra almindelige klienter som Claude Code og OpenCode. <configLink>Lær mere</configLink>",
|
||||||
|
"aiProvidersTitle": "AI-udbydere",
|
||||||
|
"aiProvidersDescription": "Forbind modeludbydere til AI-arbejdsopgaver i denne organisation",
|
||||||
|
"aiProvidersBannerTitle": "Forbind Modeludbydere",
|
||||||
|
"aiProvidersBannerDescription": "Udbydere er de moduler, Pangolin bruger til AI-arbejdsopgaver. Forbind OpenAI, Anthropic, og andre udbydere her, og tilknyt dem derefter til offentlige AI-gateways, så brugere kan tilkalde modeller med identitetsbevidst adgang, budgetter, og logning.",
|
||||||
|
"aiProvidersAdd": "Tilføj Udbyder",
|
||||||
|
"aiProvidersSearch": "Søg udbydere...",
|
||||||
|
"aiProvidersEmpty": "Ingen AI-udbydere endnu",
|
||||||
|
"aiProviderCreate": "Opret AI-udbyder",
|
||||||
|
"aiProviderCreateDescription": "Tilføj en modeludbyder for denne organisation",
|
||||||
|
"aiProviderSeeAll": "Se Alle Udbydere",
|
||||||
|
"aiProviderSetting": "Udbyderindstillinger for {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Konfigurer denne AI-udbyder",
|
||||||
|
"aiProviderGeneral": "Generelt",
|
||||||
|
"aiProviderGeneralDescription": "Basisindstillinger for denne udbyder",
|
||||||
|
"aiProviderConfiguration": "Konfiguration",
|
||||||
|
"aiProviderConfigurationDescription": "Netværksrouting og autentificering for denne udbyder",
|
||||||
|
"aiProviderNetworkSettings": "Netværksindstillinger",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Vælg hvordan trafik når denne udbyder",
|
||||||
|
"aiProviderAuthSettings": "Autentificering",
|
||||||
|
"aiProviderAuthSettingsDescription": "Konfigurer hvordan denne udbyder autentificerer anmodninger til sin upstream URL",
|
||||||
|
"aiProviderBudgetSettings": "Budget",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Konfigurer hvordan denne udbyder begrænser brug baseret på forbrug eller token-grænser",
|
||||||
|
"aiBudgetAdd": "Tilføj Budget",
|
||||||
|
"aiBudgetEmpty": "Ingen budgetter konfigureret endnu. Klik på Tilføj Budget for at angive et forbrugs- eller tokengränse.",
|
||||||
|
"aiBudgetUnit": "Forbrugstype",
|
||||||
|
"aiBudgetPeriod": "Nulstil periode",
|
||||||
|
"aiBudgetAmount": "Maksimalt Forbrug",
|
||||||
|
"aiBudgetAmountPlaceholder": "Maksimalt forbrug",
|
||||||
|
"aiBudgetPeriodHourly": "Timelig",
|
||||||
|
"aiBudgetPeriodDaily": "Daglig",
|
||||||
|
"aiBudgetPeriodWeekly": "Ugentlig",
|
||||||
|
"aiBudgetPeriodMonthly": "Månedlig",
|
||||||
|
"aiBudgetPeriodYearly": "Årlig",
|
||||||
|
"aiBudgetPeriodLifetime": "Livstid",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Tokens",
|
||||||
|
"aiBudgetConflictError": "Et budget for denne nulstillingsperiode og forbrugstype eksisterer allerede",
|
||||||
|
"aiBudgetInvalidAmountError": "Indtast et maksimalt forbrug større end 0",
|
||||||
|
"aiBudgetUpdated": "Budgetter opdateret",
|
||||||
|
"aiBudgetErrorSave": "Kunne ikke opdatere budgetter",
|
||||||
|
"aiProviderType": "Udbydertype",
|
||||||
|
"aiProviderTypeSearch": "Søg udbydere...",
|
||||||
|
"aiProviderTypeNotFound": "Ingen udbydertype fundet",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI-gateway",
|
||||||
|
"aiProviderTypeCustom": "Brugerdefineret",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Runtime API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI-gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "Brug din egen endpoint eller ruter via stedmål",
|
||||||
|
"aiProviderUpstreamUrl": "Opstrøms URL",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Basis-URL for udbyderens API",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Lad være tom for at bruge den standard opstrøms URL for denne udbyder",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Effektiv opstrøms URL",
|
||||||
|
"aiProviderApiKey": "API-nøgle",
|
||||||
|
"aiProviderApiKeyDescription": "API-nøgle bruges til at godkende forespørgsler til denne udbyder",
|
||||||
|
"aiProviderCustomHeadersDescription": "Headers sendt ved hver forespørgsel til denne udbyder. Newline adskilt: Header-Name: værdi",
|
||||||
|
"aiProviderApiKeyLastChars": "API-nøgle",
|
||||||
|
"aiProviderAuthType": "Godkendelsestype",
|
||||||
|
"aiProviderAuthTypeSearch": "Søg godkendelsestyper...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Ingen godkendelsestype fundet",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Autorisation: Bearer nøgle. Bruges af OpenAI og de fleste udbydere",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-nøgle",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-nøgle header. Bruges af Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-nøgle",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-nøgle header. Bruges af Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Autorisation: Splunk nøgle. Bruges af Splunk HTTP Event Collector",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-autorisation: Bearer nøgle. Bruges af Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeNone": "Ingen godkendelse",
|
||||||
|
"aiProviderAuthTypePassthrough": "Gennemsigtighed",
|
||||||
|
"aiProviderAuthTypeDescription": "Hvordan opstrøms API godkender forespørgsler",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Send opkalderens API-nøgle headers til det opstrøms link",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Send ikke godkendelsesheadere til det opstrøms link",
|
||||||
|
"aiProviderRoutingMode": "Routeringsmodus",
|
||||||
|
"aiProviderRoutingModeDescription": "Send trafik til en opstrøms URL eller til HTTP mål på dine steder",
|
||||||
|
"aiProviderRoutingModeUrl": "Opstrøms URL",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Kald en offentlig eller privat API basis-URL",
|
||||||
|
"aiProviderRoutingModeTarget": "Stedmål",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Rute gennem mål på dine steder",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Efter oprettelse af denne udbyder, konfigurer mål på Netværksindstillinger fanen.",
|
||||||
|
"aiProviderTargetNoOne": "Denne udbyder har ingen mål. Tilføj et mål for at rute forespørgsler gennem dine steder.",
|
||||||
|
"aiProviderSkipTlsVerification": "Spring TLS-verifikation over",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Deaktiver TLS-certifikat verifikation for opstrømsforbindelsen",
|
||||||
|
"aiProviderBudget": "Budget",
|
||||||
|
"aiProviderBudgetDescription": "Valgfrit udgifts- eller token budget for denne udbyder",
|
||||||
|
"aiProviderBudgetAmount": "Budgetbeløb",
|
||||||
|
"aiProviderBudgetUnit": "Budgetenhed",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Tokens",
|
||||||
|
"aiProviderEnabled": "Aktiveret",
|
||||||
|
"aiProviderEnabledDescription": "Deaktiver helt denne udbyder på tværs af alle ressourcer",
|
||||||
|
"aiProviderErrorCreate": "Kunne ikke oprette AI-udbyder",
|
||||||
|
"aiProviderErrorUpdate": "Kunne ikke opdatere AI-udbyder",
|
||||||
|
"aiProviderErrorDelete": "Kunne ikke slette AI-udbyder",
|
||||||
|
"aiProviderErrorLoad": "Kunne ikke indlæse AI-udbyder",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Indtast en gyldig opstrøms URL",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Opstrøms URL er påkrævet for denne udbyder",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Godkendelsestype er påkrævet",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API-nøgle er påkrævet",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Rute til stedmål er kun tilgængelig for brugerdefinerede udbydere",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Vælg mindst en API-kapabilitet",
|
||||||
|
"aiProviderCapabilities": "API-funktioner",
|
||||||
|
"aiProviderCapabilitiesDescription": "Vælg hvilke API-formater denne udbyder kan håndtere. Kendte udbydere starter med anbefalede standarder.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Vælg hvilke API-formater denne specialudbyder kan håndtere",
|
||||||
|
"aiProviderCapabilitiesSelect": "Vælg funktioner",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Ingen funktioner fundet",
|
||||||
|
"aiProviderCapabilitiesSearch": "Søg funktioner...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Chat Kompletteringer",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Understøtter /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI Svar",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Understøtter /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic Beskeder",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Understøtter /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini Generer Indhold",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Understøtter den direkte Gemini API",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Bedrock Modeller Invoker",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Understøtter Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex Generer Indhold",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Understøtter Vertex AI Gemini format",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex Rå Forudsigelse",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Understøtter Vertex AI rawPredict for Anthropic-modeller",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock Samtale",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Understøtter Amazon Bedrock Converse API",
|
||||||
|
"aiProviderCreated": "AI-udbyder oprettet",
|
||||||
|
"aiProviderUpdated": "AI-udbyder opdateret",
|
||||||
|
"aiProviderDeleted": "AI-udbyder slettet",
|
||||||
|
"aiProviderDelete": "Slet udbyder",
|
||||||
|
"aiProviderDeleteConfirm": "Slet udbyder",
|
||||||
|
"aiProviderQuestionRemove": "Er du sikker på, at du vil slette denne AI-udbyder?",
|
||||||
|
"aiProviderMessageRemove": "Dette vil permanent slette udbyderen og dens modeller og mål. Dette kan ikke fortrydes.",
|
||||||
|
"aiProviderErrorNoUpdate": "AI-udbyder er ikke tilgængelig til opdatering",
|
||||||
|
"aiProviderModels": "Modeller",
|
||||||
|
"aiProviderModelsDescription": "Definer tillad og blokér lister for denne udbyder. Forespørgsler skal matche en tillad post og må ikke matche en blokér post.",
|
||||||
|
"aiProviderCreateModelsDescription": "Vælg hvilke modeller denne udbyder kan betjene. En tom tillad-liste nægter al trafik. Du kan tilføje eller ændre modeller senere.",
|
||||||
|
"aiProviderModelsPlaceholder": "Søg modeller eller skriv en brugerdefineret nøgle",
|
||||||
|
"aiProviderModelsAllow": "Tillad Liste",
|
||||||
|
"aiProviderModelsAllowDescription": "Modeller, der kan bruges gennem denne udbyder. Tom betyder, at alt afvises.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Indtast modelnøgle",
|
||||||
|
"aiProviderModelsAllowEmpty": "Ingen modeller tilføjet endnu.",
|
||||||
|
"aiProviderModelsBlock": "Blokér Liste",
|
||||||
|
"aiProviderModelsBlockDescription": "Modeller at afvise, selvom de matcher en tillad post.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Indtast modelnøgle",
|
||||||
|
"aiProviderModelsBlockEmpty": "Ingen modeller tilføjet endnu.",
|
||||||
|
"aiProviderModelsAdd": "Tilføj Modeller",
|
||||||
|
"aiProviderModelsClearAll": "Ryd All",
|
||||||
|
"aiProviderModelsAddCustom": "Tilføj \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Tryk på Enter for at tilføje denne brugerdefinerede modelnøgle.",
|
||||||
|
"aiProviderModelsAddBulk": "Tilføj {count} brugerdefinerede nøgler",
|
||||||
|
"aiProviderModelsAddBulkHint": "Tryk på Enter for at tilføje {count} brugerdefinerede nøgler.",
|
||||||
|
"aiProviderModelsAddOne": "Tilføj {key} nu",
|
||||||
|
"aiProviderModelsAddSelected": "Tilføj Valgte",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} valgt",
|
||||||
|
"aiProviderModelsSelectAll": "Vælg alle",
|
||||||
|
"aiProviderModelsClearSelected": "Ryd",
|
||||||
|
"aiProviderModelsBulkHint": "Vælg kendte modeller eller skriv en brugerdefineret nøgle.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Ingen matchende katalogmodeller.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Kendte Modeller",
|
||||||
|
"aiProviderModelsAllLabel": "Alle modeller",
|
||||||
|
"aiProviderModelsAllPatternHint": "Wildcard: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Tillad alle modeller",
|
||||||
|
"aiProviderModelsAddAllBlock": "Blokér alle modeller",
|
||||||
|
"aiProviderModelsAddAllDescription": "Bruger * wildcard så hver modelnøgle matcher.",
|
||||||
|
"aiProviderModelsViewMore": "Se mere ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Se mindre",
|
||||||
|
"aiProviderModelsRemove": "Fjern model",
|
||||||
|
"aiProviderModelsEditHint": "Klik for at redigere modelindstillinger",
|
||||||
|
"aiProviderModelsSourceCatalog": "Kendt katalog model",
|
||||||
|
"aiProviderModelsSourceCustom": "Brugerdefineret modelnøgle",
|
||||||
|
"aiProviderModelsSourcePattern": "Wildcard mønster",
|
||||||
|
"aiProviderModelsSourceAll": "Matcher hver modelnøgle",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Budget konfigureret",
|
||||||
|
"aiProviderModelsEditTitle": "Rediger Model",
|
||||||
|
"aiProviderModelsEditDescription": "Opdater modellenøgle eller konfigurer dens budget.",
|
||||||
|
"aiProviderModelsBudgetTab": "Budget",
|
||||||
|
"aiProviderModelsKeyLabel": "Modelnøgle",
|
||||||
|
"aiProviderModelsKeyRequired": "Indtast en modelnøgle",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Denne modelnøgle er allerede på en liste",
|
||||||
|
"aiProviderModelsOverlapError": "Disse mønstre kan ikke være på begge lister: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modeller opdateret",
|
||||||
|
"aiProviderModelsErrorUpdate": "Kunne ikke opdatere modeller",
|
||||||
|
"aiResourceProviders": "Udbydere",
|
||||||
|
"aiResourceProvidersDescription": "Vælg hvilke AI-udbydere denne AI-gateway kan bruge",
|
||||||
|
"aiResourceProvidersHelp": "Vedhæft udbydere og vælg arv (brug hver udbyders lister) eller vælg (vælg en tillad liste for denne ressource). Tillad mønstre, der er i konflikt på tværs af vedhæftede udbydere er ikke tilladt.",
|
||||||
|
"aiResourceProvidersSelect": "Vælg udbydere",
|
||||||
|
"aiResourceProvidersEmpty": "Ingen AI-udbydere fundet",
|
||||||
|
"aiResourceProvidersNoneAttached": "Ingen udbydere tilknyttet endnu.",
|
||||||
|
"aiResourceProvidersAdd": "Tilføj udbyder",
|
||||||
|
"aiResourceProvidersRemove": "Fjern udbyder",
|
||||||
|
"aiResourceProviderToggleEnabled": "Aktivér eller deaktiver denne udbyder på ressourcen",
|
||||||
|
"aiResourceProviderDisabled": "Deaktiveret",
|
||||||
|
"aiResourceProvidersUpdated": "Udbydere opdateret",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Kunne ikke opdatere udbydere",
|
||||||
|
"aiResourceProviderEditDescription": "Vælg, hvordan denne udbyders modeller vises på denne ressource.",
|
||||||
|
"viewProviderSettings": "Se Udbyderindstillinger",
|
||||||
|
"aiResourceProviderMode": "Adgangsmodus",
|
||||||
|
"aiResourceProviderModeInherit": "Arv",
|
||||||
|
"aiResourceProviderModeSelect": "Vælg",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Vælg · {count} modeller",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Brug denne udbyders tillad- og blokér lister som konfigureret på udbyderen.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Vælg et underindstillet af denne udbyders tillad liste modeller til denne ressource.",
|
||||||
|
"aiResourceProviderAllowModels": "Tillad liste",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Vælg modeller",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Søg modeller...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Ingen modeller fundet",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Kun modeller fra denne udbyders tillad-liste kan vælges.",
|
||||||
|
"aiResourceAliasRequired": "Alias kræves for AI-gateways",
|
||||||
|
"aiResourceDomainConfiguration": "Domænekonfiguration",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Vælg det domæne, klienter vil bruge for at nå denne AI-gateway.",
|
||||||
|
"aiUsageAnalyticsTitle": "AI Brug Analyse",
|
||||||
|
"aiUsageAnalyticsDescription": "Analyser AI-gateway omkostninger, token forbrug, og aktivitet på tværs af udbydere, ressourcer, roller og brugere",
|
||||||
|
"aiUsageTabOverview": "Oversigt",
|
||||||
|
"aiUsageTabProviders": "Udbydere",
|
||||||
|
"aiUsageTabResources": "Ressourcer",
|
||||||
|
"aiUsageFilterProvider": "Udbyder",
|
||||||
|
"aiUsageFilterModel": "Model",
|
||||||
|
"aiUsageFilterResource": "Ressource",
|
||||||
|
"aiUsageFilterRole": "Rolle",
|
||||||
|
"aiUsageFilterUser": "Bruger",
|
||||||
|
"aiUsageFilterAllProviders": "Alle Udbydere",
|
||||||
|
"aiUsageFilterAllModels": "Alle Modeller",
|
||||||
|
"aiUsageFilterAllResources": "Alle Ressourcer",
|
||||||
|
"aiUsageFilterAllRoles": "Alle Roller",
|
||||||
|
"aiUsageFilterAllUsers": "Alle Brugere",
|
||||||
|
"aiUsageFilterSearch": "Søg...",
|
||||||
|
"aiUsageFilterNotFound": "Ingen valg fundet",
|
||||||
|
"aiUsageResetFilters": "Nulstil Filtre",
|
||||||
|
"aiUsageRefresh": "Opdater",
|
||||||
|
"aiUsageTokenTypePrompt": "Prompt",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Cache læs",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Cache skriv",
|
||||||
|
"aiUsageTokenTypeCompletion": "Komplettering",
|
||||||
|
"aiUsageTokenTypeReasoning": "Begrundelse",
|
||||||
|
"aiUsageRequests": "Forespørgsler",
|
||||||
|
"aiUsageCost": "Omkostning",
|
||||||
|
"aiUsageTokens": "Tokens",
|
||||||
|
"aiUsageOther": "Andet",
|
||||||
|
"aiUsageTotalRequests": "Total Forespørgsler",
|
||||||
|
"aiUsageTotalTokens": "Samlede tokens",
|
||||||
|
"aiUsageTotalCost": "Total Omkostning",
|
||||||
|
"aiUsageEstimated": "Estimeret",
|
||||||
|
"aiUsageRequestVolume": "Forespørgselsvolumen",
|
||||||
|
"aiUsageTokenUsage": "Token Forbrug",
|
||||||
|
"aiUsageModelCost": "Model Omkostning",
|
||||||
|
"aiUsageModelTokens": "Model tokens",
|
||||||
|
"aiUsageTopModels": "Top Modeller",
|
||||||
|
"aiUsageTopProviders": "Top Udbydere",
|
||||||
|
"aiUsageProviderCost": "Udbyder Omkostning",
|
||||||
|
"aiUsageProviderTokenUsage": "Udbyder Token Forbrug",
|
||||||
|
"aiUsageTopResources": "Top Ressourcer",
|
||||||
|
"aiUsageResourceCost": "Ressource Omkostning",
|
||||||
|
"aiUsageResourceTokenUsage": "Ressource Token Forbrug",
|
||||||
|
"aiUsageResourceTypePublic": "Offentlig Ressource",
|
||||||
|
"aiUsageResourceTypeSite": "Privat Ressource",
|
||||||
|
"aiUsageNoResource": "Ingen ressource",
|
||||||
|
"aiUsageRolesTab": "Roller",
|
||||||
|
"aiUsageUsersTab": "Brugere",
|
||||||
|
"aiUsageTopRoles": "Top Roller",
|
||||||
|
"aiUsageRoleCost": "Rolle Omkostning",
|
||||||
|
"aiUsageRoleTokenUsage": "Rolle Token Forbrug",
|
||||||
|
"aiUsageTopUsers": "Top Brugere",
|
||||||
|
"aiUsageUserCost": "Bruger Omkostning",
|
||||||
|
"aiUsageUserTokenUsage": "Bruger Token Forbrug",
|
||||||
|
"aiUsageUnknownUser": "Ukendt bruger",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Virtuelle API Nøgler",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Virtuel API Nøgle",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Alle Virtuelle API Nøgler",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Top Virtuelle API Nøgler",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Virtuel API Nøgle Omkostning",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Virtuel API Nøgle Token Forbrug",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Ingen virtuel API nøgle",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Unavngiven nøgle",
|
||||||
|
"aiUsageLoading": "Indlæser...",
|
||||||
|
"aiUsageNoData": "Ingen data",
|
||||||
|
"resourceBudgetSettings": "Budget",
|
||||||
|
"resourceBudgetSettingsDescription": "Konfigurer, hvordan denne AI-gateway begrænser brug baseret på udgifts- eller token-grænser",
|
||||||
"sidebarApiKeys": "API-nøgler",
|
"sidebarApiKeys": "API-nøgler",
|
||||||
"sidebarProvisioning": "Provisionering",
|
"sidebarProvisioning": "Provisionering",
|
||||||
"sidebarSettings": "Indstillinger",
|
"sidebarSettings": "Indstillinger",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Varslingsregel gemt",
|
"alertingRuleSaved": "Varslingsregel gemt",
|
||||||
"alertingRuleSavedCreatedDescription": "Din nye varslingsregel blev oprettet. Du kan fortsætte at redigere den på denne side.",
|
"alertingRuleSavedCreatedDescription": "Din nye varslingsregel blev oprettet. Du kan fortsætte at redigere den på denne side.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Dine ændringer i denne varslingsreglen blev gemt.",
|
"alertingRuleSavedUpdatedDescription": "Dine ændringer i denne varslingsreglen blev gemt.",
|
||||||
|
"alertingTestAlertSent": "Test-alarm sendt",
|
||||||
|
"alertingTestAlertSentDescription": "En testalarm blev sendt til de handlinger, der er konfigureret på denne regel.",
|
||||||
"alertingEditRule": "Rediger varslingsregel",
|
"alertingEditRule": "Rediger varslingsregel",
|
||||||
"alertingCreateRule": "Opret varslingsregel",
|
"alertingCreateRule": "Opret varslingsregel",
|
||||||
"alertingRuleCredenzaDescription": "Vælg hvad som skal overvåges, når det skal varsles, og hvordan du vil blive informert",
|
"alertingRuleCredenzaDescription": "Vælg hvad som skal overvåges, når det skal varsles, og hvordan du vil blive informert",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Hver regel binder sammen hvad som skal overvåges (et site, sundhedstjek eller ressource), når det skal varsles (for eksempel offline eller usund), og hvordan varsle teamet dit via e-mail, webhooks eller integrationer. Brug denne listen for at oprette, aktivere og administrer disse reglerne.",
|
"alertingRulesBannerDescription": "Hver regel binder sammen hvad som skal overvåges (et site, sundhedstjek eller ressource), når det skal varsles (for eksempel offline eller usund), og hvordan varsle teamet dit via e-mail, webhooks eller integrationer. Brug denne listen for at oprette, aktivere og administrer disse reglerne.",
|
||||||
"alertingHealthChecksBannerTitle": "Overvåg sundhed & ressourcer",
|
"alertingHealthChecksBannerTitle": "Overvåg sundhed & ressourcer",
|
||||||
"alertingHealthChecksBannerDescription": "Sundhedstjek er HTTP- eller TCP-monitorer, du definerer én gang. Du kan derefter bruge dem som kilder i varslingsregler, så du bliver varslet, når et mål bliver sundt eller usundt. Sundhedstjek på ressourcer vises også her.",
|
"alertingHealthChecksBannerDescription": "Sundhedstjek er HTTP- eller TCP-monitorer, du definerer én gang. Du kan derefter bruge dem som kilder i varslingsregler, så du bliver varslet, når et mål bliver sundt eller usundt. Sundhedstjek på ressourcer vises også her.",
|
||||||
|
"alertingTestRule": "Test Alarmregel",
|
||||||
|
"alertingAddActionHeading": "Tilføj Ny Handling",
|
||||||
|
"alertingSelectActionType": "Vælg en Handling",
|
||||||
|
"alertingNoActionsTitle": "Ingen handlinger konfigureret",
|
||||||
|
"alertingNoActionsSaveDescription": "Tilføj mindst én handling, så denne regel kan give besked til nogen, når den udløses.",
|
||||||
|
"alertingNoActionsTestDescription": "Tilføj mindst én handling, inden du kan teste denne regel.",
|
||||||
"standaloneHcTableTitle": "Sundhedstjek",
|
"standaloneHcTableTitle": "Sundhedstjek",
|
||||||
"standaloneHcSearchPlaceholder": "Søg i sundhedstjek…",
|
"standaloneHcSearchPlaceholder": "Søg i sundhedstjek…",
|
||||||
"standaloneHcAddButton": "Opret sundhedstjek",
|
"standaloneHcAddButton": "Opret sundhedstjek",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Underdomæne: {subdomain}",
|
"domainPickerSubdomain": "Underdomæne: {subdomain}",
|
||||||
"domainPickerNamespace": "Navnerom: {namespace}",
|
"domainPickerNamespace": "Navnerom: {namespace}",
|
||||||
"domainPickerShowMore": "Vis mere",
|
"domainPickerShowMore": "Vis mere",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Ingen domæner tilgængelige",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Du har endnu ikke oprettet nogen domæner. Opret et domæne for at fortsætte.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Gå til domæner",
|
||||||
"regionSelectorTitle": "Vælg Region",
|
"regionSelectorTitle": "Vælg Region",
|
||||||
"domainPickerRemoteExitNodeWarning": "Leverede domæner understøttes ikke, når sites kobles til eksterne exitnoder. For ressourcer, der skal være tilgængelige på eksterne noder, skal du i stedet bruge et brugerdefineret domæne.",
|
"domainPickerRemoteExitNodeWarning": "Leverede domæner understøttes ikke, når sites kobles til eksterne exitnoder. For ressourcer, der skal være tilgængelige på eksterne noder, skal du i stedet bruge et brugerdefineret domæne.",
|
||||||
"regionSelectorInfo": "At vælge en region hjelper oss med at give bedre ydeevne for din placering. Du behøver ikke være i samme region som serveren.",
|
"regionSelectorInfo": "At vælge en region hjelper oss med at give bedre ydeevne for din placering. Du behøver ikke være i samme region som serveren.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Subnet",
|
"subnetPlaceholder": "Subnet",
|
||||||
"addressDescription": "Den interne adressen til klienten. Skal falle inden for organisationens subnet.",
|
"addressDescription": "Den interne adressen til klienten. Skal falle inden for organisationens subnet.",
|
||||||
"selectSites": "Vælg sites",
|
"selectSites": "Vælg sites",
|
||||||
|
"selectResources": "Vælg ressourcer",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# ressource} other {# ressourcer}}",
|
||||||
"selectLabels": "Vælg etiketter",
|
"selectLabels": "Vælg etiketter",
|
||||||
"sitesDescription": "Klienten vil have forbindelse til de valgte områdene",
|
"sitesDescription": "Klienten vil have forbindelse til de valgte områdene",
|
||||||
"clientInstallOlm": "Installer Olm",
|
"clientInstallOlm": "Installer Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Tid er i sekunder",
|
"timeIsInSeconds": "Tid er i sekunder",
|
||||||
"requireDeviceApproval": "Kræv enhedsgodkendelse",
|
"requireDeviceApproval": "Kræv enhedsgodkendelse",
|
||||||
"requireDeviceApprovalDescription": "Brugere med denne rolle skal have nye enheder godkendt af en administrator, før de kan oprette forbindelse og få adgang til ressourcer.",
|
"requireDeviceApprovalDescription": "Brugere med denne rolle skal have nye enheder godkendt af en administrator, før de kan oprette forbindelse og få adgang til ressourcer.",
|
||||||
"sshSettings": "SSH Indstillinger",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI Gateway",
|
||||||
"sshAccess": "SSH-adgang",
|
"sshAccess": "SSH-adgang",
|
||||||
"rdpSettings": "RDP Indstillinger",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "VNC Indstillinger",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH-server",
|
"sshServer": "SSH-server",
|
||||||
"rdpServer": "RDP-server",
|
"rdpServer": "RDP-server",
|
||||||
"vncServer": "VNC-server",
|
"vncServer": "VNC-server",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Offentlig",
|
"resourcesTableProxyResources": "Offentlig",
|
||||||
"resourcesTableClientResources": "Privat",
|
"resourcesTableClientResources": "Privat",
|
||||||
"resourcesTableNoProxyResourcesFound": "Ingen proxy-ressourcer fundet.",
|
"resourcesTableNoProxyResourcesFound": "Ingen proxy-ressourcer fundet.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Ingen interne ressourcer fundet.",
|
"resourcesTableNoInternalResourcesFound": "Ingen private ressourcer fundet.",
|
||||||
"resourcesTableDestination": "Destination",
|
"resourcesTableDestination": "Destination",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Alias adresse",
|
"resourcesTableAliasAddress": "Alias adresse",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Annuller",
|
"editInternalResourceDialogCancel": "Annuller",
|
||||||
"editInternalResourceDialogSaveResource": "Gem ressource",
|
"editInternalResourceDialogSaveResource": "Gem ressource",
|
||||||
"editInternalResourceDialogSuccess": "Succes",
|
"editInternalResourceDialogSuccess": "Succes",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Intern ressource opdateret med succes",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Privat ressource opdateret succesfuldt",
|
||||||
"editInternalResourceDialogError": "Fejl",
|
"editInternalResourceDialogError": "Fejl",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Mislykkedes at opdatere intern ressource",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Mislykkedes at opdatere privat ressource",
|
||||||
"editInternalResourceDialogNameRequired": "Navn er påkrævet",
|
"editInternalResourceDialogNameRequired": "Navn er påkrævet",
|
||||||
"editInternalResourceDialogNameMaxLength": "Navn kan ikke være længere enn 255 tegn",
|
"editInternalResourceDialogNameMaxLength": "Navn kan ikke være længere enn 255 tegn",
|
||||||
"editInternalResourceDialogProxyPortMin": "Proxy-port skal være mindst 1",
|
"editInternalResourceDialogProxyPortMin": "Proxy-port skal være mindst 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI Gateway",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Skema",
|
"editInternalResourceDialogScheme": "Skema",
|
||||||
"editInternalResourceDialogEnableSsl": "Aktivér TLS",
|
"editInternalResourceDialogEnableSsl": "Aktivér TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Et valgfrit internt DNS-alias for denne ressource.",
|
"editInternalResourceDialogAliasDescription": "Et valgfrit internt DNS-alias for denne ressource.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Ingen tilgængelige steder",
|
"createInternalResourceDialogNoSitesAvailable": "Ingen tilgængelige steder",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Du skal have mindst ét Newt-site med et konfigureret subnet for at oprette interne ressourcer.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Du skal have mindst ét Newt-site med et konfigureret subnet for at oprette private ressourcer.",
|
||||||
"createInternalResourceDialogClose": "Luk",
|
"createInternalResourceDialogClose": "Luk",
|
||||||
"createInternalResourceDialogCreateClientResource": "Opret privat ressource",
|
"createInternalResourceDialogCreateClientResource": "Opret privat ressource",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Opret en ny ressource som kun vil være tilgængelig for kunder som er forbundet til organisationen",
|
"createInternalResourceDialogCreateClientResourceDescription": "Opret en ny ressource som kun vil være tilgængelig for kunder som er forbundet til organisationen",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Tillad ICMP-ping",
|
"privateResourceAllowIcmpPing": "Tillad ICMP-ping",
|
||||||
"privateResourceNetworkAccess": "Netværksadgang",
|
"privateResourceNetworkAccess": "Netværksadgang",
|
||||||
"privateResourceNetworkAccessDescription": "Styr TCP/UDP-portadgang og om ICMP-ping er tilladt for denne ressource.",
|
"privateResourceNetworkAccessDescription": "Styr TCP/UDP-portadgang og om ICMP-ping er tilladt for denne ressource.",
|
||||||
"hostSettings": "Værtindstillinger",
|
"hostSettings": "Host",
|
||||||
"cidrSettings": "CIDR-indstillinger",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Ressourceegenskaber",
|
"createInternalResourceDialogResourceProperties": "Ressourceegenskaber",
|
||||||
"createInternalResourceDialogName": "Navn",
|
"createInternalResourceDialogName": "Navn",
|
||||||
"createInternalResourceDialogSite": "Websted",
|
"createInternalResourceDialogSite": "Websted",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Annuller",
|
"createInternalResourceDialogCancel": "Annuller",
|
||||||
"createInternalResourceDialogCreateResource": "Opret ressource",
|
"createInternalResourceDialogCreateResource": "Opret ressource",
|
||||||
"createInternalResourceDialogSuccess": "Succes",
|
"createInternalResourceDialogSuccess": "Succes",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Intern ressource oprettet med succes",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Privat ressource oprettet succesfuldt",
|
||||||
"createInternalResourceDialogError": "Fejl",
|
"createInternalResourceDialogError": "Fejl",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke oprette intern ressource",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke oprette privat ressource",
|
||||||
"createInternalResourceDialogNameRequired": "Navn er påkrævet",
|
"createInternalResourceDialogNameRequired": "Navn er påkrævet",
|
||||||
"createInternalResourceDialogNameMaxLength": "Navn kan ikke være længere enn 255 tegn",
|
"createInternalResourceDialogNameMaxLength": "Navn kan ikke være længere enn 255 tegn",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Vælg venligst et site",
|
"createInternalResourceDialogPleaseSelectSite": "Vælg venligst et site",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI Gateway",
|
||||||
"scheme": "Skema",
|
"scheme": "Skema",
|
||||||
"createInternalResourceDialogScheme": "Skema",
|
"createInternalResourceDialogScheme": "Skema",
|
||||||
"createInternalResourceDialogEnableSsl": "Aktivér TLS",
|
"createInternalResourceDialogEnableSsl": "Aktivér TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Gyldig adgangskode",
|
"validPassword": "Gyldig adgangskode",
|
||||||
"validEmail": "Gyldig e-mail",
|
"validEmail": "Gyldig e-mail",
|
||||||
"validSSO": "Gyldig SSO",
|
"validSSO": "Gyldig SSO",
|
||||||
|
"validVirtualAPIKey": "Gyldig Virtuel API Nøgle",
|
||||||
"view": "Vis",
|
"view": "Vis",
|
||||||
"configManaged": "Konfiguration administrert",
|
"configManaged": "Konfiguration administrert",
|
||||||
"connectedClient": "Tilsluttet klient",
|
"connectedClient": "Tilsluttet klient",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Logopbevaring",
|
"logRetention": "Logopbevaring",
|
||||||
"logRetentionDescription": "Håndter hvor længe ulike typer logs beholdes for denne organisation, eller deaktivér dem",
|
"logRetentionDescription": "Håndter hvor længe ulike typer logs beholdes for denne organisation, eller deaktivér dem",
|
||||||
"requestLogsDescription": "Se detaljerede forespørgselslogs for ressourcer i denne organisation",
|
"requestLogsDescription": "Se detaljerede forespørgselslogs for ressourcer i denne organisation",
|
||||||
|
"aiSessionLogs": "AI Gateway Øktsprotokoller",
|
||||||
|
"aiSessionLogsDescription": "Se prompt og svarudskrifter for AI gateway forespørgsler i denne organisation",
|
||||||
|
"sidebarLogsAi": "Øktsprotokoller",
|
||||||
|
"commandLogsAi": "Øktsprotokoller",
|
||||||
|
"sidebarLogsAiUsage": "Bruganalyse",
|
||||||
|
"commandLogsAiUsage": "Bruganalyse",
|
||||||
|
"provider": "Udbyder",
|
||||||
|
"capability": "Kompetence",
|
||||||
|
"model": "Model",
|
||||||
|
"virtualApiKey": "Virtuel API Nøgle",
|
||||||
|
"noVirtualApiKey": "Ingen virtuel API nøgle",
|
||||||
|
"stream": "Stream",
|
||||||
|
"streaming": "Streaming",
|
||||||
|
"nonStreaming": "Ikke-Streaming",
|
||||||
|
"statusCode": "Statuskode",
|
||||||
|
"aiSessionId": "Økts-ID",
|
||||||
|
"aiSessionRequest": "Forespørgsel",
|
||||||
|
"aiSessionResponse": "Svar",
|
||||||
|
"aiSessionNoData": "Ingen data optaget",
|
||||||
|
"aiSessionCouldNotParse": "(rå, kunne ikke analysere udskrift)",
|
||||||
|
"aiSessionLogTruncated": "Denne økt blev afkortet inden lagring og kan være ufuldstændig.",
|
||||||
|
"aiSessionViewRaw": "Se Rå JSON",
|
||||||
|
"aiSessionViewChat": "Se Chat",
|
||||||
|
"cost": "Omkostning",
|
||||||
|
"estimated": "Estimeret",
|
||||||
|
"tokenUsage": "Token Forbrug",
|
||||||
|
"promptTokens": "Prompt tokens",
|
||||||
|
"cacheReadTokens": "Cache Læs Tokens",
|
||||||
|
"cacheWriteTokens": "Cache Skriv Tokens",
|
||||||
|
"completionTokens": "Komplettering Tokens",
|
||||||
|
"reasoningTokens": "Begrundelse Tokens",
|
||||||
|
"totalTokens": "Samlede tokens",
|
||||||
"requestAnalyticsDescription": "Se detaljeret anmodningsanalyse for ressourcer i denne organisation",
|
"requestAnalyticsDescription": "Se detaljeret anmodningsanalyse for ressourcer i denne organisation",
|
||||||
"logRetentionRequestLabel": "Be om logbevaring",
|
"logRetentionRequestLabel": "Be om logbevaring",
|
||||||
"logRetentionRequestDescription": "Hvor længe du vil beholde forespørgselslogs",
|
"logRetentionRequestDescription": "Hvor længe du vil beholde forespørgselslogs",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Hvor længe handlingen skal gemmes",
|
"logRetentionActionDescription": "Hvor længe handlingen skal gemmes",
|
||||||
"logRetentionConnectionLabel": "Forbindelseslog",
|
"logRetentionConnectionLabel": "Forbindelseslog",
|
||||||
"logRetentionConnectionDescription": "Hvor længe du vil beholde forbindelseslogs",
|
"logRetentionConnectionDescription": "Hvor længe du vil beholde forbindelseslogs",
|
||||||
|
"logRetentionAISessionsLabel": "AI Gateway Økt Log Opbevaring",
|
||||||
|
"logRetentionAISessionsDescription": "Hvor længe at opbevare AI gateway prompt/svar øktprotokoller",
|
||||||
"logRetentionDisabled": "Deaktiveret",
|
"logRetentionDisabled": "Deaktiveret",
|
||||||
"logRetention3Days": "3 dage",
|
"logRetention3Days": "3 dage",
|
||||||
"logRetention7Days": "7 dage",
|
"logRetention7Days": "7 dage",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Kildeadresse",
|
"sourceAddress": "Kildeadresse",
|
||||||
"destinationAddress": "Måladresse ",
|
"destinationAddress": "Måladresse ",
|
||||||
"duration": "Varighed",
|
"duration": "Varighed",
|
||||||
"licenseRequiredToUse": "En <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink>-licens eller <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> er påkrævet for at bruge denne funktion. <bookADemoLink>Book en demo eller POC-prøveversion</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Enterprise Edition licens</enterpriseEditionLink> er krævet. <bookADemoLink>Book en demo eller prøve</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> er nødvendig for at bruge denne funktion. Denne funktion er også tilgængelig i <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book en demo eller POC-prøve</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition licens</enterpriseEditionLink> er krævet. <bookADemoLink>Book en demo eller prøve</bookADemoLink>",
|
||||||
"certResolver": "Certifikatløser",
|
"certResolver": "Certifikatløser",
|
||||||
"certResolverDescription": "Vælg certifikatløser som skal bruges for denne ressource.",
|
"certResolverDescription": "Vælg certifikatløser som skal bruges for denne ressource.",
|
||||||
"selectCertResolver": "Vælg certifikatløser",
|
"selectCertResolver": "Vælg certifikatløser",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Valg af flere sites muliggør robust routing og failover for høj tilgængelighed.",
|
"internalResourceFormMultiSiteRoutingHelp": "Valg af flere sites muliggør robust routing og failover for høj tilgængelighed.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Læs mere",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Læs mere",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Begrens adgang til specifikke TCP/UDP-porte eller tillade/blokere alle porte.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Begrens adgang til specifikke TCP/UDP-porte eller tillade/blokere alle porte.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "HTTP-konfiguration",
|
"createInternalResourceDialogHttpConfiguration": "Domænekonfiguration",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Vælg domænet klienter vil bruge for at nu denne ressource via HTTP eller HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Vælg domænet klienter vil bruge for at nu denne ressource via HTTP eller HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "HTTP-konfiguration",
|
"editInternalResourceDialogHttpConfiguration": "Domænekonfiguration",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Vælg domænet klienter vil bruge for at nu denne ressource via HTTP eller HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Vælg domænet klienter vil bruge for at nu denne ressource via HTTP eller HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Uden Etiket",
|
"resourceLauncherUnlabeled": "Uden Etiket",
|
||||||
|
"resourceLauncherAiGateway": "AI Gateway",
|
||||||
"resourceLauncherNoSite": "Ingen Site",
|
"resourceLauncherNoSite": "Ingen Site",
|
||||||
|
"resourceLauncherAvailableModels": "Tilgængelige Modeller",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modeller, du kan bruge med denne AI-gateway.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Ingen modeller er tilgængelige for denne ressource.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Kunne ikke indlæse tilgængelige modeller.",
|
||||||
|
"resourceLauncherApiKeys": "API Nøgler",
|
||||||
|
"resourceLauncherApiKeysDescription": "Brug din identitetsnøgle eller en attributeret nøgle til at godkende med denne ressource.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Identitetsnøgle",
|
||||||
|
"resourceLauncherApiKeysManual": "Attributerede Nøgler",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Ingen API-nøgler er tilgængelige for denne ressource.",
|
||||||
|
"resourceLauncherApiKeysError": "Kunne ikke indlæse API-nøgler.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Ingen ressourcer i denne gruppe",
|
"resourceLauncherNoResourcesInGroup": "Ingen ressourcer i denne gruppe",
|
||||||
"resourceLauncherEmptyStateTitle": "Ingen ressourcer tilgængelige",
|
"resourceLauncherEmptyStateTitle": "Ingen ressourcer tilgængelige",
|
||||||
"resourceLauncherEmptyStateDescription": "Du har endnu ikke adgang til nogen ressourcer. Kontakt din administrator for at anmode om adgang.",
|
"resourceLauncherEmptyStateDescription": "Du har endnu ikke adgang til nogen ressourcer. Kontakt din administrator for at anmode om adgang.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Kan ikke slette launcher-visningen. Prøv venligst igen.",
|
"resourceLauncherViewDeleteFailedDescription": "Kan ikke slette launcher-visningen. Prøv venligst igen.",
|
||||||
"memberPortalPrevious": "Forrige",
|
"memberPortalPrevious": "Forrige",
|
||||||
"memberPortalNext": "Næste",
|
"memberPortalNext": "Næste",
|
||||||
"httpSettings": "HTTP Indstillinger",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "TCP Indstillinger",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "UDP Indstillinger",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Oprette en sikker forbindelse…",
|
"sshConnectingDescription": "Oprette en sikker forbindelse…",
|
||||||
"sshConnecting": "Opretter forbindelse til…",
|
"sshConnecting": "Opretter forbindelse til…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Uploaden mislykkedes",
|
"rdpUploadFailed": "Uploaden mislykkedes",
|
||||||
"rdpUnicodeKeyboardMode": "Unicode tastaturtilstand",
|
"rdpUnicodeKeyboardMode": "Unicode tastaturtilstand",
|
||||||
"sessionToolbarShow": "Vis værktøjslinje",
|
"sessionToolbarShow": "Vis værktøjslinje",
|
||||||
"sessionToolbarHide": "Skjul værktøjslinje"
|
"sessionToolbarHide": "Skjul værktøjslinje",
|
||||||
|
"actionUpdateSiteApprovals": "Opdater godkendelser på site"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Bitte stelle sicher, dass du als korrekter Benutzer angemeldet bist.",
|
"inviteLoginUser": "Bitte stelle sicher, dass du als korrekter Benutzer angemeldet bist.",
|
||||||
"inviteErrorNoUser": "Es tut uns leid, aber es sieht so aus, als sei die Einladung, auf die du zugreifen möchtest, nicht für einen existierenden Benutzer bestimmt.",
|
"inviteErrorNoUser": "Es tut uns leid, aber es sieht so aus, als sei die Einladung, auf die du zugreifen möchtest, nicht für einen existierenden Benutzer bestimmt.",
|
||||||
"inviteCreateUser": "Bitte erstelle zuerst ein Konto.",
|
"inviteCreateUser": "Bitte erstelle zuerst ein Konto.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Einladungen können nur von internen Konten angenommen werden. Melden Sie sich ab und melden Sie sich mit Ihrem Passwort für diese E-Mail an.",
|
||||||
|
"inviteLoginInternalOnly": "Einladungen erfordern ein internes Konto mit einem Passwort. Erstellen Sie ein Konto oder melden Sie sich mit Ihrem Passwort an.",
|
||||||
"goHome": "Zur Startseite",
|
"goHome": "Zur Startseite",
|
||||||
"inviteLogInOtherUser": "Als anderer Benutzer anmelden",
|
"inviteLogInOtherUser": "Als anderer Benutzer anmelden",
|
||||||
"createAnAccount": "Konto erstellen",
|
"createAnAccount": "Konto erstellen",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Löschung des Freigabelinks bestätigen",
|
"shareDeleteConfirm": "Löschung des Freigabelinks bestätigen",
|
||||||
"shareQuestionRemove": "Sind Sie sicher, dass Sie diesen Freigabelink löschen möchten?",
|
"shareQuestionRemove": "Sind Sie sicher, dass Sie diesen Freigabelink löschen möchten?",
|
||||||
"shareMessageRemove": "Nach dem Löschen funktioniert der Link nicht mehr, und jeder, der ihn nutzt, verliert den Zugriff auf die Ressource.",
|
"shareMessageRemove": "Nach dem Löschen funktioniert der Link nicht mehr, und jeder, der ihn nutzt, verliert den Zugriff auf die Ressource.",
|
||||||
"shareTokenDescription": "Das Zugriffstoken kann auf zwei Arten übergeben werden: als Abfrageparameter oder in den Request-Headern. Diese müssen vom Client auf jeder Anfrage für authentifizierten Zugriff weitergegeben werden.",
|
"shareTokenDescription": "Der Zugriffstoken kann als Abfrageparameter oder in Anforderungsheadern übergeben werden. Standardmäßig muss er bei jeder Anforderung gesendet werden. Wenn die Sitzungsbeständigkeit aktiviert ist, wird die erste Anfrage gegen ein Sitzungscookie ausgetauscht.",
|
||||||
"accessToken": "Zugriffstoken",
|
"accessToken": "Zugriffstoken",
|
||||||
"usageExamples": "Nutzungsbeispiele",
|
"usageExamples": "Nutzungsbeispiele",
|
||||||
"tokenId": "Token-ID",
|
"tokenId": "Token-ID",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Titel (optional)",
|
"shareTitleOptional": "Titel (optional)",
|
||||||
"sharePathOptional": "Pfad (optional)",
|
"sharePathOptional": "Pfad (optional)",
|
||||||
"sharePathDescription": "Der Link leitet Benutzer nach der Authentifizierung zu diesem Pfad weiter.",
|
"sharePathDescription": "Der Link leitet Benutzer nach der Authentifizierung zu diesem Pfad weiter.",
|
||||||
|
"shareAssociateUserOptional": "Benutzer zuweisen (optional)",
|
||||||
|
"shareAssociateUserDescription": "Wenn gesetzt, werden Anfragen mit diesem Link in Zugriffsprotokollen und Identitätsheadern dem Benutzer zugeordnet. Der Link wird entfernt, wenn der Benutzer die Organisation verlässt.",
|
||||||
|
"userSelect": "Benutzer auswählen",
|
||||||
|
"usersNotFound": "Keine Benutzer gefunden",
|
||||||
"expireIn": "Läuft ab in",
|
"expireIn": "Läuft ab in",
|
||||||
"neverExpire": "Läuft nie ab",
|
"neverExpire": "Läuft nie ab",
|
||||||
|
"sharePersistSession": "Sitzung nach erster Nutzung beibehalten",
|
||||||
|
"sharePersistSessionDescription": "Wenn aktiviert, setzt die erste Anfrage mit diesem Token über einen Abfrageparameter oder einen Header ein Sitzungscookie, sodass spätere Anfragen das Token nicht benötigen. Deaktivieren Sie dies für API-Clients, die das Token bei jeder Anfrage senden sollen.",
|
||||||
"shareExpireDescription": "Ablaufzeit ist, wie lange der Link verwendet werden kann und bietet Zugriff auf die Ressource. Nach dieser Zeit wird der Link nicht mehr funktionieren und Benutzer, die diesen Link benutzt haben, verlieren den Zugriff auf die Ressource.",
|
"shareExpireDescription": "Ablaufzeit ist, wie lange der Link verwendet werden kann und bietet Zugriff auf die Ressource. Nach dieser Zeit wird der Link nicht mehr funktionieren und Benutzer, die diesen Link benutzt haben, verlieren den Zugriff auf die Ressource.",
|
||||||
"shareSeeOnce": "Sie können diesen Link nur einmal sehen. Bitte kopieren Sie ihn.",
|
"shareSeeOnce": "Sie können diesen Link nur einmal sehen. Bitte kopieren Sie ihn.",
|
||||||
"shareAccessHint": "Jeder mit diesem Link kann auf die Ressource zugreifen. Teilen Sie sie mit Vorsicht.",
|
"shareAccessHint": "Jeder mit diesem Link kann auf die Ressource zugreifen. Teilen Sie sie mit Vorsicht.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Kein Land gefunden.",
|
"noCountryFound": "Kein Land gefunden.",
|
||||||
"siteSelectionDescription": "Dieser Standort wird die Verbindung zum Ziel herstellen.",
|
"siteSelectionDescription": "Dieser Standort wird die Verbindung zum Ziel herstellen.",
|
||||||
"resourceType": "Ressourcentyp",
|
"resourceType": "Ressourcentyp",
|
||||||
"resourceTypeDescription": "Dies steuert das Ressourcenprotokoll und wie es im Browser gerendert wird. Dies kann später nicht geändert werden.",
|
"resourceTypeDescription": "Dies steuert das Ressourcenprotokoll und kann später nicht mehr geändert werden.",
|
||||||
|
"resourceTypeSearch": "Suche Ressourcentypen...",
|
||||||
|
"resourceTypeNotFound": "Kein Ressourcentyp gefunden",
|
||||||
|
"resourceTypeHttpDescription": "Leiten Sie Webverkehr über HTTPS unter Verwendung eines Domänennamens weiter",
|
||||||
|
"resourceTypeInferenceDescription": "Leiten Sie KI-Anfragen über angehängte Anbieter weiter",
|
||||||
|
"resourceTypeSshDescription": "Greifen Sie von einem Browser aus auf einen SSH-Server zu",
|
||||||
|
"resourceTypeRdpDescription": "Greifen Sie von einem Browser aus auf einen Remote-Desktop zu",
|
||||||
|
"resourceTypeVncDescription": "Greifen Sie von einem Browser aus auf einen VNC-Desktop zu",
|
||||||
|
"resourceTypeTcpDescription": "Leiten Sie rohe TCP-Datenverkehr durch eine Portnummer weiter",
|
||||||
|
"resourceTypeUdpDescription": "Leiten Sie rohe UDP-Datenverkehr durch eine Portnummer weiter",
|
||||||
|
"privateResourceTypeDescription": "Dies steuert, wie Klienten auf die Ressource zugreifen können. Dies kann später nicht mehr geändert werden.",
|
||||||
|
"privateResourceTypeHostDescription": "Einen einzelnen Host im Netzwerk der Seite für angeschlossene Clients verfügbar machen",
|
||||||
|
"privateResourceTypeCidrDescription": "Einen CIDR-Bereich im Netzwerk der Seite für angeschlossene Clients verfügbar machen",
|
||||||
|
"privateResourceTypeHttpDescription": "Auf einen HTTP- oder HTTPS-Dienst über eine Domain zugreifen",
|
||||||
|
"privateResourceTypeSshDescription": "Auf einen SSH-Server von verbundenen Clients aus zugreifen",
|
||||||
"resourceDomainDescription": "Die Ressource wird unter diesem vollständig qualifizierten Domainnamen bereitgestellt.",
|
"resourceDomainDescription": "Die Ressource wird unter diesem vollständig qualifizierten Domainnamen bereitgestellt.",
|
||||||
"resourceHTTPSSettings": "HTTPS-Einstellungen",
|
"resourceHTTPSSettings": "HTTPS-Einstellungen",
|
||||||
"resourceHTTPSSettingsDescription": "Konfigurieren Sie den Zugriff auf die Ressource über HTTPS",
|
"resourceHTTPSSettingsDescription": "Konfigurieren Sie den Zugriff auf die Ressource über HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Bereitstellung",
|
"provisioningManage": "Bereitstellung",
|
||||||
"provisioningDescription": "Bereitstellungsschlüssel verwalten und ausstehende Standorte prüfen, die noch auf Genehmigung warten.",
|
"provisioningDescription": "Bereitstellungsschlüssel verwalten und ausstehende Standorte prüfen, die noch auf Genehmigung warten.",
|
||||||
"pendingSites": "Ausstehende Standorte",
|
"pendingSites": "Ausstehende Standorte",
|
||||||
"siteApproveSuccess": "Standort erfolgreich freigegeben",
|
"siteApproveSuccess": "Site und zugehörige Ressourcen erfolgreich genehmigt",
|
||||||
"siteApproveError": "Fehler beim Genehmigen des Standorts",
|
"siteApproveError": "Fehler beim Genehmigen des Standorts",
|
||||||
|
"siteReject": "Site ablehnen",
|
||||||
|
"siteQuestionReject": "Sind Sie sicher, dass Sie diese Site ablehnen möchten?",
|
||||||
|
"siteMessageReject": "Dies wird die Site und alle damit verbundenen, noch ausstehenden Ressourcen dauerhaft löschen.",
|
||||||
|
"siteConfirmReject": "Ablehnung der Site bestätigen",
|
||||||
|
"siteRejectSuccess": "Site erfolgreich abgelehnt",
|
||||||
|
"siteRejectError": "Fehler beim Ablehnen der Site",
|
||||||
"provisioningKeys": "Bereitstellungsschlüssel",
|
"provisioningKeys": "Bereitstellungsschlüssel",
|
||||||
"searchProvisioningKeys": "Bereitstellungsschlüssel suchen...",
|
"searchProvisioningKeys": "Bereitstellungsschlüssel suchen...",
|
||||||
"provisioningKeysAdd": "Bereitstellungsschlüssel generieren",
|
"provisioningKeysAdd": "Bereitstellungsschlüssel generieren",
|
||||||
@@ -467,7 +495,7 @@
|
|||||||
"provisioningKeysSaveDescription": "Sie können dies nur einmal sehen. Kopieren Sie es an einen sicheren Ort.",
|
"provisioningKeysSaveDescription": "Sie können dies nur einmal sehen. Kopieren Sie es an einen sicheren Ort.",
|
||||||
"provisioningKeysErrorCreate": "Fehler beim Erstellen des Bereitstellungsschlüssels",
|
"provisioningKeysErrorCreate": "Fehler beim Erstellen des Bereitstellungsschlüssels",
|
||||||
"provisioningKeysList": "Neuer Bereitstellungsschlüssel",
|
"provisioningKeysList": "Neuer Bereitstellungsschlüssel",
|
||||||
"provisioningKeysMaxBatchSize": "Max. Batch-Größe",
|
"provisioningKeysMaxBatchSize": "Maximale Batch-Größe",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Unbegrenzte Batch-Größe (kein Limit)",
|
"provisioningKeysUnlimitedBatchSize": "Unbegrenzte Batch-Größe (kein Limit)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Unbegrenzt",
|
"provisioningKeysMaxBatchUnlimited": "Unbegrenzt",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Geben Sie eine gültige maximale Batchgröße ein (1–1.000.000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Geben Sie eine gültige maximale Batchgröße ein (1–1.000.000).",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "Nie",
|
"provisioningKeysNeverUsed": "Nie",
|
||||||
"provisioningKeysEdit": "Bereitstellungsschlüssel bearbeiten",
|
"provisioningKeysEdit": "Bereitstellungsschlüssel bearbeiten",
|
||||||
"provisioningKeysEditDescription": "Aktualisieren Sie die maximale Batch-Größe und Ablaufzeit für diesen Schlüssel.",
|
"provisioningKeysEditDescription": "Aktualisieren Sie die maximale Batch-Größe und Ablaufzeit für diesen Schlüssel.",
|
||||||
"provisioningKeysApproveNewSites": "Neuen Standort genehmigen",
|
"provisioningKeysApproveNewSites": "Neue Sites genehmigen",
|
||||||
"provisioningKeysApproveNewSitesDescription": "Sites, die sich mit diesem Schlüssel registrieren, automatisch freigeben.",
|
"provisioningKeysApproveNewSitesDescription": "Sites, die sich mit diesem Schlüssel registrieren, automatisch freigeben.",
|
||||||
"provisioningKeysUpdateError": "Fehler beim Aktualisieren des Bereitstellungsschlüssels",
|
"provisioningKeysUpdateError": "Fehler beim Aktualisieren des Bereitstellungsschlüssels",
|
||||||
"provisioningKeysUpdated": "Bereitstellungsschlüssel aktualisiert",
|
"provisioningKeysUpdated": "Bereitstellungsschlüssel aktualisiert",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Einstellungen speichern",
|
"authMethodsSave": "Einstellungen speichern",
|
||||||
"policyAuthStackTitle": "Authentifizierung",
|
"policyAuthStackTitle": "Authentifizierung",
|
||||||
"policyAuthStackDescription": "Kontrollieren Sie, welche Authentifizierungsmethoden erforderlich sind, um auf diese Ressource zuzugreifen",
|
"policyAuthStackDescription": "Kontrollieren Sie, welche Authentifizierungsmethoden erforderlich sind, um auf diese Ressource zuzugreifen",
|
||||||
|
"policyAuthInferenceStackDescription": "Wählen Sie, welche Benutzer und Rollen sich an diesem KI-Gateway authentifizieren können",
|
||||||
"policyAuthOrLogicTitle": "Mehrere Authentifizierungsmethoden aktiv",
|
"policyAuthOrLogicTitle": "Mehrere Authentifizierungsmethoden aktiv",
|
||||||
"policyAuthOrLogicBanner": "Besucher können sich mit einer der unten aktiven Methoden authentifizieren. Sie müssen nicht alle abschließen.",
|
"policyAuthOrLogicBanner": "Besucher können sich mit einer der unten aktiven Methoden authentifizieren. Sie müssen nicht alle abschließen.",
|
||||||
"policyAuthMethodActive": "Aktiv",
|
"policyAuthMethodActive": "Aktiv",
|
||||||
"policyAuthMethodOff": "Aus",
|
"policyAuthMethodOff": "Aus",
|
||||||
"policyAuthSsoTitle": "Plattform SSO",
|
"policyAuthSsoTitle": "Plattform SSO",
|
||||||
"policyAuthSsoDescription": "Anmeldung über den Identitätsanbieter Ihrer Organisation erforderlich",
|
"policyAuthSsoDescription": "Anmeldung über den Identitätsanbieter Ihrer Organisation erforderlich",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "Anmelde-URL",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Jeder Benutzer hat bereits einen Identitäts-API-Schlüssel, sodass Sie nur virtuelle API-Schlüssel für Nicht-Benutzer-Clients oder gemeinsamen Zugriff erstellen müssen. Benutzer können ihren Schlüssel abrufen, indem sie sich bei Ihrem Identitätsanbieter an der URL dieser Ressource anmelden, wo es nach der Anmeldung angezeigt wird.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Jeder Benutzer hat bereits einen Identitäts-API-Schlüssel, sodass Sie nur virtuelle API-Schlüssel für Nicht-Benutzer-Clients oder gemeinsamen Zugriff erstellen müssen. Benutzer rufen ihren Schlüssel hier ab, nachdem sie sich bei ihrem Identitätsanbieter angemeldet haben.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} Benutzer, {roles} Rollen",
|
"policyAuthSsoSummary": "{idp} · {users} Benutzer, {roles} Rollen",
|
||||||
"policyAuthSsoDefaultIdp": "Standardanbieter",
|
"policyAuthSsoDefaultIdp": "Standardanbieter",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Standardidentitätsanbieter hinzufügen",
|
"policyAuthAddDefaultIdentityProvider": "Standardidentitätsanbieter hinzufügen",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Version",
|
"newtVersion": "Version",
|
||||||
"architecture": "Architektur",
|
"architecture": "Architektur",
|
||||||
"sites": "Standorte",
|
"sites": "Standorte",
|
||||||
"siteWgAnyClients": "Verwenden Sie jeden WireGuard-Client um sich zu verbinden. Sie müssen interne Ressourcen über die Peer-IP ansprechen.",
|
"siteWgAnyClients": "Verwenden Sie jeden beliebigen WireGuard-Client, um sich zu verbinden. Sie müssen die privaten Ressourcen mit der Peer-IP adressieren.",
|
||||||
"siteWgCompatibleAllClients": "Kompatibel mit allen WireGuard-Clients",
|
"siteWgCompatibleAllClients": "Kompatibel mit allen WireGuard-Clients",
|
||||||
"siteWgManualConfigurationRequired": "Manuelle Konfiguration erforderlich",
|
"siteWgManualConfigurationRequired": "Manuelle Konfiguration erforderlich",
|
||||||
"userErrorNotAdminOrOwner": "Benutzer ist kein Administrator oder Eigentümer",
|
"userErrorNotAdminOrOwner": "Benutzer ist kein Administrator oder Eigentümer",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Neue Rolle ist erforderlich",
|
"accessRoleErrorNewRequired": "Neue Rolle ist erforderlich",
|
||||||
"accessRoleErrorRemove": "Fehler beim Entfernen der Rolle",
|
"accessRoleErrorRemove": "Fehler beim Entfernen der Rolle",
|
||||||
"accessRoleErrorRemoveDescription": "Beim Entfernen der Rolle ist ein Fehler aufgetreten.",
|
"accessRoleErrorRemoveDescription": "Beim Entfernen der Rolle ist ein Fehler aufgetreten.",
|
||||||
|
"accessRoleInferenceBudget": "KI-Budget",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Konfigurieren Sie, wie diese Rolle die KI-Nutzung basierend auf Ausgaben oder Tokenlimits einschränkt",
|
||||||
"accessRoleName": "Rollenname",
|
"accessRoleName": "Rollenname",
|
||||||
"accessRoleQuestionRemove": "Du bist dabei die Rolle `{name}` zu löschen. Du kannst diese Aktion nicht rückgängig machen.",
|
"accessRoleQuestionRemove": "Du bist dabei die Rolle `{name}` zu löschen. Du kannst diese Aktion nicht rückgängig machen.",
|
||||||
"accessRoleRemove": "Rolle entfernen",
|
"accessRoleRemove": "Rolle entfernen",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Org Benutzer erstellen",
|
"createOrgUser": "Org Benutzer erstellen",
|
||||||
"actionUpdateOrg": "Organisation aktualisieren",
|
"actionUpdateOrg": "Organisation aktualisieren",
|
||||||
"actionRemoveInvitation": "Einladung entfernen",
|
"actionRemoveInvitation": "Einladung entfernen",
|
||||||
|
"actionRemoveUserRole": "Benutzerrolle entfernen",
|
||||||
"actionUpdateUser": "Benutzer aktualisieren",
|
"actionUpdateUser": "Benutzer aktualisieren",
|
||||||
"actionGetUser": "Benutzer abrufen",
|
"actionGetUser": "Benutzer abrufen",
|
||||||
"actionGetOrgUser": "Organisationsbenutzer abrufen",
|
"actionGetOrgUser": "Organisationsbenutzer abrufen",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Standort löschen",
|
"actionDeleteSite": "Standort löschen",
|
||||||
"actionGetSite": "Standort abrufen",
|
"actionGetSite": "Standort abrufen",
|
||||||
"actionListSites": "Standorte auflisten",
|
"actionListSites": "Standorte auflisten",
|
||||||
|
"actionCreateAiProvider": "KI-Anbieter erstellen",
|
||||||
|
"actionDeleteAiProvider": "KI-Anbieter löschen",
|
||||||
|
"actionGetAiProvider": "KI-Anbieter abrufen",
|
||||||
|
"actionListAiProviders": "KI-Anbieter auflisten",
|
||||||
|
"actionUpdateAiProvider": "KI-Anbieter aktualisieren",
|
||||||
|
"actionCreateAiModel": "KI-Modell erstellen",
|
||||||
|
"actionDeleteAiModel": "KI-Modell löschen",
|
||||||
|
"actionGetAiModel": "KI-Modell abrufen",
|
||||||
|
"actionListAiModels": "KI-Modelle auflisten",
|
||||||
|
"actionUpdateAiModel": "KI-Modell aktualisieren",
|
||||||
|
"actionCreateAiBudget": "KI-Budget erstellen",
|
||||||
|
"actionDeleteAiBudget": "KI-Budget löschen",
|
||||||
|
"actionGetAiBudget": "KI-Budget abrufen",
|
||||||
|
"actionListAiBudgets": "KI-Budgets auflisten",
|
||||||
|
"actionUpdateAiBudget": "KI-Budget aktualisieren",
|
||||||
|
"actionListResourceAiModels": "Ressourcen-KI-Modelle auflisten",
|
||||||
|
"actionSetResourceAiModels": "Ressourcen-KI-Modelle festlegen",
|
||||||
|
"actionCreateVirtualApiKey": "Virtuellen API-Schlüssel erstellen",
|
||||||
|
"actionDeleteVirtualApiKey": "Virtuellen API-Schlüssel löschen",
|
||||||
|
"actionGetVirtualApiKey": "Virtuellen API-Schlüssel abrufen",
|
||||||
|
"actionListVirtualApiKeys": "Virtuelle API-Schlüssel auflisten",
|
||||||
|
"actionUpdateVirtualApiKey": "Virtuellen API-Schlüssel aktualisieren",
|
||||||
"actionApplyBlueprint": "Blueprint anwenden",
|
"actionApplyBlueprint": "Blueprint anwenden",
|
||||||
"actionListBlueprints": "Blaupausen anzeigen",
|
"actionListBlueprints": "Blaupausen anzeigen",
|
||||||
"actionGetBlueprint": "Erhalte Blaupause",
|
"actionGetBlueprint": "Erhalte Blaupause",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Geben Sie das Setup-Token von der Serverkonsole ein.",
|
"setupTokenDescription": "Geben Sie das Setup-Token von der Serverkonsole ein.",
|
||||||
"setupTokenRequired": "Setup-Token ist erforderlich",
|
"setupTokenRequired": "Setup-Token ist erforderlich",
|
||||||
"actionUpdateSite": "Standorte aktualisieren",
|
"actionUpdateSite": "Standorte aktualisieren",
|
||||||
|
"actionApproveSite": "Site genehmigen",
|
||||||
|
"actionRejectSite": "Site ablehnen",
|
||||||
"actionResetSiteBandwidth": "Organisations-Bandbreite zurücksetzen",
|
"actionResetSiteBandwidth": "Organisations-Bandbreite zurücksetzen",
|
||||||
"actionListSiteRoles": "Erlaubte Standort-Rollen auflisten",
|
"actionListSiteRoles": "Erlaubte Standort-Rollen auflisten",
|
||||||
"actionCreateResource": "Ressource erstellen",
|
"actionCreateResource": "Ressource erstellen",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Ressourcen-PIN festlegen",
|
"actionSetResourcePincode": "Ressourcen-PIN festlegen",
|
||||||
"actionSetResourceEmailWhitelist": "Ressourcen-E-Mail-Whitelist festlegen",
|
"actionSetResourceEmailWhitelist": "Ressourcen-E-Mail-Whitelist festlegen",
|
||||||
"actionGetResourceEmailWhitelist": "Ressourcen-E-Mail-Whitelist abrufen",
|
"actionGetResourceEmailWhitelist": "Ressourcen-E-Mail-Whitelist abrufen",
|
||||||
|
"actionListResourcePolicies": "Ressourcen-Richtlinien auflisten",
|
||||||
|
"actionCreateResourcePolicy": "Ressourcen-Richtlinie erstellen",
|
||||||
"actionGetResourcePolicy": "Ressourcenrichtlinie abrufen",
|
"actionGetResourcePolicy": "Ressourcenrichtlinie abrufen",
|
||||||
"actionUpdateResourcePolicy": "Ressourcenrichtlinie aktualisieren",
|
"actionUpdateResourcePolicy": "Ressourcenrichtlinie aktualisieren",
|
||||||
|
"actionDeleteResourcePolicy": "Ressourcen-Richtlinie löschen",
|
||||||
"actionSetResourcePolicyUsers": "Ressourcenrichtlinienbenutzer festlegen",
|
"actionSetResourcePolicyUsers": "Ressourcenrichtlinienbenutzer festlegen",
|
||||||
"actionSetResourcePolicyRoles": "Rollen der Ressourcenrichtlinie festlegen",
|
"actionSetResourcePolicyRoles": "Rollen der Ressourcenrichtlinie festlegen",
|
||||||
"actionSetResourcePolicyPassword": "Passwort der Ressourcenrichtlinie festlegen",
|
"actionSetResourcePolicyPassword": "Passwort der Ressourcenrichtlinie festlegen",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Einladungen auflisten",
|
"actionListInvitations": "Einladungen auflisten",
|
||||||
"actionExportLogs": "Logs exportieren",
|
"actionExportLogs": "Logs exportieren",
|
||||||
"actionViewLogs": "Logs anzeigen",
|
"actionViewLogs": "Logs anzeigen",
|
||||||
|
"actionCreateSiteProvisioningKey": "Bereitstellungsschlüssel für Standort erstellen",
|
||||||
|
"actionListSiteProvisioningKeys": "Liste der Bereitstellungsschlüssel für Standorte",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Bereitstellungsschlüssel für Standort aktualisieren",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Bereitstellungsschlüssel für Standort löschen",
|
||||||
"noneSelected": "Keine ausgewählt",
|
"noneSelected": "Keine ausgewählt",
|
||||||
"orgNotFound2": "Keine Organisationen gefunden.",
|
"orgNotFound2": "Keine Organisationen gefunden.",
|
||||||
"search": "Suche…",
|
"search": "Suche…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Geben Sie den Code aus Ihrer Authenticator-App oder einen Ihrer einmaligen Backup-Codes ein.",
|
"otpAuthDescription": "Geben Sie den Code aus Ihrer Authenticator-App oder einen Ihrer einmaligen Backup-Codes ein.",
|
||||||
"otpAuthSubmit": "Code absenden",
|
"otpAuthSubmit": "Code absenden",
|
||||||
"idpContinue": "Oder weiter mit",
|
"idpContinue": "Oder weiter mit",
|
||||||
|
"idpLastUsed": "Zuletzt verwendet",
|
||||||
"otpAuthBack": "Zurück zum Passwort",
|
"otpAuthBack": "Zurück zum Passwort",
|
||||||
"navbar": "Navigationsmenü",
|
"navbar": "Navigationsmenü",
|
||||||
"navbarDescription": "Hauptnavigationsmenü für die Anwendung",
|
"navbarDescription": "Hauptnavigationsmenü für die Anwendung",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Maschinen-Client erstellen",
|
"commandPaletteCreateMachineClient": "Maschinen-Client erstellen",
|
||||||
"commandPaletteCreateAlertRule": "Alarmregel erstellen",
|
"commandPaletteCreateAlertRule": "Alarmregel erstellen",
|
||||||
"commandPaletteCreateIdentityProvider": "Identitätsanbieter erstellen",
|
"commandPaletteCreateIdentityProvider": "Identitätsanbieter erstellen",
|
||||||
|
"commandPaletteCreateAiProvider": "KI-Anbieter erstellen",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Virtuellen API-Schlüssel erstellen",
|
||||||
"commandPaletteToggleTheme": "Thema umschalten",
|
"commandPaletteToggleTheme": "Thema umschalten",
|
||||||
"commandPaletteChooseOrganization": "Organisation auswählen",
|
"commandPaletteChooseOrganization": "Organisation auswählen",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Einladungen",
|
"sidebarInvitations": "Einladungen",
|
||||||
"sidebarRoles": "Rollen",
|
"sidebarRoles": "Rollen",
|
||||||
"sidebarShareableLinks": "Teilbare Links",
|
"sidebarShareableLinks": "Teilbare Links",
|
||||||
|
"sidebarAiGateway": "KI-Gateway",
|
||||||
|
"sidebarAiProviders": "Anbieter",
|
||||||
|
"commandAiProviders": "KI-Anbieter",
|
||||||
|
"sidebarVirtualApiKeys": "Virtuelle API-Schlüssel",
|
||||||
|
"sidebarMyApiKeys": "Ihre API-Schlüssel",
|
||||||
|
"sidebarAccount": "Launcher",
|
||||||
|
"commandVirtualApiKeys": "Virtuelle API-Schlüssel",
|
||||||
|
"virtualApiKeysTitle": "Virtuelle API-Schlüssel verwalten",
|
||||||
|
"virtualApiKeysDescription": "Erstellen und verwalten Sie manuelle API-Schlüssel für den Zugang zum KI-Gateway des öffentlichen KI-Gateways",
|
||||||
|
"virtualApiKeysTabIdentity": "Identitätsschlüssel",
|
||||||
|
"virtualApiKeysTabVirtual": "Virtuelle Schlüssel",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Identitätsschlüssel für jeden Benutzer",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Jeder Benutzer hat bereits einen Pangolin-Identitätsschlüssel für diese Organisation. Es ist einzigartig für ihr Konto und authentifiziert sie bei KI-Gateways, auf die sie zugreifen können.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Beispiel",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Wie Benutzer ihren Schlüssel erhalten",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Besuchen Sie eine URL des öffentlichen KI-Gateways im Browser und melden Sie sich mit ihrem Konto an.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Oder gehen Sie zu <url></url>, während Sie angemeldet sind.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Sie können zusätzliche virtuelle API-Schlüssel auf der Registerkarte \"Virtuelle Schlüssel\" erstellen. Diese Schlüssel können auf bestimmte öffentliche KI-Gateways abgestimmt und optional einem Benutzer zugeordnet werden. Durch das Erstellen eines Schlüssels wird sofortiger Zugang zu den ausgewählten öffentlichen KI-Gateways gewährt.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Schlüssel manuell erstellen",
|
||||||
|
"virtualApiKeysEmailIdentity": "E-Mail-Identitätsschlüssel",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Senden Sie jedem ausgewählten Benutzer oder jeder Rolle ihren Pangolin-Identitätsschlüssel.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "An alle Benutzer senden",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "E-Mail an jedes Mitglied der Organisation, das eine Kontoe-Mail hat.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Benutzergeräte",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Rollen",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "E-Mails senden",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Identitätsschlüssel versandt",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "{sent} E-Mails wurden gesendet.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} Benutzer wurden übersprungen, da sie keine E-Mail-Adresse haben.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Wählen Sie mindestens einen Benutzer oder eine Rolle aus oder senden Sie an alle Benutzer.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Fehler beim Senden der Identitätsschlüssel",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Fehler beim E-Mail-Versand der Identitätsschlüssel",
|
||||||
|
"virtualApiKeysBannerTitle": "Identitätsschlüssel für jeden Benutzer",
|
||||||
|
"virtualApiKeysBannerDescription": "Jeder Benutzer hat bereits einen Identitätsschlüssel verfügbar unter {keysUrl}. Sie können auch manuell Schlüssel generieren, die direkten Zugang zu öffentlichen KI-Gateways gewähren.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Identitätsschlüssel anzeigen",
|
||||||
|
"virtualApiKeys": "Virtuelle API-Schlüssel",
|
||||||
|
"virtualApiKeysSearch": "Schlüssel suchen...",
|
||||||
|
"virtualApiKeysCreate": "Virtuellen API-Schlüssel erstellen",
|
||||||
|
"virtualApiKeysCreateDescription": "Einen manuellen Schlüssel erstellen, der öffentliche KI-Gateways in dieser Organisation aufrufen kann",
|
||||||
|
"virtualApiKeysCreateButton": "Schlüssel erstellen",
|
||||||
|
"virtualApiKeysEmpty": "Noch keine virtuellen API-Schlüssel vorhanden",
|
||||||
|
"virtualApiKeysName": "Name",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Beschreibung (optional)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Benutzer zuordnen (optional)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Ordnen Sie diesen Schlüssel einem Benutzer zu, um die Nutzung zu verfolgen. Sobald erstellt, gewährt dieser Schlüssel sofort Zugriffe auf die ausgewählten öffentlichen KI-Gateways. Es ist nicht notwendig, manuell eine Verbindung zur Ressource herzustellen. Der Schlüssel wird auch im Benutzerprofil angezeigt.",
|
||||||
|
"virtualApiKeysAllResources": "Alle öffentlichen KI-Gateways",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Erlauben Sie diesem Schlüssel, auf jedes öffentliche KI-Gateway in der Organisation zuzugreifen",
|
||||||
|
"virtualApiKeysSelectResources": "Öffentliche KI-Gateways",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Ressourcen auswählen",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Wählen Sie aus, auf welche öffentlichen KI-Gateways dieser Schlüssel zugreifen kann",
|
||||||
|
"virtualApiKeysNoResources": "Keine Ressourcen",
|
||||||
|
"virtualApiKeysSecret": "Schlüssel",
|
||||||
|
"virtualApiKeysCopyKey": "Kopieren Sie diesen Schlüssel. Sie können ihn später aus der Tabelle oder beim Bearbeiten erneut anzeigen.",
|
||||||
|
"virtualApiKeysViewSecret": "Geheimnis anzeigen",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Virtueller API-Schlüsselgeheimnis",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Dieses Geheimnis gewährt Zugang zu den öffentlichen KI-Gateways, die diesem Schlüssel zugewiesen sind",
|
||||||
|
"virtualApiKeysEdit": "Virtuellen API-Schlüssel bearbeiten",
|
||||||
|
"virtualApiKeysEditDescription": "Aktualisieren Sie den zugeordneten Benutzer und den Zugang zu öffentlichen KI-Gateways für diesen Schlüssel",
|
||||||
|
"virtualApiKeysSaveButton": "Änderungen speichern",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Wählen Sie mindestens ein öffentliches KI-Gateway aus oder aktivieren Sie alle öffentlichen KI-Gateways",
|
||||||
|
"virtualApiKeysUpdated": "Virtueller API-Schlüssel aktualisiert",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Der virtuelle API-Schlüssel wurde aktualisiert",
|
||||||
|
"virtualApiKeysErrorUpdate": "Fehler beim Aktualisieren des virtuellen API-Schlüssels",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Fehler beim Aktualisieren des virtuellen API-Schlüssels",
|
||||||
|
"virtualApiKeysErrorCreate": "Fehler beim Erstellen des virtuellen API-Schlüssels",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Fehler beim Erstellen des virtuellen API-Schlüssels",
|
||||||
|
"virtualApiKeysErrorDelete": "Fehler beim Löschen des virtuellen API-Schlüssels",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Fehler beim Löschen des virtuellen API-Schlüssels",
|
||||||
|
"virtualApiKeysDeleted": "Virtueller API-Schlüssel gelöscht",
|
||||||
|
"virtualApiKeysDeletedDescription": "Der virtuelle API-Schlüssel wurde gelöscht",
|
||||||
|
"virtualApiKeysDelete": "Virtuellen API-Schlüssel löschen",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Schlüssel löschen",
|
||||||
|
"virtualApiKeysQuestionRemove": "Sind Sie sicher, dass Sie diesen virtuellen API-Schlüssel löschen möchten?",
|
||||||
|
"virtualApiKeysMessageRemove": "Clients, die diesen Schlüssel verwenden, verlieren sofort den Zugriff.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Fehler beim Laden des Geheimnisses",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Fehler beim Laden des virtuellen API-Schlüsselgeheimnisses",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Unzugewiesen",
|
||||||
|
"virtualApiKeysInferenceBudget": "Budget",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Konfigurieren Sie, wie dieser Schlüssel die KI-Nutzung basierend auf Ausgaben oder Tokenlimits einschränkt",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "E-Mail-Schlüssel bei Erstellung",
|
||||||
|
"virtualApiKeysEmailThisKey": "Diesen Schlüssel per E-Mail senden",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Senden Sie den Schlüssel an den zugeordneten Benutzer und zusätzliche Adressen, nachdem er erstellt wurde",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Senden Sie den aktuellen Schlüssel an den zugeordneten Benutzer und zusätzliche Adressen",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "E-Mail ist auf diesem Server nicht konfiguriert",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Konfigurieren Sie SMTP, um virtuelle API-Schlüssel per E-Mail zu versenden.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "An den zugeordneten Benutzer senden",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Senden Sie den Schlüssel an die Kontoe-Mail des zugeordneten Benutzers",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Ordnen Sie einen Benutzer zu, um den Schlüssel an diesen Benutzer zu senden",
|
||||||
|
"virtualApiKeysEmailAdditional": "Zusätzliche E-Mails",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "E-Mail-Adresse hinzufügen und Enter drücken",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Wählen Sie den zugeordneten Benutzer aus oder fügen Sie mindestens eine E-Mail-Adresse hinzu",
|
||||||
|
"myVirtualApiKeysTitle": "Ihre API-Schlüssel",
|
||||||
|
"myVirtualApiKeysDescription": "Sehen Sie sich Ihren Identitätsschlüssel und alle Ihnen in dieser Organisation zugewiesenen virtuellen API-Schlüssel an",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Ihre API-Schlüssel für {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Sehen Sie sich Ihren Identitätsschlüssel und Ihnen zugewiesene virtuelle API-Schlüssel an, die auf {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Identitätsschlüssel",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Ihr persönlicher API-Schlüssel",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Ihr persönlicher Schlüssel für diese Organisation. Es ist einzigartig für Ihr Konto und wird verwendet, um Sie zu identifizieren, wenn Sie KI-Gateway-Ressourcen aufrufen.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Ihr persönlicher API-Schlüssel für {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Ihr persönlicher Schlüssel für diese Organisation. Verwenden Sie ihn, um {resourceName} anzurufen.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Zugewiesene Schlüssel",
|
||||||
|
"myVirtualApiKeysManualDescription": "Manuelle virtuelle API-Schlüssel, die ein Admin Ihrem Konto zugeordnet hat",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Manuelle virtuelle API-Schlüssel, die Ihrem Konto zugeordnet sind und auf {resourceName} zugreifen können",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Noch keine zugewiesenen Schlüssel vorhanden",
|
||||||
|
"myVirtualApiKeysKindUser": "Identität",
|
||||||
|
"myVirtualApiKeysKindManual": "Manuell",
|
||||||
|
"myVirtualApiKeysUnnamed": "Unbenannter Schlüssel",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Geheimnis offenlegen",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Dieses Geheimnis authentifiziert Sie zu KI-Gateway-Ressourcen",
|
||||||
|
"aiClientConfigTitle": "Coding-Agenten konfigurieren",
|
||||||
|
"aiClientConfigDescription": "Konfigurationsvorlage für beliebte Coding-Agenten kopieren oder lassen Sie das Pangolin-CLI es automatisch für Sie einrichten.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Agentisches Codierwerkzeug von Anthropic für das Terminal.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Agentisches Codierwerkzeug von OpenAI für das Terminal.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Open-Source-Coding-Agent für das Terminal.",
|
||||||
|
"aiClientConfigDescriptionCursor": "KI-Code-Editor basierend auf VS Code.",
|
||||||
|
"aiClientConfigSetup": "Einrichtung",
|
||||||
|
"aiClientConfigTabCli": "Automatisch (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Manuelle Konfiguration",
|
||||||
|
"aiClientConfigPreset": "Konfiguration",
|
||||||
|
"aiClientConfigStep": "Schritt {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Dieses Snippet enthält Beispielwerte, wie z. B. einen Modellnamen oder eine Ressourcen-URL. Ersetzen Sie sie vor der Verwendung durch Ihre eigenen.",
|
||||||
|
"aiClientConfigRevealError": "Ihr API-Schlüssel konnte nicht geladen werden.",
|
||||||
|
"aiClientConfigRevealRetry": "Versuchen Sie es erneut",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Diese Ressource kann von gängigen Clients wie Claude Code und OpenCode verwendet werden. <configLink>Erfahren Sie mehr</configLink>",
|
||||||
|
"aiProvidersTitle": "KI-Anbieter",
|
||||||
|
"aiProvidersDescription": "Modellanbieter für KI-Workloads in dieser Organisation verbinden",
|
||||||
|
"aiProvidersBannerTitle": "Modellanbieter verbinden",
|
||||||
|
"aiProvidersBannerDescription": "Anbieter sind die Modell-Backends, die Pangolin für KI-Workloads verwendet. Schließen Sie hier OpenAI, Anthropic und andere Anbieter an und ordnen Sie sie dann öffentlichen KI-Gateways zu, sodass Benutzer Modelle mit identitätsbewusstem Zugang, Budgets und Logging aufrufen können.",
|
||||||
|
"aiProvidersAdd": "Anbieter hinzufügen",
|
||||||
|
"aiProvidersSearch": "Anbieter suchen...",
|
||||||
|
"aiProvidersEmpty": "Noch keine KI-Anbieter vorhanden",
|
||||||
|
"aiProviderCreate": "KI-Anbieter erstellen",
|
||||||
|
"aiProviderCreateDescription": "Fügen Sie einen Modellanbieter für diese Organisation hinzu",
|
||||||
|
"aiProviderSeeAll": "Alle Anbieter anzeigen",
|
||||||
|
"aiProviderSetting": "Anbietereinstellungen für {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Konfigurieren Sie diesen KI-Anbieter",
|
||||||
|
"aiProviderGeneral": "Allgemein",
|
||||||
|
"aiProviderGeneralDescription": "Grundeinstellungen für diesen Anbieter",
|
||||||
|
"aiProviderConfiguration": "Konfiguration",
|
||||||
|
"aiProviderConfigurationDescription": "Netzwerk-Routing und Authentifizierung für diesen Anbieter",
|
||||||
|
"aiProviderNetworkSettings": "Netzwerkeinstellungen",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Wählen Sie aus, wie der Datenverkehr diesen Anbieter erreicht",
|
||||||
|
"aiProviderAuthSettings": "Authentifizierung",
|
||||||
|
"aiProviderAuthSettingsDescription": "Konfigurieren Sie, wie dieser Anbieter Anfragen an seine Upstream-URL authentifiziert",
|
||||||
|
"aiProviderBudgetSettings": "Budget",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Konfigurieren Sie, wie dieser Anbieter die Nutzung basierend auf Ausgabengrenzen oder Tokenlimits einschränkt",
|
||||||
|
"aiBudgetAdd": "Budget hinzufügen",
|
||||||
|
"aiBudgetEmpty": "Noch keine Budgets konfiguriert. Klicken Sie auf \"Budget hinzufügen\", um ein Ausgabe- oder Tokenlimit festzulegen.",
|
||||||
|
"aiBudgetUnit": "Ausgabetyp",
|
||||||
|
"aiBudgetPeriod": "Reset-Zeitraum",
|
||||||
|
"aiBudgetAmount": "Maximaler Verbrauch",
|
||||||
|
"aiBudgetAmountPlaceholder": "Maximaler Verbrauch",
|
||||||
|
"aiBudgetPeriodHourly": "Stündlich",
|
||||||
|
"aiBudgetPeriodDaily": "Täglich",
|
||||||
|
"aiBudgetPeriodWeekly": "Wöchentlich",
|
||||||
|
"aiBudgetPeriodMonthly": "Monatlich",
|
||||||
|
"aiBudgetPeriodYearly": "Jährlich",
|
||||||
|
"aiBudgetPeriodLifetime": "Lebenslang",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Token",
|
||||||
|
"aiBudgetConflictError": "Ein Budget für diesen Reset-Zeitraum und Ausgabetyp existiert bereits",
|
||||||
|
"aiBudgetInvalidAmountError": "Geben Sie einen maximalen Verbrauch größer als 0 ein",
|
||||||
|
"aiBudgetUpdated": "Budgets aktualisiert",
|
||||||
|
"aiBudgetErrorSave": "Fehler beim Aktualisieren der Budgets",
|
||||||
|
"aiProviderType": "Anbietertyp",
|
||||||
|
"aiProviderTypeSearch": "Anbieter suchen...",
|
||||||
|
"aiProviderTypeNotFound": "Kein Anbietertyp gefunden",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "Benutzerdefiniert",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI-API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic-API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Runtime API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "Verwenden Sie Ihren eigenen Endpoint oder leiten Sie über Seitentargets",
|
||||||
|
"aiProviderUpstreamUrl": "Upstream-URL",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Basis-URL für die Provider-API",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Leer lassen, um die Standard-Upstream-URL für diesen Anbieter zu verwenden",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Effektive Upstream-URL",
|
||||||
|
"aiProviderApiKey": "API-Schlüssel",
|
||||||
|
"aiProviderApiKeyDescription": "API-Schlüssel, der zur Authentifizierung von Anfragen an diesen Anbieter verwendet wird",
|
||||||
|
"aiProviderCustomHeadersDescription": "Header werden bei jeder Anfrage an diesen Anbieter gesendet. Neue Zeile getrennt: Header-Name: Wert",
|
||||||
|
"aiProviderApiKeyLastChars": "API-Schlüssel",
|
||||||
|
"aiProviderAuthType": "Auth-Typ",
|
||||||
|
"aiProviderAuthTypeSearch": "Auth-Typen durchsuchen...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Kein Auth-Typ gefunden",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Autorisierung: Bearer-Schlüssel. Wird von OpenAI und den meisten Anbietern verwendet",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-key-Header. Wird von Anthropic verwendet",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-key-Header. Wird von Google Gemini verwendet",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Autorisierung: Splunk-Schlüssel. Wird vom Splunk HTTP-Ereignissammler verwendet",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Bearer-Schlüssel. Wird vom Cloudflare AI Gateway verwendet",
|
||||||
|
"aiProviderAuthTypeNone": "Keine Auth",
|
||||||
|
"aiProviderAuthTypePassthrough": "Passthrough",
|
||||||
|
"aiProviderAuthTypeDescription": "Wie die Upstream-API Anfragen authentifiziert",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Leiten Sie die API-Schlüssel-Header des Anrufers an den Upstream weiter",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Keine Authentifizierungs-Header an den Upstream senden",
|
||||||
|
"aiProviderRoutingMode": "Routing-Modus",
|
||||||
|
"aiProviderRoutingModeDescription": "Senden Sie Traffic an eine Upstream-URL oder an HTTP-Ziele auf Ihren Sites",
|
||||||
|
"aiProviderRoutingModeUrl": "Upstream-URL",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Rufen Sie eine öffentliche oder private API-Basis-URL auf",
|
||||||
|
"aiProviderRoutingModeTarget": "Site-Ziele",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Über Ziele auf Ihren Sites routen",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Konfigurieren Sie nach der Erstellung dieses Anbieters Site-Ziele auf der Registerkarte 'Netzwerkeinstellungen'.",
|
||||||
|
"aiProviderTargetNoOne": "Dieser Anbieter hat keine Ziele. Fügen Sie ein Ziel hinzu, um Anfragen über Ihre Sites zu leiten.",
|
||||||
|
"aiProviderSkipTlsVerification": "TLS-Überprüfung überspringen",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "TLS-Zertifikatsüberprüfung für die Upstream-Verbindung deaktivieren",
|
||||||
|
"aiProviderBudget": "Budget",
|
||||||
|
"aiProviderBudgetDescription": "Optionales Ausgaben- oder Token-Budget für diesen Anbieter",
|
||||||
|
"aiProviderBudgetAmount": "Budgetbetrag",
|
||||||
|
"aiProviderBudgetUnit": "Budgeteinheit",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Token",
|
||||||
|
"aiProviderEnabled": "Aktiviert",
|
||||||
|
"aiProviderEnabledDescription": "Diesen Anbieter für alle Ressourcen vollständig deaktivieren",
|
||||||
|
"aiProviderErrorCreate": "Fehler beim Erstellen des KI-Anbieters",
|
||||||
|
"aiProviderErrorUpdate": "Fehler beim Aktualisieren des KI-Anbieters",
|
||||||
|
"aiProviderErrorDelete": "Fehler beim Löschen des KI-Anbieters",
|
||||||
|
"aiProviderErrorLoad": "Fehler beim Laden des KI-Anbieters",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Geben Sie eine gültige Upstream-URL ein",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Upstream-URL ist für diesen Anbieter erforderlich",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Auth-Typ ist erforderlich",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API-Schlüssel ist erforderlich",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Routen von Site-Zielen ist nur für benutzerdefinierte Anbieter verfügbar",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Wählen Sie mindestens eine API-Funktion aus",
|
||||||
|
"aiProviderCapabilities": "API-Funktionen",
|
||||||
|
"aiProviderCapabilitiesDescription": "Wählen Sie aus, welche API-Formate dieser Anbieter verarbeiten kann. Bekannte Anbieter beginnen mit empfohlenen Standardeinstellungen.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Wählen Sie aus, welche API-Formate dieser benutzerdefinierte Anbieter verarbeiten kann",
|
||||||
|
"aiProviderCapabilitiesSelect": "Fähigkeiten auswählen",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Keine Fähigkeiten gefunden",
|
||||||
|
"aiProviderCapabilitiesSearch": "Fähigkeiten suchen...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Chat-Abschlüsse",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Unterstützt /v1/chat/Abschlüsse",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI Antworten",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Unterstützt /v1/antworten",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic Nachrichten",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Unterstützt /v1/nachrichten",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini Inhalt erzeugen",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Unterstützt die direkte Gemini-API",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Bedrock Modell Aufruf",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Unterstützt Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex Inhalt erzeugen",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Unterstützt Vertex AI Gemini-Format",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex Rohvorhersage",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Unterstützt Vertex AI rawPredict für Anthropic-Modelle",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock Gespräch",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Unterstützt Amazon Bedrock Converse API",
|
||||||
|
"aiProviderCreated": "KI-Anbieter erstellt",
|
||||||
|
"aiProviderUpdated": "KI-Anbieter aktualisiert",
|
||||||
|
"aiProviderDeleted": "KI-Anbieter gelöscht",
|
||||||
|
"aiProviderDelete": "Anbieter löschen",
|
||||||
|
"aiProviderDeleteConfirm": "Anbieter löschen",
|
||||||
|
"aiProviderQuestionRemove": "Sind Sie sicher, dass Sie diesen KI-Anbieter löschen möchten?",
|
||||||
|
"aiProviderMessageRemove": "Dadurch wird der Anbieter und seine Modelle und Ziele dauerhaft gelöscht. Dies kann nicht rückgängig gemacht werden.",
|
||||||
|
"aiProviderErrorNoUpdate": "KI-Anbieter ist nicht verfügbar zur Aktualisierung",
|
||||||
|
"aiProviderModels": "Modelle",
|
||||||
|
"aiProviderModelsDescription": "Definieren Sie Zulassungs- und Sperrlisten für diesen Anbieter. Anfragen müssen mit einem erlaubten Eintrag übereinstimmen und dürfen keinen gesperrten Eintrag treffen.",
|
||||||
|
"aiProviderCreateModelsDescription": "Wählen Sie aus, welche Modelle dieser Anbieter bedienen kann. Eine leere Zulassungsliste verweigert den gesamten Datenverkehr. Sie können später Modelle hinzufügen oder ändern.",
|
||||||
|
"aiProviderModelsPlaceholder": "Modelle suchen oder einen benutzerdefinierten Schlüssel eingeben",
|
||||||
|
"aiProviderModelsAllow": "Zulassungsliste",
|
||||||
|
"aiProviderModelsAllowDescription": "Modelle, die durch diesen Anbieter genutzt werden können. Leer bedeutet, alles verweigern.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Modellschlüssel eingeben",
|
||||||
|
"aiProviderModelsAllowEmpty": "Noch keine Modelle hinzugefügt.",
|
||||||
|
"aiProviderModelsBlock": "Sperrliste",
|
||||||
|
"aiProviderModelsBlockDescription": "Modelle, die selbst dann verweigert werden, wenn sie mit einem erlaubten Eintrag übereinstimmen.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Modellschlüssel eingeben",
|
||||||
|
"aiProviderModelsBlockEmpty": "Noch keine Modelle hinzugefügt.",
|
||||||
|
"aiProviderModelsAdd": "Modelle hinzufügen",
|
||||||
|
"aiProviderModelsClearAll": "Alle löschen",
|
||||||
|
"aiProviderModelsAddCustom": "\"{key}\" hinzufügen",
|
||||||
|
"aiProviderModelsAddCustomHint": "Drücken Sie die Eingabetaste, um diesen benutzerdefinierten Modellschlüssel hinzuzufügen.",
|
||||||
|
"aiProviderModelsAddBulk": "{count} benutzerdefinierte Schlüssel hinzufügen",
|
||||||
|
"aiProviderModelsAddBulkHint": "Drücken Sie die Eingabetaste, um {count} benutzerdefinierte Schlüssel hinzuzufügen.",
|
||||||
|
"aiProviderModelsAddOne": "{key} jetzt hinzufügen",
|
||||||
|
"aiProviderModelsAddSelected": "Ausgewählte hinzufügen",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} ausgewählt",
|
||||||
|
"aiProviderModelsSelectAll": "Alle auswählen",
|
||||||
|
"aiProviderModelsClearSelected": "Löschen",
|
||||||
|
"aiProviderModelsBulkHint": "Wählen Sie bekannte Modelle aus oder geben Sie einen benutzerdefinierten Schlüssel ein.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Keine passenden Katalogmodelle.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Bekannte Modelle",
|
||||||
|
"aiProviderModelsAllLabel": "Alle Modelle",
|
||||||
|
"aiProviderModelsAllPatternHint": "Platzhalterzeichen: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Alle Modelle erlauben",
|
||||||
|
"aiProviderModelsAddAllBlock": "Alle Modelle blockieren",
|
||||||
|
"aiProviderModelsAddAllDescription": "Verwendet das Platzhalterzeichen *, sodass jeder Modellschlüssel übereinstimmt.",
|
||||||
|
"aiProviderModelsViewMore": "Mehr anzeigen ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Weniger anzeigen",
|
||||||
|
"aiProviderModelsRemove": "Modell entfernen",
|
||||||
|
"aiProviderModelsEditHint": "Klicken Sie zum Bearbeiten der Modelleinstellungen",
|
||||||
|
"aiProviderModelsSourceCatalog": "Bekannte Katalogmodelle",
|
||||||
|
"aiProviderModelsSourceCustom": "Benutzerdefinierter Modellschlüssel",
|
||||||
|
"aiProviderModelsSourcePattern": "Wildcardschlüssel",
|
||||||
|
"aiProviderModelsSourceAll": "Übereinstimmung mit jedem Modellschlüssel",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Budget konfiguriert",
|
||||||
|
"aiProviderModelsEditTitle": "Modell bearbeiten",
|
||||||
|
"aiProviderModelsEditDescription": "Aktualisieren Sie den Modellschlüssel oder konfigurieren Sie sein Budget.",
|
||||||
|
"aiProviderModelsBudgetTab": "Budget",
|
||||||
|
"aiProviderModelsKeyLabel": "Modellschlüssel",
|
||||||
|
"aiProviderModelsKeyRequired": "Modellschlüssel eingeben",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Dieser Modellschlüssel befindet sich bereits auf einer Liste",
|
||||||
|
"aiProviderModelsOverlapError": "Diese Muster können nicht auf beiden Listen sein: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modelle aktualisiert",
|
||||||
|
"aiProviderModelsErrorUpdate": "Fehler beim Aktualisieren der Modelle",
|
||||||
|
"aiResourceProviders": "Anbieter",
|
||||||
|
"aiResourceProvidersDescription": "Wählen Sie, welche KI-Anbieter dieses KI-Gateway verwenden kann",
|
||||||
|
"aiResourceProvidersHelp": "Fügen Sie Anbieter an und wählen Sie Vererben (Verwendung der Liste des jeweiligen Anbieters) oder auswählen (Wählen Sie eine Zulassungsliste für diese Ressource). Erlaubte Muster, die bei angehängten Anbietern Konflikte verursachen, sind nicht erlaubt.",
|
||||||
|
"aiResourceProvidersSelect": "Anbieter auswählen",
|
||||||
|
"aiResourceProvidersEmpty": "Keine KI-Anbieter gefunden",
|
||||||
|
"aiResourceProvidersNoneAttached": "Noch keine Anbieter angehängt.",
|
||||||
|
"aiResourceProvidersAdd": "Anbieter hinzufügen",
|
||||||
|
"aiResourceProvidersRemove": "Anbieter entfernen",
|
||||||
|
"aiResourceProviderToggleEnabled": "Aktivieren oder Deaktivieren Sie diesen Anbieter auf der Ressource",
|
||||||
|
"aiResourceProviderDisabled": "Deaktiviert",
|
||||||
|
"aiResourceProvidersUpdated": "Anbieter aktualisiert",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Anbieter konnten nicht aktualisiert werden",
|
||||||
|
"aiResourceProviderEditDescription": "Wählen Sie aus, wie die Modelle dieses Anbieters auf dieser Ressource dargestellt werden.",
|
||||||
|
"viewProviderSettings": "Anbietereinstellungen anzeigen",
|
||||||
|
"aiResourceProviderMode": "Zugriffsmodus",
|
||||||
|
"aiResourceProviderModeInherit": "Vererben",
|
||||||
|
"aiResourceProviderModeSelect": "Auswählen",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Auswählen · {count} Modelle",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Verwenden Sie die Zulassungs- und Sperrlisten dieses Anbieters, wie sie am Anbieter konfiguriert sind.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Wählen Sie ein Teilset von Modellen der Zulassungsliste dieses Anbieters für diese Ressource.",
|
||||||
|
"aiResourceProviderAllowModels": "Zulassungsliste",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Modelle auswählen",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Modelle suchen...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Keine Modelle gefunden",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Es können nur Modelle aus der Zulassungsliste dieses Anbieters ausgewählt werden.",
|
||||||
|
"aiResourceAliasRequired": "Alias ist für KI-Gateways erforderlich",
|
||||||
|
"aiResourceDomainConfiguration": "Domain-Konfiguration",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Wählen Sie die Domain aus, die Clients verwenden sollen, um dieses KI-Gateway zu erreichen.",
|
||||||
|
"aiUsageAnalyticsTitle": "KI Nutzungsanalyse",
|
||||||
|
"aiUsageAnalyticsDescription": "Analysieren Sie die Kosten, die Token-Nutzung und die Aktivität des KI-Gateways über Anbieter, Ressourcen, Rollen und Benutzer hinweg",
|
||||||
|
"aiUsageTabOverview": "Überblick",
|
||||||
|
"aiUsageTabProviders": "Anbieter",
|
||||||
|
"aiUsageTabResources": "Ressourcen",
|
||||||
|
"aiUsageFilterProvider": "Anbieter",
|
||||||
|
"aiUsageFilterModel": "Modell",
|
||||||
|
"aiUsageFilterResource": "Ressource",
|
||||||
|
"aiUsageFilterRole": "Rolle",
|
||||||
|
"aiUsageFilterUser": "Benutzer",
|
||||||
|
"aiUsageFilterAllProviders": "Alle Anbieter",
|
||||||
|
"aiUsageFilterAllModels": "Alle Modelle",
|
||||||
|
"aiUsageFilterAllResources": "Alle Ressourcen",
|
||||||
|
"aiUsageFilterAllRoles": "Alle Rollen",
|
||||||
|
"aiUsageFilterAllUsers": "Alle Benutzer",
|
||||||
|
"aiUsageFilterSearch": "Suche...",
|
||||||
|
"aiUsageFilterNotFound": "Keine Optionen gefunden",
|
||||||
|
"aiUsageResetFilters": "Filter zurücksetzen",
|
||||||
|
"aiUsageRefresh": "Aktualisieren",
|
||||||
|
"aiUsageTokenTypePrompt": "Aufforderung",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Cache-Lesezugriff",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Cache-Schreibzugriff",
|
||||||
|
"aiUsageTokenTypeCompletion": "Abschluss",
|
||||||
|
"aiUsageTokenTypeReasoning": "Logik",
|
||||||
|
"aiUsageRequests": "Anfragen",
|
||||||
|
"aiUsageCost": "Kosten",
|
||||||
|
"aiUsageTokens": "Token",
|
||||||
|
"aiUsageOther": "Andere",
|
||||||
|
"aiUsageTotalRequests": "Gesamtanfragen",
|
||||||
|
"aiUsageTotalTokens": "Gesamttoken",
|
||||||
|
"aiUsageTotalCost": "Gesamtkosten",
|
||||||
|
"aiUsageEstimated": "Geschätzt",
|
||||||
|
"aiUsageRequestVolume": "Anfragevolumen",
|
||||||
|
"aiUsageTokenUsage": "Token-Nutzung",
|
||||||
|
"aiUsageModelCost": "Modellkosten",
|
||||||
|
"aiUsageModelTokens": "Modell-Token",
|
||||||
|
"aiUsageTopModels": "Top-Modelle",
|
||||||
|
"aiUsageTopProviders": "Top-Anbieter",
|
||||||
|
"aiUsageProviderCost": "Anbieterkosten",
|
||||||
|
"aiUsageProviderTokenUsage": "Anbieter-Token-Nutzung",
|
||||||
|
"aiUsageTopResources": "Top-Ressourcen",
|
||||||
|
"aiUsageResourceCost": "Ressourcenkosten",
|
||||||
|
"aiUsageResourceTokenUsage": "Ressourcen-Token-Nutzung",
|
||||||
|
"aiUsageResourceTypePublic": "Öffentliche Ressource",
|
||||||
|
"aiUsageResourceTypeSite": "Private Ressource",
|
||||||
|
"aiUsageNoResource": "Keine Ressource",
|
||||||
|
"aiUsageRolesTab": "Rollen",
|
||||||
|
"aiUsageUsersTab": "Benutzer",
|
||||||
|
"aiUsageTopRoles": "Top-Rollen",
|
||||||
|
"aiUsageRoleCost": "Rollen-Kosten",
|
||||||
|
"aiUsageRoleTokenUsage": "Rollen-Token-Nutzung",
|
||||||
|
"aiUsageTopUsers": "Top-Benutzer",
|
||||||
|
"aiUsageUserCost": "Benutzerkosten",
|
||||||
|
"aiUsageUserTokenUsage": "Benutzer-Token-Nutzung",
|
||||||
|
"aiUsageUnknownUser": "Unbekannter Benutzer",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Virtuelle API-Schlüssel",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Virtueller API-Schlüssel",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Alle virtuellen API-Schlüssel",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Top virtuelle API-Schlüssel",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Virtueller API-Schlüssel Kost",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Virtuelle API-Schlüssel Token-Nutzung",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Kein virtueller API-Schlüssel",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Unbenannter Schlüssel",
|
||||||
|
"aiUsageLoading": "Laden...",
|
||||||
|
"aiUsageNoData": "Keine Daten",
|
||||||
|
"resourceBudgetSettings": "Budget",
|
||||||
|
"resourceBudgetSettingsDescription": "Konfigurieren Sie, wie dieses KI-Gateway die Nutzung basierend auf Ausgabe- oder Token-Limits einschränkt",
|
||||||
"sidebarApiKeys": "API-Schlüssel",
|
"sidebarApiKeys": "API-Schlüssel",
|
||||||
"sidebarProvisioning": "Bereitstellung",
|
"sidebarProvisioning": "Bereitstellung",
|
||||||
"sidebarSettings": "Einstellungen",
|
"sidebarSettings": "Einstellungen",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Benachrichtigungsregel gespeichert",
|
"alertingRuleSaved": "Benachrichtigungsregel gespeichert",
|
||||||
"alertingRuleSavedCreatedDescription": "Ihre neue Benachrichtigungsregel wurde erstellt. Sie können sie auf dieser Seite weiter bearbeiten.",
|
"alertingRuleSavedCreatedDescription": "Ihre neue Benachrichtigungsregel wurde erstellt. Sie können sie auf dieser Seite weiter bearbeiten.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Ihre Änderungen an dieser Benachrichtigungsregel wurden gespeichert.",
|
"alertingRuleSavedUpdatedDescription": "Ihre Änderungen an dieser Benachrichtigungsregel wurden gespeichert.",
|
||||||
|
"alertingTestAlertSent": "Testwarnung gesendet",
|
||||||
|
"alertingTestAlertSentDescription": "Eine Testwarnung wurde an die auf dieser Regel konfigurierten Aktionen gesendet.",
|
||||||
"alertingEditRule": "Benachrichtigungsregel bearbeiten",
|
"alertingEditRule": "Benachrichtigungsregel bearbeiten",
|
||||||
"alertingCreateRule": "Benachrichtigungsregel erstellen",
|
"alertingCreateRule": "Benachrichtigungsregel erstellen",
|
||||||
"alertingRuleCredenzaDescription": "Wählen Sie aus, was beobachtet, wann ausgelöst und wie benachrichtigt werden soll",
|
"alertingRuleCredenzaDescription": "Wählen Sie aus, was beobachtet, wann ausgelöst und wie benachrichtigt werden soll",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Jede Regel verknüpft, was beobachtet werden soll (eine Seite, ein Gesundheits-Check oder eine Ressource), wann es ausgelöst werden soll (zum Beispiel offline oder ungesund), und wie Ihr Team benachrichtigt wird, z. B. per E-Mail, Webhooks oder Integrationen. Verwenden Sie diese Liste, um diese Regeln zu erstellen, zu aktivieren und zu verwalten.",
|
"alertingRulesBannerDescription": "Jede Regel verknüpft, was beobachtet werden soll (eine Seite, ein Gesundheits-Check oder eine Ressource), wann es ausgelöst werden soll (zum Beispiel offline oder ungesund), und wie Ihr Team benachrichtigt wird, z. B. per E-Mail, Webhooks oder Integrationen. Verwenden Sie diese Liste, um diese Regeln zu erstellen, zu aktivieren und zu verwalten.",
|
||||||
"alertingHealthChecksBannerTitle": "Gesundheit & Ressourcen überwachen",
|
"alertingHealthChecksBannerTitle": "Gesundheit & Ressourcen überwachen",
|
||||||
"alertingHealthChecksBannerDescription": "Gesundheits-Checks sind HTTP- oder TCP-Monitore, die Sie einmal definieren. Sie können sie dann als Quellen in Benachrichtigungsregeln verwenden, so dass Sie benachrichtigt werden, wenn ein Ziel gesund oder ungesund wird. Gesundheits-Checks für Ressourcen erscheinen ebenfalls hier.",
|
"alertingHealthChecksBannerDescription": "Gesundheits-Checks sind HTTP- oder TCP-Monitore, die Sie einmal definieren. Sie können sie dann als Quellen in Benachrichtigungsregeln verwenden, so dass Sie benachrichtigt werden, wenn ein Ziel gesund oder ungesund wird. Gesundheits-Checks für Ressourcen erscheinen ebenfalls hier.",
|
||||||
|
"alertingTestRule": "Testwarnregel",
|
||||||
|
"alertingAddActionHeading": "Neue Aktion hinzufügen",
|
||||||
|
"alertingSelectActionType": "Wählen Sie eine Aktion aus",
|
||||||
|
"alertingNoActionsTitle": "Keine Aktionen konfiguriert",
|
||||||
|
"alertingNoActionsSaveDescription": "Fügen Sie mindestens eine Aktion hinzu, damit diese Regel jemanden benachrichtigen kann, wenn sie ausgelöst wird.",
|
||||||
|
"alertingNoActionsTestDescription": "Fügen Sie mindestens eine Aktion hinzu, bevor Sie diese Regel testen können.",
|
||||||
"standaloneHcTableTitle": "Gesundheits-Checks",
|
"standaloneHcTableTitle": "Gesundheits-Checks",
|
||||||
"standaloneHcSearchPlaceholder": "Gesundheits-Checks suchen…",
|
"standaloneHcSearchPlaceholder": "Gesundheits-Checks suchen…",
|
||||||
"standaloneHcAddButton": "Gesundheits-Check erstellen",
|
"standaloneHcAddButton": "Gesundheits-Check erstellen",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Subdomain: {subdomain}",
|
"domainPickerSubdomain": "Subdomain: {subdomain}",
|
||||||
"domainPickerNamespace": "Namespace: {namespace}",
|
"domainPickerNamespace": "Namespace: {namespace}",
|
||||||
"domainPickerShowMore": "Mehr anzeigen",
|
"domainPickerShowMore": "Mehr anzeigen",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Keine Domains verfügbar",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Sie haben noch keine Domains eingerichtet. Erstellen Sie eine Domain, um fortzufahren.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Zu Domains wechseln",
|
||||||
"regionSelectorTitle": "Region auswählen",
|
"regionSelectorTitle": "Region auswählen",
|
||||||
"domainPickerRemoteExitNodeWarning": "Angegebene Domains werden nicht unterstützt, wenn sich Websites mit externen Exit-Knoten verbinden. Damit Ressourcen auf entfernten Knoten verfügbar sind, verwenden Sie stattdessen eine eigene Domain.",
|
"domainPickerRemoteExitNodeWarning": "Angegebene Domains werden nicht unterstützt, wenn sich Websites mit externen Exit-Knoten verbinden. Damit Ressourcen auf entfernten Knoten verfügbar sind, verwenden Sie stattdessen eine eigene Domain.",
|
||||||
"regionSelectorInfo": "Das Auswählen einer Region hilft uns, eine bessere Leistung für Ihren Standort bereitzustellen. Sie müssen sich nicht in derselben Region wie Ihr Server befinden.",
|
"regionSelectorInfo": "Das Auswählen einer Region hilft uns, eine bessere Leistung für Ihren Standort bereitzustellen. Sie müssen sich nicht in derselben Region wie Ihr Server befinden.",
|
||||||
@@ -1989,7 +2483,7 @@
|
|||||||
"billingSites": "Standorte",
|
"billingSites": "Standorte",
|
||||||
"billingUsers": "Benutzergeräte",
|
"billingUsers": "Benutzergeräte",
|
||||||
"billingDomains": "Domänen",
|
"billingDomains": "Domänen",
|
||||||
"billingOrganizations": "Orden",
|
"billingOrganizations": "Organisationen",
|
||||||
"billingRemoteExitNodes": "Entfernte Knoten",
|
"billingRemoteExitNodes": "Entfernte Knoten",
|
||||||
"billingPublicResources": "Öffentliche Ressourcen",
|
"billingPublicResources": "Öffentliche Ressourcen",
|
||||||
"billingPrivateResources": "Private Ressourcen",
|
"billingPrivateResources": "Private Ressourcen",
|
||||||
@@ -2149,7 +2643,7 @@
|
|||||||
"billingResolvePaymentIssue": "Bitte beheben Sie Ihr Zahlungsproblem vor dem Upgrade oder Herabstufen",
|
"billingResolvePaymentIssue": "Bitte beheben Sie Ihr Zahlungsproblem vor dem Upgrade oder Herabstufen",
|
||||||
"signUpTerms": {
|
"signUpTerms": {
|
||||||
"IAgreeToThe": "Ich stimme den",
|
"IAgreeToThe": "Ich stimme den",
|
||||||
"termsOfService": "Nutzungsbedingungen zu",
|
"termsOfService": "Nutzungsbedingungen",
|
||||||
"and": "und",
|
"and": "und",
|
||||||
"privacyPolicy": "datenschutzrichtlinie."
|
"privacyPolicy": "datenschutzrichtlinie."
|
||||||
},
|
},
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Subnetz",
|
"subnetPlaceholder": "Subnetz",
|
||||||
"addressDescription": "Die interne Adresse des Clients. Muss in das Subnetz der Organisation fallen.",
|
"addressDescription": "Die interne Adresse des Clients. Muss in das Subnetz der Organisation fallen.",
|
||||||
"selectSites": "Standorte auswählen",
|
"selectSites": "Standorte auswählen",
|
||||||
|
"selectResources": "Ressourcen auswählen",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# Ressource} other {# Ressourcen}}",
|
||||||
"selectLabels": "Etiketten auswählen",
|
"selectLabels": "Etiketten auswählen",
|
||||||
"sitesDescription": "Der Client wird zu den ausgewählten Standorten eine Verbindung haben.",
|
"sitesDescription": "Der Client wird zu den ausgewählten Standorten eine Verbindung haben.",
|
||||||
"clientInstallOlm": "Olm installieren",
|
"clientInstallOlm": "Olm installieren",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Zeit ist in Sekunden",
|
"timeIsInSeconds": "Zeit ist in Sekunden",
|
||||||
"requireDeviceApproval": "Gerätegenehmigungen erforderlich",
|
"requireDeviceApproval": "Gerätegenehmigungen erforderlich",
|
||||||
"requireDeviceApprovalDescription": "Benutzer mit dieser Rolle benötigen neue Geräte, die von einem Administrator genehmigt wurden, bevor sie sich verbinden und auf Ressourcen zugreifen können.",
|
"requireDeviceApprovalDescription": "Benutzer mit dieser Rolle benötigen neue Geräte, die von einem Administrator genehmigt wurden, bevor sie sich verbinden und auf Ressourcen zugreifen können.",
|
||||||
"sshSettings": "SSH-Einstellungen",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "KI-Gateway",
|
||||||
"sshAccess": "SSH Zugriff",
|
"sshAccess": "SSH Zugriff",
|
||||||
"rdpSettings": "RDP-Einstellungen",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "VNC-Einstellungen",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH-Server",
|
"sshServer": "SSH-Server",
|
||||||
"rdpServer": "RDP-Server",
|
"rdpServer": "RDP-Server",
|
||||||
"vncServer": "VNC-Server",
|
"vncServer": "VNC-Server",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Öffentlich",
|
"resourcesTableProxyResources": "Öffentlich",
|
||||||
"resourcesTableClientResources": "Privat",
|
"resourcesTableClientResources": "Privat",
|
||||||
"resourcesTableNoProxyResourcesFound": "Keine Proxy-Ressourcen gefunden.",
|
"resourcesTableNoProxyResourcesFound": "Keine Proxy-Ressourcen gefunden.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Keine internen Ressourcen gefunden.",
|
"resourcesTableNoInternalResourcesFound": "Keine privaten Ressourcen gefunden.",
|
||||||
"resourcesTableDestination": "Ziel",
|
"resourcesTableDestination": "Ziel",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Alias-Adresse",
|
"resourcesTableAliasAddress": "Alias-Adresse",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Abbrechen",
|
"editInternalResourceDialogCancel": "Abbrechen",
|
||||||
"editInternalResourceDialogSaveResource": "Ressource speichern",
|
"editInternalResourceDialogSaveResource": "Ressource speichern",
|
||||||
"editInternalResourceDialogSuccess": "Erfolg",
|
"editInternalResourceDialogSuccess": "Erfolg",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interne Ressource erfolgreich aktualisiert",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private Ressource erfolgreich aktualisiert",
|
||||||
"editInternalResourceDialogError": "Fehler",
|
"editInternalResourceDialogError": "Fehler",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Interne Ressource konnte nicht aktualisiert werden",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Fehler beim Aktualisieren der privaten Ressource",
|
||||||
"editInternalResourceDialogNameRequired": "Name ist erforderlich",
|
"editInternalResourceDialogNameRequired": "Name ist erforderlich",
|
||||||
"editInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
|
"editInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
|
||||||
"editInternalResourceDialogProxyPortMin": "Proxy-Port muss mindestens 1 sein",
|
"editInternalResourceDialogProxyPortMin": "Proxy-Port muss mindestens 1 sein",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "KI-Gateway",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Schema",
|
"editInternalResourceDialogScheme": "Schema",
|
||||||
"editInternalResourceDialogEnableSsl": "TLS aktivieren",
|
"editInternalResourceDialogEnableSsl": "TLS aktivieren",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Ein optionaler interner DNS-Alias für diese Ressource.",
|
"editInternalResourceDialogAliasDescription": "Ein optionaler interner DNS-Alias für diese Ressource.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Kein Standort verfügbar",
|
"createInternalResourceDialogNoSitesAvailable": "Kein Standort verfügbar",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Sie müssen mindestens ein Newt-Standort mit einem konfigurierten Subnetz haben, um interne Ressourcen zu erstellen.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Sie müssen mindestens eine Newt-Site mit einem konfigurierten Subnetz haben, um private Ressourcen zu erstellen.",
|
||||||
"createInternalResourceDialogClose": "Schließen",
|
"createInternalResourceDialogClose": "Schließen",
|
||||||
"createInternalResourceDialogCreateClientResource": "Private Ressource erstellen",
|
"createInternalResourceDialogCreateClientResource": "Private Ressource erstellen",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Erstelle eine neue Ressource, die nur für Clients zugänglich ist, die mit der Organisation verbunden sind",
|
"createInternalResourceDialogCreateClientResourceDescription": "Erstelle eine neue Ressource, die nur für Clients zugänglich ist, die mit der Organisation verbunden sind",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "ICMP-Ping zulassen",
|
"privateResourceAllowIcmpPing": "ICMP-Ping zulassen",
|
||||||
"privateResourceNetworkAccess": "Netzwerkzugriff",
|
"privateResourceNetworkAccess": "Netzwerkzugriff",
|
||||||
"privateResourceNetworkAccessDescription": "TCP/UDP-Portzugriff kontrollieren und ICMP-Ping für diese Ressource zulassen.",
|
"privateResourceNetworkAccessDescription": "TCP/UDP-Portzugriff kontrollieren und ICMP-Ping für diese Ressource zulassen.",
|
||||||
"hostSettings": "Host-Einstellungen",
|
"hostSettings": "Host",
|
||||||
"cidrSettings": "CIDR-Einstellungen",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Ressourceneigenschaften",
|
"createInternalResourceDialogResourceProperties": "Ressourceneigenschaften",
|
||||||
"createInternalResourceDialogName": "Name",
|
"createInternalResourceDialogName": "Name",
|
||||||
"createInternalResourceDialogSite": "Standort",
|
"createInternalResourceDialogSite": "Standort",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Abbrechen",
|
"createInternalResourceDialogCancel": "Abbrechen",
|
||||||
"createInternalResourceDialogCreateResource": "Ressource erstellen",
|
"createInternalResourceDialogCreateResource": "Ressource erstellen",
|
||||||
"createInternalResourceDialogSuccess": "Erfolg",
|
"createInternalResourceDialogSuccess": "Erfolg",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interne Ressource erfolgreich erstellt",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private Ressource erfolgreich erstellt",
|
||||||
"createInternalResourceDialogError": "Fehler",
|
"createInternalResourceDialogError": "Fehler",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Interne Ressource konnte nicht erstellt werden",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Fehler beim Erstellen der privaten Ressource",
|
||||||
"createInternalResourceDialogNameRequired": "Name ist erforderlich",
|
"createInternalResourceDialogNameRequired": "Name ist erforderlich",
|
||||||
"createInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
|
"createInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Bitte wählen Sie einen Standort aus",
|
"createInternalResourceDialogPleaseSelectSite": "Bitte wählen Sie einen Standort aus",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "KI-Gateway",
|
||||||
"scheme": "Schema",
|
"scheme": "Schema",
|
||||||
"createInternalResourceDialogScheme": "Schema",
|
"createInternalResourceDialogScheme": "Schema",
|
||||||
"createInternalResourceDialogEnableSsl": "TLS aktivieren",
|
"createInternalResourceDialogEnableSsl": "TLS aktivieren",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Gültiges Passwort",
|
"validPassword": "Gültiges Passwort",
|
||||||
"validEmail": "Gültige E-Mail-Adresse",
|
"validEmail": "Gültige E-Mail-Adresse",
|
||||||
"validSSO": "Gültige SSO-Anmeldung",
|
"validSSO": "Gültige SSO-Anmeldung",
|
||||||
|
"validVirtualAPIKey": "Gültiger virtueller API-Schlüssel",
|
||||||
"view": "Ansehen",
|
"view": "Ansehen",
|
||||||
"configManaged": "Konfiguration verwaltet",
|
"configManaged": "Konfiguration verwaltet",
|
||||||
"connectedClient": "Verbundenes Gerät",
|
"connectedClient": "Verbundenes Gerät",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Log-Speicherung",
|
"logRetention": "Log-Speicherung",
|
||||||
"logRetentionDescription": "Verwalten, wie lange verschiedene Logs für diese Organisation gespeichert werden oder deaktivieren",
|
"logRetentionDescription": "Verwalten, wie lange verschiedene Logs für diese Organisation gespeichert werden oder deaktivieren",
|
||||||
"requestLogsDescription": "Detaillierte Request-Logs für Ressourcen in dieser Organisation anzeigen",
|
"requestLogsDescription": "Detaillierte Request-Logs für Ressourcen in dieser Organisation anzeigen",
|
||||||
|
"aiSessionLogs": "AI-Gateway Sitzungsprotokolle",
|
||||||
|
"aiSessionLogsDescription": "Zeigen Sie Aufforderungs- und Antwortprotokolle für Anfragen des KI-Gateways in dieser Organisation an",
|
||||||
|
"sidebarLogsAi": "Sitzungsprotokolle",
|
||||||
|
"commandLogsAi": "Sitzungsprotokolle",
|
||||||
|
"sidebarLogsAiUsage": "Nutzungsanalyse",
|
||||||
|
"commandLogsAiUsage": "Nutzungsanalyse",
|
||||||
|
"provider": "Anbieter",
|
||||||
|
"capability": "Fähigkeit",
|
||||||
|
"model": "Modell",
|
||||||
|
"virtualApiKey": "Virtueller API-Schlüssel",
|
||||||
|
"noVirtualApiKey": "Kein virtueller API-Schlüssel",
|
||||||
|
"stream": "Strom",
|
||||||
|
"streaming": "Streaming",
|
||||||
|
"nonStreaming": "Nicht-Streaming",
|
||||||
|
"statusCode": "Statuscode",
|
||||||
|
"aiSessionId": "Sitzungs-ID",
|
||||||
|
"aiSessionRequest": "Anfrage",
|
||||||
|
"aiSessionResponse": "Antwort",
|
||||||
|
"aiSessionNoData": "Keine Daten erfasst",
|
||||||
|
"aiSessionCouldNotParse": "(Roh, Protokoll konnte nicht geparst werden)",
|
||||||
|
"aiSessionLogTruncated": "Diese Sitzung wurde vor der Speicherung abgeschnitten und könnte unvollständig sein.",
|
||||||
|
"aiSessionViewRaw": "Rohes JSON anzeigen",
|
||||||
|
"aiSessionViewChat": "Chat anzeigen",
|
||||||
|
"cost": "Kosten",
|
||||||
|
"estimated": "Geschätzt",
|
||||||
|
"tokenUsage": "Token-Nutzung",
|
||||||
|
"promptTokens": "Aufforderungstoken",
|
||||||
|
"cacheReadTokens": "Cache-Lese-Token",
|
||||||
|
"cacheWriteTokens": "Cache-Schreib-Token",
|
||||||
|
"completionTokens": "Abschlusstoken",
|
||||||
|
"reasoningTokens": "Logik-Token",
|
||||||
|
"totalTokens": "Gesamttoken",
|
||||||
"requestAnalyticsDescription": "Detaillierte Anfrage-Analyse für Ressourcen in dieser Organisation anzeigen",
|
"requestAnalyticsDescription": "Detaillierte Anfrage-Analyse für Ressourcen in dieser Organisation anzeigen",
|
||||||
"logRetentionRequestLabel": "HTTP Anforderungsprotokoll Aufbewahrung",
|
"logRetentionRequestLabel": "HTTP Anforderungsprotokoll Aufbewahrung",
|
||||||
"logRetentionRequestDescription": "Wie lange sollen Request-Logs gespeichert werden",
|
"logRetentionRequestDescription": "Wie lange sollen Request-Logs gespeichert werden",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Dauer des Action-Logs",
|
"logRetentionActionDescription": "Dauer des Action-Logs",
|
||||||
"logRetentionConnectionLabel": "Verbindungsprotokoll-Speicherung",
|
"logRetentionConnectionLabel": "Verbindungsprotokoll-Speicherung",
|
||||||
"logRetentionConnectionDescription": "Wie lange Verbindungsprotokolle gespeichert werden sollen",
|
"logRetentionConnectionDescription": "Wie lange Verbindungsprotokolle gespeichert werden sollen",
|
||||||
|
"logRetentionAISessionsLabel": "Aufbewahrung von Sitzungsprotokollen des KI-Gateways",
|
||||||
|
"logRetentionAISessionsDescription": "Wie lange Sitzunglogs von Aufforderung / Antwort des KI-Gateways aufbewahrt werden",
|
||||||
"logRetentionDisabled": "Deaktiviert",
|
"logRetentionDisabled": "Deaktiviert",
|
||||||
"logRetention3Days": "3 Tage",
|
"logRetention3Days": "3 Tage",
|
||||||
"logRetention7Days": "7 Tage",
|
"logRetention7Days": "7 Tage",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Quelladresse",
|
"sourceAddress": "Quelladresse",
|
||||||
"destinationAddress": "Zieladresse",
|
"destinationAddress": "Zieladresse",
|
||||||
"duration": "Dauer",
|
"duration": "Dauer",
|
||||||
"licenseRequiredToUse": "Eine <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> Lizenz oder <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> wird benötigt, um diese Funktion nutzen zu können. <bookADemoLink>Buchen Sie eine Demo oder POC Testversion</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Enterprise Edition Lizenz</enterpriseEditionLink> ist erforderlich. <bookADemoLink>Einen Test vorführen oder ausprobieren </bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "Die <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> wird benötigt, um diese Funktion nutzen zu können. Diese Funktion ist auch in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>verfügbar. <bookADemoLink>Buchen Sie eine Demo oder POC Testversion</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition Lizenz</enterpriseEditionLink> ist erforderlich. <bookADemoLink>Vereinbare eine Demo oder einen Test</bookADemoLink>",
|
||||||
"certResolver": "Zertifikatsauflöser",
|
"certResolver": "Zertifikatsauflöser",
|
||||||
"certResolverDescription": "Wählen Sie den Zertifikatslöser aus, der für diese Ressource verwendet werden soll.",
|
"certResolverDescription": "Wählen Sie den Zertifikatslöser aus, der für diese Ressource verwendet werden soll.",
|
||||||
"selectCertResolver": "Zertifikatsauflöser auswählen",
|
"selectCertResolver": "Zertifikatsauflöser auswählen",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Durch die Auswahl mehrerer Seiten wird ein ausfallsicheres Routing und Failover für hohe Verfügbarkeit ermöglicht.",
|
"internalResourceFormMultiSiteRoutingHelp": "Durch die Auswahl mehrerer Seiten wird ein ausfallsicheres Routing und Failover für hohe Verfügbarkeit ermöglicht.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Mehr erfahren",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Mehr erfahren",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Den Zugriff auf bestimmte TCP/UDP-Ports beschränken oder alle Ports erlauben/blockieren.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Den Zugriff auf bestimmte TCP/UDP-Ports beschränken oder alle Ports erlauben/blockieren.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "HTTP-Konfiguration",
|
"createInternalResourceDialogHttpConfiguration": "Domain-Konfiguration",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Wählen Sie die Domain, die Clients verwenden, um über HTTP oder HTTPS auf diese Ressource zuzugreifen.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Wählen Sie die Domain, die Clients verwenden, um über HTTP oder HTTPS auf diese Ressource zuzugreifen.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "HTTP-Konfiguration",
|
"editInternalResourceDialogHttpConfiguration": "Domain-Konfiguration",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Wählen Sie die Domain, die Clients verwenden, um über HTTP oder HTTPS auf diese Ressource zuzugreifen.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Wählen Sie die Domain, die Clients verwenden, um über HTTP oder HTTPS auf diese Ressource zuzugreifen.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3367,7 +3901,7 @@
|
|||||||
"enterMfaCode": "Geben Sie den Code aus Ihrer Authentifizierungs-App ein",
|
"enterMfaCode": "Geben Sie den Code aus Ihrer Authentifizierungs-App ein",
|
||||||
"securityKeyRequired": "Bitte verwenden Sie Ihren Sicherheitsschlüssel zum Anmelden.",
|
"securityKeyRequired": "Bitte verwenden Sie Ihren Sicherheitsschlüssel zum Anmelden.",
|
||||||
"needToUseAnotherAccount": "Benötigen Sie ein anderes Konto?",
|
"needToUseAnotherAccount": "Benötigen Sie ein anderes Konto?",
|
||||||
"loginLegalDisclaimer": "Indem Sie auf die Buttons unten klicken, bestätigen Sie, dass Sie gelesen haben, verstehen, und stimmen den <termsOfService>Nutzungsbedingungen</termsOfService> und <privacyPolicy>Datenschutzrichtlinien</privacyPolicy> zu.",
|
"loginLegalDisclaimer": "Indem Sie auf die Buttons unten klicken, bestätigen Sie, dass Sie die <termsOfService>Nutzungsbedingungen</termsOfService> und <privacyPolicy>Datenschutzrichtlinien</privacyPolicy> gelesen haben, verstehen und ihnen zustimmen.",
|
||||||
"termsOfService": "Nutzungsbedingungen",
|
"termsOfService": "Nutzungsbedingungen",
|
||||||
"privacyPolicy": "Datenschutzerklärung",
|
"privacyPolicy": "Datenschutzerklärung",
|
||||||
"userNotFoundWithUsername": "Kein Benutzer mit diesem Benutzernamen gefunden.",
|
"userNotFoundWithUsername": "Kein Benutzer mit diesem Benutzernamen gefunden.",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Nicht etikettiert",
|
"resourceLauncherUnlabeled": "Nicht etikettiert",
|
||||||
|
"resourceLauncherAiGateway": "KI-Gateway",
|
||||||
"resourceLauncherNoSite": "Kein Standort",
|
"resourceLauncherNoSite": "Kein Standort",
|
||||||
|
"resourceLauncherAvailableModels": "Verfügbare Modelle",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modelle, die Sie mit diesem KI-Gateway verwenden können.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Für diese Ressource sind keine Modelle verfügbar.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Verfügbare Modelle konnten nicht geladen werden.",
|
||||||
|
"resourceLauncherApiKeys": "API-Schlüssel",
|
||||||
|
"resourceLauncherApiKeysDescription": "Verwenden Sie Ihren Identitätsschlüssel oder einen zugeordneten Schlüssel, um sich bei dieser Ressource zu authentifizieren.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Identitätsschlüssel",
|
||||||
|
"resourceLauncherApiKeysManual": "Zugeordnete Schlüssel",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Für diese Ressource stehen keine API-Schlüssel zur Verfügung.",
|
||||||
|
"resourceLauncherApiKeysError": "API-Schlüssel konnten nicht geladen werden.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Keine Ressourcen in dieser Gruppe",
|
"resourceLauncherNoResourcesInGroup": "Keine Ressourcen in dieser Gruppe",
|
||||||
"resourceLauncherEmptyStateTitle": "Keine Ressourcen verfügbar",
|
"resourceLauncherEmptyStateTitle": "Keine Ressourcen verfügbar",
|
||||||
"resourceLauncherEmptyStateDescription": "Sie haben noch keinen Zugriff auf Ressourcen. Kontaktieren Sie Ihren Administrator, um Zugriff anzufordern.",
|
"resourceLauncherEmptyStateDescription": "Sie haben noch keinen Zugriff auf Ressourcen. Kontaktieren Sie Ihren Administrator, um Zugriff anzufordern.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Die Startansicht konnte nicht gelöscht werden. Bitte versuchen Sie es erneut.",
|
"resourceLauncherViewDeleteFailedDescription": "Die Startansicht konnte nicht gelöscht werden. Bitte versuchen Sie es erneut.",
|
||||||
"memberPortalPrevious": "Vorherige",
|
"memberPortalPrevious": "Vorherige",
|
||||||
"memberPortalNext": "Nächste",
|
"memberPortalNext": "Nächste",
|
||||||
"httpSettings": "HTTP-Einstellungen",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "TCP-Einstellungen",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "UDP-Einstellungen",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Aufbau einer sicheren Verbindung…",
|
"sshConnectingDescription": "Aufbau einer sicheren Verbindung…",
|
||||||
"sshConnecting": "Verbindung wird hergestellt…",
|
"sshConnecting": "Verbindung wird hergestellt…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Upload fehlgeschlagen",
|
"rdpUploadFailed": "Upload fehlgeschlagen",
|
||||||
"rdpUnicodeKeyboardMode": "Unicode-Tastaturmodus",
|
"rdpUnicodeKeyboardMode": "Unicode-Tastaturmodus",
|
||||||
"sessionToolbarShow": "Werkzeugleiste zeigen",
|
"sessionToolbarShow": "Werkzeugleiste zeigen",
|
||||||
"sessionToolbarHide": "Werkzeugleiste ausblenden"
|
"sessionToolbarHide": "Werkzeugleiste ausblenden",
|
||||||
|
"actionUpdateSiteApprovals": "Standortgenehmigungen aktualisieren"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Please make sure you're logged in as the correct user.",
|
"inviteLoginUser": "Please make sure you're logged in as the correct user.",
|
||||||
"inviteErrorNoUser": "We're sorry, but it looks like the invite you're trying to access is not for a user that exists.",
|
"inviteErrorNoUser": "We're sorry, but it looks like the invite you're trying to access is not for a user that exists.",
|
||||||
"inviteCreateUser": "Please create an account first.",
|
"inviteCreateUser": "Please create an account first.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Invites can only be accepted by internal accounts. Sign out and log in with your password for this email.",
|
||||||
|
"inviteLoginInternalOnly": "Invites require an internal account with a password. Create an account or sign in with your password.",
|
||||||
"goHome": "Go Home",
|
"goHome": "Go Home",
|
||||||
"inviteLogInOtherUser": "Log In as a Different User",
|
"inviteLogInOtherUser": "Log In as a Different User",
|
||||||
"createAnAccount": "Create an Account",
|
"createAnAccount": "Create an Account",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Confirm Delete Shareable Link",
|
"shareDeleteConfirm": "Confirm Delete Shareable Link",
|
||||||
"shareQuestionRemove": "Are you sure you want to delete this share link?",
|
"shareQuestionRemove": "Are you sure you want to delete this share link?",
|
||||||
"shareMessageRemove": "Once deleted, the link will no longer work and anyone using it will lose access to the resource.",
|
"shareMessageRemove": "Once deleted, the link will no longer work and anyone using it will lose access to the resource.",
|
||||||
"shareTokenDescription": "The access token can be passed in two ways: as a query parameter or in the request headers. These must be passed from the client on every request for authenticated access.",
|
"shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
|
||||||
"accessToken": "Access Token",
|
"accessToken": "Access Token",
|
||||||
"usageExamples": "Usage Examples",
|
"usageExamples": "Usage Examples",
|
||||||
"tokenId": "Token ID",
|
"tokenId": "Token ID",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Title (optional)",
|
"shareTitleOptional": "Title (optional)",
|
||||||
"sharePathOptional": "Path (optional)",
|
"sharePathOptional": "Path (optional)",
|
||||||
"sharePathDescription": "The link will redirect users to this path after authentication.",
|
"sharePathDescription": "The link will redirect users to this path after authentication.",
|
||||||
|
"shareAssociateUserOptional": "Associate User (optional)",
|
||||||
|
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
|
||||||
|
"userSelect": "Select user",
|
||||||
|
"usersNotFound": "No users found",
|
||||||
"expireIn": "Expire In",
|
"expireIn": "Expire In",
|
||||||
"neverExpire": "Never expire",
|
"neverExpire": "Never expire",
|
||||||
|
"sharePersistSession": "Persist session after first use",
|
||||||
|
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
|
||||||
"shareExpireDescription": "Expiration time is how long the link will be usable and provide access to the resource. After this time, the link will no longer work, and users who used this link will lose access to the resource.",
|
"shareExpireDescription": "Expiration time is how long the link will be usable and provide access to the resource. After this time, the link will no longer work, and users who used this link will lose access to the resource.",
|
||||||
"shareSeeOnce": "You will only be able to see this link once. Make sure to copy it.",
|
"shareSeeOnce": "You will only be able to see this link once. Make sure to copy it.",
|
||||||
"shareAccessHint": "Anyone with this link can access the resource. Share it with care.",
|
"shareAccessHint": "Anyone with this link can access the resource. Share it with care.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "No country found.",
|
"noCountryFound": "No country found.",
|
||||||
"siteSelectionDescription": "This site will provide connectivity to the target.",
|
"siteSelectionDescription": "This site will provide connectivity to the target.",
|
||||||
"resourceType": "Resource Type",
|
"resourceType": "Resource Type",
|
||||||
"resourceTypeDescription": "This controls the resource protocol and how it will be rendered in the browser. This can’t be changed later.",
|
"resourceTypeDescription": "This controls the resource protocol and can’t be changed later.",
|
||||||
|
"resourceTypeSearch": "Search resource types...",
|
||||||
|
"resourceTypeNotFound": "No resource type found",
|
||||||
|
"resourceTypeHttpDescription": "Proxy web traffic over HTTPS using a domain name",
|
||||||
|
"resourceTypeInferenceDescription": "Route AI requests through attached providers",
|
||||||
|
"resourceTypeSshDescription": "Access an SSH server from the browser",
|
||||||
|
"resourceTypeRdpDescription": "Access a remote desktop from the browser",
|
||||||
|
"resourceTypeVncDescription": "Access a VNC desktop from the browser",
|
||||||
|
"resourceTypeTcpDescription": "Proxy raw TCP traffic using a port number",
|
||||||
|
"resourceTypeUdpDescription": "Proxy raw UDP traffic using a port number",
|
||||||
|
"privateResourceTypeDescription": "This controls how clients reach the resource. This can’t be changed later.",
|
||||||
|
"privateResourceTypeHostDescription": "Expose a single host on the site network to connected clients",
|
||||||
|
"privateResourceTypeCidrDescription": "Expose a CIDR range on the site network to connected clients",
|
||||||
|
"privateResourceTypeHttpDescription": "Access an HTTP or HTTPS service through a domain",
|
||||||
|
"privateResourceTypeSshDescription": "Access an SSH server from connected clients",
|
||||||
"resourceDomainDescription": "The resource will be served at this fully qualified domain name.",
|
"resourceDomainDescription": "The resource will be served at this fully qualified domain name.",
|
||||||
"resourceHTTPSSettings": "HTTPS Settings",
|
"resourceHTTPSSettings": "HTTPS Settings",
|
||||||
"resourceHTTPSSettingsDescription": "Configure how the resource will be accessed over HTTPS",
|
"resourceHTTPSSettingsDescription": "Configure how the resource will be accessed over HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Provisioning",
|
"provisioningManage": "Provisioning",
|
||||||
"provisioningDescription": "Manage provisioning keys and review pending sites awaiting approval.",
|
"provisioningDescription": "Manage provisioning keys and review pending sites awaiting approval.",
|
||||||
"pendingSites": "Pending Sites",
|
"pendingSites": "Pending Sites",
|
||||||
"siteApproveSuccess": "Site approved successfully",
|
"siteApproveSuccess": "Site and associated resources approved successfully",
|
||||||
"siteApproveError": "Error approving site",
|
"siteApproveError": "Error approving site",
|
||||||
|
"siteReject": "Reject Site",
|
||||||
|
"siteQuestionReject": "Are you sure you want to reject this site?",
|
||||||
|
"siteMessageReject": "This will permanently delete the site and any associated resources that are still pending.",
|
||||||
|
"siteConfirmReject": "Confirm Reject Site",
|
||||||
|
"siteRejectSuccess": "Site rejected successfully",
|
||||||
|
"siteRejectError": "Error rejecting site",
|
||||||
"provisioningKeys": "Provisioning Keys",
|
"provisioningKeys": "Provisioning Keys",
|
||||||
"searchProvisioningKeys": "Search provisioning keys...",
|
"searchProvisioningKeys": "Search provisioning keys...",
|
||||||
"provisioningKeysAdd": "Generate Provisioning Key",
|
"provisioningKeysAdd": "Generate Provisioning Key",
|
||||||
@@ -466,12 +494,12 @@
|
|||||||
"provisioningKeysSave": "Save the provisioning key",
|
"provisioningKeysSave": "Save the provisioning key",
|
||||||
"provisioningKeysSaveDescription": "You will only be able to see this once. Copy it to a secure place.",
|
"provisioningKeysSaveDescription": "You will only be able to see this once. Copy it to a secure place.",
|
||||||
"provisioningKeysErrorCreate": "Error creating provisioning key",
|
"provisioningKeysErrorCreate": "Error creating provisioning key",
|
||||||
"provisioningKeysList": "New provisioning key",
|
"provisioningKeysList": "New Provisioning Key",
|
||||||
"provisioningKeysMaxBatchSize": "Max batch size",
|
"provisioningKeysMaxBatchSize": "Max Batch Size",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Unlimited batch size (no limit)",
|
"provisioningKeysUnlimitedBatchSize": "Unlimited batch size (no limit)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Unlimited",
|
"provisioningKeysMaxBatchUnlimited": "Unlimited",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Enter a valid max batch size (1–1,000,000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Enter a valid max batch size (1–1,000,000).",
|
||||||
"provisioningKeysValidUntil": "Valid until",
|
"provisioningKeysValidUntil": "Valid Until",
|
||||||
"provisioningKeysValidUntilHint": "Leave empty for no expiration.",
|
"provisioningKeysValidUntilHint": "Leave empty for no expiration.",
|
||||||
"provisioningKeysValidUntilInvalid": "Enter a valid date and time.",
|
"provisioningKeysValidUntilInvalid": "Enter a valid date and time.",
|
||||||
"provisioningKeysNumUsed": "Times used",
|
"provisioningKeysNumUsed": "Times used",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "Never",
|
"provisioningKeysNeverUsed": "Never",
|
||||||
"provisioningKeysEdit": "Edit Provisioning Key",
|
"provisioningKeysEdit": "Edit Provisioning Key",
|
||||||
"provisioningKeysEditDescription": "Update the max batch size and expiration time for this key.",
|
"provisioningKeysEditDescription": "Update the max batch size and expiration time for this key.",
|
||||||
"provisioningKeysApproveNewSites": "Approve new sites",
|
"provisioningKeysApproveNewSites": "Approve New Sites",
|
||||||
"provisioningKeysApproveNewSitesDescription": "Automatically approve sites that register with this key.",
|
"provisioningKeysApproveNewSitesDescription": "Automatically approve sites that register with this key.",
|
||||||
"provisioningKeysUpdateError": "Error updating provisioning key",
|
"provisioningKeysUpdateError": "Error updating provisioning key",
|
||||||
"provisioningKeysUpdated": "Provisioning key updated",
|
"provisioningKeysUpdated": "Provisioning key updated",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Save Settings",
|
"authMethodsSave": "Save Settings",
|
||||||
"policyAuthStackTitle": "Authentication",
|
"policyAuthStackTitle": "Authentication",
|
||||||
"policyAuthStackDescription": "Control which authentication methods are required to access this resource",
|
"policyAuthStackDescription": "Control which authentication methods are required to access this resource",
|
||||||
|
"policyAuthInferenceStackDescription": "Choose which users and roles can authenticate to this AI gateway",
|
||||||
"policyAuthOrLogicTitle": "Multiple authentication methods active",
|
"policyAuthOrLogicTitle": "Multiple authentication methods active",
|
||||||
"policyAuthOrLogicBanner": "Visitors may authenticate using any one of the active methods below. They do not need to complete all of them.",
|
"policyAuthOrLogicBanner": "Visitors may authenticate using any one of the active methods below. They do not need to complete all of them.",
|
||||||
"policyAuthMethodActive": "Active",
|
"policyAuthMethodActive": "Active",
|
||||||
"policyAuthMethodOff": "Off",
|
"policyAuthMethodOff": "Off",
|
||||||
"policyAuthSsoTitle": "Platform SSO",
|
"policyAuthSsoTitle": "Platform SSO",
|
||||||
"policyAuthSsoDescription": "Require sign-in through your organization's identity provider",
|
"policyAuthSsoDescription": "Require sign-in through your organization's identity provider",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "Sign-in URL",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Every user already has an identity API key, so you only need to create virtual API keys for non-user clients or shared access. Users can retrieve their key by signing in with their identity provider at this resource's URL, where it will be shown after login.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Every user already has an identity API key, so you only need to create virtual API keys for non-user clients or shared access. Users retrieve their key here after signing in with their identity provider.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} users, {roles} roles",
|
"policyAuthSsoSummary": "{idp} · {users} users, {roles} roles",
|
||||||
"policyAuthSsoDefaultIdp": "Default provider",
|
"policyAuthSsoDefaultIdp": "Default provider",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Add Default Identity Provider",
|
"policyAuthAddDefaultIdentityProvider": "Add Default Identity Provider",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Version",
|
"newtVersion": "Version",
|
||||||
"architecture": "Architecture",
|
"architecture": "Architecture",
|
||||||
"sites": "Sites",
|
"sites": "Sites",
|
||||||
"siteWgAnyClients": "Use any WireGuard client to connect. You will have to address internal resources using the peer IP.",
|
"siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
|
||||||
"siteWgCompatibleAllClients": "Compatible with all WireGuard clients",
|
"siteWgCompatibleAllClients": "Compatible with all WireGuard clients",
|
||||||
"siteWgManualConfigurationRequired": "Manual configuration required",
|
"siteWgManualConfigurationRequired": "Manual configuration required",
|
||||||
"userErrorNotAdminOrOwner": "User is not an admin or owner",
|
"userErrorNotAdminOrOwner": "User is not an admin or owner",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "New role is required",
|
"accessRoleErrorNewRequired": "New role is required",
|
||||||
"accessRoleErrorRemove": "Failed to remove role",
|
"accessRoleErrorRemove": "Failed to remove role",
|
||||||
"accessRoleErrorRemoveDescription": "An error occurred while removing the role.",
|
"accessRoleErrorRemoveDescription": "An error occurred while removing the role.",
|
||||||
|
"accessRoleInferenceBudget": "AI Budget",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Configure how members of this role restrict AI usage based on spending or token limits",
|
||||||
"accessRoleName": "Role Name",
|
"accessRoleName": "Role Name",
|
||||||
"accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
|
"accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
|
||||||
"accessRoleRemove": "Remove Role",
|
"accessRoleRemove": "Remove Role",
|
||||||
@@ -1412,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Delete Site",
|
"actionDeleteSite": "Delete Site",
|
||||||
"actionGetSite": "Get Site",
|
"actionGetSite": "Get Site",
|
||||||
"actionListSites": "List Sites",
|
"actionListSites": "List Sites",
|
||||||
|
"actionCreateAiProvider": "Create AI Provider",
|
||||||
|
"actionDeleteAiProvider": "Delete AI Provider",
|
||||||
|
"actionGetAiProvider": "Get AI Provider",
|
||||||
|
"actionListAiProviders": "List AI Providers",
|
||||||
|
"actionUpdateAiProvider": "Update AI Provider",
|
||||||
|
"actionCreateAiModel": "Create AI Model",
|
||||||
|
"actionDeleteAiModel": "Delete AI Model",
|
||||||
|
"actionGetAiModel": "Get AI Model",
|
||||||
|
"actionListAiModels": "List AI Models",
|
||||||
|
"actionUpdateAiModel": "Update AI Model",
|
||||||
|
"actionCreateAiBudget": "Create AI Budget",
|
||||||
|
"actionDeleteAiBudget": "Delete AI Budget",
|
||||||
|
"actionGetAiBudget": "Get AI Budget",
|
||||||
|
"actionListAiBudgets": "List AI Budgets",
|
||||||
|
"actionUpdateAiBudget": "Update AI Budget",
|
||||||
|
"actionListResourceAiModels": "List Resource AI Models",
|
||||||
|
"actionSetResourceAiModels": "Set Resource AI Models",
|
||||||
|
"actionCreateVirtualApiKey": "Create Virtual API Key",
|
||||||
|
"actionDeleteVirtualApiKey": "Delete Virtual API Key",
|
||||||
|
"actionGetVirtualApiKey": "Get Virtual API Key",
|
||||||
|
"actionListVirtualApiKeys": "List Virtual API Keys",
|
||||||
|
"actionUpdateVirtualApiKey": "Update Virtual API Key",
|
||||||
"actionApplyBlueprint": "Apply Blueprint",
|
"actionApplyBlueprint": "Apply Blueprint",
|
||||||
"actionListBlueprints": "List Blueprints",
|
"actionListBlueprints": "List Blueprints",
|
||||||
"actionGetBlueprint": "Get Blueprint",
|
"actionGetBlueprint": "Get Blueprint",
|
||||||
@@ -1420,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Enter the setup token from the server console.",
|
"setupTokenDescription": "Enter the setup token from the server console.",
|
||||||
"setupTokenRequired": "Setup token is required",
|
"setupTokenRequired": "Setup token is required",
|
||||||
"actionUpdateSite": "Update Site",
|
"actionUpdateSite": "Update Site",
|
||||||
|
"actionApproveSite": "Approve Site",
|
||||||
|
"actionRejectSite": "Reject Site",
|
||||||
"actionResetSiteBandwidth": "Reset Organization Bandwidth",
|
"actionResetSiteBandwidth": "Reset Organization Bandwidth",
|
||||||
"actionListSiteRoles": "List Allowed Site Roles",
|
"actionListSiteRoles": "List Allowed Site Roles",
|
||||||
"actionCreateResource": "Create Resource",
|
"actionCreateResource": "Create Resource",
|
||||||
@@ -1435,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Set Resource Pincode",
|
"actionSetResourcePincode": "Set Resource Pincode",
|
||||||
"actionSetResourceEmailWhitelist": "Set Resource Email Whitelist",
|
"actionSetResourceEmailWhitelist": "Set Resource Email Whitelist",
|
||||||
"actionGetResourceEmailWhitelist": "Get Resource Email Whitelist",
|
"actionGetResourceEmailWhitelist": "Get Resource Email Whitelist",
|
||||||
|
"actionListResourcePolicies": "List Resource Policies",
|
||||||
|
"actionCreateResourcePolicy": "Create Resource Policy",
|
||||||
"actionGetResourcePolicy": "Get Resource Policy",
|
"actionGetResourcePolicy": "Get Resource Policy",
|
||||||
"actionUpdateResourcePolicy": "Update Resource Policy",
|
"actionUpdateResourcePolicy": "Update Resource Policy",
|
||||||
|
"actionDeleteResourcePolicy": "Delete Resource Policy",
|
||||||
"actionSetResourcePolicyUsers": "Set Resource Policy Users",
|
"actionSetResourcePolicyUsers": "Set Resource Policy Users",
|
||||||
"actionSetResourcePolicyRoles": "Set Resource Policy Roles",
|
"actionSetResourcePolicyRoles": "Set Resource Policy Roles",
|
||||||
"actionSetResourcePolicyPassword": "Set Resource Policy Password",
|
"actionSetResourcePolicyPassword": "Set Resource Policy Password",
|
||||||
@@ -1503,6 +1564,10 @@
|
|||||||
"actionListInvitations": "List Invitations",
|
"actionListInvitations": "List Invitations",
|
||||||
"actionExportLogs": "Export Logs",
|
"actionExportLogs": "Export Logs",
|
||||||
"actionViewLogs": "View Logs",
|
"actionViewLogs": "View Logs",
|
||||||
|
"actionCreateSiteProvisioningKey": "Create Site Provisioning Key",
|
||||||
|
"actionListSiteProvisioningKeys": "List Site Provisioning Keys",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Update Site Provisioning Key",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Delete Site Provisioning Key",
|
||||||
"noneSelected": "None selected",
|
"noneSelected": "None selected",
|
||||||
"orgNotFound2": "No organizations found.",
|
"orgNotFound2": "No organizations found.",
|
||||||
"search": "Search…",
|
"search": "Search…",
|
||||||
@@ -1542,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Create Machine Client",
|
"commandPaletteCreateMachineClient": "Create Machine Client",
|
||||||
"commandPaletteCreateAlertRule": "Create Alert Rule",
|
"commandPaletteCreateAlertRule": "Create Alert Rule",
|
||||||
"commandPaletteCreateIdentityProvider": "Create Identity Provider",
|
"commandPaletteCreateIdentityProvider": "Create Identity Provider",
|
||||||
|
"commandPaletteCreateAiProvider": "Create AI Provider",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Create Virtual API Key",
|
||||||
"commandPaletteToggleTheme": "Toggle Theme",
|
"commandPaletteToggleTheme": "Toggle Theme",
|
||||||
"commandPaletteChooseOrganization": "Choose Organization",
|
"commandPaletteChooseOrganization": "Choose Organization",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1604,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Invitations",
|
"sidebarInvitations": "Invitations",
|
||||||
"sidebarRoles": "Roles",
|
"sidebarRoles": "Roles",
|
||||||
"sidebarShareableLinks": "Shareable Links",
|
"sidebarShareableLinks": "Shareable Links",
|
||||||
|
"sidebarAiGateway": "AI Gateway",
|
||||||
|
"sidebarAiProviders": "Providers",
|
||||||
|
"commandAiProviders": "AI Providers",
|
||||||
|
"sidebarVirtualApiKeys": "Virtual API Keys",
|
||||||
|
"sidebarMyApiKeys": "Your API Keys",
|
||||||
|
"sidebarAccount": "Launcher",
|
||||||
|
"commandVirtualApiKeys": "Virtual API Keys",
|
||||||
|
"virtualApiKeysTitle": "Manage Virtual API Keys",
|
||||||
|
"virtualApiKeysDescription": "Create and manage manual API keys for AI Gateway access to public AI gateways",
|
||||||
|
"virtualApiKeysTabIdentity": "Identity Keys",
|
||||||
|
"virtualApiKeysTabVirtual": "Virtual Keys",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Identity Keys for Every User",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Every user already has a Pangolin identity key for this organization. It is unique to their account and authenticates them to AI gateways they can access.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Example",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "How Users Get Their Key",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Visit a public AI gateway URL in the browser and log in with their account.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Or go to <url></url> while signed in.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "You can create additional virtual API keys on the Virtual Keys tab. Those keys can be scoped to specific public AI gateways and optionally associated with a user. Creating a key immediately grants access to the selected public AI gateways.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Manually Create a Key",
|
||||||
|
"virtualApiKeysEmailIdentity": "Email Identity Keys",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Send each selected user or role their Pangolin identity key.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Send to all users",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Email every organization member who has an account email.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Users",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Roles",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Send Emails",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Identity keys emailed",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Sent {sent} emails.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} users were skipped because they do not have an email address.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Select at least one user or role, or send to all users.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Error sending identity keys",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Failed to email identity keys",
|
||||||
|
"virtualApiKeysBannerTitle": "Identity Keys for Every User",
|
||||||
|
"virtualApiKeysBannerDescription": "Every user already has an identity key available at {keysUrl}. You can also manually generate keys here that grant direct access to public AI gateways.",
|
||||||
|
"virtualApiKeysBannerButtonText": "View Identity Keys",
|
||||||
|
"virtualApiKeys": "Virtual API Keys",
|
||||||
|
"virtualApiKeysSearch": "Search keys...",
|
||||||
|
"virtualApiKeysCreate": "Create Virtual API Key",
|
||||||
|
"virtualApiKeysCreateDescription": "Mint a manual key that can call public AI gateways in this organization",
|
||||||
|
"virtualApiKeysCreateButton": "Create Key",
|
||||||
|
"virtualApiKeysEmpty": "No virtual API keys yet",
|
||||||
|
"virtualApiKeysName": "Name",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Description (optional)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Associate User (optional)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Associate this key with a user to track usage. Once created, this key immediately grants access to the selected public AI gateways. You do not need to associate a user to manually to the resource. The key will also show up in the user's profile.",
|
||||||
|
"virtualApiKeysAllResources": "All public AI gateways",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Allow this key to access every public AI gateway in the organization",
|
||||||
|
"virtualApiKeysSelectResources": "Public AI Gateways",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Select resources",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Choose which public AI gateways this key can access",
|
||||||
|
"virtualApiKeysNoResources": "No resources",
|
||||||
|
"virtualApiKeysSecret": "Key",
|
||||||
|
"virtualApiKeysCopyKey": "Copy this key. You can view it again later from the table or when editing.",
|
||||||
|
"virtualApiKeysViewSecret": "View Secret",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Virtual API Key Secret",
|
||||||
|
"virtualApiKeysViewSecretDescription": "This secret grants access to the public AI gateways assigned to this key",
|
||||||
|
"virtualApiKeysEdit": "Edit Virtual API Key",
|
||||||
|
"virtualApiKeysEditDescription": "Update the associated user and public AI gateway access for this key",
|
||||||
|
"virtualApiKeysSaveButton": "Save Changes",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Select at least one public AI gateway, or enable all public AI gateways",
|
||||||
|
"virtualApiKeysUpdated": "Virtual API key updated",
|
||||||
|
"virtualApiKeysUpdatedDescription": "The virtual API key has been updated",
|
||||||
|
"virtualApiKeysErrorUpdate": "Error updating virtual API key",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Failed to update virtual API key",
|
||||||
|
"virtualApiKeysErrorCreate": "Error creating virtual API key",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Failed to create virtual API key",
|
||||||
|
"virtualApiKeysErrorDelete": "Error deleting virtual API key",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Failed to delete virtual API key",
|
||||||
|
"virtualApiKeysDeleted": "Virtual API key deleted",
|
||||||
|
"virtualApiKeysDeletedDescription": "The virtual API key has been deleted",
|
||||||
|
"virtualApiKeysDelete": "Delete Virtual API Key",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Delete Key",
|
||||||
|
"virtualApiKeysQuestionRemove": "Are you sure you want to delete this virtual API key?",
|
||||||
|
"virtualApiKeysMessageRemove": "Clients using this key will lose access immediately.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Error loading secret",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Failed to load the virtual API key secret",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Unassigned",
|
||||||
|
"virtualApiKeysInferenceBudget": "Budget",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Configure how this key restricts AI usage based on spending or token limits",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Email key upon generation",
|
||||||
|
"virtualApiKeysEmailThisKey": "Email this key",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Send the key to the associated user and additional addresses after it is created",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Send the current key to the associated user and additional addresses",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "Email is not configured on this server",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Configure SMTP to email virtual API keys.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Send to associated user",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Email the key to the associated user's account email",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Associate a user to send the key to that user",
|
||||||
|
"virtualApiKeysEmailAdditional": "Additional emails",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Add email and press Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Select the associated user or add at least one email address",
|
||||||
|
"myVirtualApiKeysTitle": "Your API Keys",
|
||||||
|
"myVirtualApiKeysDescription": "View your identity key and any virtual API keys attributed to you in this organization",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Your API Keys for {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "View your identity key and virtual API keys attributed to you that can access {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Identity Key",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Your Personal API Key",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Your personal key for this organization. It is unique to your account and used to identify you when calling AI Gateway resources.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Your Personal API Key for {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Your personal key for this organization. Use it to call {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Attributed Keys",
|
||||||
|
"myVirtualApiKeysManualDescription": "Manual virtual API keys an admin associated with your account",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Manual virtual API keys associated with your account that can access {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "No attributed keys yet",
|
||||||
|
"myVirtualApiKeysKindUser": "Identity",
|
||||||
|
"myVirtualApiKeysKindManual": "Manual",
|
||||||
|
"myVirtualApiKeysUnnamed": "Unnamed key",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Reveal Secret",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "This secret authenticates you to AI Gateway resources",
|
||||||
|
"aiClientConfigTitle": "Configure Coding Agents",
|
||||||
|
"aiClientConfigDescription": "Copy configuration for popular coding agents, or let the Pangolin CLI set it up for you automatically.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Anthropic's agentic coding tool for the terminal.",
|
||||||
|
"aiClientConfigDescriptionCodex": "OpenAI's agentic coding tool for the terminal.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Open source terminal coding agent.",
|
||||||
|
"aiClientConfigDescriptionCursor": "AI code editor built on VS Code.",
|
||||||
|
"aiClientConfigSetup": "Setup",
|
||||||
|
"aiClientConfigTabCli": "Automatic (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Manual Configuration",
|
||||||
|
"aiClientConfigPreset": "Configuration",
|
||||||
|
"aiClientConfigStep": "Step {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "This snippet includes example values, such as a model name or resource URL. Replace them with your own before using it.",
|
||||||
|
"aiClientConfigRevealError": "Could not load your API key.",
|
||||||
|
"aiClientConfigRevealRetry": "Try again",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "This resource can be used from common clients like Claude Code and OpenCode. <configLink>Learn more</configLink>",
|
||||||
|
"aiProvidersTitle": "AI Providers",
|
||||||
|
"aiProvidersDescription": "Connect model providers for AI workloads in this organization",
|
||||||
|
"aiProvidersBannerTitle": "Connect Model Providers",
|
||||||
|
"aiProvidersBannerDescription": "Providers are the model backends Pangolin uses for AI workloads. Connect OpenAI, Anthropic, and other providers here, then attach them to public AI gateways so users can call models with identity-aware access, budgets, and logging.",
|
||||||
|
"aiProvidersAdd": "Add Provider",
|
||||||
|
"aiProvidersSearch": "Search providers...",
|
||||||
|
"aiProvidersEmpty": "No AI providers yet",
|
||||||
|
"aiProviderCreate": "Create AI Provider",
|
||||||
|
"aiProviderCreateDescription": "Add a model provider for this organization",
|
||||||
|
"aiProviderSeeAll": "See All Providers",
|
||||||
|
"aiProviderSetting": "Provider Settings for {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Configure this AI provider",
|
||||||
|
"aiProviderGeneral": "General",
|
||||||
|
"aiProviderGeneralDescription": "Basic settings for this provider",
|
||||||
|
"aiProviderConfiguration": "Configuration",
|
||||||
|
"aiProviderConfigurationDescription": "Network routing and authentication for this provider",
|
||||||
|
"aiProviderNetworkSettings": "Network Settings",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Choose how traffic reaches this provider",
|
||||||
|
"aiProviderAuthSettings": "Authentication",
|
||||||
|
"aiProviderAuthSettingsDescription": "Configure how this provider authenticates requests to its upstream URL",
|
||||||
|
"aiProviderBudgetSettings": "Budget",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Configure how this provider restricts usage based on spending or token limits",
|
||||||
|
"aiBudgetAdd": "Add Budget",
|
||||||
|
"aiBudgetEmpty": "No budgets configured yet. Click Add Budget to set a spending or token limit.",
|
||||||
|
"aiBudgetUnit": "Spend Type",
|
||||||
|
"aiBudgetPeriod": "Reset Period",
|
||||||
|
"aiBudgetAmount": "Maximum Spend",
|
||||||
|
"aiBudgetAmountPlaceholder": "Maximum spend",
|
||||||
|
"aiBudgetPeriodHourly": "Hourly",
|
||||||
|
"aiBudgetPeriodDaily": "Daily",
|
||||||
|
"aiBudgetPeriodWeekly": "Weekly",
|
||||||
|
"aiBudgetPeriodMonthly": "Monthly",
|
||||||
|
"aiBudgetPeriodYearly": "Yearly",
|
||||||
|
"aiBudgetPeriodLifetime": "Lifetime",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Tokens",
|
||||||
|
"aiBudgetConflictError": "A budget for this reset period and spend type already exists",
|
||||||
|
"aiBudgetInvalidAmountError": "Enter a maximum spend greater than 0",
|
||||||
|
"aiBudgetUpdated": "Budgets updated",
|
||||||
|
"aiBudgetErrorSave": "Failed to update budgets",
|
||||||
|
"aiProviderType": "Provider Type",
|
||||||
|
"aiProviderTypeSearch": "Search providers...",
|
||||||
|
"aiProviderTypeNotFound": "No provider type found",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "Custom",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Runtime API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "Bring your own endpoint or route via site targets",
|
||||||
|
"aiProviderUpstreamUrl": "Upstream URL",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Base URL for the provider API",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Leave blank to use the default upstream URL for this provider",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Effective Upstream URL",
|
||||||
|
"aiProviderApiKey": "API Key",
|
||||||
|
"aiProviderApiKeyDescription": "API key used to authenticate requests to this provider",
|
||||||
|
"aiProviderCustomHeadersDescription": "Headers sent on every request to this provider. Newline separated: Header-Name: value",
|
||||||
|
"aiProviderApiKeyLastChars": "API Key",
|
||||||
|
"aiProviderAuthType": "Auth Type",
|
||||||
|
"aiProviderAuthTypeSearch": "Search auth types...",
|
||||||
|
"aiProviderAuthTypeNotFound": "No auth type found",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Authorization: Bearer key. Used by OpenAI and most providers",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-key header. Used by Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-key header. Used by Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Authorization: Splunk key. Used by Splunk HTTP Event Collector",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Bearer key. Used by Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeNone": "No Auth",
|
||||||
|
"aiProviderAuthTypePassthrough": "Passthrough",
|
||||||
|
"aiProviderAuthTypeDescription": "How the upstream API authenticates requests",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Forward the caller's API key headers to the upstream",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Do not send authentication headers to the upstream",
|
||||||
|
"aiProviderRoutingMode": "Routing Mode",
|
||||||
|
"aiProviderRoutingModeDescription": "Send traffic to an upstream URL or to HTTP targets on your sites",
|
||||||
|
"aiProviderRoutingModeUrl": "Upstream URL",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Call a public or private API base URL",
|
||||||
|
"aiProviderRoutingModeTarget": "Site Targets",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Route through targets on your sites",
|
||||||
|
"aiProviderRoutingModeTargetNote": "After creating this provider, configure site targets on the Network Settings tab.",
|
||||||
|
"aiProviderTargetNoOne": "This provider doesn't have any targets. Add a target to route requests through your sites.",
|
||||||
|
"aiProviderSkipTlsVerification": "Skip TLS Verification",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Disable TLS certificate verification for the upstream connection",
|
||||||
|
"aiProviderBudget": "Budget",
|
||||||
|
"aiProviderBudgetDescription": "Optional spending or token budget for this provider",
|
||||||
|
"aiProviderBudgetAmount": "Budget Amount",
|
||||||
|
"aiProviderBudgetUnit": "Budget Unit",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Tokens",
|
||||||
|
"aiProviderEnabled": "Enabled",
|
||||||
|
"aiProviderEnabledDescription": "Fully disable this provider across all resources",
|
||||||
|
"aiProviderErrorCreate": "Failed to create AI provider",
|
||||||
|
"aiProviderErrorUpdate": "Failed to update AI provider",
|
||||||
|
"aiProviderErrorDelete": "Failed to delete AI provider",
|
||||||
|
"aiProviderErrorLoad": "Failed to load AI provider",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Enter a valid upstream URL",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Upstream URL is required for this provider",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Auth type is required",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API key is required",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Site targets routing is only available for custom providers",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Select at least one API capability",
|
||||||
|
"aiProviderCapabilities": "API Capabilities",
|
||||||
|
"aiProviderCapabilitiesDescription": "Select which API formats this provider can handle. Known providers start with recommended defaults.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Select which API formats this custom provider can handle",
|
||||||
|
"aiProviderCapabilitiesSelect": "Select capabilities",
|
||||||
|
"aiProviderCapabilitiesEmpty": "No capabilities found",
|
||||||
|
"aiProviderCapabilitiesSearch": "Search capabilities...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Chat Completions",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Supports /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI Responses",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Supports /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic Messages",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Supports /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini Generate Content",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Supports the direct Gemini API",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Bedrock Model Invoke",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Supports Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex Generate Content",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Supports Vertex AI Gemini format",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex Raw Predict",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Supports Vertex AI rawPredict for Anthropic models",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock Converse",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Supports Amazon Bedrock Converse API",
|
||||||
|
"aiProviderCreated": "AI provider created",
|
||||||
|
"aiProviderUpdated": "AI provider updated",
|
||||||
|
"aiProviderDeleted": "AI provider deleted",
|
||||||
|
"aiProviderDelete": "Delete Provider",
|
||||||
|
"aiProviderDeleteConfirm": "Delete Provider",
|
||||||
|
"aiProviderQuestionRemove": "Are you sure you want to delete this AI provider?",
|
||||||
|
"aiProviderMessageRemove": "This will permanently delete the provider and its models and targets. This cannot be undone.",
|
||||||
|
"aiProviderErrorNoUpdate": "AI provider is not available to update",
|
||||||
|
"aiProviderModels": "Models",
|
||||||
|
"aiProviderModelsDescription": "Define allow and block lists for this provider. Requests must match an allow entry and must not match a block entry.",
|
||||||
|
"aiProviderCreateModelsDescription": "Choose which models this provider can serve. An empty allow list denies all traffic. You can add or change models later.",
|
||||||
|
"aiProviderModelsPlaceholder": "Search models or type a custom key",
|
||||||
|
"aiProviderModelsAllow": "Allow List",
|
||||||
|
"aiProviderModelsAllowDescription": "Models that may be used through this provider. Empty means deny all.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Enter model key",
|
||||||
|
"aiProviderModelsAllowEmpty": "No models added yet.",
|
||||||
|
"aiProviderModelsBlock": "Block List",
|
||||||
|
"aiProviderModelsBlockDescription": "Models to deny even if they match an allow entry.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Enter model key",
|
||||||
|
"aiProviderModelsBlockEmpty": "No models added yet.",
|
||||||
|
"aiProviderModelsAdd": "Add Models",
|
||||||
|
"aiProviderModelsClearAll": "Clear All",
|
||||||
|
"aiProviderModelsAddCustom": "Add \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Press Enter to add this custom model key.",
|
||||||
|
"aiProviderModelsAddBulk": "Add {count} custom keys",
|
||||||
|
"aiProviderModelsAddBulkHint": "Press Enter to add {count} custom keys.",
|
||||||
|
"aiProviderModelsAddOne": "Add {key} now",
|
||||||
|
"aiProviderModelsAddSelected": "Add Selected",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} selected",
|
||||||
|
"aiProviderModelsSelectAll": "Select all",
|
||||||
|
"aiProviderModelsClearSelected": "Clear",
|
||||||
|
"aiProviderModelsBulkHint": "Select known models or type a custom key.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "No matching catalog models.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Known Models",
|
||||||
|
"aiProviderModelsAllLabel": "All models",
|
||||||
|
"aiProviderModelsAllPatternHint": "Wildcard: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Allow all models",
|
||||||
|
"aiProviderModelsAddAllBlock": "Block all models",
|
||||||
|
"aiProviderModelsAddAllDescription": "Uses the * wildcard so every model key matches.",
|
||||||
|
"aiProviderModelsViewMore": "View more ({count})",
|
||||||
|
"aiProviderModelsViewLess": "View less",
|
||||||
|
"aiProviderModelsRemove": "Remove model",
|
||||||
|
"aiProviderModelsEditHint": "Click to edit model settings",
|
||||||
|
"aiProviderModelsSourceCatalog": "Known catalog model",
|
||||||
|
"aiProviderModelsSourceCustom": "Custom model key",
|
||||||
|
"aiProviderModelsSourcePattern": "Wildcard pattern",
|
||||||
|
"aiProviderModelsSourceAll": "Matches every model key",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Budget configured",
|
||||||
|
"aiProviderModelsEditTitle": "Edit Model",
|
||||||
|
"aiProviderModelsEditDescription": "Update the model key or configure its budget.",
|
||||||
|
"aiProviderModelsBudgetTab": "Budget",
|
||||||
|
"aiProviderModelsKeyLabel": "Model Key",
|
||||||
|
"aiProviderModelsKeyRequired": "Enter a model key",
|
||||||
|
"aiProviderModelsKeyDuplicate": "This model key is already on a list",
|
||||||
|
"aiProviderModelsOverlapError": "These patterns cannot be on both lists: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Models updated",
|
||||||
|
"aiProviderModelsErrorUpdate": "Failed to update models",
|
||||||
|
"aiResourceProviders": "Providers",
|
||||||
|
"aiResourceProvidersDescription": "Choose which AI providers this AI gateway can use",
|
||||||
|
"aiResourceProvidersHelp": "Attach providers and choose inherit (use each provider's lists) or select (pick an allow list for this resource). Allow patterns that conflict across attached providers are not allowed.",
|
||||||
|
"aiResourceProvidersSelect": "Select providers",
|
||||||
|
"aiResourceProvidersEmpty": "No AI providers found",
|
||||||
|
"aiResourceProvidersNoneAttached": "No providers attached yet.",
|
||||||
|
"aiResourceProvidersAdd": "Add provider",
|
||||||
|
"aiResourceProvidersRemove": "Remove provider",
|
||||||
|
"aiResourceProviderToggleEnabled": "Enable or disable this provider on the resource",
|
||||||
|
"aiResourceProviderDisabled": "Disabled",
|
||||||
|
"aiResourceProvidersUpdated": "Providers updated",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Failed to update providers",
|
||||||
|
"aiResourceProviderEditDescription": "Choose how this provider's models are exposed on this resource.",
|
||||||
|
"viewProviderSettings": "View Provider Settings",
|
||||||
|
"aiResourceProviderMode": "Access mode",
|
||||||
|
"aiResourceProviderModeInherit": "Inherit",
|
||||||
|
"aiResourceProviderModeSelect": "Select",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Select · {count} models",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Use this provider's allow and block lists as configured on the provider.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Choose a subset of this provider's allow-list models for this resource.",
|
||||||
|
"aiResourceProviderAllowModels": "Allow list",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Select models",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Search models...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "No models found",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Only models from this provider's allow list can be selected.",
|
||||||
|
"aiResourceAliasRequired": "Alias is required for AI gateways",
|
||||||
|
"aiResourceDomainConfiguration": "Domain Configuration",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Choose the domain clients will use to reach this AI gateway.",
|
||||||
|
"aiUsageAnalyticsTitle": "AI Usage Analytics",
|
||||||
|
"aiUsageAnalyticsDescription": "Analyze AI gateway cost, token usage, and activity across providers, resources, roles, and users",
|
||||||
|
"aiUsageTabOverview": "Overview",
|
||||||
|
"aiUsageTabProviders": "Providers",
|
||||||
|
"aiUsageTabResources": "Resources",
|
||||||
|
"aiUsageFilterProvider": "Provider",
|
||||||
|
"aiUsageFilterModel": "Model",
|
||||||
|
"aiUsageFilterResource": "Resource",
|
||||||
|
"aiUsageFilterRole": "Role",
|
||||||
|
"aiUsageFilterUser": "User",
|
||||||
|
"aiUsageFilterAllProviders": "All Providers",
|
||||||
|
"aiUsageFilterAllModels": "All Models",
|
||||||
|
"aiUsageFilterAllResources": "All Resources",
|
||||||
|
"aiUsageFilterAllRoles": "All Roles",
|
||||||
|
"aiUsageFilterAllUsers": "All Users",
|
||||||
|
"aiUsageFilterSearch": "Search...",
|
||||||
|
"aiUsageFilterNotFound": "No options found",
|
||||||
|
"aiUsageResetFilters": "Reset Filters",
|
||||||
|
"aiUsageRefresh": "Refresh",
|
||||||
|
"aiUsageTokenTypePrompt": "Prompt",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Cache read",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Cache write",
|
||||||
|
"aiUsageTokenTypeCompletion": "Completion",
|
||||||
|
"aiUsageTokenTypeReasoning": "Reasoning",
|
||||||
|
"aiUsageRequests": "Requests",
|
||||||
|
"aiUsageCost": "Cost",
|
||||||
|
"aiUsageTokens": "Tokens",
|
||||||
|
"aiUsageOther": "Other",
|
||||||
|
"aiUsageTotalRequests": "Total Requests",
|
||||||
|
"aiUsageTotalTokens": "Total Tokens",
|
||||||
|
"aiUsageTotalCost": "Total Cost",
|
||||||
|
"aiUsageEstimated": "Estimated",
|
||||||
|
"aiUsageRequestVolume": "Request Volume",
|
||||||
|
"aiUsageTokenUsage": "Token Usage",
|
||||||
|
"aiUsageModelCost": "Model Cost",
|
||||||
|
"aiUsageModelTokens": "Model Tokens",
|
||||||
|
"aiUsageTopModels": "Top Models",
|
||||||
|
"aiUsageTopProviders": "Top Providers",
|
||||||
|
"aiUsageProviderCost": "Provider Cost",
|
||||||
|
"aiUsageProviderTokenUsage": "Provider Token Usage",
|
||||||
|
"aiUsageTopResources": "Top Resources",
|
||||||
|
"aiUsageResourceCost": "Resource Cost",
|
||||||
|
"aiUsageResourceTokenUsage": "Resource Token Usage",
|
||||||
|
"aiUsageResourceTypePublic": "Public Resource",
|
||||||
|
"aiUsageResourceTypeSite": "Private Resource",
|
||||||
|
"aiUsageNoResource": "No resource",
|
||||||
|
"aiUsageRolesTab": "Roles",
|
||||||
|
"aiUsageUsersTab": "Users",
|
||||||
|
"aiUsageTopRoles": "Top Roles",
|
||||||
|
"aiUsageRoleCost": "Role Cost",
|
||||||
|
"aiUsageRoleTokenUsage": "Role Token Usage",
|
||||||
|
"aiUsageTopUsers": "Top Users",
|
||||||
|
"aiUsageUserCost": "User Cost",
|
||||||
|
"aiUsageUserTokenUsage": "User Token Usage",
|
||||||
|
"aiUsageUnknownUser": "Unknown user",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Virtual API Keys",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Virtual API Key",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "All Virtual API Keys",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Top Virtual API Keys",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Virtual API Key Cost",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Virtual API Key Token Usage",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "No virtual API key",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Unnamed key",
|
||||||
|
"aiUsageLoading": "Loading...",
|
||||||
|
"aiUsageNoData": "No data",
|
||||||
|
"resourceBudgetSettings": "Budget",
|
||||||
|
"resourceBudgetSettingsDescription": "Configure how this AI gateway restricts usage based on spending or token limits",
|
||||||
"sidebarApiKeys": "API Keys",
|
"sidebarApiKeys": "API Keys",
|
||||||
"sidebarProvisioning": "Provisioning",
|
"sidebarProvisioning": "Provisioning",
|
||||||
"sidebarSettings": "Settings",
|
"sidebarSettings": "Settings",
|
||||||
@@ -1677,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Alert rule saved",
|
"alertingRuleSaved": "Alert rule saved",
|
||||||
"alertingRuleSavedCreatedDescription": "Your new alert rule was created. You can keep editing it on this page.",
|
"alertingRuleSavedCreatedDescription": "Your new alert rule was created. You can keep editing it on this page.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Your changes to this alert rule were saved.",
|
"alertingRuleSavedUpdatedDescription": "Your changes to this alert rule were saved.",
|
||||||
|
"alertingTestAlertSent": "Test alert sent",
|
||||||
|
"alertingTestAlertSentDescription": "A test alert was sent to the actions configured on this rule.",
|
||||||
"alertingEditRule": "Edit Alert Rule",
|
"alertingEditRule": "Edit Alert Rule",
|
||||||
"alertingCreateRule": "Create Alert Rule",
|
"alertingCreateRule": "Create Alert Rule",
|
||||||
"alertingRuleCredenzaDescription": "Choose what to watch, when to fire, and how to notify",
|
"alertingRuleCredenzaDescription": "Choose what to watch, when to fire, and how to notify",
|
||||||
@@ -1786,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Each rule ties together what to watch (a site, health check, or resource), when to fire (for example offline or unhealthy), and how to notify your team via email, webhooks, or integrations. Use this list to create, enable, and manage those rules.",
|
"alertingRulesBannerDescription": "Each rule ties together what to watch (a site, health check, or resource), when to fire (for example offline or unhealthy), and how to notify your team via email, webhooks, or integrations. Use this list to create, enable, and manage those rules.",
|
||||||
"alertingHealthChecksBannerTitle": "Monitor Health & Resources",
|
"alertingHealthChecksBannerTitle": "Monitor Health & Resources",
|
||||||
"alertingHealthChecksBannerDescription": "Health checks are HTTP or TCP monitors you define once. You can then use them as sources in alert rules so you get notified when a target becomes healthy or unhealthy. Health checks on resources also appear here.",
|
"alertingHealthChecksBannerDescription": "Health checks are HTTP or TCP monitors you define once. You can then use them as sources in alert rules so you get notified when a target becomes healthy or unhealthy. Health checks on resources also appear here.",
|
||||||
|
"alertingTestRule": "Test Alert Rule",
|
||||||
|
"alertingAddActionHeading": "Add New Action",
|
||||||
|
"alertingSelectActionType": "Select an Action",
|
||||||
|
"alertingNoActionsTitle": "No actions configured",
|
||||||
|
"alertingNoActionsSaveDescription": "Add at least one action so this rule can notify someone when it fires.",
|
||||||
|
"alertingNoActionsTestDescription": "Add at least one action before you can test this rule.",
|
||||||
"standaloneHcTableTitle": "Health Checks",
|
"standaloneHcTableTitle": "Health Checks",
|
||||||
"standaloneHcSearchPlaceholder": "Search health checks…",
|
"standaloneHcSearchPlaceholder": "Search health checks…",
|
||||||
"standaloneHcAddButton": "Create Health Check",
|
"standaloneHcAddButton": "Create Health Check",
|
||||||
@@ -1977,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Subdomain: {subdomain}",
|
"domainPickerSubdomain": "Subdomain: {subdomain}",
|
||||||
"domainPickerNamespace": "Namespace: {namespace}",
|
"domainPickerNamespace": "Namespace: {namespace}",
|
||||||
"domainPickerShowMore": "Show More",
|
"domainPickerShowMore": "Show More",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "No domains available",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Go to Domains",
|
||||||
"regionSelectorTitle": "Select Region",
|
"regionSelectorTitle": "Select Region",
|
||||||
"domainPickerRemoteExitNodeWarning": "Provided domains are not supported when sites connect to remote exit nodes. For resources to be available on remote nodes, use a custom domain instead.",
|
"domainPickerRemoteExitNodeWarning": "Provided domains are not supported when sites connect to remote exit nodes. For resources to be available on remote nodes, use a custom domain instead.",
|
||||||
"regionSelectorInfo": "Selecting a region helps us provide better performance for your location. You do not have to be in the same region as your server.",
|
"regionSelectorInfo": "Selecting a region helps us provide better performance for your location. You do not have to be in the same region as your server.",
|
||||||
@@ -2172,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Subnet",
|
"subnetPlaceholder": "Subnet",
|
||||||
"addressDescription": "The internal address of the client. Must fall within the organization's subnet.",
|
"addressDescription": "The internal address of the client. Must fall within the organization's subnet.",
|
||||||
"selectSites": "Select sites",
|
"selectSites": "Select sites",
|
||||||
|
"selectResources": "Select resources",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# resource} other {# resources}}",
|
||||||
"selectLabels": "Select labels",
|
"selectLabels": "Select labels",
|
||||||
"sitesDescription": "The client will have connectivity to the selected sites",
|
"sitesDescription": "The client will have connectivity to the selected sites",
|
||||||
"clientInstallOlm": "Install Machine Client",
|
"clientInstallOlm": "Install Machine Client",
|
||||||
@@ -2224,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Time is in seconds",
|
"timeIsInSeconds": "Time is in seconds",
|
||||||
"requireDeviceApproval": "Require Device Approvals",
|
"requireDeviceApproval": "Require Device Approvals",
|
||||||
"requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
|
"requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
|
||||||
"sshSettings": "SSH Settings",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI Gateway",
|
||||||
"sshAccess": "SSH Access",
|
"sshAccess": "SSH Access",
|
||||||
"rdpSettings": "RDP Settings",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "VNC Settings",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH Server",
|
"sshServer": "SSH Server",
|
||||||
"rdpServer": "RDP Server",
|
"rdpServer": "RDP Server",
|
||||||
"vncServer": "VNC Server",
|
"vncServer": "VNC Server",
|
||||||
@@ -2340,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Public",
|
"resourcesTableProxyResources": "Public",
|
||||||
"resourcesTableClientResources": "Private",
|
"resourcesTableClientResources": "Private",
|
||||||
"resourcesTableNoProxyResourcesFound": "No proxy resources found.",
|
"resourcesTableNoProxyResourcesFound": "No proxy resources found.",
|
||||||
"resourcesTableNoInternalResourcesFound": "No internal resources found.",
|
"resourcesTableNoInternalResourcesFound": "No private resources found.",
|
||||||
"resourcesTableDestination": "Destination",
|
"resourcesTableDestination": "Destination",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Alias Address",
|
"resourcesTableAliasAddress": "Alias Address",
|
||||||
@@ -2363,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Cancel",
|
"editInternalResourceDialogCancel": "Cancel",
|
||||||
"editInternalResourceDialogSaveResource": "Save Resource",
|
"editInternalResourceDialogSaveResource": "Save Resource",
|
||||||
"editInternalResourceDialogSuccess": "Success",
|
"editInternalResourceDialogSuccess": "Success",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Internal resource updated successfully",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
|
||||||
"editInternalResourceDialogError": "Error",
|
"editInternalResourceDialogError": "Error",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update internal resource",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
|
||||||
"editInternalResourceDialogNameRequired": "Name is required",
|
"editInternalResourceDialogNameRequired": "Name is required",
|
||||||
"editInternalResourceDialogNameMaxLength": "Name must be less than 255 characters",
|
"editInternalResourceDialogNameMaxLength": "Name must be less than 255 characters",
|
||||||
"editInternalResourceDialogProxyPortMin": "Proxy port must be at least 1",
|
"editInternalResourceDialogProxyPortMin": "Proxy port must be at least 1",
|
||||||
@@ -2380,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI Gateway",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Scheme",
|
"editInternalResourceDialogScheme": "Scheme",
|
||||||
"editInternalResourceDialogEnableSsl": "Enable TLS",
|
"editInternalResourceDialogEnableSsl": "Enable TLS",
|
||||||
@@ -2391,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "An optional internal DNS alias for this resource.",
|
"editInternalResourceDialogAliasDescription": "An optional internal DNS alias for this resource.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "No Sites Available",
|
"createInternalResourceDialogNoSitesAvailable": "No Sites Available",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create internal resources.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
|
||||||
"createInternalResourceDialogClose": "Close",
|
"createInternalResourceDialogClose": "Close",
|
||||||
"createInternalResourceDialogCreateClientResource": "Create Private Resource",
|
"createInternalResourceDialogCreateClientResource": "Create Private Resource",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Create a new resource that will only be accessible to clients connected to the organization",
|
"createInternalResourceDialogCreateClientResourceDescription": "Create a new resource that will only be accessible to clients connected to the organization",
|
||||||
@@ -2400,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Allow ICMP Ping",
|
"privateResourceAllowIcmpPing": "Allow ICMP Ping",
|
||||||
"privateResourceNetworkAccess": "Network Access",
|
"privateResourceNetworkAccess": "Network Access",
|
||||||
"privateResourceNetworkAccessDescription": "Control TCP/UDP port access and whether ICMP ping is allowed for this resource.",
|
"privateResourceNetworkAccessDescription": "Control TCP/UDP port access and whether ICMP ping is allowed for this resource.",
|
||||||
"hostSettings": "Host Settings",
|
"hostSettings": "Host",
|
||||||
"cidrSettings": "CIDR Settings",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Resource Properties",
|
"createInternalResourceDialogResourceProperties": "Resource Properties",
|
||||||
"createInternalResourceDialogName": "Name",
|
"createInternalResourceDialogName": "Name",
|
||||||
"createInternalResourceDialogSite": "Site",
|
"createInternalResourceDialogSite": "Site",
|
||||||
@@ -2420,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Cancel",
|
"createInternalResourceDialogCancel": "Cancel",
|
||||||
"createInternalResourceDialogCreateResource": "Create Resource",
|
"createInternalResourceDialogCreateResource": "Create Resource",
|
||||||
"createInternalResourceDialogSuccess": "Success",
|
"createInternalResourceDialogSuccess": "Success",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Internal resource created successfully",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
|
||||||
"createInternalResourceDialogError": "Error",
|
"createInternalResourceDialogError": "Error",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Failed to create internal resource",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
|
||||||
"createInternalResourceDialogNameRequired": "Name is required",
|
"createInternalResourceDialogNameRequired": "Name is required",
|
||||||
"createInternalResourceDialogNameMaxLength": "Name must be less than 255 characters",
|
"createInternalResourceDialogNameMaxLength": "Name must be less than 255 characters",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Please select a site",
|
"createInternalResourceDialogPleaseSelectSite": "Please select a site",
|
||||||
@@ -2439,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI Gateway",
|
||||||
"scheme": "Scheme",
|
"scheme": "Scheme",
|
||||||
"createInternalResourceDialogScheme": "Scheme",
|
"createInternalResourceDialogScheme": "Scheme",
|
||||||
"createInternalResourceDialogEnableSsl": "Enable TLS",
|
"createInternalResourceDialogEnableSsl": "Enable TLS",
|
||||||
@@ -3030,6 +3527,7 @@
|
|||||||
"validPassword": "Valid Password",
|
"validPassword": "Valid Password",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Valid Virtual API Key",
|
||||||
"view": "View",
|
"view": "View",
|
||||||
"configManaged": "Config Managed",
|
"configManaged": "Config Managed",
|
||||||
"connectedClient": "Connected Client",
|
"connectedClient": "Connected Client",
|
||||||
@@ -3051,6 +3549,38 @@
|
|||||||
"logRetention": "Log Retention",
|
"logRetention": "Log Retention",
|
||||||
"logRetentionDescription": "Manage how long different types of logs are retained for this organization or disable them",
|
"logRetentionDescription": "Manage how long different types of logs are retained for this organization or disable them",
|
||||||
"requestLogsDescription": "View detailed request logs for HTTPS resources in this organization",
|
"requestLogsDescription": "View detailed request logs for HTTPS resources in this organization",
|
||||||
|
"aiSessionLogs": "AI Gateway Session Logs",
|
||||||
|
"aiSessionLogsDescription": "View prompt and response transcripts for AI gateway requests in this organization",
|
||||||
|
"sidebarLogsAi": "Session Logs",
|
||||||
|
"commandLogsAi": "Session Logs",
|
||||||
|
"sidebarLogsAiUsage": "Usage Analytics",
|
||||||
|
"commandLogsAiUsage": "Usage Analytics",
|
||||||
|
"provider": "Provider",
|
||||||
|
"capability": "Capability",
|
||||||
|
"model": "Model",
|
||||||
|
"virtualApiKey": "Virtual API Key",
|
||||||
|
"noVirtualApiKey": "No virtual API key",
|
||||||
|
"stream": "Stream",
|
||||||
|
"streaming": "Streaming",
|
||||||
|
"nonStreaming": "Non-streaming",
|
||||||
|
"statusCode": "Status Code",
|
||||||
|
"aiSessionId": "Session ID",
|
||||||
|
"aiSessionRequest": "Request",
|
||||||
|
"aiSessionResponse": "Response",
|
||||||
|
"aiSessionNoData": "No data captured",
|
||||||
|
"aiSessionCouldNotParse": "(raw, could not parse transcript)",
|
||||||
|
"aiSessionLogTruncated": "This session was truncated before storage and may be incomplete.",
|
||||||
|
"aiSessionViewRaw": "View Raw JSON",
|
||||||
|
"aiSessionViewChat": "View Chat",
|
||||||
|
"cost": "Cost",
|
||||||
|
"estimated": "Estimated",
|
||||||
|
"tokenUsage": "Token Usage",
|
||||||
|
"promptTokens": "Prompt Tokens",
|
||||||
|
"cacheReadTokens": "Cache Read Tokens",
|
||||||
|
"cacheWriteTokens": "Cache Write Tokens",
|
||||||
|
"completionTokens": "Completion Tokens",
|
||||||
|
"reasoningTokens": "Reasoning Tokens",
|
||||||
|
"totalTokens": "Total Tokens",
|
||||||
"requestAnalyticsDescription": "View detailed request analytics for resources in this organization",
|
"requestAnalyticsDescription": "View detailed request analytics for resources in this organization",
|
||||||
"logRetentionRequestLabel": "HTTP Request Log Retention",
|
"logRetentionRequestLabel": "HTTP Request Log Retention",
|
||||||
"logRetentionRequestDescription": "How long to retain request logs",
|
"logRetentionRequestDescription": "How long to retain request logs",
|
||||||
@@ -3060,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "How long to retain action logs",
|
"logRetentionActionDescription": "How long to retain action logs",
|
||||||
"logRetentionConnectionLabel": "Network Log Retention",
|
"logRetentionConnectionLabel": "Network Log Retention",
|
||||||
"logRetentionConnectionDescription": "How long to retain connection logs",
|
"logRetentionConnectionDescription": "How long to retain connection logs",
|
||||||
|
"logRetentionAISessionsLabel": "AI Gateway Session Log Retention",
|
||||||
|
"logRetentionAISessionsDescription": "How long to retain AI gateway prompt/response session logs",
|
||||||
"logRetentionDisabled": "Disabled",
|
"logRetentionDisabled": "Disabled",
|
||||||
"logRetention3Days": "3 days",
|
"logRetention3Days": "3 days",
|
||||||
"logRetention7Days": "7 days",
|
"logRetention7Days": "7 days",
|
||||||
@@ -3077,8 +3609,8 @@
|
|||||||
"sourceAddress": "Source Address",
|
"sourceAddress": "Source Address",
|
||||||
"destinationAddress": "Destination Address",
|
"destinationAddress": "Destination Address",
|
||||||
"duration": "Duration",
|
"duration": "Duration",
|
||||||
"licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Enterprise Edition license</enterpriseEditionLink> is required. <bookADemoLink>Book a demo or trial</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition license</enterpriseEditionLink> is required. <bookADemoLink>Book a demo or trial</bookADemoLink>",
|
||||||
"certResolver": "Certificate Resolver",
|
"certResolver": "Certificate Resolver",
|
||||||
"certResolverDescription": "Select the certificate resolver to use for this resource.",
|
"certResolverDescription": "Select the certificate resolver to use for this resource.",
|
||||||
"selectCertResolver": "Select Certificate Resolver",
|
"selectCertResolver": "Select Certificate Resolver",
|
||||||
@@ -3276,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Selecting multiple sites enables resilient routing and failover for high availability.",
|
"internalResourceFormMultiSiteRoutingHelp": "Selecting multiple sites enables resilient routing and failover for high availability.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Learn more",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Learn more",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Restrict access to specific TCP/UDP ports or allow/block all ports.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Restrict access to specific TCP/UDP ports or allow/block all ports.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "HTTP configuration",
|
"createInternalResourceDialogHttpConfiguration": "Domain Configuration",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Choose the domain clients will use to reach this resource over HTTP or HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Choose the domain clients will use to reach this resource over HTTP or HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "HTTP configuration",
|
"editInternalResourceDialogHttpConfiguration": "Domain Configuration",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Choose the domain clients will use to reach this resource over HTTP or HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Choose the domain clients will use to reach this resource over HTTP or HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3714,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Unlabeled",
|
"resourceLauncherUnlabeled": "Unlabeled",
|
||||||
|
"resourceLauncherAiGateway": "AI Gateway",
|
||||||
"resourceLauncherNoSite": "No Site",
|
"resourceLauncherNoSite": "No Site",
|
||||||
|
"resourceLauncherAvailableModels": "Available Models",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Models you can use with this AI gateway.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "No models are available for this resource.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Could not load available models.",
|
||||||
|
"resourceLauncherApiKeys": "API Keys",
|
||||||
|
"resourceLauncherApiKeysDescription": "Use your identity key or an attributed key to authenticate with this resource.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Identity Key",
|
||||||
|
"resourceLauncherApiKeysManual": "Attributed Keys",
|
||||||
|
"resourceLauncherApiKeysEmpty": "No API keys are available for this resource.",
|
||||||
|
"resourceLauncherApiKeysError": "Could not load API keys.",
|
||||||
"resourceLauncherNoResourcesInGroup": "No resources in this group",
|
"resourceLauncherNoResourcesInGroup": "No resources in this group",
|
||||||
"resourceLauncherEmptyStateTitle": "No Resources Available",
|
"resourceLauncherEmptyStateTitle": "No Resources Available",
|
||||||
"resourceLauncherEmptyStateDescription": "You don't have access to any resources yet. Contact your administrator to request access.",
|
"resourceLauncherEmptyStateDescription": "You don't have access to any resources yet. Contact your administrator to request access.",
|
||||||
@@ -3741,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Could not delete the launcher view. Please try again.",
|
"resourceLauncherViewDeleteFailedDescription": "Could not delete the launcher view. Please try again.",
|
||||||
"memberPortalPrevious": "Previous",
|
"memberPortalPrevious": "Previous",
|
||||||
"memberPortalNext": "Next",
|
"memberPortalNext": "Next",
|
||||||
"httpSettings": "HTTP Settings",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "TCP Settings",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "UDP Settings",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Establishing a secure connection…",
|
"sshConnectingDescription": "Establishing a secure connection…",
|
||||||
"sshConnecting": "Connecting…",
|
"sshConnecting": "Connecting…",
|
||||||
@@ -3803,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Upload failed",
|
"rdpUploadFailed": "Upload failed",
|
||||||
"rdpUnicodeKeyboardMode": "Unicode keyboard mode",
|
"rdpUnicodeKeyboardMode": "Unicode keyboard mode",
|
||||||
"sessionToolbarShow": "Show toolbar",
|
"sessionToolbarShow": "Show toolbar",
|
||||||
"sessionToolbarHide": "Hide toolbar"
|
"sessionToolbarHide": "Hide toolbar",
|
||||||
|
"actionUpdateSiteApprovals": "Update Site Approvals"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Por favor, asegúrese de que ha iniciado sesión como el usuario correcto.",
|
"inviteLoginUser": "Por favor, asegúrese de que ha iniciado sesión como el usuario correcto.",
|
||||||
"inviteErrorNoUser": "Lo sentimos, pero parece que la invitación a la que intentas acceder no es para un usuario que existe.",
|
"inviteErrorNoUser": "Lo sentimos, pero parece que la invitación a la que intentas acceder no es para un usuario que existe.",
|
||||||
"inviteCreateUser": "Por favor, cree una cuenta primero.",
|
"inviteCreateUser": "Por favor, cree una cuenta primero.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Las invitaciones solo pueden ser aceptadas por cuentas internas. Cierra sesión e inicia sesión con tu contraseña para este correo electrónico.",
|
||||||
|
"inviteLoginInternalOnly": "Las invitaciones requieren una cuenta interna con una contraseña. Crea una cuenta o inicia sesión con tu contraseña.",
|
||||||
"goHome": "Ir a casa",
|
"goHome": "Ir a casa",
|
||||||
"inviteLogInOtherUser": "Iniciar sesión como un usuario diferente",
|
"inviteLogInOtherUser": "Iniciar sesión como un usuario diferente",
|
||||||
"createAnAccount": "Crear una cuenta",
|
"createAnAccount": "Crear una cuenta",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Confirmar Eliminación de Enlace Compartible",
|
"shareDeleteConfirm": "Confirmar Eliminación de Enlace Compartible",
|
||||||
"shareQuestionRemove": "¿Está seguro de que desea borrar este enlace compartido?",
|
"shareQuestionRemove": "¿Está seguro de que desea borrar este enlace compartido?",
|
||||||
"shareMessageRemove": "Una vez borrado, el enlace dejará de funcionar y cualquier persona que lo use perderá acceso al recurso.",
|
"shareMessageRemove": "Una vez borrado, el enlace dejará de funcionar y cualquier persona que lo use perderá acceso al recurso.",
|
||||||
"shareTokenDescription": "El token de acceso puede ser pasado de dos maneras: como parámetro de consulta o en las cabeceras de solicitud. Estos deben ser pasados del cliente en cada solicitud de acceso autenticado.",
|
"shareTokenDescription": "El token de acceso se puede pasar como un parámetro de consulta o en los encabezados de la solicitud. Por defecto, se debe enviar en cada solicitud. Si la persistencia de sesión está habilitada, la primera solicitud lo intercambia por una cookie de sesión.",
|
||||||
"accessToken": "Token de acceso",
|
"accessToken": "Token de acceso",
|
||||||
"usageExamples": "Ejemplos de uso",
|
"usageExamples": "Ejemplos de uso",
|
||||||
"tokenId": "ID de token",
|
"tokenId": "ID de token",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Título (opcional)",
|
"shareTitleOptional": "Título (opcional)",
|
||||||
"sharePathOptional": "Ruta (opcional)",
|
"sharePathOptional": "Ruta (opcional)",
|
||||||
"sharePathDescription": "El enlace redirigirá a los usuarios a esta ruta tras la autenticación.",
|
"sharePathDescription": "El enlace redirigirá a los usuarios a esta ruta tras la autenticación.",
|
||||||
|
"shareAssociateUserOptional": "Asociar Usuario (opcional)",
|
||||||
|
"shareAssociateUserDescription": "Cuando está configurado, las solicitudes que usan este enlace se atribuyen al usuario en los registros de acceso y encabezados de identidad. El enlace se elimina si el usuario abandona la organización.",
|
||||||
|
"userSelect": "Seleccione usuario",
|
||||||
|
"usersNotFound": "No se encontraron usuarios",
|
||||||
"expireIn": "Caduca en",
|
"expireIn": "Caduca en",
|
||||||
"neverExpire": "Nunca expirar",
|
"neverExpire": "Nunca expirar",
|
||||||
|
"sharePersistSession": "Persistir sesión después del primer uso",
|
||||||
|
"sharePersistSessionDescription": "Cuando está habilitado, la primera solicitud con este token mediante un parámetro de consulta o encabezado configura una cookie de sesión, por lo que las solicitudes posteriores no necesitan el token. Dejar desactivado para clientes de API que deben enviar el token en cada solicitud.",
|
||||||
"shareExpireDescription": "El tiempo de caducidad es cuánto tiempo el enlace será utilizable y proporcionará acceso al recurso. Después de este tiempo, el enlace ya no funcionará, y los usuarios que usaron este enlace perderán el acceso al recurso.",
|
"shareExpireDescription": "El tiempo de caducidad es cuánto tiempo el enlace será utilizable y proporcionará acceso al recurso. Después de este tiempo, el enlace ya no funcionará, y los usuarios que usaron este enlace perderán el acceso al recurso.",
|
||||||
"shareSeeOnce": "Sólo podrás ver este enlace una vez. Asegúrate de copiarlo.",
|
"shareSeeOnce": "Sólo podrás ver este enlace una vez. Asegúrate de copiarlo.",
|
||||||
"shareAccessHint": "Cualquiera con este enlace puede acceder al recurso. Compártelo con cuidado.",
|
"shareAccessHint": "Cualquiera con este enlace puede acceder al recurso. Compártelo con cuidado.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Ningún país encontrado.",
|
"noCountryFound": "Ningún país encontrado.",
|
||||||
"siteSelectionDescription": "Este sitio proporcionará conectividad al objetivo.",
|
"siteSelectionDescription": "Este sitio proporcionará conectividad al objetivo.",
|
||||||
"resourceType": "Tipo de recurso",
|
"resourceType": "Tipo de recurso",
|
||||||
"resourceTypeDescription": "Esto controla el protocolo del recurso y cómo se renderizará en el navegador. Esto no se puede cambiar más tarde.",
|
"resourceTypeDescription": "Esto controla el protocolo del recurso y no se puede cambiar más tarde.",
|
||||||
|
"resourceTypeSearch": "Buscar tipos de recursos...",
|
||||||
|
"resourceTypeNotFound": "No se encontró ningún tipo de recurso",
|
||||||
|
"resourceTypeHttpDescription": "Proxy de tráfico web a través de HTTPS usando un nombre de dominio",
|
||||||
|
"resourceTypeInferenceDescription": "Dirige las solicitudes de IA a través de proveedores adjuntos",
|
||||||
|
"resourceTypeSshDescription": "Accede a un servidor SSH desde el navegador",
|
||||||
|
"resourceTypeRdpDescription": "Accede a un escritorio remoto desde el navegador",
|
||||||
|
"resourceTypeVncDescription": "Accede a un escritorio VNC desde el navegador",
|
||||||
|
"resourceTypeTcpDescription": "Proxy de tráfico TCP crudo usando un número de puerto",
|
||||||
|
"resourceTypeUdpDescription": "Proxy de tráfico UDP crudo usando un número de puerto",
|
||||||
|
"privateResourceTypeDescription": "Esto controla cómo los clientes acceden al recurso. No se puede cambiar más tarde.",
|
||||||
|
"privateResourceTypeHostDescription": "Expone un host único en la red del sitio a los clientes conectados",
|
||||||
|
"privateResourceTypeCidrDescription": "Expón un rango CIDR en la red del sitio para los clientes conectados",
|
||||||
|
"privateResourceTypeHttpDescription": "Accede a un servicio HTTP o HTTPS a través de un dominio",
|
||||||
|
"privateResourceTypeSshDescription": "Accede a un servidor SSH desde clientes conectados",
|
||||||
"resourceDomainDescription": "El recurso se servirá en este nombre de dominio completamente calificado.",
|
"resourceDomainDescription": "El recurso se servirá en este nombre de dominio completamente calificado.",
|
||||||
"resourceHTTPSSettings": "Configuración HTTPS",
|
"resourceHTTPSSettings": "Configuración HTTPS",
|
||||||
"resourceHTTPSSettingsDescription": "Configurar cómo se accederá al recurso a través de HTTPS",
|
"resourceHTTPSSettingsDescription": "Configurar cómo se accederá al recurso a través de HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Aprovisionamiento",
|
"provisioningManage": "Aprovisionamiento",
|
||||||
"provisioningDescription": "Administrar las claves de aprovisionamiento y revisar los sitios pendientes de aprobación.",
|
"provisioningDescription": "Administrar las claves de aprovisionamiento y revisar los sitios pendientes de aprobación.",
|
||||||
"pendingSites": "Sitios pendientes",
|
"pendingSites": "Sitios pendientes",
|
||||||
"siteApproveSuccess": "Sitio aprobado con éxito",
|
"siteApproveSuccess": "Sitio y recursos asociados aprobados correctamente",
|
||||||
"siteApproveError": "Error al aprobar el sitio",
|
"siteApproveError": "Error al aprobar el sitio",
|
||||||
|
"siteReject": "Rechazar Sitio",
|
||||||
|
"siteQuestionReject": "¿Está seguro de que desea rechazar este sitio?",
|
||||||
|
"siteMessageReject": "Esto eliminará permanentemente el sitio y cualquier recurso asociado que aún esté pendiente.",
|
||||||
|
"siteConfirmReject": "Confirmar Rechazo del Sitio",
|
||||||
|
"siteRejectSuccess": "Sitio rechazado correctamente",
|
||||||
|
"siteRejectError": "Error al rechazar el sitio",
|
||||||
"provisioningKeys": "Claves de aprovisionamiento",
|
"provisioningKeys": "Claves de aprovisionamiento",
|
||||||
"searchProvisioningKeys": "Buscar claves de suministro...",
|
"searchProvisioningKeys": "Buscar claves de suministro...",
|
||||||
"provisioningKeysAdd": "Generar clave de aprovisionamiento",
|
"provisioningKeysAdd": "Generar clave de aprovisionamiento",
|
||||||
@@ -466,12 +494,12 @@
|
|||||||
"provisioningKeysSave": "Guardar la clave de aprovisionamiento",
|
"provisioningKeysSave": "Guardar la clave de aprovisionamiento",
|
||||||
"provisioningKeysSaveDescription": "Sólo podrás verlo una vez. Copítalo a un lugar seguro.",
|
"provisioningKeysSaveDescription": "Sólo podrás verlo una vez. Copítalo a un lugar seguro.",
|
||||||
"provisioningKeysErrorCreate": "Error al crear la clave de provisioning",
|
"provisioningKeysErrorCreate": "Error al crear la clave de provisioning",
|
||||||
"provisioningKeysList": "Nueva clave de aprovisionamiento",
|
"provisioningKeysList": "Nueva Clave de Provisión",
|
||||||
"provisioningKeysMaxBatchSize": "Tamaño máximo de lote",
|
"provisioningKeysMaxBatchSize": "Tamaño Máximo del Lote",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Tamaño ilimitado del lote (sin límite)",
|
"provisioningKeysUnlimitedBatchSize": "Tamaño ilimitado del lote (sin límite)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Ilimitado",
|
"provisioningKeysMaxBatchUnlimited": "Ilimitado",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Introduzca un tamaño máximo de lote válido (1–1,000,000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Introduzca un tamaño máximo de lote válido (1–1,000,000).",
|
||||||
"provisioningKeysValidUntil": "Válido hasta",
|
"provisioningKeysValidUntil": "Válido Hasta",
|
||||||
"provisioningKeysValidUntilHint": "Dejar vacío para no expirar.",
|
"provisioningKeysValidUntilHint": "Dejar vacío para no expirar.",
|
||||||
"provisioningKeysValidUntilInvalid": "Introduzca una fecha y hora válidas.",
|
"provisioningKeysValidUntilInvalid": "Introduzca una fecha y hora válidas.",
|
||||||
"provisioningKeysNumUsed": "Tiempos usados",
|
"provisioningKeysNumUsed": "Tiempos usados",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "Nunca",
|
"provisioningKeysNeverUsed": "Nunca",
|
||||||
"provisioningKeysEdit": "Editar clave de aprovisionamiento",
|
"provisioningKeysEdit": "Editar clave de aprovisionamiento",
|
||||||
"provisioningKeysEditDescription": "Actualizar el tamaño máximo de lote y el tiempo de caducidad para esta clave.",
|
"provisioningKeysEditDescription": "Actualizar el tamaño máximo de lote y el tiempo de caducidad para esta clave.",
|
||||||
"provisioningKeysApproveNewSites": "Aprobar nuevos sitios",
|
"provisioningKeysApproveNewSites": "Aprobar Nuevos Sitios",
|
||||||
"provisioningKeysApproveNewSitesDescription": "Aprobar automáticamente los sitios que se registran con esta clave.",
|
"provisioningKeysApproveNewSitesDescription": "Aprobar automáticamente los sitios que se registran con esta clave.",
|
||||||
"provisioningKeysUpdateError": "Error al actualizar la clave de aprovisionamiento",
|
"provisioningKeysUpdateError": "Error al actualizar la clave de aprovisionamiento",
|
||||||
"provisioningKeysUpdated": "Clave de aprovisionamiento actualizada",
|
"provisioningKeysUpdated": "Clave de aprovisionamiento actualizada",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Guardar ajustes",
|
"authMethodsSave": "Guardar ajustes",
|
||||||
"policyAuthStackTitle": "Autenticación",
|
"policyAuthStackTitle": "Autenticación",
|
||||||
"policyAuthStackDescription": "Controla qué métodos de autenticación son necesarios para acceder a este recurso",
|
"policyAuthStackDescription": "Controla qué métodos de autenticación son necesarios para acceder a este recurso",
|
||||||
|
"policyAuthInferenceStackDescription": "Elige qué usuarios y roles pueden autenticarse en este gateway de IA",
|
||||||
"policyAuthOrLogicTitle": "Múltiples métodos de autenticación activos",
|
"policyAuthOrLogicTitle": "Múltiples métodos de autenticación activos",
|
||||||
"policyAuthOrLogicBanner": "Los visitantes pueden autenticarse utilizando cualquier método activo a continuación. No necesitan completar todos ellos.",
|
"policyAuthOrLogicBanner": "Los visitantes pueden autenticarse utilizando cualquier método activo a continuación. No necesitan completar todos ellos.",
|
||||||
"policyAuthMethodActive": "Activo",
|
"policyAuthMethodActive": "Activo",
|
||||||
"policyAuthMethodOff": "Apagado",
|
"policyAuthMethodOff": "Apagado",
|
||||||
"policyAuthSsoTitle": "SSO de Plataforma",
|
"policyAuthSsoTitle": "SSO de Plataforma",
|
||||||
"policyAuthSsoDescription": "Requiere iniciar sesión a través del proveedor de identidad de tu organización",
|
"policyAuthSsoDescription": "Requiere iniciar sesión a través del proveedor de identidad de tu organización",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "URL de inicio de sesión",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Cada usuario ya tiene una clave API de identidad, por lo que solo necesitas crear claves API virtuales para clientes no usuarios o acceso compartido. Los usuarios pueden recuperar su clave iniciando sesión con su proveedor de identidad en la URL de este recurso, donde se mostrará después del inicio de sesión.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Cada usuario ya tiene una clave API de identidad, por lo que solo necesitas crear claves API virtuales para clientes no usuarios o acceso compartido. Los usuarios recuperan su clave aquí después de iniciar sesión con su proveedor de identidad.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} usuarios, {roles} roles",
|
"policyAuthSsoSummary": "{idp} · {users} usuarios, {roles} roles",
|
||||||
"policyAuthSsoDefaultIdp": "Proveedor por defecto",
|
"policyAuthSsoDefaultIdp": "Proveedor por defecto",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Añadir Proveedor de Identidad Predeterminado",
|
"policyAuthAddDefaultIdentityProvider": "Añadir Proveedor de Identidad Predeterminado",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Versión",
|
"newtVersion": "Versión",
|
||||||
"architecture": "Arquitectura",
|
"architecture": "Arquitectura",
|
||||||
"sites": "Sitios",
|
"sites": "Sitios",
|
||||||
"siteWgAnyClients": "Usa cualquier cliente de Wirex para conectarte. Tendrás que dirigirte a los recursos internos usando la IP de compañeros.",
|
"siteWgAnyClients": "Usa cualquier cliente de WireGuard para conectarte. Tendrás que dirigirte a recursos privados usando la IP del par.",
|
||||||
"siteWgCompatibleAllClients": "Compatible con todos los clientes de Wirex Guard",
|
"siteWgCompatibleAllClients": "Compatible con todos los clientes de Wirex Guard",
|
||||||
"siteWgManualConfigurationRequired": "Configuración manual requerida",
|
"siteWgManualConfigurationRequired": "Configuración manual requerida",
|
||||||
"userErrorNotAdminOrOwner": "El usuario no es un administrador o propietario",
|
"userErrorNotAdminOrOwner": "El usuario no es un administrador o propietario",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Se requiere un nuevo rol",
|
"accessRoleErrorNewRequired": "Se requiere un nuevo rol",
|
||||||
"accessRoleErrorRemove": "Error al eliminar el rol",
|
"accessRoleErrorRemove": "Error al eliminar el rol",
|
||||||
"accessRoleErrorRemoveDescription": "Ocurrió un error mientras se eliminaba el rol.",
|
"accessRoleErrorRemoveDescription": "Ocurrió un error mientras se eliminaba el rol.",
|
||||||
|
"accessRoleInferenceBudget": "Presupuesto de IA",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Configura cómo los miembros de este rol restringen el uso de IA según los límites de gasto o de tokens",
|
||||||
"accessRoleName": "Nombre del Rol",
|
"accessRoleName": "Nombre del Rol",
|
||||||
"accessRoleQuestionRemove": "Estás a punto de eliminar el rol `{name}`. No puedes deshacer esta acción.",
|
"accessRoleQuestionRemove": "Estás a punto de eliminar el rol `{name}`. No puedes deshacer esta acción.",
|
||||||
"accessRoleRemove": "Quitar rol",
|
"accessRoleRemove": "Quitar rol",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Crear usuario Org",
|
"createOrgUser": "Crear usuario Org",
|
||||||
"actionUpdateOrg": "Actualizar organización",
|
"actionUpdateOrg": "Actualizar organización",
|
||||||
"actionRemoveInvitation": "Eliminar invitación",
|
"actionRemoveInvitation": "Eliminar invitación",
|
||||||
|
"actionRemoveUserRole": "Quitar Rol de Usuario",
|
||||||
"actionUpdateUser": "Actualizar usuario",
|
"actionUpdateUser": "Actualizar usuario",
|
||||||
"actionGetUser": "Obtener usuario",
|
"actionGetUser": "Obtener usuario",
|
||||||
"actionGetOrgUser": "Obtener usuario de la organización",
|
"actionGetOrgUser": "Obtener usuario de la organización",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Eliminar sitio",
|
"actionDeleteSite": "Eliminar sitio",
|
||||||
"actionGetSite": "Obtener sitio",
|
"actionGetSite": "Obtener sitio",
|
||||||
"actionListSites": "Listar sitios",
|
"actionListSites": "Listar sitios",
|
||||||
|
"actionCreateAiProvider": "Crear Proveedor de IA",
|
||||||
|
"actionDeleteAiProvider": "Eliminar Proveedor de IA",
|
||||||
|
"actionGetAiProvider": "Obtener Proveedor de IA",
|
||||||
|
"actionListAiProviders": "Lista de Proveedores de IA",
|
||||||
|
"actionUpdateAiProvider": "Actualizar Proveedor de IA",
|
||||||
|
"actionCreateAiModel": "Crear Modelo de IA",
|
||||||
|
"actionDeleteAiModel": "Eliminar Modelo de IA",
|
||||||
|
"actionGetAiModel": "Obtener Modelo de IA",
|
||||||
|
"actionListAiModels": "Lista de Modelos de IA",
|
||||||
|
"actionUpdateAiModel": "Actualizar Modelo de IA",
|
||||||
|
"actionCreateAiBudget": "Crear Presupuesto de IA",
|
||||||
|
"actionDeleteAiBudget": "Eliminar Presupuesto de IA",
|
||||||
|
"actionGetAiBudget": "Obtener Presupuesto de IA",
|
||||||
|
"actionListAiBudgets": "Lista de Presupuestos de IA",
|
||||||
|
"actionUpdateAiBudget": "Actualizar Presupuesto de IA",
|
||||||
|
"actionListResourceAiModels": "Lista de Modelos de IA de Recursos",
|
||||||
|
"actionSetResourceAiModels": "Establecer Modelos de IA de Recursos",
|
||||||
|
"actionCreateVirtualApiKey": "Crear Clave API Virtual",
|
||||||
|
"actionDeleteVirtualApiKey": "Eliminar Clave API Virtual",
|
||||||
|
"actionGetVirtualApiKey": "Obtener Clave API Virtual",
|
||||||
|
"actionListVirtualApiKeys": "Lista de Claves API Virtuales",
|
||||||
|
"actionUpdateVirtualApiKey": "Actualizar Clave API Virtual",
|
||||||
"actionApplyBlueprint": "Aplicar plano",
|
"actionApplyBlueprint": "Aplicar plano",
|
||||||
"actionListBlueprints": "Listar blueprints",
|
"actionListBlueprints": "Listar blueprints",
|
||||||
"actionGetBlueprint": "Obtener blueprint",
|
"actionGetBlueprint": "Obtener blueprint",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Ingrese el token de configuración desde la consola del servidor.",
|
"setupTokenDescription": "Ingrese el token de configuración desde la consola del servidor.",
|
||||||
"setupTokenRequired": "Se requiere el token de configuración",
|
"setupTokenRequired": "Se requiere el token de configuración",
|
||||||
"actionUpdateSite": "Actualizar sitio",
|
"actionUpdateSite": "Actualizar sitio",
|
||||||
|
"actionApproveSite": "Aprobar Sitio",
|
||||||
|
"actionRejectSite": "Rechazar Sitio",
|
||||||
"actionResetSiteBandwidth": "Restablecer ancho de banda de la organización",
|
"actionResetSiteBandwidth": "Restablecer ancho de banda de la organización",
|
||||||
"actionListSiteRoles": "Lista de roles permitidos del sitio",
|
"actionListSiteRoles": "Lista de roles permitidos del sitio",
|
||||||
"actionCreateResource": "Crear Recurso",
|
"actionCreateResource": "Crear Recurso",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Establecer Pincode del recurso",
|
"actionSetResourcePincode": "Establecer Pincode del recurso",
|
||||||
"actionSetResourceEmailWhitelist": "Establecer lista blanca de correo de recursos",
|
"actionSetResourceEmailWhitelist": "Establecer lista blanca de correo de recursos",
|
||||||
"actionGetResourceEmailWhitelist": "Obtener correo electrónico de recursos",
|
"actionGetResourceEmailWhitelist": "Obtener correo electrónico de recursos",
|
||||||
|
"actionListResourcePolicies": "Lista de Políticas de Recursos",
|
||||||
|
"actionCreateResourcePolicy": "Crear Política de Recursos",
|
||||||
"actionGetResourcePolicy": "Obtener política de recursos",
|
"actionGetResourcePolicy": "Obtener política de recursos",
|
||||||
"actionUpdateResourcePolicy": "Actualizar política de recursos",
|
"actionUpdateResourcePolicy": "Actualizar política de recursos",
|
||||||
|
"actionDeleteResourcePolicy": "Eliminar Política de Recursos",
|
||||||
"actionSetResourcePolicyUsers": "Definir política de recursos para usuarios",
|
"actionSetResourcePolicyUsers": "Definir política de recursos para usuarios",
|
||||||
"actionSetResourcePolicyRoles": "Definir roles de política de recursos",
|
"actionSetResourcePolicyRoles": "Definir roles de política de recursos",
|
||||||
"actionSetResourcePolicyPassword": "Definir contraseña de política de recursos",
|
"actionSetResourcePolicyPassword": "Definir contraseña de política de recursos",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Listar invitaciones",
|
"actionListInvitations": "Listar invitaciones",
|
||||||
"actionExportLogs": "Exportar registros",
|
"actionExportLogs": "Exportar registros",
|
||||||
"actionViewLogs": "Ver registros",
|
"actionViewLogs": "Ver registros",
|
||||||
|
"actionCreateSiteProvisioningKey": "Crear clave de aprovisionamiento del sitio",
|
||||||
|
"actionListSiteProvisioningKeys": "Listado de claves de aprovisionamiento del sitio",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Actualizar clave de aprovisionamiento del sitio",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Eliminar clave de aprovisionamiento del sitio",
|
||||||
"noneSelected": "Ninguno seleccionado",
|
"noneSelected": "Ninguno seleccionado",
|
||||||
"orgNotFound2": "No se encontraron organizaciones.",
|
"orgNotFound2": "No se encontraron organizaciones.",
|
||||||
"search": "Buscar…",
|
"search": "Buscar…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Introduzca el código de su aplicación de autenticación o uno de sus códigos de copia de seguridad de un solo uso.",
|
"otpAuthDescription": "Introduzca el código de su aplicación de autenticación o uno de sus códigos de copia de seguridad de un solo uso.",
|
||||||
"otpAuthSubmit": "Enviar código",
|
"otpAuthSubmit": "Enviar código",
|
||||||
"idpContinue": "O continuar con",
|
"idpContinue": "O continuar con",
|
||||||
|
"idpLastUsed": "Último Uso",
|
||||||
"otpAuthBack": "Volver a la contraseña",
|
"otpAuthBack": "Volver a la contraseña",
|
||||||
"navbar": "Menú de navegación",
|
"navbar": "Menú de navegación",
|
||||||
"navbarDescription": "Menú de navegación principal para la aplicación",
|
"navbarDescription": "Menú de navegación principal para la aplicación",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Crear Cliente de Máquina",
|
"commandPaletteCreateMachineClient": "Crear Cliente de Máquina",
|
||||||
"commandPaletteCreateAlertRule": "Crear Regla de Alerta",
|
"commandPaletteCreateAlertRule": "Crear Regla de Alerta",
|
||||||
"commandPaletteCreateIdentityProvider": "Crear proveedor de identidad",
|
"commandPaletteCreateIdentityProvider": "Crear proveedor de identidad",
|
||||||
|
"commandPaletteCreateAiProvider": "Crear proveedor de IA",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Crear Clave API Virtual",
|
||||||
"commandPaletteToggleTheme": "Cambiar tema",
|
"commandPaletteToggleTheme": "Cambiar tema",
|
||||||
"commandPaletteChooseOrganization": "Elegir organización",
|
"commandPaletteChooseOrganization": "Elegir organización",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Invitaciones",
|
"sidebarInvitations": "Invitaciones",
|
||||||
"sidebarRoles": "Roles",
|
"sidebarRoles": "Roles",
|
||||||
"sidebarShareableLinks": "Enlaces Compartibles",
|
"sidebarShareableLinks": "Enlaces Compartibles",
|
||||||
|
"sidebarAiGateway": "Gateway de IA",
|
||||||
|
"sidebarAiProviders": "Proveedores",
|
||||||
|
"commandAiProviders": "Proveedores de IA",
|
||||||
|
"sidebarVirtualApiKeys": "Claves API Virtuales",
|
||||||
|
"sidebarMyApiKeys": "Tus Claves API",
|
||||||
|
"sidebarAccount": "Lanzador",
|
||||||
|
"commandVirtualApiKeys": "Claves API Virtuales",
|
||||||
|
"virtualApiKeysTitle": "Administrar Claves API Virtuales",
|
||||||
|
"virtualApiKeysDescription": "Crea y gestiona claves API manuales para el acceso al Gateway público de IA",
|
||||||
|
"virtualApiKeysTabIdentity": "Claves de Identidad",
|
||||||
|
"virtualApiKeysTabVirtual": "Claves Virtuales",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Claves de Identidad para Cada Usuario",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Cada usuario ya tiene una clave de identidad Pangolin para esta organización. Es única para su cuenta y los autentica en gateways de IA a los que pueden acceder.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Ejemplo",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Cómo los Usuarios Obtienen su Clave",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Visita una URL de gateway público de IA en el navegador e inicia sesión con su cuenta.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "O ve a <url></url> mientras estás conectado.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Puedes crear claves API virtuales adicionales en la pestaña de Claves Virtuales. Esas claves pueden estar limitadas a gateways públicos de IA específicos y opcionalmente asociadas a un usuario. Crear una clave concede inmediatamente acceso a los gateways públicos de IA seleccionados.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Crear Manualmente una Clave",
|
||||||
|
"virtualApiKeysEmailIdentity": "Claves de Identidad por Correo Electrónico",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Envía a cada usuario o rol seleccionado su clave de identidad Pangolin.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Enviar a todos los usuarios",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Enviar correo electrónico a cada miembro de la organización que tenga un correo electrónico de cuenta.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Usuarios",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Roles",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Enviar Correos Electrónicos",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Claves de identidad enviadas por correo electrónico",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Se enviaron {sent} correos electrónicos.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} usuarios se omitieron porque no tienen una dirección de correo electrónico.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Selecciona al menos un usuario o rol, o envía a todos los usuarios.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Error al enviar claves de identidad",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "No se pudieron enviar por correo electrónico las claves de identidad",
|
||||||
|
"virtualApiKeysBannerTitle": "Claves de Identidad para Cada Usuario",
|
||||||
|
"virtualApiKeysBannerDescription": "Cada usuario ya tiene una clave de identidad disponible en {keysUrl}. También puedes generar manualmente claves aquí que conceden acceso directo a gateways públicos de IA.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Ver Claves de Identidad",
|
||||||
|
"virtualApiKeys": "Claves API Virtuales",
|
||||||
|
"virtualApiKeysSearch": "Buscar claves...",
|
||||||
|
"virtualApiKeysCreate": "Crear Clave API Virtual",
|
||||||
|
"virtualApiKeysCreateDescription": "Genera una clave manual que pueda llamar a gateways públicos de IA en esta organización",
|
||||||
|
"virtualApiKeysCreateButton": "Crear Clave",
|
||||||
|
"virtualApiKeysEmpty": "Aún no hay claves API virtuales",
|
||||||
|
"virtualApiKeysName": "Nombre",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Descripción (opcional)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Asociar Usuario (opcional)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Asocia esta clave con un usuario para rastrear el uso. Una vez creada, esta clave concede inmediatamente acceso a los gateways públicos de IA seleccionados. No necesitas asociar un usuario manualmente al recurso. La clave también aparecerá en el perfil del usuario.",
|
||||||
|
"virtualApiKeysAllResources": "Todos los gateways públicos de IA",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Permitir que esta clave acceda a cada gateway público de IA en la organización",
|
||||||
|
"virtualApiKeysSelectResources": "Gateways Públicos de IA",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Seleccionar recursos",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Elige a qué gateways públicos de IA puede acceder esta clave",
|
||||||
|
"virtualApiKeysNoResources": "Sin recursos",
|
||||||
|
"virtualApiKeysSecret": "Clave",
|
||||||
|
"virtualApiKeysCopyKey": "Copia esta clave. Puedes verla nuevamente más tarde desde la tabla o al editar.",
|
||||||
|
"virtualApiKeysViewSecret": "Ver Secreto",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Secreto de la Clave API Virtual",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Este secreto concede acceso a los gateways públicos de IA asignados a esta clave",
|
||||||
|
"virtualApiKeysEdit": "Editar Clave API Virtual",
|
||||||
|
"virtualApiKeysEditDescription": "Actualiza el usuario asociado y el acceso al gateway público de IA para esta clave",
|
||||||
|
"virtualApiKeysSaveButton": "Guardar Cambios",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Selecciona al menos un gateway público de IA, o habilita todos los gateways públicos de IA",
|
||||||
|
"virtualApiKeysUpdated": "Clave API virtual actualizada",
|
||||||
|
"virtualApiKeysUpdatedDescription": "La clave API virtual ha sido actualizada",
|
||||||
|
"virtualApiKeysErrorUpdate": "Error al actualizar la clave API virtual",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Error al actualizar clave API virtual",
|
||||||
|
"virtualApiKeysErrorCreate": "Error al crear clave API virtual",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Error al crear clave API virtual",
|
||||||
|
"virtualApiKeysErrorDelete": "Error al eliminar clave API virtual",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Error al eliminar clave API virtual",
|
||||||
|
"virtualApiKeysDeleted": "Clave API virtual eliminada",
|
||||||
|
"virtualApiKeysDeletedDescription": "La clave API virtual ha sido eliminada",
|
||||||
|
"virtualApiKeysDelete": "Eliminar Clave API Virtual",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Eliminar Clave",
|
||||||
|
"virtualApiKeysQuestionRemove": "¿Está seguro de que desea eliminar esta clave API virtual?",
|
||||||
|
"virtualApiKeysMessageRemove": "Los clientes que usen esta clave perderán acceso inmediatamente.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Error al cargar el secreto",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Error al cargar el secreto de la clave API virtual",
|
||||||
|
"virtualApiKeysFilterUnassigned": "No asignado",
|
||||||
|
"virtualApiKeysInferenceBudget": "Presupuesto",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Configura cómo esta clave restringe el uso de IA según los límites de gasto o de tokens",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Correo electrónico al generar",
|
||||||
|
"virtualApiKeysEmailThisKey": "Envía este correo electrónico",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Envía la clave al usuario asociado y direcciones adicionales después de que se cree",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Envía la clave actual al usuario asociado y direcciones adicionales",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "El correo electrónico no está configurado en este servidor",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Configure SMTP para enviar claves API virtuales por correo electrónico.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Enviar al usuario asociado",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Envía la clave al correo electrónico de la cuenta del usuario asociado",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Asocia un usuario para enviar la clave a ese usuario",
|
||||||
|
"virtualApiKeysEmailAdditional": "Correos electrónicos adicionales",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Agrega un correo electrónico y presiona Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Selecciona el usuario asociado o agrega al menos una dirección de correo electrónico",
|
||||||
|
"myVirtualApiKeysTitle": "Tus Claves API",
|
||||||
|
"myVirtualApiKeysDescription": "Ve tu clave de identidad y cualquier clave API virtuales atribuidas a ti en esta organización",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Tus Claves API para {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Ve tu clave de identidad y claves API virtuales atribuidas a ti que pueden acceder a {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Clave de Identidad",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Tu Clave API Personal",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Tu clave personal para esta organización. Es única para tu cuenta y se utiliza para identificarte cuando llamas a recursos del Gateway de IA.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Tu Clave API Personal para {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Tu clave personal para esta organización. Úsala para llamar a {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Claves Atribuidas",
|
||||||
|
"myVirtualApiKeysManualDescription": "Claves API virtuales manuales que un administrador ha asociado con tu cuenta",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Claves API virtuales manuales asociadas a tu cuenta que pueden acceder a {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Aún no hay claves atribuidas",
|
||||||
|
"myVirtualApiKeysKindUser": "Identidad",
|
||||||
|
"myVirtualApiKeysKindManual": "Manual",
|
||||||
|
"myVirtualApiKeysUnnamed": "Clave sin nombre",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Revelar Secreto",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Este secreto te autentica en los recursos del Gateway de IA",
|
||||||
|
"aiClientConfigTitle": "Configura agentes de codificación",
|
||||||
|
"aiClientConfigDescription": "Copie la configuración para los agentes de codificación populares o deje que el CLI de Pangolin lo configure automáticamente.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Herramienta de codificación agentic de Anthropic para el terminal.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Herramienta de codificación agentic de OpenAI para el terminal.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Agente de codificación de terminal de código abierto.",
|
||||||
|
"aiClientConfigDescriptionCursor": "Editor de código AI construido sobre VS Code.",
|
||||||
|
"aiClientConfigSetup": "Configuración",
|
||||||
|
"aiClientConfigTabCli": "Automático (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Configuración manual",
|
||||||
|
"aiClientConfigPreset": "Configuración",
|
||||||
|
"aiClientConfigStep": "Paso {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Este fragmento incluye valores de ejemplo, como un nombre de modelo o URL de recursos. Reemplace con los suyos antes de usarlo.",
|
||||||
|
"aiClientConfigRevealError": "No se pudo cargar su clave API.",
|
||||||
|
"aiClientConfigRevealRetry": "Intentar de nuevo",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Este recurso se puede usar desde clientes comunes como Claude Code y OpenCode. <configLink>Aprenda más</configLink>",
|
||||||
|
"aiProvidersTitle": "Proveedores de IA",
|
||||||
|
"aiProvidersDescription": "Conecta proveedores de modelos para cargas de trabajo de IA en esta organización",
|
||||||
|
"aiProvidersBannerTitle": "Conecta Proveedores de Modelos",
|
||||||
|
"aiProvidersBannerDescription": "Los proveedores son los backends de modelo que Pangolin usa para cargas de trabajo de IA. Conecta OpenAI, Anthropic y otros proveedores aquí, luego adjúntalos a gateways públicos de IA para que los usuarios puedan llamar a modelos con acceso consciente de identidad, presupuestos y registros.",
|
||||||
|
"aiProvidersAdd": "Agregar Proveedor",
|
||||||
|
"aiProvidersSearch": "Buscar proveedores...",
|
||||||
|
"aiProvidersEmpty": "Aún no hay proveedores de IA",
|
||||||
|
"aiProviderCreate": "Crear Proveedor de IA",
|
||||||
|
"aiProviderCreateDescription": "Agrega un proveedor de modelos para esta organización",
|
||||||
|
"aiProviderSeeAll": "Ver Todos los Proveedores",
|
||||||
|
"aiProviderSetting": "Ajustes del Proveedor para {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Configura este proveedor de IA",
|
||||||
|
"aiProviderGeneral": "General",
|
||||||
|
"aiProviderGeneralDescription": "Configuraciones básicas para este proveedor",
|
||||||
|
"aiProviderConfiguration": "Configuración",
|
||||||
|
"aiProviderConfigurationDescription": "Enrutamiento de red y autenticación para este proveedor",
|
||||||
|
"aiProviderNetworkSettings": "Configuraciones de Red",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Elige cómo llega el tráfico a este proveedor",
|
||||||
|
"aiProviderAuthSettings": "Autenticación",
|
||||||
|
"aiProviderAuthSettingsDescription": "Configura cómo este proveedor autentica solicitudes a su URL upstream",
|
||||||
|
"aiProviderBudgetSettings": "Presupuesto",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Configura cómo este proveedor restringe el uso basado en los límites de gasto o de tokens",
|
||||||
|
"aiBudgetAdd": "Agregar Presupuesto",
|
||||||
|
"aiBudgetEmpty": "Aún no hay presupuestos configurados. Haz clic en Agregar Presupuesto para establecer un límite de gasto o de tokens.",
|
||||||
|
"aiBudgetUnit": "Tipo de Gasto",
|
||||||
|
"aiBudgetPeriod": "Período de Restablecimiento",
|
||||||
|
"aiBudgetAmount": "Gasto Máximo",
|
||||||
|
"aiBudgetAmountPlaceholder": "Gasto máximo",
|
||||||
|
"aiBudgetPeriodHourly": "Por hora",
|
||||||
|
"aiBudgetPeriodDaily": "Diario",
|
||||||
|
"aiBudgetPeriodWeekly": "Semanal",
|
||||||
|
"aiBudgetPeriodMonthly": "Mensual",
|
||||||
|
"aiBudgetPeriodYearly": "Anual",
|
||||||
|
"aiBudgetPeriodLifetime": "De por vida",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Tokens",
|
||||||
|
"aiBudgetConflictError": "Ya existe un presupuesto para este período de restablecimiento y tipo de gasto",
|
||||||
|
"aiBudgetInvalidAmountError": "Ingresa un gasto máximo mayor a 0",
|
||||||
|
"aiBudgetUpdated": "Presupuestos actualizados",
|
||||||
|
"aiBudgetErrorSave": "Error al actualizar presupuestos",
|
||||||
|
"aiProviderType": "Tipo de Proveedor",
|
||||||
|
"aiProviderTypeSearch": "Buscar proveedores...",
|
||||||
|
"aiProviderTypeNotFound": "No se encontró tipo de proveedor",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "Personalizado",
|
||||||
|
"aiProviderTypeOpenaiDescription": "API de OpenAI",
|
||||||
|
"aiProviderTypeAnthropicDescription": "API de Anthropic",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "API de Google Gemini",
|
||||||
|
"aiProviderTypeVertexAiDescription": "API de Vertex AI de Google",
|
||||||
|
"aiProviderTypeBedrockDescription": "API de Amazon Bedrock Runtime",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "API de Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "API de OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "API de Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustomDescription": "Lleve su propio endpoint o enrutamiento a través de objetivos del sitio",
|
||||||
|
"aiProviderUpstreamUrl": "URL de upstream",
|
||||||
|
"aiProviderUpstreamUrlDescription": "URL base para la API del proveedor",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Dejar en blanco para usar el URL de upstream predeterminado para este proveedor",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "URL de upstream efectivo",
|
||||||
|
"aiProviderApiKey": "Clave API",
|
||||||
|
"aiProviderApiKeyDescription": "Clave API usada para autenticar solicitudes a este proveedor",
|
||||||
|
"aiProviderCustomHeadersDescription": "Cabeceras enviadas en cada solicitud a este proveedor. Nueva línea separada: Nombre-Cabecera: valor",
|
||||||
|
"aiProviderApiKeyLastChars": "Clave API",
|
||||||
|
"aiProviderAuthType": "Tipo de autenticación",
|
||||||
|
"aiProviderAuthTypeSearch": "Buscar tipos de autenticación...",
|
||||||
|
"aiProviderAuthTypeNotFound": "No se encontró el tipo de autenticación",
|
||||||
|
"aiProviderAuthTypeBearer": "Portador",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Autorización: clave portador. Usado por OpenAI y la mayoría de los proveedores",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "Encabezado x-api-key. Usado por Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "Encabezado x-goog-api-key. Usado por Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Autorización: Clave Splunk. Usado por el recolector de eventos HTTP Splunk",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Gateway de IA de Cloudflare",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Clave Bearer. Usado por el Gateway de IA de Cloudflare",
|
||||||
|
"aiProviderAuthTypeNone": "Sin autenticación",
|
||||||
|
"aiProviderAuthTypePassthrough": "Paso a través",
|
||||||
|
"aiProviderAuthTypeDescription": "Cómo autentica solicitudes la API upstream",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Reenviar las cabeceras de clave API del solicitante al upstream",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "No enviar cabeceras de autenticación al upstream",
|
||||||
|
"aiProviderRoutingMode": "Modo de enrutamiento",
|
||||||
|
"aiProviderRoutingModeDescription": "Enviar tráfico a una URL de upstream o a objetivos HTTP en sus sitios",
|
||||||
|
"aiProviderRoutingModeUrl": "URL de upstream",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Llamar a una URL base de API pública o privada",
|
||||||
|
"aiProviderRoutingModeTarget": "Objetivos de sitio",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Ruta a través de objetivos en sus sitios",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Después de crear este proveedor, configure objetivos de sitio en la pestaña de Configuración de Red.",
|
||||||
|
"aiProviderTargetNoOne": "Este proveedor no tiene objetivos. Agregue un objetivo para enrutar solicitudes a través de sus sitios.",
|
||||||
|
"aiProviderSkipTlsVerification": "Omitir verificación de TLS",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Deshabilitar la verificación del certificado TLS para la conexión de upstream",
|
||||||
|
"aiProviderBudget": "Presupuesto",
|
||||||
|
"aiProviderBudgetDescription": "Presupuesto de gastos opcional o de token para este proveedor",
|
||||||
|
"aiProviderBudgetAmount": "Cantidad de presupuesto",
|
||||||
|
"aiProviderBudgetUnit": "Unidad de presupuesto",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Tokens",
|
||||||
|
"aiProviderEnabled": "Activado",
|
||||||
|
"aiProviderEnabledDescription": "Desactivar completamente este proveedor en todos los recursos",
|
||||||
|
"aiProviderErrorCreate": "Error al crear el proveedor de IA",
|
||||||
|
"aiProviderErrorUpdate": "Error al actualizar el proveedor de IA",
|
||||||
|
"aiProviderErrorDelete": "Error al eliminar el proveedor de IA",
|
||||||
|
"aiProviderErrorLoad": "Error al cargar el proveedor de IA",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Introduce una URL de upstream válida",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Se requiere URL de upstream para este proveedor",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Se requiere tipo de autenticación",
|
||||||
|
"aiProviderErrorApiKeyRequired": "Se requiere clave API",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "El enrutamiento de objetivos del sitio solo está disponible para proveedores personalizados",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Seleccione al menos una capacidad de API",
|
||||||
|
"aiProviderCapabilities": "Capacidades de la API",
|
||||||
|
"aiProviderCapabilitiesDescription": "Seleccione qué formatos de API puede manejar este proveedor. Los proveedores conocidos comienzan con valores predeterminados recomendados.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Seleccione qué formatos de API puede manejar este proveedor personalizado",
|
||||||
|
"aiProviderCapabilitiesSelect": "Seleccionar capacidades",
|
||||||
|
"aiProviderCapabilitiesEmpty": "No se encontraron capacidades",
|
||||||
|
"aiProviderCapabilitiesSearch": "Buscar capacidades...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Chat Completions",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Admite /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "Respuestas de OpenAI",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Admite /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Mensajes Antropicos",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Admite /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Generar contenido Gemini",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Admite la API directa de Gemini",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Invocar modelo de Bedrock",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Admite Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Generar contenido con Vertex",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Admite el formato Gemini de Vertex AI",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Predicción directa de Vertex",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Admite Vertex AI rawPredict para modelos Antropic",
|
||||||
|
"aiCapabilityBedrockConverse": "Convoque en Bedrock",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Admite la API de Amazon Bedrock Converse",
|
||||||
|
"aiProviderCreated": "Proveedor de IA creado",
|
||||||
|
"aiProviderUpdated": "Proveedor de IA actualizado",
|
||||||
|
"aiProviderDeleted": "Proveedor de IA eliminado",
|
||||||
|
"aiProviderDelete": "Eliminar proveedor",
|
||||||
|
"aiProviderDeleteConfirm": "Eliminar proveedor",
|
||||||
|
"aiProviderQuestionRemove": "¿Está seguro de que desea eliminar este proveedor de IA?",
|
||||||
|
"aiProviderMessageRemove": "Esto eliminará permanentemente el proveedor y sus modelos y objetivos. Esto no se puede deshacer.",
|
||||||
|
"aiProviderErrorNoUpdate": "El proveedor de IA no está disponible para actualizar",
|
||||||
|
"aiProviderModels": "Modelos",
|
||||||
|
"aiProviderModelsDescription": "Definir las listas de permitidos y bloqueados para este proveedor. Las solicitudes deben coincidir con una entrada permitida y no deben coincidir con una entrada bloqueada.",
|
||||||
|
"aiProviderCreateModelsDescription": "Elija qué modelos puede servir este proveedor. Una lista permitida vacía niega todo el tráfico. Puede agregar o cambiar modelos más tarde.",
|
||||||
|
"aiProviderModelsPlaceholder": "Buscar modelos o escribir una clave personalizada",
|
||||||
|
"aiProviderModelsAllow": "Lista de Permitidos",
|
||||||
|
"aiProviderModelsAllowDescription": "Modelos que pueden utilizarse a través de este proveedor. Vacío significa negar todos.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Ingrese la clave del modelo",
|
||||||
|
"aiProviderModelsAllowEmpty": "No se han agregado modelos aún.",
|
||||||
|
"aiProviderModelsBlock": "Lista de Bloqueados",
|
||||||
|
"aiProviderModelsBlockDescription": "Modelos para denegar incluso si coinciden con una entrada permitida.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Ingrese la clave del modelo",
|
||||||
|
"aiProviderModelsBlockEmpty": "No se han agregado modelos aún.",
|
||||||
|
"aiProviderModelsAdd": "Agregar Modelos",
|
||||||
|
"aiProviderModelsClearAll": "Borrar todo",
|
||||||
|
"aiProviderModelsAddCustom": "Agregar \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Presione Enter para agregar esta clave de modelo personalizada.",
|
||||||
|
"aiProviderModelsAddBulk": "Agregar {count} claves personalizadas.",
|
||||||
|
"aiProviderModelsAddBulkHint": "Presiona Enter para agregar {count} claves personalizadas.",
|
||||||
|
"aiProviderModelsAddOne": "Agregar {key} ahora",
|
||||||
|
"aiProviderModelsAddSelected": "Agregar seleccionado",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} seleccionados",
|
||||||
|
"aiProviderModelsSelectAll": "Seleccionar todo",
|
||||||
|
"aiProviderModelsClearSelected": "Limpiar",
|
||||||
|
"aiProviderModelsBulkHint": "Seleccione modelos conocidos o escriba una clave personalizada.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "No hay modelos de catálogo coincidentes.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Modelos conocidos",
|
||||||
|
"aiProviderModelsAllLabel": "Todos los modelos",
|
||||||
|
"aiProviderModelsAllPatternHint": "Comodín: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Permitir todos los modelos",
|
||||||
|
"aiProviderModelsAddAllBlock": "Bloquear todos los modelos",
|
||||||
|
"aiProviderModelsAddAllDescription": "Utiliza el comodín * para que cada clave de modelo coincida.",
|
||||||
|
"aiProviderModelsViewMore": "Ver más ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Ver menos",
|
||||||
|
"aiProviderModelsRemove": "Eliminar modelo",
|
||||||
|
"aiProviderModelsEditHint": "Haga clic para editar la configuración del modelo",
|
||||||
|
"aiProviderModelsSourceCatalog": "Modelo de catálogo conocido",
|
||||||
|
"aiProviderModelsSourceCustom": "Clave de modelo personalizada",
|
||||||
|
"aiProviderModelsSourcePattern": "Patrón de comodín",
|
||||||
|
"aiProviderModelsSourceAll": "Coincide con cada clave de modelo",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Presupuesto configurado",
|
||||||
|
"aiProviderModelsEditTitle": "Editar modelo",
|
||||||
|
"aiProviderModelsEditDescription": "Actualizar la clave del modelo o configurar su presupuesto.",
|
||||||
|
"aiProviderModelsBudgetTab": "Presupuesto",
|
||||||
|
"aiProviderModelsKeyLabel": "Clave del modelo",
|
||||||
|
"aiProviderModelsKeyRequired": "Ingrese una clave de modelo",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Esta clave de modelo ya está en una lista",
|
||||||
|
"aiProviderModelsOverlapError": "Estos patrones no pueden estar en ambas listas: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modelos actualizados",
|
||||||
|
"aiProviderModelsErrorUpdate": "No se pudo actualizar los modelos",
|
||||||
|
"aiResourceProviders": "Proveedores",
|
||||||
|
"aiResourceProvidersDescription": "Elija qué proveedores de IA puede usar este portal de IA",
|
||||||
|
"aiResourceProvidersHelp": "Adjunte proveedores y elija heredar (usar las listas de cada proveedor) o seleccionar (elija una lista de permitidos para este recurso). No se permiten patrones de permisos que entren en conflicto entre proveedores adjuntos.",
|
||||||
|
"aiResourceProvidersSelect": "Seleccionar proveedores",
|
||||||
|
"aiResourceProvidersEmpty": "No se encontraron proveedores de IA",
|
||||||
|
"aiResourceProvidersNoneAttached": "No se han adjuntado proveedores aún.",
|
||||||
|
"aiResourceProvidersAdd": "Agregar proveedor",
|
||||||
|
"aiResourceProvidersRemove": "Eliminar proveedor",
|
||||||
|
"aiResourceProviderToggleEnabled": "Habilitar o deshabilitar este proveedor en el recurso",
|
||||||
|
"aiResourceProviderDisabled": "Deshabilitado",
|
||||||
|
"aiResourceProvidersUpdated": "Proveedores actualizados",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Fallo al actualizar proveedores",
|
||||||
|
"aiResourceProviderEditDescription": "Elija cómo se exponen los modelos de este proveedor en este recurso.",
|
||||||
|
"viewProviderSettings": "Ver configuración del proveedor",
|
||||||
|
"aiResourceProviderMode": "Modo de acceso",
|
||||||
|
"aiResourceProviderModeInherit": "Heredar",
|
||||||
|
"aiResourceProviderModeSelect": "Seleccionar",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Seleccionar · {count} modelos",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Use las listas de permitidos y bloqueados de este proveedor según lo configurado en el proveedor.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Elija un subconjunto de modelos de la lista de permitidos de este proveedor para este recurso.",
|
||||||
|
"aiResourceProviderAllowModels": "Lista de permitidos",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Seleccionar modelos",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Buscar modelos...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "No se encontraron modelos",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Solo se pueden seleccionar modelos de la lista de permitidos de este proveedor.",
|
||||||
|
"aiResourceAliasRequired": "Alias es necesario para portales de IA",
|
||||||
|
"aiResourceDomainConfiguration": "Configuración del dominio",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Elija el dominio que los clientes usarán para llegar a este portal de IA.",
|
||||||
|
"aiUsageAnalyticsTitle": "Analítica de uso de IA",
|
||||||
|
"aiUsageAnalyticsDescription": "Analizar el costo del portal de IA, uso de token y actividad a través de proveedores, recursos, roles y usuarios",
|
||||||
|
"aiUsageTabOverview": "Resumen",
|
||||||
|
"aiUsageTabProviders": "Proveedores",
|
||||||
|
"aiUsageTabResources": "Recursos",
|
||||||
|
"aiUsageFilterProvider": "Proveedor",
|
||||||
|
"aiUsageFilterModel": "Modelo",
|
||||||
|
"aiUsageFilterResource": "Recurso",
|
||||||
|
"aiUsageFilterRole": "Rol",
|
||||||
|
"aiUsageFilterUser": "Usuario",
|
||||||
|
"aiUsageFilterAllProviders": "Todos los proveedores",
|
||||||
|
"aiUsageFilterAllModels": "Todos los modelos",
|
||||||
|
"aiUsageFilterAllResources": "Todos los recursos",
|
||||||
|
"aiUsageFilterAllRoles": "Todos los roles",
|
||||||
|
"aiUsageFilterAllUsers": "Todos los usuarios",
|
||||||
|
"aiUsageFilterSearch": "Buscar...",
|
||||||
|
"aiUsageFilterNotFound": "No se encontraron opciones",
|
||||||
|
"aiUsageResetFilters": "Restablecer filtros",
|
||||||
|
"aiUsageRefresh": "Actualizar",
|
||||||
|
"aiUsageTokenTypePrompt": "Indicio",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Lectura de caché",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Escritura de caché",
|
||||||
|
"aiUsageTokenTypeCompletion": "Completitud",
|
||||||
|
"aiUsageTokenTypeReasoning": "Razonamiento",
|
||||||
|
"aiUsageRequests": "Solicitudes",
|
||||||
|
"aiUsageCost": "Costo",
|
||||||
|
"aiUsageTokens": "Tokens",
|
||||||
|
"aiUsageOther": "Otro",
|
||||||
|
"aiUsageTotalRequests": "Solicitudes Totales",
|
||||||
|
"aiUsageTotalTokens": "Tokens Totales",
|
||||||
|
"aiUsageTotalCost": "Costo Total",
|
||||||
|
"aiUsageEstimated": "Estimado",
|
||||||
|
"aiUsageRequestVolume": "Volumen de Solicitudes",
|
||||||
|
"aiUsageTokenUsage": "Uso de Tokens",
|
||||||
|
"aiUsageModelCost": "Costo del Modelo",
|
||||||
|
"aiUsageModelTokens": "Tokens del Modelo",
|
||||||
|
"aiUsageTopModels": "Modelos Principales",
|
||||||
|
"aiUsageTopProviders": "Proveedores Principales",
|
||||||
|
"aiUsageProviderCost": "Costo del Proveedor",
|
||||||
|
"aiUsageProviderTokenUsage": "Uso de Tokens del Proveedor",
|
||||||
|
"aiUsageTopResources": "Recursos Principales",
|
||||||
|
"aiUsageResourceCost": "Costo del Recurso",
|
||||||
|
"aiUsageResourceTokenUsage": "Uso de Tokens del Recurso",
|
||||||
|
"aiUsageResourceTypePublic": "Recurso Público",
|
||||||
|
"aiUsageResourceTypeSite": "Recurso Privado",
|
||||||
|
"aiUsageNoResource": "Sin recurso",
|
||||||
|
"aiUsageRolesTab": "Roles",
|
||||||
|
"aiUsageUsersTab": "Usuarios",
|
||||||
|
"aiUsageTopRoles": "Roles Principales",
|
||||||
|
"aiUsageRoleCost": "Costo del Rol",
|
||||||
|
"aiUsageRoleTokenUsage": "Uso de Tokens del Rol",
|
||||||
|
"aiUsageTopUsers": "Usuarios principales",
|
||||||
|
"aiUsageUserCost": "Costo del Usuario",
|
||||||
|
"aiUsageUserTokenUsage": "Uso de Tokens del Usuario",
|
||||||
|
"aiUsageUnknownUser": "Usuario desconocido",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Claves API Virtuales",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Clave API Virtual",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Todas las Claves API Virtuales",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Claves API Virtuales Principales",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Costo de la Clave API Virtual",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Uso de Tokens de la Clave API Virtual",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Sin clave API virtual",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Clave sin nombre",
|
||||||
|
"aiUsageLoading": "Cargando...",
|
||||||
|
"aiUsageNoData": "Sin información",
|
||||||
|
"resourceBudgetSettings": "Presupuesto",
|
||||||
|
"resourceBudgetSettingsDescription": "Configure cómo este portal de IA restringe el uso en función de los límites de gasto o tokens",
|
||||||
"sidebarApiKeys": "Claves API",
|
"sidebarApiKeys": "Claves API",
|
||||||
"sidebarProvisioning": "Aprovisionamiento",
|
"sidebarProvisioning": "Aprovisionamiento",
|
||||||
"sidebarSettings": "Ajustes",
|
"sidebarSettings": "Ajustes",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Regla de alerta guardada",
|
"alertingRuleSaved": "Regla de alerta guardada",
|
||||||
"alertingRuleSavedCreatedDescription": "Tu nueva regla de alerta fue creada. Puedes seguir editándola en esta página.",
|
"alertingRuleSavedCreatedDescription": "Tu nueva regla de alerta fue creada. Puedes seguir editándola en esta página.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Tus cambios a esta regla de alerta fueron guardados.",
|
"alertingRuleSavedUpdatedDescription": "Tus cambios a esta regla de alerta fueron guardados.",
|
||||||
|
"alertingTestAlertSent": "Alerta de prueba enviada",
|
||||||
|
"alertingTestAlertSentDescription": "Se envió una alerta de prueba a las acciones configuradas en esta regla.",
|
||||||
"alertingEditRule": "Editar regla de alerta",
|
"alertingEditRule": "Editar regla de alerta",
|
||||||
"alertingCreateRule": "Crear regla de alerta",
|
"alertingCreateRule": "Crear regla de alerta",
|
||||||
"alertingRuleCredenzaDescription": "Elija qué observar, cuándo disparar y cómo notificar",
|
"alertingRuleCredenzaDescription": "Elija qué observar, cuándo disparar y cómo notificar",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Cada regla vincula lo que se debe observar (un sitio, chequeo de salud o recurso), cuándo disparar (por ejemplo, fuera de línea o no saludable), y cómo notificar a su equipo vía email, webhooks o integraciones. Use esta lista para crear, habilitar y administrar esas reglas.",
|
"alertingRulesBannerDescription": "Cada regla vincula lo que se debe observar (un sitio, chequeo de salud o recurso), cuándo disparar (por ejemplo, fuera de línea o no saludable), y cómo notificar a su equipo vía email, webhooks o integraciones. Use esta lista para crear, habilitar y administrar esas reglas.",
|
||||||
"alertingHealthChecksBannerTitle": "Monitorear Salud y Recursos",
|
"alertingHealthChecksBannerTitle": "Monitorear Salud y Recursos",
|
||||||
"alertingHealthChecksBannerDescription": "Los chequeos de salud son monitores HTTP o TCP que define una vez. Luego puede usarlos como fuentes en reglas de alerta para que se le notifique cuando un objetivo se vuelva saludable o no saludable. Los chequeos de salud en recursos también aparecen aquí.",
|
"alertingHealthChecksBannerDescription": "Los chequeos de salud son monitores HTTP o TCP que define una vez. Luego puede usarlos como fuentes en reglas de alerta para que se le notifique cuando un objetivo se vuelva saludable o no saludable. Los chequeos de salud en recursos también aparecen aquí.",
|
||||||
|
"alertingTestRule": "Regla de Alerta de Prueba",
|
||||||
|
"alertingAddActionHeading": "Agregar nueva acción",
|
||||||
|
"alertingSelectActionType": "Seleccione una acción",
|
||||||
|
"alertingNoActionsTitle": "No se han configurado acciones",
|
||||||
|
"alertingNoActionsSaveDescription": "Agregue al menos una acción para que esta regla pueda notificar a alguien cuando se ejecute.",
|
||||||
|
"alertingNoActionsTestDescription": "Agregue al menos una acción antes de poder probar esta regla.",
|
||||||
"standaloneHcTableTitle": "Chequeos de salud",
|
"standaloneHcTableTitle": "Chequeos de salud",
|
||||||
"standaloneHcSearchPlaceholder": "Buscar chequeos de salud…",
|
"standaloneHcSearchPlaceholder": "Buscar chequeos de salud…",
|
||||||
"standaloneHcAddButton": "Crear chequeo de salud",
|
"standaloneHcAddButton": "Crear chequeo de salud",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Subdominio: {subdomain}",
|
"domainPickerSubdomain": "Subdominio: {subdomain}",
|
||||||
"domainPickerNamespace": "Espacio de nombres: {namespace}",
|
"domainPickerNamespace": "Espacio de nombres: {namespace}",
|
||||||
"domainPickerShowMore": "Mostrar más",
|
"domainPickerShowMore": "Mostrar más",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "No hay dominios disponibles",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Aún no tiene ningún dominio configurado. Cree un dominio para continuar.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Ir a Dominios",
|
||||||
"regionSelectorTitle": "Seleccionar Región",
|
"regionSelectorTitle": "Seleccionar Región",
|
||||||
"domainPickerRemoteExitNodeWarning": "Los dominios suministrados no son compatibles cuando los sitios se conectan a nodos de salida remotos. Para que los recursos estén disponibles en nodos remotos, utilice un dominio personalizado en su lugar.",
|
"domainPickerRemoteExitNodeWarning": "Los dominios suministrados no son compatibles cuando los sitios se conectan a nodos de salida remotos. Para que los recursos estén disponibles en nodos remotos, utilice un dominio personalizado en su lugar.",
|
||||||
"regionSelectorInfo": "Seleccionar una región nos ayuda a brindar un mejor rendimiento para tu ubicación. No tienes que estar en la misma región que tu servidor.",
|
"regionSelectorInfo": "Seleccionar una región nos ayuda a brindar un mejor rendimiento para tu ubicación. No tienes que estar en la misma región que tu servidor.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Subred",
|
"subnetPlaceholder": "Subred",
|
||||||
"addressDescription": "La dirección interna del cliente. Debe estar dentro de la subred de la organización.",
|
"addressDescription": "La dirección interna del cliente. Debe estar dentro de la subred de la organización.",
|
||||||
"selectSites": "Seleccionar sitios",
|
"selectSites": "Seleccionar sitios",
|
||||||
|
"selectResources": "Seleccionar recursos",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# recurso} other {# recursos}}",
|
||||||
"selectLabels": "Seleccionar etiquetas",
|
"selectLabels": "Seleccionar etiquetas",
|
||||||
"sitesDescription": "El cliente tendrá conectividad con los sitios seleccionados",
|
"sitesDescription": "El cliente tendrá conectividad con los sitios seleccionados",
|
||||||
"clientInstallOlm": "Instalar Olm",
|
"clientInstallOlm": "Instalar Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "El tiempo está en segundos",
|
"timeIsInSeconds": "El tiempo está en segundos",
|
||||||
"requireDeviceApproval": "Requiere aprobaciones del dispositivo",
|
"requireDeviceApproval": "Requiere aprobaciones del dispositivo",
|
||||||
"requireDeviceApprovalDescription": "Los usuarios con este rol necesitan nuevos dispositivos aprobados por un administrador antes de poder conectarse y acceder a los recursos.",
|
"requireDeviceApprovalDescription": "Los usuarios con este rol necesitan nuevos dispositivos aprobados por un administrador antes de poder conectarse y acceder a los recursos.",
|
||||||
"sshSettings": "Configuración SSH",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "Portal de IA",
|
||||||
"sshAccess": "Acceso SSH",
|
"sshAccess": "Acceso SSH",
|
||||||
"rdpSettings": "Configuración RDP",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "Configuración VNC",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "Servidor SSH",
|
"sshServer": "Servidor SSH",
|
||||||
"rdpServer": "Servidor RDP",
|
"rdpServer": "Servidor RDP",
|
||||||
"vncServer": "Servidor VNC",
|
"vncServer": "Servidor VNC",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Público",
|
"resourcesTableProxyResources": "Público",
|
||||||
"resourcesTableClientResources": "Privado",
|
"resourcesTableClientResources": "Privado",
|
||||||
"resourcesTableNoProxyResourcesFound": "No se encontraron recursos de proxy.",
|
"resourcesTableNoProxyResourcesFound": "No se encontraron recursos de proxy.",
|
||||||
"resourcesTableNoInternalResourcesFound": "No se encontraron recursos internos.",
|
"resourcesTableNoInternalResourcesFound": "No se encontraron recursos privados.",
|
||||||
"resourcesTableDestination": "Destino",
|
"resourcesTableDestination": "Destino",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Dirección del alias",
|
"resourcesTableAliasAddress": "Dirección del alias",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Cancelar",
|
"editInternalResourceDialogCancel": "Cancelar",
|
||||||
"editInternalResourceDialogSaveResource": "Guardar recurso",
|
"editInternalResourceDialogSaveResource": "Guardar recurso",
|
||||||
"editInternalResourceDialogSuccess": "Éxito",
|
"editInternalResourceDialogSuccess": "Éxito",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso interno actualizado con éxito",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso privado actualizado con éxito",
|
||||||
"editInternalResourceDialogError": "Error",
|
"editInternalResourceDialogError": "Error",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Error al actualizar el recurso interno",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Error al actualizar el recurso privado",
|
||||||
"editInternalResourceDialogNameRequired": "El nombre es requerido",
|
"editInternalResourceDialogNameRequired": "El nombre es requerido",
|
||||||
"editInternalResourceDialogNameMaxLength": "El nombre no debe tener más de 255 caracteres",
|
"editInternalResourceDialogNameMaxLength": "El nombre no debe tener más de 255 caracteres",
|
||||||
"editInternalResourceDialogProxyPortMin": "El puerto del proxy debe ser al menos 1",
|
"editInternalResourceDialogProxyPortMin": "El puerto del proxy debe ser al menos 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "Portal de IA",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Esquema",
|
"editInternalResourceDialogScheme": "Esquema",
|
||||||
"editInternalResourceDialogEnableSsl": "Activar TLS",
|
"editInternalResourceDialogEnableSsl": "Activar TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Un alias DNS interno opcional para este recurso.",
|
"editInternalResourceDialogAliasDescription": "Un alias DNS interno opcional para este recurso.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "No hay sitios disponibles",
|
"createInternalResourceDialogNoSitesAvailable": "No hay sitios disponibles",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Necesita tener al menos un sitio de Newt con una subred configurada para crear recursos internos.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Necesita tener al menos un sitio de Newt con una subred configurada para crear recursos privados.",
|
||||||
"createInternalResourceDialogClose": "Cerrar",
|
"createInternalResourceDialogClose": "Cerrar",
|
||||||
"createInternalResourceDialogCreateClientResource": "Crear recurso privado",
|
"createInternalResourceDialogCreateClientResource": "Crear recurso privado",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Crear un nuevo recurso que sólo será accesible a los clientes conectados a la organización",
|
"createInternalResourceDialogCreateClientResourceDescription": "Crear un nuevo recurso que sólo será accesible a los clientes conectados a la organización",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Permitir ping ICMP",
|
"privateResourceAllowIcmpPing": "Permitir ping ICMP",
|
||||||
"privateResourceNetworkAccess": "Acceso de red",
|
"privateResourceNetworkAccess": "Acceso de red",
|
||||||
"privateResourceNetworkAccessDescription": "Controlar el acceso a puertos TCP/UDP y si se permite ping ICMP para este recurso.",
|
"privateResourceNetworkAccessDescription": "Controlar el acceso a puertos TCP/UDP y si se permite ping ICMP para este recurso.",
|
||||||
"hostSettings": "Configuraciones del anfitrión",
|
"hostSettings": "Host",
|
||||||
"cidrSettings": "Configuraciones CIDR",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Propiedades del recurso",
|
"createInternalResourceDialogResourceProperties": "Propiedades del recurso",
|
||||||
"createInternalResourceDialogName": "Nombre",
|
"createInternalResourceDialogName": "Nombre",
|
||||||
"createInternalResourceDialogSite": "Sitio",
|
"createInternalResourceDialogSite": "Sitio",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Cancelar",
|
"createInternalResourceDialogCancel": "Cancelar",
|
||||||
"createInternalResourceDialogCreateResource": "Crear recurso",
|
"createInternalResourceDialogCreateResource": "Crear recurso",
|
||||||
"createInternalResourceDialogSuccess": "Éxito",
|
"createInternalResourceDialogSuccess": "Éxito",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso interno creado con éxito",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso privado creado con éxito",
|
||||||
"createInternalResourceDialogError": "Error",
|
"createInternalResourceDialogError": "Error",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Error al crear recurso interno",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Error al crear recurso privado",
|
||||||
"createInternalResourceDialogNameRequired": "El nombre es requerido",
|
"createInternalResourceDialogNameRequired": "El nombre es requerido",
|
||||||
"createInternalResourceDialogNameMaxLength": "El nombre debe ser menor de 255 caracteres",
|
"createInternalResourceDialogNameMaxLength": "El nombre debe ser menor de 255 caracteres",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Por favor seleccione un sitio",
|
"createInternalResourceDialogPleaseSelectSite": "Por favor seleccione un sitio",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "Portal de IA",
|
||||||
"scheme": "Esquema",
|
"scheme": "Esquema",
|
||||||
"createInternalResourceDialogScheme": "Esquema",
|
"createInternalResourceDialogScheme": "Esquema",
|
||||||
"createInternalResourceDialogEnableSsl": "Activar TLS",
|
"createInternalResourceDialogEnableSsl": "Activar TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Contraseña válida",
|
"validPassword": "Contraseña válida",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Clave API Virtual Válida",
|
||||||
"view": "Ver",
|
"view": "Ver",
|
||||||
"configManaged": "Configuración Gestionada",
|
"configManaged": "Configuración Gestionada",
|
||||||
"connectedClient": "Cliente conectado",
|
"connectedClient": "Cliente conectado",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Retención de Log",
|
"logRetention": "Retención de Log",
|
||||||
"logRetentionDescription": "Administrar cuánto tiempo se conservan los diferentes tipos de registros para esta organización o desactivarlos",
|
"logRetentionDescription": "Administrar cuánto tiempo se conservan los diferentes tipos de registros para esta organización o desactivarlos",
|
||||||
"requestLogsDescription": "Ver registros de solicitudes detallados para los recursos de esta organización",
|
"requestLogsDescription": "Ver registros de solicitudes detallados para los recursos de esta organización",
|
||||||
|
"aiSessionLogs": "Registros de Sesiones del Portal de IA",
|
||||||
|
"aiSessionLogsDescription": "Ver transcripciones de solicitud y respuesta para solicitudes del portal de IA en esta organización",
|
||||||
|
"sidebarLogsAi": "Registros de Sesiones",
|
||||||
|
"commandLogsAi": "Registros de Sesiones",
|
||||||
|
"sidebarLogsAiUsage": "Analítica de Uso",
|
||||||
|
"commandLogsAiUsage": "Analítica de Uso",
|
||||||
|
"provider": "Proveedor",
|
||||||
|
"capability": "Capacidad",
|
||||||
|
"model": "Modelo",
|
||||||
|
"virtualApiKey": "Clave API Virtual",
|
||||||
|
"noVirtualApiKey": "Sin clave API virtual",
|
||||||
|
"stream": "Flujo",
|
||||||
|
"streaming": "Flujo de eventos",
|
||||||
|
"nonStreaming": "No-flujo",
|
||||||
|
"statusCode": "Código de estado",
|
||||||
|
"aiSessionId": "ID de Sesión",
|
||||||
|
"aiSessionRequest": "Solicitud",
|
||||||
|
"aiSessionResponse": "Respuesta",
|
||||||
|
"aiSessionNoData": "Sin datos capturados",
|
||||||
|
"aiSessionCouldNotParse": "(sin procesar, no se pudo analizar la transcripción)",
|
||||||
|
"aiSessionLogTruncated": "Esta sesión fue truncada antes del almacenamiento y puede estar incompleta.",
|
||||||
|
"aiSessionViewRaw": "Ver JSON sin procesar",
|
||||||
|
"aiSessionViewChat": "Ver Chat",
|
||||||
|
"cost": "Costo",
|
||||||
|
"estimated": "Estimado",
|
||||||
|
"tokenUsage": "Uso de Tokens",
|
||||||
|
"promptTokens": "Tokens de Indicio",
|
||||||
|
"cacheReadTokens": "Tokens de Lectura de Caché",
|
||||||
|
"cacheWriteTokens": "Tokens de Escritura de Caché",
|
||||||
|
"completionTokens": "Tokens de Completitud",
|
||||||
|
"reasoningTokens": "Tokens de Razonamiento",
|
||||||
|
"totalTokens": "Total de Tokens",
|
||||||
"requestAnalyticsDescription": "Ver análisis de solicitudes detalladas de recursos en esta organización",
|
"requestAnalyticsDescription": "Ver análisis de solicitudes detalladas de recursos en esta organización",
|
||||||
"logRetentionRequestLabel": "Retención de Registro de Solicitud HTTP",
|
"logRetentionRequestLabel": "Retención de Registro de Solicitud HTTP",
|
||||||
"logRetentionRequestDescription": "Cuánto tiempo conservar los registros de solicitudes",
|
"logRetentionRequestDescription": "Cuánto tiempo conservar los registros de solicitudes",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Cuánto tiempo retener los registros de acción",
|
"logRetentionActionDescription": "Cuánto tiempo retener los registros de acción",
|
||||||
"logRetentionConnectionLabel": "Retención de Registro de Conexión",
|
"logRetentionConnectionLabel": "Retención de Registro de Conexión",
|
||||||
"logRetentionConnectionDescription": "Cuánto tiempo conservar los registros de conexión",
|
"logRetentionConnectionDescription": "Cuánto tiempo conservar los registros de conexión",
|
||||||
|
"logRetentionAISessionsLabel": "Retención de Registro de Sesiones del Portal de IA",
|
||||||
|
"logRetentionAISessionsDescription": "Cuánto tiempo retener los registros de sesión de solicitud/respuesta del portal de IA",
|
||||||
"logRetentionDisabled": "Deshabilitado",
|
"logRetentionDisabled": "Deshabilitado",
|
||||||
"logRetention3Days": "3 días",
|
"logRetention3Days": "3 días",
|
||||||
"logRetention7Days": "7 días",
|
"logRetention7Days": "7 días",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Dirección de origen",
|
"sourceAddress": "Dirección de origen",
|
||||||
"destinationAddress": "Dirección de destino",
|
"destinationAddress": "Dirección de destino",
|
||||||
"duration": "Duración",
|
"duration": "Duración",
|
||||||
"licenseRequiredToUse": "Se requiere una licencia <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> o <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> para usar esta función. <bookADemoLink>Reserve una demostración o prueba POC</bookADemoLink>.",
|
"licenseRequiredToUse": "Se requiere una licencia para la <enterpriseEditionLink>Edición Empresarial</enterpriseEditionLink>. <bookADemoLink>Reserve una demostración o prueba</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "La <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> es necesaria para utilizar esta función. Esta función también está disponible en <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Reserva una demostración o prueba POC</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "Se requiere una licencia para la <enterpriseEditionLink>Edición Empresarial</enterpriseEditionLink>. <bookADemoLink>Reserve una demostración o prueba</bookADemoLink>",
|
||||||
"certResolver": "Resolver certificado",
|
"certResolver": "Resolver certificado",
|
||||||
"certResolverDescription": "Seleccione la resolución de certificados a utilizar para este recurso.",
|
"certResolverDescription": "Seleccione la resolución de certificados a utilizar para este recurso.",
|
||||||
"selectCertResolver": "Seleccionar Resolver Certificado",
|
"selectCertResolver": "Seleccionar Resolver Certificado",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Seleccionar múltiples sitios habilita el enrutamiento resistente y la conmutación por error para alta disponibilidad.",
|
"internalResourceFormMultiSiteRoutingHelp": "Seleccionar múltiples sitios habilita el enrutamiento resistente y la conmutación por error para alta disponibilidad.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Más información",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Más información",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Restringir el acceso a puertos TCP/UDP específicos o permitir/bloquear todos los puertos.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Restringir el acceso a puertos TCP/UDP específicos o permitir/bloquear todos los puertos.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "Configuración HTTP",
|
"createInternalResourceDialogHttpConfiguration": "Configuración del dominio",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Elija el dominio que los clientes usarán para alcanzar este recurso a través de HTTP o HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Elija el dominio que los clientes usarán para alcanzar este recurso a través de HTTP o HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "Configuración HTTP",
|
"editInternalResourceDialogHttpConfiguration": "Configuración del dominio",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Elija el dominio que los clientes usarán para alcanzar este recurso a través de HTTP o HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Elija el dominio que los clientes usarán para alcanzar este recurso a través de HTTP o HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Sin Etiqueta",
|
"resourceLauncherUnlabeled": "Sin Etiqueta",
|
||||||
|
"resourceLauncherAiGateway": "Portal de IA",
|
||||||
"resourceLauncherNoSite": "Sin Sitio",
|
"resourceLauncherNoSite": "Sin Sitio",
|
||||||
|
"resourceLauncherAvailableModels": "Modelos Disponibles",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modelos que puede usar con este portal de IA.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "No hay modelos disponibles para este recurso.",
|
||||||
|
"resourceLauncherAvailableModelsError": "No se pudieron cargar los modelos disponibles.",
|
||||||
|
"resourceLauncherApiKeys": "Claves API",
|
||||||
|
"resourceLauncherApiKeysDescription": "Use su clave de identidad o una clave atribuida para autenticarse con este recurso.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Clave de Identidad",
|
||||||
|
"resourceLauncherApiKeysManual": "Claves Atribuidas",
|
||||||
|
"resourceLauncherApiKeysEmpty": "No hay claves API disponibles para este recurso.",
|
||||||
|
"resourceLauncherApiKeysError": "No se pudieron cargar las claves API.",
|
||||||
"resourceLauncherNoResourcesInGroup": "No hay recursos en este grupo",
|
"resourceLauncherNoResourcesInGroup": "No hay recursos en este grupo",
|
||||||
"resourceLauncherEmptyStateTitle": "No hay Recursos Disponibles",
|
"resourceLauncherEmptyStateTitle": "No hay Recursos Disponibles",
|
||||||
"resourceLauncherEmptyStateDescription": "Todavía no tienes acceso a ningún recurso. Contacta a tu administrador para solicitar acceso.",
|
"resourceLauncherEmptyStateDescription": "Todavía no tienes acceso a ningún recurso. Contacta a tu administrador para solicitar acceso.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "No se pudo eliminar la vista del lanzador. Por favor, intenta de nuevo.",
|
"resourceLauncherViewDeleteFailedDescription": "No se pudo eliminar la vista del lanzador. Por favor, intenta de nuevo.",
|
||||||
"memberPortalPrevious": "Anterior",
|
"memberPortalPrevious": "Anterior",
|
||||||
"memberPortalNext": "Siguiente",
|
"memberPortalNext": "Siguiente",
|
||||||
"httpSettings": "Configuración HTTP",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "Configuración TCP",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "Configuración UDP",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Estableciendo una conexión segura…",
|
"sshConnectingDescription": "Estableciendo una conexión segura…",
|
||||||
"sshConnecting": "Conectando…",
|
"sshConnecting": "Conectando…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Error de subida",
|
"rdpUploadFailed": "Error de subida",
|
||||||
"rdpUnicodeKeyboardMode": "Modo teclado Unicode",
|
"rdpUnicodeKeyboardMode": "Modo teclado Unicode",
|
||||||
"sessionToolbarShow": "Mostrar barra de herramientas",
|
"sessionToolbarShow": "Mostrar barra de herramientas",
|
||||||
"sessionToolbarHide": "Ocultar barra de herramientas"
|
"sessionToolbarHide": "Ocultar barra de herramientas",
|
||||||
|
"actionUpdateSiteApprovals": "Actualizar aprobaciones del sitio"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Veuillez vous assurer que vous êtes connecté avec le bon compte.",
|
"inviteLoginUser": "Veuillez vous assurer que vous êtes connecté avec le bon compte.",
|
||||||
"inviteErrorNoUser": "Nous sommes désolés, mais il semble que l'invitation à laquelle vous essayez d'accéder ne concerne pas un utilisateur existant.",
|
"inviteErrorNoUser": "Nous sommes désolés, mais il semble que l'invitation à laquelle vous essayez d'accéder ne concerne pas un utilisateur existant.",
|
||||||
"inviteCreateUser": "Veuillez d'abord créer un compte.",
|
"inviteCreateUser": "Veuillez d'abord créer un compte.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Les invitations ne peuvent être acceptées que par des comptes internes. Déconnectez-vous et connectez-vous avec votre mot de passe pour cet email.",
|
||||||
|
"inviteLoginInternalOnly": "Les invitations nécessitent un compte interne avec un mot de passe. Créez un compte ou connectez-vous avec votre mot de passe.",
|
||||||
"goHome": "Retour à l'accueil",
|
"goHome": "Retour à l'accueil",
|
||||||
"inviteLogInOtherUser": "Se connecter en tant qu'utilisateur différent",
|
"inviteLogInOtherUser": "Se connecter en tant qu'utilisateur différent",
|
||||||
"createAnAccount": "Créer un compte",
|
"createAnAccount": "Créer un compte",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Confirmer la suppression du lien partageable",
|
"shareDeleteConfirm": "Confirmer la suppression du lien partageable",
|
||||||
"shareQuestionRemove": "Êtes-vous sûr de vouloir supprimer ce lien de partage ?",
|
"shareQuestionRemove": "Êtes-vous sûr de vouloir supprimer ce lien de partage ?",
|
||||||
"shareMessageRemove": "Une fois supprimé, le lien ne fonctionnera plus et toute personne l'utilisant perdra l'accès à la ressource.",
|
"shareMessageRemove": "Une fois supprimé, le lien ne fonctionnera plus et toute personne l'utilisant perdra l'accès à la ressource.",
|
||||||
"shareTokenDescription": "Le jeton d'accès peut être passé de deux façons : en tant que paramètre de requête ou dans les en-têtes de la requête. Elles doivent être transmises par le client à chaque demande d'accès authentifié.",
|
"shareTokenDescription": "Le jeton d'accès peut être transmis comme paramètre de requête ou dans les en-têtes de requête. Par défaut, il doit être envoyé à chaque requête. Si la persistance de session est activée, la première requête l'échange contre un cookie de session.",
|
||||||
"accessToken": "Jeton d'accès",
|
"accessToken": "Jeton d'accès",
|
||||||
"usageExamples": "Exemples d'utilisation",
|
"usageExamples": "Exemples d'utilisation",
|
||||||
"tokenId": "ID du jeton",
|
"tokenId": "ID du jeton",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Titre (facultatif)",
|
"shareTitleOptional": "Titre (facultatif)",
|
||||||
"sharePathOptional": "Chemin (optionnel)",
|
"sharePathOptional": "Chemin (optionnel)",
|
||||||
"sharePathDescription": "Le lien redirigera les utilisateurs vers ce chemin après l'authentification.",
|
"sharePathDescription": "Le lien redirigera les utilisateurs vers ce chemin après l'authentification.",
|
||||||
|
"shareAssociateUserOptional": "Associer un utilisateur (facultatif)",
|
||||||
|
"shareAssociateUserDescription": "Lorsqu'il est défini, les requêtes utilisant ce lien sont attribuées à l'utilisateur dans les journaux d'accès et les en-têtes d'identité. Le lien est supprimé si l'utilisateur quitte l'organisation.",
|
||||||
|
"userSelect": "Sélectionner un utilisateur",
|
||||||
|
"usersNotFound": "Aucun utilisateur trouvé",
|
||||||
"expireIn": "Expire dans",
|
"expireIn": "Expire dans",
|
||||||
"neverExpire": "N'expire jamais",
|
"neverExpire": "N'expire jamais",
|
||||||
|
"sharePersistSession": "Persister la session après la première utilisation",
|
||||||
|
"sharePersistSessionDescription": "Lorsqu'elle est activée, la première requête avec ce jeton via un paramètre de requête ou un en-tête définit un cookie de session afin que les requêtes ultérieures n'aient pas besoin du jeton. Désactivez-le pour les clients API qui doivent envoyer le jeton à chaque requête.",
|
||||||
"shareExpireDescription": "Le délai d'expiration correspond à la période pendant laquelle le lien sera utilisable et permettra d'accéder à la ressource. Passé ce délai, le lien ne fonctionnera plus et les utilisateurs qui l'ont utilisé perdront l'accès à la ressource.",
|
"shareExpireDescription": "Le délai d'expiration correspond à la période pendant laquelle le lien sera utilisable et permettra d'accéder à la ressource. Passé ce délai, le lien ne fonctionnera plus et les utilisateurs qui l'ont utilisé perdront l'accès à la ressource.",
|
||||||
"shareSeeOnce": "Vous ne pourrez voir ce lien qu'une seule fois. N'oubliez pas de le copier.",
|
"shareSeeOnce": "Vous ne pourrez voir ce lien qu'une seule fois. N'oubliez pas de le copier.",
|
||||||
"shareAccessHint": "N'importe qui avec ce lien peut accéder à la ressource. Partagez-le avec précaution.",
|
"shareAccessHint": "N'importe qui avec ce lien peut accéder à la ressource. Partagez-le avec précaution.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Aucun pays trouvé.",
|
"noCountryFound": "Aucun pays trouvé.",
|
||||||
"siteSelectionDescription": "Ce site fournira la connectivité à la cible.",
|
"siteSelectionDescription": "Ce site fournira la connectivité à la cible.",
|
||||||
"resourceType": "Type de ressource",
|
"resourceType": "Type de ressource",
|
||||||
"resourceTypeDescription": "Cela contrôle le protocole de la ressource et comment il sera rendu dans le navigateur. Cela ne peut pas être changé plus tard.",
|
"resourceTypeDescription": "Cela contrôle le protocole de ressource et ne peut pas être modifié ultérieurement.",
|
||||||
|
"resourceTypeSearch": "Rechercher des types de ressource...",
|
||||||
|
"resourceTypeNotFound": "Aucun type de ressource trouvé",
|
||||||
|
"resourceTypeHttpDescription": "Proxy du trafic web via HTTPS en utilisant un nom de domaine",
|
||||||
|
"resourceTypeInferenceDescription": "Acheminer les requêtes AI via les fournisseurs attachés",
|
||||||
|
"resourceTypeSshDescription": "Accéder à un serveur SSH depuis le navigateur",
|
||||||
|
"resourceTypeRdpDescription": "Accéder à un bureau distant depuis le navigateur",
|
||||||
|
"resourceTypeVncDescription": "Accéder à un bureau VNC depuis le navigateur",
|
||||||
|
"resourceTypeTcpDescription": "Proxy du trafic TCP brut utilisant un numéro de port",
|
||||||
|
"resourceTypeUdpDescription": "Proxy du trafic UDP brut utilisant un numéro de port",
|
||||||
|
"privateResourceTypeDescription": "Cela contrôle comment les clients atteignent la ressource. Cela ne peut pas être modifié plus tard.",
|
||||||
|
"privateResourceTypeHostDescription": "Exposer un hôte unique sur le réseau du site aux clients connectés",
|
||||||
|
"privateResourceTypeCidrDescription": "Exposer une plage CIDR sur le réseau du site aux clients connectés",
|
||||||
|
"privateResourceTypeHttpDescription": "Accéder à un service HTTP ou HTTPS via un domaine",
|
||||||
|
"privateResourceTypeSshDescription": "Accéder à un serveur SSH depuis les clients connectés",
|
||||||
"resourceDomainDescription": "La ressource sera servie à ce nom de domaine pleinement qualifié.",
|
"resourceDomainDescription": "La ressource sera servie à ce nom de domaine pleinement qualifié.",
|
||||||
"resourceHTTPSSettings": "Paramètres HTTPS",
|
"resourceHTTPSSettings": "Paramètres HTTPS",
|
||||||
"resourceHTTPSSettingsDescription": "Configurer comment la ressource sera accédée via HTTPS",
|
"resourceHTTPSSettingsDescription": "Configurer comment la ressource sera accédée via HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Mise en place",
|
"provisioningManage": "Mise en place",
|
||||||
"provisioningDescription": "Gérer les clés de provisioning et examiner les sites en attente d'approbation.",
|
"provisioningDescription": "Gérer les clés de provisioning et examiner les sites en attente d'approbation.",
|
||||||
"pendingSites": "Sites en attente",
|
"pendingSites": "Sites en attente",
|
||||||
"siteApproveSuccess": "Site approuvé avec succès",
|
"siteApproveSuccess": "Site et ressources associées approuvés avec succès",
|
||||||
"siteApproveError": "Erreur lors de l'approbation du site",
|
"siteApproveError": "Erreur lors de l'approbation du site",
|
||||||
|
"siteReject": "Rejeter le site",
|
||||||
|
"siteQuestionReject": "Êtes-vous sûr de vouloir rejeter ce site ?",
|
||||||
|
"siteMessageReject": "Cela supprimera définitivement le site et toutes les ressources associées qui sont encore en attente.",
|
||||||
|
"siteConfirmReject": "Confirmer le rejet du site",
|
||||||
|
"siteRejectSuccess": "Site rejeté avec succès",
|
||||||
|
"siteRejectError": "Erreur lors du rejet du site",
|
||||||
"provisioningKeys": "Clés de provisionnement",
|
"provisioningKeys": "Clés de provisionnement",
|
||||||
"searchProvisioningKeys": "Recherche des clés de provision...",
|
"searchProvisioningKeys": "Recherche des clés de provision...",
|
||||||
"provisioningKeysAdd": "Générer une clé de provisioning",
|
"provisioningKeysAdd": "Générer une clé de provisioning",
|
||||||
@@ -466,12 +494,12 @@
|
|||||||
"provisioningKeysSave": "Enregistrer la clé de provisioning",
|
"provisioningKeysSave": "Enregistrer la clé de provisioning",
|
||||||
"provisioningKeysSaveDescription": "Vous ne pourrez voir cela qu'une seule fois. Copiez-le dans un endroit sécurisé.",
|
"provisioningKeysSaveDescription": "Vous ne pourrez voir cela qu'une seule fois. Copiez-le dans un endroit sécurisé.",
|
||||||
"provisioningKeysErrorCreate": "Erreur lors de la création de la clé de provisioning",
|
"provisioningKeysErrorCreate": "Erreur lors de la création de la clé de provisioning",
|
||||||
"provisioningKeysList": "Nouvelle clé de provisioning",
|
"provisioningKeysList": "Nouvelle clé d'approvisionnement",
|
||||||
"provisioningKeysMaxBatchSize": "Taille maximale du lot",
|
"provisioningKeysMaxBatchSize": "Taille maximale du lot",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Taille de lot illimitée (sans limite)",
|
"provisioningKeysUnlimitedBatchSize": "Taille de lot illimitée (sans limite)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Illimité",
|
"provisioningKeysMaxBatchUnlimited": "Illimité",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Entrez une taille de lot maximale valide (1–1 000 000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Entrez une taille de lot maximale valide (1–1 000 000).",
|
||||||
"provisioningKeysValidUntil": "Valable jusqu'au",
|
"provisioningKeysValidUntil": "Valable jusqu'à",
|
||||||
"provisioningKeysValidUntilHint": "Laisser vide pour ne pas expirer.",
|
"provisioningKeysValidUntilHint": "Laisser vide pour ne pas expirer.",
|
||||||
"provisioningKeysValidUntilInvalid": "Entrez une date et une heure valides.",
|
"provisioningKeysValidUntilInvalid": "Entrez une date et une heure valides.",
|
||||||
"provisioningKeysNumUsed": "Nombre de fois utilisées",
|
"provisioningKeysNumUsed": "Nombre de fois utilisées",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Enregistrer les paramètres",
|
"authMethodsSave": "Enregistrer les paramètres",
|
||||||
"policyAuthStackTitle": "Authentification",
|
"policyAuthStackTitle": "Authentification",
|
||||||
"policyAuthStackDescription": "Contrôlez quelles méthodes d'authentification sont nécessaires pour accéder à cette ressource",
|
"policyAuthStackDescription": "Contrôlez quelles méthodes d'authentification sont nécessaires pour accéder à cette ressource",
|
||||||
|
"policyAuthInferenceStackDescription": "Choisissez quels utilisateurs et rôles peuvent s'authentifier à cette passerelle AI",
|
||||||
"policyAuthOrLogicTitle": "Plusieurs méthodes d'authentification actives",
|
"policyAuthOrLogicTitle": "Plusieurs méthodes d'authentification actives",
|
||||||
"policyAuthOrLogicBanner": "Les visiteurs peuvent s'authentifier en utilisant l'une des méthodes actives ci-dessous. Ils n'ont pas besoin de toutes les compléter.",
|
"policyAuthOrLogicBanner": "Les visiteurs peuvent s'authentifier en utilisant l'une des méthodes actives ci-dessous. Ils n'ont pas besoin de toutes les compléter.",
|
||||||
"policyAuthMethodActive": "Actif",
|
"policyAuthMethodActive": "Actif",
|
||||||
"policyAuthMethodOff": "Éteint",
|
"policyAuthMethodOff": "Éteint",
|
||||||
"policyAuthSsoTitle": "SSO de la plateforme",
|
"policyAuthSsoTitle": "SSO de la plateforme",
|
||||||
"policyAuthSsoDescription": "Exigez une connexion via le fournisseur d'identité de votre organisation",
|
"policyAuthSsoDescription": "Exigez une connexion via le fournisseur d'identité de votre organisation",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "URL de connexion",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Chaque utilisateur a déjà une clé API d'identité, vous devez donc uniquement créer des clés API virtuelles pour les clients non-utilisateurs ou l'accès partagé. Les utilisateurs peuvent récupérer leur clé en se connectant avec leur fournisseur d'identité à l'URL de cette ressource, où elle sera affichée après la connexion.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Chaque utilisateur a déjà une clé API d'identité, vous devez donc uniquement créer des clés API virtuelles pour les clients non-utilisateurs ou l'accès partagé. Les utilisateurs récupèrent leur clé ici après s'être connectés avec leur fournisseur d'identité.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} utilisateurs, {roles} rôles",
|
"policyAuthSsoSummary": "{idp} · {users} utilisateurs, {roles} rôles",
|
||||||
"policyAuthSsoDefaultIdp": "Fournisseur par défaut",
|
"policyAuthSsoDefaultIdp": "Fournisseur par défaut",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Ajouter un fournisseur d'identité par défaut",
|
"policyAuthAddDefaultIdentityProvider": "Ajouter un fournisseur d'identité par défaut",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Version",
|
"newtVersion": "Version",
|
||||||
"architecture": "Architecture",
|
"architecture": "Architecture",
|
||||||
"sites": "Nœuds",
|
"sites": "Nœuds",
|
||||||
"siteWgAnyClients": "Utilisez n'importe quel client WireGuard pour vous connecter. Vous devrez adresser des ressources internes en utilisant l'adresse IP du pair.",
|
"siteWgAnyClients": "Utilisez n'importe quel client WireGuard pour vous connecter. Vous devrez adresser les ressources privées en utilisant l'IP du pair.",
|
||||||
"siteWgCompatibleAllClients": "Compatible avec tous les clients WireGuard",
|
"siteWgCompatibleAllClients": "Compatible avec tous les clients WireGuard",
|
||||||
"siteWgManualConfigurationRequired": "Configuration manuelle requise",
|
"siteWgManualConfigurationRequired": "Configuration manuelle requise",
|
||||||
"userErrorNotAdminOrOwner": "L'utilisateur n'est pas un administrateur ou un propriétaire",
|
"userErrorNotAdminOrOwner": "L'utilisateur n'est pas un administrateur ou un propriétaire",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Un nouveau rôle est requis",
|
"accessRoleErrorNewRequired": "Un nouveau rôle est requis",
|
||||||
"accessRoleErrorRemove": "Échec de la suppression du rôle",
|
"accessRoleErrorRemove": "Échec de la suppression du rôle",
|
||||||
"accessRoleErrorRemoveDescription": "Une erreur s'est produite lors de la suppression du rôle.",
|
"accessRoleErrorRemoveDescription": "Une erreur s'est produite lors de la suppression du rôle.",
|
||||||
|
"accessRoleInferenceBudget": "Budget AI",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Configurez comment les membres de ce rôle restreignent l'utilisation de l'IA en fonction des dépenses ou des limites de jetons",
|
||||||
"accessRoleName": "Nom du rôle",
|
"accessRoleName": "Nom du rôle",
|
||||||
"accessRoleQuestionRemove": "Vous êtes sur le point de supprimer le rôle `{name}`. Vous ne pouvez pas annuler cette action.",
|
"accessRoleQuestionRemove": "Vous êtes sur le point de supprimer le rôle `{name}`. Vous ne pouvez pas annuler cette action.",
|
||||||
"accessRoleRemove": "Supprimer le rôle",
|
"accessRoleRemove": "Supprimer le rôle",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Créer un utilisateur Org",
|
"createOrgUser": "Créer un utilisateur Org",
|
||||||
"actionUpdateOrg": "Mettre à jour l'organisation",
|
"actionUpdateOrg": "Mettre à jour l'organisation",
|
||||||
"actionRemoveInvitation": "Supprimer l'invitation",
|
"actionRemoveInvitation": "Supprimer l'invitation",
|
||||||
|
"actionRemoveUserRole": "Supprimer le rôle d'utilisateur",
|
||||||
"actionUpdateUser": "Mettre à jour l'utilisateur",
|
"actionUpdateUser": "Mettre à jour l'utilisateur",
|
||||||
"actionGetUser": "Obtenir l'utilisateur",
|
"actionGetUser": "Obtenir l'utilisateur",
|
||||||
"actionGetOrgUser": "Obtenir l'utilisateur de l'organisation",
|
"actionGetOrgUser": "Obtenir l'utilisateur de l'organisation",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Supprimer un site",
|
"actionDeleteSite": "Supprimer un site",
|
||||||
"actionGetSite": "Obtenir un site",
|
"actionGetSite": "Obtenir un site",
|
||||||
"actionListSites": "Lister les sites",
|
"actionListSites": "Lister les sites",
|
||||||
|
"actionCreateAiProvider": "Créer un fournisseur AI",
|
||||||
|
"actionDeleteAiProvider": "Supprimer un fournisseur AI",
|
||||||
|
"actionGetAiProvider": "Obtenir un fournisseur AI",
|
||||||
|
"actionListAiProviders": "Lister les fournisseurs AI",
|
||||||
|
"actionUpdateAiProvider": "Mettre à jour un fournisseur AI",
|
||||||
|
"actionCreateAiModel": "Créer un modèle AI",
|
||||||
|
"actionDeleteAiModel": "Supprimer un modèle AI",
|
||||||
|
"actionGetAiModel": "Obtenir un modèle AI",
|
||||||
|
"actionListAiModels": "Lister les modèles AI",
|
||||||
|
"actionUpdateAiModel": "Mettre à jour un modèle AI",
|
||||||
|
"actionCreateAiBudget": "Créer un budget AI",
|
||||||
|
"actionDeleteAiBudget": "Supprimer un budget AI",
|
||||||
|
"actionGetAiBudget": "Obtenir un budget AI",
|
||||||
|
"actionListAiBudgets": "Lister les budgets AI",
|
||||||
|
"actionUpdateAiBudget": "Mettre à jour un budget AI",
|
||||||
|
"actionListResourceAiModels": "Lister les modèles AI de ressource",
|
||||||
|
"actionSetResourceAiModels": "Définir les modèles AI de ressource",
|
||||||
|
"actionCreateVirtualApiKey": "Créer une clé API virtuelle",
|
||||||
|
"actionDeleteVirtualApiKey": "Supprimer une clé API virtuelle",
|
||||||
|
"actionGetVirtualApiKey": "Obtenir une clé API virtuelle",
|
||||||
|
"actionListVirtualApiKeys": "Lister les clés API virtuelles",
|
||||||
|
"actionUpdateVirtualApiKey": "Mettre à jour une clé API virtuelle",
|
||||||
"actionApplyBlueprint": "Appliquer la Config",
|
"actionApplyBlueprint": "Appliquer la Config",
|
||||||
"actionListBlueprints": "Lister les plans",
|
"actionListBlueprints": "Lister les plans",
|
||||||
"actionGetBlueprint": "Obtenez un plan",
|
"actionGetBlueprint": "Obtenez un plan",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Entrez le jeton de configuration depuis la console du serveur.",
|
"setupTokenDescription": "Entrez le jeton de configuration depuis la console du serveur.",
|
||||||
"setupTokenRequired": "Le jeton de configuration est requis.",
|
"setupTokenRequired": "Le jeton de configuration est requis.",
|
||||||
"actionUpdateSite": "Mettre à jour un site",
|
"actionUpdateSite": "Mettre à jour un site",
|
||||||
|
"actionApproveSite": "Approuver le site",
|
||||||
|
"actionRejectSite": "Rejeter le site",
|
||||||
"actionResetSiteBandwidth": "Réinitialiser la bande passante de l'organisation",
|
"actionResetSiteBandwidth": "Réinitialiser la bande passante de l'organisation",
|
||||||
"actionListSiteRoles": "Lister les rôles autorisés du site",
|
"actionListSiteRoles": "Lister les rôles autorisés du site",
|
||||||
"actionCreateResource": "Créer une ressource",
|
"actionCreateResource": "Créer une ressource",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Définir le code PIN de la ressource",
|
"actionSetResourcePincode": "Définir le code PIN de la ressource",
|
||||||
"actionSetResourceEmailWhitelist": "Définir la liste blanche des emails de la ressource",
|
"actionSetResourceEmailWhitelist": "Définir la liste blanche des emails de la ressource",
|
||||||
"actionGetResourceEmailWhitelist": "Obtenir la liste blanche des emails de la ressource",
|
"actionGetResourceEmailWhitelist": "Obtenir la liste blanche des emails de la ressource",
|
||||||
|
"actionListResourcePolicies": "Lister les politiques de ressource",
|
||||||
|
"actionCreateResourcePolicy": "Créer une politique de ressource",
|
||||||
"actionGetResourcePolicy": "Obtenir une politique de ressources",
|
"actionGetResourcePolicy": "Obtenir une politique de ressources",
|
||||||
"actionUpdateResourcePolicy": "Mettre à jour la politique de ressources",
|
"actionUpdateResourcePolicy": "Mettre à jour la politique de ressources",
|
||||||
|
"actionDeleteResourcePolicy": "Supprimer une politique de ressource",
|
||||||
"actionSetResourcePolicyUsers": "Définir les utilisateurs de la politique de ressources",
|
"actionSetResourcePolicyUsers": "Définir les utilisateurs de la politique de ressources",
|
||||||
"actionSetResourcePolicyRoles": "Définir les rôles de la politique de ressources",
|
"actionSetResourcePolicyRoles": "Définir les rôles de la politique de ressources",
|
||||||
"actionSetResourcePolicyPassword": "Définir le mot de passe de la politique de ressources",
|
"actionSetResourcePolicyPassword": "Définir le mot de passe de la politique de ressources",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Lister les invitations",
|
"actionListInvitations": "Lister les invitations",
|
||||||
"actionExportLogs": "Exporter les journaux",
|
"actionExportLogs": "Exporter les journaux",
|
||||||
"actionViewLogs": "Voir les logs",
|
"actionViewLogs": "Voir les logs",
|
||||||
|
"actionCreateSiteProvisioningKey": "Créer une clé de provisionnement de site",
|
||||||
|
"actionListSiteProvisioningKeys": "Lister les clés de provisionnement de site",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Mettre à jour la clé de provisionnement de site",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Supprimer la clé de provisionnement de site",
|
||||||
"noneSelected": "Aucune sélection",
|
"noneSelected": "Aucune sélection",
|
||||||
"orgNotFound2": "Aucune organisation trouvée.",
|
"orgNotFound2": "Aucune organisation trouvée.",
|
||||||
"search": "Rechercher…",
|
"search": "Rechercher…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Entrez le code de votre application d'authentification ou l'un de vos codes de secours à usage unique.",
|
"otpAuthDescription": "Entrez le code de votre application d'authentification ou l'un de vos codes de secours à usage unique.",
|
||||||
"otpAuthSubmit": "Soumettre le code",
|
"otpAuthSubmit": "Soumettre le code",
|
||||||
"idpContinue": "Ou continuer avec",
|
"idpContinue": "Ou continuer avec",
|
||||||
|
"idpLastUsed": "Dernière utilisation",
|
||||||
"otpAuthBack": "Retour au mot de passe",
|
"otpAuthBack": "Retour au mot de passe",
|
||||||
"navbar": "Menu de navigation",
|
"navbar": "Menu de navigation",
|
||||||
"navbarDescription": "Menu de navigation principal de l'application",
|
"navbarDescription": "Menu de navigation principal de l'application",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Créer un client machine",
|
"commandPaletteCreateMachineClient": "Créer un client machine",
|
||||||
"commandPaletteCreateAlertRule": "Créer une règle d'alerte",
|
"commandPaletteCreateAlertRule": "Créer une règle d'alerte",
|
||||||
"commandPaletteCreateIdentityProvider": "Créer un fournisseur d'identité",
|
"commandPaletteCreateIdentityProvider": "Créer un fournisseur d'identité",
|
||||||
|
"commandPaletteCreateAiProvider": "Créer le fournisseur d'IA",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Créer une clé API virtuelle",
|
||||||
"commandPaletteToggleTheme": "Changer de thème",
|
"commandPaletteToggleTheme": "Changer de thème",
|
||||||
"commandPaletteChooseOrganization": "Choisir une organisation",
|
"commandPaletteChooseOrganization": "Choisir une organisation",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Invitations",
|
"sidebarInvitations": "Invitations",
|
||||||
"sidebarRoles": "Rôles",
|
"sidebarRoles": "Rôles",
|
||||||
"sidebarShareableLinks": "Liens partageables",
|
"sidebarShareableLinks": "Liens partageables",
|
||||||
|
"sidebarAiGateway": "Passerelle AI",
|
||||||
|
"sidebarAiProviders": "Fournisseurs",
|
||||||
|
"commandAiProviders": "Fournisseurs AI",
|
||||||
|
"sidebarVirtualApiKeys": "Clés API virtuelles",
|
||||||
|
"sidebarMyApiKeys": "Vos clés API",
|
||||||
|
"sidebarAccount": "Lanceur",
|
||||||
|
"commandVirtualApiKeys": "Clés API virtuelles",
|
||||||
|
"virtualApiKeysTitle": "Gérer les clés API virtuelles",
|
||||||
|
"virtualApiKeysDescription": "Créer et gérer des clés API manuelles pour l'accès à la passerelle AI publique",
|
||||||
|
"virtualApiKeysTabIdentity": "Clés d'identité",
|
||||||
|
"virtualApiKeysTabVirtual": "Clés virtuelles",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Clés d'identité pour chaque utilisateur",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Chaque utilisateur a déjà une clé d'identité Pangolin pour cette organisation. Elle est unique à leur compte et les authentifie aux passerelles AI qu'ils peuvent utiliser.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Exemple",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Comment les utilisateurs obtiennent leur clé",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Visitez une URL de passerelle AI publique dans le navigateur et connectez-vous avec leur compte.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Ou accédez à <url></url> en étant connecté.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Vous pouvez créer des clés API virtuelles supplémentaires dans l'onglet Clés Virtuelles. Ces clés peuvent être délimitées à des passerelles AI publiques spécifiques et éventuellement associées à un utilisateur. Créer une clé accorde immédiatement l'accès aux passerelles AI publiques sélectionnées.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Créer manuellement une clé",
|
||||||
|
"virtualApiKeysEmailIdentity": "Envoyer les clés d'identité par email",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Envoyez à chaque utilisateur sélectionné ou rôle leur clé d'identité Pangolin.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Envoyer à tous les utilisateurs",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Envoyez un email à chaque membre de l'organisation possédant une adresse email de compte.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Utilisateurs",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Rôles",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Envoyer des emails",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Clés d'identité envoyées par email",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "{skipped} utilisateurs ont été ignorés car ils n'ont pas d'adresse email.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "Sélectionnez au moins un utilisateur ou rôle, ou envoyez à tous les utilisateurs.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Erreur lors de l'envoi des clés d'identité",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Échec de l'envoi des clés d'identité par email",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Clés d'identité pour chaque utilisateur",
|
||||||
|
"virtualApiKeysBannerTitle": "Tous les utilisateurs ont déjà une clé d'identité disponible à {keysUrl}. Vous pouvez également générer manuellement des clés ici pour accorder un accès direct aux passerelles AI publiques.",
|
||||||
|
"virtualApiKeysBannerDescription": "Voir les clés d'identité",
|
||||||
|
"virtualApiKeysBannerButtonText": "Voir les clés d'identité",
|
||||||
|
"virtualApiKeys": "Clés API virtuelles",
|
||||||
|
"virtualApiKeysSearch": "Rechercher des clés...",
|
||||||
|
"virtualApiKeysCreate": "Émettre une clé manuelle pouvant appeler les passerelles AI publiques dans cette organisation",
|
||||||
|
"virtualApiKeysCreateDescription": "Créer une clé",
|
||||||
|
"virtualApiKeysCreateButton": "Créer une clé",
|
||||||
|
"virtualApiKeysEmpty": "Nom",
|
||||||
|
"virtualApiKeysName": "Nom",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Associer un utilisateur (facultatif)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Associer un utilisateur (facultatif)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Toutes les passerelles AI publiques",
|
||||||
|
"virtualApiKeysAllResources": "Permettre à cette clé d'accéder à chaque passerelle AI publique de l'organisation",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Passerelles AI publiques",
|
||||||
|
"virtualApiKeysSelectResources": "Sélectionner des ressources",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Sélectionner des ressources",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Aucune ressource",
|
||||||
|
"virtualApiKeysNoResources": "Clé",
|
||||||
|
"virtualApiKeysSecret": "Clé",
|
||||||
|
"virtualApiKeysCopyKey": "Voir le secret",
|
||||||
|
"virtualApiKeysViewSecret": "Voir le secret",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Cet accès secret accorde l'accès aux passerelles AI publiques assignées à cette clé",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Modifier la clé API virtuelle",
|
||||||
|
"virtualApiKeysEdit": "Mettre à jour l'utilisateur associé et l'accès à la passerelle AI publique pour cette clé",
|
||||||
|
"virtualApiKeysEditDescription": "Enregistrer les modifications",
|
||||||
|
"virtualApiKeysSaveButton": "Sélectionnez au moins une passerelle AI publique, ou activez toutes les passerelles AI publiques",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Clé API virtuelle mise à jour",
|
||||||
|
"virtualApiKeysUpdated": "La clé API virtuelle a été mise à jour",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Erreur lors de la mise à jour de la clé API virtuelle",
|
||||||
|
"virtualApiKeysErrorUpdate": "Échec de la mise à jour de la clé API virtuelle",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Erreur lors de la création de la clé API virtuelle",
|
||||||
|
"virtualApiKeysErrorCreate": "Échec de la création de la clé API virtuelle",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Erreur lors de la suppression de la clé API virtuelle",
|
||||||
|
"virtualApiKeysErrorDelete": "Échec de la suppression de la clé API virtuelle",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Clé API virtuelle supprimée",
|
||||||
|
"virtualApiKeysDeleted": "La clé API virtuelle a été supprimée",
|
||||||
|
"virtualApiKeysDeletedDescription": "Supprimer la clé API virtuelle",
|
||||||
|
"virtualApiKeysDelete": "Supprimer la clé",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Supprimer la clé",
|
||||||
|
"virtualApiKeysQuestionRemove": "Êtes-vous sûr de vouloir supprimer cette clé API virtuelle ?",
|
||||||
|
"virtualApiKeysMessageRemove": "Erreur lors du chargement du secret",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Erreur lors du chargement du secret",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Non assigné",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Budget",
|
||||||
|
"virtualApiKeysInferenceBudget": "Budget",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Email de la clé lors de la génération",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Envoyer cette clé par email",
|
||||||
|
"virtualApiKeysEmailThisKey": "Envoyer la clé à l'utilisateur associé et à des adresses supplémentaires après sa création",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Envoyez la clé actuelle à l'utilisateur associé et à des adresses supplémentaires",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "L'email n'est pas configuré sur ce serveur",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "L'Email n'est pas configuré sur ce serveur",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Envoyer à l'utilisateur associé",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Envoyez la clé à l'adresse email du compte de l'utilisateur associé",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Associez un utilisateur pour envoyer la clé à cet utilisateur",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Emails supplémentaires",
|
||||||
|
"virtualApiKeysEmailAdditional": "Ajoutez un email et appuyez sur Entrée",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Sélectionnez l'utilisateur associé ou ajoutez au moins une adresse email",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Vos clés API",
|
||||||
|
"myVirtualApiKeysTitle": "Voyez votre clé d'identité et toutes les clés API virtuelles attribuées à vous dans cette organisation",
|
||||||
|
"myVirtualApiKeysDescription": "Vos clés API pour {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Voyez votre clé d'identité et les clés API virtuelles attribuées à vous qui peuvent accéder à {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Clé d'identité",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Clé d'identité",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Votre clé API personnelle",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Votre clé API personnelle pour {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Votre clé personnelle pour cette organisation. Utilisez-la pour appeler {resourceName}.",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Clés attribuées",
|
||||||
|
"myVirtualApiKeysManualTitle": "Clés attribuées",
|
||||||
|
"myVirtualApiKeysManualDescription": "Clés API virtuelles manuelles associées à votre compte qui peuvent accéder à {resourceName}",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Pas encore de clés attribuées",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Identité",
|
||||||
|
"myVirtualApiKeysKindUser": "Manuel",
|
||||||
|
"myVirtualApiKeysKindManual": "Clé non nommée",
|
||||||
|
"myVirtualApiKeysUnnamed": "Révéler le secret",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Ce secret vous authentifie aux ressources de la passerelle AI",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Fournisseurs AI",
|
||||||
|
"aiClientConfigTitle": "Configurer les agents de codage",
|
||||||
|
"aiClientConfigDescription": "Copiez la configuration pour les agents de codage populaires ou laissez le CLI de Pangolin le configurer automatiquement pour vous.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Outil de codage agentique d'Anthropic pour le terminal.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Outil de codage agentique d'OpenAI pour le terminal.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Agent de codage terminal open source.",
|
||||||
|
"aiClientConfigDescriptionCursor": "Éditeur de code IA basé sur VS Code.",
|
||||||
|
"aiClientConfigSetup": "Configuration",
|
||||||
|
"aiClientConfigTabCli": "Automatique (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Configuration manuelle",
|
||||||
|
"aiClientConfigPreset": "Configuration",
|
||||||
|
"aiClientConfigStep": "Étape {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Ce snippet inclut des valeurs d'exemple, telles qu'un nom de modèle ou une URL de ressource. Remplacez-les par les vôtres avant de l'utiliser.",
|
||||||
|
"aiClientConfigRevealError": "Impossible de charger votre clé API.",
|
||||||
|
"aiClientConfigRevealRetry": "Réessayer",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Cette ressource peut être utilisée à partir de clients communs comme Claude Code et OpenCode. <configLink>En savoir plus</configLink>",
|
||||||
|
"aiProvidersTitle": "Connectez des fournisseurs de modèles pour des charges de travail AI dans cette organisation",
|
||||||
|
"aiProvidersDescription": "Connecter les fournisseurs de modèles",
|
||||||
|
"aiProvidersBannerTitle": "Les fournisseurs sont les backends de modèle que Pangolin utilise pour les charges de travail AI. Connectez OpenAI, Anthropic et d'autres fournisseurs ici, puis attachez-les aux passerelles AI publiques afin que les utilisateurs puissent appeler des modèles avec un accès conscient de l'identité, des budgets et des journaux.",
|
||||||
|
"aiProvidersBannerDescription": "Ajouter un fournisseur",
|
||||||
|
"aiProvidersAdd": "Rechercher des fournisseurs...",
|
||||||
|
"aiProvidersSearch": "Aucun fournisseur AI pour le moment",
|
||||||
|
"aiProvidersEmpty": "Créer un fournisseur AI",
|
||||||
|
"aiProviderCreate": "Ajouter un fournisseur de modèles pour cette organisation",
|
||||||
|
"aiProviderCreateDescription": "Voir tous les fournisseurs",
|
||||||
|
"aiProviderSeeAll": "Paramètres du fournisseur pour {providerName}",
|
||||||
|
"aiProviderSetting": "Configurez ce fournisseur AI",
|
||||||
|
"aiProviderSettingDescription": "Général",
|
||||||
|
"aiProviderGeneral": "Paramètres de base pour ce fournisseur",
|
||||||
|
"aiProviderGeneralDescription": "Configuration",
|
||||||
|
"aiProviderConfiguration": "Routage du réseau et authentification pour ce fournisseur",
|
||||||
|
"aiProviderConfigurationDescription": "Paramètres du réseau",
|
||||||
|
"aiProviderNetworkSettings": "Choisissez comment le trafic atteint ce fournisseur",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Authentification",
|
||||||
|
"aiProviderAuthSettings": "Authentification",
|
||||||
|
"aiProviderAuthSettingsDescription": "Budget",
|
||||||
|
"aiProviderBudgetSettings": "Configurez comment ce fournisseur restreint l'utilisation en fonction des dépenses ou des limites de jetons",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Ajouter un budget",
|
||||||
|
"aiBudgetAdd": "Ajouter un budget",
|
||||||
|
"aiBudgetEmpty": "Type de dépense",
|
||||||
|
"aiBudgetUnit": "Période de réinitialisation",
|
||||||
|
"aiBudgetPeriod": "Dépense maximale",
|
||||||
|
"aiBudgetAmount": "Dépense maximale",
|
||||||
|
"aiBudgetAmountPlaceholder": "Horaire",
|
||||||
|
"aiBudgetPeriodHourly": "Quotidien",
|
||||||
|
"aiBudgetPeriodDaily": "Hebdomadaire",
|
||||||
|
"aiBudgetPeriodWeekly": "Mensuel",
|
||||||
|
"aiBudgetPeriodMonthly": "Annuel",
|
||||||
|
"aiBudgetPeriodYearly": "Durée de vie",
|
||||||
|
"aiBudgetPeriodLifetime": "Durée de vie",
|
||||||
|
"aiBudgetUnitUsd": "Jetons",
|
||||||
|
"aiBudgetUnitTokens": "Un budget pour cette période de réinitialisation et ce type de dépense existe déjà",
|
||||||
|
"aiBudgetConflictError": "Entrez une dépense maximale supérieure à 0",
|
||||||
|
"aiBudgetInvalidAmountError": "Entrez une dépense maximale supérieure à 0",
|
||||||
|
"aiBudgetUpdated": "Échec de la mise à jour des budgets",
|
||||||
|
"aiBudgetErrorSave": "Type de fournisseur",
|
||||||
|
"aiProviderType": "Type de fournisseur",
|
||||||
|
"aiProviderTypeSearch": "Rechercher des fournisseurs...",
|
||||||
|
"aiProviderTypeNotFound": "OpenAI",
|
||||||
|
"aiProviderTypeOpenai": "Anthropic",
|
||||||
|
"aiProviderTypeAnthropic": "Google Gemini",
|
||||||
|
"aiProviderTypeGoogleGemini": "Vertex AI",
|
||||||
|
"aiProviderTypeVertexAi": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeBedrock": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "OpenRouter",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Personnalisé",
|
||||||
|
"aiProviderTypeCustom": "Personnalisé",
|
||||||
|
"aiProviderTypeOpenaiDescription": "API Anthropic",
|
||||||
|
"aiProviderTypeAnthropicDescription": "API Google Gemini",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "API Google Vertex AI",
|
||||||
|
"aiProviderTypeVertexAiDescription": "API d'exécution Amazon Bedrock",
|
||||||
|
"aiProviderTypeBedrockDescription": "API Microsoft Foundry",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "API OpenRouter",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "API Passerelle Vercel AI",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "API de passerelle AI Vercel",
|
||||||
|
"aiProviderTypeCustomDescription": "Apportez votre propre point de terminaison ou routez via les cibles du site",
|
||||||
|
"aiProviderUpstreamUrl": "URL amont",
|
||||||
|
"aiProviderUpstreamUrlDescription": "URL de base pour l'API du fournisseur",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Laissez vide pour utiliser l'URL amont par défaut pour ce fournisseur",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "URL amont effective",
|
||||||
|
"aiProviderApiKey": "Clé API",
|
||||||
|
"aiProviderApiKeyDescription": "Clé API utilisée pour authentifier les requêtes auprès de ce fournisseur",
|
||||||
|
"aiProviderCustomHeadersDescription": "En-têtes envoyés à chaque requête à ce fournisseur. Séparé par une nouvelle ligne : Nom-de-l'en-tête: valeur",
|
||||||
|
"aiProviderApiKeyLastChars": "Clé API",
|
||||||
|
"aiProviderAuthType": "Type d'authentification",
|
||||||
|
"aiProviderAuthTypeSearch": "Rechercher des types d'authentification...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Aucun type d'authentification trouvé",
|
||||||
|
"aiProviderAuthTypeBearer": "Porteur",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Authorization : Clé Bearer. Utilisé par OpenAI et la plupart des fournisseurs",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "En-tête x-api-key. Utilisé par Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "En-tête x-goog-api-key. Utilisé par Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Authorization : Clé Splunk. Utilisé par le collecteur d'événements HTTP Splunk",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Passerelle AI de Cloudflare",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization : Clé Bearer. Utilisé par la passerelle AI de Cloudflare",
|
||||||
|
"aiProviderAuthTypeNone": "Pas d'authentification",
|
||||||
|
"aiProviderAuthTypePassthrough": "Transparence",
|
||||||
|
"aiProviderAuthTypeDescription": "Comment l'API amont authentifie les requêtes",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Transmettez les en-têtes de clé API de l'appelant vers l'amont",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Ne pas envoyer d'en-têtes d'authentification vers l'amont",
|
||||||
|
"aiProviderRoutingMode": "Mode de routage",
|
||||||
|
"aiProviderRoutingModeDescription": "Envoyez le trafic vers une URL amont ou vers des cibles HTTP sur vos sites",
|
||||||
|
"aiProviderRoutingModeUrl": "URL amont",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Appelez une URL de base d'API publique ou privée",
|
||||||
|
"aiProviderRoutingModeTarget": "Cibles du site",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Route à travers les cibles sur vos sites",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Après avoir créé ce fournisseur, configurez les cibles du site dans l'onglet Paramètres du réseau.",
|
||||||
|
"aiProviderTargetNoOne": "Ce fournisseur n'a aucune cible. Ajoutez une cible pour acheminer les requêtes via vos sites.",
|
||||||
|
"aiProviderSkipTlsVerification": "Ignorer la vérification TLS",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Désactiver la vérification du certificat TLS pour la connexion amont",
|
||||||
|
"aiProviderBudget": "Budget",
|
||||||
|
"aiProviderBudgetDescription": "Budget de dépenses ou de jetons optionnel pour ce fournisseur",
|
||||||
|
"aiProviderBudgetAmount": "Montant du budget",
|
||||||
|
"aiProviderBudgetUnit": "Unité de budget",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Jetons",
|
||||||
|
"aiProviderEnabled": "Activé",
|
||||||
|
"aiProviderEnabledDescription": "Désactivez complètement ce fournisseur sur toutes les ressources",
|
||||||
|
"aiProviderErrorCreate": "Échec de la création du fournisseur AI",
|
||||||
|
"aiProviderErrorUpdate": "Échec de la mise à jour du fournisseur AI",
|
||||||
|
"aiProviderErrorDelete": "Échec de la suppression du fournisseur AI",
|
||||||
|
"aiProviderErrorLoad": "Échec du chargement du fournisseur AI",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Entrez une URL amont valide",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Une URL amont est requise pour ce fournisseur",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Le type d'authentification est requis",
|
||||||
|
"aiProviderErrorApiKeyRequired": "La clé API est requise",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Le routage des cibles du site est uniquement disponible pour les fournisseurs personnalisés",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Sélectionnez au moins une capacité API",
|
||||||
|
"aiProviderCapabilities": "Capacités API",
|
||||||
|
"aiProviderCapabilitiesDescription": "Sélectionnez les formats d'API que ce fournisseur peut gérer. Les fournisseurs connus commencent avec des réglages recommandés.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Sélectionnez quels formats d'API ce fournisseur personnalisé peut gérer",
|
||||||
|
"aiProviderCapabilitiesSelect": "Sélectionner les capacités",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Aucune capacité trouvée",
|
||||||
|
"aiProviderCapabilitiesSearch": "Rechercher des capacités...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Completions de Chat",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Prend en charge /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "Réponses OpenAI",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Prend en charge /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Messages Anthropiques",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Prend en charge /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Générer du Contenu Gemini",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Prend en charge l'API directe de Gemini",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Invocation du Modèle Bedrock",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Prend en charge Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Générer du Contenu Vertex",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Prend en charge le format Gemini de Vertex AI",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Prédiction Brute Vertex",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Prend en charge la prédiction brute Vertex AI pour les modèles anthropiques",
|
||||||
|
"aiCapabilityBedrockConverse": "Converse Bedrock",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Prend en charge l'API Converse d'Amazon Bedrock",
|
||||||
|
"aiProviderCreated": "Fournisseur d'IA créé",
|
||||||
|
"aiProviderUpdated": "Fournisseur d'IA mis à jour",
|
||||||
|
"aiProviderDeleted": "Fournisseur d'IA supprimé",
|
||||||
|
"aiProviderDelete": "Supprimer le fournisseur",
|
||||||
|
"aiProviderDeleteConfirm": "Supprimer le fournisseur",
|
||||||
|
"aiProviderQuestionRemove": "Êtes-vous sûr de vouloir supprimer ce fournisseur d'IA ?",
|
||||||
|
"aiProviderMessageRemove": "Cela supprimera définitivement le fournisseur ainsi que ses modèles et cibles. Cela ne peut pas être annulé.",
|
||||||
|
"aiProviderErrorNoUpdate": "Le fournisseur d'IA n'est pas disponible pour la mise à jour",
|
||||||
|
"aiProviderModels": "Modèles",
|
||||||
|
"aiProviderModelsDescription": "Définissez les listes d'autorisation et de blocage pour ce fournisseur. Les demandes doivent correspondre à une entrée autorisée et ne doivent pas correspondre à une entrée bloquée.",
|
||||||
|
"aiProviderCreateModelsDescription": "Choisissez quels modèles ce fournisseur peut desservir. Une liste d'autorisation vide bloque tout le trafic. Vous pouvez ajouter ou modifier des modèles plus tard.",
|
||||||
|
"aiProviderModelsPlaceholder": "Recherchez des modèles ou tapez une clé personnalisée",
|
||||||
|
"aiProviderModelsAllow": "Liste d'autorisation",
|
||||||
|
"aiProviderModelsAllowDescription": "Modèles qui peuvent être utilisés via ce fournisseur. Vide signifie tout bloquer.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Entrez la clé du modèle",
|
||||||
|
"aiProviderModelsAllowEmpty": "Pas de modèles ajoutés pour le moment.",
|
||||||
|
"aiProviderModelsBlock": "Liste de blocage",
|
||||||
|
"aiProviderModelsBlockDescription": "Modèles à refuser même s'ils correspondent à une entrée autorisée.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Entrez la clé du modèle",
|
||||||
|
"aiProviderModelsBlockEmpty": "Pas de modèles ajoutés pour le moment.",
|
||||||
|
"aiProviderModelsAdd": "Ajouter des modèles",
|
||||||
|
"aiProviderModelsClearAll": "Effacer tout",
|
||||||
|
"aiProviderModelsAddCustom": "Ajouter \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Appuyez sur Entrée pour ajouter cette clé de modèle personnalisée.",
|
||||||
|
"aiProviderModelsAddBulk": "Ajouter {count} clés personnalisées",
|
||||||
|
"aiProviderModelsAddBulkHint": "Appuyez sur Entrée pour ajouter {count} clés personnalisées.",
|
||||||
|
"aiProviderModelsAddOne": "Ajouter {key} maintenant",
|
||||||
|
"aiProviderModelsAddSelected": "Ajouter la sélection",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} sélectionné(s)",
|
||||||
|
"aiProviderModelsSelectAll": "Tout sélectionner",
|
||||||
|
"aiProviderModelsClearSelected": "Effacer",
|
||||||
|
"aiProviderModelsBulkHint": "Sélectionnez des modèles connus ou tapez une clé personnalisée.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Aucun modèle de catalogue correspondant.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Modèles connus",
|
||||||
|
"aiProviderModelsAllLabel": "Tous les modèles",
|
||||||
|
"aiProviderModelsAllPatternHint": "Joker : *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Autoriser tous les modèles",
|
||||||
|
"aiProviderModelsAddAllBlock": "Bloquer tous les modèles",
|
||||||
|
"aiProviderModelsAddAllDescription": "Utilise le modèle * joker pour que chaque clé de modèle corresponde.",
|
||||||
|
"aiProviderModelsViewMore": "Voir plus ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Voir moins",
|
||||||
|
"aiProviderModelsRemove": "Supprimer le modèle",
|
||||||
|
"aiProviderModelsEditHint": "Cliquez pour modifier les paramètres du modèle",
|
||||||
|
"aiProviderModelsSourceCatalog": "Modèle de catalogue connu",
|
||||||
|
"aiProviderModelsSourceCustom": "Clé de modèle personnalisée",
|
||||||
|
"aiProviderModelsSourcePattern": "Modèle de correspondance avec générique",
|
||||||
|
"aiProviderModelsSourceAll": "Correspond à chaque clé de modèle",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Budget configuré",
|
||||||
|
"aiProviderModelsEditTitle": "Modifier le modèle",
|
||||||
|
"aiProviderModelsEditDescription": "Mettez à jour la clé du modèle ou configurez son budget.",
|
||||||
|
"aiProviderModelsBudgetTab": "Budget",
|
||||||
|
"aiProviderModelsKeyLabel": "Clé du modèle",
|
||||||
|
"aiProviderModelsKeyRequired": "Entrez une clé de modèle",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Cette clé de modèle est déjà sur une liste",
|
||||||
|
"aiProviderModelsOverlapError": "Ces modèles ne peuvent être sur les deux listes : {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modèles mis à jour",
|
||||||
|
"aiProviderModelsErrorUpdate": "Échec de la mise à jour des modèles",
|
||||||
|
"aiResourceProviders": "Fournisseurs",
|
||||||
|
"aiResourceProvidersDescription": "Choisissez quels fournisseurs d'IA ce portail AI peut utiliser",
|
||||||
|
"aiResourceProvidersHelp": "Joignez des fournisseurs et choisissez d'hériter (utiliser les listes de chaque fournisseur) ou de sélectionner (choisir une liste autorisée pour cette ressource). Les modèles conflictuels des fournisseurs attachés ne sont pas autorisés.",
|
||||||
|
"aiResourceProvidersSelect": "Sélectionnez les fournisseurs",
|
||||||
|
"aiResourceProvidersEmpty": "Aucun fournisseur d'IA trouvé",
|
||||||
|
"aiResourceProvidersNoneAttached": "Aucun fournisseur n'est attaché pour le moment.",
|
||||||
|
"aiResourceProvidersAdd": "Ajouter un fournisseur",
|
||||||
|
"aiResourceProvidersRemove": "Supprimer le fournisseur",
|
||||||
|
"aiResourceProviderToggleEnabled": "Activer ou désactiver ce fournisseur sur la ressource",
|
||||||
|
"aiResourceProviderDisabled": "Désactivé",
|
||||||
|
"aiResourceProvidersUpdated": "Fournisseurs mis à jour",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Échec de la mise à jour des fournisseurs",
|
||||||
|
"aiResourceProviderEditDescription": "Choisissez comment les modèles de ce fournisseur sont exposés sur cette ressource.",
|
||||||
|
"viewProviderSettings": "Voir les paramètres du fournisseur",
|
||||||
|
"aiResourceProviderMode": "Mode d'accès",
|
||||||
|
"aiResourceProviderModeInherit": "Hériter",
|
||||||
|
"aiResourceProviderModeSelect": "Sélectionner",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Sélectionner · {count} modèles",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Utilisez les listes d'autorisation et de blocage de ce fournisseur comme configuré sur le fournisseur.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Choisissez un sous-ensemble des modèles de liste autorisée de ce fournisseur pour cette ressource.",
|
||||||
|
"aiResourceProviderAllowModels": "Liste autorisée",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Sélectionnez des modèles",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Rechercher des modèles...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Aucun modèle trouvé",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Seuls les modèles de la liste autorisée de ce fournisseur peuvent être sélectionnés.",
|
||||||
|
"aiResourceAliasRequired": "L'alias est requis pour les portails AI",
|
||||||
|
"aiResourceDomainConfiguration": "Configuration du Domaine",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Choisissez le domaine que les clients utiliseront pour atteindre ce portail AI.",
|
||||||
|
"aiUsageAnalyticsTitle": "Analytique d'Utilisation d'IA",
|
||||||
|
"aiUsageAnalyticsDescription": "Analysez le coût, l'utilisation des jetons et l'activité du portail AI avec les fournisseurs, les ressources, les rôles et les utilisateurs",
|
||||||
|
"aiUsageTabOverview": "Vue d'ensemble",
|
||||||
|
"aiUsageTabProviders": "Fournisseurs",
|
||||||
|
"aiUsageTabResources": "Ressources",
|
||||||
|
"aiUsageFilterProvider": "Fournisseur",
|
||||||
|
"aiUsageFilterModel": "Modèle",
|
||||||
|
"aiUsageFilterResource": "Ressource",
|
||||||
|
"aiUsageFilterRole": "Rôle",
|
||||||
|
"aiUsageFilterUser": "Utilisateur",
|
||||||
|
"aiUsageFilterAllProviders": "Tous les Fournisseurs",
|
||||||
|
"aiUsageFilterAllModels": "Tous les Modèles",
|
||||||
|
"aiUsageFilterAllResources": "Toutes les Ressources",
|
||||||
|
"aiUsageFilterAllRoles": "Tous les Rôles",
|
||||||
|
"aiUsageFilterAllUsers": "Tous les Utilisateurs",
|
||||||
|
"aiUsageFilterSearch": "Rechercher...",
|
||||||
|
"aiUsageFilterNotFound": "Aucune option trouvée",
|
||||||
|
"aiUsageResetFilters": "Réinitialiser les filtres",
|
||||||
|
"aiUsageRefresh": "Actualiser",
|
||||||
|
"aiUsageTokenTypePrompt": "Invite",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Lecture du cache",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Écriture du cache",
|
||||||
|
"aiUsageTokenTypeCompletion": "Achèvement",
|
||||||
|
"aiUsageTokenTypeReasoning": "Raisonnement",
|
||||||
|
"aiUsageRequests": "Requêtes",
|
||||||
|
"aiUsageCost": "Coût",
|
||||||
|
"aiUsageTokens": "Jetons",
|
||||||
|
"aiUsageOther": "Autre",
|
||||||
|
"aiUsageTotalRequests": "Total des Requêtes",
|
||||||
|
"aiUsageTotalTokens": "Total des Jetons",
|
||||||
|
"aiUsageTotalCost": "Coût Total",
|
||||||
|
"aiUsageEstimated": "Estimé",
|
||||||
|
"aiUsageRequestVolume": "Volume de Requêtes",
|
||||||
|
"aiUsageTokenUsage": "Usage de Jeton",
|
||||||
|
"aiUsageModelCost": "Coût de Modèle",
|
||||||
|
"aiUsageModelTokens": "Jetons de Modèle",
|
||||||
|
"aiUsageTopModels": "Meilleurs Modèles",
|
||||||
|
"aiUsageTopProviders": "Meilleurs Fournisseurs",
|
||||||
|
"aiUsageProviderCost": "Coût du Fournisseur",
|
||||||
|
"aiUsageProviderTokenUsage": "Usage de Jeton du Fournisseur",
|
||||||
|
"aiUsageTopResources": "Meilleures Ressources",
|
||||||
|
"aiUsageResourceCost": "Coût des Ressources",
|
||||||
|
"aiUsageResourceTokenUsage": "Usage de Jeton des Ressources",
|
||||||
|
"aiUsageResourceTypePublic": "Ressource Publique",
|
||||||
|
"aiUsageResourceTypeSite": "Ressource Privée",
|
||||||
|
"aiUsageNoResource": "Pas de ressource",
|
||||||
|
"aiUsageRolesTab": "Rôles",
|
||||||
|
"aiUsageUsersTab": "Utilisateurs",
|
||||||
|
"aiUsageTopRoles": "Meilleurs Rôles",
|
||||||
|
"aiUsageRoleCost": "Coût du Rôle",
|
||||||
|
"aiUsageRoleTokenUsage": "Usage de Jeton du Rôle",
|
||||||
|
"aiUsageTopUsers": "Meilleurs Utilisateurs",
|
||||||
|
"aiUsageUserCost": "Coût de l'Utilisateur",
|
||||||
|
"aiUsageUserTokenUsage": "Usage de Jeton de l'Utilisateur",
|
||||||
|
"aiUsageUnknownUser": "Utilisateur Inconnu",
|
||||||
|
"aiUsageVirtualApiKeysTab": "API Clés Virtuelles",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Clé API Virtuelle",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Toutes les Clés API Virtuelles",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Meilleures Clés API Virtuelles",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Coût de la Clé API Virtuelle",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Usage de Jeton de la Clé API Virtuelle",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Pas de clé API virtuelle",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Clé sans nom",
|
||||||
|
"aiUsageLoading": "Chargement...",
|
||||||
|
"aiUsageNoData": "Pas de données",
|
||||||
|
"resourceBudgetSettings": "Budget",
|
||||||
|
"resourceBudgetSettingsDescription": "Configurez comment ce portail AI limite l'utilisation en fonction des dépenses ou des limites de jetons",
|
||||||
"sidebarApiKeys": "Clés API",
|
"sidebarApiKeys": "Clés API",
|
||||||
"sidebarProvisioning": "Mise en place",
|
"sidebarProvisioning": "Mise en place",
|
||||||
"sidebarSettings": "Réglages",
|
"sidebarSettings": "Réglages",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Règle d'alerte enregistrée",
|
"alertingRuleSaved": "Règle d'alerte enregistrée",
|
||||||
"alertingRuleSavedCreatedDescription": "Votre nouvelle règle d'alerte a été créée. Vous pouvez continuer à la modifier sur cette page.",
|
"alertingRuleSavedCreatedDescription": "Votre nouvelle règle d'alerte a été créée. Vous pouvez continuer à la modifier sur cette page.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Vos modifications apportées à cette règle d'alerte ont été enregistrées.",
|
"alertingRuleSavedUpdatedDescription": "Vos modifications apportées à cette règle d'alerte ont été enregistrées.",
|
||||||
|
"alertingTestAlertSent": "Alerte de test envoyée",
|
||||||
|
"alertingTestAlertSentDescription": "Une alerte de test a été envoyée aux actions configurées sur cette règle.",
|
||||||
"alertingEditRule": "Modifier la règle d'alerte",
|
"alertingEditRule": "Modifier la règle d'alerte",
|
||||||
"alertingCreateRule": "Créer une règle d'alerte",
|
"alertingCreateRule": "Créer une règle d'alerte",
|
||||||
"alertingRuleCredenzaDescription": "Choisissez ce qu'il faut surveiller, quand la déclencher et comment notifier",
|
"alertingRuleCredenzaDescription": "Choisissez ce qu'il faut surveiller, quand la déclencher et comment notifier",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Chaque règle associe ce qu'il faut surveiller (un site, une vérification de l'état de santé ou une ressource), quand l'exécuter (par exemple, hors ligne ou non saine), et comment notifier votre équipe par e-mail, webhooks ou intégrations. Utilisez cette liste pour créer, activer et gérer ces règles.",
|
"alertingRulesBannerDescription": "Chaque règle associe ce qu'il faut surveiller (un site, une vérification de l'état de santé ou une ressource), quand l'exécuter (par exemple, hors ligne ou non saine), et comment notifier votre équipe par e-mail, webhooks ou intégrations. Utilisez cette liste pour créer, activer et gérer ces règles.",
|
||||||
"alertingHealthChecksBannerTitle": "Surveiller la santé et les ressources",
|
"alertingHealthChecksBannerTitle": "Surveiller la santé et les ressources",
|
||||||
"alertingHealthChecksBannerDescription": "Les vérifications de l'état de santé sont des moniteurs HTTP ou TCP que vous définissez une fois. Vous pouvez ensuite les utiliser comme sources dans les règles d'alerte pour être averti lorsqu'une cible devient saine ou non saine. Les vérifications de l'état de santé sur les ressources apparaissent également ici.",
|
"alertingHealthChecksBannerDescription": "Les vérifications de l'état de santé sont des moniteurs HTTP ou TCP que vous définissez une fois. Vous pouvez ensuite les utiliser comme sources dans les règles d'alerte pour être averti lorsqu'une cible devient saine ou non saine. Les vérifications de l'état de santé sur les ressources apparaissent également ici.",
|
||||||
|
"alertingTestRule": "Règle d'alerte de test",
|
||||||
|
"alertingAddActionHeading": "Ajouter une nouvelle action",
|
||||||
|
"alertingSelectActionType": "Sélectionner une action",
|
||||||
|
"alertingNoActionsTitle": "Aucune action configurée",
|
||||||
|
"alertingNoActionsSaveDescription": "Ajoutez au moins une action pour que cette règle puisse notifier quelqu'un lorsqu'elle est déclenchée.",
|
||||||
|
"alertingNoActionsTestDescription": "Ajoutez au moins une action avant de pouvoir tester cette règle.",
|
||||||
"standaloneHcTableTitle": "Vérifications de l'état de santé",
|
"standaloneHcTableTitle": "Vérifications de l'état de santé",
|
||||||
"standaloneHcSearchPlaceholder": "Rechercher des vérifications de l'état de santé…",
|
"standaloneHcSearchPlaceholder": "Rechercher des vérifications de l'état de santé…",
|
||||||
"standaloneHcAddButton": "Créer une vérification de l'état de santé",
|
"standaloneHcAddButton": "Créer une vérification de l'état de santé",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Sous-domaine : {subdomain}",
|
"domainPickerSubdomain": "Sous-domaine : {subdomain}",
|
||||||
"domainPickerNamespace": "Espace de noms : {namespace}",
|
"domainPickerNamespace": "Espace de noms : {namespace}",
|
||||||
"domainPickerShowMore": "Afficher plus",
|
"domainPickerShowMore": "Afficher plus",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Aucun domaine disponible",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Vous n'avez pas encore configuré de domaine. Créez un domaine pour continuer.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Aller aux domaines",
|
||||||
"regionSelectorTitle": "Sélectionner Région",
|
"regionSelectorTitle": "Sélectionner Région",
|
||||||
"domainPickerRemoteExitNodeWarning": "Les domaines fournis ne sont pas pris en charge lorsque les sites se connectent à des nœuds de sortie distants. Pour que les ressources soient disponibles sur des nœuds distants, utilisez un domaine personnalisé à la place.",
|
"domainPickerRemoteExitNodeWarning": "Les domaines fournis ne sont pas pris en charge lorsque les sites se connectent à des nœuds de sortie distants. Pour que les ressources soient disponibles sur des nœuds distants, utilisez un domaine personnalisé à la place.",
|
||||||
"regionSelectorInfo": "Sélectionner une région nous aide à offrir de meilleures performances pour votre localisation. Vous n'avez pas besoin d'être dans la même région que votre serveur.",
|
"regionSelectorInfo": "Sélectionner une région nous aide à offrir de meilleures performances pour votre localisation. Vous n'avez pas besoin d'être dans la même région que votre serveur.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Sous-réseau",
|
"subnetPlaceholder": "Sous-réseau",
|
||||||
"addressDescription": "L'adresse interne du client. Doit être dans le sous-réseau de l'organisation.",
|
"addressDescription": "L'adresse interne du client. Doit être dans le sous-réseau de l'organisation.",
|
||||||
"selectSites": "Sélectionner des sites",
|
"selectSites": "Sélectionner des sites",
|
||||||
|
"selectResources": "Sélectionner des ressources",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# ressource} other {# ressources}}",
|
||||||
"selectLabels": "Sélectionner des étiquettes",
|
"selectLabels": "Sélectionner des étiquettes",
|
||||||
"sitesDescription": "Le client aura une connectivité vers les sites sélectionnés",
|
"sitesDescription": "Le client aura une connectivité vers les sites sélectionnés",
|
||||||
"clientInstallOlm": "Installer Olm",
|
"clientInstallOlm": "Installer Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Le temps est exprimé en secondes",
|
"timeIsInSeconds": "Le temps est exprimé en secondes",
|
||||||
"requireDeviceApproval": "Exiger les autorisations de l'appareil",
|
"requireDeviceApproval": "Exiger les autorisations de l'appareil",
|
||||||
"requireDeviceApprovalDescription": "Les utilisateurs ayant ce rôle ont besoin de nouveaux périphériques approuvés par un administrateur avant de pouvoir se connecter et accéder aux ressources.",
|
"requireDeviceApprovalDescription": "Les utilisateurs ayant ce rôle ont besoin de nouveaux périphériques approuvés par un administrateur avant de pouvoir se connecter et accéder aux ressources.",
|
||||||
"sshSettings": "Paramètres SSH",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "Portail AI",
|
||||||
"sshAccess": "Accès SSH",
|
"sshAccess": "Accès SSH",
|
||||||
"rdpSettings": "Paramètres RDP",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "Paramètres VNC",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "Serveur SSH",
|
"sshServer": "Serveur SSH",
|
||||||
"rdpServer": "Serveur RDP",
|
"rdpServer": "Serveur RDP",
|
||||||
"vncServer": "Serveur VNC",
|
"vncServer": "Serveur VNC",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Publique",
|
"resourcesTableProxyResources": "Publique",
|
||||||
"resourcesTableClientResources": "Privé",
|
"resourcesTableClientResources": "Privé",
|
||||||
"resourcesTableNoProxyResourcesFound": "Aucune ressource proxy trouvée.",
|
"resourcesTableNoProxyResourcesFound": "Aucune ressource proxy trouvée.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Aucune ressource interne trouvée.",
|
"resourcesTableNoInternalResourcesFound": "Aucune ressource privée trouvée.",
|
||||||
"resourcesTableDestination": "Destination",
|
"resourcesTableDestination": "Destination",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Adresse de l'alias",
|
"resourcesTableAliasAddress": "Adresse de l'alias",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Abandonner",
|
"editInternalResourceDialogCancel": "Abandonner",
|
||||||
"editInternalResourceDialogSaveResource": "Enregistrer la ressource",
|
"editInternalResourceDialogSaveResource": "Enregistrer la ressource",
|
||||||
"editInternalResourceDialogSuccess": "Succès",
|
"editInternalResourceDialogSuccess": "Succès",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Ressource interne mise à jour avec succès",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Ressource privée mise à jour avec succès",
|
||||||
"editInternalResourceDialogError": "Erreur",
|
"editInternalResourceDialogError": "Erreur",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Échec de la mise à jour de la ressource interne",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Échec de la mise à jour de la ressource privée",
|
||||||
"editInternalResourceDialogNameRequired": "Le nom est requis",
|
"editInternalResourceDialogNameRequired": "Le nom est requis",
|
||||||
"editInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
|
"editInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
|
||||||
"editInternalResourceDialogProxyPortMin": "Le port proxy doit être d'au moins 1",
|
"editInternalResourceDialogProxyPortMin": "Le port proxy doit être d'au moins 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "Portail AI",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Méthode HTTP",
|
"editInternalResourceDialogScheme": "Méthode HTTP",
|
||||||
"editInternalResourceDialogEnableSsl": "Activer TLS",
|
"editInternalResourceDialogEnableSsl": "Activer TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Un alias DNS interne optionnel pour cette ressource.",
|
"editInternalResourceDialogAliasDescription": "Un alias DNS interne optionnel pour cette ressource.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Aucun site disponible",
|
"createInternalResourceDialogNoSitesAvailable": "Aucun site disponible",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Vous devez avoir au moins un site Newt avec un sous-réseau configuré pour créer des ressources internes.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Vous devez avoir au moins un site Newt avec un sous-réseau configuré pour créer des ressources privées.",
|
||||||
"createInternalResourceDialogClose": "Fermer",
|
"createInternalResourceDialogClose": "Fermer",
|
||||||
"createInternalResourceDialogCreateClientResource": "Créer une ressource privée",
|
"createInternalResourceDialogCreateClientResource": "Créer une ressource privée",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Créer une nouvelle ressource qui ne sera accessible qu'aux clients connectés à l'organisation",
|
"createInternalResourceDialogCreateClientResourceDescription": "Créer une nouvelle ressource qui ne sera accessible qu'aux clients connectés à l'organisation",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Autoriser le ping ICMP",
|
"privateResourceAllowIcmpPing": "Autoriser le ping ICMP",
|
||||||
"privateResourceNetworkAccess": "Accès au réseau",
|
"privateResourceNetworkAccess": "Accès au réseau",
|
||||||
"privateResourceNetworkAccessDescription": "Contrôler l'accès aux ports TCP/UDP et si le ping ICMP est autorisé pour cette ressource.",
|
"privateResourceNetworkAccessDescription": "Contrôler l'accès aux ports TCP/UDP et si le ping ICMP est autorisé pour cette ressource.",
|
||||||
"hostSettings": "Paramètres de l'hôte",
|
"hostSettings": "Hôte",
|
||||||
"cidrSettings": "Paramètres CIDR",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Propriétés de la ressource",
|
"createInternalResourceDialogResourceProperties": "Propriétés de la ressource",
|
||||||
"createInternalResourceDialogName": "Nom",
|
"createInternalResourceDialogName": "Nom",
|
||||||
"createInternalResourceDialogSite": "Site",
|
"createInternalResourceDialogSite": "Site",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Abandonner",
|
"createInternalResourceDialogCancel": "Abandonner",
|
||||||
"createInternalResourceDialogCreateResource": "Créer une ressource",
|
"createInternalResourceDialogCreateResource": "Créer une ressource",
|
||||||
"createInternalResourceDialogSuccess": "Succès",
|
"createInternalResourceDialogSuccess": "Succès",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Ressource interne créée avec succès",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Ressource privée créée avec succès",
|
||||||
"createInternalResourceDialogError": "Erreur",
|
"createInternalResourceDialogError": "Erreur",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Échec de la création de la ressource interne",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Échec de la création de la ressource privée",
|
||||||
"createInternalResourceDialogNameRequired": "Le nom est requis",
|
"createInternalResourceDialogNameRequired": "Le nom est requis",
|
||||||
"createInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
|
"createInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Veuillez sélectionner un site",
|
"createInternalResourceDialogPleaseSelectSite": "Veuillez sélectionner un site",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "Portail AI",
|
||||||
"scheme": "Méthode HTTP",
|
"scheme": "Méthode HTTP",
|
||||||
"createInternalResourceDialogScheme": "Méthode HTTP",
|
"createInternalResourceDialogScheme": "Méthode HTTP",
|
||||||
"createInternalResourceDialogEnableSsl": "Activer TLS",
|
"createInternalResourceDialogEnableSsl": "Activer TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Mot de passe valide",
|
"validPassword": "Mot de passe valide",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Clé API Virtuelle Valide",
|
||||||
"view": "Afficher",
|
"view": "Afficher",
|
||||||
"configManaged": "Configuration gérée",
|
"configManaged": "Configuration gérée",
|
||||||
"connectedClient": "Client connecté",
|
"connectedClient": "Client connecté",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Journaliser la rétention",
|
"logRetention": "Journaliser la rétention",
|
||||||
"logRetentionDescription": "Gérer la durée de conservation des différents types de logs pour cette organisation ou les désactiver",
|
"logRetentionDescription": "Gérer la durée de conservation des différents types de logs pour cette organisation ou les désactiver",
|
||||||
"requestLogsDescription": "Voir les journaux détaillés des requêtes pour les ressources de cette organisation",
|
"requestLogsDescription": "Voir les journaux détaillés des requêtes pour les ressources de cette organisation",
|
||||||
|
"aiSessionLogs": "Journaux de Session du Portail AI",
|
||||||
|
"aiSessionLogsDescription": "Voir les transcriptions de l'invite et de la réponse pour les requêtes de portail AI dans cette organisation",
|
||||||
|
"sidebarLogsAi": "Journaux de Session",
|
||||||
|
"commandLogsAi": "Journaux de Session",
|
||||||
|
"sidebarLogsAiUsage": "Analytique d'Utilisation",
|
||||||
|
"commandLogsAiUsage": "Analytique d'Utilisation",
|
||||||
|
"provider": "Fournisseur",
|
||||||
|
"capability": "Capacité",
|
||||||
|
"model": "Modèle",
|
||||||
|
"virtualApiKey": "Clé API Virtuelle",
|
||||||
|
"noVirtualApiKey": "Pas de clé API virtuelle",
|
||||||
|
"stream": "Flux",
|
||||||
|
"streaming": "En Flux",
|
||||||
|
"nonStreaming": "Non-Flux",
|
||||||
|
"statusCode": "Code d'État",
|
||||||
|
"aiSessionId": "ID de Session",
|
||||||
|
"aiSessionRequest": "Requête",
|
||||||
|
"aiSessionResponse": "Réponse",
|
||||||
|
"aiSessionNoData": "Aucune donnée capturée",
|
||||||
|
"aiSessionCouldNotParse": "(brut, n'a pas pu analyser la transcription)",
|
||||||
|
"aiSessionLogTruncated": "Cette session a été tronquée avant le stockage et peut être incomplète.",
|
||||||
|
"aiSessionViewRaw": "Afficher le JSON Brut",
|
||||||
|
"aiSessionViewChat": "Afficher la Discussion",
|
||||||
|
"cost": "Coût",
|
||||||
|
"estimated": "Estimé",
|
||||||
|
"tokenUsage": "Usage de Jeton",
|
||||||
|
"promptTokens": "Jetons Prompt",
|
||||||
|
"cacheReadTokens": "Jetons Lecture Cache",
|
||||||
|
"cacheWriteTokens": "Jetons Écriture Cache",
|
||||||
|
"completionTokens": "Jetons Completion",
|
||||||
|
"reasoningTokens": "Jetons Raisonnement",
|
||||||
|
"totalTokens": "Total des Jetons",
|
||||||
"requestAnalyticsDescription": "Voir les analyses détaillées des demandes pour les ressources de cette organisation",
|
"requestAnalyticsDescription": "Voir les analyses détaillées des demandes pour les ressources de cette organisation",
|
||||||
"logRetentionRequestLabel": "Rétention des Journaux de Requêtes HTTP",
|
"logRetentionRequestLabel": "Rétention des Journaux de Requêtes HTTP",
|
||||||
"logRetentionRequestDescription": "Durée de conservation des journaux de requêtes",
|
"logRetentionRequestDescription": "Durée de conservation des journaux de requêtes",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Durée de conservation du journal des actions",
|
"logRetentionActionDescription": "Durée de conservation du journal des actions",
|
||||||
"logRetentionConnectionLabel": "Rétention du journal de connexion",
|
"logRetentionConnectionLabel": "Rétention du journal de connexion",
|
||||||
"logRetentionConnectionDescription": "Durée de conservation des logs de connexion",
|
"logRetentionConnectionDescription": "Durée de conservation des logs de connexion",
|
||||||
|
"logRetentionAISessionsLabel": "Rétention des Journaux des Sessions du Portail AI",
|
||||||
|
"logRetentionAISessionsDescription": "Combien de temps conserver les journaux des sessions d'invite/réponse du portail AI",
|
||||||
"logRetentionDisabled": "Désactivé",
|
"logRetentionDisabled": "Désactivé",
|
||||||
"logRetention3Days": "3 jours",
|
"logRetention3Days": "3 jours",
|
||||||
"logRetention7Days": "7 jours",
|
"logRetention7Days": "7 jours",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Adresse source",
|
"sourceAddress": "Adresse source",
|
||||||
"destinationAddress": "Adresse de destination",
|
"destinationAddress": "Adresse de destination",
|
||||||
"duration": "Durée",
|
"duration": "Durée",
|
||||||
"licenseRequiredToUse": "Une <enterpriseLicenseLink>licence Enterprise Edition</enterpriseLicenseLink> ou <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> est requise pour utiliser cette fonctionnalité. <bookADemoLink>Réservez une démonstration ou une évaluation de POC</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Licence Enterprise Edition</enterpriseEditionLink> requise. <bookADemoLink>Réserver une démo ou un essai</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "La version <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> est requise pour utiliser cette fonctionnalité. Cette fonctionnalité est également disponible dans <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Réservez une démo ou un essai POC</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Licence Enterprise Edition</enterpriseEditionLink> requise. <bookADemoLink>Réserver une démo ou un essai</bookADemoLink>",
|
||||||
"certResolver": "Résolveur de certificat",
|
"certResolver": "Résolveur de certificat",
|
||||||
"certResolverDescription": "Sélectionnez le solveur de certificat à utiliser pour cette ressource.",
|
"certResolverDescription": "Sélectionnez le solveur de certificat à utiliser pour cette ressource.",
|
||||||
"selectCertResolver": "Sélectionnez le résolveur de certificat",
|
"selectCertResolver": "Sélectionnez le résolveur de certificat",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "La sélection de plusieurs sites permet un routage résilient et un basculement pour une haute disponibilité.",
|
"internalResourceFormMultiSiteRoutingHelp": "La sélection de plusieurs sites permet un routage résilient et un basculement pour une haute disponibilité.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "En savoir plus",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "En savoir plus",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Restreindre l'accès à des ports TCP/UDP spécifiques ou autoriser/bloquer tous les ports.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Restreindre l'accès à des ports TCP/UDP spécifiques ou autoriser/bloquer tous les ports.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "Configuration HTTP",
|
"createInternalResourceDialogHttpConfiguration": "Configuration du Domaine",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Choisissez le domaine que les clients utiliseront pour atteindre cette ressource via HTTP ou HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Choisissez le domaine que les clients utiliseront pour atteindre cette ressource via HTTP ou HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "Configuration HTTP",
|
"editInternalResourceDialogHttpConfiguration": "Configuration du Domaine",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Choisissez le domaine que les clients utiliseront pour atteindre cette ressource via HTTP ou HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Choisissez le domaine que les clients utiliseront pour atteindre cette ressource via HTTP ou HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Non étiqueté",
|
"resourceLauncherUnlabeled": "Non étiqueté",
|
||||||
|
"resourceLauncherAiGateway": "Portail AI",
|
||||||
"resourceLauncherNoSite": "Aucun nœud",
|
"resourceLauncherNoSite": "Aucun nœud",
|
||||||
|
"resourceLauncherAvailableModels": "Modèles Disponibles",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modèles que vous pouvez utiliser avec ce portail AI.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Aucun modèle n'est disponible pour cette ressource.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Impossible de charger les modèles disponibles.",
|
||||||
|
"resourceLauncherApiKeys": "Clés API",
|
||||||
|
"resourceLauncherApiKeysDescription": "Utilisez votre clé d'identité ou une clé attribuée pour vous authentifier avec cette ressource.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Clé d'identité",
|
||||||
|
"resourceLauncherApiKeysManual": "Clés Attribuées",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Pas de clés API disponibles pour cette ressource.",
|
||||||
|
"resourceLauncherApiKeysError": "Impossible de charger les clés API.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Aucune ressource dans ce groupe",
|
"resourceLauncherNoResourcesInGroup": "Aucune ressource dans ce groupe",
|
||||||
"resourceLauncherEmptyStateTitle": "Aucune ressource disponible",
|
"resourceLauncherEmptyStateTitle": "Aucune ressource disponible",
|
||||||
"resourceLauncherEmptyStateDescription": "Vous n'avez pas encore accès à des ressources. Contactez votre administrateur pour demander l'accès.",
|
"resourceLauncherEmptyStateDescription": "Vous n'avez pas encore accès à des ressources. Contactez votre administrateur pour demander l'accès.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Impossible de supprimer la vue de lancement. Veuillez réessayer.",
|
"resourceLauncherViewDeleteFailedDescription": "Impossible de supprimer la vue de lancement. Veuillez réessayer.",
|
||||||
"memberPortalPrevious": "Précédent",
|
"memberPortalPrevious": "Précédent",
|
||||||
"memberPortalNext": "Suivant",
|
"memberPortalNext": "Suivant",
|
||||||
"httpSettings": "Paramètres HTTP",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "Paramètres TCP",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "Paramètres UDP",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Établissement d'une connexion sécurisée…",
|
"sshConnectingDescription": "Établissement d'une connexion sécurisée…",
|
||||||
"sshConnecting": "Connexion…",
|
"sshConnecting": "Connexion…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Échec du téléchargement",
|
"rdpUploadFailed": "Échec du téléchargement",
|
||||||
"rdpUnicodeKeyboardMode": "Mode clavier Unicode",
|
"rdpUnicodeKeyboardMode": "Mode clavier Unicode",
|
||||||
"sessionToolbarShow": "Afficher la barre d'outils",
|
"sessionToolbarShow": "Afficher la barre d'outils",
|
||||||
"sessionToolbarHide": "Masquer la barre d'outils"
|
"sessionToolbarHide": "Masquer la barre d'outils",
|
||||||
|
"actionUpdateSiteApprovals": "Mettre à jour les approbations de site"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Assicurati di aver effettuato l'accesso come utente corretto.",
|
"inviteLoginUser": "Assicurati di aver effettuato l'accesso come utente corretto.",
|
||||||
"inviteErrorNoUser": "Siamo spiacenti, ma sembra che l'invito che stai cercando di accedere non sia per un utente che esiste.",
|
"inviteErrorNoUser": "Siamo spiacenti, ma sembra che l'invito che stai cercando di accedere non sia per un utente che esiste.",
|
||||||
"inviteCreateUser": "Si prega di creare un account prima.",
|
"inviteCreateUser": "Si prega di creare un account prima.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Gli inviti possono essere accettati solo da account interni. Esci e accedi con la tua password per questa email.",
|
||||||
|
"inviteLoginInternalOnly": "Gli inviti richiedono un account interno con una password. Crea un account o accedi con la tua password.",
|
||||||
"goHome": "Vai alla Home",
|
"goHome": "Vai alla Home",
|
||||||
"inviteLogInOtherUser": "Accedi come utente diverso",
|
"inviteLogInOtherUser": "Accedi come utente diverso",
|
||||||
"createAnAccount": "Crea un account",
|
"createAnAccount": "Crea un account",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Conferma Eliminazione Collegamento Condivisibile",
|
"shareDeleteConfirm": "Conferma Eliminazione Collegamento Condivisibile",
|
||||||
"shareQuestionRemove": "Sei sicuro di voler eliminare questo link di condivisione?",
|
"shareQuestionRemove": "Sei sicuro di voler eliminare questo link di condivisione?",
|
||||||
"shareMessageRemove": "Una volta eliminato, il link non funzionerà più e chiunque lo utilizzi perderà l'accesso alla risorsa.",
|
"shareMessageRemove": "Una volta eliminato, il link non funzionerà più e chiunque lo utilizzi perderà l'accesso alla risorsa.",
|
||||||
"shareTokenDescription": "Il token di accesso può essere passato in due modi: come parametro di interrogazione o nelle intestazioni della richiesta. Questi devono essere passati dal client su ogni richiesta di accesso autenticato.",
|
"shareTokenDescription": "Il token di accesso può essere passato come parametro di query o nei header delle richieste. Per impostazione predefinita deve essere inviato a ogni richiesta. Se la persistenza della sessione è abilitata, la prima richiesta lo scambia per un cookie di sessione.",
|
||||||
"accessToken": "Token Di Accesso",
|
"accessToken": "Token Di Accesso",
|
||||||
"usageExamples": "Esempi Di Utilizzo",
|
"usageExamples": "Esempi Di Utilizzo",
|
||||||
"tokenId": "ID del Token",
|
"tokenId": "ID del Token",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Titolo (facoltativo)",
|
"shareTitleOptional": "Titolo (facoltativo)",
|
||||||
"sharePathOptional": "Percorso (opzionale)",
|
"sharePathOptional": "Percorso (opzionale)",
|
||||||
"sharePathDescription": "Il link reindirizzerà gli utenti a questo percorso dopo l'autenticazione.",
|
"sharePathDescription": "Il link reindirizzerà gli utenti a questo percorso dopo l'autenticazione.",
|
||||||
|
"shareAssociateUserOptional": "Associa utente (opzionale)",
|
||||||
|
"shareAssociateUserDescription": "Quando impostato, le richieste utilizzando questo link sono attribuite all'utente nei log di accesso e negli header di identità. Il link viene rimosso se l'utente lascia l'organizzazione.",
|
||||||
|
"userSelect": "Seleziona utente",
|
||||||
|
"usersNotFound": "Nessun utente trovato",
|
||||||
"expireIn": "Scadenza In",
|
"expireIn": "Scadenza In",
|
||||||
"neverExpire": "Nessuna scadenza",
|
"neverExpire": "Nessuna scadenza",
|
||||||
|
"sharePersistSession": "Mantieni la sessione dopo il primo utilizzo",
|
||||||
|
"sharePersistSessionDescription": "Quando abilitato, la prima richiesta con questo token tramite un parametro di query o header imposta un cookie di sessione quindi le richieste successive non hanno bisogno del token. Disattivare per i client API che devono inviare il token a ogni richiesta.",
|
||||||
"shareExpireDescription": "Il tempo di scadenza indica per quanto tempo il link sarà utilizzabile e fornirà accesso alla risorsa. Dopo questo tempo, il link non funzionerà più e gli utenti che hanno utilizzato questo link perderanno l'accesso alla risorsa.",
|
"shareExpireDescription": "Il tempo di scadenza indica per quanto tempo il link sarà utilizzabile e fornirà accesso alla risorsa. Dopo questo tempo, il link non funzionerà più e gli utenti che hanno utilizzato questo link perderanno l'accesso alla risorsa.",
|
||||||
"shareSeeOnce": "Potrai vedere questo link solo una volta. Assicurati di copiarlo.",
|
"shareSeeOnce": "Potrai vedere questo link solo una volta. Assicurati di copiarlo.",
|
||||||
"shareAccessHint": "Chiunque abbia questo link può accedere alla risorsa. Condividilo con cura.",
|
"shareAccessHint": "Chiunque abbia questo link può accedere alla risorsa. Condividilo con cura.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Nessun paese trovato.",
|
"noCountryFound": "Nessun paese trovato.",
|
||||||
"siteSelectionDescription": "Questo sito fornirà connettività all'oggetto target.",
|
"siteSelectionDescription": "Questo sito fornirà connettività all'oggetto target.",
|
||||||
"resourceType": "Tipo Di Risorsa",
|
"resourceType": "Tipo Di Risorsa",
|
||||||
"resourceTypeDescription": "Questo controlla il protocollo delle risorse e come verrà reso nel browser. Questo non può essere modificato in seguito.",
|
"resourceTypeDescription": "Questo controlla il protocollo della risorsa e non può essere cambiato in seguito.",
|
||||||
|
"resourceTypeSearch": "Cerca tipi di risorse...",
|
||||||
|
"resourceTypeNotFound": "Nessun tipo di risorsa trovato",
|
||||||
|
"resourceTypeHttpDescription": "Proxy del traffico web su HTTPS usando un nome di dominio",
|
||||||
|
"resourceTypeInferenceDescription": "Instrada le richieste AI tramite i provider allegati",
|
||||||
|
"resourceTypeSshDescription": "Accedi a un server SSH dal browser",
|
||||||
|
"resourceTypeRdpDescription": "Accedi a un desktop remoto dal browser",
|
||||||
|
"resourceTypeVncDescription": "Accedi a un desktop VNC dal browser",
|
||||||
|
"resourceTypeTcpDescription": "Proxy del traffico TCP grezzo utilizzando un numero di porta",
|
||||||
|
"resourceTypeUdpDescription": "Proxy del traffico UDP grezzo utilizzando un numero di porta",
|
||||||
|
"privateResourceTypeDescription": "Questo controlla come i client raggiungono la risorsa. Non può essere modificato in seguito.",
|
||||||
|
"privateResourceTypeHostDescription": "Espone un singolo host sulla rete del sito ai client connessi",
|
||||||
|
"privateResourceTypeCidrDescription": "Espone un intervallo CIDR sulla rete del sito ai client connessi",
|
||||||
|
"privateResourceTypeHttpDescription": "Accedi a un servizio HTTP o HTTPS tramite un dominio",
|
||||||
|
"privateResourceTypeSshDescription": "Accedi a un server SSH dai client connessi",
|
||||||
"resourceDomainDescription": "La risorsa sarà servita su questo dominio completamente qualificato.",
|
"resourceDomainDescription": "La risorsa sarà servita su questo dominio completamente qualificato.",
|
||||||
"resourceHTTPSSettings": "Impostazioni HTTPS",
|
"resourceHTTPSSettings": "Impostazioni HTTPS",
|
||||||
"resourceHTTPSSettingsDescription": "Configura come sarà possibile accedere alla risorsa su HTTPS",
|
"resourceHTTPSSettingsDescription": "Configura come sarà possibile accedere alla risorsa su HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Accantonamento",
|
"provisioningManage": "Accantonamento",
|
||||||
"provisioningDescription": "Gestire le chiavi di provisioning e rivedere i siti in attesa di approvazione.",
|
"provisioningDescription": "Gestire le chiavi di provisioning e rivedere i siti in attesa di approvazione.",
|
||||||
"pendingSites": "Siti In Attesa",
|
"pendingSites": "Siti In Attesa",
|
||||||
"siteApproveSuccess": "Sito approvato con successo",
|
"siteApproveSuccess": "Sito e risorse associate approvate con successo",
|
||||||
"siteApproveError": "Errore nell'approvazione del sito",
|
"siteApproveError": "Errore nell'approvazione del sito",
|
||||||
|
"siteReject": "Rifiuta Sito",
|
||||||
|
"siteQuestionReject": "Sei sicuro di voler rifiutare questo sito?",
|
||||||
|
"siteMessageReject": "Questo eliminerà permanentemente il sito e tutte le risorse associate ancora in sospeso.",
|
||||||
|
"siteConfirmReject": "Conferma Rifiuto Sito",
|
||||||
|
"siteRejectSuccess": "Sito rifiutato con successo",
|
||||||
|
"siteRejectError": "Errore nel rifiutare il sito",
|
||||||
"provisioningKeys": "Chiavi Di Provvedimento",
|
"provisioningKeys": "Chiavi Di Provvedimento",
|
||||||
"searchProvisioningKeys": "Cerca le chiavi di provisioning...",
|
"searchProvisioningKeys": "Cerca le chiavi di provisioning...",
|
||||||
"provisioningKeysAdd": "Genera Chiave di provisioning",
|
"provisioningKeysAdd": "Genera Chiave di provisioning",
|
||||||
@@ -466,12 +494,12 @@
|
|||||||
"provisioningKeysSave": "Salva la chiave di provisioning",
|
"provisioningKeysSave": "Salva la chiave di provisioning",
|
||||||
"provisioningKeysSaveDescription": "Sarai in grado di vedere solo una volta. Copiarlo in un posto sicuro.",
|
"provisioningKeysSaveDescription": "Sarai in grado di vedere solo una volta. Copiarlo in un posto sicuro.",
|
||||||
"provisioningKeysErrorCreate": "Errore nella creazione della chiave di provisioning",
|
"provisioningKeysErrorCreate": "Errore nella creazione della chiave di provisioning",
|
||||||
"provisioningKeysList": "Nuova chiave di provisioning",
|
"provisioningKeysList": "Nuova Chiave di Provisioning",
|
||||||
"provisioningKeysMaxBatchSize": "Dimensione massima batch",
|
"provisioningKeysMaxBatchSize": "Dimensione Massima Batch",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Dimensione illimitata del batch (nessun limite)",
|
"provisioningKeysUnlimitedBatchSize": "Dimensione illimitata del batch (nessun limite)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Illimitato",
|
"provisioningKeysMaxBatchUnlimited": "Illimitato",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Inserisci una dimensione massima valida del batch (1–1.000.000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Inserisci una dimensione massima valida del batch (1–1.000.000).",
|
||||||
"provisioningKeysValidUntil": "Valido fino al",
|
"provisioningKeysValidUntil": "Valido Fino a",
|
||||||
"provisioningKeysValidUntilHint": "Lasciare vuoto per nessuna scadenza.",
|
"provisioningKeysValidUntilHint": "Lasciare vuoto per nessuna scadenza.",
|
||||||
"provisioningKeysValidUntilInvalid": "Inserisci una data e ora valide.",
|
"provisioningKeysValidUntilInvalid": "Inserisci una data e ora valide.",
|
||||||
"provisioningKeysNumUsed": "Volte usate",
|
"provisioningKeysNumUsed": "Volte usate",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "Mai",
|
"provisioningKeysNeverUsed": "Mai",
|
||||||
"provisioningKeysEdit": "Modifica Chiave di provisioning",
|
"provisioningKeysEdit": "Modifica Chiave di provisioning",
|
||||||
"provisioningKeysEditDescription": "Aggiorna la dimensione massima del batch e il tempo di scadenza per questa chiave.",
|
"provisioningKeysEditDescription": "Aggiorna la dimensione massima del batch e il tempo di scadenza per questa chiave.",
|
||||||
"provisioningKeysApproveNewSites": "Approva nuovi siti",
|
"provisioningKeysApproveNewSites": "Approva Nuovi Siti",
|
||||||
"provisioningKeysApproveNewSitesDescription": "Approvare automaticamente i siti che si registrano con questa chiave.",
|
"provisioningKeysApproveNewSitesDescription": "Approvare automaticamente i siti che si registrano con questa chiave.",
|
||||||
"provisioningKeysUpdateError": "Errore nell'aggiornamento della chiave di provisioning",
|
"provisioningKeysUpdateError": "Errore nell'aggiornamento della chiave di provisioning",
|
||||||
"provisioningKeysUpdated": "Chiave di provisioning aggiornata",
|
"provisioningKeysUpdated": "Chiave di provisioning aggiornata",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Salva Impostazioni",
|
"authMethodsSave": "Salva Impostazioni",
|
||||||
"policyAuthStackTitle": "Autenticazione",
|
"policyAuthStackTitle": "Autenticazione",
|
||||||
"policyAuthStackDescription": "Controlla quali metodi di autenticazione sono richiesti per accedere a questa risorsa",
|
"policyAuthStackDescription": "Controlla quali metodi di autenticazione sono richiesti per accedere a questa risorsa",
|
||||||
|
"policyAuthInferenceStackDescription": "Scegli quali utenti e ruoli possono autenticarsi a questo gateway AI",
|
||||||
"policyAuthOrLogicTitle": "Più metodi di autenticazione attivi",
|
"policyAuthOrLogicTitle": "Più metodi di autenticazione attivi",
|
||||||
"policyAuthOrLogicBanner": "I visitatori possono autenticarsi utilizzando uno qualsiasi dei metodi attivi sottostanti. Non è necessario completarli tutti.",
|
"policyAuthOrLogicBanner": "I visitatori possono autenticarsi utilizzando uno qualsiasi dei metodi attivi sottostanti. Non è necessario completarli tutti.",
|
||||||
"policyAuthMethodActive": "Attivo",
|
"policyAuthMethodActive": "Attivo",
|
||||||
"policyAuthMethodOff": "Disattivo",
|
"policyAuthMethodOff": "Disattivo",
|
||||||
"policyAuthSsoTitle": "SSO della Piattaforma",
|
"policyAuthSsoTitle": "SSO della Piattaforma",
|
||||||
"policyAuthSsoDescription": "Richiedi l'accesso tramite il provider di identità della tua organizzazione",
|
"policyAuthSsoDescription": "Richiedi l'accesso tramite il provider di identità della tua organizzazione",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "URL di accesso",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Ogni utente ha già una chiave API di identità, quindi devi solo creare chiavi API virtuali per i client non utente o per l'accesso condiviso. Gli utenti possono recuperare la loro chiave accedendo con il loro provider di identità all'URL di questa risorsa, dove verrà mostrata dopo il login.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Ogni utente ha già una chiave API di identità, quindi devi solo creare chiavi API virtuali per i client non utente o per l'accesso condiviso. Gli utenti recuperano la loro chiave qui dopo aver effettuato l'accesso con il loro provider di identità.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} utenti, {roles} ruoli",
|
"policyAuthSsoSummary": "{idp} · {users} utenti, {roles} ruoli",
|
||||||
"policyAuthSsoDefaultIdp": "Provider predefinito",
|
"policyAuthSsoDefaultIdp": "Provider predefinito",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Aggiungi Provider di Identità Predefinito",
|
"policyAuthAddDefaultIdentityProvider": "Aggiungi Provider di Identità Predefinito",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Versione",
|
"newtVersion": "Versione",
|
||||||
"architecture": "Architettura",
|
"architecture": "Architettura",
|
||||||
"sites": "Siti",
|
"sites": "Siti",
|
||||||
"siteWgAnyClients": "Usa qualsiasi client WireGuard per connetterti. Dovrai indirizzare le risorse interne utilizzando l'IP del peer.",
|
"siteWgAnyClients": "Usa qualsiasi client WireGuard per connetterti. Dovrai indirizzare le risorse private utilizzando l'IP del peer.",
|
||||||
"siteWgCompatibleAllClients": "Compatibile con tutti i client WireGuard",
|
"siteWgCompatibleAllClients": "Compatibile con tutti i client WireGuard",
|
||||||
"siteWgManualConfigurationRequired": "Configurazione manuale richiesta",
|
"siteWgManualConfigurationRequired": "Configurazione manuale richiesta",
|
||||||
"userErrorNotAdminOrOwner": "L'utente non è un amministratore o proprietario",
|
"userErrorNotAdminOrOwner": "L'utente non è un amministratore o proprietario",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Nuovo ruolo richiesto",
|
"accessRoleErrorNewRequired": "Nuovo ruolo richiesto",
|
||||||
"accessRoleErrorRemove": "Impossibile rimuovere il ruolo",
|
"accessRoleErrorRemove": "Impossibile rimuovere il ruolo",
|
||||||
"accessRoleErrorRemoveDescription": "Si è verificato un errore durante la rimozione del ruolo.",
|
"accessRoleErrorRemoveDescription": "Si è verificato un errore durante la rimozione del ruolo.",
|
||||||
|
"accessRoleInferenceBudget": "Budget AI",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Configura come i membri di questo ruolo limitano l'uso dell'AI in base alla spesa o ai limiti di token",
|
||||||
"accessRoleName": "Nome Del Ruolo",
|
"accessRoleName": "Nome Del Ruolo",
|
||||||
"accessRoleQuestionRemove": "Stai per eliminare il ruolo `{name}`. Non puoi annullare questa azione.",
|
"accessRoleQuestionRemove": "Stai per eliminare il ruolo `{name}`. Non puoi annullare questa azione.",
|
||||||
"accessRoleRemove": "Rimuovi Ruolo",
|
"accessRoleRemove": "Rimuovi Ruolo",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Crea Utente Org",
|
"createOrgUser": "Crea Utente Org",
|
||||||
"actionUpdateOrg": "Aggiorna Organizzazione",
|
"actionUpdateOrg": "Aggiorna Organizzazione",
|
||||||
"actionRemoveInvitation": "Rimuovi Invito",
|
"actionRemoveInvitation": "Rimuovi Invito",
|
||||||
|
"actionRemoveUserRole": "Rimuovi Ruolo Utente",
|
||||||
"actionUpdateUser": "Aggiorna Utente",
|
"actionUpdateUser": "Aggiorna Utente",
|
||||||
"actionGetUser": "Ottieni Utente",
|
"actionGetUser": "Ottieni Utente",
|
||||||
"actionGetOrgUser": "Ottieni Utente Organizzazione",
|
"actionGetOrgUser": "Ottieni Utente Organizzazione",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Elimina Sito",
|
"actionDeleteSite": "Elimina Sito",
|
||||||
"actionGetSite": "Ottieni Sito",
|
"actionGetSite": "Ottieni Sito",
|
||||||
"actionListSites": "Elenca Siti",
|
"actionListSites": "Elenca Siti",
|
||||||
|
"actionCreateAiProvider": "Crea Provider AI",
|
||||||
|
"actionDeleteAiProvider": "Elimina Provider AI",
|
||||||
|
"actionGetAiProvider": "Ottieni Provider AI",
|
||||||
|
"actionListAiProviders": "Elenca Provider AI",
|
||||||
|
"actionUpdateAiProvider": "Aggiorna Provider AI",
|
||||||
|
"actionCreateAiModel": "Crea Modello AI",
|
||||||
|
"actionDeleteAiModel": "Elimina Modello AI",
|
||||||
|
"actionGetAiModel": "Ottieni Modello AI",
|
||||||
|
"actionListAiModels": "Elenca Modelli AI",
|
||||||
|
"actionUpdateAiModel": "Aggiorna Modello AI",
|
||||||
|
"actionCreateAiBudget": "Crea Budget AI",
|
||||||
|
"actionDeleteAiBudget": "Elimina Budget AI",
|
||||||
|
"actionGetAiBudget": "Ottieni Budget AI",
|
||||||
|
"actionListAiBudgets": "Elenca Budget AI",
|
||||||
|
"actionUpdateAiBudget": "Aggiorna Budget AI",
|
||||||
|
"actionListResourceAiModels": "Elenca Modelli AI Risorsa",
|
||||||
|
"actionSetResourceAiModels": "Imposta Modelli AI Risorsa",
|
||||||
|
"actionCreateVirtualApiKey": "Crea Chiave API Virtuale",
|
||||||
|
"actionDeleteVirtualApiKey": "Elimina Chiave API Virtuale",
|
||||||
|
"actionGetVirtualApiKey": "Ottieni Chiave API Virtuale",
|
||||||
|
"actionListVirtualApiKeys": "Elenca Chiavi API Virtuali",
|
||||||
|
"actionUpdateVirtualApiKey": "Aggiorna Chiave API Virtuale",
|
||||||
"actionApplyBlueprint": "Applica Progetto",
|
"actionApplyBlueprint": "Applica Progetto",
|
||||||
"actionListBlueprints": "Elenco Blueprints",
|
"actionListBlueprints": "Elenco Blueprints",
|
||||||
"actionGetBlueprint": "Ottieni Blueprint",
|
"actionGetBlueprint": "Ottieni Blueprint",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Inserisci il token di configurazione dalla console del server.",
|
"setupTokenDescription": "Inserisci il token di configurazione dalla console del server.",
|
||||||
"setupTokenRequired": "Il token di configurazione è richiesto",
|
"setupTokenRequired": "Il token di configurazione è richiesto",
|
||||||
"actionUpdateSite": "Aggiorna Sito",
|
"actionUpdateSite": "Aggiorna Sito",
|
||||||
|
"actionApproveSite": "Approva Sito",
|
||||||
|
"actionRejectSite": "Rifiuta Sito",
|
||||||
"actionResetSiteBandwidth": "Reimposta Larghezza Banda Dell'Organizzazione",
|
"actionResetSiteBandwidth": "Reimposta Larghezza Banda Dell'Organizzazione",
|
||||||
"actionListSiteRoles": "Elenca Ruoli Sito Consentiti",
|
"actionListSiteRoles": "Elenca Ruoli Sito Consentiti",
|
||||||
"actionCreateResource": "Crea Risorsa",
|
"actionCreateResource": "Crea Risorsa",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Imposta Codice PIN Risorsa",
|
"actionSetResourcePincode": "Imposta Codice PIN Risorsa",
|
||||||
"actionSetResourceEmailWhitelist": "Imposta Lista Autorizzazioni Email Risorsa",
|
"actionSetResourceEmailWhitelist": "Imposta Lista Autorizzazioni Email Risorsa",
|
||||||
"actionGetResourceEmailWhitelist": "Ottieni Lista Autorizzazioni Email Risorsa",
|
"actionGetResourceEmailWhitelist": "Ottieni Lista Autorizzazioni Email Risorsa",
|
||||||
|
"actionListResourcePolicies": "Elenca Politiche Risorsa",
|
||||||
|
"actionCreateResourcePolicy": "Crea Politica Risorsa",
|
||||||
"actionGetResourcePolicy": "Ottieni la Politica della Risorsa",
|
"actionGetResourcePolicy": "Ottieni la Politica della Risorsa",
|
||||||
"actionUpdateResourcePolicy": "Aggiorna la Politica della Risorsa",
|
"actionUpdateResourcePolicy": "Aggiorna la Politica della Risorsa",
|
||||||
|
"actionDeleteResourcePolicy": "Elimina Politica Risorsa",
|
||||||
"actionSetResourcePolicyUsers": "Imposta Utenti della Politica Risorsa",
|
"actionSetResourcePolicyUsers": "Imposta Utenti della Politica Risorsa",
|
||||||
"actionSetResourcePolicyRoles": "Imposta Ruoli della Politica Risorsa",
|
"actionSetResourcePolicyRoles": "Imposta Ruoli della Politica Risorsa",
|
||||||
"actionSetResourcePolicyPassword": "Imposta Password della Politica Risorsa",
|
"actionSetResourcePolicyPassword": "Imposta Password della Politica Risorsa",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Elenco Inviti",
|
"actionListInvitations": "Elenco Inviti",
|
||||||
"actionExportLogs": "Esporta Log",
|
"actionExportLogs": "Esporta Log",
|
||||||
"actionViewLogs": "Visualizza Log",
|
"actionViewLogs": "Visualizza Log",
|
||||||
|
"actionCreateSiteProvisioningKey": "Crea Chiave di Provisioning del Sito",
|
||||||
|
"actionListSiteProvisioningKeys": "Elenca Chiavi di Provisioning del Sito",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Aggiorna Chiave di Provisioning del Sito",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Elimina Chiave di Provisioning del Sito",
|
||||||
"noneSelected": "Nessuna selezione",
|
"noneSelected": "Nessuna selezione",
|
||||||
"orgNotFound2": "Nessuna organizzazione trovata.",
|
"orgNotFound2": "Nessuna organizzazione trovata.",
|
||||||
"search": "Cerca…",
|
"search": "Cerca…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Inserisci il codice dalla tua app di autenticazione o uno dei tuoi codici di backup monouso.",
|
"otpAuthDescription": "Inserisci il codice dalla tua app di autenticazione o uno dei tuoi codici di backup monouso.",
|
||||||
"otpAuthSubmit": "Invia Codice",
|
"otpAuthSubmit": "Invia Codice",
|
||||||
"idpContinue": "O continua con",
|
"idpContinue": "O continua con",
|
||||||
|
"idpLastUsed": "Ultimo Utilizzo",
|
||||||
"otpAuthBack": "Torna alla Password",
|
"otpAuthBack": "Torna alla Password",
|
||||||
"navbar": "Menu di Navigazione",
|
"navbar": "Menu di Navigazione",
|
||||||
"navbarDescription": "Menu di navigazione principale dell'applicazione",
|
"navbarDescription": "Menu di navigazione principale dell'applicazione",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Crea Client Macchina",
|
"commandPaletteCreateMachineClient": "Crea Client Macchina",
|
||||||
"commandPaletteCreateAlertRule": "Crea Regola di Avviso",
|
"commandPaletteCreateAlertRule": "Crea Regola di Avviso",
|
||||||
"commandPaletteCreateIdentityProvider": "Crea Provider di Identità",
|
"commandPaletteCreateIdentityProvider": "Crea Provider di Identità",
|
||||||
|
"commandPaletteCreateAiProvider": "Crea Provider AI",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Crea Chiave API Virtuale",
|
||||||
"commandPaletteToggleTheme": "Attiva/Disattiva Tema",
|
"commandPaletteToggleTheme": "Attiva/Disattiva Tema",
|
||||||
"commandPaletteChooseOrganization": "Scegli Organizzazione",
|
"commandPaletteChooseOrganization": "Scegli Organizzazione",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Inviti",
|
"sidebarInvitations": "Inviti",
|
||||||
"sidebarRoles": "Ruoli",
|
"sidebarRoles": "Ruoli",
|
||||||
"sidebarShareableLinks": "Collegamenti Condivisibili",
|
"sidebarShareableLinks": "Collegamenti Condivisibili",
|
||||||
|
"sidebarAiGateway": "Gateway AI",
|
||||||
|
"sidebarAiProviders": "Provider",
|
||||||
|
"commandAiProviders": "Provider AI",
|
||||||
|
"sidebarVirtualApiKeys": "Chiavi API Virtuali",
|
||||||
|
"sidebarMyApiKeys": "Le Tue Chiavi API",
|
||||||
|
"sidebarAccount": "Launcher",
|
||||||
|
"commandVirtualApiKeys": "Chiavi API Virtuali",
|
||||||
|
"virtualApiKeysTitle": "Gestisci Chiavi API Virtuali",
|
||||||
|
"virtualApiKeysDescription": "Crea e gestisci chiavi API manuali per l'accesso ai gateway AI pubblici",
|
||||||
|
"virtualApiKeysTabIdentity": "Chiavi Identità",
|
||||||
|
"virtualApiKeysTabVirtual": "Chiavi Virtuali",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Chiavi di Identità per Ogni Utente",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Ogni utente ha già una chiave di identità Pangolin per questa organizzazione. È unica per il loro account e li autentica ai gateway AI a cui possono accedere.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Esempio",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Come Gli Utenti Ottengono La Loro Chiave",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Visita un URL di gateway AI pubblico nel browser e accedi con il tuo account.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Oppure vai su <url></url> mentre sei loggato.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Puoi creare ulteriori chiavi API virtuali nella scheda Chiavi Virtuali. Quelle chiavi possono essere limitate a specifici gateway AI pubblici e opzionalmente associate a un utente. La creazione di una chiave concede immediatamente l'accesso ai gateway AI pubblici selezionati.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Crea Manualmente una Chiave",
|
||||||
|
"virtualApiKeysEmailIdentity": "Email Chiavi Identità",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Invia a ogni utente o ruolo selezionato la loro chiave di identità Pangolin.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Invia a tutti gli utenti",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Invia un'email a ogni membro dell'organizzazione che ha un'email associata.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Utenti",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Ruoli",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Invia Email",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Chiavi di Identità Inviate Via Email",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Inviate {sent} email.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} utenti sono stati saltati perché non hanno un indirizzo email.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Seleziona almeno un utente o ruolo, oppure invia a tutti gli utenti.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Errore nell'invio delle chiavi di identità",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Impossibile inviare email chiavi di identità",
|
||||||
|
"virtualApiKeysBannerTitle": "Chiavi di Identità per Ogni Utente",
|
||||||
|
"virtualApiKeysBannerDescription": "Ogni utente ha già una chiave di identità disponibile su {keysUrl}. Puoi anche generare manualmente chiavi qui che concedono accesso diretto a gateway AI pubblici.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Visualizza Chiavi di Identità",
|
||||||
|
"virtualApiKeys": "Chiavi API Virtuali",
|
||||||
|
"virtualApiKeysSearch": "Cerca chiavi...",
|
||||||
|
"virtualApiKeysCreate": "Crea Chiave API Virtuale",
|
||||||
|
"virtualApiKeysCreateDescription": "Crea una chiave manuale che possa chiamare gateway AI pubblici in questa organizzazione",
|
||||||
|
"virtualApiKeysCreateButton": "Crea Chiave",
|
||||||
|
"virtualApiKeysEmpty": "Ancora nessuna chiave API virtuale",
|
||||||
|
"virtualApiKeysName": "Nome",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Descrizione (opzionale)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Associa Utente (opzionale)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Associa questa chiave a un utente per monitorare l'uso. Una volta creata, questa chiave concede immediatamente accesso ai gateway AI pubblici selezionati. Non è necessario associare manualmente un utente alla risorsa. La chiave verrà visualizzata anche nel profilo utente.",
|
||||||
|
"virtualApiKeysAllResources": "Tutti i gateway AI pubblici",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Consenti a questa chiave di accedere a tutti i gateway AI pubblici dell'organizzazione",
|
||||||
|
"virtualApiKeysSelectResources": "Gateway AI Pubblici",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Seleziona risorse",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Scegli quali gateway AI pubblici questa chiave può accedere",
|
||||||
|
"virtualApiKeysNoResources": "Nessuna risorsa",
|
||||||
|
"virtualApiKeysSecret": "Chiave",
|
||||||
|
"virtualApiKeysCopyKey": "Copia questa chiave. Puoi vederla di nuovo più tardi dalla tabella o quando la modifichi.",
|
||||||
|
"virtualApiKeysViewSecret": "Visualizza Segreto",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Segreto della Chiave API Virtuale",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Questo segreto concede l'accesso ai gateway AI pubblici assegnati a questa chiave",
|
||||||
|
"virtualApiKeysEdit": "Modifica Chiave API Virtuale",
|
||||||
|
"virtualApiKeysEditDescription": "Aggiorna l'utente associato e l'accesso ai gateway AI pubblici per questa chiave",
|
||||||
|
"virtualApiKeysSaveButton": "Salva Modifiche",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Seleziona almeno un gateway AI pubblico, o abilita tutti i gateway AI pubblici",
|
||||||
|
"virtualApiKeysUpdated": "Chiave API virtuale aggiornata",
|
||||||
|
"virtualApiKeysUpdatedDescription": "La chiave API virtuale è stata aggiornata",
|
||||||
|
"virtualApiKeysErrorUpdate": "Errore nell'aggiornamento della chiave API virtuale",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Impossibile aggiornare la chiave API virtuale",
|
||||||
|
"virtualApiKeysErrorCreate": "Errore nella creazione della chiave API virtuale",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Impossibile creare la chiave API virtuale",
|
||||||
|
"virtualApiKeysErrorDelete": "Errore nell'eliminazione della chiave API virtuale",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Impossibile eliminare la chiave API virtuale",
|
||||||
|
"virtualApiKeysDeleted": "Chiave API virtuale eliminata",
|
||||||
|
"virtualApiKeysDeletedDescription": "La chiave API virtuale è stata eliminata",
|
||||||
|
"virtualApiKeysDelete": "Elimina Chiave API Virtuale",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Elimina Chiave",
|
||||||
|
"virtualApiKeysQuestionRemove": "Sei sicuro di voler eliminare questa chiave API virtuale?",
|
||||||
|
"virtualApiKeysMessageRemove": "I client che usano questa chiave perderanno immediatamente l'accesso.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Errore nel caricamento del segreto",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Impossibile caricare il segreto della chiave API virtuale",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Non assegnato",
|
||||||
|
"virtualApiKeysInferenceBudget": "Budget",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Configura come questa chiave limita l'uso dell'AI in base alla spesa o ai limiti di token",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Email chiave alla generazione",
|
||||||
|
"virtualApiKeysEmailThisKey": "Email questa chiave",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Invia la chiave all'utente associato e ad indirizzi aggiuntivi dopo che è creata",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Invia la chiave attuale all'utente associato e ad indirizzi aggiuntivi",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "Email non configurata su questo server",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Configura SMTP per email chiavi API virtuali.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Invia all'utente associato",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Email della chiave all'email dell'account dell'utente associato",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Associa un utente per inviare la chiave a tale utente",
|
||||||
|
"virtualApiKeysEmailAdditional": "Email aggiuntive",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Aggiungi email e premi Invio",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Seleziona l'utente associato o aggiungi almeno un indirizzo email",
|
||||||
|
"myVirtualApiKeysTitle": "Le Tue Chiavi API",
|
||||||
|
"myVirtualApiKeysDescription": "Visualizza la tua chiave di identità e tutte le chiavi API virtuali attribuite a te in questa organizzazione",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Le Tue Chiavi API per {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Visualizza la tua chiave di identità e le chiavi API virtuali a te attribuite che possono accedere a {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Chiave di Identità",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "La Tua Chiave API Personale",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "La tua chiave personale per questa organizzazione. È unica per il tuo account e viene utilizzata per identificarti quando chiami le risorse Gateway AI.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "La Tua Chiave API Personale per {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "La tua chiave personale per questa organizzazione. Usala per chiamare {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Chiavi Attribuite",
|
||||||
|
"myVirtualApiKeysManualDescription": "Chiavi API virtuali manuali attribuite al tuo account",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Chiavi API virtuali manuali associate al tuo account che possono accedere a {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Ancora nessuna chiave attribuita",
|
||||||
|
"myVirtualApiKeysKindUser": "Identità",
|
||||||
|
"myVirtualApiKeysKindManual": "Manuale",
|
||||||
|
"myVirtualApiKeysUnnamed": "Chiave senza nome",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Rivela Segreto",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Questo segreto ti autentica alle risorse Gateway AI",
|
||||||
|
"aiClientConfigTitle": "Configura Agenti di Coding",
|
||||||
|
"aiClientConfigDescription": "Copia la configurazione per agenti di coding comuni, o lascia che il CLI di Pangolin la imposti automaticamente per te.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Strumento di coding agente di Anthropic per il terminale.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Strumento di coding agente di OpenAI per il terminale.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Agente di coding open source per il terminale.",
|
||||||
|
"aiClientConfigDescriptionCursor": "Editor di codice AI basato su VS Code.",
|
||||||
|
"aiClientConfigSetup": "Impostazione",
|
||||||
|
"aiClientConfigTabCli": "Automatico (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Configurazione Manuale",
|
||||||
|
"aiClientConfigPreset": "Configurazione",
|
||||||
|
"aiClientConfigStep": "Passo {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Questo snippet include valori di esempio, come un nome modello o un URL risorsa. Sostituiscili con i tuoi prima di utilizzarlo.",
|
||||||
|
"aiClientConfigRevealError": "Impossibile caricare la tua chiave API.",
|
||||||
|
"aiClientConfigRevealRetry": "Riprova",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Questa risorsa può essere utilizzata da client comuni come Claude Code e OpenCode. <configLink>Scopri di più</configLink>",
|
||||||
|
"aiProvidersTitle": "Provider AI",
|
||||||
|
"aiProvidersDescription": "Connetti provider di modelli per i carichi di lavoro AI in questa organizzazione",
|
||||||
|
"aiProvidersBannerTitle": "Connetti Provider di Modelli",
|
||||||
|
"aiProvidersBannerDescription": "I provider sono i backend dei modelli che Pangolin utilizza per i carichi di lavoro AI. Connetti OpenAI, Anthropic e altri provider qui, poi allegali ai gateway AI pubblici in modo che gli utenti possano chiamare modelli con accesso consapevole dell'identità, budget e registrazione.",
|
||||||
|
"aiProvidersAdd": "Aggiungi Provider",
|
||||||
|
"aiProvidersSearch": "Cerca provider...",
|
||||||
|
"aiProvidersEmpty": "Ancora nessun provider AI",
|
||||||
|
"aiProviderCreate": "Crea Provider AI",
|
||||||
|
"aiProviderCreateDescription": "Aggiungi un provider di modelli per questa organizzazione",
|
||||||
|
"aiProviderSeeAll": "Vedi Tutti i Provider",
|
||||||
|
"aiProviderSetting": "Impostazioni Provider per {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Configura questo provider AI",
|
||||||
|
"aiProviderGeneral": "Generale",
|
||||||
|
"aiProviderGeneralDescription": "Impostazioni di base per questo provider",
|
||||||
|
"aiProviderConfiguration": "Configurazione",
|
||||||
|
"aiProviderConfigurationDescription": "Instradamento di rete e autenticazione per questo provider",
|
||||||
|
"aiProviderNetworkSettings": "Impostazioni di Rete",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Scegli come raggiungere questo provider tramite il traffico",
|
||||||
|
"aiProviderAuthSettings": "Autenticazione",
|
||||||
|
"aiProviderAuthSettingsDescription": "Configura come questo provider autentica le richieste al suo URL a monte",
|
||||||
|
"aiProviderBudgetSettings": "Budget",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Configura come questo provider limita l'uso basato su spese o limiti di token",
|
||||||
|
"aiBudgetAdd": "Aggiungi Budget",
|
||||||
|
"aiBudgetEmpty": "Nessun budget ancora configurato. Clicca su Aggiungi Budget per impostare un limite di spesa o token.",
|
||||||
|
"aiBudgetUnit": "Tipo di Spesa",
|
||||||
|
"aiBudgetPeriod": "Periodo di Reset",
|
||||||
|
"aiBudgetAmount": "Spesa Massima",
|
||||||
|
"aiBudgetAmountPlaceholder": "Spesa massima",
|
||||||
|
"aiBudgetPeriodHourly": "Oraria",
|
||||||
|
"aiBudgetPeriodDaily": "Giornaliera",
|
||||||
|
"aiBudgetPeriodWeekly": "Settimanale",
|
||||||
|
"aiBudgetPeriodMonthly": "Mensile",
|
||||||
|
"aiBudgetPeriodYearly": "Annuale",
|
||||||
|
"aiBudgetPeriodLifetime": "A Vita",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Token",
|
||||||
|
"aiBudgetConflictError": "Esiste già un budget per questo periodo di reset e tipo di spesa",
|
||||||
|
"aiBudgetInvalidAmountError": "Inserisci una spesa massima superiore a 0",
|
||||||
|
"aiBudgetUpdated": "Budget aggiornati",
|
||||||
|
"aiBudgetErrorSave": "Impossibile aggiornare i budget",
|
||||||
|
"aiProviderType": "Tipo di Provider",
|
||||||
|
"aiProviderTypeSearch": "Cerca provider...",
|
||||||
|
"aiProviderTypeNotFound": "Nessun tipo di provider trovato",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Gateway AI Vercel",
|
||||||
|
"aiProviderTypeCustom": "Personalizzato",
|
||||||
|
"aiProviderTypeOpenaiDescription": "API di OpenAI",
|
||||||
|
"aiProviderTypeAnthropicDescription": "API di Anthropic",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "API di Google Gemini",
|
||||||
|
"aiProviderTypeVertexAiDescription": "API di Google Vertex AI",
|
||||||
|
"aiProviderTypeBedrockDescription": "API di Runtime di Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "API di Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "API di OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "API di Gateway AI Vercel",
|
||||||
|
"aiProviderTypeCustomDescription": "Porta il tuo endpoint o instrada tramite target del sito",
|
||||||
|
"aiProviderUpstreamUrl": "URL a monte",
|
||||||
|
"aiProviderUpstreamUrlDescription": "URL di base per l'API del provider",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Lascia vuoto per usare l'URL a monte predefinito per questo provider",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "URL effettivo a monte",
|
||||||
|
"aiProviderApiKey": "Chiave API",
|
||||||
|
"aiProviderApiKeyDescription": "Chiave API utilizzata per autenticare le richieste a questo provider",
|
||||||
|
"aiProviderCustomHeadersDescription": "Intestazioni inviate su ogni richiesta a questo fornitore. Separato da nuova riga: Nome-Intestazione: valore",
|
||||||
|
"aiProviderApiKeyLastChars": "Chiave API",
|
||||||
|
"aiProviderAuthType": "Tipo di Auth",
|
||||||
|
"aiProviderAuthTypeSearch": "Cerca tipi di auth...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Nessun tipo di auth trovato",
|
||||||
|
"aiProviderAuthTypeBearer": "Portatore",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Autorizzazione: chiave del portatore. Utilizzato da OpenAI e dalla maggior parte dei provider",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "intestazione x-api-key. Utilizzato da Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "intestazione x-goog-api-key. Utilizzato da Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Autorizzazione: chiave Splunk. Utilizzato dal Collettore di Eventi HTTP di Splunk",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-autorizzazione: chiave del portatore. Utilizzato da Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeNone": "Nessuna autentificazione",
|
||||||
|
"aiProviderAuthTypePassthrough": "Trasmissione diretta",
|
||||||
|
"aiProviderAuthTypeDescription": "Come l'API a monte autentica le richieste",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Trasmetti le intestazioni della chiave API del chiamante al monte",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Non inviare intestazioni di autenticazione all'a monte",
|
||||||
|
"aiProviderRoutingMode": "Modalità di instradamento",
|
||||||
|
"aiProviderRoutingModeDescription": "Invia il traffico a un URL a monte o a target HTTP sui tuoi siti",
|
||||||
|
"aiProviderRoutingModeUrl": "URL a monte",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Chiama un URL base API pubblico o privato",
|
||||||
|
"aiProviderRoutingModeTarget": "Target del sito",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Instrada tramite target sui tuoi siti",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Dopo aver creato questo provider, configura i target del sito nella scheda Impostazioni di Rete.",
|
||||||
|
"aiProviderTargetNoOne": "Questo provider non ha alcun target. Aggiungi un target per instradare le richieste attraverso i tuoi siti.",
|
||||||
|
"aiProviderSkipTlsVerification": "Salta la verifica TLS",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Disabilita la verifica del certificato TLS per la connessione a monte",
|
||||||
|
"aiProviderBudget": "Budget",
|
||||||
|
"aiProviderBudgetDescription": "Budget opzionale di spesa o di token per questo provider",
|
||||||
|
"aiProviderBudgetAmount": "Importo del budget",
|
||||||
|
"aiProviderBudgetUnit": "Unità di budget",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Token",
|
||||||
|
"aiProviderEnabled": "Abilitato",
|
||||||
|
"aiProviderEnabledDescription": "Disabilita completamente questo provider su tutte le risorse",
|
||||||
|
"aiProviderErrorCreate": "Impossibile creare il fornitore di AI",
|
||||||
|
"aiProviderErrorUpdate": "Impossibile aggiornare il fornitore di AI",
|
||||||
|
"aiProviderErrorDelete": "Impossibile eliminare il fornitore di AI",
|
||||||
|
"aiProviderErrorLoad": "Impossibile caricare il fornitore di AI",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Inserisci un URL a monte valido",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "L'URL a monte è richiesto per questo provider",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "È richiesto un tipo di autenticazione",
|
||||||
|
"aiProviderErrorApiKeyRequired": "È richiesta la chiave API",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "L'instradamento dei target del sito è disponibile solo per provider personalizzati",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Seleziona almeno una capacità API",
|
||||||
|
"aiProviderCapabilities": "Capacità dell'API",
|
||||||
|
"aiProviderCapabilitiesDescription": "Seleziona quale formato API questo fornitore può gestire. I fornitori noti iniziano con impostazioni predefinite raccomandate.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Seleziona quali formati API questo provider personalizzato può gestire",
|
||||||
|
"aiProviderCapabilitiesSelect": "Seleziona capacità",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Nessuna capacità trovata",
|
||||||
|
"aiProviderCapabilitiesSearch": "Cerca capacità...",
|
||||||
|
"aiCapabilityOpenaiChat": "Completamenti Chat OpenAI",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Supporta /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "Risposte OpenAI",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Supporta /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Messaggi Anthropic",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Supporta /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Generazione di Contenuti Gemini",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Supporta l'API diretta di Gemini",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Invoca Modello Bedrock",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Supporta Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Generazione di Contenuti Vertex",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Supporta il formato Vertex AI Gemini",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Predizione Grezza Vertex",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Supporta la predizione grezza di Vertex AI per i modelli Anthropic",
|
||||||
|
"aiCapabilityBedrockConverse": "Conversazione Bedrock",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Supporta l'API di Conversazione Amazon Bedrock",
|
||||||
|
"aiProviderCreated": "Provider AI creato",
|
||||||
|
"aiProviderUpdated": "Provider AI aggiornato",
|
||||||
|
"aiProviderDeleted": "Provider AI eliminato",
|
||||||
|
"aiProviderDelete": "Elimina Provider",
|
||||||
|
"aiProviderDeleteConfirm": "Elimina Provider",
|
||||||
|
"aiProviderQuestionRemove": "Sei sicuro di voler eliminare questo provider AI?",
|
||||||
|
"aiProviderMessageRemove": "Questo eliminerà permanentemente il provider e i suoi modelli e obiettivi. Questa azione non può essere annullata.",
|
||||||
|
"aiProviderErrorNoUpdate": "Il provider AI non è disponibile per l'aggiornamento",
|
||||||
|
"aiProviderModels": "Modelli",
|
||||||
|
"aiProviderModelsDescription": "Definisci le liste di autorizzazione e blocco per questo provider. Le richieste devono corrispondere a un'entrata di autorizzazione e non devono corrispondere a un'entrata di blocco.",
|
||||||
|
"aiProviderCreateModelsDescription": "Scegli quali modelli questo provider può servire. Una lista di autorizzazione vuota nega tutto il traffico. Puoi aggiungere o modificare i modelli in un secondo momento.",
|
||||||
|
"aiProviderModelsPlaceholder": "Cerca modelli o digita una chiave personalizzata",
|
||||||
|
"aiProviderModelsAllow": "Lista di Autorizzazione",
|
||||||
|
"aiProviderModelsAllowDescription": "Modelli che possono essere utilizzati tramite questo provider. Vuoto significa negare tutto.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Inserisci chiave modello",
|
||||||
|
"aiProviderModelsAllowEmpty": "Nessun modello aggiunto ancora.",
|
||||||
|
"aiProviderModelsBlock": "Lista di Blocco",
|
||||||
|
"aiProviderModelsBlockDescription": "Modelli da negare anche se corrispondono a un'entrata di autorizzazione.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Inserisci chiave modello",
|
||||||
|
"aiProviderModelsBlockEmpty": "Nessun modello aggiunto ancora.",
|
||||||
|
"aiProviderModelsAdd": "Aggiungi Modelli",
|
||||||
|
"aiProviderModelsClearAll": "Cancella Tutto",
|
||||||
|
"aiProviderModelsAddCustom": "Aggiungi \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Premi Invio per aggiungere questa chiave modello personalizzata.",
|
||||||
|
"aiProviderModelsAddBulk": "Aggiungi {count} chiavi personalizzate",
|
||||||
|
"aiProviderModelsAddBulkHint": "Premi Invio per aggiungere {count} chiavi personalizzate.",
|
||||||
|
"aiProviderModelsAddOne": "Aggiungi {key} ora",
|
||||||
|
"aiProviderModelsAddSelected": "Aggiungi Selezionati",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} selezionato",
|
||||||
|
"aiProviderModelsSelectAll": "Seleziona tutto",
|
||||||
|
"aiProviderModelsClearSelected": "Cancella",
|
||||||
|
"aiProviderModelsBulkHint": "Seleziona modelli conosciuti o digita una chiave personalizzata.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Nessun modello di catalogo corrispondente.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Modelli Conosciuti",
|
||||||
|
"aiProviderModelsAllLabel": "Tutti i modelli",
|
||||||
|
"aiProviderModelsAllPatternHint": "Jolly: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Consenti a tutti i modelli",
|
||||||
|
"aiProviderModelsAddAllBlock": "Blocca tutti i modelli",
|
||||||
|
"aiProviderModelsAddAllDescription": "Utilizza il carattere jolly * in modo che ogni chiave modello corrisponda.",
|
||||||
|
"aiProviderModelsViewMore": "Visualizza di più ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Visualizza meno",
|
||||||
|
"aiProviderModelsRemove": "Rimuovi modello",
|
||||||
|
"aiProviderModelsEditHint": "Fai clic per modificare le impostazioni del modello",
|
||||||
|
"aiProviderModelsSourceCatalog": "Modello di catalogo conosciuto",
|
||||||
|
"aiProviderModelsSourceCustom": "Chiave modello personalizzata",
|
||||||
|
"aiProviderModelsSourcePattern": "Modello Jolly",
|
||||||
|
"aiProviderModelsSourceAll": "Corrisponde a ogni chiave modello",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Budget configurato",
|
||||||
|
"aiProviderModelsEditTitle": "Modifica Modello",
|
||||||
|
"aiProviderModelsEditDescription": "Aggiorna la chiave del modello o configura il suo budget.",
|
||||||
|
"aiProviderModelsBudgetTab": "Budget",
|
||||||
|
"aiProviderModelsKeyLabel": "Chiave Modello",
|
||||||
|
"aiProviderModelsKeyRequired": "Inserisci una chiave modello",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Questa chiave modello è già in una lista",
|
||||||
|
"aiProviderModelsOverlapError": "Questi modelli non possono essere in entrambe le liste: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modelli aggiornati",
|
||||||
|
"aiProviderModelsErrorUpdate": "Impossibile aggiornare i modelli",
|
||||||
|
"aiResourceProviders": "Provider",
|
||||||
|
"aiResourceProvidersDescription": "Scegli quali provider AI questo gateway AI può utilizzare",
|
||||||
|
"aiResourceProvidersHelp": "Allega i provider e scegli eredita (usa le liste di ciascun provider) o seleziona (scegli una lista di autorizzazione per questa risorsa). Non sono ammessi schemi che confliggono tra i provider allegati.",
|
||||||
|
"aiResourceProvidersSelect": "Seleziona i provider",
|
||||||
|
"aiResourceProvidersEmpty": "Nessun provider AI trovato",
|
||||||
|
"aiResourceProvidersNoneAttached": "Nessun provider allegato ancora.",
|
||||||
|
"aiResourceProvidersAdd": "Aggiungi provider",
|
||||||
|
"aiResourceProvidersRemove": "Rimuovi provider",
|
||||||
|
"aiResourceProviderToggleEnabled": "Abilita o disabilita questo provider sulla risorsa",
|
||||||
|
"aiResourceProviderDisabled": "Disabilitato",
|
||||||
|
"aiResourceProvidersUpdated": "Provider aggiornati",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Impossibile aggiornare i provider",
|
||||||
|
"aiResourceProviderEditDescription": "Scegli come sono esposti i modelli di questo provider su questa risorsa.",
|
||||||
|
"viewProviderSettings": "Visualizza le Impostazioni del Provider",
|
||||||
|
"aiResourceProviderMode": "Modalità di Accesso",
|
||||||
|
"aiResourceProviderModeInherit": "Eredita",
|
||||||
|
"aiResourceProviderModeSelect": "Seleziona",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Seleziona · {count} modelli",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Utilizza le liste di autorizzazione e blocco di questo provider come configurato sul provider.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Scegli un sottoinsieme dei modelli della lista di autorizzazione di questo provider per questa risorsa.",
|
||||||
|
"aiResourceProviderAllowModels": "Lista di autorizzazione",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Seleziona modelli",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Cerca modelli...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Nessun modello trovato",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Solo i modelli dalla lista di autorizzazione di questo provider possono essere selezionati.",
|
||||||
|
"aiResourceAliasRequired": "Alias è richiesto per gateway AI",
|
||||||
|
"aiResourceDomainConfiguration": "Configurazione del Dominio",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Scegli il dominio che i clienti utilizzeranno per accedere a questo gateway AI.",
|
||||||
|
"aiUsageAnalyticsTitle": "Analisi dell'Uso AI",
|
||||||
|
"aiUsageAnalyticsDescription": "Analizza il costo del gateway AI, l'uso dei token e l'attività tra provider, risorse, ruoli e utenti",
|
||||||
|
"aiUsageTabOverview": "Panoramica",
|
||||||
|
"aiUsageTabProviders": "Provider",
|
||||||
|
"aiUsageTabResources": "Risorse",
|
||||||
|
"aiUsageFilterProvider": "Provider",
|
||||||
|
"aiUsageFilterModel": "Modello",
|
||||||
|
"aiUsageFilterResource": "Risorsa",
|
||||||
|
"aiUsageFilterRole": "Ruolo",
|
||||||
|
"aiUsageFilterUser": "Utente",
|
||||||
|
"aiUsageFilterAllProviders": "Tutti i Provider",
|
||||||
|
"aiUsageFilterAllModels": "Tutti i Modelli",
|
||||||
|
"aiUsageFilterAllResources": "Tutte le Risorse",
|
||||||
|
"aiUsageFilterAllRoles": "Tutti i Ruoli",
|
||||||
|
"aiUsageFilterAllUsers": "Tutti gli Utenti",
|
||||||
|
"aiUsageFilterSearch": "Ricerca...",
|
||||||
|
"aiUsageFilterNotFound": "Nessuna opzione trovata",
|
||||||
|
"aiUsageResetFilters": "Ripristina Filtri",
|
||||||
|
"aiUsageRefresh": "Ricarica",
|
||||||
|
"aiUsageTokenTypePrompt": "Prompt",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Leggi Cache",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Scrivi Cache",
|
||||||
|
"aiUsageTokenTypeCompletion": "Completamento",
|
||||||
|
"aiUsageTokenTypeReasoning": "Ragionamento",
|
||||||
|
"aiUsageRequests": "Richieste",
|
||||||
|
"aiUsageCost": "Costo",
|
||||||
|
"aiUsageTokens": "Token",
|
||||||
|
"aiUsageOther": "Altro",
|
||||||
|
"aiUsageTotalRequests": "Richieste Totali",
|
||||||
|
"aiUsageTotalTokens": "Token Totali",
|
||||||
|
"aiUsageTotalCost": "Costo Totale",
|
||||||
|
"aiUsageEstimated": "Stimato",
|
||||||
|
"aiUsageRequestVolume": "Volume delle Richieste",
|
||||||
|
"aiUsageTokenUsage": "Uso dei Token",
|
||||||
|
"aiUsageModelCost": "Costo del Modello",
|
||||||
|
"aiUsageModelTokens": "Token del Modello",
|
||||||
|
"aiUsageTopModels": "Migliori Modelli",
|
||||||
|
"aiUsageTopProviders": "Migliori Provider",
|
||||||
|
"aiUsageProviderCost": "Costo del Provider",
|
||||||
|
"aiUsageProviderTokenUsage": "Uso del Token del Provider",
|
||||||
|
"aiUsageTopResources": "Migliori Risorse",
|
||||||
|
"aiUsageResourceCost": "Costo della Risorsa",
|
||||||
|
"aiUsageResourceTokenUsage": "Uso del Token della Risorsa",
|
||||||
|
"aiUsageResourceTypePublic": "Risorsa Pubblica",
|
||||||
|
"aiUsageResourceTypeSite": "Risorsa Privata",
|
||||||
|
"aiUsageNoResource": "Nessuna risorsa",
|
||||||
|
"aiUsageRolesTab": "Ruoli",
|
||||||
|
"aiUsageUsersTab": "Utenti",
|
||||||
|
"aiUsageTopRoles": "Migliori Ruoli",
|
||||||
|
"aiUsageRoleCost": "Costo Ruolo",
|
||||||
|
"aiUsageRoleTokenUsage": "Uso del Token Ruolo",
|
||||||
|
"aiUsageTopUsers": "Migliori Utenti",
|
||||||
|
"aiUsageUserCost": "Costo Utente",
|
||||||
|
"aiUsageUserTokenUsage": "Uso del Token Utente",
|
||||||
|
"aiUsageUnknownUser": "Utente sconosciuto",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Chiavi API Virtuali",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Chiave API Virtuale",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Tutte le Chiavi API Virtuali",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Migliori Chiavi API Virtuali",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Costo Chiave API Virtuale",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Uso del Token Chiave API Virtuale",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Nessuna chiave API virtuale",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Chiave senza nome",
|
||||||
|
"aiUsageLoading": "Caricamento...",
|
||||||
|
"aiUsageNoData": "Nessun dato",
|
||||||
|
"resourceBudgetSettings": "Budget",
|
||||||
|
"resourceBudgetSettingsDescription": "Configura come questo gateway AI limita l'uso basato sulla spesa o sui limiti di token",
|
||||||
"sidebarApiKeys": "Chiavi API",
|
"sidebarApiKeys": "Chiavi API",
|
||||||
"sidebarProvisioning": "Accantonamento",
|
"sidebarProvisioning": "Accantonamento",
|
||||||
"sidebarSettings": "Impostazioni",
|
"sidebarSettings": "Impostazioni",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Regola di allerta salvata",
|
"alertingRuleSaved": "Regola di allerta salvata",
|
||||||
"alertingRuleSavedCreatedDescription": "La tua nuova regola di allerta è stata creata. Puoi continuare a modificarla su questa pagina.",
|
"alertingRuleSavedCreatedDescription": "La tua nuova regola di allerta è stata creata. Puoi continuare a modificarla su questa pagina.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Le modifiche a questa regola di allerta sono state salvate.",
|
"alertingRuleSavedUpdatedDescription": "Le modifiche a questa regola di allerta sono state salvate.",
|
||||||
|
"alertingTestAlertSent": "Avviso di test inviato",
|
||||||
|
"alertingTestAlertSentDescription": "Un avviso di test è stato inviato alle azioni configurate in questa regola.",
|
||||||
"alertingEditRule": "Modifica Regola di Allerta",
|
"alertingEditRule": "Modifica Regola di Allerta",
|
||||||
"alertingCreateRule": "Crea Regola di Allerta",
|
"alertingCreateRule": "Crea Regola di Allerta",
|
||||||
"alertingRuleCredenzaDescription": "Scegli cosa monitorare, quando attivare e come notificare",
|
"alertingRuleCredenzaDescription": "Scegli cosa monitorare, quando attivare e come notificare",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Ogni regola collega ciò che monitorare (un sito, controllo di salute o risorsa), quando attivare (ad esempio offline o non sano) e come notificare il tuo team via email, webhook o integrazioni. Usa questo elenco per creare, abilitare e gestire queste regole.",
|
"alertingRulesBannerDescription": "Ogni regola collega ciò che monitorare (un sito, controllo di salute o risorsa), quando attivare (ad esempio offline o non sano) e come notificare il tuo team via email, webhook o integrazioni. Usa questo elenco per creare, abilitare e gestire queste regole.",
|
||||||
"alertingHealthChecksBannerTitle": "Monitora Salute & Risorse",
|
"alertingHealthChecksBannerTitle": "Monitora Salute & Risorse",
|
||||||
"alertingHealthChecksBannerDescription": "I controlli di salute sono monitor HTTP o TCP che definisci una volta. Puoi poi usarli come fonti nelle regole di allerta così ricevi avvisi quando un obiettivo diventa sano o non sano. I controlli di salute sulle risorse appaiono anche qui.",
|
"alertingHealthChecksBannerDescription": "I controlli di salute sono monitor HTTP o TCP che definisci una volta. Puoi poi usarli come fonti nelle regole di allerta così ricevi avvisi quando un obiettivo diventa sano o non sano. I controlli di salute sulle risorse appaiono anche qui.",
|
||||||
|
"alertingTestRule": "Regola di Avviso di Test",
|
||||||
|
"alertingAddActionHeading": "Aggiungi Nuova Azione",
|
||||||
|
"alertingSelectActionType": "Seleziona un'Azione",
|
||||||
|
"alertingNoActionsTitle": "Nessuna azione configurata",
|
||||||
|
"alertingNoActionsSaveDescription": "Aggiungi almeno un'azione in modo che questa regola possa notificare qualcuno quando viene attivata.",
|
||||||
|
"alertingNoActionsTestDescription": "Aggiungi almeno un'azione prima di poter testare questa regola.",
|
||||||
"standaloneHcTableTitle": "Controlli di Salute",
|
"standaloneHcTableTitle": "Controlli di Salute",
|
||||||
"standaloneHcSearchPlaceholder": "Cerca controlli di salute…",
|
"standaloneHcSearchPlaceholder": "Cerca controlli di salute…",
|
||||||
"standaloneHcAddButton": "Crea Controllo di Salute",
|
"standaloneHcAddButton": "Crea Controllo di Salute",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Sottodominio: {subdomain}",
|
"domainPickerSubdomain": "Sottodominio: {subdomain}",
|
||||||
"domainPickerNamespace": "Namespace: {namespace}",
|
"domainPickerNamespace": "Namespace: {namespace}",
|
||||||
"domainPickerShowMore": "Mostra Altro",
|
"domainPickerShowMore": "Mostra Altro",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Nessun dominio disponibile",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Non hai ancora configurato alcun dominio. Crea un dominio per continuare.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Vai ai Domini",
|
||||||
"regionSelectorTitle": "Seleziona regione",
|
"regionSelectorTitle": "Seleziona regione",
|
||||||
"domainPickerRemoteExitNodeWarning": "I domini forniti non sono supportati quando i siti si connettono a nodi di uscita remoti. Affinché le risorse siano disponibili su nodi remoti, utilizza invece un dominio personalizzato.",
|
"domainPickerRemoteExitNodeWarning": "I domini forniti non sono supportati quando i siti si connettono a nodi di uscita remoti. Affinché le risorse siano disponibili su nodi remoti, utilizza invece un dominio personalizzato.",
|
||||||
"regionSelectorInfo": "Selezionare una regione ci aiuta a fornire migliori performance per la tua posizione. Non devi necessariamente essere nella stessa regione del tuo server.",
|
"regionSelectorInfo": "Selezionare una regione ci aiuta a fornire migliori performance per la tua posizione. Non devi necessariamente essere nella stessa regione del tuo server.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Sottorete",
|
"subnetPlaceholder": "Sottorete",
|
||||||
"addressDescription": "L'indirizzo interno del client. Deve rientrare nella sottorete dell'organizzazione.",
|
"addressDescription": "L'indirizzo interno del client. Deve rientrare nella sottorete dell'organizzazione.",
|
||||||
"selectSites": "Seleziona siti",
|
"selectSites": "Seleziona siti",
|
||||||
|
"selectResources": "Seleziona risorse",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# risorsa} other {# risorse}}",
|
||||||
"selectLabels": "Seleziona etichette",
|
"selectLabels": "Seleziona etichette",
|
||||||
"sitesDescription": "Il cliente avrà connettività ai siti selezionati",
|
"sitesDescription": "Il cliente avrà connettività ai siti selezionati",
|
||||||
"clientInstallOlm": "Installa Olm",
|
"clientInstallOlm": "Installa Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Il tempo è in secondi",
|
"timeIsInSeconds": "Il tempo è in secondi",
|
||||||
"requireDeviceApproval": "Richiede Approvazioni Dispositivo",
|
"requireDeviceApproval": "Richiede Approvazioni Dispositivo",
|
||||||
"requireDeviceApprovalDescription": "Gli utenti con questo ruolo hanno bisogno di nuovi dispositivi approvati da un amministratore prima di poter connettersi e accedere alle risorse.",
|
"requireDeviceApprovalDescription": "Gli utenti con questo ruolo hanno bisogno di nuovi dispositivi approvati da un amministratore prima di poter connettersi e accedere alle risorse.",
|
||||||
"sshSettings": "Impostazioni SSH",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI Gateway",
|
||||||
"sshAccess": "Accesso SSH",
|
"sshAccess": "Accesso SSH",
|
||||||
"rdpSettings": "Impostazioni RDP",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "Impostazioni VNC",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "Server SSH",
|
"sshServer": "Server SSH",
|
||||||
"rdpServer": "Server RDP",
|
"rdpServer": "Server RDP",
|
||||||
"vncServer": "Server VNC",
|
"vncServer": "Server VNC",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Pubblico",
|
"resourcesTableProxyResources": "Pubblico",
|
||||||
"resourcesTableClientResources": "Privato",
|
"resourcesTableClientResources": "Privato",
|
||||||
"resourcesTableNoProxyResourcesFound": "Nessuna risorsa proxy trovata.",
|
"resourcesTableNoProxyResourcesFound": "Nessuna risorsa proxy trovata.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Nessuna risorsa interna trovata.",
|
"resourcesTableNoInternalResourcesFound": "Nessuna risorsa privata trovata.",
|
||||||
"resourcesTableDestination": "Destinazione",
|
"resourcesTableDestination": "Destinazione",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Indirizzo Alias",
|
"resourcesTableAliasAddress": "Indirizzo Alias",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Annulla",
|
"editInternalResourceDialogCancel": "Annulla",
|
||||||
"editInternalResourceDialogSaveResource": "Salva Risorsa",
|
"editInternalResourceDialogSaveResource": "Salva Risorsa",
|
||||||
"editInternalResourceDialogSuccess": "Successo",
|
"editInternalResourceDialogSuccess": "Successo",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Risorsa interna aggiornata con successo",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Risorsa privata aggiornata con successo",
|
||||||
"editInternalResourceDialogError": "Errore",
|
"editInternalResourceDialogError": "Errore",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Impossibile aggiornare la risorsa interna",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Impossibile aggiornare la risorsa privata",
|
||||||
"editInternalResourceDialogNameRequired": "Il nome è obbligatorio",
|
"editInternalResourceDialogNameRequired": "Il nome è obbligatorio",
|
||||||
"editInternalResourceDialogNameMaxLength": "Il nome deve essere inferiore a 255 caratteri",
|
"editInternalResourceDialogNameMaxLength": "Il nome deve essere inferiore a 255 caratteri",
|
||||||
"editInternalResourceDialogProxyPortMin": "La porta proxy deve essere almeno 1",
|
"editInternalResourceDialogProxyPortMin": "La porta proxy deve essere almeno 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI Gateway",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Metodo HTTP",
|
"editInternalResourceDialogScheme": "Metodo HTTP",
|
||||||
"editInternalResourceDialogEnableSsl": "Abilita TLS",
|
"editInternalResourceDialogEnableSsl": "Abilita TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Un alias DNS interno opzionale per questa risorsa.",
|
"editInternalResourceDialogAliasDescription": "Un alias DNS interno opzionale per questa risorsa.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Nessun Sito Disponibile",
|
"createInternalResourceDialogNoSitesAvailable": "Nessun Sito Disponibile",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Devi avere almeno un sito Newt con una subnet configurata per creare risorse interne.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Devi avere almeno un sito Newt con una subnet configurata per creare risorse private.",
|
||||||
"createInternalResourceDialogClose": "Chiudi",
|
"createInternalResourceDialogClose": "Chiudi",
|
||||||
"createInternalResourceDialogCreateClientResource": "Crea Risorsa Privata",
|
"createInternalResourceDialogCreateClientResource": "Crea Risorsa Privata",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Crea una nuova risorsa che sarà accessibile solo ai client connessi all'organizzazione",
|
"createInternalResourceDialogCreateClientResourceDescription": "Crea una nuova risorsa che sarà accessibile solo ai client connessi all'organizzazione",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Consenti ICMP Ping",
|
"privateResourceAllowIcmpPing": "Consenti ICMP Ping",
|
||||||
"privateResourceNetworkAccess": "Accesso alla Rete",
|
"privateResourceNetworkAccess": "Accesso alla Rete",
|
||||||
"privateResourceNetworkAccessDescription": "Controlla l'accesso alle porte TCP/UDP e se ICMP ping è consentito per questa risorsa.",
|
"privateResourceNetworkAccessDescription": "Controlla l'accesso alle porte TCP/UDP e se ICMP ping è consentito per questa risorsa.",
|
||||||
"hostSettings": "Impostazioni dell'Host",
|
"hostSettings": "Host",
|
||||||
"cidrSettings": "Impostazioni CIDR",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Proprietà della Risorsa",
|
"createInternalResourceDialogResourceProperties": "Proprietà della Risorsa",
|
||||||
"createInternalResourceDialogName": "Nome",
|
"createInternalResourceDialogName": "Nome",
|
||||||
"createInternalResourceDialogSite": "Sito",
|
"createInternalResourceDialogSite": "Sito",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Annulla",
|
"createInternalResourceDialogCancel": "Annulla",
|
||||||
"createInternalResourceDialogCreateResource": "Crea Risorsa",
|
"createInternalResourceDialogCreateResource": "Crea Risorsa",
|
||||||
"createInternalResourceDialogSuccess": "Successo",
|
"createInternalResourceDialogSuccess": "Successo",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Risorsa interna creata con successo",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Risorsa privata creata con successo",
|
||||||
"createInternalResourceDialogError": "Errore",
|
"createInternalResourceDialogError": "Errore",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Impossibile creare la risorsa interna",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Impossibile creare la risorsa privata",
|
||||||
"createInternalResourceDialogNameRequired": "Il nome è obbligatorio",
|
"createInternalResourceDialogNameRequired": "Il nome è obbligatorio",
|
||||||
"createInternalResourceDialogNameMaxLength": "Il nome non deve superare i 255 caratteri",
|
"createInternalResourceDialogNameMaxLength": "Il nome non deve superare i 255 caratteri",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Si prega di selezionare un sito",
|
"createInternalResourceDialogPleaseSelectSite": "Si prega di selezionare un sito",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI Gateway",
|
||||||
"scheme": "Metodo HTTP",
|
"scheme": "Metodo HTTP",
|
||||||
"createInternalResourceDialogScheme": "Metodo HTTP",
|
"createInternalResourceDialogScheme": "Metodo HTTP",
|
||||||
"createInternalResourceDialogEnableSsl": "Abilita TLS",
|
"createInternalResourceDialogEnableSsl": "Abilita TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Password Valida",
|
"validPassword": "Password Valida",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Chiave API Virtuale Valida",
|
||||||
"view": "Visualizza",
|
"view": "Visualizza",
|
||||||
"configManaged": "Gestione Configurazione",
|
"configManaged": "Gestione Configurazione",
|
||||||
"connectedClient": "Cliente Connesso",
|
"connectedClient": "Cliente Connesso",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Ritenzione Registro",
|
"logRetention": "Ritenzione Registro",
|
||||||
"logRetentionDescription": "Gestisci per quanto tempo i diversi tipi di log sono mantenuti per questa organizzazione o disabilitali",
|
"logRetentionDescription": "Gestisci per quanto tempo i diversi tipi di log sono mantenuti per questa organizzazione o disabilitali",
|
||||||
"requestLogsDescription": "Visualizza i registri di richiesta dettagliati per le risorse in questa organizzazione",
|
"requestLogsDescription": "Visualizza i registri di richiesta dettagliati per le risorse in questa organizzazione",
|
||||||
|
"aiSessionLogs": "Log delle Sessioni AI Gateway",
|
||||||
|
"aiSessionLogsDescription": "Visualizza trascrizioni di prompt e risposte per le richieste del gateway AI in questa organizzazione",
|
||||||
|
"sidebarLogsAi": "Log delle Sessioni",
|
||||||
|
"commandLogsAi": "Log delle Sessioni",
|
||||||
|
"sidebarLogsAiUsage": "Analytics sull'Uso",
|
||||||
|
"commandLogsAiUsage": "Analytics sull'Uso",
|
||||||
|
"provider": "Provider",
|
||||||
|
"capability": "Capacità",
|
||||||
|
"model": "Modello",
|
||||||
|
"virtualApiKey": "Chiave API Virtuale",
|
||||||
|
"noVirtualApiKey": "Nessuna chiave API virtuale",
|
||||||
|
"stream": "Flusso",
|
||||||
|
"streaming": "Streaming",
|
||||||
|
"nonStreaming": "Non-streaming",
|
||||||
|
"statusCode": "Codice di Stato",
|
||||||
|
"aiSessionId": "ID Sessione",
|
||||||
|
"aiSessionRequest": "Richiesta",
|
||||||
|
"aiSessionResponse": "Risposta",
|
||||||
|
"aiSessionNoData": "Nessun dato catturato",
|
||||||
|
"aiSessionCouldNotParse": "(grezzo, non è stato possibile analizzare la trascrizione)",
|
||||||
|
"aiSessionLogTruncated": "Questa sessione è stata troncata prima dell'archiviazione e potrebbe essere incompleta.",
|
||||||
|
"aiSessionViewRaw": "Visualizza JSON Grezzo",
|
||||||
|
"aiSessionViewChat": "Visualizza Chat",
|
||||||
|
"cost": "Costo",
|
||||||
|
"estimated": "Stimato",
|
||||||
|
"tokenUsage": "Uso del Token",
|
||||||
|
"promptTokens": "Token Prompt",
|
||||||
|
"cacheReadTokens": "Token Lettura Cache",
|
||||||
|
"cacheWriteTokens": "Token Scrittura Cache",
|
||||||
|
"completionTokens": "Token Completamento",
|
||||||
|
"reasoningTokens": "Token Ragionamento",
|
||||||
|
"totalTokens": "Token Totali",
|
||||||
"requestAnalyticsDescription": "Visualizza le analisi dettagliate della richiesta per le risorse in questa organizzazione",
|
"requestAnalyticsDescription": "Visualizza le analisi dettagliate della richiesta per le risorse in questa organizzazione",
|
||||||
"logRetentionRequestLabel": "Conservazione Log Richieste HTTP",
|
"logRetentionRequestLabel": "Conservazione Log Richieste HTTP",
|
||||||
"logRetentionRequestDescription": "Per quanto tempo conservare i log delle richieste",
|
"logRetentionRequestDescription": "Per quanto tempo conservare i log delle richieste",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Per quanto tempo conservare i log delle azioni",
|
"logRetentionActionDescription": "Per quanto tempo conservare i log delle azioni",
|
||||||
"logRetentionConnectionLabel": "Ritenzione Registro Di Connessione",
|
"logRetentionConnectionLabel": "Ritenzione Registro Di Connessione",
|
||||||
"logRetentionConnectionDescription": "Per quanto tempo conservare i log di connessione",
|
"logRetentionConnectionDescription": "Per quanto tempo conservare i log di connessione",
|
||||||
|
"logRetentionAISessionsLabel": "Conservazione Log delle Sessioni AI Gateway",
|
||||||
|
"logRetentionAISessionsDescription": "Per quanto tempo mantenere i log delle sessioni prompt/risposta del gateway AI",
|
||||||
"logRetentionDisabled": "Disabilitato",
|
"logRetentionDisabled": "Disabilitato",
|
||||||
"logRetention3Days": "3 giorni",
|
"logRetention3Days": "3 giorni",
|
||||||
"logRetention7Days": "7 giorni",
|
"logRetention7Days": "7 giorni",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Indirizzo Di Origine",
|
"sourceAddress": "Indirizzo Di Origine",
|
||||||
"destinationAddress": "Indirizzo Di Destinazione",
|
"destinationAddress": "Indirizzo Di Destinazione",
|
||||||
"duration": "Durata",
|
"duration": "Durata",
|
||||||
"licenseRequiredToUse": "Per utilizzare questa funzione è necessaria una licenza <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> o <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> . <bookADemoLink>Prenota una demo o una prova POC</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Licenza Enterprise Edition</enterpriseEditionLink> è richiesta. <bookADemoLink>Prenota una demo o prova</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "L' <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> è necessaria per utilizzare questa funzione. Questa funzione è disponibile anche in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Prenota una demo o una prova POC</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Licenza Enterprise Edition</enterpriseEditionLink> è richiesta. <bookADemoLink>Prenota una demo o prova</bookADemoLink>",
|
||||||
"certResolver": "Risolutore Di Certificato",
|
"certResolver": "Risolutore Di Certificato",
|
||||||
"certResolverDescription": "Selezionare il risolutore di certificati da usare per questa risorsa.",
|
"certResolverDescription": "Selezionare il risolutore di certificati da usare per questa risorsa.",
|
||||||
"selectCertResolver": "Seleziona Risolutore Di Certificato",
|
"selectCertResolver": "Seleziona Risolutore Di Certificato",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Selezionare più siti consente un routing resiliente e Failover per alta disponibilità.",
|
"internalResourceFormMultiSiteRoutingHelp": "Selezionare più siti consente un routing resiliente e Failover per alta disponibilità.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Scopri di più",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Scopri di più",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Limita l'accesso a porte TCP/UDP specifiche o consenti/blocca tutte le porte.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Limita l'accesso a porte TCP/UDP specifiche o consenti/blocca tutte le porte.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "Configurazione HTTP",
|
"createInternalResourceDialogHttpConfiguration": "Configurazione del Dominio",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Scegli il dominio che i clienti utilizzeranno per accedere a questa risorsa tramite HTTP o HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Scegli il dominio che i clienti utilizzeranno per accedere a questa risorsa tramite HTTP o HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "Configurazione HTTP",
|
"editInternalResourceDialogHttpConfiguration": "Configurazione del Dominio",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Scegli il dominio che i clienti utilizzeranno per accedere a questa risorsa tramite HTTP o HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Scegli il dominio che i clienti utilizzeranno per accedere a questa risorsa tramite HTTP o HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Non Etichettato",
|
"resourceLauncherUnlabeled": "Non Etichettato",
|
||||||
|
"resourceLauncherAiGateway": "AI Gateway",
|
||||||
"resourceLauncherNoSite": "Nessun Sito",
|
"resourceLauncherNoSite": "Nessun Sito",
|
||||||
|
"resourceLauncherAvailableModels": "Modelli Disponibili",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modelli che puoi usare con questo gateway AI.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Nessun modello è disponibile per questa risorsa.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Impossibile caricare i modelli disponibili.",
|
||||||
|
"resourceLauncherApiKeys": "Chiavi API",
|
||||||
|
"resourceLauncherApiKeysDescription": "Usa la tua chiave di identità o una chiave attribuita per autenticarti con questa risorsa.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Chiave di Identità",
|
||||||
|
"resourceLauncherApiKeysManual": "Chiavi Attribuite",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Nessuna chiave API è disponibile per questa risorsa.",
|
||||||
|
"resourceLauncherApiKeysError": "Impossibile caricare le chiavi API.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Nessuna risorsa in questo gruppo",
|
"resourceLauncherNoResourcesInGroup": "Nessuna risorsa in questo gruppo",
|
||||||
"resourceLauncherEmptyStateTitle": "Non ci sono risorse disponibili",
|
"resourceLauncherEmptyStateTitle": "Non ci sono risorse disponibili",
|
||||||
"resourceLauncherEmptyStateDescription": "Non hai ancora accesso a nessuna risorsa. Contatta il tuo amministratore per richiedere l'accesso.",
|
"resourceLauncherEmptyStateDescription": "Non hai ancora accesso a nessuna risorsa. Contatta il tuo amministratore per richiedere l'accesso.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Non è stato possibile eliminare la visualizzazione del lanscia. Per favore riprova.",
|
"resourceLauncherViewDeleteFailedDescription": "Non è stato possibile eliminare la visualizzazione del lanscia. Per favore riprova.",
|
||||||
"memberPortalPrevious": "Precedente",
|
"memberPortalPrevious": "Precedente",
|
||||||
"memberPortalNext": "Successivo",
|
"memberPortalNext": "Successivo",
|
||||||
"httpSettings": "Impostazioni HTTP",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "Impostazioni TCP",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "Impostazioni UDP",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Stabilire una connessione sicura…",
|
"sshConnectingDescription": "Stabilire una connessione sicura…",
|
||||||
"sshConnecting": "Connessione…",
|
"sshConnecting": "Connessione…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Caricamento fallito",
|
"rdpUploadFailed": "Caricamento fallito",
|
||||||
"rdpUnicodeKeyboardMode": "Modalità tastiera Unicode",
|
"rdpUnicodeKeyboardMode": "Modalità tastiera Unicode",
|
||||||
"sessionToolbarShow": "Mostra barra degli strumenti",
|
"sessionToolbarShow": "Mostra barra degli strumenti",
|
||||||
"sessionToolbarHide": "Nascondi barra degli strumenti"
|
"sessionToolbarHide": "Nascondi barra degli strumenti",
|
||||||
|
"actionUpdateSiteApprovals": "Aggiorna Approvazioni del Sito"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "올바른 사용자로 로그인했는지 확인하십시오.",
|
"inviteLoginUser": "올바른 사용자로 로그인했는지 확인하십시오.",
|
||||||
"inviteErrorNoUser": "죄송하지만, 접근하려는 초대가 존재하지 않는 사용자에 대한 것인 것 같습니다.",
|
"inviteErrorNoUser": "죄송하지만, 접근하려는 초대가 존재하지 않는 사용자에 대한 것인 것 같습니다.",
|
||||||
"inviteCreateUser": "먼저 계정을 생성해 주세요.",
|
"inviteCreateUser": "먼저 계정을 생성해 주세요.",
|
||||||
|
"inviteErrorOidcNotAllowed": "초대는 내부 계정만 수락할 수 있습니다. 이 이메일의 비밀번호로 로그아웃하고 다시 로그인하십시오.",
|
||||||
|
"inviteLoginInternalOnly": "초대에는 비밀번호가 있는 내부 계정이 필요합니다. 계정을 생성하거나 비밀번호로 로그인하십시오.",
|
||||||
"goHome": "홈으로 가기",
|
"goHome": "홈으로 가기",
|
||||||
"inviteLogInOtherUser": "다른 사용자로 로그인",
|
"inviteLogInOtherUser": "다른 사용자로 로그인",
|
||||||
"createAnAccount": "계정 만들기",
|
"createAnAccount": "계정 만들기",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "공유 가능한 링크 삭제 확인",
|
"shareDeleteConfirm": "공유 가능한 링크 삭제 확인",
|
||||||
"shareQuestionRemove": "이 공유 링크를 삭제하시겠습니까?",
|
"shareQuestionRemove": "이 공유 링크를 삭제하시겠습니까?",
|
||||||
"shareMessageRemove": "삭제되면 링크가 더 이상 작동하지 않으며, 이를 사용하는 모든 사용자는 자원에 대한 접근을 잃게 됩니다.",
|
"shareMessageRemove": "삭제되면 링크가 더 이상 작동하지 않으며, 이를 사용하는 모든 사용자는 자원에 대한 접근을 잃게 됩니다.",
|
||||||
"shareTokenDescription": "액세스 토큰은 쿼리 매개변수 또는 요청 헤더의 두 가지 방법으로 전달될 수 있습니다. 이는 인증된 액세스를 위해 클라이언트에서 모든 요청마다 전달되어야 합니다.",
|
"shareTokenDescription": "액세스 토큰은 쿼리 매개변수로 또는 요청 헤더에 전달될 수 있습니다. 기본적으로 모든 요청에 포함되어야 합니다. 세션 지속이 활성화된 경우, 첫 번째 요청이 세션 쿠키로 교환됩니다.",
|
||||||
"accessToken": "액세스 토큰",
|
"accessToken": "액세스 토큰",
|
||||||
"usageExamples": "사용 예",
|
"usageExamples": "사용 예",
|
||||||
"tokenId": "토큰 ID",
|
"tokenId": "토큰 ID",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "제목 (선택 사항)",
|
"shareTitleOptional": "제목 (선택 사항)",
|
||||||
"sharePathOptional": "경로 (선택 사항)",
|
"sharePathOptional": "경로 (선택 사항)",
|
||||||
"sharePathDescription": "링크는 인증 후 이 경로로 사용자를 리디렉션합니다.",
|
"sharePathDescription": "링크는 인증 후 이 경로로 사용자를 리디렉션합니다.",
|
||||||
|
"shareAssociateUserOptional": "사용자 연관 (선택 사항)",
|
||||||
|
"shareAssociateUserDescription": "설정 시, 이 링크를 사용하는 요청은 액세스 로그와 ID 헤더에서 사용자로 기록됩니다. 사용자가 조직을 떠나면 링크가 제거됩니다.",
|
||||||
|
"userSelect": "사용자 선택",
|
||||||
|
"usersNotFound": "사용자를 찾을 수 없습니다",
|
||||||
"expireIn": "만료됨",
|
"expireIn": "만료됨",
|
||||||
"neverExpire": "만료되지 않음",
|
"neverExpire": "만료되지 않음",
|
||||||
|
"sharePersistSession": "첫 사용 후 세션 지속",
|
||||||
|
"sharePersistSessionDescription": "활성화된 경우, 쿼리 매개변수나 헤더를 통해 이 토큰으로 첫 요청 시 세션 쿠키가 설정되어 이후 요청에는 토큰이 필요하지 않습니다. 모든 요청에 토큰을 포함해야 하는 API 클라이언트의 경우, 이 옵션을 해제하세요.",
|
||||||
"shareExpireDescription": "만료 시간은 링크가 사용 가능하고 리소스에 접근할 수 있는 기간입니다. 이 시간이 지나면 링크는 더 이상 작동하지 않으며, 이 링크를 사용한 사용자는 리소스에 대한 접근 권한을 잃게 됩니다.",
|
"shareExpireDescription": "만료 시간은 링크가 사용 가능하고 리소스에 접근할 수 있는 기간입니다. 이 시간이 지나면 링크는 더 이상 작동하지 않으며, 이 링크를 사용한 사용자는 리소스에 대한 접근 권한을 잃게 됩니다.",
|
||||||
"shareSeeOnce": "이 링크는 한 번만 볼 수 있습니다. 반드시 복사해 두세요.",
|
"shareSeeOnce": "이 링크는 한 번만 볼 수 있습니다. 반드시 복사해 두세요.",
|
||||||
"shareAccessHint": "이 링크가 있는 누구나 리소스에 접근할 수 있습니다. 주의해서 공유하세요.",
|
"shareAccessHint": "이 링크가 있는 누구나 리소스에 접근할 수 있습니다. 주의해서 공유하세요.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "국가를 찾을 수 없습니다.",
|
"noCountryFound": "국가를 찾을 수 없습니다.",
|
||||||
"siteSelectionDescription": "이 사이트는 대상에 대한 연결을 제공합니다.",
|
"siteSelectionDescription": "이 사이트는 대상에 대한 연결을 제공합니다.",
|
||||||
"resourceType": "리소스 유형",
|
"resourceType": "리소스 유형",
|
||||||
"resourceTypeDescription": "이것은 리소스 프로토콜 및 브라우저에서 렌더링되는 방식에 영향을 줍니다. 나중에 변경할 수 없습니다.",
|
"resourceTypeDescription": "이 리소스 프로토콜을 제어하며 나중에 변경할 수 없습니다.",
|
||||||
|
"resourceTypeSearch": "리소스 유형 검색...",
|
||||||
|
"resourceTypeNotFound": "리소스 유형이 발견되지 않았습니다",
|
||||||
|
"resourceTypeHttpDescription": "도메인 이름을 사용하여 HTTPS를 통한 웹 트래픽 프록시",
|
||||||
|
"resourceTypeInferenceDescription": "연결된 공급자를 통해 AI 요청을 라우팅",
|
||||||
|
"resourceTypeSshDescription": "브라우저에서 SSH 서버에 액세스",
|
||||||
|
"resourceTypeRdpDescription": "브라우저에서 원격 데스크톱에 액세스",
|
||||||
|
"resourceTypeVncDescription": "브라우저에서 VNC 데스크톱에 액세스",
|
||||||
|
"resourceTypeTcpDescription": "포트 번호를 사용하여 원시 TCP 트래픽 프록시",
|
||||||
|
"resourceTypeUdpDescription": "포트 번호를 사용하여 원시 UDP 트래픽 프록시",
|
||||||
|
"privateResourceTypeDescription": "클라이언트가 리소스에 도달하는 방법을 제어합니다. 나중에 변경할 수 없습니다.",
|
||||||
|
"privateResourceTypeHostDescription": "연결된 클라이언트에게 사이트 네트워크에서 단일 호스트를 노출",
|
||||||
|
"privateResourceTypeCidrDescription": "연결된 클라이언트에게 사이트 네트워크에서 CIDR 범위를 노출",
|
||||||
|
"privateResourceTypeHttpDescription": "도메인을 통해 HTTP 또는 HTTPS 서비스에 액세스",
|
||||||
|
"privateResourceTypeSshDescription": "연결된 클라이언트에서 SSH 서버에 액세스",
|
||||||
"resourceDomainDescription": "리소스는 숙주 네임에서 제공됩니다.",
|
"resourceDomainDescription": "리소스는 숙주 네임에서 제공됩니다.",
|
||||||
"resourceHTTPSSettings": "HTTPS 설정",
|
"resourceHTTPSSettings": "HTTPS 설정",
|
||||||
"resourceHTTPSSettingsDescription": "리소스가 HTTPS로 접근할 수 있는 방식을 구성합니다.",
|
"resourceHTTPSSettingsDescription": "리소스가 HTTPS로 접근할 수 있는 방식을 구성합니다.",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "프로비저닝",
|
"provisioningManage": "프로비저닝",
|
||||||
"provisioningDescription": "프로비저닝 키를 관리하고 승인을 기다리는 사이트를 검토합니다.",
|
"provisioningDescription": "프로비저닝 키를 관리하고 승인을 기다리는 사이트를 검토합니다.",
|
||||||
"pendingSites": "대기중인 사이트",
|
"pendingSites": "대기중인 사이트",
|
||||||
"siteApproveSuccess": "사이트가 성공적으로 승인되었습니다",
|
"siteApproveSuccess": "사이트 및 관련 리소스가 성공적으로 승인되었습니다",
|
||||||
"siteApproveError": "사이트 승인 오류",
|
"siteApproveError": "사이트 승인 오류",
|
||||||
|
"siteReject": "사이트 거부",
|
||||||
|
"siteQuestionReject": "이 사이트를 거부하시겠습니까?",
|
||||||
|
"siteMessageReject": "이렇게 하면 펜딩 중인 사이트 및 관련 리소스가 영구적으로 삭제됩니다.",
|
||||||
|
"siteConfirmReject": "사이트 거부 확인",
|
||||||
|
"siteRejectSuccess": "사이트가 성공적으로 거부되었습니다",
|
||||||
|
"siteRejectError": "사이트 거부 오류",
|
||||||
"provisioningKeys": "프로비저닝 키",
|
"provisioningKeys": "프로비저닝 키",
|
||||||
"searchProvisioningKeys": "프로비저닝 키 검색...",
|
"searchProvisioningKeys": "프로비저닝 키 검색...",
|
||||||
"provisioningKeysAdd": "프로비저닝 키 생성",
|
"provisioningKeysAdd": "프로비저닝 키 생성",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "절대",
|
"provisioningKeysNeverUsed": "절대",
|
||||||
"provisioningKeysEdit": "프로비저닝 키 수정",
|
"provisioningKeysEdit": "프로비저닝 키 수정",
|
||||||
"provisioningKeysEditDescription": "이 키의 최대 배치 크기 및 만료 시간을 업데이트하세요.",
|
"provisioningKeysEditDescription": "이 키의 최대 배치 크기 및 만료 시간을 업데이트하세요.",
|
||||||
"provisioningKeysApproveNewSites": "새로운 사이트 승인",
|
"provisioningKeysApproveNewSites": "새 사이트 승인",
|
||||||
"provisioningKeysApproveNewSitesDescription": "이 키를 등록하는 사이트를 자동으로 승인합니다.",
|
"provisioningKeysApproveNewSitesDescription": "이 키를 등록하는 사이트를 자동으로 승인합니다.",
|
||||||
"provisioningKeysUpdateError": "프로비저닝 키 업데이트 오류",
|
"provisioningKeysUpdateError": "프로비저닝 키 업데이트 오류",
|
||||||
"provisioningKeysUpdated": "프로비저닝 키가 업데이트되었습니다",
|
"provisioningKeysUpdated": "프로비저닝 키가 업데이트되었습니다",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "설정 저장",
|
"authMethodsSave": "설정 저장",
|
||||||
"policyAuthStackTitle": "인증",
|
"policyAuthStackTitle": "인증",
|
||||||
"policyAuthStackDescription": "이 리소스에 접근하려면 어떤 인증 방법이 필요한지 제어합니다",
|
"policyAuthStackDescription": "이 리소스에 접근하려면 어떤 인증 방법이 필요한지 제어합니다",
|
||||||
|
"policyAuthInferenceStackDescription": "이 AI 게이트웨이에 인증할 수 있는 사용자 및 역할을 선택하십시오",
|
||||||
"policyAuthOrLogicTitle": "다수의 인증 방법 활성화",
|
"policyAuthOrLogicTitle": "다수의 인증 방법 활성화",
|
||||||
"policyAuthOrLogicBanner": "방문자는 아래 활성화된 방법 중 하나만을 선택하여 인증할 수 있습니다. 모든 방법을 완료할 필요는 없습니다.",
|
"policyAuthOrLogicBanner": "방문자는 아래 활성화된 방법 중 하나만을 선택하여 인증할 수 있습니다. 모든 방법을 완료할 필요는 없습니다.",
|
||||||
"policyAuthMethodActive": "활성화",
|
"policyAuthMethodActive": "활성화",
|
||||||
"policyAuthMethodOff": "비활성화",
|
"policyAuthMethodOff": "비활성화",
|
||||||
"policyAuthSsoTitle": "플랫폼 SSO",
|
"policyAuthSsoTitle": "플랫폼 SSO",
|
||||||
"policyAuthSsoDescription": "사용자의 아이덴티티 공급자를 통해 로그인 필요",
|
"policyAuthSsoDescription": "사용자의 아이덴티티 공급자를 통해 로그인 필요",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "로그인 URL",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "모든 사용자는 이미 ID API 키를 보유하고 있으므로 비사용자 클라이언트 또는 공유 액세스를 위한 가상 API 키만 생성하면 됩니다. 사용자는 이 리소스의 URL에서 ID 공급자로 로그인하면 키를 검색할 수 있습니다.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "모든 사용자는 이미 ID API 키를 보유하고 있으므로 비사용자 클라이언트 또는 공유 액세스를 위한 가상 API 키만 생성하면 됩니다. 사용자는 여기서 ID 공급자로 로그인 후 키를 검색할 수 있습니다.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} 사용자, {roles} 역할",
|
"policyAuthSsoSummary": "{idp} · {users} 사용자, {roles} 역할",
|
||||||
"policyAuthSsoDefaultIdp": "기본 공급자",
|
"policyAuthSsoDefaultIdp": "기본 공급자",
|
||||||
"policyAuthAddDefaultIdentityProvider": "기본 아이덴티티 공급자 추가",
|
"policyAuthAddDefaultIdentityProvider": "기본 아이덴티티 공급자 추가",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "버전",
|
"newtVersion": "버전",
|
||||||
"architecture": "아키텍처",
|
"architecture": "아키텍처",
|
||||||
"sites": "사이트",
|
"sites": "사이트",
|
||||||
"siteWgAnyClients": "WireGuard 클라이언트를 사용하여 연결하십시오. 피어 IP를 사용하여 내부 리소스에 접근해야 합니다.",
|
"siteWgAnyClients": "WireGuard 클라이언트를 사용하여 연결하십시오. 피어 IP를 사용하여 개인 리소스에 접근해야 합니다.",
|
||||||
"siteWgCompatibleAllClients": "모든 WireGuard 클라이언트와 호환",
|
"siteWgCompatibleAllClients": "모든 WireGuard 클라이언트와 호환",
|
||||||
"siteWgManualConfigurationRequired": "수동 구성이 필요합니다.",
|
"siteWgManualConfigurationRequired": "수동 구성이 필요합니다.",
|
||||||
"userErrorNotAdminOrOwner": "사용자는 관리자 또는 소유자가 아닙니다.",
|
"userErrorNotAdminOrOwner": "사용자는 관리자 또는 소유자가 아닙니다.",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "새 역할이 필요합니다.",
|
"accessRoleErrorNewRequired": "새 역할이 필요합니다.",
|
||||||
"accessRoleErrorRemove": "역할 제거에 실패했습니다.",
|
"accessRoleErrorRemove": "역할 제거에 실패했습니다.",
|
||||||
"accessRoleErrorRemoveDescription": "역할을 제거하는 동안 오류가 발생했습니다.",
|
"accessRoleErrorRemoveDescription": "역할을 제거하는 동안 오류가 발생했습니다.",
|
||||||
|
"accessRoleInferenceBudget": "AI 예산",
|
||||||
|
"accessRoleInferenceBudgetDescription": "이 역할의 구성원이 AI 사용을 지출 또는 토큰 제한에 따라 제한하는 방법을 구성하십시오",
|
||||||
"accessRoleName": "역할 이름",
|
"accessRoleName": "역할 이름",
|
||||||
"accessRoleQuestionRemove": "`{name}` 역할을 삭제하려고 합니다. 이 작업은 되돌릴 수 없습니다.",
|
"accessRoleQuestionRemove": "`{name}` 역할을 삭제하려고 합니다. 이 작업은 되돌릴 수 없습니다.",
|
||||||
"accessRoleRemove": "역할 제거",
|
"accessRoleRemove": "역할 제거",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "조직 사용자 생성",
|
"createOrgUser": "조직 사용자 생성",
|
||||||
"actionUpdateOrg": "조직 업데이트",
|
"actionUpdateOrg": "조직 업데이트",
|
||||||
"actionRemoveInvitation": "초대 제거",
|
"actionRemoveInvitation": "초대 제거",
|
||||||
|
"actionRemoveUserRole": "사용자 역할 제거",
|
||||||
"actionUpdateUser": "사용자 업데이트",
|
"actionUpdateUser": "사용자 업데이트",
|
||||||
"actionGetUser": "사용자 조회",
|
"actionGetUser": "사용자 조회",
|
||||||
"actionGetOrgUser": "조직 사용자 가져오기",
|
"actionGetOrgUser": "조직 사용자 가져오기",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "사이트 삭제",
|
"actionDeleteSite": "사이트 삭제",
|
||||||
"actionGetSite": "사이트 가져오기",
|
"actionGetSite": "사이트 가져오기",
|
||||||
"actionListSites": "사이트 목록",
|
"actionListSites": "사이트 목록",
|
||||||
|
"actionCreateAiProvider": "AI 공급자 생성",
|
||||||
|
"actionDeleteAiProvider": "AI 공급자 삭제",
|
||||||
|
"actionGetAiProvider": "AI 공급자 가져오기",
|
||||||
|
"actionListAiProviders": "AI 공급자 목록",
|
||||||
|
"actionUpdateAiProvider": "AI 공급자 업데이트",
|
||||||
|
"actionCreateAiModel": "AI 모델 생성",
|
||||||
|
"actionDeleteAiModel": "AI 모델 삭제",
|
||||||
|
"actionGetAiModel": "AI 모델 가져오기",
|
||||||
|
"actionListAiModels": "AI 모델 목록",
|
||||||
|
"actionUpdateAiModel": "AI 모델 업데이트",
|
||||||
|
"actionCreateAiBudget": "AI 예산 생성",
|
||||||
|
"actionDeleteAiBudget": "AI 예산 삭제",
|
||||||
|
"actionGetAiBudget": "AI 예산 가져오기",
|
||||||
|
"actionListAiBudgets": "AI 예산 목록",
|
||||||
|
"actionUpdateAiBudget": "AI 예산 업데이트",
|
||||||
|
"actionListResourceAiModels": "리소스 AI 모델 목록",
|
||||||
|
"actionSetResourceAiModels": "리소스 AI 모델 설정",
|
||||||
|
"actionCreateVirtualApiKey": "가상 API 키 생성",
|
||||||
|
"actionDeleteVirtualApiKey": "가상 API 키 삭제",
|
||||||
|
"actionGetVirtualApiKey": "가상 API 키 가져오기",
|
||||||
|
"actionListVirtualApiKeys": "가상 API 키 목록",
|
||||||
|
"actionUpdateVirtualApiKey": "가상 API 키 업데이트",
|
||||||
"actionApplyBlueprint": "청사진 적용",
|
"actionApplyBlueprint": "청사진 적용",
|
||||||
"actionListBlueprints": "청사진 목록",
|
"actionListBlueprints": "청사진 목록",
|
||||||
"actionGetBlueprint": "청사진 가져오기",
|
"actionGetBlueprint": "청사진 가져오기",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "서버 콘솔에서 설정 토큰 입력.",
|
"setupTokenDescription": "서버 콘솔에서 설정 토큰 입력.",
|
||||||
"setupTokenRequired": "설정 토큰이 필요합니다",
|
"setupTokenRequired": "설정 토큰이 필요합니다",
|
||||||
"actionUpdateSite": "사이트 업데이트",
|
"actionUpdateSite": "사이트 업데이트",
|
||||||
|
"actionApproveSite": "사이트 승인",
|
||||||
|
"actionRejectSite": "사이트 거부",
|
||||||
"actionResetSiteBandwidth": "조직 대역폭 재설정",
|
"actionResetSiteBandwidth": "조직 대역폭 재설정",
|
||||||
"actionListSiteRoles": "허용된 사이트 역할 목록",
|
"actionListSiteRoles": "허용된 사이트 역할 목록",
|
||||||
"actionCreateResource": "리소스 생성",
|
"actionCreateResource": "리소스 생성",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "리소스 핀코드 설정",
|
"actionSetResourcePincode": "리소스 핀코드 설정",
|
||||||
"actionSetResourceEmailWhitelist": "리소스 이메일 화이트리스트 설정",
|
"actionSetResourceEmailWhitelist": "리소스 이메일 화이트리스트 설정",
|
||||||
"actionGetResourceEmailWhitelist": "리소스 이메일 화이트리스트 가져오기",
|
"actionGetResourceEmailWhitelist": "리소스 이메일 화이트리스트 가져오기",
|
||||||
|
"actionListResourcePolicies": "리소스 정책 목록",
|
||||||
|
"actionCreateResourcePolicy": "리소스 정책 생성",
|
||||||
"actionGetResourcePolicy": "리소스 정책 가져오기",
|
"actionGetResourcePolicy": "리소스 정책 가져오기",
|
||||||
"actionUpdateResourcePolicy": "리소스 정책 업데이트",
|
"actionUpdateResourcePolicy": "리소스 정책 업데이트",
|
||||||
|
"actionDeleteResourcePolicy": "리소스 정책 삭제",
|
||||||
"actionSetResourcePolicyUsers": "리소스 정책 사용자 설정",
|
"actionSetResourcePolicyUsers": "리소스 정책 사용자 설정",
|
||||||
"actionSetResourcePolicyRoles": "리소스 정책 역할 설정",
|
"actionSetResourcePolicyRoles": "리소스 정책 역할 설정",
|
||||||
"actionSetResourcePolicyPassword": "리소스 정책 비밀번호 설정",
|
"actionSetResourcePolicyPassword": "리소스 정책 비밀번호 설정",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "초대 목록",
|
"actionListInvitations": "초대 목록",
|
||||||
"actionExportLogs": "로그 내보내기",
|
"actionExportLogs": "로그 내보내기",
|
||||||
"actionViewLogs": "로그 보기",
|
"actionViewLogs": "로그 보기",
|
||||||
|
"actionCreateSiteProvisioningKey": "사이트 프로비저닝 키 생성",
|
||||||
|
"actionListSiteProvisioningKeys": "사이트 프로비저닝 키 목록",
|
||||||
|
"actionUpdateSiteProvisioningKey": "사이트 프로비저닝 키 업데이트",
|
||||||
|
"actionDeleteSiteProvisioningKey": "사이트 프로비저닝 키 삭제",
|
||||||
"noneSelected": "선택된 항목 없음",
|
"noneSelected": "선택된 항목 없음",
|
||||||
"orgNotFound2": "조직이 없습니다.",
|
"orgNotFound2": "조직이 없습니다.",
|
||||||
"search": "검색…",
|
"search": "검색…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "인증 앱에서 코드를 입력하거나 단일 사용 백업 코드 중 하나를 입력하세요.",
|
"otpAuthDescription": "인증 앱에서 코드를 입력하거나 단일 사용 백업 코드 중 하나를 입력하세요.",
|
||||||
"otpAuthSubmit": "코드 제출",
|
"otpAuthSubmit": "코드 제출",
|
||||||
"idpContinue": "또는 계속 진행하십시오.",
|
"idpContinue": "또는 계속 진행하십시오.",
|
||||||
|
"idpLastUsed": "마지막 사용",
|
||||||
"otpAuthBack": "비밀번호로 돌아가기",
|
"otpAuthBack": "비밀번호로 돌아가기",
|
||||||
"navbar": "탐색 메뉴",
|
"navbar": "탐색 메뉴",
|
||||||
"navbarDescription": "애플리케이션의 주요 탐색 메뉴",
|
"navbarDescription": "애플리케이션의 주요 탐색 메뉴",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "머신 클라이언트 생성",
|
"commandPaletteCreateMachineClient": "머신 클라이언트 생성",
|
||||||
"commandPaletteCreateAlertRule": "경고 규칙 생성",
|
"commandPaletteCreateAlertRule": "경고 규칙 생성",
|
||||||
"commandPaletteCreateIdentityProvider": "신원 공급자 생성",
|
"commandPaletteCreateIdentityProvider": "신원 공급자 생성",
|
||||||
|
"commandPaletteCreateAiProvider": "AI 공급자 생성",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "가상 API 키 생성",
|
||||||
"commandPaletteToggleTheme": "테마 전환",
|
"commandPaletteToggleTheme": "테마 전환",
|
||||||
"commandPaletteChooseOrganization": "조직 선택",
|
"commandPaletteChooseOrganization": "조직 선택",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "초대",
|
"sidebarInvitations": "초대",
|
||||||
"sidebarRoles": "역할",
|
"sidebarRoles": "역할",
|
||||||
"sidebarShareableLinks": "공유 가능한 링크",
|
"sidebarShareableLinks": "공유 가능한 링크",
|
||||||
|
"sidebarAiGateway": "AI 게이트웨이",
|
||||||
|
"sidebarAiProviders": "공급자",
|
||||||
|
"commandAiProviders": "AI 공급자",
|
||||||
|
"sidebarVirtualApiKeys": "가상 API 키",
|
||||||
|
"sidebarMyApiKeys": "귀하의 API 키",
|
||||||
|
"sidebarAccount": "실행기",
|
||||||
|
"commandVirtualApiKeys": "가상 API 키",
|
||||||
|
"virtualApiKeysTitle": "가상 API 키 관리",
|
||||||
|
"virtualApiKeysDescription": "공용 AI 게이트웨이에 대한 AI 게이트웨이 액세스를 위한 수동 API 키 생성 및 관리",
|
||||||
|
"virtualApiKeysTabIdentity": "신원 키",
|
||||||
|
"virtualApiKeysTabVirtual": "가상 키",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "모든 사용자에 대한 신원 키",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "이 조직을 위한 Pangolin 신원 키가 모든 사용자에게 이미 있습니다. 계정에 고유하며 액세스할 수 있는 AI 게이트웨이에 인증합니다.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "예시",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "사용자가 키 받는 방법",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "브라우저에서 공용 AI 게이트웨이 URL을 방문하고 계정으로 로그인합니다.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "<url></url>을 방문하여 로그인한 상태에서 이동하십시오.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "추가 가상 API 키를 가상 키 탭에서 생성할 수 있습니다. 이러한 키는 특정 공용 AI 게이트웨이에 범위를 지정할 수 있으며, 선택적으로 사용자와 연결할 수 있습니다. 키 생성 즉시 선택된 공용 AI 게이트웨이에 대한 액세스 권한이 부여됩니다.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "키 수동 생성",
|
||||||
|
"virtualApiKeysEmailIdentity": "이메일 신원 키",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "선택한 각 사용자 또는 역할에게 Pangolin 신원 키 보내기.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "모든 사용자에게 보내기",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "계정 이메일이 있는 모든 조직 구성원에게 이메일 발송.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "사용자",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "역할",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "이메일 보내기",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "신원 키 전송",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "{sent}개의 이메일이 전송되었습니다.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped}명의 사용자가 이메일 주소가 없어 건너뛰었습니다.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "최소한 하나의 사용자 또는 역할을 선택하거나 모든 사용자에게 보냅니다.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "신원 키 전송 오류",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "신원 키 이메일 전송 실패",
|
||||||
|
"virtualApiKeysBannerTitle": "모든 사용자에 대한 신원 키",
|
||||||
|
"virtualApiKeysBannerDescription": "모든 사용자는 {keysUrl}에서 신원 키를 이미 사용할 수 있습니다. 공용 AI 게이트웨이에 대한 직접 액세스를 부여하는 키를 수동으로 여기에서 생성할 수도 있습니다.",
|
||||||
|
"virtualApiKeysBannerButtonText": "신원 키 보기",
|
||||||
|
"virtualApiKeys": "가상 API 키",
|
||||||
|
"virtualApiKeysSearch": "키 검색...",
|
||||||
|
"virtualApiKeysCreate": "가상 API 키 생성",
|
||||||
|
"virtualApiKeysCreateDescription": "이 조직의 공용 AI 게이트웨이를 호출할 수 있는 수동 키 발급",
|
||||||
|
"virtualApiKeysCreateButton": "키 생성",
|
||||||
|
"virtualApiKeysEmpty": "가상 API 키가 아직 없습니다",
|
||||||
|
"virtualApiKeysName": "이름",
|
||||||
|
"virtualApiKeysDescriptionOptional": "설명 (선택사항)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "사용자 연결 (선택사항)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "이 키를 사용자와 연결하여 사용을 추적합니다. 생성되면 선택한 공용 AI 게이트웨이에 즉시 액세스 권한이 부여됩니다. 수동으로 리소스와 연결할 필요가 없습니다. 키는 사용자의 프로필에도 표시됩니다.",
|
||||||
|
"virtualApiKeysAllResources": "모든 공용 AI 게이트웨이",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "이 키가 조직의 모든 공용 AI 게이트웨이에 액세스할 수 있도록 허용",
|
||||||
|
"virtualApiKeysSelectResources": "공용 AI 게이트웨이",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "리소스 선택",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "이 키가 액세스할 수 있는 공용 AI 게이트웨이를 선택하십시오",
|
||||||
|
"virtualApiKeysNoResources": "리소스 없음",
|
||||||
|
"virtualApiKeysSecret": "키",
|
||||||
|
"virtualApiKeysCopyKey": "이 키를 복사하십시오. 나중에 표에서 또는 편집할 때 다시 볼 수 있습니다.",
|
||||||
|
"virtualApiKeysViewSecret": "비밀 보기",
|
||||||
|
"virtualApiKeysViewSecretTitle": "가상 API 키 비밀",
|
||||||
|
"virtualApiKeysViewSecretDescription": "이 비밀은 이 키에 할당된 공용 AI 게이트웨이에 대한 액세스를 부여합니다",
|
||||||
|
"virtualApiKeysEdit": "가상 API 키 편집",
|
||||||
|
"virtualApiKeysEditDescription": "이 키의 관련 사용자 및 공용 AI 게이트웨이 액세스를 업데이트하십시오",
|
||||||
|
"virtualApiKeysSaveButton": "변경 사항 저장",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "최소한 하나의 공용 AI 게이트웨이를 선택하거나 모든 공용 AI 게이트웨이를 활성화하십시오",
|
||||||
|
"virtualApiKeysUpdated": "가상 API 키가 업데이트되었습니다",
|
||||||
|
"virtualApiKeysUpdatedDescription": "가상 API 키가 업데이트되었습니다",
|
||||||
|
"virtualApiKeysErrorUpdate": "가상 API 키 업데이트 오류",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "가상 API 키 업데이트에 실패했습니다",
|
||||||
|
"virtualApiKeysErrorCreate": "가상 API 키 생성 오류",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "가상 API 키 생성에 실패했습니다",
|
||||||
|
"virtualApiKeysErrorDelete": "가상 API 키 삭제 오류",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "가상 API 키 삭제에 실패했습니다",
|
||||||
|
"virtualApiKeysDeleted": "가상 API 키가 삭제되었습니다",
|
||||||
|
"virtualApiKeysDeletedDescription": "가상 API 키가 삭제되었습니다",
|
||||||
|
"virtualApiKeysDelete": "가상 API 키 삭제",
|
||||||
|
"virtualApiKeysDeleteConfirm": "키 삭제",
|
||||||
|
"virtualApiKeysQuestionRemove": "이 가상 API 키를 삭제하시겠습니까?",
|
||||||
|
"virtualApiKeysMessageRemove": "이 키를 사용하는 클라이언트는 즉시 액세스를 잃습니다.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "비밀 로딩 오류",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "가상 API 키 비밀 로딩에 실패했습니다",
|
||||||
|
"virtualApiKeysFilterUnassigned": "할당되지 않음",
|
||||||
|
"virtualApiKeysInferenceBudget": "예산",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "이 키가 지출 또는 토큰 제한에 따라 AI 사용을 제한하는 방법을 구성하십시오",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "생성 시 이메일 키",
|
||||||
|
"virtualApiKeysEmailThisKey": "이 키를 이메일로 발송",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "생성 후 이 키를 관련 사용자 및 추가 주소로 보냅니다",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "현재 키를 관련 사용자 및 추가 주소로 보냅니다",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "이 서버에 이메일 구성이 되어 있지 않습니다",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "가상 API 키를 이메일로 보내려면 SMTP를 구성하십시오.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "관련 사용자에게 전송",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "관련 사용자의 계정 이메일로 키 전송",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "키를 해당 사용자에게 보내기 위해 사용자를 연결하십시오",
|
||||||
|
"virtualApiKeysEmailAdditional": "추가 이메일",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "이메일을 추가하고 Enter를 누르십시오",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "관련 사용자를 선택하거나 최소한 하나의 이메일 주소를 추가하십시오",
|
||||||
|
"myVirtualApiKeysTitle": "귀하의 API 키",
|
||||||
|
"myVirtualApiKeysDescription": "이 조직에서 자신에게 할당된 신원 키 및 가상 API 키를 확인하십시오",
|
||||||
|
"myVirtualApiKeysResourceTitle": "{resourceName}에 대한 귀하의 API 키",
|
||||||
|
"myVirtualApiKeysResourceDescription": "{resourceName}에 액세스할 수 있도록 귀하에게 할당된 신원 키 및 가상 API 키를 확인하십시오",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "신원 키",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "개인 API 키",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "이 조직에 대한 귀하의 개인 키입니다. AI 게이트웨이 리소스를 호출할 때 귀하를 식별하는 데 사용됩니다.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "{resourceName}에 대한 귀하의 개인 API 키",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "이 조직에 대한 귀하의 개인 키입니다. {resourceName}을 호출하는 데 사용하십시오.",
|
||||||
|
"myVirtualApiKeysManualTitle": "귀속 키",
|
||||||
|
"myVirtualApiKeysManualDescription": "관리자가 귀하의 계정에 연결한 수동 가상 API 키",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "{resourceName}에 액세스할 수 있는 귀하의 계정에 연결된 수동 가상 API 키",
|
||||||
|
"myVirtualApiKeysManualEmpty": "아직 귀속된 키가 없습니다",
|
||||||
|
"myVirtualApiKeysKindUser": "신원",
|
||||||
|
"myVirtualApiKeysKindManual": "수동",
|
||||||
|
"myVirtualApiKeysUnnamed": "이름 없는 키",
|
||||||
|
"myVirtualApiKeysRevealSecret": "비밀 공개",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "이 비밀은 AI 게이트웨이 리소스에 대한 귀하의 인증을 수행합니다",
|
||||||
|
"aiClientConfigTitle": "코딩 에이전트 구성",
|
||||||
|
"aiClientConfigDescription": "인기 코딩 에이전트의 구성을 복사하거나 Pangolin CLI가 자동으로 설정하도록 하세요.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Anthropic의 터미널 에이전트 코딩 도구입니다.",
|
||||||
|
"aiClientConfigDescriptionCodex": "OpenAI의 터미널 에이전트 코딩 도구입니다.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "오픈 소스 터미널 코딩 에이전트.",
|
||||||
|
"aiClientConfigDescriptionCursor": "VS Code를 기반으로 한 AI 코드 편집기.",
|
||||||
|
"aiClientConfigSetup": "설정",
|
||||||
|
"aiClientConfigTabCli": "자동 (CLI)",
|
||||||
|
"aiClientConfigTabManual": "수동 구성",
|
||||||
|
"aiClientConfigPreset": "설정",
|
||||||
|
"aiClientConfigStep": "단계 {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "이 스니펫에는 모델 이름이나 리소스 URL과 같은 예제 값이 포함되어 있습니다. 사용하기 전에 이를 고유 값으로 바꾸세요.",
|
||||||
|
"aiClientConfigRevealError": "API 키를 로드할 수 없습니다.",
|
||||||
|
"aiClientConfigRevealRetry": "다시 시도하십시오",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "이 리소스는 Claude Code 및 OpenCode와 같은 일반적인 클라이언트에서 사용할 수 있습니다. <configLink>더 알아보기</configLink>",
|
||||||
|
"aiProvidersTitle": "AI 공급자",
|
||||||
|
"aiProvidersDescription": "이 조직의 AI 작업량에 대한 모델 공급자를 연결하십시오",
|
||||||
|
"aiProvidersBannerTitle": "모델 공급자 연결",
|
||||||
|
"aiProvidersBannerDescription": "공급자는 AI 작업량을 위한 백엔드 모델입니다. 여기에서 OpenAI, Anthropic 및 기타 공급자를 연결한 다음 공용 AI 게이트웨이에 연결하여 사용자가 정체성 인식 액세스, 예산 및 로깅으로 모델을 호출할 수 있도록 하십시오.",
|
||||||
|
"aiProvidersAdd": "공급자 추가",
|
||||||
|
"aiProvidersSearch": "공급자 검색...",
|
||||||
|
"aiProvidersEmpty": "아직 AI 공급자가 없습니다",
|
||||||
|
"aiProviderCreate": "AI 공급자 생성",
|
||||||
|
"aiProviderCreateDescription": "이 조직을 위한 모델 공급자 추가",
|
||||||
|
"aiProviderSeeAll": "모든 공급자 보기",
|
||||||
|
"aiProviderSetting": "{providerName}을 위한 공급자 설정",
|
||||||
|
"aiProviderSettingDescription": "이 AI 공급자 구성을 설정하십시오",
|
||||||
|
"aiProviderGeneral": "일반",
|
||||||
|
"aiProviderGeneralDescription": "이 공급자의 기본 설정",
|
||||||
|
"aiProviderConfiguration": "설정",
|
||||||
|
"aiProviderConfigurationDescription": "이 공급자의 네트워크 라우팅 및 인증 설정",
|
||||||
|
"aiProviderNetworkSettings": "네트워크 설정",
|
||||||
|
"aiProviderNetworkSettingsDescription": "이 공급자로 트래픽을 전달하는 방법을 선택하십시오",
|
||||||
|
"aiProviderAuthSettings": "인증",
|
||||||
|
"aiProviderAuthSettingsDescription": "이 공급자가 업스트림 URL에 대한 요청을 인증하는 방법을 구성하십시오",
|
||||||
|
"aiProviderBudgetSettings": "예산",
|
||||||
|
"aiProviderBudgetSettingsDescription": "이 공급자가 지출 또는 토큰 한도에 따라 사용을 제한하는 방법을 구성하십시오",
|
||||||
|
"aiBudgetAdd": "예산 추가",
|
||||||
|
"aiBudgetEmpty": "아직 예산 구성되지 않았습니다. 예산 추가를 클릭하여 지출 또는 토큰 한도를 설정하십시오.",
|
||||||
|
"aiBudgetUnit": "지출 유형",
|
||||||
|
"aiBudgetPeriod": "재설정 기간",
|
||||||
|
"aiBudgetAmount": "최대 지출",
|
||||||
|
"aiBudgetAmountPlaceholder": "최대 지출",
|
||||||
|
"aiBudgetPeriodHourly": "시간당",
|
||||||
|
"aiBudgetPeriodDaily": "일일",
|
||||||
|
"aiBudgetPeriodWeekly": "주간",
|
||||||
|
"aiBudgetPeriodMonthly": "월간",
|
||||||
|
"aiBudgetPeriodYearly": "연간",
|
||||||
|
"aiBudgetPeriodLifetime": "평생",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "토큰",
|
||||||
|
"aiBudgetConflictError": "이미 이 재설정 기간과 지출 유형에 대한 예산이 존재합니다",
|
||||||
|
"aiBudgetInvalidAmountError": "0보다 큰 최대 지출을 입력하십시오",
|
||||||
|
"aiBudgetUpdated": "예산 업데이트됨",
|
||||||
|
"aiBudgetErrorSave": "예산 업데이트 실패",
|
||||||
|
"aiProviderType": "공급자 유형",
|
||||||
|
"aiProviderTypeSearch": "공급자 검색...",
|
||||||
|
"aiProviderTypeNotFound": "공급자 유형 없음",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "Custom",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Runtime API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "자체 엔드포인트를 가져오거나 사이트 타겟을 통해 라우트하십시오",
|
||||||
|
"aiProviderUpstreamUrl": "상류 URL",
|
||||||
|
"aiProviderUpstreamUrlDescription": "공급자 API의 기본 URL",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "기본 상류 URL 사용을 위해 빈칸으로 두십시오",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "유효 상류 URL",
|
||||||
|
"aiProviderApiKey": "API 키",
|
||||||
|
"aiProviderApiKeyDescription": "이 공급자에 대한 요청을 인증하기 위해 사용하는 API 키",
|
||||||
|
"aiProviderCustomHeadersDescription": "이 공급자에게 보내는 모든 요청에 대해 전송되는 헤더. 새 줄로 구분된: 헤더-이름: 값",
|
||||||
|
"aiProviderApiKeyLastChars": "API 키",
|
||||||
|
"aiProviderAuthType": "인증 유형",
|
||||||
|
"aiProviderAuthTypeSearch": "인증 유형 검색...",
|
||||||
|
"aiProviderAuthTypeNotFound": "인증 유형을 찾을 수 없습니다",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Authorization: Bearer 키. OpenAI 및 대부분의 공급자에서 사용",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-key 헤더. Anthropic에서 사용",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-key 헤더. Google Gemini에서 사용",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Authorization: Splunk 키. Splunk HTTP 이벤트 수집기에서 사용",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI 게이트웨이",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Bearer 키. Cloudflare AI 게이트웨이에서 사용",
|
||||||
|
"aiProviderAuthTypeNone": "인증 없음",
|
||||||
|
"aiProviderAuthTypePassthrough": "통과",
|
||||||
|
"aiProviderAuthTypeDescription": "상류 API에서 요청을 인증하는 방법",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "발신자의 API 키 헤더를 상류로 전달",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "상류로 인증 헤더를 보내지 않음",
|
||||||
|
"aiProviderRoutingMode": "라우팅 모드",
|
||||||
|
"aiProviderRoutingModeDescription": "상류 URL로 트래픽을 보내거나 사이트의 HTTP 타겟으로 보냅니다",
|
||||||
|
"aiProviderRoutingModeUrl": "상류 URL",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "공개 또는 개인 API의 기본 URL 호출",
|
||||||
|
"aiProviderRoutingModeTarget": "사이트 타겟",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "사이트의 타겟을 통해 라우트",
|
||||||
|
"aiProviderRoutingModeTargetNote": "이 공급자를 생성한 후 네트워크 설정 탭에 사이트 타겟을 구성합니다.",
|
||||||
|
"aiProviderTargetNoOne": "이 공급자에게 타겟이 없습니다. 사이트를 통해 요청을 라우트하기 위한 타겟을 추가하십시오.",
|
||||||
|
"aiProviderSkipTlsVerification": "TLS 검증 건너뛰기",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "상류 연결에 대한 TLS 인증서 검증 비활성화",
|
||||||
|
"aiProviderBudget": "예산",
|
||||||
|
"aiProviderBudgetDescription": "이 공급자에 대한 선택적 지출 또는 토큰 예산",
|
||||||
|
"aiProviderBudgetAmount": "예산 금액",
|
||||||
|
"aiProviderBudgetUnit": "예산 단위",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "토큰",
|
||||||
|
"aiProviderEnabled": "활성화됨",
|
||||||
|
"aiProviderEnabledDescription": "모든 리소스에 대해 이 공급자를 완전히 비활성화합니다",
|
||||||
|
"aiProviderErrorCreate": "AI 공급자 생성에 실패했습니다",
|
||||||
|
"aiProviderErrorUpdate": "AI 공급자 업데이트에 실패했습니다",
|
||||||
|
"aiProviderErrorDelete": "AI 공급자 삭제에 실패했습니다",
|
||||||
|
"aiProviderErrorLoad": "AI 공급자 로드에 실패했습니다",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "유효한 상류 URL을 입력하십시오",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "이 공급자에는 상류 URL이 필요합니다",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "인증 유형이 필요합니다",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API 키가 필요합니다",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "사이트 타겟 라우팅은 맞춤형 공급자에게만 가능합니다",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "최소 한 가지 API 기능을 선택하십시오",
|
||||||
|
"aiProviderCapabilities": "API 기능",
|
||||||
|
"aiProviderCapabilitiesDescription": "이 공급자가 처리할 수 있는 API 형식을 선택하십시오. 알려진 공급자는 권장 기본값으로 시작합니다.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "사용자 지정 제공자가 처리할 수 있는 API 형식을 선택하십시오",
|
||||||
|
"aiProviderCapabilitiesSelect": "기능 선택",
|
||||||
|
"aiProviderCapabilitiesEmpty": "능력을 찾을 수 없습니다",
|
||||||
|
"aiProviderCapabilitiesSearch": "능력 검색...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI 채팅 완료",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "/v1/chat/completions 지원",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI 응답",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "/v1/responses 지원",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic 메시지",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "/v1/messages 지원",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini 콘텐츠 생성",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "직접 Gemini API 지원",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Bedrock 모델 실행",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Amazon Bedrock InvokeModel 지원",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex 콘텐츠 생성",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Vertex AI Gemini 형식 지원",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex Raw 예측",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Anthropic 모델에 대한 Vertex AI rawPredict 지원",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock 회화",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Amazon Bedrock Converse API 지원",
|
||||||
|
"aiProviderCreated": "AI 제공자가 생성되었습니다",
|
||||||
|
"aiProviderUpdated": "AI 제공자가 업데이트되었습니다",
|
||||||
|
"aiProviderDeleted": "AI 제공자가 삭제되었습니다",
|
||||||
|
"aiProviderDelete": "제공자 삭제",
|
||||||
|
"aiProviderDeleteConfirm": "제공자 삭제",
|
||||||
|
"aiProviderQuestionRemove": "이 AI 제공자를 삭제하시겠습니까?",
|
||||||
|
"aiProviderMessageRemove": "이 작업을 실행하면 제공자와 해당 모델 및 대상이 영구적으로 삭제됩니다. 이는 되돌릴 수 없습니다.",
|
||||||
|
"aiProviderErrorNoUpdate": "AI 제공자를 업데이트할 수 없습니다",
|
||||||
|
"aiProviderModels": "모델",
|
||||||
|
"aiProviderModelsDescription": "이 제공자에 대한 허용 및 차단 목록을 정의하십시오. 요청은 허용 항목과 일치해야 하며 차단 항목과 일치하지 않아야 합니다.",
|
||||||
|
"aiProviderCreateModelsDescription": "이 제공자가 제공할 수 있는 모델을 선택합니다. 허용 목록이 비어 있으면 모든 트래픽이 거부됩니다. 나중에 모델을 추가하거나 변경할 수 있습니다.",
|
||||||
|
"aiProviderModelsPlaceholder": "모델을 검색하거나 사용자 지정 키를 입력하세요",
|
||||||
|
"aiProviderModelsAllow": "허용 목록",
|
||||||
|
"aiProviderModelsAllowDescription": "이 제공자를 통해 사용할 수 있는 모델입니다. 비어 있으면 모두 거부를 의미합니다.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "모델 키 입력",
|
||||||
|
"aiProviderModelsAllowEmpty": "아직 추가된 모델이 없습니다.",
|
||||||
|
"aiProviderModelsBlock": "차단 목록",
|
||||||
|
"aiProviderModelsBlockDescription": "허용 항목과 일치하더라도 사용할 수 없는 모델입니다.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "모델 키 입력",
|
||||||
|
"aiProviderModelsBlockEmpty": "아직 추가된 모델이 없습니다.",
|
||||||
|
"aiProviderModelsAdd": "모델 추가",
|
||||||
|
"aiProviderModelsClearAll": "모두 지우기",
|
||||||
|
"aiProviderModelsAddCustom": "\"{key}\" 추가",
|
||||||
|
"aiProviderModelsAddCustomHint": "이 사용자 지정 모델 키를 추가하려면 Enter 키를 누르십시오.",
|
||||||
|
"aiProviderModelsAddBulk": "{count}개의 사용자 지정 키 추가",
|
||||||
|
"aiProviderModelsAddBulkHint": "{count}개의 사용자 지정 키를 추가하려면 Enter 키를 누르십시오.",
|
||||||
|
"aiProviderModelsAddOne": "지금 {key} 추가",
|
||||||
|
"aiProviderModelsAddSelected": "선택 항목 추가",
|
||||||
|
"aiProviderModelsSelectedCount": "{count}개 선택됨",
|
||||||
|
"aiProviderModelsSelectAll": "모두 선택",
|
||||||
|
"aiProviderModelsClearSelected": "지우기",
|
||||||
|
"aiProviderModelsBulkHint": "알려진 모델을 선택하거나 사용자 지정 키를 입력하십시오.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "일치하는 카탈로그 모델이 없습니다.",
|
||||||
|
"aiProviderModelsCatalogHeading": "알려진 모델",
|
||||||
|
"aiProviderModelsAllLabel": "모든 모델",
|
||||||
|
"aiProviderModelsAllPatternHint": "와일드카드: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "모든 모델 허용",
|
||||||
|
"aiProviderModelsAddAllBlock": "모델 모두 차단",
|
||||||
|
"aiProviderModelsAddAllDescription": "* 와일드카드를 사용하여 모든 모델 키를 일치시킵니다.",
|
||||||
|
"aiProviderModelsViewMore": "더 보기 ({count})",
|
||||||
|
"aiProviderModelsViewLess": "덜 보기",
|
||||||
|
"aiProviderModelsRemove": "모델 제거",
|
||||||
|
"aiProviderModelsEditHint": "모델 설정을 수정하려면 클릭하세요",
|
||||||
|
"aiProviderModelsSourceCatalog": "알려진 카탈로그 모델",
|
||||||
|
"aiProviderModelsSourceCustom": "사용자 지정 모델 키",
|
||||||
|
"aiProviderModelsSourcePattern": "와일드카드 패턴",
|
||||||
|
"aiProviderModelsSourceAll": "모든 모델 키와 일치",
|
||||||
|
"aiProviderModelsBudgetConfigured": "설정된 예산",
|
||||||
|
"aiProviderModelsEditTitle": "모델 편집",
|
||||||
|
"aiProviderModelsEditDescription": "모델 키를 업데이트하거나 해당 예산을 구성하십시오.",
|
||||||
|
"aiProviderModelsBudgetTab": "예산",
|
||||||
|
"aiProviderModelsKeyLabel": "모델 키",
|
||||||
|
"aiProviderModelsKeyRequired": "모델 키를 입력하십시오",
|
||||||
|
"aiProviderModelsKeyDuplicate": "이 모델 키는 이미 목록에 있습니다",
|
||||||
|
"aiProviderModelsOverlapError": "이 패턴은 두 목록에 모두 있을 수 없습니다: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "모델이 업데이트되었습니다",
|
||||||
|
"aiProviderModelsErrorUpdate": "모델 업데이트에 실패했습니다",
|
||||||
|
"aiResourceProviders": "제공자",
|
||||||
|
"aiResourceProvidersDescription": "이 AI 게이트웨이가 사용할 수 있는 AI 제공자를 선택합니다",
|
||||||
|
"aiResourceProvidersHelp": "공급자를 연결하고 상속(각 공급자의 목록 사용) 또는 선택(이 리소스에 대한 허용 목록 선택)을 선택하십시오. 연결된 공급자 전반에 걸쳐 충돌하는 허용 패턴은 허용되지 않습니다.",
|
||||||
|
"aiResourceProvidersSelect": "공급자 선택",
|
||||||
|
"aiResourceProvidersEmpty": "AI 제공자를 찾을 수 없습니다",
|
||||||
|
"aiResourceProvidersNoneAttached": "아직 연결된 공급자가 없습니다.",
|
||||||
|
"aiResourceProvidersAdd": "제공자 추가",
|
||||||
|
"aiResourceProvidersRemove": "제공자 제거",
|
||||||
|
"aiResourceProviderToggleEnabled": "이 리소스에서 공급자를 활성화하거나 비활성화합니다",
|
||||||
|
"aiResourceProviderDisabled": "사용 중지됨",
|
||||||
|
"aiResourceProvidersUpdated": "공급자가 업데이트되었습니다",
|
||||||
|
"aiResourceProvidersErrorUpdate": "공급자 업데이트에 실패했습니다",
|
||||||
|
"aiResourceProviderEditDescription": "이 공급자의 모델이 리소스에서 어떻게 노출되는지 선택하십시오.",
|
||||||
|
"viewProviderSettings": "제공자 설정 보기",
|
||||||
|
"aiResourceProviderMode": "액세스 모드",
|
||||||
|
"aiResourceProviderModeInherit": "상속",
|
||||||
|
"aiResourceProviderModeSelect": "선택",
|
||||||
|
"aiResourceProviderModeSelectSummary": "선택 · {count} 모델",
|
||||||
|
"aiResourceProviderModeInheritHelp": "공급자에서 구성한 대로 이 공급자의 허용 및 차단 목록을 사용하십시오.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "이 리소스를 위한 공급자의 허용 목록 모델의 하위 집합을 선택하십시오.",
|
||||||
|
"aiResourceProviderAllowModels": "허용 목록",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "모델 선택",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "모델 검색...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "모델을 찾을 수 없습니다",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "제공자의 허용 목록에 있는 모델만 선택할 수 있습니다.",
|
||||||
|
"aiResourceAliasRequired": "AI 게이트웨이에 별칭이 필요합니다",
|
||||||
|
"aiResourceDomainConfiguration": "도메인 구성",
|
||||||
|
"aiResourceDomainConfigurationDescription": "고객이 이 AI 게이트웨이를 사용하기 위해 사용할 도메인을 선택하십시오.",
|
||||||
|
"aiUsageAnalyticsTitle": "AI 사용 분석",
|
||||||
|
"aiUsageAnalyticsDescription": "제공자, 리소스, 역할 및 사용자 간의 AI 게이트웨이 비용, 토큰 사용량 및 활동을 분석합니다",
|
||||||
|
"aiUsageTabOverview": "개요",
|
||||||
|
"aiUsageTabProviders": "공급자",
|
||||||
|
"aiUsageTabResources": "리소스",
|
||||||
|
"aiUsageFilterProvider": "제공자",
|
||||||
|
"aiUsageFilterModel": "모델",
|
||||||
|
"aiUsageFilterResource": "리소스",
|
||||||
|
"aiUsageFilterRole": "역할",
|
||||||
|
"aiUsageFilterUser": "사용자",
|
||||||
|
"aiUsageFilterAllProviders": "모든 공급자",
|
||||||
|
"aiUsageFilterAllModels": "모든 모델",
|
||||||
|
"aiUsageFilterAllResources": "모든 리소스",
|
||||||
|
"aiUsageFilterAllRoles": "모든 역할",
|
||||||
|
"aiUsageFilterAllUsers": "모든 사용자",
|
||||||
|
"aiUsageFilterSearch": "검색...",
|
||||||
|
"aiUsageFilterNotFound": "옵션을 찾을 수 없습니다",
|
||||||
|
"aiUsageResetFilters": "필터 재설정",
|
||||||
|
"aiUsageRefresh": "새로 고침",
|
||||||
|
"aiUsageTokenTypePrompt": "프롬프트",
|
||||||
|
"aiUsageTokenTypeCacheRead": "캐시 읽기",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "캐시 쓰기",
|
||||||
|
"aiUsageTokenTypeCompletion": "완료",
|
||||||
|
"aiUsageTokenTypeReasoning": "추론",
|
||||||
|
"aiUsageRequests": "요청",
|
||||||
|
"aiUsageCost": "비용",
|
||||||
|
"aiUsageTokens": "토큰",
|
||||||
|
"aiUsageOther": "기타",
|
||||||
|
"aiUsageTotalRequests": "총 요청 수",
|
||||||
|
"aiUsageTotalTokens": "총 토큰수",
|
||||||
|
"aiUsageTotalCost": "총 비용",
|
||||||
|
"aiUsageEstimated": "추정치",
|
||||||
|
"aiUsageRequestVolume": "요청량",
|
||||||
|
"aiUsageTokenUsage": "토큰 사용",
|
||||||
|
"aiUsageModelCost": "모델 비용",
|
||||||
|
"aiUsageModelTokens": "모델 토큰",
|
||||||
|
"aiUsageTopModels": "상위 모델",
|
||||||
|
"aiUsageTopProviders": "상위 제공자",
|
||||||
|
"aiUsageProviderCost": "제공자 비용",
|
||||||
|
"aiUsageProviderTokenUsage": "제공자 토큰 사용량",
|
||||||
|
"aiUsageTopResources": "최고의 리소스",
|
||||||
|
"aiUsageResourceCost": "리소스 비용",
|
||||||
|
"aiUsageResourceTokenUsage": "리소스 토큰 사용량",
|
||||||
|
"aiUsageResourceTypePublic": "공용 리소스",
|
||||||
|
"aiUsageResourceTypeSite": "개인 리소스",
|
||||||
|
"aiUsageNoResource": "리소스 없음",
|
||||||
|
"aiUsageRolesTab": "역할",
|
||||||
|
"aiUsageUsersTab": "사용자들",
|
||||||
|
"aiUsageTopRoles": "최고의 역할",
|
||||||
|
"aiUsageRoleCost": "역할 비용",
|
||||||
|
"aiUsageRoleTokenUsage": "역할 토큰 사용량",
|
||||||
|
"aiUsageTopUsers": "최고의 사용자",
|
||||||
|
"aiUsageUserCost": "사용자 비용",
|
||||||
|
"aiUsageUserTokenUsage": "사용자 토큰 사용량",
|
||||||
|
"aiUsageUnknownUser": "알 수 없는 사용자",
|
||||||
|
"aiUsageVirtualApiKeysTab": "가상 API 키",
|
||||||
|
"aiUsageFilterVirtualApiKey": "가상 API 키",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "모든 가상 API 키",
|
||||||
|
"aiUsageTopVirtualApiKeys": "최고의 가상 API 키",
|
||||||
|
"aiUsageVirtualApiKeyCost": "가상 API 키 비용",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "가상 API 키 사용량",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "가상 API 키 없음",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "이름 없는 키",
|
||||||
|
"aiUsageLoading": "로딩 중...",
|
||||||
|
"aiUsageNoData": "데이터 없음",
|
||||||
|
"resourceBudgetSettings": "예산",
|
||||||
|
"resourceBudgetSettingsDescription": "이 AI 게이트웨이가 지출 또는 토큰 제한에 따라 사용을 제한하는 방법을 구성하십시오",
|
||||||
"sidebarApiKeys": "API 키",
|
"sidebarApiKeys": "API 키",
|
||||||
"sidebarProvisioning": "프로비저닝",
|
"sidebarProvisioning": "프로비저닝",
|
||||||
"sidebarSettings": "설정",
|
"sidebarSettings": "설정",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "알림 규칙 저장됨",
|
"alertingRuleSaved": "알림 규칙 저장됨",
|
||||||
"alertingRuleSavedCreatedDescription": "새 알림 규칙이 생성되었습니다. 이 페이지에서 계속 편집할 수 있습니다.",
|
"alertingRuleSavedCreatedDescription": "새 알림 규칙이 생성되었습니다. 이 페이지에서 계속 편집할 수 있습니다.",
|
||||||
"alertingRuleSavedUpdatedDescription": "이 알림 규칙에 대한 변경 사항이 저장되었습니다.",
|
"alertingRuleSavedUpdatedDescription": "이 알림 규칙에 대한 변경 사항이 저장되었습니다.",
|
||||||
|
"alertingTestAlertSent": "테스트 경고 전송됨",
|
||||||
|
"alertingTestAlertSentDescription": "이 규칙에 구성된 조치에 테스트 경고가 전송되었습니다.",
|
||||||
"alertingEditRule": "알림 규칙 편집",
|
"alertingEditRule": "알림 규칙 편집",
|
||||||
"alertingCreateRule": "알림 규칙 생성",
|
"alertingCreateRule": "알림 규칙 생성",
|
||||||
"alertingRuleCredenzaDescription": "무엇을 감시할지, 언제 알릴지, 어떻게 알릴지를 선택하세요.",
|
"alertingRuleCredenzaDescription": "무엇을 감시할지, 언제 알릴지, 어떻게 알릴지를 선택하세요.",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "각 규칙은 무엇을 감시할지(사이트, 상태 확인, 리소스), 언제 발동할지(예: 오프라인 또는 비정상), 이메일, 웹훅 또는 통합을 통해 팀에 어떻게 알릴지를 연결합니다. 이 목록을 사용하여 규칙을 생성, 활성화 및 관리하세요.",
|
"alertingRulesBannerDescription": "각 규칙은 무엇을 감시할지(사이트, 상태 확인, 리소스), 언제 발동할지(예: 오프라인 또는 비정상), 이메일, 웹훅 또는 통합을 통해 팀에 어떻게 알릴지를 연결합니다. 이 목록을 사용하여 규칙을 생성, 활성화 및 관리하세요.",
|
||||||
"alertingHealthChecksBannerTitle": "건강 및 리소스 모니터링",
|
"alertingHealthChecksBannerTitle": "건강 및 리소스 모니터링",
|
||||||
"alertingHealthChecksBannerDescription": "상태 확인은 한 번 정의한 HTTP 또는 TCP 모니터링입니다. 그런 다음 이를 알림 규칙의 소스로 사용하여 타겟이 정상 또는 비정상이 되었을 때 알림을 받을 수 있습니다. 리소스의 상태 확인도 여기에 나타납니다.",
|
"alertingHealthChecksBannerDescription": "상태 확인은 한 번 정의한 HTTP 또는 TCP 모니터링입니다. 그런 다음 이를 알림 규칙의 소스로 사용하여 타겟이 정상 또는 비정상이 되었을 때 알림을 받을 수 있습니다. 리소스의 상태 확인도 여기에 나타납니다.",
|
||||||
|
"alertingTestRule": "테스트 경고 규칙",
|
||||||
|
"alertingAddActionHeading": "새 작업 추가",
|
||||||
|
"alertingSelectActionType": "작업 선택",
|
||||||
|
"alertingNoActionsTitle": "구성된 작업이 없습니다",
|
||||||
|
"alertingNoActionsSaveDescription": "이 규칙이 작동할 때 누군가에게 알리기 위해 적어도 하나의 작업을 추가하십시오.",
|
||||||
|
"alertingNoActionsTestDescription": "이 규칙을 테스트하기 전에 적어도 하나의 작업을 추가하십시오.",
|
||||||
"standaloneHcTableTitle": "상태 확인",
|
"standaloneHcTableTitle": "상태 확인",
|
||||||
"standaloneHcSearchPlaceholder": "상태 확인 검색…",
|
"standaloneHcSearchPlaceholder": "상태 확인 검색…",
|
||||||
"standaloneHcAddButton": "상태 확인 생성",
|
"standaloneHcAddButton": "상태 확인 생성",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "서브도메인: {subdomain}",
|
"domainPickerSubdomain": "서브도메인: {subdomain}",
|
||||||
"domainPickerNamespace": "이름 공간: {namespace}",
|
"domainPickerNamespace": "이름 공간: {namespace}",
|
||||||
"domainPickerShowMore": "더보기",
|
"domainPickerShowMore": "더보기",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "사용 가능한 도메인이 없습니다",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "설정된 도메인이 아직 없습니다. 계속하려면 도메인을 생성하세요.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "도메인으로 이동",
|
||||||
"regionSelectorTitle": "지역 선택",
|
"regionSelectorTitle": "지역 선택",
|
||||||
"domainPickerRemoteExitNodeWarning": "제공된 도메인은 원격 종료 노드에 연결된 사이트에서 지원되지 않습니다. 원격 노드에서 리소스를 사용하려면 사용자 지정 도메인을 사용하십시오.",
|
"domainPickerRemoteExitNodeWarning": "제공된 도메인은 원격 종료 노드에 연결된 사이트에서 지원되지 않습니다. 원격 노드에서 리소스를 사용하려면 사용자 지정 도메인을 사용하십시오.",
|
||||||
"regionSelectorInfo": "지역을 선택하면 위치에 따라 더 나은 성능이 제공됩니다. 서버와 같은 지역에 있을 필요는 없습니다.",
|
"regionSelectorInfo": "지역을 선택하면 위치에 따라 더 나은 성능이 제공됩니다. 서버와 같은 지역에 있을 필요는 없습니다.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "서브넷",
|
"subnetPlaceholder": "서브넷",
|
||||||
"addressDescription": "클라이언트의 내부 주소. 조직의 서브넷 내에 있어야 합니다.",
|
"addressDescription": "클라이언트의 내부 주소. 조직의 서브넷 내에 있어야 합니다.",
|
||||||
"selectSites": "사이트 선택",
|
"selectSites": "사이트 선택",
|
||||||
|
"selectResources": "리소스 선택",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, other {# 자원}}",
|
||||||
"selectLabels": "레이블 선택",
|
"selectLabels": "레이블 선택",
|
||||||
"sitesDescription": "클라이언트는 선택한 사이트에 연결됩니다.",
|
"sitesDescription": "클라이언트는 선택한 사이트에 연결됩니다.",
|
||||||
"clientInstallOlm": "Olm 설치",
|
"clientInstallOlm": "Olm 설치",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "시간은 초 단위입니다",
|
"timeIsInSeconds": "시간은 초 단위입니다",
|
||||||
"requireDeviceApproval": "장치 승인 요구",
|
"requireDeviceApproval": "장치 승인 요구",
|
||||||
"requireDeviceApprovalDescription": "이 역할을 가진 사용자는 장치가 연결되기 전에 관리자의 승인이 필요합니다.",
|
"requireDeviceApprovalDescription": "이 역할을 가진 사용자는 장치가 연결되기 전에 관리자의 승인이 필요합니다.",
|
||||||
"sshSettings": "SSH 설정",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI 게이트웨이",
|
||||||
"sshAccess": "SSH 접속",
|
"sshAccess": "SSH 접속",
|
||||||
"rdpSettings": "RDP 설정",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "VNC 설정",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH 서버",
|
"sshServer": "SSH 서버",
|
||||||
"rdpServer": "RDP 서버",
|
"rdpServer": "RDP 서버",
|
||||||
"vncServer": "VNC 서버",
|
"vncServer": "VNC 서버",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "공유",
|
"resourcesTableProxyResources": "공유",
|
||||||
"resourcesTableClientResources": "비공개",
|
"resourcesTableClientResources": "비공개",
|
||||||
"resourcesTableNoProxyResourcesFound": "프록시 리소스를 찾을 수 없습니다.",
|
"resourcesTableNoProxyResourcesFound": "프록시 리소스를 찾을 수 없습니다.",
|
||||||
"resourcesTableNoInternalResourcesFound": "내부 리소스를 찾을 수 없습니다.",
|
"resourcesTableNoInternalResourcesFound": "개인 리소스를 찾을 수 없습니다.",
|
||||||
"resourcesTableDestination": "대상지",
|
"resourcesTableDestination": "대상지",
|
||||||
"resourcesTableAlias": "별칭",
|
"resourcesTableAlias": "별칭",
|
||||||
"resourcesTableAliasAddress": "별칭 주소",
|
"resourcesTableAliasAddress": "별칭 주소",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "취소",
|
"editInternalResourceDialogCancel": "취소",
|
||||||
"editInternalResourceDialogSaveResource": "리소스 저장",
|
"editInternalResourceDialogSaveResource": "리소스 저장",
|
||||||
"editInternalResourceDialogSuccess": "성공",
|
"editInternalResourceDialogSuccess": "성공",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "내부 리소스가 성공적으로 업데이트되었습니다",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "개인 리소스가 성공적으로 업데이트되었습니다",
|
||||||
"editInternalResourceDialogError": "오류",
|
"editInternalResourceDialogError": "오류",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "내부 리소스 업데이트 실패",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "개인 리소스 업데이트 실패",
|
||||||
"editInternalResourceDialogNameRequired": "이름은 필수입니다.",
|
"editInternalResourceDialogNameRequired": "이름은 필수입니다.",
|
||||||
"editInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.",
|
"editInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.",
|
||||||
"editInternalResourceDialogProxyPortMin": "프록시 포트는 최소 1이어야 합니다.",
|
"editInternalResourceDialogProxyPortMin": "프록시 포트는 최소 1이어야 합니다.",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI 게이트웨이",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "스킴",
|
"editInternalResourceDialogScheme": "스킴",
|
||||||
"editInternalResourceDialogEnableSsl": "TLS 활성화",
|
"editInternalResourceDialogEnableSsl": "TLS 활성화",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "별칭",
|
"editInternalResourceDialogAlias": "별칭",
|
||||||
"editInternalResourceDialogAliasDescription": "이 리소스에 대한 선택적 내부 DNS 별칭입니다.",
|
"editInternalResourceDialogAliasDescription": "이 리소스에 대한 선택적 내부 DNS 별칭입니다.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "사용 가능한 사이트가 없습니다.",
|
"createInternalResourceDialogNoSitesAvailable": "사용 가능한 사이트가 없습니다.",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "내부 리소스를 생성하려면 서브넷이 구성된 최소 하나의 Newt 사이트가 필요합니다.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "개인 리소스를 생성하려면 서브넷이 구성된 최소 하나의 Newt 사이트가 필요합니다.",
|
||||||
"createInternalResourceDialogClose": "닫기",
|
"createInternalResourceDialogClose": "닫기",
|
||||||
"createInternalResourceDialogCreateClientResource": "사이트 리소스 생성",
|
"createInternalResourceDialogCreateClientResource": "사이트 리소스 생성",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "선택한 사이트에 연결된 클라이언트에 접근할 새 리소스를 생성합니다",
|
"createInternalResourceDialogCreateClientResourceDescription": "선택한 사이트에 연결된 클라이언트에 접근할 새 리소스를 생성합니다",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "ICMP 핑 허용",
|
"privateResourceAllowIcmpPing": "ICMP 핑 허용",
|
||||||
"privateResourceNetworkAccess": "네트워크 접근",
|
"privateResourceNetworkAccess": "네트워크 접근",
|
||||||
"privateResourceNetworkAccessDescription": "이 리소스에 대한 TCP/UDP 포트 접근과 ICMP 핑이 허용되는지 여부를 제어합니다.",
|
"privateResourceNetworkAccessDescription": "이 리소스에 대한 TCP/UDP 포트 접근과 ICMP 핑이 허용되는지 여부를 제어합니다.",
|
||||||
"hostSettings": "호스트 설정",
|
"hostSettings": "호스트",
|
||||||
"cidrSettings": "CIDR 설정",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "리소스 속성",
|
"createInternalResourceDialogResourceProperties": "리소스 속성",
|
||||||
"createInternalResourceDialogName": "이름",
|
"createInternalResourceDialogName": "이름",
|
||||||
"createInternalResourceDialogSite": "사이트",
|
"createInternalResourceDialogSite": "사이트",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "취소",
|
"createInternalResourceDialogCancel": "취소",
|
||||||
"createInternalResourceDialogCreateResource": "리소스 생성",
|
"createInternalResourceDialogCreateResource": "리소스 생성",
|
||||||
"createInternalResourceDialogSuccess": "성공",
|
"createInternalResourceDialogSuccess": "성공",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "내부 리소스가 성공적으로 생성되었습니다.",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "개인 리소스가 성공적으로 생성되었습니다",
|
||||||
"createInternalResourceDialogError": "오류",
|
"createInternalResourceDialogError": "오류",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "내부 리소스 생성 실패",
|
"createInternalResourceDialogFailedToCreateInternalResource": "개인 리소스 생성 실패",
|
||||||
"createInternalResourceDialogNameRequired": "이름은 필수입니다.",
|
"createInternalResourceDialogNameRequired": "이름은 필수입니다.",
|
||||||
"createInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.",
|
"createInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "사이트를 선택하세요",
|
"createInternalResourceDialogPleaseSelectSite": "사이트를 선택하세요",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI 게이트웨이",
|
||||||
"scheme": "스킴",
|
"scheme": "스킴",
|
||||||
"createInternalResourceDialogScheme": "스킴",
|
"createInternalResourceDialogScheme": "스킴",
|
||||||
"createInternalResourceDialogEnableSsl": "TLS 활성화",
|
"createInternalResourceDialogEnableSsl": "TLS 활성화",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "유효한 비밀번호",
|
"validPassword": "유효한 비밀번호",
|
||||||
"validEmail": "유효한 이메일",
|
"validEmail": "유효한 이메일",
|
||||||
"validSSO": "유효한 SSO",
|
"validSSO": "유효한 SSO",
|
||||||
|
"validVirtualAPIKey": "유효한 가상 API 키",
|
||||||
"view": "보기",
|
"view": "보기",
|
||||||
"configManaged": "구성 관리됨",
|
"configManaged": "구성 관리됨",
|
||||||
"connectedClient": "연결된 클라이언트",
|
"connectedClient": "연결된 클라이언트",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "로그 보관",
|
"logRetention": "로그 보관",
|
||||||
"logRetentionDescription": "다양한 유형의 로그를 이 조직에 대해 얼마나 오래 보관할지 관리하거나 비활성화합니다",
|
"logRetentionDescription": "다양한 유형의 로그를 이 조직에 대해 얼마나 오래 보관할지 관리하거나 비활성화합니다",
|
||||||
"requestLogsDescription": "이 조직의 자원에 대한 상세한 요청 로그를 봅니다",
|
"requestLogsDescription": "이 조직의 자원에 대한 상세한 요청 로그를 봅니다",
|
||||||
|
"aiSessionLogs": "AI 게이트웨이 세션 로그",
|
||||||
|
"aiSessionLogsDescription": "이 조직의 AI 게이트웨이 요청에 대한 프롬프트 및 응답 대본을 봅니다",
|
||||||
|
"sidebarLogsAi": "세션 로그",
|
||||||
|
"commandLogsAi": "세션 로그",
|
||||||
|
"sidebarLogsAiUsage": "사용 분석",
|
||||||
|
"commandLogsAiUsage": "사용 분석",
|
||||||
|
"provider": "제공자",
|
||||||
|
"capability": "능력",
|
||||||
|
"model": "모델",
|
||||||
|
"virtualApiKey": "가상 API 키",
|
||||||
|
"noVirtualApiKey": "가상 API 키가 없습니다",
|
||||||
|
"stream": "스트림",
|
||||||
|
"streaming": "스트리밍",
|
||||||
|
"nonStreaming": "비스트리밍",
|
||||||
|
"statusCode": "상태 코드",
|
||||||
|
"aiSessionId": "세션 ID",
|
||||||
|
"aiSessionRequest": "요청",
|
||||||
|
"aiSessionResponse": "응답",
|
||||||
|
"aiSessionNoData": "캡처된 데이터 없음",
|
||||||
|
"aiSessionCouldNotParse": "(원시, 대본을 구문 분석할 수 없음)",
|
||||||
|
"aiSessionLogTruncated": "이 세션은 저장소 전송되기 전에 잘린 상태일 수 있습니다.",
|
||||||
|
"aiSessionViewRaw": "원시 JSON 보기",
|
||||||
|
"aiSessionViewChat": "채팅 보기",
|
||||||
|
"cost": "비용",
|
||||||
|
"estimated": "추정된",
|
||||||
|
"tokenUsage": "토큰 사용량",
|
||||||
|
"promptTokens": "프롬프트 토큰",
|
||||||
|
"cacheReadTokens": "캐시 조회 토큰",
|
||||||
|
"cacheWriteTokens": "캐시 쓰기 토큰",
|
||||||
|
"completionTokens": "완료 토큰",
|
||||||
|
"reasoningTokens": "추론 토큰",
|
||||||
|
"totalTokens": "총 토큰수",
|
||||||
"requestAnalyticsDescription": "이 조직의 리소스에 대한 자세한 요청 분석 보기",
|
"requestAnalyticsDescription": "이 조직의 리소스에 대한 자세한 요청 분석 보기",
|
||||||
"logRetentionRequestLabel": "HTTP 요청 로그 보관",
|
"logRetentionRequestLabel": "HTTP 요청 로그 보관",
|
||||||
"logRetentionRequestDescription": "요청 로그를 얼마나 오래 보관할지",
|
"logRetentionRequestDescription": "요청 로그를 얼마나 오래 보관할지",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "작업 로그를 얼마나 오래 보관할지",
|
"logRetentionActionDescription": "작업 로그를 얼마나 오래 보관할지",
|
||||||
"logRetentionConnectionLabel": "연결 로그 보유 기간",
|
"logRetentionConnectionLabel": "연결 로그 보유 기간",
|
||||||
"logRetentionConnectionDescription": "연결 로그를 얼마나 오래 보유할지",
|
"logRetentionConnectionDescription": "연결 로그를 얼마나 오래 보유할지",
|
||||||
|
"logRetentionAISessionsLabel": "AI 게이트웨이 세션 로그 보관",
|
||||||
|
"logRetentionAISessionsDescription": "AI 게이트웨이 프롬프트/응답 세션 로그를 보관할 기간",
|
||||||
"logRetentionDisabled": "비활성화됨",
|
"logRetentionDisabled": "비활성화됨",
|
||||||
"logRetention3Days": "3 일",
|
"logRetention3Days": "3 일",
|
||||||
"logRetention7Days": "7 일",
|
"logRetention7Days": "7 일",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "소스 주소",
|
"sourceAddress": "소스 주소",
|
||||||
"destinationAddress": "대상 주소",
|
"destinationAddress": "대상 주소",
|
||||||
"duration": "지속 시간",
|
"duration": "지속 시간",
|
||||||
"licenseRequiredToUse": "이 기능을 사용하려면 <enterpriseLicenseLink>엔터프라이즈 에디션</enterpriseLicenseLink> 라이선스가 필요합니다. 이 기능은 <pangolinCloudLink>판골린 클라우드</pangolinCloudLink>에서도 사용할 수 있습니다. <bookADemoLink>데모 또는 POC 체험을 예약하세요</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Enterprise Edition 라이센스</enterpriseEditionLink>가 필요합니다. <bookADemoLink>데모 또는 평가판 예약</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "이 기능을 사용하려면 <enterpriseEditionLink>엔터프라이즈 에디션</enterpriseEditionLink>이(가) 필요합니다. 이 기능은 <pangolinCloudLink>판골린 클라우드</pangolinCloudLink>에서도 사용할 수 있습니다. <bookADemoLink>데모 또는 POC 체험을 예약하세요</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition 라이센스</enterpriseEditionLink>가 필요합니다. <bookADemoLink>데모 또는 평가판 예약</bookADemoLink>",
|
||||||
"certResolver": "인증서 해결사",
|
"certResolver": "인증서 해결사",
|
||||||
"certResolverDescription": "이 리소스에 사용할 인증서 해결사를 선택하세요.",
|
"certResolverDescription": "이 리소스에 사용할 인증서 해결사를 선택하세요.",
|
||||||
"selectCertResolver": "인증서 해결사 선택",
|
"selectCertResolver": "인증서 해결사 선택",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "다중 사이트를 선택하면 높은 가용성을 위해 회복력 있는 라우팅 및 페일오버가 가능해집니다.",
|
"internalResourceFormMultiSiteRoutingHelp": "다중 사이트를 선택하면 높은 가용성을 위해 회복력 있는 라우팅 및 페일오버가 가능해집니다.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "자세히 알아보기",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "자세히 알아보기",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "특정 TCP/UDP 포트에 대한 접근을 제한하거나 모든 포트를 허용/차단하십시오.",
|
"editInternalResourceDialogPortRestrictionsDescription": "특정 TCP/UDP 포트에 대한 접근을 제한하거나 모든 포트를 허용/차단하십시오.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "HTTP 구성",
|
"createInternalResourceDialogHttpConfiguration": "도메인 구성",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "이 리소스에 HTTP 또는 HTTPS로 도달하기 위한 도메인을 선택하세요.",
|
"createInternalResourceDialogHttpConfigurationDescription": "이 리소스에 HTTP 또는 HTTPS로 도달하기 위한 도메인을 선택하세요.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "HTTP 구성",
|
"editInternalResourceDialogHttpConfiguration": "도메인 구성",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "이 리소스에 HTTP 또는 HTTPS로 도달하기 위한 도메인을 선택하세요.",
|
"editInternalResourceDialogHttpConfigurationDescription": "이 리소스에 HTTP 또는 HTTPS로 도달하기 위한 도메인을 선택하세요.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "레이블 없음",
|
"resourceLauncherUnlabeled": "레이블 없음",
|
||||||
|
"resourceLauncherAiGateway": "AI 게이트웨이",
|
||||||
"resourceLauncherNoSite": "사이트 없음",
|
"resourceLauncherNoSite": "사이트 없음",
|
||||||
|
"resourceLauncherAvailableModels": "사용 가능한 모델",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "이 AI 게이트웨이에서 사용할 수 있는 모델입니다.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "이 리소스에 사용할 수 있는 모델이 없습니다.",
|
||||||
|
"resourceLauncherAvailableModelsError": "사용 가능한 모델을 로드할 수 없습니다.",
|
||||||
|
"resourceLauncherApiKeys": "API 키",
|
||||||
|
"resourceLauncherApiKeysDescription": "신원 키나 속성 키를 사용하여 이 리소스에 인증하십시오.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "신원 키",
|
||||||
|
"resourceLauncherApiKeysManual": "속성 키",
|
||||||
|
"resourceLauncherApiKeysEmpty": "이 리소스에 사용할 수 있는 API 키가 없습니다.",
|
||||||
|
"resourceLauncherApiKeysError": "API 키를 로드할 수 없습니다.",
|
||||||
"resourceLauncherNoResourcesInGroup": "이 그룹에는 리소스가 없습니다",
|
"resourceLauncherNoResourcesInGroup": "이 그룹에는 리소스가 없습니다",
|
||||||
"resourceLauncherEmptyStateTitle": "사용 가능한 리소스 없음",
|
"resourceLauncherEmptyStateTitle": "사용 가능한 리소스 없음",
|
||||||
"resourceLauncherEmptyStateDescription": "아직 리소스에 대한 액세스 권한이 없습니다. 액세스를 요청하려면 관리자에게 문의하세요.",
|
"resourceLauncherEmptyStateDescription": "아직 리소스에 대한 액세스 권한이 없습니다. 액세스를 요청하려면 관리자에게 문의하세요.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "런처 뷰를 삭제할 수 없습니다. 다시 시도하세요.",
|
"resourceLauncherViewDeleteFailedDescription": "런처 뷰를 삭제할 수 없습니다. 다시 시도하세요.",
|
||||||
"memberPortalPrevious": "이전",
|
"memberPortalPrevious": "이전",
|
||||||
"memberPortalNext": "다음",
|
"memberPortalNext": "다음",
|
||||||
"httpSettings": "HTTP 설정",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "TCP 설정",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "UDP 설정",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "보안 연결 설정 중…",
|
"sshConnectingDescription": "보안 연결 설정 중…",
|
||||||
"sshConnecting": "연결 중…",
|
"sshConnecting": "연결 중…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "업로드 실패",
|
"rdpUploadFailed": "업로드 실패",
|
||||||
"rdpUnicodeKeyboardMode": "유니코드 키보드 모드",
|
"rdpUnicodeKeyboardMode": "유니코드 키보드 모드",
|
||||||
"sessionToolbarShow": "툴바 보기",
|
"sessionToolbarShow": "툴바 보기",
|
||||||
"sessionToolbarHide": "툴바 숨기기"
|
"sessionToolbarHide": "툴바 숨기기",
|
||||||
|
"actionUpdateSiteApprovals": "사이트 승인 업데이트"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Vennligst sjekk at du er logget inn som riktig bruker.",
|
"inviteLoginUser": "Vennligst sjekk at du er logget inn som riktig bruker.",
|
||||||
"inviteErrorNoUser": "Vi beklager, men det ser ut som invitasjonen du prøver å få tilgang til ikke er for en bruker som eksisterer.",
|
"inviteErrorNoUser": "Vi beklager, men det ser ut som invitasjonen du prøver å få tilgang til ikke er for en bruker som eksisterer.",
|
||||||
"inviteCreateUser": "Vennligst opprett en konto først.",
|
"inviteCreateUser": "Vennligst opprett en konto først.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Invitasjoner kan kun aksepteres av interne kontoer. Logg ut og logg inn med passordet ditt for denne e-posten.",
|
||||||
|
"inviteLoginInternalOnly": "Invitasjoner krever en intern konto med et passord. Opprett en konto eller logg inn med passordet ditt.",
|
||||||
"goHome": "Gå hjem",
|
"goHome": "Gå hjem",
|
||||||
"inviteLogInOtherUser": "Logg inn som en annen bruker",
|
"inviteLogInOtherUser": "Logg inn som en annen bruker",
|
||||||
"createAnAccount": "Lag konto",
|
"createAnAccount": "Lag konto",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Bekreft sletting av delbar lenke",
|
"shareDeleteConfirm": "Bekreft sletting av delbar lenke",
|
||||||
"shareQuestionRemove": "Er du sikker på at du vil slette denne delingslenken?",
|
"shareQuestionRemove": "Er du sikker på at du vil slette denne delingslenken?",
|
||||||
"shareMessageRemove": "Når slettet, vil lenken ikke lenger fungere, og alle som bruker den vil miste tilgang til ressursen.",
|
"shareMessageRemove": "Når slettet, vil lenken ikke lenger fungere, og alle som bruker den vil miste tilgang til ressursen.",
|
||||||
"shareTokenDescription": "Adgangstoken kan sendes på to måter: som en spørringsparameter eller i forespørselsoverskriftene. Disse må sendes fra klienten på hver forespørsel om autentisert tilgang.",
|
"shareTokenDescription": "Tilgangstokenn kan sendes som en spørringsparameter eller i forespørselshoder. Som standard må det sendes med hver forespørsel. Hvis sesjonsvedholdenhet er aktivert, byttes den første forespørselen mot en sesjons-cookie.",
|
||||||
"accessToken": "Tilgangsnøkkel",
|
"accessToken": "Tilgangsnøkkel",
|
||||||
"usageExamples": "Brukseksempler",
|
"usageExamples": "Brukseksempler",
|
||||||
"tokenId": "Token-ID",
|
"tokenId": "Token-ID",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Tittel (valgfritt)",
|
"shareTitleOptional": "Tittel (valgfritt)",
|
||||||
"sharePathOptional": "Bane (valgfritt)",
|
"sharePathOptional": "Bane (valgfritt)",
|
||||||
"sharePathDescription": "Lenken vil videresende brukere til denne stien etter autentisering.",
|
"sharePathDescription": "Lenken vil videresende brukere til denne stien etter autentisering.",
|
||||||
|
"shareAssociateUserOptional": "Tilknytt bruker (valgfritt)",
|
||||||
|
"shareAssociateUserDescription": "Når den er satt, blir forespørsler som bruker denne koblingen tilskrevet brukeren i tilgangslogger og identitetshoder. Koblingen fjernes hvis brukeren forlater organisasjonen.",
|
||||||
|
"userSelect": "Velg bruker",
|
||||||
|
"usersNotFound": "Ingen brukere funnet",
|
||||||
"expireIn": "Utløper om",
|
"expireIn": "Utløper om",
|
||||||
"neverExpire": "Utløper aldri",
|
"neverExpire": "Utløper aldri",
|
||||||
|
"sharePersistSession": "Behold sesjonen etter første bruk",
|
||||||
|
"sharePersistSessionDescription": "Når den er aktivert, setter den første forespørselen med dette tokenet via en spørringsparameter eller et hode en sesjons-cookie slik at senere forespørsler ikke trenger tokenet. La det være av for API-klienter som skal sende tokenet ved hver forespørsel.",
|
||||||
"shareExpireDescription": "Utløpstid er hvor lenge lenken vil være brukbar og gi tilgang til ressursen. Etter denne tiden vil lenken ikke lenger fungere, og brukere som brukte denne lenken vil miste tilgangen til ressursen.",
|
"shareExpireDescription": "Utløpstid er hvor lenge lenken vil være brukbar og gi tilgang til ressursen. Etter denne tiden vil lenken ikke lenger fungere, og brukere som brukte denne lenken vil miste tilgangen til ressursen.",
|
||||||
"shareSeeOnce": "Du vil bare kunne se denne linken én gang. Pass på å kopiere den.",
|
"shareSeeOnce": "Du vil bare kunne se denne linken én gang. Pass på å kopiere den.",
|
||||||
"shareAccessHint": "Alle med denne lenken kan få tilgang til ressursen. Del forsiktig.",
|
"shareAccessHint": "Alle med denne lenken kan få tilgang til ressursen. Del forsiktig.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Ingen land funnet.",
|
"noCountryFound": "Ingen land funnet.",
|
||||||
"siteSelectionDescription": "Dette området vil gi tilkobling til mål.",
|
"siteSelectionDescription": "Dette området vil gi tilkobling til mål.",
|
||||||
"resourceType": "Ressurstype",
|
"resourceType": "Ressurstype",
|
||||||
"resourceTypeDescription": "Dette kontrollerer ressursprotokollen og hvordan den vil vises i nettleseren. Dette kan ikke endres senere.",
|
"resourceTypeDescription": "Dette styrer ressursprotokollen og kan ikke endres senere.",
|
||||||
|
"resourceTypeSearch": "Søk i ressurstyper...",
|
||||||
|
"resourceTypeNotFound": "Ingen ressurstype funnet",
|
||||||
|
"resourceTypeHttpDescription": "Proxy nettverkstrafikk over HTTPS ved bruk av et domenenavn",
|
||||||
|
"resourceTypeInferenceDescription": "Ruter AI-forespørsler gjennom tilkoblede leverandører",
|
||||||
|
"resourceTypeSshDescription": "Tilgang til en SSH-server fra nettleseren",
|
||||||
|
"resourceTypeRdpDescription": "Tilgang til en fjernskrivebord fra nettleseren",
|
||||||
|
"resourceTypeVncDescription": "Tilgang til et VNC-skrivebord fra nettleseren",
|
||||||
|
"resourceTypeTcpDescription": "Proxy rå TCP-trafikk ved bruk av et portnummer",
|
||||||
|
"resourceTypeUdpDescription": "Proxy rå UDP-trafikk ved bruk av et portnummer",
|
||||||
|
"privateResourceTypeDescription": "Dette styrer hvordan klienter kommer til ressursen. Dette kan ikke endres senere.",
|
||||||
|
"privateResourceTypeHostDescription": "Eksponer en enkel vert på nettverksområdet for tilkoblede klienter",
|
||||||
|
"privateResourceTypeCidrDescription": "Eksponer et CIDR-område på nettverksområdet for tilkoblede klienter",
|
||||||
|
"privateResourceTypeHttpDescription": "Tilgang til en HTTP- eller HTTPS-tjeneste gjennom et domene",
|
||||||
|
"privateResourceTypeSshDescription": "Tilgang til en SSH-server fra tilkoblede klienter",
|
||||||
"resourceDomainDescription": "Ressursen vil bli servert på dette fullstendig kvalifiserte domenenavnet.",
|
"resourceDomainDescription": "Ressursen vil bli servert på dette fullstendig kvalifiserte domenenavnet.",
|
||||||
"resourceHTTPSSettings": "HTTPS-innstillinger",
|
"resourceHTTPSSettings": "HTTPS-innstillinger",
|
||||||
"resourceHTTPSSettingsDescription": "Konfigurer hvordan ressursen skal nås over HTTPS",
|
"resourceHTTPSSettingsDescription": "Konfigurer hvordan ressursen skal nås over HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Levering",
|
"provisioningManage": "Levering",
|
||||||
"provisioningDescription": "Administrer foreløpig nøkler og gjennomgå ventende nettsteder som venter på godkjenning.",
|
"provisioningDescription": "Administrer foreløpig nøkler og gjennomgå ventende nettsteder som venter på godkjenning.",
|
||||||
"pendingSites": "Ventende nettsteder",
|
"pendingSites": "Ventende nettsteder",
|
||||||
"siteApproveSuccess": "Vellykket godkjenning av nettsted",
|
"siteApproveSuccess": "Område og tilknyttede ressurser godkjent",
|
||||||
"siteApproveError": "Feil ved godkjenning av side",
|
"siteApproveError": "Feil ved godkjenning av side",
|
||||||
|
"siteReject": "Avvis Område",
|
||||||
|
"siteQuestionReject": "Er du sikker på at du vil avvise dette området?",
|
||||||
|
"siteMessageReject": "Dette vil permanent slette området og eventuelle tilknyttede ressurser som fortsatt venter.",
|
||||||
|
"siteConfirmReject": "Bekreft Avvisning av Område",
|
||||||
|
"siteRejectSuccess": "Område avvist",
|
||||||
|
"siteRejectError": "Feil ved avvisning av området",
|
||||||
"provisioningKeys": "Foreløpig nøkler",
|
"provisioningKeys": "Foreløpig nøkler",
|
||||||
"searchProvisioningKeys": "Søk varer i lagrings nøkler...",
|
"searchProvisioningKeys": "Søk varer i lagrings nøkler...",
|
||||||
"provisioningKeysAdd": "Generer fremvisende nøkkel",
|
"provisioningKeysAdd": "Generer fremvisende nøkkel",
|
||||||
@@ -466,12 +494,12 @@
|
|||||||
"provisioningKeysSave": "Lagre den midlertidig nøkkelen",
|
"provisioningKeysSave": "Lagre den midlertidig nøkkelen",
|
||||||
"provisioningKeysSaveDescription": "Du kan bare se denne én gang. Kopier det til et sikkert sted.",
|
"provisioningKeysSaveDescription": "Du kan bare se denne én gang. Kopier det til et sikkert sted.",
|
||||||
"provisioningKeysErrorCreate": "Feil under oppretting av foreløpig nøkkel",
|
"provisioningKeysErrorCreate": "Feil under oppretting av foreløpig nøkkel",
|
||||||
"provisioningKeysList": "Ny provisorisk nøkkel",
|
"provisioningKeysList": "Ny Forsyningsnøkkel",
|
||||||
"provisioningKeysMaxBatchSize": "Maks størrelse på bunt",
|
"provisioningKeysMaxBatchSize": "Maks Batch Størrelse",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Ubegrenset mengde bunt (ingen begrensning)",
|
"provisioningKeysUnlimitedBatchSize": "Ubegrenset mengde bunt (ingen begrensning)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Ubegrenset",
|
"provisioningKeysMaxBatchUnlimited": "Ubegrenset",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Angi en gyldig sjakkstørrelse (1–1 000.000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Angi en gyldig sjakkstørrelse (1–1 000.000).",
|
||||||
"provisioningKeysValidUntil": "Gyldig til",
|
"provisioningKeysValidUntil": "Gyldig Til",
|
||||||
"provisioningKeysValidUntilHint": "La stå tomt for ingen utløp.",
|
"provisioningKeysValidUntilHint": "La stå tomt for ingen utløp.",
|
||||||
"provisioningKeysValidUntilInvalid": "Angi en gyldig dato og klokkeslett.",
|
"provisioningKeysValidUntilInvalid": "Angi en gyldig dato og klokkeslett.",
|
||||||
"provisioningKeysNumUsed": "Antall ganger brukt",
|
"provisioningKeysNumUsed": "Antall ganger brukt",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "Aldri",
|
"provisioningKeysNeverUsed": "Aldri",
|
||||||
"provisioningKeysEdit": "Rediger bestemmelsesnøkkel",
|
"provisioningKeysEdit": "Rediger bestemmelsesnøkkel",
|
||||||
"provisioningKeysEditDescription": "Oppdater maksimal størrelse for bunt og utløpstid for denne nøkkelen.",
|
"provisioningKeysEditDescription": "Oppdater maksimal størrelse for bunt og utløpstid for denne nøkkelen.",
|
||||||
"provisioningKeysApproveNewSites": "Godkjenn nye nettsteder",
|
"provisioningKeysApproveNewSites": "Godkjenn Nye Områder",
|
||||||
"provisioningKeysApproveNewSitesDescription": "Godkjenn automatisk nettsteder som registrerer deg med denne nøkkelen.",
|
"provisioningKeysApproveNewSitesDescription": "Godkjenn automatisk nettsteder som registrerer deg med denne nøkkelen.",
|
||||||
"provisioningKeysUpdateError": "Feil under oppdatering av foreløpig nøkkel",
|
"provisioningKeysUpdateError": "Feil under oppdatering av foreløpig nøkkel",
|
||||||
"provisioningKeysUpdated": "Foreslå nøkkel oppdatert",
|
"provisioningKeysUpdated": "Foreslå nøkkel oppdatert",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Lagre innstillinger",
|
"authMethodsSave": "Lagre innstillinger",
|
||||||
"policyAuthStackTitle": "Autentisering",
|
"policyAuthStackTitle": "Autentisering",
|
||||||
"policyAuthStackDescription": "Kontroller hvilke autentiseringsmetoder som kreves for å få tilgang til denne ressursen",
|
"policyAuthStackDescription": "Kontroller hvilke autentiseringsmetoder som kreves for å få tilgang til denne ressursen",
|
||||||
|
"policyAuthInferenceStackDescription": "Velg hvilke brukere og roller som kan autentisere seg til denne AI-porten",
|
||||||
"policyAuthOrLogicTitle": "Flere autentiseringsmetoder aktive",
|
"policyAuthOrLogicTitle": "Flere autentiseringsmetoder aktive",
|
||||||
"policyAuthOrLogicBanner": "Besøkende kan autentisere ved bruk av en hvilken som helst av de aktive metodene nedenfor. De trenger ikke å fullføre alle.",
|
"policyAuthOrLogicBanner": "Besøkende kan autentisere ved bruk av en hvilken som helst av de aktive metodene nedenfor. De trenger ikke å fullføre alle.",
|
||||||
"policyAuthMethodActive": "Aktiv",
|
"policyAuthMethodActive": "Aktiv",
|
||||||
"policyAuthMethodOff": "Av",
|
"policyAuthMethodOff": "Av",
|
||||||
"policyAuthSsoTitle": "Plattform SSO",
|
"policyAuthSsoTitle": "Plattform SSO",
|
||||||
"policyAuthSsoDescription": "Krev pålogging gjennom din organisasjons identitetsleverandør",
|
"policyAuthSsoDescription": "Krev pålogging gjennom din organisasjons identitetsleverandør",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "Logg inn URL",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Hver bruker har allerede en identitet API-nøkkel, så du trenger bare å opprette virtuelle API-nøkler for ikke-brukerklienter eller delt tilgang. Brukere kan hente sin nøkkel ved å logge inn med sin identitetsleverandør på denne ressursens URL, hvor den vil vises etter innlogging.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Hver bruker har allerede en identitet API-nøkkel, så du trenger bare å opprette virtuelle API-nøkler for ikke-brukerklienter eller delt tilgang. Brukere henter sin nøkkel her etter innlogging med sin identitetsleverandør.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} brukere, {roles} roller",
|
"policyAuthSsoSummary": "{idp} · {users} brukere, {roles} roller",
|
||||||
"policyAuthSsoDefaultIdp": "Standardleverandør",
|
"policyAuthSsoDefaultIdp": "Standardleverandør",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Legg til standard identitetsleverandør",
|
"policyAuthAddDefaultIdentityProvider": "Legg til standard identitetsleverandør",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Versjon",
|
"newtVersion": "Versjon",
|
||||||
"architecture": "Arkitektur",
|
"architecture": "Arkitektur",
|
||||||
"sites": "Områder",
|
"sites": "Områder",
|
||||||
"siteWgAnyClients": "Bruk hvilken som helst WireGuard klient til å koble til. Du må adressere interne ressurser ved hjelp av peer IP.",
|
"siteWgAnyClients": "Bruk hvilken som helst WireGuard-klient for å koble til. Du må adressere private ressurser ved å bruke peer-IP.",
|
||||||
"siteWgCompatibleAllClients": "Kompatibel med alle WireGuard-klienter",
|
"siteWgCompatibleAllClients": "Kompatibel med alle WireGuard-klienter",
|
||||||
"siteWgManualConfigurationRequired": "Manuell konfigurasjon påkrevd",
|
"siteWgManualConfigurationRequired": "Manuell konfigurasjon påkrevd",
|
||||||
"userErrorNotAdminOrOwner": "Bruker er ikke administrator eller eier",
|
"userErrorNotAdminOrOwner": "Bruker er ikke administrator eller eier",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Ny rolle kreves",
|
"accessRoleErrorNewRequired": "Ny rolle kreves",
|
||||||
"accessRoleErrorRemove": "Kunne ikke fjerne rolle",
|
"accessRoleErrorRemove": "Kunne ikke fjerne rolle",
|
||||||
"accessRoleErrorRemoveDescription": "Det oppstod en feil under fjerning av rollen.",
|
"accessRoleErrorRemoveDescription": "Det oppstod en feil under fjerning av rollen.",
|
||||||
|
"accessRoleInferenceBudget": "AI Budsjett",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Konfigurer hvordan medlemmene av denne rollen begrenser AI-bruk basert på forbruk eller tokenbegrensninger",
|
||||||
"accessRoleName": "Rollenavn",
|
"accessRoleName": "Rollenavn",
|
||||||
"accessRoleQuestionRemove": "Du er ferd med å slette rollen `{name}. Du kan ikke angre denne handlingen.",
|
"accessRoleQuestionRemove": "Du er ferd med å slette rollen `{name}. Du kan ikke angre denne handlingen.",
|
||||||
"accessRoleRemove": "Fjern Rolle",
|
"accessRoleRemove": "Fjern Rolle",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Opprett Org bruker",
|
"createOrgUser": "Opprett Org bruker",
|
||||||
"actionUpdateOrg": "Oppdater organisasjon",
|
"actionUpdateOrg": "Oppdater organisasjon",
|
||||||
"actionRemoveInvitation": "Fjern invitasjon",
|
"actionRemoveInvitation": "Fjern invitasjon",
|
||||||
|
"actionRemoveUserRole": "Fjern Brukerrolle",
|
||||||
"actionUpdateUser": "Oppdater bruker",
|
"actionUpdateUser": "Oppdater bruker",
|
||||||
"actionGetUser": "Hent bruker",
|
"actionGetUser": "Hent bruker",
|
||||||
"actionGetOrgUser": "Hent organisasjonsbruker",
|
"actionGetOrgUser": "Hent organisasjonsbruker",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Slett område",
|
"actionDeleteSite": "Slett område",
|
||||||
"actionGetSite": "Hent område",
|
"actionGetSite": "Hent område",
|
||||||
"actionListSites": "List opp områder",
|
"actionListSites": "List opp områder",
|
||||||
|
"actionCreateAiProvider": "Opprett AI-leverandør",
|
||||||
|
"actionDeleteAiProvider": "Slett AI-leverandør",
|
||||||
|
"actionGetAiProvider": "Hent AI-leverandør",
|
||||||
|
"actionListAiProviders": "List opp AI-leverandører",
|
||||||
|
"actionUpdateAiProvider": "Oppdater AI-leverandør",
|
||||||
|
"actionCreateAiModel": "Opprett AI-modell",
|
||||||
|
"actionDeleteAiModel": "Slett AI-modell",
|
||||||
|
"actionGetAiModel": "Hent AI-modell",
|
||||||
|
"actionListAiModels": "List opp AI-modeller",
|
||||||
|
"actionUpdateAiModel": "Oppdater AI-modell",
|
||||||
|
"actionCreateAiBudget": "Opprett AI-budsjett",
|
||||||
|
"actionDeleteAiBudget": "Slett AI-budsjett",
|
||||||
|
"actionGetAiBudget": "Hent AI-budsjett",
|
||||||
|
"actionListAiBudgets": "List opp AI-budsjetter",
|
||||||
|
"actionUpdateAiBudget": "Oppdater AI-budsjett",
|
||||||
|
"actionListResourceAiModels": "List opp ressurs AI-modeller",
|
||||||
|
"actionSetResourceAiModels": "Angi ressurs AI-modeller",
|
||||||
|
"actionCreateVirtualApiKey": "Opprett virtuell API-nøkkel",
|
||||||
|
"actionDeleteVirtualApiKey": "Slett virtuell API-nøkkel",
|
||||||
|
"actionGetVirtualApiKey": "Hent virtuell API-nøkkel",
|
||||||
|
"actionListVirtualApiKeys": "List opp virtuelle API-nøkler",
|
||||||
|
"actionUpdateVirtualApiKey": "Oppdater virtuell API-nøkkel",
|
||||||
"actionApplyBlueprint": "Bruk blåkopi",
|
"actionApplyBlueprint": "Bruk blåkopi",
|
||||||
"actionListBlueprints": "List opp blåkopier",
|
"actionListBlueprints": "List opp blåkopier",
|
||||||
"actionGetBlueprint": "Hent blåkopi",
|
"actionGetBlueprint": "Hent blåkopi",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Skriv inn oppsetttoken fra serverkonsollen.",
|
"setupTokenDescription": "Skriv inn oppsetttoken fra serverkonsollen.",
|
||||||
"setupTokenRequired": "Oppsetttoken er nødvendig",
|
"setupTokenRequired": "Oppsetttoken er nødvendig",
|
||||||
"actionUpdateSite": "Oppdater område",
|
"actionUpdateSite": "Oppdater område",
|
||||||
|
"actionApproveSite": "Godkjenn Område",
|
||||||
|
"actionRejectSite": "Avvis Område",
|
||||||
"actionResetSiteBandwidth": "Tilbakestill organisasjons-båndbredde",
|
"actionResetSiteBandwidth": "Tilbakestill organisasjons-båndbredde",
|
||||||
"actionListSiteRoles": "List opp tillatte områderoller",
|
"actionListSiteRoles": "List opp tillatte områderoller",
|
||||||
"actionCreateResource": "Opprett ressurs",
|
"actionCreateResource": "Opprett ressurs",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Angi ressurspinkode",
|
"actionSetResourcePincode": "Angi ressurspinkode",
|
||||||
"actionSetResourceEmailWhitelist": "Angi e-post-hviteliste for ressurs",
|
"actionSetResourceEmailWhitelist": "Angi e-post-hviteliste for ressurs",
|
||||||
"actionGetResourceEmailWhitelist": "Hent e-post-hviteliste for ressurs",
|
"actionGetResourceEmailWhitelist": "Hent e-post-hviteliste for ressurs",
|
||||||
|
"actionListResourcePolicies": "List opp ressursregler",
|
||||||
|
"actionCreateResourcePolicy": "Opprett ressursregel",
|
||||||
"actionGetResourcePolicy": "Hent ressursregel",
|
"actionGetResourcePolicy": "Hent ressursregel",
|
||||||
"actionUpdateResourcePolicy": "Oppdater ressursregel",
|
"actionUpdateResourcePolicy": "Oppdater ressursregel",
|
||||||
|
"actionDeleteResourcePolicy": "Slett ressursregel",
|
||||||
"actionSetResourcePolicyUsers": "Sett ressursregel for brukere",
|
"actionSetResourcePolicyUsers": "Sett ressursregel for brukere",
|
||||||
"actionSetResourcePolicyRoles": "Sett ressursregel for roller",
|
"actionSetResourcePolicyRoles": "Sett ressursregel for roller",
|
||||||
"actionSetResourcePolicyPassword": "Sett ressursregel for passord",
|
"actionSetResourcePolicyPassword": "Sett ressursregel for passord",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Liste invitasjoner",
|
"actionListInvitations": "Liste invitasjoner",
|
||||||
"actionExportLogs": "Eksportlogger",
|
"actionExportLogs": "Eksportlogger",
|
||||||
"actionViewLogs": "Vis logger",
|
"actionViewLogs": "Vis logger",
|
||||||
|
"actionCreateSiteProvisioningKey": "Opprett Klargjøringsnøkkel for Sted",
|
||||||
|
"actionListSiteProvisioningKeys": "List Klargjøringsnøkler for Sted",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Oppdater Klargjøringsnøkkel for Sted",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Slett Klargjøringsnøkkel for Sted",
|
||||||
"noneSelected": "Ingen valgt",
|
"noneSelected": "Ingen valgt",
|
||||||
"orgNotFound2": "Ingen organisasjoner funnet.",
|
"orgNotFound2": "Ingen organisasjoner funnet.",
|
||||||
"search": "Søk…",
|
"search": "Søk…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Skriv inn koden fra autentiseringsappen din eller en av dine engangs reservekoder.",
|
"otpAuthDescription": "Skriv inn koden fra autentiseringsappen din eller en av dine engangs reservekoder.",
|
||||||
"otpAuthSubmit": "Send inn kode",
|
"otpAuthSubmit": "Send inn kode",
|
||||||
"idpContinue": "Eller fortsett med",
|
"idpContinue": "Eller fortsett med",
|
||||||
|
"idpLastUsed": "Sist brukt",
|
||||||
"otpAuthBack": "Tilbake til passord",
|
"otpAuthBack": "Tilbake til passord",
|
||||||
"navbar": "Navigasjonsmeny",
|
"navbar": "Navigasjonsmeny",
|
||||||
"navbarDescription": "Hovednavigasjonsmeny for applikasjonen",
|
"navbarDescription": "Hovednavigasjonsmeny for applikasjonen",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Opprett maskinklient",
|
"commandPaletteCreateMachineClient": "Opprett maskinklient",
|
||||||
"commandPaletteCreateAlertRule": "Opprett varslingsregel",
|
"commandPaletteCreateAlertRule": "Opprett varslingsregel",
|
||||||
"commandPaletteCreateIdentityProvider": "Opprett identitetsleverandør",
|
"commandPaletteCreateIdentityProvider": "Opprett identitetsleverandør",
|
||||||
|
"commandPaletteCreateAiProvider": "Opprett AI-leverandør",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Opprett virtuell API-nøkkel",
|
||||||
"commandPaletteToggleTheme": "Bytt tema",
|
"commandPaletteToggleTheme": "Bytt tema",
|
||||||
"commandPaletteChooseOrganization": "Velg organisasjon",
|
"commandPaletteChooseOrganization": "Velg organisasjon",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Invitasjoner",
|
"sidebarInvitations": "Invitasjoner",
|
||||||
"sidebarRoles": "Roller",
|
"sidebarRoles": "Roller",
|
||||||
"sidebarShareableLinks": "Delbare lenker",
|
"sidebarShareableLinks": "Delbare lenker",
|
||||||
|
"sidebarAiGateway": "AI Gateway",
|
||||||
|
"sidebarAiProviders": "Leverandører",
|
||||||
|
"commandAiProviders": "AI-leverandører",
|
||||||
|
"sidebarVirtualApiKeys": "Virtuelle API-nøkler",
|
||||||
|
"sidebarMyApiKeys": "Dine API-nøkler",
|
||||||
|
"sidebarAccount": "Starter",
|
||||||
|
"commandVirtualApiKeys": "Virtuelle API-nøkler",
|
||||||
|
"virtualApiKeysTitle": "Administrer virtuelle API-nøkler",
|
||||||
|
"virtualApiKeysDescription": "Opprett og administrer manuelle API-nøkler for AI Gateway-tilgang til offentlige AI-portene",
|
||||||
|
"virtualApiKeysTabIdentity": "Identitetsnøkler",
|
||||||
|
"virtualApiKeysTabVirtual": "Virtuelle nøkler",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Identitetsnøkler for hver bruker",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Hver bruker har allerede en Pangolin identitetsnøkkel for denne organisasjonen. Den er unik for brukerkontoen deres og autentiserer dem til AI-portene de kan få tilgang til.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Eksempel",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Hvordan brukere henter sin nøkkel",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Besøk en offentlig AI Gateway-URL i nettleseren og logg inn med kontoen din.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Eller gå til <url></url> mens du er logget inn.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Du kan opprette flere virtuelle API-nøkler i kategorien Virtuelle nøkler. Disse nøklene kan avgrenses til spesifikke offentlige AI-portene og eventuelt assosieres med en bruker. Opprettelse av en nøkkel gir umiddelbar tilgang til de valgte offentlige AI-portene.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Manuelt opprett en nøkkel",
|
||||||
|
"virtualApiKeysEmailIdentity": "E-postidentitetsnøkler",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Send hver valgt bruker eller rolle deres Pangolin identitetsnøkkel.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Send til alle brukere",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "E-post til alle medlemmer av organisasjonen som har en kontoe-post.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Brukere",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Roller",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Send e-poster",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Identitetsnøkler sendt på e-post",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Sendt {sent} e-poster.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} brukere ble hoppet over fordi de ikke har en e-postadresse.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Velg minst én bruker eller rolle, eller send til alle brukere.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Feil ved sending av identitetsnøkler",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Kunne ikke sende identitetsnøkler",
|
||||||
|
"virtualApiKeysBannerTitle": "Identitetsnøkler for hver bruker",
|
||||||
|
"virtualApiKeysBannerDescription": "Hver bruker har allerede en identitetsnøkkel tilgjengelig på {keysUrl}. Du kan også manuelt opprette nøkler her som gir direkte tilgang til offentlige AI-portene.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Vis identitetsnøkler",
|
||||||
|
"virtualApiKeys": "Virtuelle API-nøkler",
|
||||||
|
"virtualApiKeysSearch": "Søk nøklene...",
|
||||||
|
"virtualApiKeysCreate": "Opprett virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysCreateDescription": "Lag en manuell nøkkel som kan kalle offentlige AI-gatewayer i denne organisasjonen",
|
||||||
|
"virtualApiKeysCreateButton": "Opprett nøkkel",
|
||||||
|
"virtualApiKeysEmpty": "Ingen virtuelle API-nøkler ennå",
|
||||||
|
"virtualApiKeysName": "Navn",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Beskrivelse (valgfritt)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Assosier bruker (valgfritt)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Assosier denne nøkkelen med en bruker for å spore bruken. Når den er opprettet, gir denne nøkkelen umiddelbar tilgang til de valgte offentlige AI-portene. Du trenger ikke å manuelt assosiere en bruker til ressursen. Nøkkelen vil også vises i brukerens profil.",
|
||||||
|
"virtualApiKeysAllResources": "Alle offentlige AI-portene",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Tillat denne nøkkelen å få tilgang til hver offentlig AI-port i organisasjonen",
|
||||||
|
"virtualApiKeysSelectResources": "Offentlige AI-portene",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Velg ressurser",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Velg hvilke offentlige AI-portene denne nøkkelen kan få tilgang til",
|
||||||
|
"virtualApiKeysNoResources": "Ingen ressurser",
|
||||||
|
"virtualApiKeysSecret": "Nøkkel",
|
||||||
|
"virtualApiKeysCopyKey": "Kopier denne nøkkelen. Du kan se den igjen senere fra tabellen eller når du redigerer.",
|
||||||
|
"virtualApiKeysViewSecret": "Vis hemmelighet",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Virtuell API-nøkkel hemmelighet",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Denne hemmeligheten gir tilgang til de offentlige AI-portene som er tildelt denne nøkkelen",
|
||||||
|
"virtualApiKeysEdit": "Rediger virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysEditDescription": "Oppdater den tilknyttede brukeren og tilgang til offentlige AI-port for denne nøkkelen",
|
||||||
|
"virtualApiKeysSaveButton": "Lagre endringer",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Velg minst én offentlig AI-port, eller aktiver alle offentlige AI-portene",
|
||||||
|
"virtualApiKeysUpdated": "Virtuell API-nøkkel oppdatert",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Den virtuelle API-nøkkelen er oppdatert",
|
||||||
|
"virtualApiKeysErrorUpdate": "Feil ved oppdatering av virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Kunne ikke oppdatere virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysErrorCreate": "Feil ved opprettelse av virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Kunne ikke opprette virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysErrorDelete": "Feil ved sletting av virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Kunne ikke slette virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysDeleted": "Virtuell API-nøkkel slettet",
|
||||||
|
"virtualApiKeysDeletedDescription": "Den virtuelle API-nøkkelen er slettet",
|
||||||
|
"virtualApiKeysDelete": "Slett virtuell API-nøkkel",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Slett nøkkel",
|
||||||
|
"virtualApiKeysQuestionRemove": "Er du sikker på at du vil slette denne virtuelle API-nøkkelen?",
|
||||||
|
"virtualApiKeysMessageRemove": "Klienter som bruker denne nøkkelen vil miste tilgang umiddelbart.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Feil ved lasting av hemmelighet",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Kunne ikke laste den virtuelle API-nøkkelen hemmelighet",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Uten hentydning",
|
||||||
|
"virtualApiKeysInferenceBudget": "Budsjett",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Konfigurer hvordan denne nøkkelen begrenser AI-bruk basert på forbruk eller token begrensninger",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "E-postnøkkel ved generering",
|
||||||
|
"virtualApiKeysEmailThisKey": "E-post denne nøkkelen",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Send nøkkelen til den tilknyttede brukeren og ytterligere adresser etter at den er opprettet",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Send den nåværende nøkkelen til den tilknyttede brukeren og ytterligere adresser",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "E-post er ikke konfigurert på denne serveren",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Konfigurér SMTP for å sende virtuelle API-nøkler.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Send til tilknyttet bruker",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Send nøkkelen til den tilknyttede brukerens kontoe-post",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Assosier en bruker for å sende nøkkelen til den brukeren",
|
||||||
|
"virtualApiKeysEmailAdditional": "Ekstra e-poster",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Legg til e-post og trykk Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Velg den tilknyttede brukeren eller legg til minst én e-postadresse",
|
||||||
|
"myVirtualApiKeysTitle": "Dine API-nøkler",
|
||||||
|
"myVirtualApiKeysDescription": "Vis din identitetsnøkkel og eventuelle virtuelle API-nøkler tilskrives deg i denne organisasjonen",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Dine API-nøkler for {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Vis din identitetsnøkkel og virtuelle API-nøkler tilskrives deg som kan få tilgang til {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Identitetsnøkkel",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Din personlige API-nøkkel",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Din personlige nøkkel for denne organisasjonen. Den er unik til kontoen din og brukes til å identifisere deg når du kaller AI Gateway-ressurser.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Din personlige API-nøkkel for {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Din personlige nøkkel for denne organisasjonen. Bruk den til å kalle {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Tilskrevne nøkler",
|
||||||
|
"myVirtualApiKeysManualDescription": "Manuelle virtuelle API-nøkler en admin assosiert med kontoen din",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Manuelle virtuelle API-nøkler assosiert med kontoen din som kan få tilgang til {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Ingen tilskrevne nøkler ennå",
|
||||||
|
"myVirtualApiKeysKindUser": "Identitet",
|
||||||
|
"myVirtualApiKeysKindManual": "Manuell",
|
||||||
|
"myVirtualApiKeysUnnamed": "Uten navngitt nøkkel",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Avslør hemmelighet",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Denne hemmeligheten autentiserer deg til AI Gateway-ressurser",
|
||||||
|
"aiClientConfigTitle": "Konfigurer kodeagenter",
|
||||||
|
"aiClientConfigDescription": "Kopier konfigurasjon for populære kodeagenter, eller la Pangolin CLI sette det opp for deg automatisk.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Anthropics agentiske kodingsverktøy for terminalen.",
|
||||||
|
"aiClientConfigDescriptionCodex": "OpenAIs agentiske kodingsverktøy for terminalen.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Åpen kildekode terminal kodeagent.",
|
||||||
|
"aiClientConfigDescriptionCursor": "AI-kodeeditor bygget på VS Code.",
|
||||||
|
"aiClientConfigSetup": "Oppsett",
|
||||||
|
"aiClientConfigTabCli": "Automatisk (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Manuell konfigurasjon",
|
||||||
|
"aiClientConfigPreset": "Konfigurasjon",
|
||||||
|
"aiClientConfigStep": "Steg {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https:\\/\\/example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Denne koden inkluderer eksempelverdier, som et modellnavn eller en ressurs-URL. Erstatt de med dine egne før du bruker det.",
|
||||||
|
"aiClientConfigRevealError": "Kunne ikke laste inn din API-nøkkel.",
|
||||||
|
"aiClientConfigRevealRetry": "Prøv igjen",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Denne ressursen kan brukes fra vanlige klienter som Claude Code og OpenCode. <configLink>Lær mer<\\/configLink>",
|
||||||
|
"aiProvidersTitle": "AI-leverandører",
|
||||||
|
"aiProvidersDescription": "Koble modellleverandører for AI-arbeidslaster i denne organisasjonen",
|
||||||
|
"aiProvidersBannerTitle": "Koble modellleverandører",
|
||||||
|
"aiProvidersBannerDescription": "Leverandører er modell-backendene Pangolin bruker for AI-arbeidslaster. Koble OpenAI, Anthropic, og andre leverandører her, og fest dem deretter til offentlige AI-portene slik at brukere kan kalle modeller med identitetsbevisst tilgang, budsjetter, og logging.",
|
||||||
|
"aiProvidersAdd": "Legg til leverandør",
|
||||||
|
"aiProvidersSearch": "Søk leverandører...",
|
||||||
|
"aiProvidersEmpty": "Ingen AI-leverandører ennå",
|
||||||
|
"aiProviderCreate": "Opprett AI-leverandør",
|
||||||
|
"aiProviderCreateDescription": "Legg til en modellleverandør for denne organisasjonen",
|
||||||
|
"aiProviderSeeAll": "Se alle leverandører",
|
||||||
|
"aiProviderSetting": "Leverandørinnstillinger for {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Konfigurer denne AI-leverandøren",
|
||||||
|
"aiProviderGeneral": "Generelt",
|
||||||
|
"aiProviderGeneralDescription": "Grunnleggende innstillinger for denne leverandøren",
|
||||||
|
"aiProviderConfiguration": "Konfigurasjon",
|
||||||
|
"aiProviderConfigurationDescription": "Nettverksrutting og autentisering for denne leverandøren",
|
||||||
|
"aiProviderNetworkSettings": "Nettverksinnstillinger",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Velg hvordan trafikken når denne leverandøren",
|
||||||
|
"aiProviderAuthSettings": "Autentisering",
|
||||||
|
"aiProviderAuthSettingsDescription": "Konfigurer hvordan denne leverandøren autentiserer forespørsler til sin oppstrøms-URL",
|
||||||
|
"aiProviderBudgetSettings": "Budsjett",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Konfigurer hvordan denne leverandøren begrenser bruk basert på forbruk eller tokenbegrensninger",
|
||||||
|
"aiBudgetAdd": "Legg til budsjett",
|
||||||
|
"aiBudgetEmpty": "Ingen budsjetter konfigurert ennå. Klikk Legg til budsjett for å angi en forbruks- eller tokenbegrensning.",
|
||||||
|
"aiBudgetUnit": "Brukstype",
|
||||||
|
"aiBudgetPeriod": "Tilbakestill periode",
|
||||||
|
"aiBudgetAmount": "Maksimal forbruk",
|
||||||
|
"aiBudgetAmountPlaceholder": "Maksimal forbruk",
|
||||||
|
"aiBudgetPeriodHourly": "Timebasis",
|
||||||
|
"aiBudgetPeriodDaily": "Daglig",
|
||||||
|
"aiBudgetPeriodWeekly": "Ukentlig",
|
||||||
|
"aiBudgetPeriodMonthly": "Månedlig",
|
||||||
|
"aiBudgetPeriodYearly": "Årlig",
|
||||||
|
"aiBudgetPeriodLifetime": "Livstid",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Tokens",
|
||||||
|
"aiBudgetConflictError": "Et budsjett for denne tilbakestillingsperioden og forbrukstype eksisterer allerede",
|
||||||
|
"aiBudgetInvalidAmountError": "Angi et maksimalt forbruk større enn 0",
|
||||||
|
"aiBudgetUpdated": "Budsjetter oppdatert",
|
||||||
|
"aiBudgetErrorSave": "Kunne ikke oppdatere budsjettene",
|
||||||
|
"aiProviderType": "Leverandørtype",
|
||||||
|
"aiProviderTypeSearch": "Søk leverandører...",
|
||||||
|
"aiProviderTypeNotFound": "Ingen leverandør type funnet",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "Tilpasset",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Runtime API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "Bruk din egen endepunkt eller rute via områdetargets",
|
||||||
|
"aiProviderUpstreamUrl": "Oppstrøms URL",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Basis URL for leverandørens API",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "La stå tom for å bruke standard oppstrøms URL for denne leverandøren",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Effektiv oppstrøms URL",
|
||||||
|
"aiProviderApiKey": "API-nøkkel",
|
||||||
|
"aiProviderApiKeyDescription": "API-nøkkel brukt for å autentisere forespørsler til denne leverandøren",
|
||||||
|
"aiProviderCustomHeadersDescription": "Overskrifter sendt ved hver forespørsel til denne leverandøren. Ny linje separert: Overskriftsnavn: verdi",
|
||||||
|
"aiProviderApiKeyLastChars": "API-nøkkel",
|
||||||
|
"aiProviderAuthType": "Autentiseringstype",
|
||||||
|
"aiProviderAuthTypeSearch": "Søk autentiseringstyper...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Ingen autentiseringstype funnet",
|
||||||
|
"aiProviderAuthTypeBearer": "Bærer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Autorisasjon: Bærer nøkkel. Brukt av OpenAI og de fleste leverandører",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-key overskrift. Brukt av Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-key overskrift. Brukt av Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Autorisasjon: Splunk nøkkel. Brukt av Splunk HTTP Event Collector",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Bærer nøkkel. Brukt av Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeNone": "Ingen autentisering",
|
||||||
|
"aiProviderAuthTypePassthrough": "Gjennomkjøring",
|
||||||
|
"aiProviderAuthTypeDescription": "Hvordan det oppstrøms API-et autentiserer forespørsler",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Videreformidle anroperens API-nøkler til oppstrøms",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Ikke send autentiseringsoverskrifter til oppstrøms",
|
||||||
|
"aiProviderRoutingMode": "Ruteringsmodus",
|
||||||
|
"aiProviderRoutingModeDescription": "Send trafikk til en oppstrøms URL eller til HTTP-mål på dine nettsteder",
|
||||||
|
"aiProviderRoutingModeUrl": "Oppstrøms URL",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Ring en offentlig eller privat API-basis URL",
|
||||||
|
"aiProviderRoutingModeTarget": "Områdemål",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Rute gjennom mål på dine nettsteder",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Etter å ha opprettet denne leverandøren, konfigurer områdemål på fanen Nettverksinnstillinger.",
|
||||||
|
"aiProviderTargetNoOne": "Denne leverandøren har ingen mål. Legg til et mål for å rute forespørsler gjennom dine nettsteder.",
|
||||||
|
"aiProviderSkipTlsVerification": "Hopp over TLS-verifisering",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Deaktiver TLS-sertifikatverifisering for oppstrøms tilkobling",
|
||||||
|
"aiProviderBudget": "Budsjett",
|
||||||
|
"aiProviderBudgetDescription": "Valgfritt utgifts- eller tokenbudsjett for denne leverandøren",
|
||||||
|
"aiProviderBudgetAmount": "Budsjettbeløp",
|
||||||
|
"aiProviderBudgetUnit": "Budsjettenhet",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Tokens",
|
||||||
|
"aiProviderEnabled": "Aktivert",
|
||||||
|
"aiProviderEnabledDescription": "Deaktiver denne leverandøren fullstendig på tvers av alle ressurser",
|
||||||
|
"aiProviderErrorCreate": "Kunne ikke opprette AI-leverandør",
|
||||||
|
"aiProviderErrorUpdate": "Mislyktes å oppdatere AI-leverandør",
|
||||||
|
"aiProviderErrorDelete": "Kunne ikke slette AI-leverandør",
|
||||||
|
"aiProviderErrorLoad": "Kunne ikke laste AI-leverandør",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Skriv inn en gyldig oppstrøms URL",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Oppstrøms URL er nødvendig for denne leverandøren",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Autentiseringstype er påkrevd",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API-nøkkel er påkrevd",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Områdetargets rute er kun tilgjengelig for kundespesifikke leverandører",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Velg minst en API-kapasitet",
|
||||||
|
"aiProviderCapabilities": "API Kapasiteter",
|
||||||
|
"aiProviderCapabilitiesDescription": "Velg hvilke API-formater denne leverandøren kan håndtere. Kjente leverandører starter med anbefalte standarder.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Velg hvilke API-formater denne tilpassede leverandøren kan håndtere",
|
||||||
|
"aiProviderCapabilitiesSelect": "Velg kapasiteter",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Ingen kapasiteter funnet",
|
||||||
|
"aiProviderCapabilitiesSearch": "Søk kapasiteter...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Chat Fullføringer",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Støtter /v1/chat/fullføringer",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI Responser",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Støtter /v1/responser",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic Meldinger",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Støtter /v1/meldinger",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini Generer Innhold",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Støtter direkte Gemini API",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Bedrock Modell Påkalling",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Støtter Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex Generer Innhold",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Støtter Vertex AI Gemini format",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex Rå Prediksjon",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Støtter Vertex AI råPredikt for Anthropic-modeller",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock Samtale",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Støtter Amazon Bedrock Converse API",
|
||||||
|
"aiProviderCreated": "AI-leverandør opprettet",
|
||||||
|
"aiProviderUpdated": "AI-leverandør oppdatert",
|
||||||
|
"aiProviderDeleted": "AI-leverandør slettet",
|
||||||
|
"aiProviderDelete": "Slett Leverandør",
|
||||||
|
"aiProviderDeleteConfirm": "Slett Leverandør",
|
||||||
|
"aiProviderQuestionRemove": "Er du sikker på at du vil slette denne AI-leverandøren?",
|
||||||
|
"aiProviderMessageRemove": "Dette vil permanent slette leverandøren og dens modeller og mål. Dette kan ikke angres.",
|
||||||
|
"aiProviderErrorNoUpdate": "AI-leverandør er ikke tilgjengelig for oppdatering",
|
||||||
|
"aiProviderModels": "Modeller",
|
||||||
|
"aiProviderModelsDescription": "Definer tillat- og blokk-lister for denne leverandøren. Forespørslene må matche en tillat oppføring og må ikke samsvare med en blokk oppføring.",
|
||||||
|
"aiProviderCreateModelsDescription": "Velg hvilke modeller denne leverandøren kan betjene. En tom tillatsliste avviser alle trafikk. Du kan legge til eller endre modeller senere.",
|
||||||
|
"aiProviderModelsPlaceholder": "Søk modeller eller skriv inn en tilpasset nøkkel",
|
||||||
|
"aiProviderModelsAllow": "Tillat Liste",
|
||||||
|
"aiProviderModelsAllowDescription": "Modeller som kan brukes gjennom denne leverandøren. Tom betyr å nekte alt.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Skriv inn modellenøkkel",
|
||||||
|
"aiProviderModelsAllowEmpty": "Ingen modeller lagt til enda.",
|
||||||
|
"aiProviderModelsBlock": "Blokker Liste",
|
||||||
|
"aiProviderModelsBlockDescription": "Modeller for å nekte, selv om de samsvarer med en tillat oppføring.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Skriv inn modellenøkkel",
|
||||||
|
"aiProviderModelsBlockEmpty": "Ingen modeller lagt til enda.",
|
||||||
|
"aiProviderModelsAdd": "Legg til Modeller",
|
||||||
|
"aiProviderModelsClearAll": "Fjern alle",
|
||||||
|
"aiProviderModelsAddCustom": "Legg til \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Trykk Enter for å legge til denne tilpassede modellenøkkelen.",
|
||||||
|
"aiProviderModelsAddBulk": "Legg til {count} tilpassede nøkler",
|
||||||
|
"aiProviderModelsAddBulkHint": "Trykk Enter for å legge til {count} tilpassede nøkler.",
|
||||||
|
"aiProviderModelsAddOne": "Legg til {key} nå",
|
||||||
|
"aiProviderModelsAddSelected": "Legg til Valgt",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} valgt",
|
||||||
|
"aiProviderModelsSelectAll": "Velg alle",
|
||||||
|
"aiProviderModelsClearSelected": "Fjern",
|
||||||
|
"aiProviderModelsBulkHint": "Velg kjente modeller eller skriv inn en tilpasset nøkkel.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Ingen matchende katalogmodeller.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Kjente Modeller",
|
||||||
|
"aiProviderModelsAllLabel": "Alle modeller",
|
||||||
|
"aiProviderModelsAllPatternHint": "Jokertegn: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Tillat alle modeller",
|
||||||
|
"aiProviderModelsAddAllBlock": "Blokker alle modeller",
|
||||||
|
"aiProviderModelsAddAllDescription": "Bruker jokertegnet * slik at hver modellenøkkel matcher.",
|
||||||
|
"aiProviderModelsViewMore": "Vis mer ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Vis mindre",
|
||||||
|
"aiProviderModelsRemove": "Fjern modell",
|
||||||
|
"aiProviderModelsEditHint": "Klikk for å redigere modellinnstillinger",
|
||||||
|
"aiProviderModelsSourceCatalog": "Kjent katalogmodell",
|
||||||
|
"aiProviderModelsSourceCustom": "Tilpasset modellenøkkel",
|
||||||
|
"aiProviderModelsSourcePattern": "Jokertegnsmønster",
|
||||||
|
"aiProviderModelsSourceAll": "Matcher hver modellenøkkel",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Budsjett konfigurert",
|
||||||
|
"aiProviderModelsEditTitle": "Rediger Modell",
|
||||||
|
"aiProviderModelsEditDescription": "Oppdater modellenøkkelen eller konfigurer budsjettet.",
|
||||||
|
"aiProviderModelsBudgetTab": "Budsjett",
|
||||||
|
"aiProviderModelsKeyLabel": "Modell Nøkkel",
|
||||||
|
"aiProviderModelsKeyRequired": "Skriv inn en modellenøkkel",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Denne modellenøkkelen er allerede på en liste",
|
||||||
|
"aiProviderModelsOverlapError": "Disse mønstrene kan ikke være på begge listene: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modeller oppdatert",
|
||||||
|
"aiProviderModelsErrorUpdate": "Kunne ikke oppdatere modeller",
|
||||||
|
"aiResourceProviders": "Leverandører",
|
||||||
|
"aiResourceProvidersDescription": "Velg hvilke AI-leverandører denne AI-portalen kan bruke",
|
||||||
|
"aiResourceProvidersHelp": "Fest leverandører og velg arv (bruk hver leverandørlister) eller velg (velg en tillatliste for denne ressursen). Tillatmønstre som er i konflikt på tvers av vedlagte leverandører er ikke tillatt.",
|
||||||
|
"aiResourceProvidersSelect": "Velg leverandører",
|
||||||
|
"aiResourceProvidersEmpty": "Ingen AI-leverandører funnet",
|
||||||
|
"aiResourceProvidersNoneAttached": "Ingen leverandører knyttet ennå.",
|
||||||
|
"aiResourceProvidersAdd": "Legg til leverandør",
|
||||||
|
"aiResourceProvidersRemove": "Fjern leverandør",
|
||||||
|
"aiResourceProviderToggleEnabled": "Aktiver eller deaktiver denne leverandøren på ressursen",
|
||||||
|
"aiResourceProviderDisabled": "Deaktivert",
|
||||||
|
"aiResourceProvidersUpdated": "Leverandører oppdatert",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Kunne ikke oppdatere leverandører",
|
||||||
|
"aiResourceProviderEditDescription": "Velg hvordan denne leverandørens modeller er eksponert på denne ressursen.",
|
||||||
|
"viewProviderSettings": "Vis Leverandørinnstillinger",
|
||||||
|
"aiResourceProviderMode": "Tilgangsmodus",
|
||||||
|
"aiResourceProviderModeInherit": "Arve",
|
||||||
|
"aiResourceProviderModeSelect": "Velg",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Velg · {count} modeller",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Bruk denne leverandørens tillat- og blokk-lister som konfigurert på leverandøren.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Velg en delmengde av denne leverandørens tillat-listemodeller for denne ressursen.",
|
||||||
|
"aiResourceProviderAllowModels": "Tillat liste",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Velg modeller",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Søk modeller...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Ingen modeller funnet",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Bare modeller fra denne leverandørens tillat liste kan velges.",
|
||||||
|
"aiResourceAliasRequired": "Alias er påkrevd for AI-portaler",
|
||||||
|
"aiResourceDomainConfiguration": "Domene Konfigurasjon",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Velg domenet kunder vil bruke for å nå denne AI-portalen.",
|
||||||
|
"aiUsageAnalyticsTitle": "AI Bruksanalyse",
|
||||||
|
"aiUsageAnalyticsDescription": "Analyser AI-gatewaykostnad, tokenbruk og aktivitet på tvers av leverandører, ressurser, roller og brukere",
|
||||||
|
"aiUsageTabOverview": "Oversikt",
|
||||||
|
"aiUsageTabProviders": "Leverandører",
|
||||||
|
"aiUsageTabResources": "Ressurser",
|
||||||
|
"aiUsageFilterProvider": "Leverandør",
|
||||||
|
"aiUsageFilterModel": "Modell",
|
||||||
|
"aiUsageFilterResource": "Ressurs",
|
||||||
|
"aiUsageFilterRole": "Rolle",
|
||||||
|
"aiUsageFilterUser": "Bruker",
|
||||||
|
"aiUsageFilterAllProviders": "Alle Leverandører",
|
||||||
|
"aiUsageFilterAllModels": "Alle Modeller",
|
||||||
|
"aiUsageFilterAllResources": "Alle Ressurser",
|
||||||
|
"aiUsageFilterAllRoles": "Alle Roller",
|
||||||
|
"aiUsageFilterAllUsers": "Alle Brukere",
|
||||||
|
"aiUsageFilterSearch": "Søk...",
|
||||||
|
"aiUsageFilterNotFound": "Ingen alternativer funnet",
|
||||||
|
"aiUsageResetFilters": "Tilbakestill Filtre",
|
||||||
|
"aiUsageRefresh": "Oppdater",
|
||||||
|
"aiUsageTokenTypePrompt": "Stikkord",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Cache-lesing",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Cache-skriving",
|
||||||
|
"aiUsageTokenTypeCompletion": "Fullføring",
|
||||||
|
"aiUsageTokenTypeReasoning": "Resonnering",
|
||||||
|
"aiUsageRequests": "Forespørsler",
|
||||||
|
"aiUsageCost": "Kostnad",
|
||||||
|
"aiUsageTokens": "Token",
|
||||||
|
"aiUsageOther": "Annet",
|
||||||
|
"aiUsageTotalRequests": "Totale Forespørsler",
|
||||||
|
"aiUsageTotalTokens": "Totale Token",
|
||||||
|
"aiUsageTotalCost": "Totale Kostnad",
|
||||||
|
"aiUsageEstimated": "Anslått",
|
||||||
|
"aiUsageRequestVolume": "Forespørselsvolum",
|
||||||
|
"aiUsageTokenUsage": "Tokenforbruk",
|
||||||
|
"aiUsageModelCost": "Modellkostnad",
|
||||||
|
"aiUsageModelTokens": "Modelltoken",
|
||||||
|
"aiUsageTopModels": "Toppmodeller",
|
||||||
|
"aiUsageTopProviders": "Topp Leverandører",
|
||||||
|
"aiUsageProviderCost": "Leverandørkostnad",
|
||||||
|
"aiUsageProviderTokenUsage": "Leverandør Tokenforbruk",
|
||||||
|
"aiUsageTopResources": "Top Ressurser",
|
||||||
|
"aiUsageResourceCost": "Ressurskostnad",
|
||||||
|
"aiUsageResourceTokenUsage": "Ressurs Tokenforbruk",
|
||||||
|
"aiUsageResourceTypePublic": "Offentlig Ressurs",
|
||||||
|
"aiUsageResourceTypeSite": "Privat Ressurs",
|
||||||
|
"aiUsageNoResource": "Ingen ressurs",
|
||||||
|
"aiUsageRolesTab": "Roller",
|
||||||
|
"aiUsageUsersTab": "Brukere",
|
||||||
|
"aiUsageTopRoles": "Topproller",
|
||||||
|
"aiUsageRoleCost": "Rollekostnad",
|
||||||
|
"aiUsageRoleTokenUsage": "Rolle Tokenforbruk",
|
||||||
|
"aiUsageTopUsers": "Toppbrukere",
|
||||||
|
"aiUsageUserCost": "Brukerkostnad",
|
||||||
|
"aiUsageUserTokenUsage": "Bruker Tokenforbruk",
|
||||||
|
"aiUsageUnknownUser": "Ukjent bruker",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Virtuelle API-nøkler",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Virtuell API-nøkkel",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Alle Virtuelle API-nøkler",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Topp Virtuelle API-nøkler",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Virtuell API-nøkkelkostnad",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Virtuell API-nøkkel Tokenforbruk",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Ingen virtuell API-nøkkel",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Uten navn nøkkel",
|
||||||
|
"aiUsageLoading": "Laster inn...",
|
||||||
|
"aiUsageNoData": "Ingen data",
|
||||||
|
"resourceBudgetSettings": "Budsjett",
|
||||||
|
"resourceBudgetSettingsDescription": "Konfigurer hvordan denne AI-portalen begrenser bruk basert på utgifter eller token-grenser",
|
||||||
"sidebarApiKeys": "API-nøkler",
|
"sidebarApiKeys": "API-nøkler",
|
||||||
"sidebarProvisioning": "Levering",
|
"sidebarProvisioning": "Levering",
|
||||||
"sidebarSettings": "Innstillinger",
|
"sidebarSettings": "Innstillinger",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Varslingsregel lagret",
|
"alertingRuleSaved": "Varslingsregel lagret",
|
||||||
"alertingRuleSavedCreatedDescription": "Din nye varslingsregel ble opprettet. Du kan fortsette å redigere den på denne siden.",
|
"alertingRuleSavedCreatedDescription": "Din nye varslingsregel ble opprettet. Du kan fortsette å redigere den på denne siden.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Endringene dine i denne varslingsregelen ble lagret.",
|
"alertingRuleSavedUpdatedDescription": "Endringene dine i denne varslingsregelen ble lagret.",
|
||||||
|
"alertingTestAlertSent": "Testvarsel sendt",
|
||||||
|
"alertingTestAlertSentDescription": "Et testvarsel ble sendt til handlingene konfigurert på denne regelen.",
|
||||||
"alertingEditRule": "Rediger varslingsregel",
|
"alertingEditRule": "Rediger varslingsregel",
|
||||||
"alertingCreateRule": "Opprett varslingsregel",
|
"alertingCreateRule": "Opprett varslingsregel",
|
||||||
"alertingRuleCredenzaDescription": "Velg hva som skal overvåkes, når det skal varsles, og hvordan du vil bli informert",
|
"alertingRuleCredenzaDescription": "Velg hva som skal overvåkes, når det skal varsles, og hvordan du vil bli informert",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Hver regel binder sammen hva som skal overvåkes (et område, helsekontroll eller ressurs), når det skal varsles (for eksempel offline eller usunn), og hvordan varsle teamet ditt via e-post, webhooks eller integrasjoner. Bruk denne listen for å opprette, aktivere og administrere disse reglene.",
|
"alertingRulesBannerDescription": "Hver regel binder sammen hva som skal overvåkes (et område, helsekontroll eller ressurs), når det skal varsles (for eksempel offline eller usunn), og hvordan varsle teamet ditt via e-post, webhooks eller integrasjoner. Bruk denne listen for å opprette, aktivere og administrere disse reglene.",
|
||||||
"alertingHealthChecksBannerTitle": "Overvåk helse & ressurser",
|
"alertingHealthChecksBannerTitle": "Overvåk helse & ressurser",
|
||||||
"alertingHealthChecksBannerDescription": "Helsekontroller er HTTP- eller TCP-monitorer du definerer én gang. Du kan deretter bruke dem som kilder i varslingsregler slik at du blir varslet når et mål blir sunt eller usunt. Helsekontroller på ressurser vises også her.",
|
"alertingHealthChecksBannerDescription": "Helsekontroller er HTTP- eller TCP-monitorer du definerer én gang. Du kan deretter bruke dem som kilder i varslingsregler slik at du blir varslet når et mål blir sunt eller usunt. Helsekontroller på ressurser vises også her.",
|
||||||
|
"alertingTestRule": "Test varselsregel",
|
||||||
|
"alertingAddActionHeading": "Legg til ny handling",
|
||||||
|
"alertingSelectActionType": "Velg en handling",
|
||||||
|
"alertingNoActionsTitle": "Ingen handlinger konfigurert",
|
||||||
|
"alertingNoActionsSaveDescription": "Legg til minst én handling slik at denne regelen kan varsle noen når den utløses.",
|
||||||
|
"alertingNoActionsTestDescription": "Legg til minst én handling før du kan teste denne regelen.",
|
||||||
"standaloneHcTableTitle": "Helsekontroller",
|
"standaloneHcTableTitle": "Helsekontroller",
|
||||||
"standaloneHcSearchPlaceholder": "Søk i helsekontroller…",
|
"standaloneHcSearchPlaceholder": "Søk i helsekontroller…",
|
||||||
"standaloneHcAddButton": "Opprett helsekontroll",
|
"standaloneHcAddButton": "Opprett helsekontroll",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Underdomene: {subdomain}",
|
"domainPickerSubdomain": "Underdomene: {subdomain}",
|
||||||
"domainPickerNamespace": "Navnerom: {namespace}",
|
"domainPickerNamespace": "Navnerom: {namespace}",
|
||||||
"domainPickerShowMore": "Vis mer",
|
"domainPickerShowMore": "Vis mer",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Ingen domener tilgjengelig",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Du har ikke satt opp noen domener ennå. Opprett et domene for å fortsette.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Gå til domener",
|
||||||
"regionSelectorTitle": "Velg Region",
|
"regionSelectorTitle": "Velg Region",
|
||||||
"domainPickerRemoteExitNodeWarning": "Tilbudte domener støttes ikke når sider kobles til eksterne avkjøringsnoder. For ressurser som skal være tilgjengelige på eksterne noder, brukes et egendefinert domene i stedet.",
|
"domainPickerRemoteExitNodeWarning": "Tilbudte domener støttes ikke når sider kobles til eksterne avkjøringsnoder. For ressurser som skal være tilgjengelige på eksterne noder, brukes et egendefinert domene i stedet.",
|
||||||
"regionSelectorInfo": "Å velge en region hjelper oss med å gi bedre ytelse for din lokasjon. Du trenger ikke være i samme region som serveren.",
|
"regionSelectorInfo": "Å velge en region hjelper oss med å gi bedre ytelse for din lokasjon. Du trenger ikke være i samme region som serveren.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Subnett",
|
"subnetPlaceholder": "Subnett",
|
||||||
"addressDescription": "Den interne adressen til klienten. Må falle innenfor organisasjonens undernett.",
|
"addressDescription": "Den interne adressen til klienten. Må falle innenfor organisasjonens undernett.",
|
||||||
"selectSites": "Velg områder",
|
"selectSites": "Velg områder",
|
||||||
|
"selectResources": "Velg ressurser",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# ressurs} other {# ressurser}}",
|
||||||
"selectLabels": "Velg etiketter",
|
"selectLabels": "Velg etiketter",
|
||||||
"sitesDescription": "Klienten vil ha tilkobling til de valgte områdene",
|
"sitesDescription": "Klienten vil ha tilkobling til de valgte områdene",
|
||||||
"clientInstallOlm": "Installer Olm",
|
"clientInstallOlm": "Installer Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Tid er i sekunder",
|
"timeIsInSeconds": "Tid er i sekunder",
|
||||||
"requireDeviceApproval": "Krev enhetsgodkjenning",
|
"requireDeviceApproval": "Krev enhetsgodkjenning",
|
||||||
"requireDeviceApprovalDescription": "Brukere med denne rollen trenger nye enheter godkjent av en admin før de kan koble seg og få tilgang til ressurser.",
|
"requireDeviceApprovalDescription": "Brukere med denne rollen trenger nye enheter godkjent av en admin før de kan koble seg og få tilgang til ressurser.",
|
||||||
"sshSettings": "SSH Innstillinger",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI Portal",
|
||||||
"sshAccess": "SSH-tilgang",
|
"sshAccess": "SSH-tilgang",
|
||||||
"rdpSettings": "RDP Innstillinger",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "VNC Innstillinger",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH-server",
|
"sshServer": "SSH-server",
|
||||||
"rdpServer": "RDP-server",
|
"rdpServer": "RDP-server",
|
||||||
"vncServer": "VNC-server",
|
"vncServer": "VNC-server",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Offentlig",
|
"resourcesTableProxyResources": "Offentlig",
|
||||||
"resourcesTableClientResources": "Privat",
|
"resourcesTableClientResources": "Privat",
|
||||||
"resourcesTableNoProxyResourcesFound": "Ingen proxy-ressurser funnet.",
|
"resourcesTableNoProxyResourcesFound": "Ingen proxy-ressurser funnet.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Ingen interne ressurser funnet.",
|
"resourcesTableNoInternalResourcesFound": "Ingen private ressurser funnet.",
|
||||||
"resourcesTableDestination": "Destinasjon",
|
"resourcesTableDestination": "Destinasjon",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Alias adresse",
|
"resourcesTableAliasAddress": "Alias adresse",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Avbryt",
|
"editInternalResourceDialogCancel": "Avbryt",
|
||||||
"editInternalResourceDialogSaveResource": "Lagre ressurs",
|
"editInternalResourceDialogSaveResource": "Lagre ressurs",
|
||||||
"editInternalResourceDialogSuccess": "Suksess",
|
"editInternalResourceDialogSuccess": "Suksess",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Intern ressurs oppdatert vellykket",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Privat ressurs oppdatert vellykket",
|
||||||
"editInternalResourceDialogError": "Feil",
|
"editInternalResourceDialogError": "Feil",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Mislyktes å oppdatere intern ressurs",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Feil ved oppdatering av privat ressurs",
|
||||||
"editInternalResourceDialogNameRequired": "Navn er påkrevd",
|
"editInternalResourceDialogNameRequired": "Navn er påkrevd",
|
||||||
"editInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn",
|
"editInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn",
|
||||||
"editInternalResourceDialogProxyPortMin": "Proxy-port må være minst 1",
|
"editInternalResourceDialogProxyPortMin": "Proxy-port må være minst 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI Portal",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Skjema",
|
"editInternalResourceDialogScheme": "Skjema",
|
||||||
"editInternalResourceDialogEnableSsl": "Aktiver TLS",
|
"editInternalResourceDialogEnableSsl": "Aktiver TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Et valgfritt internt DNS-alias for denne ressursen.",
|
"editInternalResourceDialogAliasDescription": "Et valgfritt internt DNS-alias for denne ressursen.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Ingen tilgjengelige steder",
|
"createInternalResourceDialogNoSitesAvailable": "Ingen tilgjengelige steder",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Du må ha minst ett Newt-område med et konfigureret delnett for å lage interne ressurser.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Du må ha minst ett Newt-område med et subnett konfigurert for å opprette private ressurser.",
|
||||||
"createInternalResourceDialogClose": "Lukk",
|
"createInternalResourceDialogClose": "Lukk",
|
||||||
"createInternalResourceDialogCreateClientResource": "Opprett privat ressurs",
|
"createInternalResourceDialogCreateClientResource": "Opprett privat ressurs",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Opprett en ny ressurs som bare vil være tilgjengelig for kunder som er koblet til organisasjonen",
|
"createInternalResourceDialogCreateClientResourceDescription": "Opprett en ny ressurs som bare vil være tilgjengelig for kunder som er koblet til organisasjonen",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Tillat ICMP Ping",
|
"privateResourceAllowIcmpPing": "Tillat ICMP Ping",
|
||||||
"privateResourceNetworkAccess": "Nettverkstilgang",
|
"privateResourceNetworkAccess": "Nettverkstilgang",
|
||||||
"privateResourceNetworkAccessDescription": "Kontroller TCP/UDP porttilgang og om ICMP ping tillates for denne ressursen.",
|
"privateResourceNetworkAccessDescription": "Kontroller TCP/UDP porttilgang og om ICMP ping tillates for denne ressursen.",
|
||||||
"hostSettings": "Vertinnstillinger",
|
"hostSettings": "Vert",
|
||||||
"cidrSettings": "CIDR-innstillinger",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Ressursegenskaper",
|
"createInternalResourceDialogResourceProperties": "Ressursegenskaper",
|
||||||
"createInternalResourceDialogName": "Navn",
|
"createInternalResourceDialogName": "Navn",
|
||||||
"createInternalResourceDialogSite": "Område",
|
"createInternalResourceDialogSite": "Område",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Avbryt",
|
"createInternalResourceDialogCancel": "Avbryt",
|
||||||
"createInternalResourceDialogCreateResource": "Opprett ressurs",
|
"createInternalResourceDialogCreateResource": "Opprett ressurs",
|
||||||
"createInternalResourceDialogSuccess": "Suksess",
|
"createInternalResourceDialogSuccess": "Suksess",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Intern ressurs opprettet vellykket",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Privat ressurs opprettet vellykket",
|
||||||
"createInternalResourceDialogError": "Feil",
|
"createInternalResourceDialogError": "Feil",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke opprette intern ressurs",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke opprette privat ressurs",
|
||||||
"createInternalResourceDialogNameRequired": "Navn er påkrevd",
|
"createInternalResourceDialogNameRequired": "Navn er påkrevd",
|
||||||
"createInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn",
|
"createInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Vennligst velg et område",
|
"createInternalResourceDialogPleaseSelectSite": "Vennligst velg et område",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI Portal",
|
||||||
"scheme": "Skjema",
|
"scheme": "Skjema",
|
||||||
"createInternalResourceDialogScheme": "Skjema",
|
"createInternalResourceDialogScheme": "Skjema",
|
||||||
"createInternalResourceDialogEnableSsl": "Aktiver TLS",
|
"createInternalResourceDialogEnableSsl": "Aktiver TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Gyldig passord",
|
"validPassword": "Gyldig passord",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Gyldig Virtuell API-nøkkel",
|
||||||
"view": "Vis",
|
"view": "Vis",
|
||||||
"configManaged": "Konfigurasjon administrert",
|
"configManaged": "Konfigurasjon administrert",
|
||||||
"connectedClient": "Tilkoblet klient",
|
"connectedClient": "Tilkoblet klient",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Logg tilbaketrekning",
|
"logRetention": "Logg tilbaketrekning",
|
||||||
"logRetentionDescription": "Håndter hvor lenge ulike typer logger beholdes for denne organisasjonen, eller deaktiver dem",
|
"logRetentionDescription": "Håndter hvor lenge ulike typer logger beholdes for denne organisasjonen, eller deaktiver dem",
|
||||||
"requestLogsDescription": "Se detaljerte forespørselslogger for ressurser i denne organisasjonen",
|
"requestLogsDescription": "Se detaljerte forespørselslogger for ressurser i denne organisasjonen",
|
||||||
|
"aiSessionLogs": "AI Portal Sesjonslogger",
|
||||||
|
"aiSessionLogsDescription": "Vis stikkord- og responsutskrifter for AI-portal forespørsler i denne organisasjonen",
|
||||||
|
"sidebarLogsAi": "Sesjonslogger",
|
||||||
|
"commandLogsAi": "Sesjonslogger",
|
||||||
|
"sidebarLogsAiUsage": "Bruksanalyse",
|
||||||
|
"commandLogsAiUsage": "Bruksanalyse",
|
||||||
|
"provider": "Leverandør",
|
||||||
|
"capability": "Kapasitet",
|
||||||
|
"model": "Modell",
|
||||||
|
"virtualApiKey": "Virtuell API-nøkkel",
|
||||||
|
"noVirtualApiKey": "Ingen virtuell API-nøkkel",
|
||||||
|
"stream": "Strøm",
|
||||||
|
"streaming": "Strømming",
|
||||||
|
"nonStreaming": "Ikke-strømming",
|
||||||
|
"statusCode": "Statuskode",
|
||||||
|
"aiSessionId": "Sesjons ID",
|
||||||
|
"aiSessionRequest": "Forespørsel",
|
||||||
|
"aiSessionResponse": "Respons",
|
||||||
|
"aiSessionNoData": "Ingen data registrert",
|
||||||
|
"aiSessionCouldNotParse": "(rå, kunne ikke analysere utskrift)",
|
||||||
|
"aiSessionLogTruncated": "Denne sesjonen ble avkortet før lagring og kan være ufullstendig.",
|
||||||
|
"aiSessionViewRaw": "Vis Rå JSON",
|
||||||
|
"aiSessionViewChat": "Vis Chat",
|
||||||
|
"cost": "Kostnad",
|
||||||
|
"estimated": "Anslått",
|
||||||
|
"tokenUsage": "Tokenforbruk",
|
||||||
|
"promptTokens": "Stikkord Token",
|
||||||
|
"cacheReadTokens": "Cache-lesing Token",
|
||||||
|
"cacheWriteTokens": "Cache-skriving Token",
|
||||||
|
"completionTokens": "Fullføring Token",
|
||||||
|
"reasoningTokens": "Resonnering Token",
|
||||||
|
"totalTokens": "Totale Token",
|
||||||
"requestAnalyticsDescription": "Se detaljert rekvisisjonsanalyse for ressurser i denne organisasjonen",
|
"requestAnalyticsDescription": "Se detaljert rekvisisjonsanalyse for ressurser i denne organisasjonen",
|
||||||
"logRetentionRequestLabel": "Be om loggbevaring",
|
"logRetentionRequestLabel": "Be om loggbevaring",
|
||||||
"logRetentionRequestDescription": "Hvor lenge du vil beholde forespørselslogger",
|
"logRetentionRequestDescription": "Hvor lenge du vil beholde forespørselslogger",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Hvor lenge handlingen skal lagres",
|
"logRetentionActionDescription": "Hvor lenge handlingen skal lagres",
|
||||||
"logRetentionConnectionLabel": "Logg nyhet",
|
"logRetentionConnectionLabel": "Logg nyhet",
|
||||||
"logRetentionConnectionDescription": "Hvor lenge du vil beholde tilkoblingslogger",
|
"logRetentionConnectionDescription": "Hvor lenge du vil beholde tilkoblingslogger",
|
||||||
|
"logRetentionAISessionsLabel": "Bevaringsinnstillinger AI-portal sesjonslogger",
|
||||||
|
"logRetentionAISessionsDescription": "Hvor lenge man skal bevare stikkord/response sesjonslogger for AI-portaler",
|
||||||
"logRetentionDisabled": "Deaktivert",
|
"logRetentionDisabled": "Deaktivert",
|
||||||
"logRetention3Days": "3 dager",
|
"logRetention3Days": "3 dager",
|
||||||
"logRetention7Days": "7 dager",
|
"logRetention7Days": "7 dager",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Kilde adresse",
|
"sourceAddress": "Kilde adresse",
|
||||||
"destinationAddress": "Måladresse (Automatic Translation)",
|
"destinationAddress": "Måladresse (Automatic Translation)",
|
||||||
"duration": "Varighet",
|
"duration": "Varighet",
|
||||||
"licenseRequiredToUse": "En <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> lisens eller <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> er påkrevd for å bruke denne funksjonen. <bookADemoLink>Bestill en demo eller POC prøveversjon</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Enterprise Edition lisens</enterpriseEditionLink> er påkrevd. <bookADemoLink>Bestill en demo eller prøveversjon</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> er nødvendig for å bruke denne funksjonen. Denne funksjonen er også tilgjengelig i <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Bestill en demo eller POC studie</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition lisens</enterpriseEditionLink> er påkrevd. <bookADemoLink>Bestill en demo eller prøveversjon</bookADemoLink>",
|
||||||
"certResolver": "Sertifikat løser",
|
"certResolver": "Sertifikat løser",
|
||||||
"certResolverDescription": "Velg sertifikatløser som skal brukes for denne ressursen.",
|
"certResolverDescription": "Velg sertifikatløser som skal brukes for denne ressursen.",
|
||||||
"selectCertResolver": "Velg sertifikatløser",
|
"selectCertResolver": "Velg sertifikatløser",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Valg av flere nettsteder muliggjør motstandskraftig ruting og failover for høy tilgjengelighet.",
|
"internalResourceFormMultiSiteRoutingHelp": "Valg av flere nettsteder muliggjør motstandskraftig ruting og failover for høy tilgjengelighet.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Lær mer",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Lær mer",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Begrens tilgang til spesifikke TCP/UDP-porter eller tillate/blokkere alle porter.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Begrens tilgang til spesifikke TCP/UDP-porter eller tillate/blokkere alle porter.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "HTTP-konfigurasjon",
|
"createInternalResourceDialogHttpConfiguration": "Domene Konfigurasjon",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Velg domenet klienter vil bruke for å nå denne ressursen via HTTP eller HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Velg domenet klienter vil bruke for å nå denne ressursen via HTTP eller HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "HTTP-konfigurasjon",
|
"editInternalResourceDialogHttpConfiguration": "Domene Konfigurasjon",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Velg domenet klienter vil bruke for å nå denne ressursen via HTTP eller HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Velg domenet klienter vil bruke for å nå denne ressursen via HTTP eller HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Umerket",
|
"resourceLauncherUnlabeled": "Umerket",
|
||||||
|
"resourceLauncherAiGateway": "AI Portal",
|
||||||
"resourceLauncherNoSite": "Ingen område",
|
"resourceLauncherNoSite": "Ingen område",
|
||||||
|
"resourceLauncherAvailableModels": "Tilgjengelige Modeller",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modeller du kan bruke med denne AI-portalen.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Ingen modeller er tilgjengelige for denne ressursen.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Kunne ikke laste inn tilgjengelige modeller.",
|
||||||
|
"resourceLauncherApiKeys": "API-nøkler",
|
||||||
|
"resourceLauncherApiKeysDescription": "Bruk din identitetsnøkkel eller en tillagt nøkkel for å autentisere med denne ressursen.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Identitetsnøkkel",
|
||||||
|
"resourceLauncherApiKeysManual": "Tildelte nøkler",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Ingen API-nøkler er tilgjengelige for denne ressursen.",
|
||||||
|
"resourceLauncherApiKeysError": "Kunne ikke laste inn API-nøkler.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Ingen ressurser i denne gruppen",
|
"resourceLauncherNoResourcesInGroup": "Ingen ressurser i denne gruppen",
|
||||||
"resourceLauncherEmptyStateTitle": "Ingen tilgjengelige ressurser",
|
"resourceLauncherEmptyStateTitle": "Ingen tilgjengelige ressurser",
|
||||||
"resourceLauncherEmptyStateDescription": "Du har ennå ikke tilgang til noen ressurser. Kontakt administratoren din for å be om tilgang.",
|
"resourceLauncherEmptyStateDescription": "Du har ennå ikke tilgang til noen ressurser. Kontakt administratoren din for å be om tilgang.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Kunne ikke slette lanseringsvisningen. Vennligst prøv igjen.",
|
"resourceLauncherViewDeleteFailedDescription": "Kunne ikke slette lanseringsvisningen. Vennligst prøv igjen.",
|
||||||
"memberPortalPrevious": "Forrige",
|
"memberPortalPrevious": "Forrige",
|
||||||
"memberPortalNext": "Neste",
|
"memberPortalNext": "Neste",
|
||||||
"httpSettings": "HTTP Innstillinger",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "TCP Innstillinger",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "UDP Innstillinger",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Opprette en sikker tilkobling…",
|
"sshConnectingDescription": "Opprette en sikker tilkobling…",
|
||||||
"sshConnecting": "Kobler til…",
|
"sshConnecting": "Kobler til…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Opplastningen mislyktes",
|
"rdpUploadFailed": "Opplastningen mislyktes",
|
||||||
"rdpUnicodeKeyboardMode": "Unicode tastaturmodus",
|
"rdpUnicodeKeyboardMode": "Unicode tastaturmodus",
|
||||||
"sessionToolbarShow": "Vis verktøylinje",
|
"sessionToolbarShow": "Vis verktøylinje",
|
||||||
"sessionToolbarHide": "Skjul verktøylinje"
|
"sessionToolbarHide": "Skjul verktøylinje",
|
||||||
|
"actionUpdateSiteApprovals": "Oppdater Stedsgodkjenninger"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Upewnij się, że jesteś zalogowany jako właściwy użytkownik.",
|
"inviteLoginUser": "Upewnij się, że jesteś zalogowany jako właściwy użytkownik.",
|
||||||
"inviteErrorNoUser": "Przykro nam, ale wygląda na to, że zaproszenie, do którego próbujesz uzyskać dostęp, nie jest dla użytkownika, który istnieje.",
|
"inviteErrorNoUser": "Przykro nam, ale wygląda na to, że zaproszenie, do którego próbujesz uzyskać dostęp, nie jest dla użytkownika, który istnieje.",
|
||||||
"inviteCreateUser": "Proszę najpierw utworzyć konto.",
|
"inviteCreateUser": "Proszę najpierw utworzyć konto.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Zaproszenia mogą być akceptowane tylko przez wewnętrzne konta. Wyloguj się i zaloguj, używając hasła dla tego e-maila.",
|
||||||
|
"inviteLoginInternalOnly": "Zaproszenia wymagają wewnętrznego konta z hasłem. Stwórz konto lub zaloguj się używając hasła.",
|
||||||
"goHome": "Przejdź do strony głównej",
|
"goHome": "Przejdź do strony głównej",
|
||||||
"inviteLogInOtherUser": "Zaloguj się jako inny użytkownik",
|
"inviteLogInOtherUser": "Zaloguj się jako inny użytkownik",
|
||||||
"createAnAccount": "Utwórz konto",
|
"createAnAccount": "Utwórz konto",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Potwierdź usunięcie linku do udostępnienia",
|
"shareDeleteConfirm": "Potwierdź usunięcie linku do udostępnienia",
|
||||||
"shareQuestionRemove": "Czy na pewno chcesz usunąć ten link udostępniania?",
|
"shareQuestionRemove": "Czy na pewno chcesz usunąć ten link udostępniania?",
|
||||||
"shareMessageRemove": "Po usunięciu, link przestanie działać i wszyscy korzystający z niego stracą dostęp do zasobu.",
|
"shareMessageRemove": "Po usunięciu, link przestanie działać i wszyscy korzystający z niego stracą dostęp do zasobu.",
|
||||||
"shareTokenDescription": "Token dostępu może być przekazywany na dwa sposoby: jako parametr zapytania lub w nagłówkach żądania. Muszą być przekazywane z klienta na każde żądanie uwierzytelnionego dostępu.",
|
"shareTokenDescription": "Token dostępu można przekazać jako parametr zapytania lub w nagłówkach żądania. Domyślnie musi być wysyłany w każdym żądaniu. Jeśli trwałość sesji jest włączona, pierwsze żądanie wymienia go na ciasteczko sesji.",
|
||||||
"accessToken": "Token dostępu",
|
"accessToken": "Token dostępu",
|
||||||
"usageExamples": "Przykłady użycia",
|
"usageExamples": "Przykłady użycia",
|
||||||
"tokenId": "Identyfikator tokena",
|
"tokenId": "Identyfikator tokena",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Tytuł (opcjonalnie)",
|
"shareTitleOptional": "Tytuł (opcjonalnie)",
|
||||||
"sharePathOptional": "Ścieżka (opcjonalnie)",
|
"sharePathOptional": "Ścieżka (opcjonalnie)",
|
||||||
"sharePathDescription": "Link przekieruje użytkowników do tej ścieżki po uwierzytelnieniu.",
|
"sharePathDescription": "Link przekieruje użytkowników do tej ścieżki po uwierzytelnieniu.",
|
||||||
|
"shareAssociateUserOptional": "Powiąż użytkownika (opcjonalnie)",
|
||||||
|
"shareAssociateUserDescription": "Po ustawieniu, żądania korzystające z tego linku są przypisywane do użytkownika w logach dostępu i nagłówkach tożsamości. Link jest usuwany, jeśli użytkownik opuszcza organizację.",
|
||||||
|
"userSelect": "Wybierz użytkownika",
|
||||||
|
"usersNotFound": "Nie znaleziono użytkowników",
|
||||||
"expireIn": "Wygasa za",
|
"expireIn": "Wygasa za",
|
||||||
"neverExpire": "Nigdy nie wygasa",
|
"neverExpire": "Nigdy nie wygasa",
|
||||||
|
"sharePersistSession": "Utrzymaj sesję po pierwszym użyciu",
|
||||||
|
"sharePersistSessionDescription": "Gdy ta opcja jest włączona, pierwsze żądanie z tym tokenem przez parametr zapytania lub nagłówek ustawia ciasteczko sesji, dzięki czemu późniejsze żądania nie wymagają tokena. Pomijaj dla klienta API, który powinien wysyłać token w każdym żądaniu.",
|
||||||
"shareExpireDescription": "Czas wygaśnięcia to jak długo link będzie mógł być użyty i zapewni dostęp do zasobu. Po tym czasie link nie będzie już działał, a użytkownicy, którzy użyli tego linku, utracą dostęp do zasobu.",
|
"shareExpireDescription": "Czas wygaśnięcia to jak długo link będzie mógł być użyty i zapewni dostęp do zasobu. Po tym czasie link nie będzie już działał, a użytkownicy, którzy użyli tego linku, utracą dostęp do zasobu.",
|
||||||
"shareSeeOnce": "Możesz zobaczyć ten link tylko raz. Pamiętaj, aby go skopiować.",
|
"shareSeeOnce": "Możesz zobaczyć ten link tylko raz. Pamiętaj, aby go skopiować.",
|
||||||
"shareAccessHint": "Każdy z tym linkiem może uzyskać dostęp do zasobu. Podziel się nim ostrożnie.",
|
"shareAccessHint": "Każdy z tym linkiem może uzyskać dostęp do zasobu. Podziel się nim ostrożnie.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Nie znaleziono kraju.",
|
"noCountryFound": "Nie znaleziono kraju.",
|
||||||
"siteSelectionDescription": "Ta strona zapewni połączenie z celem.",
|
"siteSelectionDescription": "Ta strona zapewni połączenie z celem.",
|
||||||
"resourceType": "Typ zasobu",
|
"resourceType": "Typ zasobu",
|
||||||
"resourceTypeDescription": "To kontroluje protokół zasobu i sposób jego renderowania w przeglądarce. Później nie można tego zmienić.",
|
"resourceTypeDescription": "To kontroluje protokół zasobów i nie można tego później zmienić.",
|
||||||
|
"resourceTypeSearch": "Szukaj typów zasobów...",
|
||||||
|
"resourceTypeNotFound": "Nie znaleziono typu zasobu",
|
||||||
|
"resourceTypeHttpDescription": "Proxy ruchu sieciowego przez HTTPS za pomocą nazwy domeny",
|
||||||
|
"resourceTypeInferenceDescription": "Przekieruj żądania AI przez dołączonych dostawców",
|
||||||
|
"resourceTypeSshDescription": "Dostęp do serwera SSH z przeglądarki",
|
||||||
|
"resourceTypeRdpDescription": "Dostęp do pulpitu zdalnego z przeglądarki",
|
||||||
|
"resourceTypeVncDescription": "Dostęp do pulpitu VNC z przeglądarki",
|
||||||
|
"resourceTypeTcpDescription": "Proxy surowego ruchu TCP za pomocą numeru portu",
|
||||||
|
"resourceTypeUdpDescription": "Proxy surowego ruchu UDP za pomocą numeru portu",
|
||||||
|
"privateResourceTypeDescription": "To kontroluje, jak klienci uzyskują dostęp do zasobu. To nie może być zmienione później.",
|
||||||
|
"privateResourceTypeHostDescription": "Udostępnij pojedynczego hosta w sieci witryny dla połączonych klientów",
|
||||||
|
"privateResourceTypeCidrDescription": "Udostępnij zakres CIDR w sieci witryny dla połączonych klientów",
|
||||||
|
"privateResourceTypeHttpDescription": "Dostęp do usługi HTTP lub HTTPS przez domenę",
|
||||||
|
"privateResourceTypeSshDescription": "Dostęp do serwera SSH dla połączonych klientów",
|
||||||
"resourceDomainDescription": "Zasób będzie udostępniany pod tym w pełni kwalifikowanym adresem domenowym.",
|
"resourceDomainDescription": "Zasób będzie udostępniany pod tym w pełni kwalifikowanym adresem domenowym.",
|
||||||
"resourceHTTPSSettings": "Ustawienia HTTPS",
|
"resourceHTTPSSettings": "Ustawienia HTTPS",
|
||||||
"resourceHTTPSSettingsDescription": "Skonfiguruj jak zasób będzie dostępny przez HTTPS",
|
"resourceHTTPSSettingsDescription": "Skonfiguruj jak zasób będzie dostępny przez HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Dostarczanie",
|
"provisioningManage": "Dostarczanie",
|
||||||
"provisioningDescription": "Zarządzaj kluczami rezerwacji i sprawdzaj oczekujące strony oczekujące na zatwierdzenie.",
|
"provisioningDescription": "Zarządzaj kluczami rezerwacji i sprawdzaj oczekujące strony oczekujące na zatwierdzenie.",
|
||||||
"pendingSites": "Witryny oczekujące",
|
"pendingSites": "Witryny oczekujące",
|
||||||
"siteApproveSuccess": "Witryna została pomyślnie zatwierdzona",
|
"siteApproveSuccess": "Witryna i powiązane zasoby zostały zatwierdzone pomyślnie",
|
||||||
"siteApproveError": "Błąd zatwierdzania witryny",
|
"siteApproveError": "Błąd zatwierdzania witryny",
|
||||||
|
"siteReject": "Odrzuć witrynę",
|
||||||
|
"siteQuestionReject": "Czy na pewno chcesz odrzucić tę witrynę?",
|
||||||
|
"siteMessageReject": "Spowoduje to trwałe usunięcie witryny i wszelkich powiązanych, nadal oczekujących zasobów.",
|
||||||
|
"siteConfirmReject": "Potwierdź odrzucenie witryny",
|
||||||
|
"siteRejectSuccess": "Witryna została odrzucona pomyślnie",
|
||||||
|
"siteRejectError": "Błąd podczas odrzucania witryny",
|
||||||
"provisioningKeys": "Klucze Zaopatrzenia",
|
"provisioningKeys": "Klucze Zaopatrzenia",
|
||||||
"searchProvisioningKeys": "Szukaj kluczy zaopatrzenia...",
|
"searchProvisioningKeys": "Szukaj kluczy zaopatrzenia...",
|
||||||
"provisioningKeysAdd": "Wygeneruj klucz zaopatrzenia",
|
"provisioningKeysAdd": "Wygeneruj klucz zaopatrzenia",
|
||||||
@@ -466,7 +494,7 @@
|
|||||||
"provisioningKeysSave": "Zapisz klucz zaopatrzenia",
|
"provisioningKeysSave": "Zapisz klucz zaopatrzenia",
|
||||||
"provisioningKeysSaveDescription": "Możesz to zobaczyć tylko raz. Skopiuj je do bezpiecznego miejsca.",
|
"provisioningKeysSaveDescription": "Możesz to zobaczyć tylko raz. Skopiuj je do bezpiecznego miejsca.",
|
||||||
"provisioningKeysErrorCreate": "Błąd podczas tworzenia klucza zaopatrzenia",
|
"provisioningKeysErrorCreate": "Błąd podczas tworzenia klucza zaopatrzenia",
|
||||||
"provisioningKeysList": "Nowy klucz rezerwacji",
|
"provisioningKeysList": "Nowy klucz aprowizacyjny",
|
||||||
"provisioningKeysMaxBatchSize": "Maksymalny rozmiar partii",
|
"provisioningKeysMaxBatchSize": "Maksymalny rozmiar partii",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Nieograniczony rozmiar partii (bez limitu)",
|
"provisioningKeysUnlimitedBatchSize": "Nieograniczony rozmiar partii (bez limitu)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Nieograniczona",
|
"provisioningKeysMaxBatchUnlimited": "Nieograniczona",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Zapisz ustawienia",
|
"authMethodsSave": "Zapisz ustawienia",
|
||||||
"policyAuthStackTitle": "Uwierzytelnianie",
|
"policyAuthStackTitle": "Uwierzytelnianie",
|
||||||
"policyAuthStackDescription": "Kontroluj, które metody uwierzytelniania są wymagane do uzyskania dostępu do tego zasobu",
|
"policyAuthStackDescription": "Kontroluj, które metody uwierzytelniania są wymagane do uzyskania dostępu do tego zasobu",
|
||||||
|
"policyAuthInferenceStackDescription": "Wybierz, którzy użytkownicy i role mogą się uwierzytelniać w tym stogu inferencyjnym AI",
|
||||||
"policyAuthOrLogicTitle": "Kilka metod uwierzytelniania jest aktywnych",
|
"policyAuthOrLogicTitle": "Kilka metod uwierzytelniania jest aktywnych",
|
||||||
"policyAuthOrLogicBanner": "Odwiedzający mogą się uwierzytelnić, korzystając z jednej z poniższych aktywnych metod. Nie muszą ukończyć wszystkich z nich.",
|
"policyAuthOrLogicBanner": "Odwiedzający mogą się uwierzytelnić, korzystając z jednej z poniższych aktywnych metod. Nie muszą ukończyć wszystkich z nich.",
|
||||||
"policyAuthMethodActive": "Aktywny",
|
"policyAuthMethodActive": "Aktywny",
|
||||||
"policyAuthMethodOff": "Wyłączony",
|
"policyAuthMethodOff": "Wyłączony",
|
||||||
"policyAuthSsoTitle": "Platforma SSO",
|
"policyAuthSsoTitle": "Platforma SSO",
|
||||||
"policyAuthSsoDescription": "Wymagany znak w identyfikatorze dostawcy Twojej organizacji",
|
"policyAuthSsoDescription": "Wymagany znak w identyfikatorze dostawcy Twojej organizacji",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "URL logowania",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Każdy użytkownik już posiada klucz API tożsamości, więc musisz tylko utworzyć wirtualne klucze API dla klientów niebędących użytkownikami lub wspólnego dostępu. Użytkownicy mogą pobrać swój klucz, logując się przez swojego dostawcę tożsamości na URL tego zasobu, gdzie będzie pokazany po zalogowaniu.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Każdy użytkownik już posiada klucz API tożsamości, więc musisz tylko utworzyć wirtualne klucze API dla klientów niebędących użytkownikami lub wspólnego dostępu. Użytkownicy pobierają swój klucz tutaj po zalogowaniu się przez swojego dostawcę tożsamości.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} użytkowników, {roles} ról",
|
"policyAuthSsoSummary": "{idp} · {users} użytkowników, {roles} ról",
|
||||||
"policyAuthSsoDefaultIdp": "Dostawca domyślny",
|
"policyAuthSsoDefaultIdp": "Dostawca domyślny",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Dodaj Dostawcę Tożsamości Domyślnej",
|
"policyAuthAddDefaultIdentityProvider": "Dodaj Dostawcę Tożsamości Domyślnej",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Wersja",
|
"newtVersion": "Wersja",
|
||||||
"architecture": "Architektura",
|
"architecture": "Architektura",
|
||||||
"sites": "Witryny",
|
"sites": "Witryny",
|
||||||
"siteWgAnyClients": "Użyj dowolnego klienta WireGuard, aby się połączyć. Będziesz musiał przekierować wewnętrzne zasoby za pomocą adresu IP.",
|
"siteWgAnyClients": "Użyj dowolnego klienta WireGuard do połączenia. Będziesz musiał adresować prywatne zasoby używając IP współpracownika.",
|
||||||
"siteWgCompatibleAllClients": "Kompatybilny ze wszystkimi klientami WireGuard",
|
"siteWgCompatibleAllClients": "Kompatybilny ze wszystkimi klientami WireGuard",
|
||||||
"siteWgManualConfigurationRequired": "Wymagana konfiguracja ręczna",
|
"siteWgManualConfigurationRequired": "Wymagana konfiguracja ręczna",
|
||||||
"userErrorNotAdminOrOwner": "Użytkownik nie jest administratorem ani właścicielem",
|
"userErrorNotAdminOrOwner": "Użytkownik nie jest administratorem ani właścicielem",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Nowa rola jest wymagana",
|
"accessRoleErrorNewRequired": "Nowa rola jest wymagana",
|
||||||
"accessRoleErrorRemove": "Nie udało się usunąć roli",
|
"accessRoleErrorRemove": "Nie udało się usunąć roli",
|
||||||
"accessRoleErrorRemoveDescription": "Wystąpił błąd podczas usuwania roli.",
|
"accessRoleErrorRemoveDescription": "Wystąpił błąd podczas usuwania roli.",
|
||||||
|
"accessRoleInferenceBudget": "Budżet AI",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Skonfiguruj, jak członkowie tej roli ograniczają użycie AI na podstawie wydatków lub limitów tokenów",
|
||||||
"accessRoleName": "Nazwa roli",
|
"accessRoleName": "Nazwa roli",
|
||||||
"accessRoleQuestionRemove": "Zamierzasz usunąć rolę `{name}`. Nie możesz cofnąć tej czynności.",
|
"accessRoleQuestionRemove": "Zamierzasz usunąć rolę `{name}`. Nie możesz cofnąć tej czynności.",
|
||||||
"accessRoleRemove": "Usuń rolę",
|
"accessRoleRemove": "Usuń rolę",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Utwórz użytkownika Org",
|
"createOrgUser": "Utwórz użytkownika Org",
|
||||||
"actionUpdateOrg": "Aktualizuj organizację",
|
"actionUpdateOrg": "Aktualizuj organizację",
|
||||||
"actionRemoveInvitation": "Usuń zaproszenie",
|
"actionRemoveInvitation": "Usuń zaproszenie",
|
||||||
|
"actionRemoveUserRole": "Usuń rolę użytkownika",
|
||||||
"actionUpdateUser": "Zaktualizuj użytkownika",
|
"actionUpdateUser": "Zaktualizuj użytkownika",
|
||||||
"actionGetUser": "Pobierz użytkownika",
|
"actionGetUser": "Pobierz użytkownika",
|
||||||
"actionGetOrgUser": "Pobierz użytkownika organizacji",
|
"actionGetOrgUser": "Pobierz użytkownika organizacji",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Usuń witrynę",
|
"actionDeleteSite": "Usuń witrynę",
|
||||||
"actionGetSite": "Pobierz witrynę",
|
"actionGetSite": "Pobierz witrynę",
|
||||||
"actionListSites": "Lista witryn",
|
"actionListSites": "Lista witryn",
|
||||||
|
"actionCreateAiProvider": "Utwórz Dostawcę AI",
|
||||||
|
"actionDeleteAiProvider": "Usuń Dostawcę AI",
|
||||||
|
"actionGetAiProvider": "Pobierz Dostawcę AI",
|
||||||
|
"actionListAiProviders": "Lista Dostawców AI",
|
||||||
|
"actionUpdateAiProvider": "Aktualizuj Dostawcę AI",
|
||||||
|
"actionCreateAiModel": "Utwórz Model AI",
|
||||||
|
"actionDeleteAiModel": "Usuń Model AI",
|
||||||
|
"actionGetAiModel": "Pobierz Model AI",
|
||||||
|
"actionListAiModels": "Lista Modeli AI",
|
||||||
|
"actionUpdateAiModel": "Aktualizuj Model AI",
|
||||||
|
"actionCreateAiBudget": "Utwórz Budżet AI",
|
||||||
|
"actionDeleteAiBudget": "Usuń Budżet AI",
|
||||||
|
"actionGetAiBudget": "Pobierz Budżet AI",
|
||||||
|
"actionListAiBudgets": "Lista Budżetów AI",
|
||||||
|
"actionUpdateAiBudget": "Aktualizuj Budżet AI",
|
||||||
|
"actionListResourceAiModels": "Lista modeli AI dla zasobu",
|
||||||
|
"actionSetResourceAiModels": "Ustaw modele AI dla zasobu",
|
||||||
|
"actionCreateVirtualApiKey": "Utwórz Wirtualny Klucz API",
|
||||||
|
"actionDeleteVirtualApiKey": "Usuń Wirtualny Klucz API",
|
||||||
|
"actionGetVirtualApiKey": "Pobierz Wirtualny Klucz API",
|
||||||
|
"actionListVirtualApiKeys": "Lista Wirtualnych Kluczy API",
|
||||||
|
"actionUpdateVirtualApiKey": "Aktualizuj Wirtualny Klucz API",
|
||||||
"actionApplyBlueprint": "Zastosuj schemat",
|
"actionApplyBlueprint": "Zastosuj schemat",
|
||||||
"actionListBlueprints": "Lista planów",
|
"actionListBlueprints": "Lista planów",
|
||||||
"actionGetBlueprint": "Pobierz plan",
|
"actionGetBlueprint": "Pobierz plan",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Wprowadź token konfiguracji z konsoli serwera.",
|
"setupTokenDescription": "Wprowadź token konfiguracji z konsoli serwera.",
|
||||||
"setupTokenRequired": "Wymagany jest token konfiguracji",
|
"setupTokenRequired": "Wymagany jest token konfiguracji",
|
||||||
"actionUpdateSite": "Aktualizuj witrynę",
|
"actionUpdateSite": "Aktualizuj witrynę",
|
||||||
|
"actionApproveSite": "Zatwierdź witrynę",
|
||||||
|
"actionRejectSite": "Odrzuć witrynę",
|
||||||
"actionResetSiteBandwidth": "Zresetuj przepustowość organizacji",
|
"actionResetSiteBandwidth": "Zresetuj przepustowość organizacji",
|
||||||
"actionListSiteRoles": "Lista dozwolonych ról witryny",
|
"actionListSiteRoles": "Lista dozwolonych ról witryny",
|
||||||
"actionCreateResource": "Utwórz zasób",
|
"actionCreateResource": "Utwórz zasób",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Ustaw kod PIN zasobu",
|
"actionSetResourcePincode": "Ustaw kod PIN zasobu",
|
||||||
"actionSetResourceEmailWhitelist": "Ustaw białą listę email zasobu",
|
"actionSetResourceEmailWhitelist": "Ustaw białą listę email zasobu",
|
||||||
"actionGetResourceEmailWhitelist": "Pobierz białą listę email zasobu",
|
"actionGetResourceEmailWhitelist": "Pobierz białą listę email zasobu",
|
||||||
|
"actionListResourcePolicies": "Lista zasad zasobu",
|
||||||
|
"actionCreateResourcePolicy": "Utwórz zasadę dla zasobu",
|
||||||
"actionGetResourcePolicy": "Pobierz politykę zasobów",
|
"actionGetResourcePolicy": "Pobierz politykę zasobów",
|
||||||
"actionUpdateResourcePolicy": "Zaktualizuj politykę zasobów",
|
"actionUpdateResourcePolicy": "Zaktualizuj politykę zasobów",
|
||||||
|
"actionDeleteResourcePolicy": "Usuń zasadę dla zasobu",
|
||||||
"actionSetResourcePolicyUsers": "Ustaw użytkowników polityki zasobów",
|
"actionSetResourcePolicyUsers": "Ustaw użytkowników polityki zasobów",
|
||||||
"actionSetResourcePolicyRoles": "Ustaw role polityki zasobów",
|
"actionSetResourcePolicyRoles": "Ustaw role polityki zasobów",
|
||||||
"actionSetResourcePolicyPassword": "Ustaw hasło polityki zasobów",
|
"actionSetResourcePolicyPassword": "Ustaw hasło polityki zasobów",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Lista zaproszeń",
|
"actionListInvitations": "Lista zaproszeń",
|
||||||
"actionExportLogs": "Eksportuj dzienniki",
|
"actionExportLogs": "Eksportuj dzienniki",
|
||||||
"actionViewLogs": "Zobacz dzienniki",
|
"actionViewLogs": "Zobacz dzienniki",
|
||||||
|
"actionCreateSiteProvisioningKey": "Utwórz klucz konfiguracji strony",
|
||||||
|
"actionListSiteProvisioningKeys": "Lista kluczy konfiguracji strony",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Zaktualizuj klucz konfiguracji strony",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Usuń klucz konfiguracji strony",
|
||||||
"noneSelected": "Nie wybrano",
|
"noneSelected": "Nie wybrano",
|
||||||
"orgNotFound2": "Nie znaleziono organizacji.",
|
"orgNotFound2": "Nie znaleziono organizacji.",
|
||||||
"search": "Szukaj…",
|
"search": "Szukaj…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Wprowadź kod z aplikacji uwierzytelniającej lub jeden z jednorazowych kodów zapasowych.",
|
"otpAuthDescription": "Wprowadź kod z aplikacji uwierzytelniającej lub jeden z jednorazowych kodów zapasowych.",
|
||||||
"otpAuthSubmit": "Wyślij kod",
|
"otpAuthSubmit": "Wyślij kod",
|
||||||
"idpContinue": "Lub kontynuuj z",
|
"idpContinue": "Lub kontynuuj z",
|
||||||
|
"idpLastUsed": "Ostatnio używany",
|
||||||
"otpAuthBack": "Powrót do hasła",
|
"otpAuthBack": "Powrót do hasła",
|
||||||
"navbar": "Menu nawigacyjne",
|
"navbar": "Menu nawigacyjne",
|
||||||
"navbarDescription": "Główne menu nawigacyjne aplikacji",
|
"navbarDescription": "Główne menu nawigacyjne aplikacji",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Utwórz klienta maszynowego",
|
"commandPaletteCreateMachineClient": "Utwórz klienta maszynowego",
|
||||||
"commandPaletteCreateAlertRule": "Utwórz regułę powiadomień",
|
"commandPaletteCreateAlertRule": "Utwórz regułę powiadomień",
|
||||||
"commandPaletteCreateIdentityProvider": "Utwórz dostawcę tożsamości",
|
"commandPaletteCreateIdentityProvider": "Utwórz dostawcę tożsamości",
|
||||||
|
"commandPaletteCreateAiProvider": "Utwórz dostawcę AI",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Utwórz wirtualny klucz API",
|
||||||
"commandPaletteToggleTheme": "Przełącz motyw",
|
"commandPaletteToggleTheme": "Przełącz motyw",
|
||||||
"commandPaletteChooseOrganization": "Wybierz organizację",
|
"commandPaletteChooseOrganization": "Wybierz organizację",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Zaproszenia",
|
"sidebarInvitations": "Zaproszenia",
|
||||||
"sidebarRoles": "Role",
|
"sidebarRoles": "Role",
|
||||||
"sidebarShareableLinks": "Linki do udostępnienia",
|
"sidebarShareableLinks": "Linki do udostępnienia",
|
||||||
|
"sidebarAiGateway": "Gateway AI",
|
||||||
|
"sidebarAiProviders": "Dostawcy",
|
||||||
|
"commandAiProviders": "Dostawcy AI",
|
||||||
|
"sidebarVirtualApiKeys": "Wirtualne Klucze API",
|
||||||
|
"sidebarMyApiKeys": "Twoje Klucze API",
|
||||||
|
"sidebarAccount": "Launcher",
|
||||||
|
"commandVirtualApiKeys": "Wirtualne Klucze API",
|
||||||
|
"virtualApiKeysTitle": "Zarządzaj Wirtualnymi Kluczami API",
|
||||||
|
"virtualApiKeysDescription": "Utwórz i zarządzaj ręcznymi kluczami API dla dostępu do publicznych bram AI",
|
||||||
|
"virtualApiKeysTabIdentity": "Klucze Tożsamości",
|
||||||
|
"virtualApiKeysTabVirtual": "Klucze Wirtualne",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Klucze Tożsamości dla Każdego Użytkownika",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Każdy użytkownik już posiada klucz tożsamości Pangolin dla tej organizacji. Jest unikalny dla ich konta i uwierzytelnia ich do bramek AI, do których mogą uzyskać dostęp.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Przykład",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Jak Użytkownicy Pozyskują Swoje Klucze",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Odwiedź publiczny URL Gateway AI w przeglądarce i zaloguj się na swoje konto.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Lub odwiedź <url></url> podczas zalogowania się.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Możesz stworzyć dodatkowe wirtualne klucze API na karcie Klucze Wirtualne. Te klucze mogą być przypisane do konkretnych publicznych bram AI i opcjonalnie przypisane do użytkownika. Tworzenie klucza natychmiast przyznaje dostęp do wybranych publicznych bramek AI.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Ręcznie Utwórz Klucz",
|
||||||
|
"virtualApiKeysEmailIdentity": "Wyślij Klucze Tożsamości Emailem",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Wyślij każdemu z wybranych użytkownikowi lub roli ich klucz tożsamości Pangolin.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Wyślij do wszystkich użytkowników",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Wyślij do wszystkich członków organizacji, którzy mają emaile kont.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Użytkownicy",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Role",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Wyślij Emaile",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Klucze tożsamości wysłane emailem",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Wysłano {sent} wiadomości e-mail.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} użytkowników zostało pominiętych, ponieważ nie mają adresu e-mail.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Wybierz co najmniej jednego użytkownika lub rolę, lub wyślij do wszystkich użytkowników.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Błąd przy wysyłaniu kluczy tożsamości",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Nie udało się wysłać emaila z kluczami tożsamości",
|
||||||
|
"virtualApiKeysBannerTitle": "Klucze Tożsamości dla Każdego Użytkownika",
|
||||||
|
"virtualApiKeysBannerDescription": "Każdy użytkownik już posiada klucz tożsamości dostępny pod {keysUrl}. Możesz również ręcznie wygenerować klucze tutaj, które przyznają bezpośredni dostęp do publicznych bramek AI.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Zobacz Klucze Tożsamości",
|
||||||
|
"virtualApiKeys": "Wirtualne Klucze API",
|
||||||
|
"virtualApiKeysSearch": "Szukaj kluczy...",
|
||||||
|
"virtualApiKeysCreate": "Utwórz Wirtualny Klucz API",
|
||||||
|
"virtualApiKeysCreateDescription": "Uwierz klucz ręczny, który może wywołać publiczne bramki AI w tej organizacji",
|
||||||
|
"virtualApiKeysCreateButton": "Utwórz Klucz",
|
||||||
|
"virtualApiKeysEmpty": "Nie ma jeszcze wirtualnych kluczy API",
|
||||||
|
"virtualApiKeysName": "Nazwa",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Opis (opcjonalnie)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Przypisz Użytkownika (opcjonalnie)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Przypisz ten klucz do użytkownika, aby śledzić użycie. Po utworzeniu klucz natychmiast przyznaje dostęp do wybranych publicznych bramek AI. Nie musisz przypisywać użytkownika ręcznie do zasobu. Klucz pojawi się również w profilu użytkownika.",
|
||||||
|
"virtualApiKeysAllResources": "Wszystkie publiczne bramki AI",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Pozwól temu kluczowi uzyskać dostęp do każdej publicznej bramki AI w organizacji",
|
||||||
|
"virtualApiKeysSelectResources": "Publiczne Bramki AI",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Wybierz zasoby",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Wybierz, do których publicznych bramek AI ten klucz może uzyskać dostęp",
|
||||||
|
"virtualApiKeysNoResources": "Brak zasobów",
|
||||||
|
"virtualApiKeysSecret": "Klucz",
|
||||||
|
"virtualApiKeysCopyKey": "Skopiuj ten klucz. Możesz go ponownie zobaczyć później w tabeli lub podczas edytowania.",
|
||||||
|
"virtualApiKeysViewSecret": "Zobacz Sekret",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Sekret Wirtualnego Klucza API",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Ten sekret zapewnia dostęp do publicznych bramek AI przypisanych do tego klucza",
|
||||||
|
"virtualApiKeysEdit": "Edytuj Wirtualny Klucz API",
|
||||||
|
"virtualApiKeysEditDescription": "Zaktualizuj powiązanego użytkownika i dostęp do publicznych bramek AI dla tego klucza",
|
||||||
|
"virtualApiKeysSaveButton": "Zapisz zmiany",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Wybierz co najmniej jedną publiczną bramkę AI lub włącz wszystkie publiczne bramki AI",
|
||||||
|
"virtualApiKeysUpdated": "Wirtualny klucz API zaktualizowany",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Wirtualny klucz API został zaktualizowany",
|
||||||
|
"virtualApiKeysErrorUpdate": "Błąd podczas aktualizacji wirtualnego klucza API",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Nie udało się zaktualizować wirtualnego klucza API",
|
||||||
|
"virtualApiKeysErrorCreate": "Błąd podczas tworzenia wirtualnego klucza API",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Nie udało się utworzyć wirtualnego klucza API",
|
||||||
|
"virtualApiKeysErrorDelete": "Błąd podczas usuwania wirtualnego klucza API",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Nie udało się usunąć wirtualnego klucza API",
|
||||||
|
"virtualApiKeysDeleted": "Wirtualny klucz API usunięty",
|
||||||
|
"virtualApiKeysDeletedDescription": "Wirtualny klucz API został usunięty",
|
||||||
|
"virtualApiKeysDelete": "Usuń Wirtualny Klucz API",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Usuń Klucz",
|
||||||
|
"virtualApiKeysQuestionRemove": "Czy na pewno chcesz usunąć ten wirtualny klucz API?",
|
||||||
|
"virtualApiKeysMessageRemove": "Klienci korzystający z tego klucza stracą natychmiastowo dostęp.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Błąd ładowania sekretu",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Nie udało się załadować sekretu wirtualnego klucza API",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Nieprzypisane",
|
||||||
|
"virtualApiKeysInferenceBudget": "Budżet",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Skonfiguruj, jak ten klucz ogranicza użytkowanie AI na podstawie wydatków lub limitów tokenów",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Wyślij klucz po jego wygenerowaniu",
|
||||||
|
"virtualApiKeysEmailThisKey": "Wyślij ten klucz emailem",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Wyślij klucz do powiązanego użytkownika i dodatkowych adresów po jego utworzeniu",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Wyślij bieżący klucz do powiązanego użytkownika i dodatkowych adresów",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "E-maile nie są skonfigurowane na tym serwerze",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Skonfiguruj SMTP, aby wysłać wirtualne klucze API emailem.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Wyślij do powiązanego użytkownika",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Wyślij klucz na e-mail konta powiązanego użytkownika",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Przypisz użytkownika, aby wysłać mu klucz",
|
||||||
|
"virtualApiKeysEmailAdditional": "Dodatkowe emaile",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Dodaj email i naciśnij Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Wybierz powiązanego użytkownika lub dodaj co najmniej jeden adres e-mail",
|
||||||
|
"myVirtualApiKeysTitle": "Twoje Klucze API",
|
||||||
|
"myVirtualApiKeysDescription": "Zobacz swój klucz tożsamości i wszelkie wirtualne klucze API przypisane do Ciebie w tej organizacji",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Twoje Klucze API dla {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Zobacz swój klucz tożsamości i wirtualne klucze API przypisane do Ciebie, które mogą uzyskać dostęp do {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Klucz Tożsamości",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Twój Osobisty Klucz API",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Twój osobisty klucz dla tej organizacji. Jest unikalny dla twojego konta i używany, aby zidentyfikować cię podczas wywoływania zasobów Gateway AI.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Twój Osobisty Klucz API dla {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Twój osobisty klucz dla tej organizacji. Użyj go, aby wywołać {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Przypisane Klucze",
|
||||||
|
"myVirtualApiKeysManualDescription": "Ręczne wirtualne klucze API, które administrator przypisał do twojego konta",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Ręczne wirtualne klucze API przypisane do twojego konta, które mogą uzyskać dostęp do {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Nie ma jeszcze przypisanych kluczy",
|
||||||
|
"myVirtualApiKeysKindUser": "Tożsamość",
|
||||||
|
"myVirtualApiKeysKindManual": "Ręczne",
|
||||||
|
"myVirtualApiKeysUnnamed": "Bez nazwy",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Ujawnij Sekret",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Ten sekret uwierzytelnia cię do zasobów Gateway AI",
|
||||||
|
"aiClientConfigTitle": "Skonfiguruj agentów kodujących",
|
||||||
|
"aiClientConfigDescription": "Skopiuj konfigurację dla popularnych agentów kodujących lub pozwól CLI Pangolin ustawić to automatycznie.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Agent narzędzia kodującego Anthropic dla terminala.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Agent narzędzia kodującego OpenAI dla terminala.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Agent open source do kodowania w terminalu.",
|
||||||
|
"aiClientConfigDescriptionCursor": "Edytor kodu AI oparty na VS Code.",
|
||||||
|
"aiClientConfigSetup": "Ustawienie",
|
||||||
|
"aiClientConfigTabCli": "Automatyczne (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Konfiguracja ręczna",
|
||||||
|
"aiClientConfigPreset": "Konfiguracja",
|
||||||
|
"aiClientConfigStep": "Krok {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Ten fragment zawiera przykładowe wartości, takie jak nazwa modelu czy URL zasobu. Zastąp je własnymi zanim użyjesz.",
|
||||||
|
"aiClientConfigRevealError": "Nie można załadować twojego klucza API.",
|
||||||
|
"aiClientConfigRevealRetry": "Spróbuj ponownie",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Ten zasób można używać z popularnymi klientami jak Claude Code i OpenCode. <configLink>Dowiedz się więcej</configLink>",
|
||||||
|
"aiProvidersTitle": "Dostawcy AI",
|
||||||
|
"aiProvidersDescription": "Połącz dostawców modeli dla obciążeń AI w tej organizacji",
|
||||||
|
"aiProvidersBannerTitle": "Połącz dostawców modeli",
|
||||||
|
"aiProvidersBannerDescription": "Dostawcy są modelami backendowymi, które Pangolin używa dla obciążeń AI. Połącz OpenAI, Anthropic i innych dostawców tutaj, a następnie dołącz je do publicznych bramek AI, aby użytkownicy mogli wywoływać modele z dostępem świadomym tożsamości, budżetami i logowaniem.",
|
||||||
|
"aiProvidersAdd": "Dodaj Dostawcę",
|
||||||
|
"aiProvidersSearch": "Szukaj dostawców...",
|
||||||
|
"aiProvidersEmpty": "Nie ma jeszcze dostawców AI",
|
||||||
|
"aiProviderCreate": "Utwórz Dostawcę AI",
|
||||||
|
"aiProviderCreateDescription": "Dodaj dostawcę modeli dla tej organizacji",
|
||||||
|
"aiProviderSeeAll": "Zobacz Wszystkich Dostawców",
|
||||||
|
"aiProviderSetting": "Ustawienia dostawcy dla {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Skonfiguruj tego dostawcę AI",
|
||||||
|
"aiProviderGeneral": "Ogólne",
|
||||||
|
"aiProviderGeneralDescription": "Podstawowe ustawienia dla tego dostawcy",
|
||||||
|
"aiProviderConfiguration": "Konfiguracja",
|
||||||
|
"aiProviderConfigurationDescription": "Routing sieciowy i uwierzytelnianie dla tego dostawcy",
|
||||||
|
"aiProviderNetworkSettings": "Ustawienia sieciowe",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Wybierz, jak ruch dociera do tego dostawcy",
|
||||||
|
"aiProviderAuthSettings": "Uwierzytelnianie",
|
||||||
|
"aiProviderAuthSettingsDescription": "Skonfiguruj, jak ten dostawca uwierzytelnia zapytania do swojego URL upstream",
|
||||||
|
"aiProviderBudgetSettings": "Budżet",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Skonfiguruj, jak ten dostawca ogranicza użycie na podstawie wydatków lub limitów tokenów",
|
||||||
|
"aiBudgetAdd": "Dodaj Budżet",
|
||||||
|
"aiBudgetEmpty": "Nie skonfigurowano jeszcze budżetów. Kliknij Dodaj Budżet, aby ustawić limit wydatków lub tokenów.",
|
||||||
|
"aiBudgetUnit": "Typ wydatku",
|
||||||
|
"aiBudgetPeriod": "Okres resetowania",
|
||||||
|
"aiBudgetAmount": "Maksymalny Wydatek",
|
||||||
|
"aiBudgetAmountPlaceholder": "Maksymalny wydatek",
|
||||||
|
"aiBudgetPeriodHourly": "Co godzinę",
|
||||||
|
"aiBudgetPeriodDaily": "Codziennie",
|
||||||
|
"aiBudgetPeriodWeekly": "Cotygodniowo",
|
||||||
|
"aiBudgetPeriodMonthly": "Co miesiąc",
|
||||||
|
"aiBudgetPeriodYearly": "Co rok",
|
||||||
|
"aiBudgetPeriodLifetime": "Na całe życie",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Tokeny",
|
||||||
|
"aiBudgetConflictError": "Istnieje już budżet dla tego okresu resetowania i typu wydatku",
|
||||||
|
"aiBudgetInvalidAmountError": "Wprowadź maksymalny wydatek większy niż 0",
|
||||||
|
"aiBudgetUpdated": "Budżety zaktualizowane",
|
||||||
|
"aiBudgetErrorSave": "Nie udało się zaktualizować budżetów",
|
||||||
|
"aiProviderType": "Typ dostawcy",
|
||||||
|
"aiProviderTypeSearch": "Szukaj dostawców...",
|
||||||
|
"aiProviderTypeNotFound": "Nie znaleziono typu dostawcy",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "Niestandardowy",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Runtime API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "Przynieś swój własny endpoint lub trasę przez cele witryny",
|
||||||
|
"aiProviderUpstreamUrl": "URL do góry",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Podstawowy URL dla API dostawcy",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Pozostaw puste, aby użyć domyślnego URL-u w górnym kierunku dla tego dostawcy",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Efektywny URL do góry",
|
||||||
|
"aiProviderApiKey": "Klucz API",
|
||||||
|
"aiProviderApiKeyDescription": "Klucz API używany do uwierzytelniania zapytań do tego dostawcy",
|
||||||
|
"aiProviderCustomHeadersDescription": "Nagłówki wysyłane przy każdym zapytaniu do tego dostawcy. Oddzielone nową linią: Nazwa nagłówka: wartość",
|
||||||
|
"aiProviderApiKeyLastChars": "Klucz API",
|
||||||
|
"aiProviderAuthType": "Typ autoryzacji",
|
||||||
|
"aiProviderAuthTypeSearch": "Wyszukaj typy autoryzacji...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Nie znaleziono typu autoryzacji",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Autoryzacja: klucz Bearer. Używane przez OpenAI i większość dostawców",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-klucz-api",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "nagłówek x-klucz-api. Używane przez Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-klucz-api",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "nagłówek x-goog-klucz-api. Używane przez Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Autoryzacja: klucz Splunk. Używane przez Splunk HTTP Event Collector",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-autoryzacja: klucz Bearer. Używane przez Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeNone": "Bez autoryzacji",
|
||||||
|
"aiProviderAuthTypePassthrough": "Przejście",
|
||||||
|
"aiProviderAuthTypeDescription": "Jak upstream API autoryzuje zapytania",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Przekaż nagłówki klucza API dzwoniącego do upstream",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Nie wysyłaj nagłówków autoryzacyjnych do upstream",
|
||||||
|
"aiProviderRoutingMode": "Tryb trasowania",
|
||||||
|
"aiProviderRoutingModeDescription": "Wysyłaj ruch do URL-u w górnym kierunku lub do celów HTTP na Twoich witrynach",
|
||||||
|
"aiProviderRoutingModeUrl": "URL do góry",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Zadzwoń na publiczny lub prywatny podstawowy URL API",
|
||||||
|
"aiProviderRoutingModeTarget": "Cele witryny",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Trasa przez cele na Twoich witrynach",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Po utworzeniu tego dostawcy, skonfiguruj cele witryny na karcie Ustawienia sieci.",
|
||||||
|
"aiProviderTargetNoOne": "Ten dostawca nie ma żadnych celów. Dodaj cel, aby trasować zapytania przez swoje witryny.",
|
||||||
|
"aiProviderSkipTlsVerification": "Pomiń weryfikację TLS",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Wyłącz weryfikację certyfikatu TLS dla połączenia w górę",
|
||||||
|
"aiProviderBudget": "Budżet",
|
||||||
|
"aiProviderBudgetDescription": "Opcjonalny budżet wydatków lub tokena dla tego dostawcy",
|
||||||
|
"aiProviderBudgetAmount": "Kwota budżetu",
|
||||||
|
"aiProviderBudgetUnit": "Jednostka budżetu",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Tokeny",
|
||||||
|
"aiProviderEnabled": "Włączone",
|
||||||
|
"aiProviderEnabledDescription": "Całkowicie wyłącz tego dostawcę we wszystkich zasobach",
|
||||||
|
"aiProviderErrorCreate": "Nie udało się utworzyć dostawcy AI",
|
||||||
|
"aiProviderErrorUpdate": "Nie udało się zaktualizować dostawcy AI",
|
||||||
|
"aiProviderErrorDelete": "Nie udało się usunąć dostawcy AI",
|
||||||
|
"aiProviderErrorLoad": "Nie udało się załadować dostawcy AI",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Wprowadź prawidłowy URL w górę",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "W tym dostawcy wymagany jest URL w górnym kierunku",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Wymagany typ autoryzacji",
|
||||||
|
"aiProviderErrorApiKeyRequired": "Wymagany klucz API",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Trasowanie celów witryny jest dostępne tylko dla niestandardowych dostawców",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Wybierz przynajmniej jedną zdolność API",
|
||||||
|
"aiProviderCapabilities": "Zdolności API",
|
||||||
|
"aiProviderCapabilitiesDescription": "Wybierz, które formaty API ten dostawca może obsługiwać. Znani dostawcy zaczynają od zalecanych domyślnych.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Wybierz, które formaty API ten niestandardowy dostawca może obsłużyć",
|
||||||
|
"aiProviderCapabilitiesSelect": "Wybierz możliwości",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Nie znaleziono możliwości",
|
||||||
|
"aiProviderCapabilitiesSearch": "Szukaj możliwości...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Chat Ukończone",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Obsługuje /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI Odpowiedzi",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Obsługuje /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic Wiadomości",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Obsługuje /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini Generowanie Treści",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Obsługuje bezpośredni Gemini API",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Model Bedrock Wywołanie",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Obsługuje Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex Generowanie Treści",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Obsługuje Vertex AI Gemini format",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex Surowe Predykcje",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Obsługuje Vertex AI przewidywania surowe dla modeli Anthropic",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock Rozmowa",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Obsługuje Amazon Bedrock Converse API",
|
||||||
|
"aiProviderCreated": "Dostawca AI utworzony",
|
||||||
|
"aiProviderUpdated": "Dostawca AI zaktualizowany",
|
||||||
|
"aiProviderDeleted": "Dostawca AI usunięty",
|
||||||
|
"aiProviderDelete": "Usuń Dostawcę",
|
||||||
|
"aiProviderDeleteConfirm": "Usuń Dostawcę",
|
||||||
|
"aiProviderQuestionRemove": "Czy na pewno chcesz usunąć tego dostawcę AI?",
|
||||||
|
"aiProviderMessageRemove": "To na zawsze usunie dostawcę i jego modele oraz cele. Tego nie można cofnąć.",
|
||||||
|
"aiProviderErrorNoUpdate": "Dostawca AI nie jest dostępny do aktualizacji",
|
||||||
|
"aiProviderModels": "Modele",
|
||||||
|
"aiProviderModelsDescription": "Zdefiniuj listy dozwolone i zablokowane dla tego dostawcy. Żądania muszą pasować do wpisu z listy dozwolonych i nie pasować do zablokowanych.",
|
||||||
|
"aiProviderCreateModelsDescription": "Wybierz, które modele ten dostawca może obsłużyć. Pusta lista dozwolonych odrzuca cały ruch. Możesz później dodać lub zmienić modele.",
|
||||||
|
"aiProviderModelsPlaceholder": "Szukaj modeli lub wpisz własny klucz",
|
||||||
|
"aiProviderModelsAllow": "Lista Dozwolonych",
|
||||||
|
"aiProviderModelsAllowDescription": "Modele, które można używać przez tego dostawcę. Pusta oznacza odrzucenie wszystkiego.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Wprowadź klucz modelu",
|
||||||
|
"aiProviderModelsAllowEmpty": "Nie dodano jeszcze żadnych modeli.",
|
||||||
|
"aiProviderModelsBlock": "Lista Zablokowanych",
|
||||||
|
"aiProviderModelsBlockDescription": "Modele do odrzucenia, nawet jeśli pasują do wpisu z listy dozwolonych.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Wprowadź klucz modelu",
|
||||||
|
"aiProviderModelsBlockEmpty": "Nie dodano jeszcze żadnych modeli.",
|
||||||
|
"aiProviderModelsAdd": "Dodaj Modele",
|
||||||
|
"aiProviderModelsClearAll": "Wyczyść Wszystko",
|
||||||
|
"aiProviderModelsAddCustom": "Dodaj \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Naciśnij Enter, aby dodać ten własny klucz modelu.",
|
||||||
|
"aiProviderModelsAddBulk": "Dodaj {count} własne klucze",
|
||||||
|
"aiProviderModelsAddBulkHint": "Naciśnij Enter, aby dodać {count} własne klucze.",
|
||||||
|
"aiProviderModelsAddOne": "Dodaj {key} teraz",
|
||||||
|
"aiProviderModelsAddSelected": "Dodaj Wybrane",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} wybrane",
|
||||||
|
"aiProviderModelsSelectAll": "Zaznacz wszystko",
|
||||||
|
"aiProviderModelsClearSelected": "Wyczyść",
|
||||||
|
"aiProviderModelsBulkHint": "Wybierz znane modele lub wpisz własny klucz.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Brak pasujących modeli w katalogu.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Znane Modele",
|
||||||
|
"aiProviderModelsAllLabel": "Wszystkie modele",
|
||||||
|
"aiProviderModelsAllPatternHint": "Dzika karta: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Zezwól na wszystkie modele",
|
||||||
|
"aiProviderModelsAddAllBlock": "Zablokuj wszystkie modele",
|
||||||
|
"aiProviderModelsAddAllDescription": "Używa dzikiej karty *, więc pasuje do każdego klucza modelu.",
|
||||||
|
"aiProviderModelsViewMore": "Zobacz więcej ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Zobacz mniej",
|
||||||
|
"aiProviderModelsRemove": "Usuń model",
|
||||||
|
"aiProviderModelsEditHint": "Kliknij, aby edytować ustawienia modelu",
|
||||||
|
"aiProviderModelsSourceCatalog": "Znany model katalogu",
|
||||||
|
"aiProviderModelsSourceCustom": "Własny klucz modelu",
|
||||||
|
"aiProviderModelsSourcePattern": "Wzór dzikiej karty",
|
||||||
|
"aiProviderModelsSourceAll": "Pasuje do każdego klucza modelu",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Budżet skonfigurowany",
|
||||||
|
"aiProviderModelsEditTitle": "Edytuj Model",
|
||||||
|
"aiProviderModelsEditDescription": "Zaktualizuj klucz modelu lub skonfiguruj jego budżet.",
|
||||||
|
"aiProviderModelsBudgetTab": "Budżet",
|
||||||
|
"aiProviderModelsKeyLabel": "Klucz Modelu",
|
||||||
|
"aiProviderModelsKeyRequired": "Wpisz klucz modelu",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Ten klucz modelu już jest na liście",
|
||||||
|
"aiProviderModelsOverlapError": "Te wzorce nie mogą być na obydwu listach: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modele zaktualizowane",
|
||||||
|
"aiProviderModelsErrorUpdate": "Nie udało się zaktualizować modeli",
|
||||||
|
"aiResourceProviders": "Dostawcy",
|
||||||
|
"aiResourceProvidersDescription": "Wybierz, z których dostawców AI ta brama AI może korzystać",
|
||||||
|
"aiResourceProvidersHelp": "Dołącz dostawców i wybierz dziedziczenie (użyj list każdego dostawcy) lub wybierz (wybierz listę dozwoloną dla tego zasobu). Wzory dozwolone, które konfliktują między dołączonymi dostawcami, nie są dozwolone.",
|
||||||
|
"aiResourceProvidersSelect": "Wybierz dostawców",
|
||||||
|
"aiResourceProvidersEmpty": "Nie znaleziono dostawców AI",
|
||||||
|
"aiResourceProvidersNoneAttached": "Nie dołączono jeszcze żadnych dostawców.",
|
||||||
|
"aiResourceProvidersAdd": "Dodaj dostawcę",
|
||||||
|
"aiResourceProvidersRemove": "Usuń dostawcę",
|
||||||
|
"aiResourceProviderToggleEnabled": "Włącz lub wyłącz tego dostawcę na zasobie",
|
||||||
|
"aiResourceProviderDisabled": "Wyłączone",
|
||||||
|
"aiResourceProvidersUpdated": "Dostawcy zaktualizowani",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Nie udało się zaktualizować dostawców",
|
||||||
|
"aiResourceProviderEditDescription": "Wybierz, jak modele tego dostawcy są udostępniane na tym zasobie.",
|
||||||
|
"viewProviderSettings": "Zobacz Ustawienia Dostawcy",
|
||||||
|
"aiResourceProviderMode": "Tryb dostępu",
|
||||||
|
"aiResourceProviderModeInherit": "Dziedziczenie",
|
||||||
|
"aiResourceProviderModeSelect": "Wybierz",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Wybierz · {count} modele",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Użyj list dozwolonych i zablokowanych tego dostawcy, skonfigurowanych na dostawcy.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Wybierz podzbiór modeli z listy dozwolonych tego dostawcy dla tego zasobu.",
|
||||||
|
"aiResourceProviderAllowModels": "Lista dozwolonych",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Wybierz modele",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Szukaj modeli...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Nie znaleziono modeli",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Tylko modele z listy dozwolonych tego dostawcy mogą być wybrane.",
|
||||||
|
"aiResourceAliasRequired": "Alias jest wymagany dla bramy AI",
|
||||||
|
"aiResourceDomainConfiguration": "Konfiguracja Domeny",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Wybierz domenę, której klienci będą używać, aby dotrzeć do tej bramy AI.",
|
||||||
|
"aiUsageAnalyticsTitle": "AI Użycie Analityki",
|
||||||
|
"aiUsageAnalyticsDescription": "Analizuj koszty bramy AI, użycie tokenów i aktywność wśród dostawców, zasobów, ról i użytkowników",
|
||||||
|
"aiUsageTabOverview": "Przegląd",
|
||||||
|
"aiUsageTabProviders": "Dostawcy",
|
||||||
|
"aiUsageTabResources": "Zasoby",
|
||||||
|
"aiUsageFilterProvider": "Dostawca",
|
||||||
|
"aiUsageFilterModel": "Model",
|
||||||
|
"aiUsageFilterResource": "Zasób",
|
||||||
|
"aiUsageFilterRole": "Rola",
|
||||||
|
"aiUsageFilterUser": "Użytkownik",
|
||||||
|
"aiUsageFilterAllProviders": "Wszyscy Dostawcy",
|
||||||
|
"aiUsageFilterAllModels": "Wszystkie Modele",
|
||||||
|
"aiUsageFilterAllResources": "Wszystkie Zasoby",
|
||||||
|
"aiUsageFilterAllRoles": "Wszystkie Role",
|
||||||
|
"aiUsageFilterAllUsers": "Wszyscy Użytkownicy",
|
||||||
|
"aiUsageFilterSearch": "Szukaj...",
|
||||||
|
"aiUsageFilterNotFound": "Nie znaleziono opcji",
|
||||||
|
"aiUsageResetFilters": "Resetuj Filtry",
|
||||||
|
"aiUsageRefresh": "Odśwież",
|
||||||
|
"aiUsageTokenTypePrompt": "Podpowiedź",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Odczyt z bufora",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Zapis do bufora",
|
||||||
|
"aiUsageTokenTypeCompletion": "Ukończenie",
|
||||||
|
"aiUsageTokenTypeReasoning": "Rozumowanie",
|
||||||
|
"aiUsageRequests": "Żądania",
|
||||||
|
"aiUsageCost": "Koszt",
|
||||||
|
"aiUsageTokens": "Tokeny",
|
||||||
|
"aiUsageOther": "Inne",
|
||||||
|
"aiUsageTotalRequests": "Łączna liczba Żądań",
|
||||||
|
"aiUsageTotalTokens": "Łączna liczba Tokenów",
|
||||||
|
"aiUsageTotalCost": "Całkowity Koszt",
|
||||||
|
"aiUsageEstimated": "Szacowany",
|
||||||
|
"aiUsageRequestVolume": "Objętość żądań",
|
||||||
|
"aiUsageTokenUsage": "Użycie Tokenów",
|
||||||
|
"aiUsageModelCost": "Koszt Modelu",
|
||||||
|
"aiUsageModelTokens": "Tokeny Modelu",
|
||||||
|
"aiUsageTopModels": "Najlepsze Modele",
|
||||||
|
"aiUsageTopProviders": "Najlepsi Dostawcy",
|
||||||
|
"aiUsageProviderCost": "Koszt Dostawcy",
|
||||||
|
"aiUsageProviderTokenUsage": "Użycie Tokenów Dostawcy",
|
||||||
|
"aiUsageTopResources": "Najlepsze Zasoby",
|
||||||
|
"aiUsageResourceCost": "Koszt Zasobu",
|
||||||
|
"aiUsageResourceTokenUsage": "Użycie Tokenów Zasobu",
|
||||||
|
"aiUsageResourceTypePublic": "Publiczny Zasób",
|
||||||
|
"aiUsageResourceTypeSite": "Prywatny Zasób",
|
||||||
|
"aiUsageNoResource": "Brak zasobu",
|
||||||
|
"aiUsageRolesTab": "Role",
|
||||||
|
"aiUsageUsersTab": "Użytkownicy",
|
||||||
|
"aiUsageTopRoles": "Najlepsze Role",
|
||||||
|
"aiUsageRoleCost": "Koszt Roli",
|
||||||
|
"aiUsageRoleTokenUsage": "Użycie Tokenów Roli",
|
||||||
|
"aiUsageTopUsers": "Najwięcej Użytkowników",
|
||||||
|
"aiUsageUserCost": "Koszt Użytkownika",
|
||||||
|
"aiUsageUserTokenUsage": "Użycie Tokenów Użytkownika",
|
||||||
|
"aiUsageUnknownUser": "Nieznany użytkownik",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Wirtualne Klucze API",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Wirtualny Klucz API",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Wszystkie Wirtualne Klucze API",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Najlepsze Wirtualne Klucze API",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Koszt Wirtualnego Klucza API",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Użycie Tokenów Wirtualnego Klucza API",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Brak wirtualnego klucza API",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Bezimienny klucz",
|
||||||
|
"aiUsageLoading": "Ładowanie...",
|
||||||
|
"aiUsageNoData": "Brak danych",
|
||||||
|
"resourceBudgetSettings": "Budżet",
|
||||||
|
"resourceBudgetSettingsDescription": "Skonfiguruj, jak ta brama AI ogranicza użycie na podstawie limitów wydatków lub tokenów",
|
||||||
"sidebarApiKeys": "Klucze API",
|
"sidebarApiKeys": "Klucze API",
|
||||||
"sidebarProvisioning": "Dostarczanie",
|
"sidebarProvisioning": "Dostarczanie",
|
||||||
"sidebarSettings": "Ustawienia",
|
"sidebarSettings": "Ustawienia",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Reguła alarmowa zapisana",
|
"alertingRuleSaved": "Reguła alarmowa zapisana",
|
||||||
"alertingRuleSavedCreatedDescription": "Nowa reguła alarmowa została utworzona. Możesz ją kontynuować edytować na tej stronie.",
|
"alertingRuleSavedCreatedDescription": "Nowa reguła alarmowa została utworzona. Możesz ją kontynuować edytować na tej stronie.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Twoje zmiany w tej regule alarmowej zostały zapisane.",
|
"alertingRuleSavedUpdatedDescription": "Twoje zmiany w tej regule alarmowej zostały zapisane.",
|
||||||
|
"alertingTestAlertSent": "Wysłano alert testowy",
|
||||||
|
"alertingTestAlertSentDescription": "Alert testowy został wysłany do działań skonfigurowanych na tej regule.",
|
||||||
"alertingEditRule": "Edytuj regułę alarmową",
|
"alertingEditRule": "Edytuj regułę alarmową",
|
||||||
"alertingCreateRule": "Utwórz regułę alarmową",
|
"alertingCreateRule": "Utwórz regułę alarmową",
|
||||||
"alertingRuleCredenzaDescription": "Wybierz, co obserwować, kiedy uruchamiać i jak powiadamiać.",
|
"alertingRuleCredenzaDescription": "Wybierz, co obserwować, kiedy uruchamiać i jak powiadamiać.",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Każda reguła wiąże ze sobą co obserwować (np. witryna, kontrola zdrowia czy zasób), kiedy uruchomić (np. offline lub niezdrowy), oraz jak powiadomić zespół przez e-mail, webhooks lub integracje. Użyj tej listy, aby utworzyć, włączyć i zarządzać tymi regułami.",
|
"alertingRulesBannerDescription": "Każda reguła wiąże ze sobą co obserwować (np. witryna, kontrola zdrowia czy zasób), kiedy uruchomić (np. offline lub niezdrowy), oraz jak powiadomić zespół przez e-mail, webhooks lub integracje. Użyj tej listy, aby utworzyć, włączyć i zarządzać tymi regułami.",
|
||||||
"alertingHealthChecksBannerTitle": "Monitor Zdrowia i Zasobów",
|
"alertingHealthChecksBannerTitle": "Monitor Zdrowia i Zasobów",
|
||||||
"alertingHealthChecksBannerDescription": "Kontrole zdrowia to monitory HTTP lub TCP, które definiujesz raz. Następnie możesz używać ich jako źródeł w regułach alarmowych, aby otrzymywać powiadomienia, kiedy cel stanie się zdrowy lub niezdrowy. Kontrole zdrowia w zasobach również pojawiają się tutaj.",
|
"alertingHealthChecksBannerDescription": "Kontrole zdrowia to monitory HTTP lub TCP, które definiujesz raz. Następnie możesz używać ich jako źródeł w regułach alarmowych, aby otrzymywać powiadomienia, kiedy cel stanie się zdrowy lub niezdrowy. Kontrole zdrowia w zasobach również pojawiają się tutaj.",
|
||||||
|
"alertingTestRule": "Testowa reguła alertów",
|
||||||
|
"alertingAddActionHeading": "Dodaj nowe działanie",
|
||||||
|
"alertingSelectActionType": "Wybierz działanie",
|
||||||
|
"alertingNoActionsTitle": "Nie skonfigurowano działań",
|
||||||
|
"alertingNoActionsSaveDescription": "Dodaj przynajmniej jedno działanie, aby ta reguła mogła powiadomić osobę, gdy zostanie uruchomiona.",
|
||||||
|
"alertingNoActionsTestDescription": "Dodaj przynajmniej jedno działanie przed przetestowaniem tej reguły.",
|
||||||
"standaloneHcTableTitle": "Kontrole Zdrowia",
|
"standaloneHcTableTitle": "Kontrole Zdrowia",
|
||||||
"standaloneHcSearchPlaceholder": "Szukaj kontroli zdrowia…",
|
"standaloneHcSearchPlaceholder": "Szukaj kontroli zdrowia…",
|
||||||
"standaloneHcAddButton": "Utwórz Kontrolę Zdrowia",
|
"standaloneHcAddButton": "Utwórz Kontrolę Zdrowia",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Subdomena: {subdomain}",
|
"domainPickerSubdomain": "Subdomena: {subdomain}",
|
||||||
"domainPickerNamespace": "Przestrzeń nazw: {namespace}",
|
"domainPickerNamespace": "Przestrzeń nazw: {namespace}",
|
||||||
"domainPickerShowMore": "Pokaż więcej",
|
"domainPickerShowMore": "Pokaż więcej",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Brak dostępnych domen",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Nie masz jeszcze skonfigurowanych żadnych domen. Utwórz domenę, aby kontynuować.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Przejdź do Domena",
|
||||||
"regionSelectorTitle": "Wybierz region",
|
"regionSelectorTitle": "Wybierz region",
|
||||||
"domainPickerRemoteExitNodeWarning": "Podane domeny nie są obsługiwane, gdy witryny łączą się ze zdalnymi węzłami wyjścia. Aby zasoby były dostępne w węzłach zdalnych, użyj domeny niestandardowej.",
|
"domainPickerRemoteExitNodeWarning": "Podane domeny nie są obsługiwane, gdy witryny łączą się ze zdalnymi węzłami wyjścia. Aby zasoby były dostępne w węzłach zdalnych, użyj domeny niestandardowej.",
|
||||||
"regionSelectorInfo": "Wybór regionu pomaga nam zapewnić lepszą wydajność dla Twojej lokalizacji. Nie musisz być w tym samym regionie co Twój serwer.",
|
"regionSelectorInfo": "Wybór regionu pomaga nam zapewnić lepszą wydajność dla Twojej lokalizacji. Nie musisz być w tym samym regionie co Twój serwer.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Podsieć",
|
"subnetPlaceholder": "Podsieć",
|
||||||
"addressDescription": "Adres wewnętrzny klienta. Musi mieścić się w podsieci organizacji.",
|
"addressDescription": "Adres wewnętrzny klienta. Musi mieścić się w podsieci organizacji.",
|
||||||
"selectSites": "Wybierz witryny",
|
"selectSites": "Wybierz witryny",
|
||||||
|
"selectResources": "Wybierz zasoby",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# zasób} few {# zasoby} many {# zasobów} other {# zasobów}}",
|
||||||
"selectLabels": "Wybierz etykiety",
|
"selectLabels": "Wybierz etykiety",
|
||||||
"sitesDescription": "Klient będzie miał łączność z wybranymi witrynami",
|
"sitesDescription": "Klient będzie miał łączność z wybranymi witrynami",
|
||||||
"clientInstallOlm": "Zainstaluj Olm",
|
"clientInstallOlm": "Zainstaluj Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Czas w sekundach",
|
"timeIsInSeconds": "Czas w sekundach",
|
||||||
"requireDeviceApproval": "Wymagaj zatwierdzenia urządzenia",
|
"requireDeviceApproval": "Wymagaj zatwierdzenia urządzenia",
|
||||||
"requireDeviceApprovalDescription": "Użytkownicy o tej roli potrzebują nowych urządzeń zatwierdzonych przez administratora, zanim będą mogli połączyć się i uzyskać dostęp do zasobów.",
|
"requireDeviceApprovalDescription": "Użytkownicy o tej roli potrzebują nowych urządzeń zatwierdzonych przez administratora, zanim będą mogli połączyć się i uzyskać dostęp do zasobów.",
|
||||||
"sshSettings": "Ustawienia SSH",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "Brama AI",
|
||||||
"sshAccess": "Dostęp SSH",
|
"sshAccess": "Dostęp SSH",
|
||||||
"rdpSettings": "Ustawienia RDP",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "Ustawienia VNC",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "Serwer SSH",
|
"sshServer": "Serwer SSH",
|
||||||
"rdpServer": "Serwer RDP",
|
"rdpServer": "Serwer RDP",
|
||||||
"vncServer": "Serwer VNC",
|
"vncServer": "Serwer VNC",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Publiczne",
|
"resourcesTableProxyResources": "Publiczne",
|
||||||
"resourcesTableClientResources": "Prywatny",
|
"resourcesTableClientResources": "Prywatny",
|
||||||
"resourcesTableNoProxyResourcesFound": "Nie znaleziono zasobów proxy.",
|
"resourcesTableNoProxyResourcesFound": "Nie znaleziono zasobów proxy.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Nie znaleziono wewnętrznych zasobów.",
|
"resourcesTableNoInternalResourcesFound": "Nie znaleziono prywatnych zasobów.",
|
||||||
"resourcesTableDestination": "Miejsce docelowe",
|
"resourcesTableDestination": "Miejsce docelowe",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Adres aliasu",
|
"resourcesTableAliasAddress": "Adres aliasu",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Anuluj",
|
"editInternalResourceDialogCancel": "Anuluj",
|
||||||
"editInternalResourceDialogSaveResource": "Zapisz zasób",
|
"editInternalResourceDialogSaveResource": "Zapisz zasób",
|
||||||
"editInternalResourceDialogSuccess": "Sukces",
|
"editInternalResourceDialogSuccess": "Sukces",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Wewnętrzny zasób zaktualizowany pomyślnie",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Prywatny zasób został pomyślnie zaktualizowany",
|
||||||
"editInternalResourceDialogError": "Błąd",
|
"editInternalResourceDialogError": "Błąd",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Nie udało się zaktualizować wewnętrznego zasobu",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Nie udało się zaktualizować prywatnego zasobu",
|
||||||
"editInternalResourceDialogNameRequired": "Nazwa jest wymagana",
|
"editInternalResourceDialogNameRequired": "Nazwa jest wymagana",
|
||||||
"editInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
|
"editInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
|
||||||
"editInternalResourceDialogProxyPortMin": "Port proxy musi wynosić przynajmniej 1",
|
"editInternalResourceDialogProxyPortMin": "Port proxy musi wynosić przynajmniej 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "Brama AI",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Schemat",
|
"editInternalResourceDialogScheme": "Schemat",
|
||||||
"editInternalResourceDialogEnableSsl": "Włącz TLS",
|
"editInternalResourceDialogEnableSsl": "Włącz TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Opcjonalny wewnętrzny alias DNS dla tego zasobu.",
|
"editInternalResourceDialogAliasDescription": "Opcjonalny wewnętrzny alias DNS dla tego zasobu.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Brak dostępnych stron",
|
"createInternalResourceDialogNoSitesAvailable": "Brak dostępnych stron",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Musisz mieć co najmniej jedną stronę Newt z skonfigurowanym podsiecią, aby tworzyć wewnętrzne zasoby.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Musisz mieć co najmniej jedną lokalizację Newt z skonfigurowaną podsiecią, aby tworzyć prywatne zasoby.",
|
||||||
"createInternalResourceDialogClose": "Zamknij",
|
"createInternalResourceDialogClose": "Zamknij",
|
||||||
"createInternalResourceDialogCreateClientResource": "Utwórz zasób prywatny",
|
"createInternalResourceDialogCreateClientResource": "Utwórz zasób prywatny",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Utwórz nowy zasób, który będzie dostępny tylko dla klientów podłączonych do organizacji",
|
"createInternalResourceDialogCreateClientResourceDescription": "Utwórz nowy zasób, który będzie dostępny tylko dla klientów podłączonych do organizacji",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Zezwalaj na ping ICMP",
|
"privateResourceAllowIcmpPing": "Zezwalaj na ping ICMP",
|
||||||
"privateResourceNetworkAccess": "Dostęp do sieci",
|
"privateResourceNetworkAccess": "Dostęp do sieci",
|
||||||
"privateResourceNetworkAccessDescription": "Kontroluj dostęp do portów TCP/UDP i czy ping ICMP jest dozwolony dla tego zasobu.",
|
"privateResourceNetworkAccessDescription": "Kontroluj dostęp do portów TCP/UDP i czy ping ICMP jest dozwolony dla tego zasobu.",
|
||||||
"hostSettings": "Ustawienia hosta",
|
"hostSettings": "Host",
|
||||||
"cidrSettings": "Ustawienia CIDR",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Właściwości zasobów",
|
"createInternalResourceDialogResourceProperties": "Właściwości zasobów",
|
||||||
"createInternalResourceDialogName": "Nazwa",
|
"createInternalResourceDialogName": "Nazwa",
|
||||||
"createInternalResourceDialogSite": "Witryna",
|
"createInternalResourceDialogSite": "Witryna",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Anuluj",
|
"createInternalResourceDialogCancel": "Anuluj",
|
||||||
"createInternalResourceDialogCreateResource": "Utwórz zasób",
|
"createInternalResourceDialogCreateResource": "Utwórz zasób",
|
||||||
"createInternalResourceDialogSuccess": "Sukces",
|
"createInternalResourceDialogSuccess": "Sukces",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Wewnętrzny zasób utworzony pomyślnie",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Prywatny zasób został pomyślnie utworzony",
|
||||||
"createInternalResourceDialogError": "Błąd",
|
"createInternalResourceDialogError": "Błąd",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Nie udało się utworzyć wewnętrznego zasobu",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Nie udało się utworzyć prywatnego zasobu",
|
||||||
"createInternalResourceDialogNameRequired": "Nazwa jest wymagana",
|
"createInternalResourceDialogNameRequired": "Nazwa jest wymagana",
|
||||||
"createInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
|
"createInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Proszę wybrać stronę",
|
"createInternalResourceDialogPleaseSelectSite": "Proszę wybrać stronę",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "Brama AI",
|
||||||
"scheme": "Schemat",
|
"scheme": "Schemat",
|
||||||
"createInternalResourceDialogScheme": "Schemat",
|
"createInternalResourceDialogScheme": "Schemat",
|
||||||
"createInternalResourceDialogEnableSsl": "Włącz TLS",
|
"createInternalResourceDialogEnableSsl": "Włącz TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Prawidłowe hasło",
|
"validPassword": "Prawidłowe hasło",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Ważny Wirtualny Klucz API",
|
||||||
"view": "Zobacz",
|
"view": "Zobacz",
|
||||||
"configManaged": "Konfiguracja zarządzana",
|
"configManaged": "Konfiguracja zarządzana",
|
||||||
"connectedClient": "Połączony Klient",
|
"connectedClient": "Połączony Klient",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Zachowanie dziennika",
|
"logRetention": "Zachowanie dziennika",
|
||||||
"logRetentionDescription": "Zarządzaj jak długo różne typy logów są zachowane dla tej organizacji lub wyłącz je",
|
"logRetentionDescription": "Zarządzaj jak długo różne typy logów są zachowane dla tej organizacji lub wyłącz je",
|
||||||
"requestLogsDescription": "Zobacz szczegółowe dzienniki żądań zasobów w tej organizacji",
|
"requestLogsDescription": "Zobacz szczegółowe dzienniki żądań zasobów w tej organizacji",
|
||||||
|
"aiSessionLogs": "Dzienniki Sesji Bramy AI",
|
||||||
|
"aiSessionLogsDescription": "Zobacz transkrypcje podpowiedzi i odpowiedzi dla żądań bramy AI w tej organizacji",
|
||||||
|
"sidebarLogsAi": "Dzienniki Sesji",
|
||||||
|
"commandLogsAi": "Dzienniki Sesji",
|
||||||
|
"sidebarLogsAiUsage": "Analiza Użycia",
|
||||||
|
"commandLogsAiUsage": "Analiza Użycia",
|
||||||
|
"provider": "Dostawca",
|
||||||
|
"capability": "Zdolność",
|
||||||
|
"model": "Model",
|
||||||
|
"virtualApiKey": "Wirtualny Klucz API",
|
||||||
|
"noVirtualApiKey": "Brak wirtualnego klucza API",
|
||||||
|
"stream": "Strumień",
|
||||||
|
"streaming": "Strumieniowanie",
|
||||||
|
"nonStreaming": "Niestrumieniowane",
|
||||||
|
"statusCode": "Kod Stanu",
|
||||||
|
"aiSessionId": "Identyfikator Sesji",
|
||||||
|
"aiSessionRequest": "Żądanie",
|
||||||
|
"aiSessionResponse": "Odpowiedź",
|
||||||
|
"aiSessionNoData": "Brak danych do przechwycenia",
|
||||||
|
"aiSessionCouldNotParse": "(nieprzetworzone, nie można było parsować transkrypcji)",
|
||||||
|
"aiSessionLogTruncated": "Ta sesja została przycięta przed przechowywaniem i może być niekompletna.",
|
||||||
|
"aiSessionViewRaw": "Zobacz Raw JSON",
|
||||||
|
"aiSessionViewChat": "Zobacz Czat",
|
||||||
|
"cost": "Koszt",
|
||||||
|
"estimated": "Szacowany",
|
||||||
|
"tokenUsage": "Użycie Tokenów",
|
||||||
|
"promptTokens": "Tokeny Podpowiedzi",
|
||||||
|
"cacheReadTokens": "Tokeny Odczytu Bufora",
|
||||||
|
"cacheWriteTokens": "Tokeny Zapisu Bufora",
|
||||||
|
"completionTokens": "Tokeny Ukończenia",
|
||||||
|
"reasoningTokens": "Tokeny Rozumowania",
|
||||||
|
"totalTokens": "Całkowita Liczba Tokenów",
|
||||||
"requestAnalyticsDescription": "Zobacz szczegółowe analizy żądań dla zasobów w tej organizacji",
|
"requestAnalyticsDescription": "Zobacz szczegółowe analizy żądań dla zasobów w tej organizacji",
|
||||||
"logRetentionRequestLabel": "Przechowywanie dzienników żądań HTTP",
|
"logRetentionRequestLabel": "Przechowywanie dzienników żądań HTTP",
|
||||||
"logRetentionRequestDescription": "Jak długo zachować dzienniki żądań",
|
"logRetentionRequestDescription": "Jak długo zachować dzienniki żądań",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Jak długo zachować dzienniki akcji",
|
"logRetentionActionDescription": "Jak długo zachować dzienniki akcji",
|
||||||
"logRetentionConnectionLabel": "Zachowanie dziennika połączeń",
|
"logRetentionConnectionLabel": "Zachowanie dziennika połączeń",
|
||||||
"logRetentionConnectionDescription": "Jak długo zachować dzienniki połączeń",
|
"logRetentionConnectionDescription": "Jak długo zachować dzienniki połączeń",
|
||||||
|
"logRetentionAISessionsLabel": "Retencja Dzienników Sesji Bramy AI",
|
||||||
|
"logRetentionAISessionsDescription": "Jak długo przechowywać dzienniki sesji podpowiedzi/odpowiedzi bramy AI",
|
||||||
"logRetentionDisabled": "Wyłączone",
|
"logRetentionDisabled": "Wyłączone",
|
||||||
"logRetention3Days": "3 dni",
|
"logRetention3Days": "3 dni",
|
||||||
"logRetention7Days": "7 dni",
|
"logRetention7Days": "7 dni",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Adres źródłowy",
|
"sourceAddress": "Adres źródłowy",
|
||||||
"destinationAddress": "Adres docelowy",
|
"destinationAddress": "Adres docelowy",
|
||||||
"duration": "Czas trwania",
|
"duration": "Czas trwania",
|
||||||
"licenseRequiredToUse": "Do korzystania z tej funkcji wymagana jest licencja <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> lub <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> . <bookADemoLink>Zarezerwuj wersję demonstracyjną lub wersję próbną POC</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Licencja Wydania Enterprise</enterpriseEditionLink> jest wymagana. <bookADemoLink>Zarezerwuj demo lub próbę</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> jest wymagany do korzystania z tej funkcji. Ta funkcja jest również dostępna w <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Zarezerwuj demo lub okres próbny POC</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Licencja Wydania Enterprise</enterpriseEditionLink> jest wymagana. <bookADemoLink>Zarezerwuj demo lub próbę</bookADemoLink>",
|
||||||
"certResolver": "Rozwiązywanie certyfikatów",
|
"certResolver": "Rozwiązywanie certyfikatów",
|
||||||
"certResolverDescription": "Wybierz resolver certyfikatów do użycia dla tego zasobu.",
|
"certResolverDescription": "Wybierz resolver certyfikatów do użycia dla tego zasobu.",
|
||||||
"selectCertResolver": "Wybierz Resolver certyfikatów",
|
"selectCertResolver": "Wybierz Resolver certyfikatów",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Wybór wielu stron umożliwia odporne trasowanie i awarię dla wysokiej dostępności.",
|
"internalResourceFormMultiSiteRoutingHelp": "Wybór wielu stron umożliwia odporne trasowanie i awarię dla wysokiej dostępności.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Dowiedz się więcej",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Dowiedz się więcej",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Ogranicz dostęp do konkretnych portów TCP/UDP lub zezwól/zablokuj wszystkie porty.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Ogranicz dostęp do konkretnych portów TCP/UDP lub zezwól/zablokuj wszystkie porty.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "Konfiguracja HTTP",
|
"createInternalResourceDialogHttpConfiguration": "Konfiguracja Domeny",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Wybierz domenę, której klienci będą używać, aby dotrzeć do tego zasobu przez HTTP lub HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Wybierz domenę, której klienci będą używać, aby dotrzeć do tego zasobu przez HTTP lub HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "Konfiguracja HTTP",
|
"editInternalResourceDialogHttpConfiguration": "Konfiguracja Domeny",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Wybierz domenę, której klienci będą używać, aby dotrzeć do tego zasobu przez HTTP lub HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Wybierz domenę, której klienci będą używać, aby dotrzeć do tego zasobu przez HTTP lub HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Bez etykiety",
|
"resourceLauncherUnlabeled": "Bez etykiety",
|
||||||
|
"resourceLauncherAiGateway": "Brama AI",
|
||||||
"resourceLauncherNoSite": "Brak strony",
|
"resourceLauncherNoSite": "Brak strony",
|
||||||
|
"resourceLauncherAvailableModels": "Dostępne Modele",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modele, z których możesz korzystać z tą bramą AI.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Brak dostępnych modeli dla tego zasobu.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Nie można załadować dostępnych modeli.",
|
||||||
|
"resourceLauncherApiKeys": "Klucze API",
|
||||||
|
"resourceLauncherApiKeysDescription": "Użyj klucza tożsamości lub przypisanego klucza, aby uwierzytelnić się przy użyciu tego zasobu.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Klucz Tożsamości",
|
||||||
|
"resourceLauncherApiKeysManual": "Klucze Przypisane",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Brak dostępnych kluczy API dla tego zasobu.",
|
||||||
|
"resourceLauncherApiKeysError": "Nie można załadować kluczy API.",
|
||||||
"resourceLauncherNoResourcesInGroup": "W tej grupie nie ma zasobów",
|
"resourceLauncherNoResourcesInGroup": "W tej grupie nie ma zasobów",
|
||||||
"resourceLauncherEmptyStateTitle": "Brak dostępnych zasobów",
|
"resourceLauncherEmptyStateTitle": "Brak dostępnych zasobów",
|
||||||
"resourceLauncherEmptyStateDescription": "Jeszcze nie masz dostępu do żadnych zasobów. Skontaktuj się z administratorem, aby poprosić o dostęp.",
|
"resourceLauncherEmptyStateDescription": "Jeszcze nie masz dostępu do żadnych zasobów. Skontaktuj się z administratorem, aby poprosić o dostęp.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Nie można usunąć widoku uruchamiacza. Proszę spróbować ponownie.",
|
"resourceLauncherViewDeleteFailedDescription": "Nie można usunąć widoku uruchamiacza. Proszę spróbować ponownie.",
|
||||||
"memberPortalPrevious": "Poprzedni",
|
"memberPortalPrevious": "Poprzedni",
|
||||||
"memberPortalNext": "Następny",
|
"memberPortalNext": "Następny",
|
||||||
"httpSettings": "Ustawienia HTTP",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "Ustawienia TCP",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "Ustawienia UDP",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Nawiązywanie bezpiecznego połączenia…",
|
"sshConnectingDescription": "Nawiązywanie bezpiecznego połączenia…",
|
||||||
"sshConnecting": "Łączenie…",
|
"sshConnecting": "Łączenie…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Niepowodzenie przesyłania",
|
"rdpUploadFailed": "Niepowodzenie przesyłania",
|
||||||
"rdpUnicodeKeyboardMode": "Tryb klawiatury Unicode",
|
"rdpUnicodeKeyboardMode": "Tryb klawiatury Unicode",
|
||||||
"sessionToolbarShow": "Pokaż pasek narzędzi",
|
"sessionToolbarShow": "Pokaż pasek narzędzi",
|
||||||
"sessionToolbarHide": "Ukryj pasek narzędzi"
|
"sessionToolbarHide": "Ukryj pasek narzędzi",
|
||||||
|
"actionUpdateSiteApprovals": "Zaktualizuj zgody na stronę"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Verifique se você está logado como o utilizador correto.",
|
"inviteLoginUser": "Verifique se você está logado como o utilizador correto.",
|
||||||
"inviteErrorNoUser": "Desculpe, mas parece que o convite que está a tentar aceder não é para um utilizador que existe.",
|
"inviteErrorNoUser": "Desculpe, mas parece que o convite que está a tentar aceder não é para um utilizador que existe.",
|
||||||
"inviteCreateUser": "Por favor, crie uma conta primeiro.",
|
"inviteCreateUser": "Por favor, crie uma conta primeiro.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Convites só podem ser aceitos por contas internas. Faça logout e acesse com sua senha para este e-mail.",
|
||||||
|
"inviteLoginInternalOnly": "Convites exigem uma conta interna com uma senha. Crie uma conta ou faça login com sua senha.",
|
||||||
"goHome": "Voltar ao inicio",
|
"goHome": "Voltar ao inicio",
|
||||||
"inviteLogInOtherUser": "Fazer login como um utilizador diferente",
|
"inviteLogInOtherUser": "Fazer login como um utilizador diferente",
|
||||||
"createAnAccount": "Crie uma conta",
|
"createAnAccount": "Crie uma conta",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Confirmar exclusão do Link Compartilhável",
|
"shareDeleteConfirm": "Confirmar exclusão do Link Compartilhável",
|
||||||
"shareQuestionRemove": "Tem certeza de que deseja excluir este link de compartilhamento?",
|
"shareQuestionRemove": "Tem certeza de que deseja excluir este link de compartilhamento?",
|
||||||
"shareMessageRemove": "Uma vez excluído, o link não funcionará mais e qualquer pessoa que o utilizar perderá o acesso ao recurso.",
|
"shareMessageRemove": "Uma vez excluído, o link não funcionará mais e qualquer pessoa que o utilizar perderá o acesso ao recurso.",
|
||||||
"shareTokenDescription": "O token de acesso pode ser passado de duas maneiras: como um parâmetro de consulta ou nos cabeçalhos da solicitação. Estes devem ser passados do cliente em todas as solicitações para acesso autenticado.",
|
"shareTokenDescription": "O token de acesso pode ser passado como um parâmetro de consulta ou nos cabeçalhos da solicitação. Por padrão, ele deve ser enviado em todas as solicitações. Se a persistência da sessão estiver ativada, a primeira solicitação o troca por um cookie de sessão.",
|
||||||
"accessToken": "Token de acesso",
|
"accessToken": "Token de acesso",
|
||||||
"usageExamples": "Exemplos de uso",
|
"usageExamples": "Exemplos de uso",
|
||||||
"tokenId": "ID do Token",
|
"tokenId": "ID do Token",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Título (opcional)",
|
"shareTitleOptional": "Título (opcional)",
|
||||||
"sharePathOptional": "Caminho (opcional)",
|
"sharePathOptional": "Caminho (opcional)",
|
||||||
"sharePathDescription": "O link redirecionará os usuários para este caminho após a autenticação.",
|
"sharePathDescription": "O link redirecionará os usuários para este caminho após a autenticação.",
|
||||||
|
"shareAssociateUserOptional": "Associar Usuário (opcional)",
|
||||||
|
"shareAssociateUserDescription": "Quando definido, as solicitações usando este link são atribuídas ao usuário nos registros de acesso e cabeçalhos de identidade. O link é removido se o usuário sair da organização.",
|
||||||
|
"userSelect": "Selecionar um usuário",
|
||||||
|
"usersNotFound": "Nenhum usuário encontrado",
|
||||||
"expireIn": "Expira em",
|
"expireIn": "Expira em",
|
||||||
"neverExpire": "Nunca expirar",
|
"neverExpire": "Nunca expirar",
|
||||||
|
"sharePersistSession": "Persistir sessão após o primeiro uso",
|
||||||
|
"sharePersistSessionDescription": "Quando ativado, a primeira solicitação com este token por meio de um parâmetro de consulta ou cabeçalho define um cookie de sessão, para que solicitações posteriores não precisem do token. Mantenha desativado para clientes de API que devem enviar o token em todas as solicitações.",
|
||||||
"shareExpireDescription": "Tempo de expiração é quanto tempo o link será utilizável e oferecerá acesso ao recurso. Após este tempo, o link não funcionará mais, e os utilizadores que usaram este link perderão acesso ao recurso.",
|
"shareExpireDescription": "Tempo de expiração é quanto tempo o link será utilizável e oferecerá acesso ao recurso. Após este tempo, o link não funcionará mais, e os utilizadores que usaram este link perderão acesso ao recurso.",
|
||||||
"shareSeeOnce": "Você só poderá ver este link uma vez. Certifique-se de copiá-lo.",
|
"shareSeeOnce": "Você só poderá ver este link uma vez. Certifique-se de copiá-lo.",
|
||||||
"shareAccessHint": "Qualquer um com este link pode aceder o recurso. Compartilhe com cuidado.",
|
"shareAccessHint": "Qualquer um com este link pode aceder o recurso. Compartilhe com cuidado.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Nenhum país encontrado.",
|
"noCountryFound": "Nenhum país encontrado.",
|
||||||
"siteSelectionDescription": "Este site fornecerá conectividade ao destino.",
|
"siteSelectionDescription": "Este site fornecerá conectividade ao destino.",
|
||||||
"resourceType": "Tipo de Recurso",
|
"resourceType": "Tipo de Recurso",
|
||||||
"resourceTypeDescription": "Isso controla o protocolo do recurso e como ele será renderizado no navegador. Isso não pode ser alterado posteriormente.",
|
"resourceTypeDescription": "Isso controla o protocolo do recurso e não pode ser alterado posteriormente.",
|
||||||
|
"resourceTypeSearch": "Procurar tipos de recursos...",
|
||||||
|
"resourceTypeNotFound": "Nenhum tipo de recurso encontrado",
|
||||||
|
"resourceTypeHttpDescription": "Proxy de tráfego web sobre HTTPS usando um nome de domínio",
|
||||||
|
"resourceTypeInferenceDescription": "Roteie solicitações de IA através de provedores conectados",
|
||||||
|
"resourceTypeSshDescription": "Acesse um servidor SSH a partir do navegador",
|
||||||
|
"resourceTypeRdpDescription": "Acesse uma área de trabalho remota a partir do navegador",
|
||||||
|
"resourceTypeVncDescription": "Acesse uma área de trabalho VNC a partir do navegador",
|
||||||
|
"resourceTypeTcpDescription": "Proxy de tráfego TCP bruto usando um número de porta",
|
||||||
|
"resourceTypeUdpDescription": "Proxy de tráfego UDP bruto usando um número de porta",
|
||||||
|
"privateResourceTypeDescription": "Isso controla como os clientes alcançam o recurso. Não pode ser alterado posteriormente.",
|
||||||
|
"privateResourceTypeHostDescription": "Exponha um único host na rede do site para clientes conectados",
|
||||||
|
"privateResourceTypeCidrDescription": "Exponha um intervalo CIDR na rede do site para clientes conectados",
|
||||||
|
"privateResourceTypeHttpDescription": "Acesse um serviço HTTP ou HTTPS por meio de um domínio",
|
||||||
|
"privateResourceTypeSshDescription": "Acesse um servidor SSH de clientes conectados",
|
||||||
"resourceDomainDescription": "O recurso será servido neste nome de domínio totalmente qualificado.",
|
"resourceDomainDescription": "O recurso será servido neste nome de domínio totalmente qualificado.",
|
||||||
"resourceHTTPSSettings": "Configurações de HTTPS",
|
"resourceHTTPSSettings": "Configurações de HTTPS",
|
||||||
"resourceHTTPSSettingsDescription": "Configure como o recurso será acessado por HTTPS",
|
"resourceHTTPSSettingsDescription": "Configure como o recurso será acessado por HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Provisionamento",
|
"provisioningManage": "Provisionamento",
|
||||||
"provisioningDescription": "Gerenciar chaves de provisionamento e revisar sites pendentes aguardando aprovação.",
|
"provisioningDescription": "Gerenciar chaves de provisionamento e revisar sites pendentes aguardando aprovação.",
|
||||||
"pendingSites": "Sites pendentes",
|
"pendingSites": "Sites pendentes",
|
||||||
"siteApproveSuccess": "Site aprovado com sucesso",
|
"siteApproveSuccess": "Site e recursos associados aprovados com sucesso",
|
||||||
"siteApproveError": "Erro ao aprovar site",
|
"siteApproveError": "Erro ao aprovar site",
|
||||||
|
"siteReject": "Rejeitar Site",
|
||||||
|
"siteQuestionReject": "Tem certeza de que deseja rejeitar este site?",
|
||||||
|
"siteMessageReject": "Isto eliminará permanentemente o site e quaisquer recursos associados que ainda estejam pendentes.",
|
||||||
|
"siteConfirmReject": "Confirmar Rejeição de Site",
|
||||||
|
"siteRejectSuccess": "Site rejeitado com sucesso",
|
||||||
|
"siteRejectError": "Erro ao rejeitar site",
|
||||||
"provisioningKeys": "Posicionando chaves",
|
"provisioningKeys": "Posicionando chaves",
|
||||||
"searchProvisioningKeys": "Pesquisar chaves de provisionamento...",
|
"searchProvisioningKeys": "Pesquisar chaves de provisionamento...",
|
||||||
"provisioningKeysAdd": "Gerar chave de provisionamento",
|
"provisioningKeysAdd": "Gerar chave de provisionamento",
|
||||||
@@ -466,12 +494,12 @@
|
|||||||
"provisioningKeysSave": "Salvar a chave de provisionamento",
|
"provisioningKeysSave": "Salvar a chave de provisionamento",
|
||||||
"provisioningKeysSaveDescription": "Você só será capaz de ver esta vez. Copiá-lo para um lugar seguro.",
|
"provisioningKeysSaveDescription": "Você só será capaz de ver esta vez. Copiá-lo para um lugar seguro.",
|
||||||
"provisioningKeysErrorCreate": "Erro ao criar chave de provisionamento",
|
"provisioningKeysErrorCreate": "Erro ao criar chave de provisionamento",
|
||||||
"provisioningKeysList": "Nova chave de aprovisionamento",
|
"provisioningKeysList": "Nova Chave de Provisionamento",
|
||||||
"provisioningKeysMaxBatchSize": "Tamanho máximo do lote",
|
"provisioningKeysMaxBatchSize": "Tamanho Máximo do Lote",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Tamanho ilimitado em lote (sem limite)",
|
"provisioningKeysUnlimitedBatchSize": "Tamanho ilimitado em lote (sem limite)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Ilimitado",
|
"provisioningKeysMaxBatchUnlimited": "Ilimitado",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Informe um tamanho máximo válido em lote (1–1,000,000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Informe um tamanho máximo válido em lote (1–1,000,000).",
|
||||||
"provisioningKeysValidUntil": "Valido ate",
|
"provisioningKeysValidUntil": "Válido Até",
|
||||||
"provisioningKeysValidUntilHint": "Deixe em branco para nenhuma expiração.",
|
"provisioningKeysValidUntilHint": "Deixe em branco para nenhuma expiração.",
|
||||||
"provisioningKeysValidUntilInvalid": "Informe uma data e hora válidas.",
|
"provisioningKeysValidUntilInvalid": "Informe uma data e hora válidas.",
|
||||||
"provisioningKeysNumUsed": "Use percentual",
|
"provisioningKeysNumUsed": "Use percentual",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "nunca",
|
"provisioningKeysNeverUsed": "nunca",
|
||||||
"provisioningKeysEdit": "Editar chave de provisionamento",
|
"provisioningKeysEdit": "Editar chave de provisionamento",
|
||||||
"provisioningKeysEditDescription": "Atualizar o tamanho máximo do lote e tempo de expiração para esta chave.",
|
"provisioningKeysEditDescription": "Atualizar o tamanho máximo do lote e tempo de expiração para esta chave.",
|
||||||
"provisioningKeysApproveNewSites": "Aprovar novos sites",
|
"provisioningKeysApproveNewSites": "Aprovar Novos Sites",
|
||||||
"provisioningKeysApproveNewSitesDescription": "Aprovar automaticamente sites que se registram com esta chave.",
|
"provisioningKeysApproveNewSitesDescription": "Aprovar automaticamente sites que se registram com esta chave.",
|
||||||
"provisioningKeysUpdateError": "Erro ao atualizar chave de provisionamento",
|
"provisioningKeysUpdateError": "Erro ao atualizar chave de provisionamento",
|
||||||
"provisioningKeysUpdated": "Chave de provisionamento atualizada",
|
"provisioningKeysUpdated": "Chave de provisionamento atualizada",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Salvar Configurações",
|
"authMethodsSave": "Salvar Configurações",
|
||||||
"policyAuthStackTitle": "Autenticação",
|
"policyAuthStackTitle": "Autenticação",
|
||||||
"policyAuthStackDescription": "Controle quais métodos de autenticação são necessários para acessar este recurso",
|
"policyAuthStackDescription": "Controle quais métodos de autenticação são necessários para acessar este recurso",
|
||||||
|
"policyAuthInferenceStackDescription": "Escolha quais usuários e funções podem autenticar com este gateway de IA",
|
||||||
"policyAuthOrLogicTitle": "Vários métodos de autenticação ativos",
|
"policyAuthOrLogicTitle": "Vários métodos de autenticação ativos",
|
||||||
"policyAuthOrLogicBanner": "Os visitantes podem autenticar-se usando qualquer um dos métodos ativos abaixo. Eles não precisam completar todos eles.",
|
"policyAuthOrLogicBanner": "Os visitantes podem autenticar-se usando qualquer um dos métodos ativos abaixo. Eles não precisam completar todos eles.",
|
||||||
"policyAuthMethodActive": "Ativo",
|
"policyAuthMethodActive": "Ativo",
|
||||||
"policyAuthMethodOff": "Desligado",
|
"policyAuthMethodOff": "Desligado",
|
||||||
"policyAuthSsoTitle": "SSO da Plataforma",
|
"policyAuthSsoTitle": "SSO da Plataforma",
|
||||||
"policyAuthSsoDescription": "Exigir login pelo provedor de identidade da sua organização",
|
"policyAuthSsoDescription": "Exigir login pelo provedor de identidade da sua organização",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "URL de entrada",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Todo usuário já possui uma chave de API de identidade, portanto, você só precisa criar chaves de API virtuais para clientes que não são de usuários ou acesso compartilhado. Os usuários podem recuperar sua chave fazendo login com seu provedor de identidade no URL deste recurso, onde ela será mostrada após o login.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Todo usuário já possui uma chave de API de identidade, então você só precisa criar chaves de API virtuais para clientes que não são de usuários ou acesso compartilhado. Os usuários recuperam sua chave aqui após fazer login com seu provedor de identidade.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} usuários, {roles} funções",
|
"policyAuthSsoSummary": "{idp} · {users} usuários, {roles} funções",
|
||||||
"policyAuthSsoDefaultIdp": "Provedor padrão",
|
"policyAuthSsoDefaultIdp": "Provedor padrão",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Adicionar Provedor de Identidade Padrão",
|
"policyAuthAddDefaultIdentityProvider": "Adicionar Provedor de Identidade Padrão",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Versão",
|
"newtVersion": "Versão",
|
||||||
"architecture": "Arquitetura",
|
"architecture": "Arquitetura",
|
||||||
"sites": "sites",
|
"sites": "sites",
|
||||||
"siteWgAnyClients": "Use qualquer cliente do WireGuard para se conectar. Você terá que endereçar recursos internos usando o IP de pares.",
|
"siteWgAnyClients": "Use qualquer cliente WireGuard para conectar-se. Você terá que endereçar recursos privados usando o IP do par.",
|
||||||
"siteWgCompatibleAllClients": "Compatível com todos os clientes WireGuard",
|
"siteWgCompatibleAllClients": "Compatível com todos os clientes WireGuard",
|
||||||
"siteWgManualConfigurationRequired": "Configuração manual necessária",
|
"siteWgManualConfigurationRequired": "Configuração manual necessária",
|
||||||
"userErrorNotAdminOrOwner": "Usuário não é administrador ou proprietário",
|
"userErrorNotAdminOrOwner": "Usuário não é administrador ou proprietário",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Nova função é necessária",
|
"accessRoleErrorNewRequired": "Nova função é necessária",
|
||||||
"accessRoleErrorRemove": "Falha ao remover função",
|
"accessRoleErrorRemove": "Falha ao remover função",
|
||||||
"accessRoleErrorRemoveDescription": "Ocorreu um erro ao remover a função.",
|
"accessRoleErrorRemoveDescription": "Ocorreu um erro ao remover a função.",
|
||||||
|
"accessRoleInferenceBudget": "Orçamento de IA",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Configure como membros desta função restringem o uso de IA com base nos limites de gasto ou token",
|
||||||
"accessRoleName": "Nome da Função",
|
"accessRoleName": "Nome da Função",
|
||||||
"accessRoleQuestionRemove": "Você está prestes a apagar o papel `{name}. Você não pode desfazer esta ação.",
|
"accessRoleQuestionRemove": "Você está prestes a apagar o papel `{name}. Você não pode desfazer esta ação.",
|
||||||
"accessRoleRemove": "Remover Função",
|
"accessRoleRemove": "Remover Função",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Criar utilizador Org",
|
"createOrgUser": "Criar utilizador Org",
|
||||||
"actionUpdateOrg": "Atualizar Organização",
|
"actionUpdateOrg": "Atualizar Organização",
|
||||||
"actionRemoveInvitation": "Remover Convite",
|
"actionRemoveInvitation": "Remover Convite",
|
||||||
|
"actionRemoveUserRole": "Remover Função de Utilizador",
|
||||||
"actionUpdateUser": "Atualizar Usuário",
|
"actionUpdateUser": "Atualizar Usuário",
|
||||||
"actionGetUser": "Obter Usuário",
|
"actionGetUser": "Obter Usuário",
|
||||||
"actionGetOrgUser": "Obter Utilizador da Organização",
|
"actionGetOrgUser": "Obter Utilizador da Organização",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Eliminar Site",
|
"actionDeleteSite": "Eliminar Site",
|
||||||
"actionGetSite": "Obter Site",
|
"actionGetSite": "Obter Site",
|
||||||
"actionListSites": "Listar Sites",
|
"actionListSites": "Listar Sites",
|
||||||
|
"actionCreateAiProvider": "Criar Provedor de IA",
|
||||||
|
"actionDeleteAiProvider": "Excluir Provedor de IA",
|
||||||
|
"actionGetAiProvider": "Obter Provedor de IA",
|
||||||
|
"actionListAiProviders": "Listar Provedores de IA",
|
||||||
|
"actionUpdateAiProvider": "Atualizar Provedor de IA",
|
||||||
|
"actionCreateAiModel": "Criar Modelo de IA",
|
||||||
|
"actionDeleteAiModel": "Excluir Modelo de IA",
|
||||||
|
"actionGetAiModel": "Obter Modelo de IA",
|
||||||
|
"actionListAiModels": "Listar Modelos de IA",
|
||||||
|
"actionUpdateAiModel": "Atualizar Modelo de IA",
|
||||||
|
"actionCreateAiBudget": "Criar Orçamento de IA",
|
||||||
|
"actionDeleteAiBudget": "Excluir Orçamento de IA",
|
||||||
|
"actionGetAiBudget": "Obter Orçamento de IA",
|
||||||
|
"actionListAiBudgets": "Listar Orçamentos de IA",
|
||||||
|
"actionUpdateAiBudget": "Atualizar Orçamento de IA",
|
||||||
|
"actionListResourceAiModels": "Listar Modelos de IA de Recursos",
|
||||||
|
"actionSetResourceAiModels": "Definir Modelos de IA de Recurso",
|
||||||
|
"actionCreateVirtualApiKey": "Criar Chave de API Virtual",
|
||||||
|
"actionDeleteVirtualApiKey": "Excluir Chave de API Virtual",
|
||||||
|
"actionGetVirtualApiKey": "Obter Chave de API Virtual",
|
||||||
|
"actionListVirtualApiKeys": "Listar Chaves de API Virtuais",
|
||||||
|
"actionUpdateVirtualApiKey": "Atualizar Chave de API Virtual",
|
||||||
"actionApplyBlueprint": "Aplicar Diagrama",
|
"actionApplyBlueprint": "Aplicar Diagrama",
|
||||||
"actionListBlueprints": "Listar Modelos",
|
"actionListBlueprints": "Listar Modelos",
|
||||||
"actionGetBlueprint": "Obter Modelo",
|
"actionGetBlueprint": "Obter Modelo",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Digite o token de configuração do console do servidor.",
|
"setupTokenDescription": "Digite o token de configuração do console do servidor.",
|
||||||
"setupTokenRequired": "Token de configuração é necessário",
|
"setupTokenRequired": "Token de configuração é necessário",
|
||||||
"actionUpdateSite": "Atualizar Site",
|
"actionUpdateSite": "Atualizar Site",
|
||||||
|
"actionApproveSite": "Aprovar Site",
|
||||||
|
"actionRejectSite": "Rejeitar Site",
|
||||||
"actionResetSiteBandwidth": "Redefinir banda da organização",
|
"actionResetSiteBandwidth": "Redefinir banda da organização",
|
||||||
"actionListSiteRoles": "Listar Funções Permitidas do Site",
|
"actionListSiteRoles": "Listar Funções Permitidas do Site",
|
||||||
"actionCreateResource": "Criar Recurso",
|
"actionCreateResource": "Criar Recurso",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Definir Código PIN do Recurso",
|
"actionSetResourcePincode": "Definir Código PIN do Recurso",
|
||||||
"actionSetResourceEmailWhitelist": "Definir Lista Permitida de Emails do Recurso",
|
"actionSetResourceEmailWhitelist": "Definir Lista Permitida de Emails do Recurso",
|
||||||
"actionGetResourceEmailWhitelist": "Obter Lista Permitida de Emails do Recurso",
|
"actionGetResourceEmailWhitelist": "Obter Lista Permitida de Emails do Recurso",
|
||||||
|
"actionListResourcePolicies": "Listar Políticas de Recursos",
|
||||||
|
"actionCreateResourcePolicy": "Criar Política de Recurso",
|
||||||
"actionGetResourcePolicy": "Obter Política de Recurso",
|
"actionGetResourcePolicy": "Obter Política de Recurso",
|
||||||
"actionUpdateResourcePolicy": "Atualizar Política de Recurso",
|
"actionUpdateResourcePolicy": "Atualizar Política de Recurso",
|
||||||
|
"actionDeleteResourcePolicy": "Excluir Política de Recurso",
|
||||||
"actionSetResourcePolicyUsers": "Definir Utilizadores da Política de Recurso",
|
"actionSetResourcePolicyUsers": "Definir Utilizadores da Política de Recurso",
|
||||||
"actionSetResourcePolicyRoles": "Definir Papéis da Política de Recurso",
|
"actionSetResourcePolicyRoles": "Definir Papéis da Política de Recurso",
|
||||||
"actionSetResourcePolicyPassword": "Definir Palavra-passe da Política de Recurso",
|
"actionSetResourcePolicyPassword": "Definir Palavra-passe da Política de Recurso",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Listar Convites",
|
"actionListInvitations": "Listar Convites",
|
||||||
"actionExportLogs": "Exportar logs",
|
"actionExportLogs": "Exportar logs",
|
||||||
"actionViewLogs": "Visualizar registros",
|
"actionViewLogs": "Visualizar registros",
|
||||||
|
"actionCreateSiteProvisioningKey": "Criar Chave de Provisionamento do Site",
|
||||||
|
"actionListSiteProvisioningKeys": "Listar Chaves de Provisionamento do Site",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Atualizar Chave de Provisionamento do Site",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Excluir Chave de Provisionamento do Site",
|
||||||
"noneSelected": "Nenhum selecionado",
|
"noneSelected": "Nenhum selecionado",
|
||||||
"orgNotFound2": "Nenhuma organização encontrada.",
|
"orgNotFound2": "Nenhuma organização encontrada.",
|
||||||
"search": "Pesquisar…",
|
"search": "Pesquisar…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Insira o código da sua aplicação de autenticação ou um dos seus códigos de backup de uso único.",
|
"otpAuthDescription": "Insira o código da sua aplicação de autenticação ou um dos seus códigos de backup de uso único.",
|
||||||
"otpAuthSubmit": "Submeter Código",
|
"otpAuthSubmit": "Submeter Código",
|
||||||
"idpContinue": "Ou continuar com",
|
"idpContinue": "Ou continuar com",
|
||||||
|
"idpLastUsed": "Última Utilização",
|
||||||
"otpAuthBack": "Voltar à Palavra-passe",
|
"otpAuthBack": "Voltar à Palavra-passe",
|
||||||
"navbar": "Menu de Navegação",
|
"navbar": "Menu de Navegação",
|
||||||
"navbarDescription": "Menu de navegação principal da aplicação",
|
"navbarDescription": "Menu de navegação principal da aplicação",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Criar Cliente de Máquina",
|
"commandPaletteCreateMachineClient": "Criar Cliente de Máquina",
|
||||||
"commandPaletteCreateAlertRule": "Criar Regra de Alerta",
|
"commandPaletteCreateAlertRule": "Criar Regra de Alerta",
|
||||||
"commandPaletteCreateIdentityProvider": "Criar Provedor de Identidade",
|
"commandPaletteCreateIdentityProvider": "Criar Provedor de Identidade",
|
||||||
|
"commandPaletteCreateAiProvider": "Criar Provedor de IA",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Criar Chave API Virtual",
|
||||||
"commandPaletteToggleTheme": "Alternar Tema",
|
"commandPaletteToggleTheme": "Alternar Tema",
|
||||||
"commandPaletteChooseOrganization": "Escolher Organização",
|
"commandPaletteChooseOrganization": "Escolher Organização",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Convites",
|
"sidebarInvitations": "Convites",
|
||||||
"sidebarRoles": "Papéis",
|
"sidebarRoles": "Papéis",
|
||||||
"sidebarShareableLinks": "Links Compartilháveis",
|
"sidebarShareableLinks": "Links Compartilháveis",
|
||||||
|
"sidebarAiGateway": "Gateway de IA",
|
||||||
|
"sidebarAiProviders": "Fornecedores",
|
||||||
|
"commandAiProviders": "Provedores de IA",
|
||||||
|
"sidebarVirtualApiKeys": "Chaves de API Virtuais",
|
||||||
|
"sidebarMyApiKeys": "Suas Chaves de API",
|
||||||
|
"sidebarAccount": "Lançador",
|
||||||
|
"commandVirtualApiKeys": "Chaves de API Virtuais",
|
||||||
|
"virtualApiKeysTitle": "Gerir Chaves de API Virtuais",
|
||||||
|
"virtualApiKeysDescription": "Crie e gerencie chaves de API manuais para acesso ao Gateway de IA público",
|
||||||
|
"virtualApiKeysTabIdentity": "Chaves de Identidade",
|
||||||
|
"virtualApiKeysTabVirtual": "Chaves Virtuais",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Chaves de Identidade para Todos os Usuários",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Todo usuário já possui uma chave de identidade Pangolin para esta organização. É exclusiva para a conta deles e os autentica em gateways de IA que eles podem acessar.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Exemplo",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Como os Usuários Obtêm Sua Chave",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Visite um URL de gateway de IA público no navegador e faça login com sua conta.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Ou vá para <url></url> enquanto estiver logado.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Você pode criar chaves de API virtuais adicionais na guia Chaves Virtuais. Essas chaves podem ser limitadas a gateways de IA públicos específicos e opcionalmente associadas a um usuário. Criação da chave concede acesso imediato aos gateways de IA públicos selecionados.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Criar manualmente uma chave",
|
||||||
|
"virtualApiKeysEmailIdentity": "Chaves de Identidade de E-mail",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Envie para cada usuário ou função selecionada a chave de identidade Pangolin deles.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Enviar para todos os usuários",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Envie um e-mail para cada membro da organização que tenha um e-mail de conta.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Utilizadores",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Papéis",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Enviar E-mails",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Chaves de identidade enviadas por e-mail",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Foram enviados {sent} e-mails.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} usuários foram pulados porque não têm endereço de e-mail.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Selecione pelo menos um usuário ou função, ou envie para todos os usuários.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Erro ao enviar chaves de identidade",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Falha ao enviar chaves de identidade por e-mail",
|
||||||
|
"virtualApiKeysBannerTitle": "Chaves de Identidade para Todos os Usuários",
|
||||||
|
"virtualApiKeysBannerDescription": "Todo usuário já tem uma chave de identidade disponível em {keysUrl}. Você também pode gerar manualmente chaves aqui que concedem acesso direto a gateways de IA públicos.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Ver Chaves de Identidade",
|
||||||
|
"virtualApiKeys": "Chaves de API Virtuais",
|
||||||
|
"virtualApiKeysSearch": "Procurar chaves...",
|
||||||
|
"virtualApiKeysCreate": "Criar Chave de API Virtual",
|
||||||
|
"virtualApiKeysCreateDescription": "Mintar uma chave manual que pode chamar gateways de IA públicos nesta organização",
|
||||||
|
"virtualApiKeysCreateButton": "Criar Chave",
|
||||||
|
"virtualApiKeysEmpty": "Ainda nenhuma chave de API virtual",
|
||||||
|
"virtualApiKeysName": "Nome",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Descrição (opcional)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Associar Usuário (opcional)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Associe esta chave a um usuário para rastrear o uso. Uma vez criada, esta chave concede acesso imediato aos gateways de IA públicos selecionados. Não é necessário associar um usuário manualmente ao recurso. A chave também aparecerá no perfil do usuário.",
|
||||||
|
"virtualApiKeysAllResources": "Todos os gateways de IA públicos",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Permitir que esta chave acesse todos os gateways de IA públicos da organização",
|
||||||
|
"virtualApiKeysSelectResources": "Gateways Públicos de IA",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Selecionar recursos",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Escolha quais gateways de IA públicos esta chave pode acessar",
|
||||||
|
"virtualApiKeysNoResources": "Nenhum recurso",
|
||||||
|
"virtualApiKeysSecret": "Chave",
|
||||||
|
"virtualApiKeysCopyKey": "Copie esta chave. Você pode visualizá-la novamente mais tarde na tabela ou ao editar.",
|
||||||
|
"virtualApiKeysViewSecret": "Ver Segredo",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Segredo da Chave de API Virtual",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Este segredo concede acesso aos gateways de IA públicos atribuídos a esta chave",
|
||||||
|
"virtualApiKeysEdit": "Editar Chave de API Virtual",
|
||||||
|
"virtualApiKeysEditDescription": "Atualize o usuário associado e o acesso ao gateway de IA público para esta chave",
|
||||||
|
"virtualApiKeysSaveButton": "Salvar mudanças",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Selecione pelo menos um gateway de IA público, ou habilite todos os gateways de IA públicos",
|
||||||
|
"virtualApiKeysUpdated": "Chave de API virtual atualizada",
|
||||||
|
"virtualApiKeysUpdatedDescription": "A chave de API virtual foi atualizada",
|
||||||
|
"virtualApiKeysErrorUpdate": "Erro ao atualizar chave de API virtual",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Falha ao atualizar chave de API virtual",
|
||||||
|
"virtualApiKeysErrorCreate": "Erro ao criar chave de API virtual",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Falha ao criar chave de API virtual",
|
||||||
|
"virtualApiKeysErrorDelete": "Erro ao excluir chave de API virtual",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Falha ao excluir chave de API virtual",
|
||||||
|
"virtualApiKeysDeleted": "Chave de API virtual excluída",
|
||||||
|
"virtualApiKeysDeletedDescription": "A chave de API virtual foi excluída",
|
||||||
|
"virtualApiKeysDelete": "Excluir Chave de API Virtual",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Excluir Chave",
|
||||||
|
"virtualApiKeysQuestionRemove": "Tem certeza que deseja excluir esta chave de API virtual?",
|
||||||
|
"virtualApiKeysMessageRemove": "Clientes usando esta chave perderão acesso imediatamente.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Erro ao carregar segredo",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Falha ao carregar segredo da chave de API virtual",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Não atribuído",
|
||||||
|
"virtualApiKeysInferenceBudget": "Orçamento",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Configure como esta chave restringe o uso de IA com base nos limites de gasto ou token",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Enviar chave por e-mail ao gerar",
|
||||||
|
"virtualApiKeysEmailThisKey": "Enviar esta chave por e-mail",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Envie a chave para o usuário associado e endereços adicionais após ser criada",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Envie a chave atual para o usuário associado e endereços adicionais",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "O e-mail não está configurado neste servidor",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Configurar SMTP para enviar chaves de API virtuais por e-mail.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Enviar para usuário associado",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Envie a chave para o e-mail da conta do usuário associado",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Associe um usuário para enviar a chave para esse usuário",
|
||||||
|
"virtualApiKeysEmailAdditional": "E-mails adicionais",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Adicionar e-mail e pressionar Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Selecione o usuário associado ou adicione pelo menos um endereço de e-mail",
|
||||||
|
"myVirtualApiKeysTitle": "Suas Chaves de API",
|
||||||
|
"myVirtualApiKeysDescription": "Veja sua chave de identidade e quaisquer chaves de API virtuais atribuídas a você nesta organização",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Suas Chaves de API para {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Veja sua chave de identidade e chaves de API virtuais atribuídas a você que podem acessar {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Chave de Identidade",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Sua Chave de API Pessoal",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Sua chave pessoal para esta organização. É exclusiva para sua conta e usada para identificá-lo ao chamar recursos do Gateway de IA.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Sua Chave de API Pessoal para {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Sua chave pessoal para esta organização. Use-a para chamar {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Chaves Atribuídas",
|
||||||
|
"myVirtualApiKeysManualDescription": "Chaves de API virtuais manuais associadas a sua conta",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Chaves de API virtuais manuais associadas à sua conta que podem acessar {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Ainda não há chaves atribuídas",
|
||||||
|
"myVirtualApiKeysKindUser": "Identidade",
|
||||||
|
"myVirtualApiKeysKindManual": "Manual",
|
||||||
|
"myVirtualApiKeysUnnamed": "Chave sem nome",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Revelar Segredo",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Este segredo o autentica em recursos do Gateway de IA",
|
||||||
|
"aiClientConfigTitle": "Configurar Agentes de Codificação",
|
||||||
|
"aiClientConfigDescription": "Copie a configuração para agentes de codificação populares ou deixe o CLI Pangolin configurá-lo automaticamente para você.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Ferramenta de codificação agentic de Anthropic para o terminal.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Ferramenta de codificação agentic da OpenAI para o terminal.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Agente de codificação de terminal de código aberto.",
|
||||||
|
"aiClientConfigDescriptionCursor": "Editor de código de IA baseado no VS Code.",
|
||||||
|
"aiClientConfigSetup": "Configuração",
|
||||||
|
"aiClientConfigTabCli": "Automático (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Configuração Manual",
|
||||||
|
"aiClientConfigPreset": "Configuração",
|
||||||
|
"aiClientConfigStep": "Etapa {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Este snippet inclui valores de exemplo, como um nome de modelo ou URL de recurso. Substitua-os pelos seus antes de usá-lo.",
|
||||||
|
"aiClientConfigRevealError": "Não foi possível carregar sua chave API.",
|
||||||
|
"aiClientConfigRevealRetry": "Tente novamente",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Este recurso pode ser usado por clientes comuns como Claude Code e OpenCode. <configLink>Saiba mais</configLink>",
|
||||||
|
"aiProvidersTitle": "Provedores de IA",
|
||||||
|
"aiProvidersDescription": "Conecte provedores de modelo para cargas de trabalho de IA nesta organização",
|
||||||
|
"aiProvidersBannerTitle": "Conectar Provedores de Modelo",
|
||||||
|
"aiProvidersBannerDescription": "Provedores são os backends de modelo que o Pangolin usa para cargas de trabalho de IA. Conecte OpenAI, Anthropic e outros provedores aqui, depois anexe os gateways de IA públicos para que os usuários possam chamar modelos com acesso baseado em identidade, orçamentos e logs.",
|
||||||
|
"aiProvidersAdd": "Adicionar Provedor",
|
||||||
|
"aiProvidersSearch": "Procurar provedores...",
|
||||||
|
"aiProvidersEmpty": "Ainda não há provedores de IA",
|
||||||
|
"aiProviderCreate": "Criar Provedor de IA",
|
||||||
|
"aiProviderCreateDescription": "Adicionar um provedor de modelo para esta organização",
|
||||||
|
"aiProviderSeeAll": "Ver Todos os Provedores",
|
||||||
|
"aiProviderSetting": "Configurações do Provedor para {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Configure este provedor de IA",
|
||||||
|
"aiProviderGeneral": "Gerais",
|
||||||
|
"aiProviderGeneralDescription": "Configurações básicas para este provedor",
|
||||||
|
"aiProviderConfiguration": "Configuração",
|
||||||
|
"aiProviderConfigurationDescription": "Roteamento de rede e autenticação para este provedor",
|
||||||
|
"aiProviderNetworkSettings": "Configurações de Rede",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Escolha como o tráfego chega a este provedor",
|
||||||
|
"aiProviderAuthSettings": "Autenticação",
|
||||||
|
"aiProviderAuthSettingsDescription": "Configure como este provedor autentica solicitações para seu URL upstream",
|
||||||
|
"aiProviderBudgetSettings": "Orçamento",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Configure como este provedor restringe o uso com base nos limites de gasto ou token",
|
||||||
|
"aiBudgetAdd": "Adicionar Orçamento",
|
||||||
|
"aiBudgetEmpty": "Nenhum orçamento configurado ainda. Clique em Adicionar Orçamento para definir um limite de gasto ou token.",
|
||||||
|
"aiBudgetUnit": "Tipo de Gasto",
|
||||||
|
"aiBudgetPeriod": "Período de Reinicialização",
|
||||||
|
"aiBudgetAmount": "Gasto Máximo",
|
||||||
|
"aiBudgetAmountPlaceholder": "Gasto máximo",
|
||||||
|
"aiBudgetPeriodHourly": "Por hora",
|
||||||
|
"aiBudgetPeriodDaily": "Diário",
|
||||||
|
"aiBudgetPeriodWeekly": "Semanal",
|
||||||
|
"aiBudgetPeriodMonthly": "Mensal",
|
||||||
|
"aiBudgetPeriodYearly": "Anual",
|
||||||
|
"aiBudgetPeriodLifetime": "Por toda a vida",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Tokens",
|
||||||
|
"aiBudgetConflictError": "Já existe um orçamento para este período de reinicialização e tipo de gasto",
|
||||||
|
"aiBudgetInvalidAmountError": "Digite um gasto máximo maior que 0",
|
||||||
|
"aiBudgetUpdated": "Orçamentos atualizados",
|
||||||
|
"aiBudgetErrorSave": "Falha ao atualizar orçamentos",
|
||||||
|
"aiProviderType": "Tipo de Provedor",
|
||||||
|
"aiProviderTypeSearch": "Procurar provedores...",
|
||||||
|
"aiProviderTypeNotFound": "Nenhum tipo de provedor encontrado",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Antropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Gateway de IA Vercel",
|
||||||
|
"aiProviderTypeCustom": "Personalizado",
|
||||||
|
"aiProviderTypeOpenaiDescription": "API OpenAI",
|
||||||
|
"aiProviderTypeAnthropicDescription": "API Antropic",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "API Google Gemini",
|
||||||
|
"aiProviderTypeVertexAiDescription": "API Google Vertex AI",
|
||||||
|
"aiProviderTypeBedrockDescription": "API Runtime do Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "API Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "API OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "API Gateway de IA Vercel",
|
||||||
|
"aiProviderTypeCustomDescription": "Traga seu próprio ponto de extremidade ou roteie através de alvos do site",
|
||||||
|
"aiProviderUpstreamUrl": "URL de Upstream",
|
||||||
|
"aiProviderUpstreamUrlDescription": "URL base para a API do provedor",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Deixe em branco para usar o URL de upstream padrão para este provedor",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "URL de Upstream Efetivo",
|
||||||
|
"aiProviderApiKey": "Chave API",
|
||||||
|
"aiProviderApiKeyDescription": "Chave API usada para autenticar pedidos a este provedor",
|
||||||
|
"aiProviderCustomHeadersDescription": "Cabeçalhos enviados em cada solicitação para este provedor. Separados por novas linhas: Nome-Do-Cabeçalho: valor",
|
||||||
|
"aiProviderApiKeyLastChars": "Chave API",
|
||||||
|
"aiProviderAuthType": "Tipo de Autenticação",
|
||||||
|
"aiProviderAuthTypeSearch": "Buscar tipos de autenticação...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Nenhum tipo de autenticação encontrado",
|
||||||
|
"aiProviderAuthTypeBearer": "Portador",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Autorização: Chave Portador. Usada pelo OpenAI e pela maioria dos provedores",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "Cabeçalho x-api-key. Usado por Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "Cabeçalho x-goog-api-key. Usado pelo Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Autorização: Chave Splunk. Usada pelo Coletor de Eventos HTTP Splunk",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Gateway AI da Cloudflare",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Chave Portador. Usada pelo Gateway AI da Cloudflare",
|
||||||
|
"aiProviderAuthTypeNone": "Sem Autenticação",
|
||||||
|
"aiProviderAuthTypePassthrough": "Transmissão",
|
||||||
|
"aiProviderAuthTypeDescription": "Como a API de upstream autentica os pedidos",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Encaminhar cabeçalhos da chave API do chamador para o upstream",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Não enviar cabeçalhos de autenticação para o upstream",
|
||||||
|
"aiProviderRoutingMode": "Modo de Roteamento",
|
||||||
|
"aiProviderRoutingModeDescription": "Enviar tráfego para um URL de upstream ou para alvos HTTP em seus sites",
|
||||||
|
"aiProviderRoutingModeUrl": "URL de Upstream",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Chamar uma URL base de API pública ou privada",
|
||||||
|
"aiProviderRoutingModeTarget": "Alvos do Site",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Roteie através de alvos em seus sites",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Após criar este provedor, configure alvos do site na aba Configurações de Rede.",
|
||||||
|
"aiProviderTargetNoOne": "Este provedor não tem alvos. Adicione um alvo para rotear pedidos pelos seus sites.",
|
||||||
|
"aiProviderSkipTlsVerification": "Pular Verificação TLS",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Desativar a verificação de certificado TLS para a conexão upstream",
|
||||||
|
"aiProviderBudget": "Orçamento",
|
||||||
|
"aiProviderBudgetDescription": "Orçamento opcional de despesas ou tokens para este provedor",
|
||||||
|
"aiProviderBudgetAmount": "Valor do Orçamento",
|
||||||
|
"aiProviderBudgetUnit": "Unidade de Orçamento",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Tokens",
|
||||||
|
"aiProviderEnabled": "Ativado",
|
||||||
|
"aiProviderEnabledDescription": "Desativar totalmente este provedor em todos os recursos",
|
||||||
|
"aiProviderErrorCreate": "Falha ao criar provedor de IA",
|
||||||
|
"aiProviderErrorUpdate": "Falha ao atualizar provedor de IA",
|
||||||
|
"aiProviderErrorDelete": "Falha ao apagar provedor de IA",
|
||||||
|
"aiProviderErrorLoad": "Falha ao carregar provedor de IA",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Digite um URL de upstream válido",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "URL de upstream é necessário para este provedor",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Tipo de autenticação é necessário",
|
||||||
|
"aiProviderErrorApiKeyRequired": "Chave API é necessária",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Roteamento de alvos do site está disponível somente para provedores personalizados",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Selecione pelo menos uma capacidade de API",
|
||||||
|
"aiProviderCapabilities": "Capacidades de API",
|
||||||
|
"aiProviderCapabilitiesDescription": "Selecione quais formatos de API este provedor pode manipular. Provedores conhecidos começam com padrões recomendados.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Selecione quais formatos de API este fornecedor personalizado pode lidar",
|
||||||
|
"aiProviderCapabilitiesSelect": "Selecionar capacidades",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Nenhuma capacidade encontrada",
|
||||||
|
"aiProviderCapabilitiesSearch": "Buscar capacidades...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Chat Completações",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Suporta /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "Respostas OpenAI",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Suporta /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Mensagens Antropicas",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Suporta /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gêmeos Gerar Conteúdo",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Suporta a API diretta do Gêmeos",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Modelo Bedrock Invocar",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Suporta InvocarModelo do Amazon Bedrock",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex Gerar Conteúdo",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Suporta o formato Vertex AI Gêmeos",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Predict Bruto do Vertex",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Suporta Vertex AI rawPredict para modelos Antropicos",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock Conversa",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Suporta API de Conversa da Amazon Bedrock",
|
||||||
|
"aiProviderCreated": "Fornecedor de IA criado",
|
||||||
|
"aiProviderUpdated": "Fornecedor de IA atualizado",
|
||||||
|
"aiProviderDeleted": "Fornecedor de IA excluído",
|
||||||
|
"aiProviderDelete": "Excluir Provedor",
|
||||||
|
"aiProviderDeleteConfirm": "Excluir o Provedor",
|
||||||
|
"aiProviderQuestionRemove": "Tem certeza de que deseja excluir este fornecedor de IA?",
|
||||||
|
"aiProviderMessageRemove": "Isso excluirá permanentemente o fornecedor e seus modelos e alvos. Isso não pode ser desfeito.",
|
||||||
|
"aiProviderErrorNoUpdate": "Fornecedor de IA não está disponível para atualização",
|
||||||
|
"aiProviderModels": "Modelos",
|
||||||
|
"aiProviderModelsDescription": "Defina listas de permissão e bloqueio para este provedor. As solicitações devem corresponder a uma entrada permitida e não devem corresponder a uma entrada bloqueada.",
|
||||||
|
"aiProviderCreateModelsDescription": "Escolha quais modelos este fornecedor pode oferecer. Uma lista de permissão vazia nega todo o tráfego. Você pode adicionar ou alterar modelos mais tarde.",
|
||||||
|
"aiProviderModelsPlaceholder": "Buscar modelos ou digitar uma chave personalizada",
|
||||||
|
"aiProviderModelsAllow": "Lista de Permissão",
|
||||||
|
"aiProviderModelsAllowDescription": "Modelos que podem ser usados através deste fornecedor. Vazia significa negar tudo.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Insira a chave do modelo",
|
||||||
|
"aiProviderModelsAllowEmpty": "Nenhum modelo adicionado ainda.",
|
||||||
|
"aiProviderModelsBlock": "Lista de Bloqueio",
|
||||||
|
"aiProviderModelsBlockDescription": "Modelos a serem negados, mesmo que correspondam a uma entrada permitida.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Insira a chave do modelo",
|
||||||
|
"aiProviderModelsBlockEmpty": "Nenhum modelo adicionado ainda.",
|
||||||
|
"aiProviderModelsAdd": "Adicionar Modelos",
|
||||||
|
"aiProviderModelsClearAll": "Limpar Tudo",
|
||||||
|
"aiProviderModelsAddCustom": "Adicionar \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Pressione Enter para adicionar esta chave de modelo personalizada.",
|
||||||
|
"aiProviderModelsAddBulk": "Adicionar {count} chaves personalizadas",
|
||||||
|
"aiProviderModelsAddBulkHint": "Pressione Enter para adicionar {count} chaves personalizadas.",
|
||||||
|
"aiProviderModelsAddOne": "Adicionar {key} agora",
|
||||||
|
"aiProviderModelsAddSelected": "Adicionar Selecionado",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} selecionados",
|
||||||
|
"aiProviderModelsSelectAll": "Selecionar tudo",
|
||||||
|
"aiProviderModelsClearSelected": "Limpar",
|
||||||
|
"aiProviderModelsBulkHint": "Selecione modelos conhecidos ou digite uma chave personalizada.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Nenhum modelo de catálogo correspondente.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Modelos Conhecidos",
|
||||||
|
"aiProviderModelsAllLabel": "Todos os modelos",
|
||||||
|
"aiProviderModelsAllPatternHint": "Curinga: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Permitir todos os modelos",
|
||||||
|
"aiProviderModelsAddAllBlock": "Bloquear todos os modelos",
|
||||||
|
"aiProviderModelsAddAllDescription": "Usa o curinga * para que toda chave de modelo corresponda.",
|
||||||
|
"aiProviderModelsViewMore": "Ver mais ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Ver menos",
|
||||||
|
"aiProviderModelsRemove": "Remover modelo",
|
||||||
|
"aiProviderModelsEditHint": "Clique para editar configurações de modelo",
|
||||||
|
"aiProviderModelsSourceCatalog": "Modelo de catálogo conhecido",
|
||||||
|
"aiProviderModelsSourceCustom": "Chave de modelo personalizada",
|
||||||
|
"aiProviderModelsSourcePattern": "Padrão curinga",
|
||||||
|
"aiProviderModelsSourceAll": "Corresponde a toda chave de modelo",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Orçamento configurado",
|
||||||
|
"aiProviderModelsEditTitle": "Editar Modelo",
|
||||||
|
"aiProviderModelsEditDescription": "Atualizar a chave do modelo ou configure seu orçamento.",
|
||||||
|
"aiProviderModelsBudgetTab": "Orçamento",
|
||||||
|
"aiProviderModelsKeyLabel": "Chave do Modelo",
|
||||||
|
"aiProviderModelsKeyRequired": "Insira uma chave de modelo",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Esta chave de modelo já está em uma lista",
|
||||||
|
"aiProviderModelsOverlapError": "Esses padrões não podem estar em ambas as listas: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modelos atualizados",
|
||||||
|
"aiProviderModelsErrorUpdate": "Falha ao atualizar modelos",
|
||||||
|
"aiResourceProviders": "Provedores",
|
||||||
|
"aiResourceProvidersDescription": "Escolha quais fornecedores de IA este gateway de IA pode usar",
|
||||||
|
"aiResourceProvidersHelp": "Anexe fornecedores e escolha herdar (usar as listas de cada fornecedor) ou selecionar (escolher uma lista de permissão para este recurso). Padrões de permissão que conflitam entre os fornecedores anexados não são permitidos.",
|
||||||
|
"aiResourceProvidersSelect": "Selecione fornecedores",
|
||||||
|
"aiResourceProvidersEmpty": "Nenhum fornecedor de IA encontrado",
|
||||||
|
"aiResourceProvidersNoneAttached": "Nenhum fornecedor anexado ainda.",
|
||||||
|
"aiResourceProvidersAdd": "Adicionar fornecedor",
|
||||||
|
"aiResourceProvidersRemove": "Remover fornecedor",
|
||||||
|
"aiResourceProviderToggleEnabled": "Ativar ou desativar este fornecedor no recurso",
|
||||||
|
"aiResourceProviderDisabled": "Desativado",
|
||||||
|
"aiResourceProvidersUpdated": "Provedores atualizados",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Falha ao atualizar provedores",
|
||||||
|
"aiResourceProviderEditDescription": "Escolha como os modelos deste fornecedor são expostos neste recurso.",
|
||||||
|
"viewProviderSettings": "Ver Configurações do Provedor",
|
||||||
|
"aiResourceProviderMode": "Modo de acesso",
|
||||||
|
"aiResourceProviderModeInherit": "Herdar",
|
||||||
|
"aiResourceProviderModeSelect": "Selecionar",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Selecionar · {count} modelos",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Use as listas de permissão e bloqueio deste provedor conforme configurado no mesmo.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Escolha um subconjunto dos modelos da lista de permissão deste fornecedor para este recurso.",
|
||||||
|
"aiResourceProviderAllowModels": "Lista de permissão",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Selecionar modelos",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Buscar modelos...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Nenhum modelo encontrado",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Somente modelos da lista de permissão deste fornecedor podem ser selecionados.",
|
||||||
|
"aiResourceAliasRequired": "Alias é exigido para gateways de IA",
|
||||||
|
"aiResourceDomainConfiguration": "Configuração do Domínio",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Escolha o domínio que os clientes usarão para acessar este gateway de IA.",
|
||||||
|
"aiUsageAnalyticsTitle": "Análise de Uso de IA",
|
||||||
|
"aiUsageAnalyticsDescription": "Analise custo de gateway de IA, uso de token e atividade entre fornecedores, recursos, funções e usuários",
|
||||||
|
"aiUsageTabOverview": "Visão geral",
|
||||||
|
"aiUsageTabProviders": "Provedores",
|
||||||
|
"aiUsageTabResources": "Recursos",
|
||||||
|
"aiUsageFilterProvider": "Provedor",
|
||||||
|
"aiUsageFilterModel": "Modelo",
|
||||||
|
"aiUsageFilterResource": "Recurso",
|
||||||
|
"aiUsageFilterRole": "Função",
|
||||||
|
"aiUsageFilterUser": "Usuário",
|
||||||
|
"aiUsageFilterAllProviders": "Todos os Provedores",
|
||||||
|
"aiUsageFilterAllModels": "Todos os Modelos",
|
||||||
|
"aiUsageFilterAllResources": "Todos os Recursos",
|
||||||
|
"aiUsageFilterAllRoles": "Todas as Funções",
|
||||||
|
"aiUsageFilterAllUsers": "Todos os Usuários",
|
||||||
|
"aiUsageFilterSearch": "Pesquisar...",
|
||||||
|
"aiUsageFilterNotFound": "Nenhuma opção encontrada",
|
||||||
|
"aiUsageResetFilters": "Redefinir Filtros",
|
||||||
|
"aiUsageRefresh": "Atualizar",
|
||||||
|
"aiUsageTokenTypePrompt": "Prompt",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Leitura de cache",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Gravação de cache",
|
||||||
|
"aiUsageTokenTypeCompletion": "Conclusão",
|
||||||
|
"aiUsageTokenTypeReasoning": "Raciocínio",
|
||||||
|
"aiUsageRequests": "Solicitações",
|
||||||
|
"aiUsageCost": "Custo",
|
||||||
|
"aiUsageTokens": "Tokens",
|
||||||
|
"aiUsageOther": "Outro",
|
||||||
|
"aiUsageTotalRequests": "Total de Solicitações",
|
||||||
|
"aiUsageTotalTokens": "Total de Tokens",
|
||||||
|
"aiUsageTotalCost": "Custo Total",
|
||||||
|
"aiUsageEstimated": "Estimado",
|
||||||
|
"aiUsageRequestVolume": "Volume de Solicitações",
|
||||||
|
"aiUsageTokenUsage": "Uso de Token",
|
||||||
|
"aiUsageModelCost": "Custo do Modelo",
|
||||||
|
"aiUsageModelTokens": "Tokens do Modelo",
|
||||||
|
"aiUsageTopModels": "Principais Modelos",
|
||||||
|
"aiUsageTopProviders": "Principais Provedores",
|
||||||
|
"aiUsageProviderCost": "Custo do Provedor",
|
||||||
|
"aiUsageProviderTokenUsage": "Uso de Token do Provedor",
|
||||||
|
"aiUsageTopResources": "Principais Recursos",
|
||||||
|
"aiUsageResourceCost": "Custo do Recurso",
|
||||||
|
"aiUsageResourceTokenUsage": "Uso de Token do Recurso",
|
||||||
|
"aiUsageResourceTypePublic": "Recurso Público",
|
||||||
|
"aiUsageResourceTypeSite": "Recurso Privado",
|
||||||
|
"aiUsageNoResource": "Sem recurso",
|
||||||
|
"aiUsageRolesTab": "Funções",
|
||||||
|
"aiUsageUsersTab": "Usuários",
|
||||||
|
"aiUsageTopRoles": "Principais Funções",
|
||||||
|
"aiUsageRoleCost": "Custo da Função",
|
||||||
|
"aiUsageRoleTokenUsage": "Uso de Token da Função",
|
||||||
|
"aiUsageTopUsers": "Principais Usuários",
|
||||||
|
"aiUsageUserCost": "Custo do Usuário",
|
||||||
|
"aiUsageUserTokenUsage": "Uso de Token do Usuário",
|
||||||
|
"aiUsageUnknownUser": "Usuário desconhecido",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Chaves de API Virtuais",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Chave de API Virtual",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Todas as Chaves de API Virtuais",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Principais Chaves de API Virtuais",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Custo da Chave de API Virtual",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Uso de Token da Chave de API Virtual",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Nenhuma chave de API virtual",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Chave não nomeada",
|
||||||
|
"aiUsageLoading": "Carregando...",
|
||||||
|
"aiUsageNoData": "Sem dados",
|
||||||
|
"resourceBudgetSettings": "Orçamento",
|
||||||
|
"resourceBudgetSettingsDescription": "Configure como este gateway de IA restringe o uso com base em gastos ou limites de tokens",
|
||||||
"sidebarApiKeys": "Chaves API",
|
"sidebarApiKeys": "Chaves API",
|
||||||
"sidebarProvisioning": "Provisionamento",
|
"sidebarProvisioning": "Provisionamento",
|
||||||
"sidebarSettings": "Configurações",
|
"sidebarSettings": "Configurações",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Regra de alerta salva",
|
"alertingRuleSaved": "Regra de alerta salva",
|
||||||
"alertingRuleSavedCreatedDescription": "Sua nova regra de alerta foi criada. Você pode continuar editando-a nesta página.",
|
"alertingRuleSavedCreatedDescription": "Sua nova regra de alerta foi criada. Você pode continuar editando-a nesta página.",
|
||||||
"alertingRuleSavedUpdatedDescription": "As suas alterações para esta regra de alerta foram salvas.",
|
"alertingRuleSavedUpdatedDescription": "As suas alterações para esta regra de alerta foram salvas.",
|
||||||
|
"alertingTestAlertSent": "Alerta de teste enviado",
|
||||||
|
"alertingTestAlertSentDescription": "Um alerta de teste foi enviado para as ações configuradas nesta regra.",
|
||||||
"alertingEditRule": "Editar Regra de Alerta",
|
"alertingEditRule": "Editar Regra de Alerta",
|
||||||
"alertingCreateRule": "Criar Regra de Alerta",
|
"alertingCreateRule": "Criar Regra de Alerta",
|
||||||
"alertingRuleCredenzaDescription": "Escolha o que observar, quando disparar e como notificar",
|
"alertingRuleCredenzaDescription": "Escolha o que observar, quando disparar e como notificar",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Cada regra une o que observar (um site, verificação de saúde ou recurso), quando disparar (por exemplo, offline ou não saudável) e como notificar sua equipe por e-mail, webhooks ou integrações. Use esta lista para criar, ativar e gerenciar essas regras.",
|
"alertingRulesBannerDescription": "Cada regra une o que observar (um site, verificação de saúde ou recurso), quando disparar (por exemplo, offline ou não saudável) e como notificar sua equipe por e-mail, webhooks ou integrações. Use esta lista para criar, ativar e gerenciar essas regras.",
|
||||||
"alertingHealthChecksBannerTitle": "Monitorar Saúde & Recursos",
|
"alertingHealthChecksBannerTitle": "Monitorar Saúde & Recursos",
|
||||||
"alertingHealthChecksBannerDescription": "As verificações de saúde são monitores HTTP ou TCP que você define uma vez. Você pode, então, usá-los como fontes em regras de alerta, para ser notificado quando um alvo se tornar saudável ou não saudável. As verificações de saúde em recursos também aparecem aqui.",
|
"alertingHealthChecksBannerDescription": "As verificações de saúde são monitores HTTP ou TCP que você define uma vez. Você pode, então, usá-los como fontes em regras de alerta, para ser notificado quando um alvo se tornar saudável ou não saudável. As verificações de saúde em recursos também aparecem aqui.",
|
||||||
|
"alertingTestRule": "Regra de Alerta de Teste",
|
||||||
|
"alertingAddActionHeading": "Adicionar Nova Ação",
|
||||||
|
"alertingSelectActionType": "Selecionar uma Ação",
|
||||||
|
"alertingNoActionsTitle": "Nenhuma ação configurada",
|
||||||
|
"alertingNoActionsSaveDescription": "Adicione pelo menos uma ação para que esta regra possa notificar alguém quando for acionada.",
|
||||||
|
"alertingNoActionsTestDescription": "Adicione pelo menos uma ação antes de poder testar esta regra.",
|
||||||
"standaloneHcTableTitle": "Verificações de Saúde",
|
"standaloneHcTableTitle": "Verificações de Saúde",
|
||||||
"standaloneHcSearchPlaceholder": "Pesquisar verificações de saúde…",
|
"standaloneHcSearchPlaceholder": "Pesquisar verificações de saúde…",
|
||||||
"standaloneHcAddButton": "Criar Verificação de Saúde",
|
"standaloneHcAddButton": "Criar Verificação de Saúde",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Subdomínio: {subdomain}",
|
"domainPickerSubdomain": "Subdomínio: {subdomain}",
|
||||||
"domainPickerNamespace": "Namespace: {namespace}",
|
"domainPickerNamespace": "Namespace: {namespace}",
|
||||||
"domainPickerShowMore": "Mostrar Mais",
|
"domainPickerShowMore": "Mostrar Mais",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Nenhum domínio disponível",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Você ainda não configurou nenhum domínio. Crie um domínio para continuar.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Ir para Domínios",
|
||||||
"regionSelectorTitle": "Selecionar Região",
|
"regionSelectorTitle": "Selecionar Região",
|
||||||
"domainPickerRemoteExitNodeWarning": "Domínios fornecidos não são suportados quando os sites se conectam a nós de saída remota. Para recursos disponíveis em nós remotos, use um domínio personalizado.",
|
"domainPickerRemoteExitNodeWarning": "Domínios fornecidos não são suportados quando os sites se conectam a nós de saída remota. Para recursos disponíveis em nós remotos, use um domínio personalizado.",
|
||||||
"regionSelectorInfo": "Selecionar uma região nos ajuda a fornecer melhor desempenho para sua localização. Você não precisa estar na mesma região que seu servidor.",
|
"regionSelectorInfo": "Selecionar uma região nos ajuda a fornecer melhor desempenho para sua localização. Você não precisa estar na mesma região que seu servidor.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Sub-rede",
|
"subnetPlaceholder": "Sub-rede",
|
||||||
"addressDescription": "O endereço interno do cliente. Deve estar dentro da sub-rede da organização.",
|
"addressDescription": "O endereço interno do cliente. Deve estar dentro da sub-rede da organização.",
|
||||||
"selectSites": "Selecionar sites",
|
"selectSites": "Selecionar sites",
|
||||||
|
"selectResources": "Selecionar recursos",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# recurso} other {# recursos}}",
|
||||||
"selectLabels": "Selecionar etiquetas",
|
"selectLabels": "Selecionar etiquetas",
|
||||||
"sitesDescription": "O cliente terá conectividade com os sites selecionados",
|
"sitesDescription": "O cliente terá conectividade com os sites selecionados",
|
||||||
"clientInstallOlm": "Instalar Olm",
|
"clientInstallOlm": "Instalar Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "O tempo está em segundos",
|
"timeIsInSeconds": "O tempo está em segundos",
|
||||||
"requireDeviceApproval": "Exigir aprovação do dispositivo",
|
"requireDeviceApproval": "Exigir aprovação do dispositivo",
|
||||||
"requireDeviceApprovalDescription": "Usuários com esta função precisam de novos dispositivos aprovados por um administrador antes que eles possam se conectar e acessar recursos.",
|
"requireDeviceApprovalDescription": "Usuários com esta função precisam de novos dispositivos aprovados por um administrador antes que eles possam se conectar e acessar recursos.",
|
||||||
"sshSettings": "Configurações SSH",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "Gateway de IA",
|
||||||
"sshAccess": "Acesso SSH",
|
"sshAccess": "Acesso SSH",
|
||||||
"rdpSettings": "Configurações RDP",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "Configurações VNC",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "Servidor SSH",
|
"sshServer": "Servidor SSH",
|
||||||
"rdpServer": "Servidor RDP",
|
"rdpServer": "Servidor RDP",
|
||||||
"vncServer": "Servidor VNC",
|
"vncServer": "Servidor VNC",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Público",
|
"resourcesTableProxyResources": "Público",
|
||||||
"resourcesTableClientResources": "Privado",
|
"resourcesTableClientResources": "Privado",
|
||||||
"resourcesTableNoProxyResourcesFound": "Nenhum recurso de proxy encontrado.",
|
"resourcesTableNoProxyResourcesFound": "Nenhum recurso de proxy encontrado.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Nenhum recurso interno encontrado.",
|
"resourcesTableNoInternalResourcesFound": "Nenhum recurso privado encontrado.",
|
||||||
"resourcesTableDestination": "Destino",
|
"resourcesTableDestination": "Destino",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Endereço do Pseudônimo",
|
"resourcesTableAliasAddress": "Endereço do Pseudônimo",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Cancelar",
|
"editInternalResourceDialogCancel": "Cancelar",
|
||||||
"editInternalResourceDialogSaveResource": "Guardar Recurso",
|
"editInternalResourceDialogSaveResource": "Guardar Recurso",
|
||||||
"editInternalResourceDialogSuccess": "Sucesso",
|
"editInternalResourceDialogSuccess": "Sucesso",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso interno atualizado com sucesso",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso privado atualizado com sucesso",
|
||||||
"editInternalResourceDialogError": "Erro",
|
"editInternalResourceDialogError": "Erro",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Falha ao atualizar recurso interno",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Falha ao atualizar recurso privado",
|
||||||
"editInternalResourceDialogNameRequired": "Nome é obrigatório",
|
"editInternalResourceDialogNameRequired": "Nome é obrigatório",
|
||||||
"editInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
|
"editInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
|
||||||
"editInternalResourceDialogProxyPortMin": "Porta de proxy deve ser pelo menos 1",
|
"editInternalResourceDialogProxyPortMin": "Porta de proxy deve ser pelo menos 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "Gateway de IA",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Esquema",
|
"editInternalResourceDialogScheme": "Esquema",
|
||||||
"editInternalResourceDialogEnableSsl": "Ativar TLS",
|
"editInternalResourceDialogEnableSsl": "Ativar TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Um alias de DNS interno opcional para este recurso.",
|
"editInternalResourceDialogAliasDescription": "Um alias de DNS interno opcional para este recurso.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Nenhum Site Disponível",
|
"createInternalResourceDialogNoSitesAvailable": "Nenhum Site Disponível",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Você precisa ter pelo menos um site Newt com uma sub-rede configurada para criar recursos internos.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Você precisa ter pelo menos um site Newt com uma sub-rede configurada para criar recursos privados.",
|
||||||
"createInternalResourceDialogClose": "Fechar",
|
"createInternalResourceDialogClose": "Fechar",
|
||||||
"createInternalResourceDialogCreateClientResource": "Criar Recurso Privado",
|
"createInternalResourceDialogCreateClientResource": "Criar Recurso Privado",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Criar um novo recurso que só será acessível para clientes conectados à organização",
|
"createInternalResourceDialogCreateClientResourceDescription": "Criar um novo recurso que só será acessível para clientes conectados à organização",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Permitir ICMP Ping",
|
"privateResourceAllowIcmpPing": "Permitir ICMP Ping",
|
||||||
"privateResourceNetworkAccess": "Acesso à Rede",
|
"privateResourceNetworkAccess": "Acesso à Rede",
|
||||||
"privateResourceNetworkAccessDescription": "Controlar o acesso à porta TCP/UDP e se o ICMP ping é permitido para este recurso.",
|
"privateResourceNetworkAccessDescription": "Controlar o acesso à porta TCP/UDP e se o ICMP ping é permitido para este recurso.",
|
||||||
"hostSettings": "Configurações do Host",
|
"hostSettings": "Host",
|
||||||
"cidrSettings": "Configurações CIDR",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Propriedades do Recurso",
|
"createInternalResourceDialogResourceProperties": "Propriedades do Recurso",
|
||||||
"createInternalResourceDialogName": "Nome",
|
"createInternalResourceDialogName": "Nome",
|
||||||
"createInternalResourceDialogSite": "Site",
|
"createInternalResourceDialogSite": "Site",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Cancelar",
|
"createInternalResourceDialogCancel": "Cancelar",
|
||||||
"createInternalResourceDialogCreateResource": "Criar Recurso",
|
"createInternalResourceDialogCreateResource": "Criar Recurso",
|
||||||
"createInternalResourceDialogSuccess": "Sucesso",
|
"createInternalResourceDialogSuccess": "Sucesso",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso interno criado com sucesso",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso privado criado com sucesso",
|
||||||
"createInternalResourceDialogError": "Erro",
|
"createInternalResourceDialogError": "Erro",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Falha ao criar recurso interno",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Falha ao criar recurso privado",
|
||||||
"createInternalResourceDialogNameRequired": "Nome é obrigatório",
|
"createInternalResourceDialogNameRequired": "Nome é obrigatório",
|
||||||
"createInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
|
"createInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Por favor, selecione um site",
|
"createInternalResourceDialogPleaseSelectSite": "Por favor, selecione um site",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "Gateway de IA",
|
||||||
"scheme": "Esquema",
|
"scheme": "Esquema",
|
||||||
"createInternalResourceDialogScheme": "Esquema",
|
"createInternalResourceDialogScheme": "Esquema",
|
||||||
"createInternalResourceDialogEnableSsl": "Ativar TLS",
|
"createInternalResourceDialogEnableSsl": "Ativar TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Senha válida",
|
"validPassword": "Senha válida",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Chave de API Virtual Válida",
|
||||||
"view": "Visualizar",
|
"view": "Visualizar",
|
||||||
"configManaged": "Configuração Gerenciada",
|
"configManaged": "Configuração Gerenciada",
|
||||||
"connectedClient": "Cliente Conectado",
|
"connectedClient": "Cliente Conectado",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Retenção de Log",
|
"logRetention": "Retenção de Log",
|
||||||
"logRetentionDescription": "Gerenciar quanto tempo os diferentes tipos de logs são mantidos para esta organização ou desativá-los",
|
"logRetentionDescription": "Gerenciar quanto tempo os diferentes tipos de logs são mantidos para esta organização ou desativá-los",
|
||||||
"requestLogsDescription": "Ver registros de pedidos detalhados de recursos nesta organização",
|
"requestLogsDescription": "Ver registros de pedidos detalhados de recursos nesta organização",
|
||||||
|
"aiSessionLogs": "Registros de Sessão do Gateway de IA",
|
||||||
|
"aiSessionLogsDescription": "Veja as transcrições de prompt e resposta para solicitações de gateway de IA nesta organização",
|
||||||
|
"sidebarLogsAi": "Registros de Sessão",
|
||||||
|
"commandLogsAi": "Registros de Sessão",
|
||||||
|
"sidebarLogsAiUsage": "Análise de Uso",
|
||||||
|
"commandLogsAiUsage": "Análise de Uso",
|
||||||
|
"provider": "Provedor",
|
||||||
|
"capability": "Capacidade",
|
||||||
|
"model": "Modelo",
|
||||||
|
"virtualApiKey": "Chave de API Virtual",
|
||||||
|
"noVirtualApiKey": "Sem chave de API virtual",
|
||||||
|
"stream": "Stream",
|
||||||
|
"streaming": "Transmitindo",
|
||||||
|
"nonStreaming": "Não-streaming",
|
||||||
|
"statusCode": "Código de Status",
|
||||||
|
"aiSessionId": "ID de Sessão",
|
||||||
|
"aiSessionRequest": "Solicitação",
|
||||||
|
"aiSessionResponse": "Resposta",
|
||||||
|
"aiSessionNoData": "Nenhum dado capturado",
|
||||||
|
"aiSessionCouldNotParse": "(bruto, não foi possível analisar transcrição)",
|
||||||
|
"aiSessionLogTruncated": "Esta sessão foi truncada antes do armazenamento e pode estar incompleta.",
|
||||||
|
"aiSessionViewRaw": "Ver JSON Bruto",
|
||||||
|
"aiSessionViewChat": "Ver Chat",
|
||||||
|
"cost": "Custo",
|
||||||
|
"estimated": "Estimado",
|
||||||
|
"tokenUsage": "Uso de Token",
|
||||||
|
"promptTokens": "Tokens de Prompt",
|
||||||
|
"cacheReadTokens": "Tokens de Leitura de Cache",
|
||||||
|
"cacheWriteTokens": "Tokens de Gravação de Cache",
|
||||||
|
"completionTokens": "Tokens de Conclusão",
|
||||||
|
"reasoningTokens": "Tokens de Raciocínio",
|
||||||
|
"totalTokens": "Total de Tokens",
|
||||||
"requestAnalyticsDescription": "Exibir análise detalhada de pedidos para recursos nesta organização",
|
"requestAnalyticsDescription": "Exibir análise detalhada de pedidos para recursos nesta organização",
|
||||||
"logRetentionRequestLabel": "Retenção de Registro de Pedido HTTP",
|
"logRetentionRequestLabel": "Retenção de Registro de Pedido HTTP",
|
||||||
"logRetentionRequestDescription": "Por quanto tempo manter os registros de pedidos",
|
"logRetentionRequestDescription": "Por quanto tempo manter os registros de pedidos",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Por quanto tempo manter os registros de ação",
|
"logRetentionActionDescription": "Por quanto tempo manter os registros de ação",
|
||||||
"logRetentionConnectionLabel": "Retenção de registro de conexão",
|
"logRetentionConnectionLabel": "Retenção de registro de conexão",
|
||||||
"logRetentionConnectionDescription": "Por quanto tempo manter os registros de conexão",
|
"logRetentionConnectionDescription": "Por quanto tempo manter os registros de conexão",
|
||||||
|
"logRetentionAISessionsLabel": "Retenção de Registros de Sessão do Gateway de IA",
|
||||||
|
"logRetentionAISessionsDescription": "Quanto tempo reter logs de sessão de prompt/resposta do gateway de IA",
|
||||||
"logRetentionDisabled": "Desabilitado",
|
"logRetentionDisabled": "Desabilitado",
|
||||||
"logRetention3Days": "3 dias",
|
"logRetention3Days": "3 dias",
|
||||||
"logRetention7Days": "7 dias",
|
"logRetention7Days": "7 dias",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Endereço de origem",
|
"sourceAddress": "Endereço de origem",
|
||||||
"destinationAddress": "Endereço de destino",
|
"destinationAddress": "Endereço de destino",
|
||||||
"duration": "Duração",
|
"duration": "Duração",
|
||||||
"licenseRequiredToUse": "Uma licença <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> ou <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> é necessária para usar este recurso. <bookADemoLink>Reserve um teste de demonstração ou POC</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Licença da Edição Empresarial</enterpriseEditionLink> é necessária. <bookADemoLink>Agende uma demo ou teste</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "O <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> é necessário para usar este recurso. Este recurso também está disponível no <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Reserve uma demonstração ou avaliação POC</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Licença da Edição Empresarial</enterpriseEditionLink> é necessária. <bookADemoLink>Agende uma demo ou teste</bookADemoLink>",
|
||||||
"certResolver": "Resolvedor de Certificado",
|
"certResolver": "Resolvedor de Certificado",
|
||||||
"certResolverDescription": "Selecione o resolvedor de certificados para este recurso.",
|
"certResolverDescription": "Selecione o resolvedor de certificados para este recurso.",
|
||||||
"selectCertResolver": "Selecionar solucionador de certificado",
|
"selectCertResolver": "Selecionar solucionador de certificado",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Selecionar múltiplos sites permite roteamento resiliente e failover para alta disponibilidade.",
|
"internalResourceFormMultiSiteRoutingHelp": "Selecionar múltiplos sites permite roteamento resiliente e failover para alta disponibilidade.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Saiba mais",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Saiba mais",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Restrinja o acesso a portas TCP/UDP específicas ou permita/bloqueie todas as portas.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Restrinja o acesso a portas TCP/UDP específicas ou permita/bloqueie todas as portas.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "Configuração HTTP",
|
"createInternalResourceDialogHttpConfiguration": "Configuração do Domínio",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Escolha o domínio que os clientes usarão para acessar este recurso via HTTP ou HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Escolha o domínio que os clientes usarão para acessar este recurso via HTTP ou HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "Configuração HTTP",
|
"editInternalResourceDialogHttpConfiguration": "Configuração do Domínio",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Escolha o domínio que os clientes usarão para acessar este recurso via HTTP ou HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Escolha o domínio que os clientes usarão para acessar este recurso via HTTP ou HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Sem Etiqueta",
|
"resourceLauncherUnlabeled": "Sem Etiqueta",
|
||||||
|
"resourceLauncherAiGateway": "Gateway de IA",
|
||||||
"resourceLauncherNoSite": "Sem Site",
|
"resourceLauncherNoSite": "Sem Site",
|
||||||
|
"resourceLauncherAvailableModels": "Modelos Disponíveis",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Modelos que você pode usar com este gateway de IA.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Nenhum modelo está disponível para este recurso.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Não foi possível carregar modelos disponíveis.",
|
||||||
|
"resourceLauncherApiKeys": "Chaves de API",
|
||||||
|
"resourceLauncherApiKeysDescription": "Use sua chave de identidade ou uma chave atribuída para autenticar com este recurso.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Chave de Identidade",
|
||||||
|
"resourceLauncherApiKeysManual": "Chaves Atribuídas",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Nenhuma chave de API está disponível para este recurso.",
|
||||||
|
"resourceLauncherApiKeysError": "Não foi possível carregar chaves de API.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Nenhum recurso neste grupo",
|
"resourceLauncherNoResourcesInGroup": "Nenhum recurso neste grupo",
|
||||||
"resourceLauncherEmptyStateTitle": "Nenhum Recurso Disponível",
|
"resourceLauncherEmptyStateTitle": "Nenhum Recurso Disponível",
|
||||||
"resourceLauncherEmptyStateDescription": "Você não tem acesso a nenhum recurso ainda. Entre em contato com seu administrador para solicitar acesso.",
|
"resourceLauncherEmptyStateDescription": "Você não tem acesso a nenhum recurso ainda. Entre em contato com seu administrador para solicitar acesso.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Não foi possível excluir a visualização do lançador. Por favor, tente novamente.",
|
"resourceLauncherViewDeleteFailedDescription": "Não foi possível excluir a visualização do lançador. Por favor, tente novamente.",
|
||||||
"memberPortalPrevious": "Anterior",
|
"memberPortalPrevious": "Anterior",
|
||||||
"memberPortalNext": "Próximo",
|
"memberPortalNext": "Próximo",
|
||||||
"httpSettings": "Configurações HTTP",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "Configurações TCP",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "Configurações UDP",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Estabelecendo uma conexão segura…",
|
"sshConnectingDescription": "Estabelecendo uma conexão segura…",
|
||||||
"sshConnecting": "A conectar…",
|
"sshConnecting": "A conectar…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Falha no upload",
|
"rdpUploadFailed": "Falha no upload",
|
||||||
"rdpUnicodeKeyboardMode": "Modo de teclado Unicode",
|
"rdpUnicodeKeyboardMode": "Modo de teclado Unicode",
|
||||||
"sessionToolbarShow": "Mostrar barra de ferramentas",
|
"sessionToolbarShow": "Mostrar barra de ferramentas",
|
||||||
"sessionToolbarHide": "Ocultar barra de ferramentas"
|
"sessionToolbarHide": "Ocultar barra de ferramentas",
|
||||||
|
"actionUpdateSiteApprovals": "Atualizar Aprovações do Site"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Убедитесь, что вы вошли под правильным пользователем.",
|
"inviteLoginUser": "Убедитесь, что вы вошли под правильным пользователем.",
|
||||||
"inviteErrorNoUser": "Извините, но похоже, что приглашение, к которому вы пытаетесь получить доступ, предназначено для несуществующего пользователя.",
|
"inviteErrorNoUser": "Извините, но похоже, что приглашение, к которому вы пытаетесь получить доступ, предназначено для несуществующего пользователя.",
|
||||||
"inviteCreateUser": "Сначала создайте аккаунт.",
|
"inviteCreateUser": "Сначала создайте аккаунт.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Приглашения могут быть приняты только внутренними учетными записями. Выйдите и войдите с вашим паролем для этого электронного адреса.",
|
||||||
|
"inviteLoginInternalOnly": "Приглашения требуют внутреннюю учетную запись с паролем. Создайте учетную запись или войдите с вашим паролем.",
|
||||||
"goHome": "На главную",
|
"goHome": "На главную",
|
||||||
"inviteLogInOtherUser": "Войти под другим пользователем",
|
"inviteLogInOtherUser": "Войти под другим пользователем",
|
||||||
"createAnAccount": "Создать учётную запись",
|
"createAnAccount": "Создать учётную запись",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Подтвердить удаление общей ссылки",
|
"shareDeleteConfirm": "Подтвердить удаление общей ссылки",
|
||||||
"shareQuestionRemove": "Вы уверены, что хотите удалить эту общую ссылку?",
|
"shareQuestionRemove": "Вы уверены, что хотите удалить эту общую ссылку?",
|
||||||
"shareMessageRemove": "После удаления ссылка перестанет работать, и все, кто ее использует, потеряют доступ к ресурсу.",
|
"shareMessageRemove": "После удаления ссылка перестанет работать, и все, кто ее использует, потеряют доступ к ресурсу.",
|
||||||
"shareTokenDescription": "Токен доступа может быть передан двумя способами: как параметр запроса или в заголовках запроса. Они должны быть переданы от клиента по каждому запросу для аутентифицированного доступа.",
|
"shareTokenDescription": "Токен доступа может быть передан в виде параметра запроса или в заголовках запроса. По умолчанию, он должен отправляться при каждом запросе. Если включена устойчивость сеанса, первый запрос обменяет его на сеансовый файл cookie.",
|
||||||
"accessToken": "Токен доступа",
|
"accessToken": "Токен доступа",
|
||||||
"usageExamples": "Примеры использования",
|
"usageExamples": "Примеры использования",
|
||||||
"tokenId": "ID токена",
|
"tokenId": "ID токена",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Заголовок (необязательно)",
|
"shareTitleOptional": "Заголовок (необязательно)",
|
||||||
"sharePathOptional": "Путь (необязательно)",
|
"sharePathOptional": "Путь (необязательно)",
|
||||||
"sharePathDescription": "Ссылка перенаправит пользователей на этот путь после аутентификации.",
|
"sharePathDescription": "Ссылка перенаправит пользователей на этот путь после аутентификации.",
|
||||||
|
"shareAssociateUserOptional": "Связать пользователя (необязательно)",
|
||||||
|
"shareAssociateUserDescription": "При установке, запросы с этой ссылкой записываются за пользователем в журналах доступа и заголовках идентификации. Ссылка удаляется, если пользователь покидает организацию.",
|
||||||
|
"userSelect": "Выберите пользователя",
|
||||||
|
"usersNotFound": "Пользователи не найдены",
|
||||||
"expireIn": "Срок действия",
|
"expireIn": "Срок действия",
|
||||||
"neverExpire": "Бессрочный доступ",
|
"neverExpire": "Бессрочный доступ",
|
||||||
|
"sharePersistSession": "Сохранять сеанс после первого использования",
|
||||||
|
"sharePersistSessionDescription": "При включении, первый запрос с этим токеном через параметр запроса или заголовок устанавливает сеансовый файл cookie, так что последующие запросы не требуют токена. Оставьте для API-клиентов, которые должны отправлять токен при каждом запросе.",
|
||||||
"shareExpireDescription": "Срок действия - это период, в течение которого ссылка будет работать и предоставлять доступ к ресурсу. После этого времени ссылка перестанет работать, и пользователи, использовавшие эту ссылку, потеряют доступ к ресурсу.",
|
"shareExpireDescription": "Срок действия - это период, в течение которого ссылка будет работать и предоставлять доступ к ресурсу. После этого времени ссылка перестанет работать, и пользователи, использовавшие эту ссылку, потеряют доступ к ресурсу.",
|
||||||
"shareSeeOnce": "Вы сможете увидеть эту ссылку только один раз. Обязательно скопируйте ее.",
|
"shareSeeOnce": "Вы сможете увидеть эту ссылку только один раз. Обязательно скопируйте ее.",
|
||||||
"shareAccessHint": "Любой, у кого есть эта ссылка, может получить доступ к ресурсу. Делитесь ею с осторожностью.",
|
"shareAccessHint": "Любой, у кого есть эта ссылка, может получить доступ к ресурсу. Делитесь ею с осторожностью.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Страна не найдена.",
|
"noCountryFound": "Страна не найдена.",
|
||||||
"siteSelectionDescription": "Этот сайт предоставит подключение к цели.",
|
"siteSelectionDescription": "Этот сайт предоставит подключение к цели.",
|
||||||
"resourceType": "Тип ресурса",
|
"resourceType": "Тип ресурса",
|
||||||
"resourceTypeDescription": "Это контролирует протокол ресурса и то, как он будет отображаться в браузере. Это нельзя изменить позже.",
|
"resourceTypeDescription": "Это контролирует протокол ресурса и не может быть изменено позже.",
|
||||||
|
"resourceTypeSearch": "Поиск типов ресурсов...",
|
||||||
|
"resourceTypeNotFound": "Тип ресурса не найден",
|
||||||
|
"resourceTypeHttpDescription": "Проксирование веб-трафика через HTTPS с использованием доменного имени",
|
||||||
|
"resourceTypeInferenceDescription": "Маршрутизация запросов ИИ через прикрепленных поставщиков",
|
||||||
|
"resourceTypeSshDescription": "Доступ к серверу SSH из браузера",
|
||||||
|
"resourceTypeRdpDescription": "Доступ к удаленному рабочему столу из браузера",
|
||||||
|
"resourceTypeVncDescription": "Доступ к рабочему столу VNC из браузера",
|
||||||
|
"resourceTypeTcpDescription": "Проксирование сырых TCP данных с использованием номера порта",
|
||||||
|
"resourceTypeUdpDescription": "Проксирование сырых UDP данных с использованием номера порта",
|
||||||
|
"privateResourceTypeDescription": "Это контролирует, как клиенты достигают ресурса. Это не может быть изменено позже.",
|
||||||
|
"privateResourceTypeHostDescription": "Опубликуйте один хост в сети сайта для подключенных клиентов",
|
||||||
|
"privateResourceTypeCidrDescription": "Опубликуйте диапазон CIDR в сети сайта для подключенных клиентов",
|
||||||
|
"privateResourceTypeHttpDescription": "Доступ к сервису HTTP или HTTPS через домен",
|
||||||
|
"privateResourceTypeSshDescription": "Доступ к серверу SSH от подключенных клиентов",
|
||||||
"resourceDomainDescription": "Ресурс будет предоставлен по этому полностью определенному доменному имени.",
|
"resourceDomainDescription": "Ресурс будет предоставлен по этому полностью определенному доменному имени.",
|
||||||
"resourceHTTPSSettings": "Настройки HTTPS",
|
"resourceHTTPSSettings": "Настройки HTTPS",
|
||||||
"resourceHTTPSSettingsDescription": "Настройка доступа к ресурсу по HTTPS",
|
"resourceHTTPSSettingsDescription": "Настройка доступа к ресурсу по HTTPS",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Подготовка",
|
"provisioningManage": "Подготовка",
|
||||||
"provisioningDescription": "Управляйте предоставленными ключами и проверять непроверенные сайты, ожидающие утверждения.",
|
"provisioningDescription": "Управляйте предоставленными ключами и проверять непроверенные сайты, ожидающие утверждения.",
|
||||||
"pendingSites": "Ожидающие сайты",
|
"pendingSites": "Ожидающие сайты",
|
||||||
"siteApproveSuccess": "Сайт успешно утвержден",
|
"siteApproveSuccess": "Сайт и связанные ресурсы успешно одобрены",
|
||||||
"siteApproveError": "Ошибка при утверждении сайта",
|
"siteApproveError": "Ошибка при утверждении сайта",
|
||||||
|
"siteReject": "Отклонить сайт",
|
||||||
|
"siteQuestionReject": "Вы уверены, что хотите отклонить этот сайт?",
|
||||||
|
"siteMessageReject": "Этот процесс окончательно удалит сайт и все связанные с ним ресурсы, которые еще ожидают.",
|
||||||
|
"siteConfirmReject": "Подтвердите отклонение сайта",
|
||||||
|
"siteRejectSuccess": "Сайт успешно отклонен",
|
||||||
|
"siteRejectError": "Ошибка при отклонении сайта",
|
||||||
"provisioningKeys": "Ключи подготовки",
|
"provisioningKeys": "Ключи подготовки",
|
||||||
"searchProvisioningKeys": "Поиск подготовительных ключей...",
|
"searchProvisioningKeys": "Поиск подготовительных ключей...",
|
||||||
"provisioningKeysAdd": "Сгенерировать ключ подготовки",
|
"provisioningKeysAdd": "Сгенерировать ключ подготовки",
|
||||||
@@ -466,8 +494,8 @@
|
|||||||
"provisioningKeysSave": "Сохранить ключ подготовки",
|
"provisioningKeysSave": "Сохранить ключ подготовки",
|
||||||
"provisioningKeysSaveDescription": "Вы сможете увидеть это только один раз. Скопируйте его в безопасное место.",
|
"provisioningKeysSaveDescription": "Вы сможете увидеть это только один раз. Скопируйте его в безопасное место.",
|
||||||
"provisioningKeysErrorCreate": "Ошибка при создании ключа подготовки",
|
"provisioningKeysErrorCreate": "Ошибка при создании ключа подготовки",
|
||||||
"provisioningKeysList": "Новый подготовительный ключ",
|
"provisioningKeysList": "Новый ключ для подготовки",
|
||||||
"provisioningKeysMaxBatchSize": "Макс. размер партии",
|
"provisioningKeysMaxBatchSize": "Максимальный размер партии",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Неограниченный размер партии (без ограничений)",
|
"provisioningKeysUnlimitedBatchSize": "Неограниченный размер партии (без ограничений)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Неограниченный",
|
"provisioningKeysMaxBatchUnlimited": "Неограниченный",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Введите максимальный размер пакета (1–1,000,000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Введите максимальный размер пакета (1–1,000,000).",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Сохранить настройки",
|
"authMethodsSave": "Сохранить настройки",
|
||||||
"policyAuthStackTitle": "Аутентификация",
|
"policyAuthStackTitle": "Аутентификация",
|
||||||
"policyAuthStackDescription": "Контроль, какие методы аутентификации требуются для доступа к этому ресурсу",
|
"policyAuthStackDescription": "Контроль, какие методы аутентификации требуются для доступа к этому ресурсу",
|
||||||
|
"policyAuthInferenceStackDescription": "Выберите, какие пользователи и роли могут аутентифицироваться на этом ИИ шлюзе",
|
||||||
"policyAuthOrLogicTitle": "Несколько методов аутентификации активны",
|
"policyAuthOrLogicTitle": "Несколько методов аутентификации активны",
|
||||||
"policyAuthOrLogicBanner": "Посетители могут аутентифицироваться, используя любой из активных методов ниже. Им не нужно выполнять все.",
|
"policyAuthOrLogicBanner": "Посетители могут аутентифицироваться, используя любой из активных методов ниже. Им не нужно выполнять все.",
|
||||||
"policyAuthMethodActive": "Активно",
|
"policyAuthMethodActive": "Активно",
|
||||||
"policyAuthMethodOff": "Отключено",
|
"policyAuthMethodOff": "Отключено",
|
||||||
"policyAuthSsoTitle": "Платформа SSO",
|
"policyAuthSsoTitle": "Платформа SSO",
|
||||||
"policyAuthSsoDescription": "Требуется войти через поставщика удостоверений вашей организации",
|
"policyAuthSsoDescription": "Требуется войти через поставщика удостоверений вашей организации",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "URL входа в систему",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "У каждого пользователя уже есть идентификационный ключ API, поэтому вам нужно создать виртуальные ключи API для не пользовательских клиентов или общего доступа.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Пользователи получают свой ключ здесь после входа в систему с провайдером идентификаторов.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} пользователей, {roles} ролей",
|
"policyAuthSsoSummary": "{idp} · {users} пользователей, {roles} ролей",
|
||||||
"policyAuthSsoDefaultIdp": "Поставщик по умолчанию",
|
"policyAuthSsoDefaultIdp": "Поставщик по умолчанию",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Добавить поставщика удостоверений по умолчанию",
|
"policyAuthAddDefaultIdentityProvider": "Добавить поставщика удостоверений по умолчанию",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Версия",
|
"newtVersion": "Версия",
|
||||||
"architecture": "Архитектура",
|
"architecture": "Архитектура",
|
||||||
"sites": "Сайты",
|
"sites": "Сайты",
|
||||||
"siteWgAnyClients": "Для подключения используйте любой клиент WireGuard. Вы должны будете адресовать внутренние ресурсы, используя IP адрес пира.",
|
"siteWgAnyClients": "Используйте любой клиент WireGuard для подключения. Вам придётся обращаться к частным ресурсам, используя IP узла.",
|
||||||
"siteWgCompatibleAllClients": "Совместим со всеми клиентами WireGuard",
|
"siteWgCompatibleAllClients": "Совместим со всеми клиентами WireGuard",
|
||||||
"siteWgManualConfigurationRequired": "Требуется ручная настройка",
|
"siteWgManualConfigurationRequired": "Требуется ручная настройка",
|
||||||
"userErrorNotAdminOrOwner": "Пользователь не является администратором или владельцем",
|
"userErrorNotAdminOrOwner": "Пользователь не является администратором или владельцем",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Новая роль обязательна",
|
"accessRoleErrorNewRequired": "Новая роль обязательна",
|
||||||
"accessRoleErrorRemove": "Не удалось удалить роль",
|
"accessRoleErrorRemove": "Не удалось удалить роль",
|
||||||
"accessRoleErrorRemoveDescription": "Произошла ошибка при удалении роли.",
|
"accessRoleErrorRemoveDescription": "Произошла ошибка при удалении роли.",
|
||||||
|
"accessRoleInferenceBudget": "Бюджет ИИ",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Настройте, как члены этой роли ограничивают использование ИИ в зависимости от расходов или лимитов токенов",
|
||||||
"accessRoleName": "Название роли",
|
"accessRoleName": "Название роли",
|
||||||
"accessRoleQuestionRemove": "Вы собираетесь удалить `{name}` роль. Это действие нельзя отменить.",
|
"accessRoleQuestionRemove": "Вы собираетесь удалить `{name}` роль. Это действие нельзя отменить.",
|
||||||
"accessRoleRemove": "Удалить роль",
|
"accessRoleRemove": "Удалить роль",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Создать пользователя Org",
|
"createOrgUser": "Создать пользователя Org",
|
||||||
"actionUpdateOrg": "Обновить организацию",
|
"actionUpdateOrg": "Обновить организацию",
|
||||||
"actionRemoveInvitation": "Удалить приглашение",
|
"actionRemoveInvitation": "Удалить приглашение",
|
||||||
|
"actionRemoveUserRole": "Удалить роль пользователя",
|
||||||
"actionUpdateUser": "Обновить пользователя",
|
"actionUpdateUser": "Обновить пользователя",
|
||||||
"actionGetUser": "Получить пользователя",
|
"actionGetUser": "Получить пользователя",
|
||||||
"actionGetOrgUser": "Получить пользователя организации",
|
"actionGetOrgUser": "Получить пользователя организации",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Удалить сайт",
|
"actionDeleteSite": "Удалить сайт",
|
||||||
"actionGetSite": "Получить сайт",
|
"actionGetSite": "Получить сайт",
|
||||||
"actionListSites": "Список сайтов",
|
"actionListSites": "Список сайтов",
|
||||||
|
"actionCreateAiProvider": "Создать поставщика ИИ",
|
||||||
|
"actionDeleteAiProvider": "Удалить поставщика ИИ",
|
||||||
|
"actionGetAiProvider": "Получить поставщика ИИ",
|
||||||
|
"actionListAiProviders": "Список поставщиков ИИ",
|
||||||
|
"actionUpdateAiProvider": "Обновить поставщика ИИ",
|
||||||
|
"actionCreateAiModel": "Создать модель ИИ",
|
||||||
|
"actionDeleteAiModel": "Удалить модель ИИ",
|
||||||
|
"actionGetAiModel": "Получить модель ИИ",
|
||||||
|
"actionListAiModels": "Список моделей ИИ",
|
||||||
|
"actionUpdateAiModel": "Обновить модель ИИ",
|
||||||
|
"actionCreateAiBudget": "Создать бюджет ИИ",
|
||||||
|
"actionDeleteAiBudget": "Удалить бюджет ИИ",
|
||||||
|
"actionGetAiBudget": "Получить бюджет ИИ",
|
||||||
|
"actionListAiBudgets": "Список бюджетов ИИ",
|
||||||
|
"actionUpdateAiBudget": "Обновить бюджет ИИ",
|
||||||
|
"actionListResourceAiModels": "Список моделей ИИ ресурса",
|
||||||
|
"actionSetResourceAiModels": "Установить модели ИИ ресурса",
|
||||||
|
"actionCreateVirtualApiKey": "Создать виртуальный ключ API",
|
||||||
|
"actionDeleteVirtualApiKey": "Удалить виртуальный ключ API",
|
||||||
|
"actionGetVirtualApiKey": "Получить виртуальный API ключ",
|
||||||
|
"actionListVirtualApiKeys": "Список виртуальных ключей API",
|
||||||
|
"actionUpdateVirtualApiKey": "Обновить виртуальный ключ API",
|
||||||
"actionApplyBlueprint": "Применить чертёж",
|
"actionApplyBlueprint": "Применить чертёж",
|
||||||
"actionListBlueprints": "Список чертежей",
|
"actionListBlueprints": "Список чертежей",
|
||||||
"actionGetBlueprint": "Получить чертёж",
|
"actionGetBlueprint": "Получить чертёж",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Введите токен настройки из консоли сервера.",
|
"setupTokenDescription": "Введите токен настройки из консоли сервера.",
|
||||||
"setupTokenRequired": "Токен настройки обязателен",
|
"setupTokenRequired": "Токен настройки обязателен",
|
||||||
"actionUpdateSite": "Обновить сайт",
|
"actionUpdateSite": "Обновить сайт",
|
||||||
|
"actionApproveSite": "Одобрить сайт",
|
||||||
|
"actionRejectSite": "Отклонить сайт",
|
||||||
"actionResetSiteBandwidth": "Сброс пропускной способности организации",
|
"actionResetSiteBandwidth": "Сброс пропускной способности организации",
|
||||||
"actionListSiteRoles": "Список разрешенных ролей сайта",
|
"actionListSiteRoles": "Список разрешенных ролей сайта",
|
||||||
"actionCreateResource": "Создать ресурс",
|
"actionCreateResource": "Создать ресурс",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Установить ПИН-код ресурса",
|
"actionSetResourcePincode": "Установить ПИН-код ресурса",
|
||||||
"actionSetResourceEmailWhitelist": "Настроить белый список ресурсов email",
|
"actionSetResourceEmailWhitelist": "Настроить белый список ресурсов email",
|
||||||
"actionGetResourceEmailWhitelist": "Получить белый список ресурсов email",
|
"actionGetResourceEmailWhitelist": "Получить белый список ресурсов email",
|
||||||
|
"actionListResourcePolicies": "Список политик ресурсов",
|
||||||
|
"actionCreateResourcePolicy": "Создать политику ресурса",
|
||||||
"actionGetResourcePolicy": "Получить политику ресурса",
|
"actionGetResourcePolicy": "Получить политику ресурса",
|
||||||
"actionUpdateResourcePolicy": "Обновить политику ресурса",
|
"actionUpdateResourcePolicy": "Обновить политику ресурса",
|
||||||
|
"actionDeleteResourcePolicy": "Удалить политику ресурса",
|
||||||
"actionSetResourcePolicyUsers": "Установить пользователей политики ресурса",
|
"actionSetResourcePolicyUsers": "Установить пользователей политики ресурса",
|
||||||
"actionSetResourcePolicyRoles": "Установить роли политики ресурса",
|
"actionSetResourcePolicyRoles": "Установить роли политики ресурса",
|
||||||
"actionSetResourcePolicyPassword": "Установить пароль политики ресурса",
|
"actionSetResourcePolicyPassword": "Установить пароль политики ресурса",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Список приглашений",
|
"actionListInvitations": "Список приглашений",
|
||||||
"actionExportLogs": "Экспорт журналов",
|
"actionExportLogs": "Экспорт журналов",
|
||||||
"actionViewLogs": "Просмотр журналов",
|
"actionViewLogs": "Просмотр журналов",
|
||||||
|
"actionCreateSiteProvisioningKey": "Создать ключ конфигурации сайта",
|
||||||
|
"actionListSiteProvisioningKeys": "Список ключей конфигурации сайтов",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Обновить ключ конфигурации сайта",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Удалить ключ конфигурации сайта",
|
||||||
"noneSelected": "Ничего не выбрано",
|
"noneSelected": "Ничего не выбрано",
|
||||||
"orgNotFound2": "Организации не найдены.",
|
"orgNotFound2": "Организации не найдены.",
|
||||||
"search": "Поиск…",
|
"search": "Поиск…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Введите код из вашего приложения-аутентификатора или один из ваших одноразовых резервных кодов.",
|
"otpAuthDescription": "Введите код из вашего приложения-аутентификатора или один из ваших одноразовых резервных кодов.",
|
||||||
"otpAuthSubmit": "Отправить код",
|
"otpAuthSubmit": "Отправить код",
|
||||||
"idpContinue": "Или продолжить с",
|
"idpContinue": "Или продолжить с",
|
||||||
|
"idpLastUsed": "Последнее использование",
|
||||||
"otpAuthBack": "Назад к паролю",
|
"otpAuthBack": "Назад к паролю",
|
||||||
"navbar": "Навигационное меню",
|
"navbar": "Навигационное меню",
|
||||||
"navbarDescription": "Главное навигационное меню приложения",
|
"navbarDescription": "Главное навигационное меню приложения",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Создать клиент машин",
|
"commandPaletteCreateMachineClient": "Создать клиент машин",
|
||||||
"commandPaletteCreateAlertRule": "Создать правило предупреждения",
|
"commandPaletteCreateAlertRule": "Создать правило предупреждения",
|
||||||
"commandPaletteCreateIdentityProvider": "Создать поставщика удостоверений",
|
"commandPaletteCreateIdentityProvider": "Создать поставщика удостоверений",
|
||||||
|
"commandPaletteCreateAiProvider": "Создать поставщика AI",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Создать виртуальный API ключ",
|
||||||
"commandPaletteToggleTheme": "Переключить тему",
|
"commandPaletteToggleTheme": "Переключить тему",
|
||||||
"commandPaletteChooseOrganization": "Выбрать организацию",
|
"commandPaletteChooseOrganization": "Выбрать организацию",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Приглашения",
|
"sidebarInvitations": "Приглашения",
|
||||||
"sidebarRoles": "Роли",
|
"sidebarRoles": "Роли",
|
||||||
"sidebarShareableLinks": "Общие ссылки",
|
"sidebarShareableLinks": "Общие ссылки",
|
||||||
|
"sidebarAiGateway": "ИИ шлюз",
|
||||||
|
"sidebarAiProviders": "Поставщики",
|
||||||
|
"commandAiProviders": "Поставщики ИИ",
|
||||||
|
"sidebarVirtualApiKeys": "Виртуальные ключи API",
|
||||||
|
"sidebarMyApiKeys": "Ваши ключи API",
|
||||||
|
"sidebarAccount": "Пусковая установка",
|
||||||
|
"commandVirtualApiKeys": "Виртуальные ключи API",
|
||||||
|
"virtualApiKeysTitle": "Управление виртуальными ключами API",
|
||||||
|
"virtualApiKeysDescription": "Создание и управление ручными ключами API для доступа к ИИ шлюзам",
|
||||||
|
"virtualApiKeysTabIdentity": "Ключи Идентификации",
|
||||||
|
"virtualApiKeysTabVirtual": "Виртуальные ключи",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Ключи Идентификации для каждого пользователя",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Каждый пользователь уже имеет ключ для идентификации Pangolin для этой организации.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Пример",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Как пользователи получают свой ключ",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Перейдите по URL публичного ИИ шлюза в браузере и войдите в систему под своей учётной записью.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Или перейдите на <url></url>, находясь в системе.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Вы можете создать дополнительные виртуальные ключи API на вкладке Виртуальные ключи.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Создать ключ вручную",
|
||||||
|
"virtualApiKeysEmailIdentity": "Идентификационные ключи электронной почты",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Отправьте каждому выбранному пользователю или роли их идентификационный ключ Pangolin.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Отправить всем пользователям",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Отправить электронное письмо каждому члену организации, имеющему электронную почту.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Пользователи",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Роли",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "Отправить сообщения электронной почты",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Ключи идентификации отправлены по электронной почте",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "Отправлено {sent} сообщений электронной почты.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} пользователей пропущено, поскольку у них нет адреса электронной почты.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "Выберите хотя бы одного пользователя или роль, или отправьте всем пользователям.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Ошибка при отправке ключей идентификации",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Не удалось отправить ключи идентификации по электронной почте",
|
||||||
|
"virtualApiKeysBannerTitle": "Ключи идентификации для каждого пользователя",
|
||||||
|
"virtualApiKeysBannerDescription": "Каждый пользователь уже имеет ключ идентификации, доступный на {keysUrl}.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Просмотр ключей идентификации",
|
||||||
|
"virtualApiKeys": "Виртуальные ключи API",
|
||||||
|
"virtualApiKeysSearch": "Поиск ключей...",
|
||||||
|
"virtualApiKeysCreate": "Создать виртуальный ключ API",
|
||||||
|
"virtualApiKeysCreateDescription": "Создать ручной ключ, который может вызвать публичные ИИ шлюзы в этой организации",
|
||||||
|
"virtualApiKeysCreateButton": "Создать ключ",
|
||||||
|
"virtualApiKeysEmpty": "Виртуальные ключи API еще не созданы",
|
||||||
|
"virtualApiKeysName": "Имя",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Описание (опционально)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Связать пользователя (опционально)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Свяжите этот ключ с пользователем для отслеживания использования.",
|
||||||
|
"virtualApiKeysAllResources": "Все публичные ИИ шлюзы",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Разрешите этому ключу доступ ко всем публичным ИИ шлюзам в организации",
|
||||||
|
"virtualApiKeysSelectResources": "Публичные ИИ шлюзы",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Выберите ресурсы",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Выберите, к каким публичным ИИ шлюзам этот ключ может получить доступ",
|
||||||
|
"virtualApiKeysNoResources": "Нет ресурсов",
|
||||||
|
"virtualApiKeysSecret": "Ключ",
|
||||||
|
"virtualApiKeysCopyKey": "Скопируйте этот ключ. Вы можете просмотреть его позже в таблице или при редактировании.",
|
||||||
|
"virtualApiKeysViewSecret": "Посмотреть секрет",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Секрет виртуального ключа API",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Этот секрет предоставляет доступ к назначенным публичным ИИ шлюзам этого ключа",
|
||||||
|
"virtualApiKeysEdit": "Изменить виртуальный ключ API",
|
||||||
|
"virtualApiKeysEditDescription": "Обновите связанного пользователя и доступ к публичным ИИ шлюзам для этого ключа",
|
||||||
|
"virtualApiKeysSaveButton": "Сохранить изменения",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "Выберите хотя бы один публичный ИИ шлюз или разрешите все публичные ИИ шлюзы",
|
||||||
|
"virtualApiKeysUpdated": "Виртуальный ключ API обновлен",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Виртуальный ключ API обновлен",
|
||||||
|
"virtualApiKeysErrorUpdate": "Ошибка обновления виртуального ключа API",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Не удалось обновить виртуальный ключ API",
|
||||||
|
"virtualApiKeysErrorCreate": "Ошибка создания виртуального ключа API",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Не удалось создать виртуальный ключ API",
|
||||||
|
"virtualApiKeysErrorDelete": "Ошибка удаления виртуального ключа API",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Не удалось удалить виртуальный ключ API",
|
||||||
|
"virtualApiKeysDeleted": "Виртуальный ключ API удален",
|
||||||
|
"virtualApiKeysDeletedDescription": "Виртуальный ключ API удален",
|
||||||
|
"virtualApiKeysDelete": "Удалить виртуальный ключ API",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Удалить ключ",
|
||||||
|
"virtualApiKeysQuestionRemove": "Вы уверены, что хотите удалить этот виртуальный ключ API?",
|
||||||
|
"virtualApiKeysMessageRemove": "Клиенты, использующие этот ключ, немедленно потеряют доступ.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Ошибка загрузки секрета",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Не удалось загрузить секрет виртуального ключа API",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Не назначен",
|
||||||
|
"virtualApiKeysInferenceBudget": "Бюджет",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Настройте, как этот ключ ограничивает использование ИИ на основе расходов или лимитов токенов",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Отправить ключ по электронной почте при создании",
|
||||||
|
"virtualApiKeysEmailThisKey": "Отправить этот ключ по электронной почте",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Отправьте ключ связанному пользователю и дополнительным адресам после его создания",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Отправьте текущий ключ связанному пользователю и дополнительным адресам",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "На этом сервере не настроена электронная почта",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "Настройте SMTP для отправки ключей API по электронной почте.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "Отправить связанному пользователю",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Отправьте ключ на адрес электронной почты учетной записи связанного пользователя",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "Свяжите пользователя, чтобы отправить ему ключ",
|
||||||
|
"virtualApiKeysEmailAdditional": "Дополнительные электронные письма",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "Добавьте электронный адрес и нажмите Enter",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "Выберите связанного пользователя или добавьте хотя бы один адрес электронной почты",
|
||||||
|
"myVirtualApiKeysTitle": "Ваши ключи API",
|
||||||
|
"myVirtualApiKeysDescription": "Просмотрите ваш ключ идентификации и любые виртуальные ключи API, принадлежащие вам в этой организации",
|
||||||
|
"myVirtualApiKeysResourceTitle": "Ваши ключи API для {resourceName}",
|
||||||
|
"myVirtualApiKeysResourceDescription": "Просмотрите ваш ключ идентификации и виртуальные ключи API, принадлежащие вам, которые могут получить доступ к {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Ключ идентификации",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Ваш личный ключ API",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Ваш личный ключ для этой организации.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "Ваш личный ключ API для {resourceName}",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Ваш личный ключ для этой организации. Используйте его для вызова {resourceName}.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Назначенные ключи",
|
||||||
|
"myVirtualApiKeysManualDescription": "Ручные виртуальные ключи API, с которыми администратор связал вашу учетную запись",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "Ручные виртуальные ключи API, с которыми связана ваша учетная запись и которые могут получить доступ к {resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Назначенные ключи еще не созданы",
|
||||||
|
"myVirtualApiKeysKindUser": "Идентификация",
|
||||||
|
"myVirtualApiKeysKindManual": "Ручной",
|
||||||
|
"myVirtualApiKeysUnnamed": "Неназванный ключ",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Показать секрет",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Этот секрет аутентифицирует вас в ресурсах ИИ шлюза",
|
||||||
|
"aiClientConfigTitle": "Настроить кодирующие агенты",
|
||||||
|
"aiClientConfigDescription": "Скопируйте конфигурацию для популярных кодирующих агентов или позвольте Pangolin CLI настроить это автоматически.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Агентивное кодирующее средство Anthropic для терминала.",
|
||||||
|
"aiClientConfigDescriptionCodex": "Агентивное кодирующее средство OpenAI для терминала.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Открытый исходный агент для кодирования в терминале.",
|
||||||
|
"aiClientConfigDescriptionCursor": "AI редактор кода на основе VS Code.",
|
||||||
|
"aiClientConfigSetup": "Настройка",
|
||||||
|
"aiClientConfigTabCli": "Автоматическое (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Ручная конфигурация",
|
||||||
|
"aiClientConfigPreset": "Конфигурация",
|
||||||
|
"aiClientConfigStep": "Шаг {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Этот фрагмент включает в себя примерные значения, такие как название модели или URL ресурса. Замените их своими собственными, прежде чем использовать.",
|
||||||
|
"aiClientConfigRevealError": "Не удалось загрузить ваш API ключ.",
|
||||||
|
"aiClientConfigRevealRetry": "Попробовать снова",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Этот ресурс может быть использован с обычными клиентами, такими как Claude Code и OpenCode. <configLink>Узнать больше</configLink>",
|
||||||
|
"aiProvidersTitle": "Поставщики ИИ",
|
||||||
|
"aiProvidersDescription": "Подключите поставщиков моделей для ИИ нагрузок в этой организации",
|
||||||
|
"aiProvidersBannerTitle": "Подключить поставщиков моделей",
|
||||||
|
"aiProvidersBannerDescription": "Поставщики являются бэкэндами моделей, которые Pangolin использует для ИИ нагрузок.",
|
||||||
|
"aiProvidersAdd": "Добавить поставщика",
|
||||||
|
"aiProvidersSearch": "Поиск поставщиков...",
|
||||||
|
"aiProvidersEmpty": "Поставщики ИИ еще не созданы",
|
||||||
|
"aiProviderCreate": "Создать поставщика ИИ",
|
||||||
|
"aiProviderCreateDescription": "Добавьте поставщика моделей для этой организации",
|
||||||
|
"aiProviderSeeAll": "Посмотреть всех поставщиков",
|
||||||
|
"aiProviderSetting": "Настройки поставщика {providerName}",
|
||||||
|
"aiProviderSettingDescription": "Настройте этого поставщика ИИ",
|
||||||
|
"aiProviderGeneral": "Общие",
|
||||||
|
"aiProviderGeneralDescription": "Основные настройки для этого поставщика",
|
||||||
|
"aiProviderConfiguration": "Конфигурация",
|
||||||
|
"aiProviderConfigurationDescription": "Маршрутизация сети и аутентификация для этого поставщика",
|
||||||
|
"aiProviderNetworkSettings": "Настройки сети",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Выберите, как трафик достигает этого поставщика",
|
||||||
|
"aiProviderAuthSettings": "Аутентификация",
|
||||||
|
"aiProviderAuthSettingsDescription": "Настройте аутентификацию запросов этого поставщика к его URL-адресу",
|
||||||
|
"aiProviderBudgetSettings": "Бюджет",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Настройте, как этот поставщик ограничивает использование на основе расходов или лимитов токенов",
|
||||||
|
"aiBudgetAdd": "Добавить бюджет",
|
||||||
|
"aiBudgetEmpty": "Бюджеты еще не настроены. Нажмите «Добавить бюджет», чтобы установить лимит расходов или токенов.",
|
||||||
|
"aiBudgetUnit": "Тип расходов",
|
||||||
|
"aiBudgetPeriod": "Период сброса",
|
||||||
|
"aiBudgetAmount": "Максимальная трата",
|
||||||
|
"aiBudgetAmountPlaceholder": "Максимальная трата",
|
||||||
|
"aiBudgetPeriodHourly": "Почасово",
|
||||||
|
"aiBudgetPeriodDaily": "Ежедневно",
|
||||||
|
"aiBudgetPeriodWeekly": "Еженедельно",
|
||||||
|
"aiBudgetPeriodMonthly": "Ежемесячно",
|
||||||
|
"aiBudgetPeriodYearly": "Ежегодно",
|
||||||
|
"aiBudgetPeriodLifetime": "На протяжении жизни",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Токены",
|
||||||
|
"aiBudgetConflictError": "Бюджет для этого периода сброса и типа расходов уже существует",
|
||||||
|
"aiBudgetInvalidAmountError": "Введите максимальную трату, большую 0",
|
||||||
|
"aiBudgetUpdated": "Бюджеты обновлены",
|
||||||
|
"aiBudgetErrorSave": "Не удалось обновить бюджеты",
|
||||||
|
"aiProviderType": "Тип поставщика",
|
||||||
|
"aiProviderTypeSearch": "Поиск поставщиков...",
|
||||||
|
"aiProviderTypeNotFound": "Тип поставщика не найден",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Шлюз Vercel AI",
|
||||||
|
"aiProviderTypeCustom": "Пользовательский",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "API Google Vertex AI",
|
||||||
|
"aiProviderTypeBedrockDescription": "API Amazon Bedrock Runtime",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "API Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "API OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Шлюз Vercel AI API",
|
||||||
|
"aiProviderTypeCustomDescription": "Используйте свой собственный конечный узел или маршрутизируйте через целевые сайты",
|
||||||
|
"aiProviderUpstreamUrl": "Исходный URL",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Базовый URL для API провайдера",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Оставьте пустым, чтобы использовать исходный URL по умолчанию для этого провайдера",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Эффективный исходный URL",
|
||||||
|
"aiProviderApiKey": "API ключ",
|
||||||
|
"aiProviderApiKeyDescription": "API ключ, используемый для аутентификации запросов к этому провайдеру",
|
||||||
|
"aiProviderCustomHeadersDescription": "Заголовки, отправляемые в каждом запросе к этому провайдеру. Разделены новыми строками: Имя-заголовка: значение",
|
||||||
|
"aiProviderApiKeyLastChars": "API ключ",
|
||||||
|
"aiProviderAuthType": "Тип аутентификации",
|
||||||
|
"aiProviderAuthTypeSearch": "Поиск типов аутентификации...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Тип аутентификации не найден",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Authorization: Bearer key. Используется OpenAI и большинством провайдеров",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "Заголовок x-api-key. Используется компанией Anthropic",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "Заголовок x-goog-api-key. Используется компанией Google Gemini",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Authorization: Splunk key. Используется Splunk HTTP Event Collector",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization: Bearer key. Используется Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeNone": "Без аутентификации",
|
||||||
|
"aiProviderAuthTypePassthrough": "Passthrough",
|
||||||
|
"aiProviderAuthTypeDescription": "Как исходный API аутентифицирует запросы",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Перенаправьте заголовки API ключей вызывающего на исходный сервер",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Не отправлять заголовки аутентификации на исходный сервер",
|
||||||
|
"aiProviderRoutingMode": "Режим маршрутизации",
|
||||||
|
"aiProviderRoutingModeDescription": "Отправка трафика на исходный URL или на HTTP-цели на ваших сайтах",
|
||||||
|
"aiProviderRoutingModeUrl": "Исходный URL",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Вызов общественного или частного базового URL-адреса API",
|
||||||
|
"aiProviderRoutingModeTarget": "Цели сайта",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Маршрутизация через цели на ваших сайтах",
|
||||||
|
"aiProviderRoutingModeTargetNote": "После создания этого провайдера настройте целевые сайты на вкладке Сетевые настройки.",
|
||||||
|
"aiProviderTargetNoOne": "У этого провайдера нет целей. Добавьте цель для маршрутизации запросов через ваши сайты.",
|
||||||
|
"aiProviderSkipTlsVerification": "Пропустить проверку TLS",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Отключить проверку сертификата TLS для исходного соединения",
|
||||||
|
"aiProviderBudget": "Бюджет",
|
||||||
|
"aiProviderBudgetDescription": "Дополнительные расходы или бюджет токенов для этого провайдера",
|
||||||
|
"aiProviderBudgetAmount": "Сумма бюджета",
|
||||||
|
"aiProviderBudgetUnit": "Единица бюджета",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Токены",
|
||||||
|
"aiProviderEnabled": "Включено",
|
||||||
|
"aiProviderEnabledDescription": "Полностью отключите этого провайдера на всех ресурсах",
|
||||||
|
"aiProviderErrorCreate": "Не удалось создать провайдера AI",
|
||||||
|
"aiProviderErrorUpdate": "Не удалось обновить провайдера AI",
|
||||||
|
"aiProviderErrorDelete": "Не удалось удалить провайдера AI",
|
||||||
|
"aiProviderErrorLoad": "Не удалось загрузить провайдера AI",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Введите действительный исходный URL",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Исходный URL обязателен для этого провайдера",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Тип аутентификации обязателен",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API ключ обязателен",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Маршрутизация целевых сайтов доступна только для пользовательских провайдеров",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "Выберите хотя бы одну возможность API",
|
||||||
|
"aiProviderCapabilities": "Возможности API",
|
||||||
|
"aiProviderCapabilitiesDescription": "Выберите, какие форматы API этот провайдер может обработать. Известные провайдеры начинают с рекомендованных по умолчанию.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Выберите, какие форматы API может обрабатывать этот пользовательский провайдер",
|
||||||
|
"aiProviderCapabilitiesSelect": "Выберите возможности",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Возможности не найдены",
|
||||||
|
"aiProviderCapabilitiesSearch": "Поиск возможностей...",
|
||||||
|
"aiCapabilityOpenaiChat": "Чат завершений OpenAI",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "Поддерживает /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "Ответы OpenAI",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "Поддерживает /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Сообщения Anthropic",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "Поддерживает /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini Создание контента",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Поддерживает прямой API Gemini",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Вызов модели Bedrock",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Поддерживает Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex Создание контента",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Поддерживает формат Vertex AI Gemini",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Сырой прогноз Vertex",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Поддерживает Vertex AI rawPredict для моделей Anthropic",
|
||||||
|
"aiCapabilityBedrockConverse": "Общение Bedrock",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Поддерживает API общения Amazon Bedrock",
|
||||||
|
"aiProviderCreated": "Провайдер AI создан",
|
||||||
|
"aiProviderUpdated": "Провайдер AI обновлен",
|
||||||
|
"aiProviderDeleted": "Провайдер AI удален",
|
||||||
|
"aiProviderDelete": "Удалить провайдера",
|
||||||
|
"aiProviderDeleteConfirm": "Удалить провайдера",
|
||||||
|
"aiProviderQuestionRemove": "Вы уверены, что хотите удалить этого провайдера AI?",
|
||||||
|
"aiProviderMessageRemove": "Это приведет к окончательному удалению провайдера и его моделей и целей. Это действие нельзя отменить.",
|
||||||
|
"aiProviderErrorNoUpdate": "Провайдер AI недоступен для обновления",
|
||||||
|
"aiProviderModels": "Модели",
|
||||||
|
"aiProviderModelsDescription": "Определите списки разрешений и блокировок для этого провайдера. Запросы должны соответствовать записи в списке разрешений и не должны соответствовать записи в списке блокировок.",
|
||||||
|
"aiProviderCreateModelsDescription": "Выберите, какие модели сможет обслуживать этот провайдер. Пустой список разрешений запрещает весь трафик. Вы можете добавлять или изменять модели позже.",
|
||||||
|
"aiProviderModelsPlaceholder": "Поиск моделей или введите пользовательский ключ",
|
||||||
|
"aiProviderModelsAllow": "Список разрешений",
|
||||||
|
"aiProviderModelsAllowDescription": "Модели, которые могут быть использованы через этого провайдера. Пустой список означает запретить все.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Введите ключ модели",
|
||||||
|
"aiProviderModelsAllowEmpty": "Пока модели не добавлены.",
|
||||||
|
"aiProviderModelsBlock": "Список блокировок",
|
||||||
|
"aiProviderModelsBlockDescription": "Модели для отклонения, даже если они соответствуют записи в списке разрешений.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Введите ключ модели",
|
||||||
|
"aiProviderModelsBlockEmpty": "Модели пока не добавлены.",
|
||||||
|
"aiProviderModelsAdd": "Добавить модели",
|
||||||
|
"aiProviderModelsClearAll": "Очистить все",
|
||||||
|
"aiProviderModelsAddCustom": "Добавить \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "Нажмите Enter, чтобы добавить этот пользовательский ключ модели.",
|
||||||
|
"aiProviderModelsAddBulk": "Добавить {count} пользовательских ключей",
|
||||||
|
"aiProviderModelsAddBulkHint": "Нажмите Enter, чтобы добавить {count} пользовательских ключей.",
|
||||||
|
"aiProviderModelsAddOne": "Добавить {key} сейчас",
|
||||||
|
"aiProviderModelsAddSelected": "Добавить выбранное",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} выбрано",
|
||||||
|
"aiProviderModelsSelectAll": "Выбрать все",
|
||||||
|
"aiProviderModelsClearSelected": "Очистить",
|
||||||
|
"aiProviderModelsBulkHint": "Выберите известные модели или введите пользовательский ключ.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Нет подходящих моделей каталога.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Известные модели",
|
||||||
|
"aiProviderModelsAllLabel": "Все модели",
|
||||||
|
"aiProviderModelsAllPatternHint": "Подстановочный знак: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Разрешить все модели",
|
||||||
|
"aiProviderModelsAddAllBlock": "Блокировать все модели",
|
||||||
|
"aiProviderModelsAddAllDescription": "Использует подстановочный знак *, чтобы каждый ключ модели соответствовал.",
|
||||||
|
"aiProviderModelsViewMore": "Просмотреть больше ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Просмотреть меньше",
|
||||||
|
"aiProviderModelsRemove": "Удалить модель",
|
||||||
|
"aiProviderModelsEditHint": "Нажмите, чтобы изменить параметры модели",
|
||||||
|
"aiProviderModelsSourceCatalog": "Известная модель каталога",
|
||||||
|
"aiProviderModelsSourceCustom": "Пользовательский ключ модели",
|
||||||
|
"aiProviderModelsSourcePattern": "Подстановочный шаблон",
|
||||||
|
"aiProviderModelsSourceAll": "Соответствует каждому ключу модели",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Бюджет настроен",
|
||||||
|
"aiProviderModelsEditTitle": "Изменить модель",
|
||||||
|
"aiProviderModelsEditDescription": "Обновите ключ модели или настройте его бюджет.",
|
||||||
|
"aiProviderModelsBudgetTab": "Бюджет",
|
||||||
|
"aiProviderModelsKeyLabel": "Ключ модели",
|
||||||
|
"aiProviderModelsKeyRequired": "Введите ключ модели",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Этот ключ модели уже находится в списке",
|
||||||
|
"aiProviderModelsOverlapError": "Эти шаблоны не могут находиться в обоих списках: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Модели обновлены",
|
||||||
|
"aiProviderModelsErrorUpdate": "Не удалось обновить модели",
|
||||||
|
"aiResourceProviders": "Провайдеры",
|
||||||
|
"aiResourceProvidersDescription": "Выберите, какие провайдеры AI может использовать этот шлюз AI",
|
||||||
|
"aiResourceProvidersHelp": "Присоединяйте провайдеров и выбирайте наследовать (использовать списки каждого провайдера) или выберите (выберите список разрешений для этого ресурса). Шаблоны разрешений, конфликтующие по присоединенным провайдерам, не допускаются.",
|
||||||
|
"aiResourceProvidersSelect": "Выберите провайдеров",
|
||||||
|
"aiResourceProvidersEmpty": "Провайдеры AI не найдены",
|
||||||
|
"aiResourceProvidersNoneAttached": "Пока провайдеры не прикреплены.",
|
||||||
|
"aiResourceProvidersAdd": "Добавить провайдера",
|
||||||
|
"aiResourceProvidersRemove": "Удалить провайдера",
|
||||||
|
"aiResourceProviderToggleEnabled": "Включить или отключить этот провайдер для ресурса",
|
||||||
|
"aiResourceProviderDisabled": "Отключено",
|
||||||
|
"aiResourceProvidersUpdated": "Провайдеры обновлены",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Не удалось обновить провайдеров",
|
||||||
|
"aiResourceProviderEditDescription": "Выберите, как модели этого провайдера будут выставлены на этом ресурсе.",
|
||||||
|
"viewProviderSettings": "Просмотреть настройки провайдера",
|
||||||
|
"aiResourceProviderMode": "Режим доступа",
|
||||||
|
"aiResourceProviderModeInherit": "Наследовать",
|
||||||
|
"aiResourceProviderModeSelect": "Выбрать",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Выбрать · {count} моделей",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Используйте разрешенные и блокирующие списки этого провайдера, как настроено на провайдере.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Выберите подмножество моделей из разрешенного списка этого провайдера для этого ресурса.",
|
||||||
|
"aiResourceProviderAllowModels": "Список разрешений",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Выберите модели",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Поиск моделей...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Модели не найдены",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Можно выбрать только модели из разрешенного списка этого провайдера.",
|
||||||
|
"aiResourceAliasRequired": "Для шлюзов AI требуется псевдоним",
|
||||||
|
"aiResourceDomainConfiguration": "Конфигурация домена",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Выберите домен, который клиенты будут использовать для доступа к этому шлюзу AI.",
|
||||||
|
"aiUsageAnalyticsTitle": "Аналитика использования AI",
|
||||||
|
"aiUsageAnalyticsDescription": "Анализируйте стоимость шлюза AI, использование токена и активность по провайдерам, ресурсам, ролям и пользователям",
|
||||||
|
"aiUsageTabOverview": "Обзор",
|
||||||
|
"aiUsageTabProviders": "Провайдеры",
|
||||||
|
"aiUsageTabResources": "Ресурсы",
|
||||||
|
"aiUsageFilterProvider": "Провайдер",
|
||||||
|
"aiUsageFilterModel": "Модель",
|
||||||
|
"aiUsageFilterResource": "Ресурс",
|
||||||
|
"aiUsageFilterRole": "Роль",
|
||||||
|
"aiUsageFilterUser": "Пользователь",
|
||||||
|
"aiUsageFilterAllProviders": "Все провайдеры",
|
||||||
|
"aiUsageFilterAllModels": "Все модели",
|
||||||
|
"aiUsageFilterAllResources": "Все ресурсы",
|
||||||
|
"aiUsageFilterAllRoles": "Все роли",
|
||||||
|
"aiUsageFilterAllUsers": "Все пользователи",
|
||||||
|
"aiUsageFilterSearch": "Поиск...",
|
||||||
|
"aiUsageFilterNotFound": "Опции не найдены",
|
||||||
|
"aiUsageResetFilters": "Сбросить фильтры",
|
||||||
|
"aiUsageRefresh": "Обновить",
|
||||||
|
"aiUsageTokenTypePrompt": "Подсказка",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Чтение кэша",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Запись в кэш",
|
||||||
|
"aiUsageTokenTypeCompletion": "Завершение",
|
||||||
|
"aiUsageTokenTypeReasoning": "Размышление",
|
||||||
|
"aiUsageRequests": "Запросы",
|
||||||
|
"aiUsageCost": "Стоимость",
|
||||||
|
"aiUsageTokens": "Токены",
|
||||||
|
"aiUsageOther": "Другое",
|
||||||
|
"aiUsageTotalRequests": "Всего запросов",
|
||||||
|
"aiUsageTotalTokens": "Всего токенов",
|
||||||
|
"aiUsageTotalCost": "Общая стоимость",
|
||||||
|
"aiUsageEstimated": "Оценочная",
|
||||||
|
"aiUsageRequestVolume": "Объем запросов",
|
||||||
|
"aiUsageTokenUsage": "Использование токенов",
|
||||||
|
"aiUsageModelCost": "Стоимость модели",
|
||||||
|
"aiUsageModelTokens": "Токены модели",
|
||||||
|
"aiUsageTopModels": "Лучшие модели",
|
||||||
|
"aiUsageTopProviders": "Лучшие провайдеры",
|
||||||
|
"aiUsageProviderCost": "Стоимость провайдера",
|
||||||
|
"aiUsageProviderTokenUsage": "Использование токенов провайдера",
|
||||||
|
"aiUsageTopResources": "Лучшие ресурсы",
|
||||||
|
"aiUsageResourceCost": "Стоимость ресурса",
|
||||||
|
"aiUsageResourceTokenUsage": "Использование токенов ресурса",
|
||||||
|
"aiUsageResourceTypePublic": "Общественный ресурс",
|
||||||
|
"aiUsageResourceTypeSite": "Частный ресурс",
|
||||||
|
"aiUsageNoResource": "Нет ресурса",
|
||||||
|
"aiUsageRolesTab": "Роли",
|
||||||
|
"aiUsageUsersTab": "Пользователи",
|
||||||
|
"aiUsageTopRoles": "Лучшие роли",
|
||||||
|
"aiUsageRoleCost": "Стоимость роли",
|
||||||
|
"aiUsageRoleTokenUsage": "Использование токенов роли",
|
||||||
|
"aiUsageTopUsers": "Лучшие пользователи",
|
||||||
|
"aiUsageUserCost": "Стоимость пользователя",
|
||||||
|
"aiUsageUserTokenUsage": "Использование токенов пользователя",
|
||||||
|
"aiUsageUnknownUser": "Неизвестный пользователь",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Виртуальные API ключи",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Виртуальный API ключ",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Все виртуальные API ключи",
|
||||||
|
"aiUsageTopVirtualApiKeys": "Лучшие виртуальные API ключи",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Стоимость виртуального API ключа",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Использование токенов виртуального API ключа",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Нет виртуального API ключа",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "Неименованный ключ",
|
||||||
|
"aiUsageLoading": "Загрузка...",
|
||||||
|
"aiUsageNoData": "Нет данных",
|
||||||
|
"resourceBudgetSettings": "Бюджет",
|
||||||
|
"resourceBudgetSettingsDescription": "Настройте, как этот шлюз AI ограничивает использование на основе затрат или лимитов токенов",
|
||||||
"sidebarApiKeys": "API ключи",
|
"sidebarApiKeys": "API ключи",
|
||||||
"sidebarProvisioning": "Подготовка",
|
"sidebarProvisioning": "Подготовка",
|
||||||
"sidebarSettings": "Настройки",
|
"sidebarSettings": "Настройки",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Правило оповещений сохранено",
|
"alertingRuleSaved": "Правило оповещений сохранено",
|
||||||
"alertingRuleSavedCreatedDescription": "Ваше новое правило оповещений создано. Вы можете продолжать редактировать его на этой странице.",
|
"alertingRuleSavedCreatedDescription": "Ваше новое правило оповещений создано. Вы можете продолжать редактировать его на этой странице.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Ваши изменения в этом правиле оповещений были сохранены.",
|
"alertingRuleSavedUpdatedDescription": "Ваши изменения в этом правиле оповещений были сохранены.",
|
||||||
|
"alertingTestAlertSent": "Тестовое предупреждение отправлено",
|
||||||
|
"alertingTestAlertSentDescription": "Тестовое предупреждение было отправлено на действия, настроенные на этом правиле.",
|
||||||
"alertingEditRule": "Редактировать правило оповещений",
|
"alertingEditRule": "Редактировать правило оповещений",
|
||||||
"alertingCreateRule": "Создать правило оповещений",
|
"alertingCreateRule": "Создать правило оповещений",
|
||||||
"alertingRuleCredenzaDescription": "Выберите, что отслеживать, когда срабатывать и как уведомлять",
|
"alertingRuleCredenzaDescription": "Выберите, что отслеживать, когда срабатывать и как уведомлять",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Каждое правило объединяет, что отслеживать (сайт, проверка состояния или ресурс), когда срабатывать (например, оффлайн или нарушение), и как уведомлять вашу команду через email, вебхуки или интеграции. Используйте этот список для создания, включения и управления этими правилами.",
|
"alertingRulesBannerDescription": "Каждое правило объединяет, что отслеживать (сайт, проверка состояния или ресурс), когда срабатывать (например, оффлайн или нарушение), и как уведомлять вашу команду через email, вебхуки или интеграции. Используйте этот список для создания, включения и управления этими правилами.",
|
||||||
"alertingHealthChecksBannerTitle": "Мониторинг здоровья и ресурсов",
|
"alertingHealthChecksBannerTitle": "Мониторинг здоровья и ресурсов",
|
||||||
"alertingHealthChecksBannerDescription": "Проверки здоровья — это HTTP или TCP мониторы, которые вы определяете один раз. Затем вы можете использовать их в правилах оповещений, чтобы получать уведомления, когда цель становится здоровой или нездоровой. Проверки здоровья для ресурсов также появляются здесь.",
|
"alertingHealthChecksBannerDescription": "Проверки здоровья — это HTTP или TCP мониторы, которые вы определяете один раз. Затем вы можете использовать их в правилах оповещений, чтобы получать уведомления, когда цель становится здоровой или нездоровой. Проверки здоровья для ресурсов также появляются здесь.",
|
||||||
|
"alertingTestRule": "Правило тестового предупреждения",
|
||||||
|
"alertingAddActionHeading": "Добавить новое действие",
|
||||||
|
"alertingSelectActionType": "Выберите действие",
|
||||||
|
"alertingNoActionsTitle": "Нет настроенных действий",
|
||||||
|
"alertingNoActionsSaveDescription": "Добавьте хотя бы одно действие, чтобы это правило могло уведомить кого-то при его срабатывании.",
|
||||||
|
"alertingNoActionsTestDescription": "Добавьте хотя бы одно действие перед тестированием этого правила.",
|
||||||
"standaloneHcTableTitle": "Проверки здоровья",
|
"standaloneHcTableTitle": "Проверки здоровья",
|
||||||
"standaloneHcSearchPlaceholder": "Поиск проверок здоровья…",
|
"standaloneHcSearchPlaceholder": "Поиск проверок здоровья…",
|
||||||
"standaloneHcAddButton": "Создать проверку здоровья",
|
"standaloneHcAddButton": "Создать проверку здоровья",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Поддомен: {subdomain}",
|
"domainPickerSubdomain": "Поддомен: {subdomain}",
|
||||||
"domainPickerNamespace": "Пространство имен: {namespace}",
|
"domainPickerNamespace": "Пространство имен: {namespace}",
|
||||||
"domainPickerShowMore": "Показать еще",
|
"domainPickerShowMore": "Показать еще",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Нет доступных доменов",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "У вас еще не настроены домены. Создайте домен, чтобы продолжить.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Перейти к доменам",
|
||||||
"regionSelectorTitle": "Выберите регион",
|
"regionSelectorTitle": "Выберите регион",
|
||||||
"domainPickerRemoteExitNodeWarning": "Предоставленные домены не поддерживаются при подключении сайтов к удаленным узлам. Для доступа к ресурсам на удаленных узлах используйте пользовательский домен.",
|
"domainPickerRemoteExitNodeWarning": "Предоставленные домены не поддерживаются при подключении сайтов к удаленным узлам. Для доступа к ресурсам на удаленных узлах используйте пользовательский домен.",
|
||||||
"regionSelectorInfo": "Выбор региона помогает нам обеспечить лучшее качество обслуживания для вашего расположения. Вам необязательно находиться в том же регионе, что и ваш сервер.",
|
"regionSelectorInfo": "Выбор региона помогает нам обеспечить лучшее качество обслуживания для вашего расположения. Вам необязательно находиться в том же регионе, что и ваш сервер.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Подсеть",
|
"subnetPlaceholder": "Подсеть",
|
||||||
"addressDescription": "Внутренний адрес клиента. Должен находиться в подсети организации.",
|
"addressDescription": "Внутренний адрес клиента. Должен находиться в подсети организации.",
|
||||||
"selectSites": "Выберите сайты",
|
"selectSites": "Выберите сайты",
|
||||||
|
"selectResources": "Выберите ресурсы",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# ресурс} few {# ресурса} many {# ресурсов} other {# ресурсов}}",
|
||||||
"selectLabels": "Выберите метки",
|
"selectLabels": "Выберите метки",
|
||||||
"sitesDescription": "Клиент будет иметь подключение к выбранным сайтам",
|
"sitesDescription": "Клиент будет иметь подключение к выбранным сайтам",
|
||||||
"clientInstallOlm": "Установить Olm",
|
"clientInstallOlm": "Установить Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Время указано в секундах",
|
"timeIsInSeconds": "Время указано в секундах",
|
||||||
"requireDeviceApproval": "Требовать подтверждения устройства",
|
"requireDeviceApproval": "Требовать подтверждения устройства",
|
||||||
"requireDeviceApprovalDescription": "Пользователям с этой ролью нужны новые устройства, одобренные администратором, прежде чем они смогут подключаться и получать доступ к ресурсам.",
|
"requireDeviceApprovalDescription": "Пользователям с этой ролью нужны новые устройства, одобренные администратором, прежде чем они смогут подключаться и получать доступ к ресурсам.",
|
||||||
"sshSettings": "Настройки SSH",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI Шлюз",
|
||||||
"sshAccess": "Доступ по SSH",
|
"sshAccess": "Доступ по SSH",
|
||||||
"rdpSettings": "Настройки RDP",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "Настройки VNC",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH сервер",
|
"sshServer": "SSH сервер",
|
||||||
"rdpServer": "RDP сервер",
|
"rdpServer": "RDP сервер",
|
||||||
"vncServer": "VNC сервер",
|
"vncServer": "VNC сервер",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Публичный",
|
"resourcesTableProxyResources": "Публичный",
|
||||||
"resourcesTableClientResources": "Приватный",
|
"resourcesTableClientResources": "Приватный",
|
||||||
"resourcesTableNoProxyResourcesFound": "Проксированных ресурсов не найдено.",
|
"resourcesTableNoProxyResourcesFound": "Проксированных ресурсов не найдено.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Внутренних ресурсов не найдено.",
|
"resourcesTableNoInternalResourcesFound": "Частные ресурсы не найдены.",
|
||||||
"resourcesTableDestination": "Пункт назначения",
|
"resourcesTableDestination": "Пункт назначения",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "Псевдоним адреса",
|
"resourcesTableAliasAddress": "Псевдоним адреса",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "Отмена",
|
"editInternalResourceDialogCancel": "Отмена",
|
||||||
"editInternalResourceDialogSaveResource": "Сохранить ресурс",
|
"editInternalResourceDialogSaveResource": "Сохранить ресурс",
|
||||||
"editInternalResourceDialogSuccess": "Успешно",
|
"editInternalResourceDialogSuccess": "Успешно",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Внутренний ресурс успешно обновлен",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Частный ресурс успешно обновлен",
|
||||||
"editInternalResourceDialogError": "Ошибка",
|
"editInternalResourceDialogError": "Ошибка",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Не удалось обновить внутренний ресурс",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Не удалось обновить частный ресурс",
|
||||||
"editInternalResourceDialogNameRequired": "Имя обязательно",
|
"editInternalResourceDialogNameRequired": "Имя обязательно",
|
||||||
"editInternalResourceDialogNameMaxLength": "Имя не должно быть длиннее 255 символов",
|
"editInternalResourceDialogNameMaxLength": "Имя не должно быть длиннее 255 символов",
|
||||||
"editInternalResourceDialogProxyPortMin": "Порт прокси должен быть не менее 1",
|
"editInternalResourceDialogProxyPortMin": "Порт прокси должен быть не менее 1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "СИДР",
|
"editInternalResourceDialogModeCidr": "СИДР",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI Шлюз",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Схема",
|
"editInternalResourceDialogScheme": "Схема",
|
||||||
"editInternalResourceDialogEnableSsl": "Включить TLS",
|
"editInternalResourceDialogEnableSsl": "Включить TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "Дополнительный внутренний DNS псевдоним для этого ресурса.",
|
"editInternalResourceDialogAliasDescription": "Дополнительный внутренний DNS псевдоним для этого ресурса.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Нет доступных сайтов",
|
"createInternalResourceDialogNoSitesAvailable": "Нет доступных сайтов",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Вам необходимо иметь хотя бы один сайт Newt с настроенной подсетью для создания внутреннего ресурса.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Вам необходимо иметь хотя бы один сайт Newt с настроенной подсетью для создания частных ресурсов.",
|
||||||
"createInternalResourceDialogClose": "Закрыть",
|
"createInternalResourceDialogClose": "Закрыть",
|
||||||
"createInternalResourceDialogCreateClientResource": "Создать приватный ресурс",
|
"createInternalResourceDialogCreateClientResource": "Создать приватный ресурс",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Создать новый ресурс, который будет доступен только клиентам, подключенным к организации",
|
"createInternalResourceDialogCreateClientResourceDescription": "Создать новый ресурс, который будет доступен только клиентам, подключенным к организации",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "Разрешить ICMP Ping",
|
"privateResourceAllowIcmpPing": "Разрешить ICMP Ping",
|
||||||
"privateResourceNetworkAccess": "Сетевой доступ",
|
"privateResourceNetworkAccess": "Сетевой доступ",
|
||||||
"privateResourceNetworkAccessDescription": "Управляйте доступом к портам TCP/UDP и настройте разрешение ICMP ping для данного ресурса.",
|
"privateResourceNetworkAccessDescription": "Управляйте доступом к портам TCP/UDP и настройте разрешение ICMP ping для данного ресурса.",
|
||||||
"hostSettings": "Настройки хоста",
|
"hostSettings": "Хост",
|
||||||
"cidrSettings": "Настройки CIDR",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Свойства ресурса",
|
"createInternalResourceDialogResourceProperties": "Свойства ресурса",
|
||||||
"createInternalResourceDialogName": "Имя",
|
"createInternalResourceDialogName": "Имя",
|
||||||
"createInternalResourceDialogSite": "Сайт",
|
"createInternalResourceDialogSite": "Сайт",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "Отмена",
|
"createInternalResourceDialogCancel": "Отмена",
|
||||||
"createInternalResourceDialogCreateResource": "Создать ресурс",
|
"createInternalResourceDialogCreateResource": "Создать ресурс",
|
||||||
"createInternalResourceDialogSuccess": "Успешно",
|
"createInternalResourceDialogSuccess": "Успешно",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Внутренний ресурс успешно создан",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Частный ресурс успешно создан",
|
||||||
"createInternalResourceDialogError": "Ошибка",
|
"createInternalResourceDialogError": "Ошибка",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Не удалось создать внутренний ресурс",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Не удалось создать частный ресурс",
|
||||||
"createInternalResourceDialogNameRequired": "Имя обязательно",
|
"createInternalResourceDialogNameRequired": "Имя обязательно",
|
||||||
"createInternalResourceDialogNameMaxLength": "Имя должно содержать менее 255 символов",
|
"createInternalResourceDialogNameMaxLength": "Имя должно содержать менее 255 символов",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Пожалуйста, выберите сайт",
|
"createInternalResourceDialogPleaseSelectSite": "Пожалуйста, выберите сайт",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI Шлюз",
|
||||||
"scheme": "Схема",
|
"scheme": "Схема",
|
||||||
"createInternalResourceDialogScheme": "Схема",
|
"createInternalResourceDialogScheme": "Схема",
|
||||||
"createInternalResourceDialogEnableSsl": "Включить TLS",
|
"createInternalResourceDialogEnableSsl": "Включить TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Допустимый пароль",
|
"validPassword": "Допустимый пароль",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "Действительный виртуальный API ключ",
|
||||||
"view": "Просмотр",
|
"view": "Просмотр",
|
||||||
"configManaged": "Конфигурация управляется",
|
"configManaged": "Конфигурация управляется",
|
||||||
"connectedClient": "Подключенный клиент",
|
"connectedClient": "Подключенный клиент",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Сохранение журнала",
|
"logRetention": "Сохранение журнала",
|
||||||
"logRetentionDescription": "Управление сохранением различных типов журналов для этой организации или отключение их",
|
"logRetentionDescription": "Управление сохранением различных типов журналов для этой организации или отключение их",
|
||||||
"requestLogsDescription": "Просмотреть подробные журналы запроса ресурсов в этой организации",
|
"requestLogsDescription": "Просмотреть подробные журналы запроса ресурсов в этой организации",
|
||||||
|
"aiSessionLogs": "AI Логи сессии шлюза",
|
||||||
|
"aiSessionLogsDescription": "Просмотр транскриптов запросов и ответов для шлюзов AI в этой организации",
|
||||||
|
"sidebarLogsAi": "Логи сессий",
|
||||||
|
"commandLogsAi": "Логи сессий",
|
||||||
|
"sidebarLogsAiUsage": "Аналитика использования",
|
||||||
|
"commandLogsAiUsage": "Аналитика использования",
|
||||||
|
"provider": "Провайдер",
|
||||||
|
"capability": "Возможность",
|
||||||
|
"model": "Модель",
|
||||||
|
"virtualApiKey": "Виртуальный API ключ",
|
||||||
|
"noVirtualApiKey": "Нет виртуального API ключа",
|
||||||
|
"stream": "Поток",
|
||||||
|
"streaming": "Потоковая передача",
|
||||||
|
"nonStreaming": "Не потоковая",
|
||||||
|
"statusCode": "Код статуса",
|
||||||
|
"aiSessionId": "ID сессии",
|
||||||
|
"aiSessionRequest": "Запрос",
|
||||||
|
"aiSessionResponse": "Ответ",
|
||||||
|
"aiSessionNoData": "Данные не захвачены",
|
||||||
|
"aiSessionCouldNotParse": "(сырое, не удалось разобрать транскрипт)",
|
||||||
|
"aiSessionLogTruncated": "Эта сессия была усечена перед хранением и может быть неполной.",
|
||||||
|
"aiSessionViewRaw": "Просмотреть сырой JSON",
|
||||||
|
"aiSessionViewChat": "Просмотреть чат",
|
||||||
|
"cost": "Стоимость",
|
||||||
|
"estimated": "Оценочная",
|
||||||
|
"tokenUsage": "Использование токенов",
|
||||||
|
"promptTokens": "Токены подсказок",
|
||||||
|
"cacheReadTokens": "Токены чтения кэша",
|
||||||
|
"cacheWriteTokens": "Токены записи в кэш",
|
||||||
|
"completionTokens": "Токены завершения",
|
||||||
|
"reasoningTokens": "Токены размышления",
|
||||||
|
"totalTokens": "Всего токенов",
|
||||||
"requestAnalyticsDescription": "Просмотреть подробную аналитику запроса для ресурсов в этой организации",
|
"requestAnalyticsDescription": "Просмотреть подробную аналитику запроса для ресурсов в этой организации",
|
||||||
"logRetentionRequestLabel": "Сохранение HTTP Запросов Лога",
|
"logRetentionRequestLabel": "Сохранение HTTP Запросов Лога",
|
||||||
"logRetentionRequestDescription": "Как долго сохранять журналы запросов",
|
"logRetentionRequestDescription": "Как долго сохранять журналы запросов",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Как долго хранить журналы действий",
|
"logRetentionActionDescription": "Как долго хранить журналы действий",
|
||||||
"logRetentionConnectionLabel": "Сохранение журнала подключений",
|
"logRetentionConnectionLabel": "Сохранение журнала подключений",
|
||||||
"logRetentionConnectionDescription": "Как долго хранить журналы подключений",
|
"logRetentionConnectionDescription": "Как долго хранить журналы подключений",
|
||||||
|
"logRetentionAISessionsLabel": "Сохранение логов сессий AI шлюза",
|
||||||
|
"logRetentionAISessionsDescription": "Как долго сохранять логи сессий запросов/ответов шлюза AI",
|
||||||
"logRetentionDisabled": "Отключено",
|
"logRetentionDisabled": "Отключено",
|
||||||
"logRetention3Days": "3 дня",
|
"logRetention3Days": "3 дня",
|
||||||
"logRetention7Days": "7 дней",
|
"logRetention7Days": "7 дней",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Адрес источника",
|
"sourceAddress": "Адрес источника",
|
||||||
"destinationAddress": "Адрес назначения",
|
"destinationAddress": "Адрес назначения",
|
||||||
"duration": "Продолжительность",
|
"duration": "Продолжительность",
|
||||||
"licenseRequiredToUse": "Требуется лицензия на <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> или <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> для использования этой функции. <bookADemoLink>Забронируйте демонстрацию или пробный POC</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Лицензия Enterprise Edition</enterpriseEditionLink> требуется. <bookADemoLink>Записаться на демо или пробную версию</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> требуется для использования этой функции. Эта функция также доступна в <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Забронируйте демонстрацию или пробный POC</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Лицензия Enterprise Edition</enterpriseEditionLink> требуется. <bookADemoLink>Записаться на демо или пробную версию</bookADemoLink>",
|
||||||
"certResolver": "Резольвер сертификата",
|
"certResolver": "Резольвер сертификата",
|
||||||
"certResolverDescription": "Выберите резолвер сертификата, который будет использоваться для этого ресурса.",
|
"certResolverDescription": "Выберите резолвер сертификата, который будет использоваться для этого ресурса.",
|
||||||
"selectCertResolver": "Выберите резолвер сертификата",
|
"selectCertResolver": "Выберите резолвер сертификата",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Выбор нескольких сайтов позволяет обеспечить отказоустойчивую маршрутизацию и фейловер для высокой доступности.",
|
"internalResourceFormMultiSiteRoutingHelp": "Выбор нескольких сайтов позволяет обеспечить отказоустойчивую маршрутизацию и фейловер для высокой доступности.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Узнать больше",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Узнать больше",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Ограничьте доступ к определенным TCP/UDP-портам или разрешите/заблокируйте все порты.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Ограничьте доступ к определенным TCP/UDP-портам или разрешите/заблокируйте все порты.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "Конфигурация HTTP",
|
"createInternalResourceDialogHttpConfiguration": "Конфигурация домена",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "Выберите домен, который клиенты будут использовать для доступа к этому ресурсу через HTTP или HTTPS.",
|
"createInternalResourceDialogHttpConfigurationDescription": "Выберите домен, который клиенты будут использовать для доступа к этому ресурсу через HTTP или HTTPS.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "Конфигурация HTTP",
|
"editInternalResourceDialogHttpConfiguration": "Конфигурация домена",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "Выберите домен, который клиенты будут использовать для доступа к этому ресурсу через HTTP или HTTPS.",
|
"editInternalResourceDialogHttpConfigurationDescription": "Выберите домен, который клиенты будут использовать для доступа к этому ресурсу через HTTP или HTTPS.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Без меток",
|
"resourceLauncherUnlabeled": "Без меток",
|
||||||
|
"resourceLauncherAiGateway": "AI Шлюз",
|
||||||
"resourceLauncherNoSite": "Без сайта",
|
"resourceLauncherNoSite": "Без сайта",
|
||||||
|
"resourceLauncherAvailableModels": "Доступные модели",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Модели, которые вы можете использовать с этим шлюзом AI.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Нет доступных моделей для этого ресурса.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Не удалось загрузить доступные модели.",
|
||||||
|
"resourceLauncherApiKeys": "API ключи",
|
||||||
|
"resourceLauncherApiKeysDescription": "Используйте свой идентификационный ключ или атрибутивный ключ для аутентификации с этим ресурсом.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Идентификационный ключ",
|
||||||
|
"resourceLauncherApiKeysManual": "Атрибутные ключи",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Нет доступных API ключей для этого ресурса.",
|
||||||
|
"resourceLauncherApiKeysError": "Не удалось загрузить API ключи.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Нет ресурсов в данной группе",
|
"resourceLauncherNoResourcesInGroup": "Нет ресурсов в данной группе",
|
||||||
"resourceLauncherEmptyStateTitle": "Нет доступных ресурсов",
|
"resourceLauncherEmptyStateTitle": "Нет доступных ресурсов",
|
||||||
"resourceLauncherEmptyStateDescription": "У вас пока нет доступа ни к одному ресурсу. Обратитесь к администратору, чтобы запросить доступ.",
|
"resourceLauncherEmptyStateDescription": "У вас пока нет доступа ни к одному ресурсу. Обратитесь к администратору, чтобы запросить доступ.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Не удалось удалить вид. Пожалуйста, попробуйте еще раз.",
|
"resourceLauncherViewDeleteFailedDescription": "Не удалось удалить вид. Пожалуйста, попробуйте еще раз.",
|
||||||
"memberPortalPrevious": "Предыдущий",
|
"memberPortalPrevious": "Предыдущий",
|
||||||
"memberPortalNext": "Следующий",
|
"memberPortalNext": "Следующий",
|
||||||
"httpSettings": "Настройки HTTP",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "Настройки TCP",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "Настройки UDP",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Установление защищенного соединения…",
|
"sshConnectingDescription": "Установление защищенного соединения…",
|
||||||
"sshConnecting": "Подключение…",
|
"sshConnecting": "Подключение…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Ошибка загрузки",
|
"rdpUploadFailed": "Ошибка загрузки",
|
||||||
"rdpUnicodeKeyboardMode": "Режим клавиатуры Unicode",
|
"rdpUnicodeKeyboardMode": "Режим клавиатуры Unicode",
|
||||||
"sessionToolbarShow": "Показать панель инструментов",
|
"sessionToolbarShow": "Показать панель инструментов",
|
||||||
"sessionToolbarHide": "Скрыть панель инструментов"
|
"sessionToolbarHide": "Скрыть панель инструментов",
|
||||||
|
"actionUpdateSiteApprovals": "Обновить утверждения сайта"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "Lütfen doğru kullanıcı olarak oturum açtığınızdan emin olun.",
|
"inviteLoginUser": "Lütfen doğru kullanıcı olarak oturum açtığınızdan emin olun.",
|
||||||
"inviteErrorNoUser": "Üzgünüz, ancak erişmeye çalıştığınız davet, var olan bir kullanıcı için değil gibi görünüyor.",
|
"inviteErrorNoUser": "Üzgünüz, ancak erişmeye çalıştığınız davet, var olan bir kullanıcı için değil gibi görünüyor.",
|
||||||
"inviteCreateUser": "Öncelikle bir hesap oluşturun.",
|
"inviteCreateUser": "Öncelikle bir hesap oluşturun.",
|
||||||
|
"inviteErrorOidcNotAllowed": "Davetler yalnızca dahili hesaplar tarafından kabul edilebilir. Oturumunuzu kapatın ve bu e-postayla parolanızla giriş yapın.",
|
||||||
|
"inviteLoginInternalOnly": "Davet, parolası olan bir dahili hesap gerektirir. Hesap oluşturun veya parolanızla giriş yapın.",
|
||||||
"goHome": "Ana Sayfaya Dön",
|
"goHome": "Ana Sayfaya Dön",
|
||||||
"inviteLogInOtherUser": "Başka bir kullanıcı olarak giriş yapın",
|
"inviteLogInOtherUser": "Başka bir kullanıcı olarak giriş yapın",
|
||||||
"createAnAccount": "Bir Hesap Oluşturun",
|
"createAnAccount": "Bir Hesap Oluşturun",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "Paylaşılabilir Bağlantıyı Silmeyi Onayla",
|
"shareDeleteConfirm": "Paylaşılabilir Bağlantıyı Silmeyi Onayla",
|
||||||
"shareQuestionRemove": "Bu paylaşım bağlantısını silmek istediğinizden emin misiniz?",
|
"shareQuestionRemove": "Bu paylaşım bağlantısını silmek istediğinizden emin misiniz?",
|
||||||
"shareMessageRemove": "Silindikten sonra, bağlantı artık çalışmayacak ve kullanan herkes kaynağa erişimini kaybedecek.",
|
"shareMessageRemove": "Silindikten sonra, bağlantı artık çalışmayacak ve kullanan herkes kaynağa erişimini kaybedecek.",
|
||||||
"shareTokenDescription": "Erişim jetonunuz iki şekilde iletilebilir: sorgu parametresi olarak veya istek başlıklarında. Kimlik doğrulanmış erişim için her istekten müşteri tarafından iletilmelidir.",
|
"shareTokenDescription": "Erişim belirteci bir sorgu parametresi olarak veya istek başlıkları içinden gönderilebilir. Varsayılan olarak her istekte gönderilmelidir. Oturum kalıcılığı etkinse, ilk istek oturum çereziyle değiştirilir.",
|
||||||
"accessToken": "Erişim Jetonu",
|
"accessToken": "Erişim Jetonu",
|
||||||
"usageExamples": "Kullanım Örnekleri",
|
"usageExamples": "Kullanım Örnekleri",
|
||||||
"tokenId": "Jeton ID",
|
"tokenId": "Jeton ID",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "Başlık (isteğe bağlı)",
|
"shareTitleOptional": "Başlık (isteğe bağlı)",
|
||||||
"sharePathOptional": "Yol (isteğe bağlı)",
|
"sharePathOptional": "Yol (isteğe bağlı)",
|
||||||
"sharePathDescription": "Bağlantıdan sonra kullanıcıları bu yola yönlendirecek bağlantıyı tanımlayın.",
|
"sharePathDescription": "Bağlantıdan sonra kullanıcıları bu yola yönlendirecek bağlantıyı tanımlayın.",
|
||||||
|
"shareAssociateUserOptional": "Kullanıcıyla İlişkilendir (isteğe bağlı)",
|
||||||
|
"shareAssociateUserDescription": "Ayarladığında, bu bağlantıyı kullanan istekler erişim günlüklerinde ve kimlik başlıklarında kullanıcıya atanır. Kullanıcı kuruluşu terk ederse bağlantı kaldırılır.",
|
||||||
|
"userSelect": "Kullanıcı seçin",
|
||||||
|
"usersNotFound": "Kullanıcı bulunamadı",
|
||||||
"expireIn": "Süresi Dolacak",
|
"expireIn": "Süresi Dolacak",
|
||||||
"neverExpire": "Hiçbir Zaman Sona Ermez",
|
"neverExpire": "Hiçbir Zaman Sona Ermez",
|
||||||
|
"sharePersistSession": "İlk kullanım sonrası oturumu kalıcı yap",
|
||||||
|
"sharePersistSessionDescription": "Etkinleştirildiğinde, bu belirteçle yapılan ilk istek, sorgu parametresi veya başlık üzerinden, bir oturum çerezi ayarlayarak sonraki isteklerde belirteç gerektirmeyecek. Her istek için belirteç göndermesi gereken API müşterileri için bırakın.",
|
||||||
"shareExpireDescription": "Son kullanma süresi, bağlantının kullanılabilir ve kaynağa erişim sağlayacak süresidir. Bu süreden sonra bağlantı çalışmayı durduracak ve bu bağlantıyı kullanan kullanıcılar kaynağa erişimini kaybedecektir.",
|
"shareExpireDescription": "Son kullanma süresi, bağlantının kullanılabilir ve kaynağa erişim sağlayacak süresidir. Bu süreden sonra bağlantı çalışmayı durduracak ve bu bağlantıyı kullanan kullanıcılar kaynağa erişimini kaybedecektir.",
|
||||||
"shareSeeOnce": "Bu bağlantıyı yalnızca bir kez görebileceksiniz. Kopyaladığınızdan emin olun.",
|
"shareSeeOnce": "Bu bağlantıyı yalnızca bir kez görebileceksiniz. Kopyaladığınızdan emin olun.",
|
||||||
"shareAccessHint": "Bu bağlantıya sahip olan herkes kaynağa erişebilir. Dikkatle paylaşın.",
|
"shareAccessHint": "Bu bağlantıya sahip olan herkes kaynağa erişebilir. Dikkatle paylaşın.",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "Ülke bulunamadı.",
|
"noCountryFound": "Ülke bulunamadı.",
|
||||||
"siteSelectionDescription": "Bu site hedefe bağlantı sağlayacaktır.",
|
"siteSelectionDescription": "Bu site hedefe bağlantı sağlayacaktır.",
|
||||||
"resourceType": "Kaynak Türü",
|
"resourceType": "Kaynak Türü",
|
||||||
"resourceTypeDescription": "Bu, kaynak protokolünü ve tarayıcıda nasıl görüntüleneceğini kontrol eder. Bu daha sonra değiştirilemez.",
|
"resourceTypeDescription": "Bu, kaynak protokolünü kontrol eder ve daha sonra değiştirilemez.",
|
||||||
|
"resourceTypeSearch": "Kaynak türlerini ara...",
|
||||||
|
"resourceTypeNotFound": "Hiçbir kaynak türü bulunamadı",
|
||||||
|
"resourceTypeHttpDescription": "Bir alan adı kullanarak HTTPS üzerinden web trafiğini proxy yapın",
|
||||||
|
"resourceTypeInferenceDescription": "Bağlı sağlayıcılar üzerinden AI isteklerini yönlendirin",
|
||||||
|
"resourceTypeSshDescription": "Tarayıcıdan bir SSH sunucusuna erişim",
|
||||||
|
"resourceTypeRdpDescription": "Tarayıcıdan bir uzaktan masaüstüne erişim",
|
||||||
|
"resourceTypeVncDescription": "Tarayıcıdan bir VNC masaüstüne erişim",
|
||||||
|
"resourceTypeTcpDescription": "Bir bağlantı noktası numarası kullanarak ham TCP trafiğini proxy yapın",
|
||||||
|
"resourceTypeUdpDescription": "Bir bağlantı noktası numarası kullanarak ham UDP trafiğini proxy yapın",
|
||||||
|
"privateResourceTypeDescription": "Bu, müşterilerin kaynağa nasıl erişeceğini kontrol eder. Daha sonra değiştirilemez.",
|
||||||
|
"privateResourceTypeHostDescription": "Bağlanan müşterilere site ağında tek bir ana makineyi açığa çıkartın",
|
||||||
|
"privateResourceTypeCidrDescription": "Bağlanan müşterilere site ağında bir CIDR aralığını açığa çıkartın",
|
||||||
|
"privateResourceTypeHttpDescription": "Bir alan adı üzerinden HTTP veya HTTPS hizmetine eriş",
|
||||||
|
"privateResourceTypeSshDescription": "Bağlanan müşteriler için bir SSH sunucusuna eriş",
|
||||||
"resourceDomainDescription": "Kaynak bu tam etki alanı adıyla sunulacak.",
|
"resourceDomainDescription": "Kaynak bu tam etki alanı adıyla sunulacak.",
|
||||||
"resourceHTTPSSettings": "HTTPS Ayarları",
|
"resourceHTTPSSettings": "HTTPS Ayarları",
|
||||||
"resourceHTTPSSettingsDescription": "Kaynağınıza HTTPS üzerinden erişimin nasıl sağlanacağını yapılandırın",
|
"resourceHTTPSSettingsDescription": "Kaynağınıza HTTPS üzerinden erişimin nasıl sağlanacağını yapılandırın",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "Tedarik",
|
"provisioningManage": "Tedarik",
|
||||||
"provisioningDescription": "Tedarik anahtarlarını yönetin ve onay bekleyen siteleri gözden geçirin.",
|
"provisioningDescription": "Tedarik anahtarlarını yönetin ve onay bekleyen siteleri gözden geçirin.",
|
||||||
"pendingSites": "Bekleyen Siteler",
|
"pendingSites": "Bekleyen Siteler",
|
||||||
"siteApproveSuccess": "Site başarıyla onaylandı",
|
"siteApproveSuccess": "Site ve ilgili kaynaklar başarıyla onaylandı",
|
||||||
"siteApproveError": "Site onaylanırken hata oluştu",
|
"siteApproveError": "Site onaylanırken hata oluştu",
|
||||||
|
"siteReject": "Siteyi Reddet",
|
||||||
|
"siteQuestionReject": "Bu siteyi reddetmek istediğinizden emin misiniz?",
|
||||||
|
"siteMessageReject": "Bu işlem, siteyi ve hala beklemede olan herhangi bir ilgili kaynağı kalıcı olarak silecektir.",
|
||||||
|
"siteConfirmReject": "Site Reddetmeyi Onayla",
|
||||||
|
"siteRejectSuccess": "Site başarıyla reddedildi",
|
||||||
|
"siteRejectError": "Site reddedilirken hata oluştu",
|
||||||
"provisioningKeys": "Tedarik Anahtarları",
|
"provisioningKeys": "Tedarik Anahtarları",
|
||||||
"searchProvisioningKeys": "Tedarik anahtarlarını ara...",
|
"searchProvisioningKeys": "Tedarik anahtarlarını ara...",
|
||||||
"provisioningKeysAdd": "Tedarik Anahtarı Üret",
|
"provisioningKeysAdd": "Tedarik Anahtarı Üret",
|
||||||
@@ -466,12 +494,12 @@
|
|||||||
"provisioningKeysSave": "Tedarik anahtarını kaydet",
|
"provisioningKeysSave": "Tedarik anahtarını kaydet",
|
||||||
"provisioningKeysSaveDescription": "Bunu yalnızca bir kez görebileceksiniz. Güvenli bir yere kopyalayın.",
|
"provisioningKeysSaveDescription": "Bunu yalnızca bir kez görebileceksiniz. Güvenli bir yere kopyalayın.",
|
||||||
"provisioningKeysErrorCreate": "Tedarik anahtarı oluşturulurken hata oluştu",
|
"provisioningKeysErrorCreate": "Tedarik anahtarı oluşturulurken hata oluştu",
|
||||||
"provisioningKeysList": "Yeni tedarik anahtarı",
|
"provisioningKeysList": "Yeni Sağlama Anahtarı",
|
||||||
"provisioningKeysMaxBatchSize": "Maksimum toplu iş boyutu",
|
"provisioningKeysMaxBatchSize": "Maksimum Toplu İş Boyutu",
|
||||||
"provisioningKeysUnlimitedBatchSize": "Sınırsız toplu iş boyutu (sınırlama yok)",
|
"provisioningKeysUnlimitedBatchSize": "Sınırsız toplu iş boyutu (sınırlama yok)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "Sınırsız",
|
"provisioningKeysMaxBatchUnlimited": "Sınırsız",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "Geçerli bir maksimum toplu iş boyutu girin (1–1,000,000).",
|
"provisioningKeysMaxBatchSizeInvalid": "Geçerli bir maksimum toplu iş boyutu girin (1–1,000,000).",
|
||||||
"provisioningKeysValidUntil": "Geçerlilik tarihi",
|
"provisioningKeysValidUntil": "Geçerli Olma Süresi",
|
||||||
"provisioningKeysValidUntilHint": "Son kullanım tarihi için boş bırakın.",
|
"provisioningKeysValidUntilHint": "Son kullanım tarihi için boş bırakın.",
|
||||||
"provisioningKeysValidUntilInvalid": "Geçerli bir tarih ve saat girin.",
|
"provisioningKeysValidUntilInvalid": "Geçerli bir tarih ve saat girin.",
|
||||||
"provisioningKeysNumUsed": "Kullanım Sayısı",
|
"provisioningKeysNumUsed": "Kullanım Sayısı",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "Asla",
|
"provisioningKeysNeverUsed": "Asla",
|
||||||
"provisioningKeysEdit": "Tedarik Anahtarını Düzenle",
|
"provisioningKeysEdit": "Tedarik Anahtarını Düzenle",
|
||||||
"provisioningKeysEditDescription": "Bu anahtar için maksimum toplu iş boyutunu ve son kullanma zamanını güncelleyin.",
|
"provisioningKeysEditDescription": "Bu anahtar için maksimum toplu iş boyutunu ve son kullanma zamanını güncelleyin.",
|
||||||
"provisioningKeysApproveNewSites": "Yeni siteleri onayla",
|
"provisioningKeysApproveNewSites": "Yeni Siteleri Onayla",
|
||||||
"provisioningKeysApproveNewSitesDescription": "Bu anahtar ile kayıt olan siteleri otomatik olarak onayla.",
|
"provisioningKeysApproveNewSitesDescription": "Bu anahtar ile kayıt olan siteleri otomatik olarak onayla.",
|
||||||
"provisioningKeysUpdateError": "Tedarik anahtarı güncellenirken hata oluştu",
|
"provisioningKeysUpdateError": "Tedarik anahtarı güncellenirken hata oluştu",
|
||||||
"provisioningKeysUpdated": "Tedarik anahtarı güncellendi",
|
"provisioningKeysUpdated": "Tedarik anahtarı güncellendi",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "Ayarları Kaydet",
|
"authMethodsSave": "Ayarları Kaydet",
|
||||||
"policyAuthStackTitle": "Kimlik Doğrulama",
|
"policyAuthStackTitle": "Kimlik Doğrulama",
|
||||||
"policyAuthStackDescription": "Bu kaynağa erişim için hangi kimlik doğrulama yöntemlerinin gerekli olduğuna karar verin",
|
"policyAuthStackDescription": "Bu kaynağa erişim için hangi kimlik doğrulama yöntemlerinin gerekli olduğuna karar verin",
|
||||||
|
"policyAuthInferenceStackDescription": "Bu AI geçidine kimlerin ve hangi rollerin kimlik doğrulama yapabileceğini seçin",
|
||||||
"policyAuthOrLogicTitle": "Birden fazla kimlik doğrulama yöntemi etkin",
|
"policyAuthOrLogicTitle": "Birden fazla kimlik doğrulama yöntemi etkin",
|
||||||
"policyAuthOrLogicBanner": "Ziyaretçiler aşağıdaki etkin yöntemlerden herhangi birini kullanarak kimlik doğrulaması yapabilirler. Hepsini tamamlamaları gerekmez.",
|
"policyAuthOrLogicBanner": "Ziyaretçiler aşağıdaki etkin yöntemlerden herhangi birini kullanarak kimlik doğrulaması yapabilirler. Hepsini tamamlamaları gerekmez.",
|
||||||
"policyAuthMethodActive": "Etkin",
|
"policyAuthMethodActive": "Etkin",
|
||||||
"policyAuthMethodOff": "Kapalı",
|
"policyAuthMethodOff": "Kapalı",
|
||||||
"policyAuthSsoTitle": "Platform SSO",
|
"policyAuthSsoTitle": "Platform SSO",
|
||||||
"policyAuthSsoDescription": "Organizasyonunuzun kimlik sağlayıcısı üzerinden oturum açmayı zorunlu kılın",
|
"policyAuthSsoDescription": "Organizasyonunuzun kimlik sağlayıcısı üzerinden oturum açmayı zorunlu kılın",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "Giriş URL'si",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "Her kullanıcının zaten bir kimlik API anahtarı vardır, bu nedenle yalnızca kullanıcı olmayan istemciler veya ortak erişim için sanal API anahtarları oluşturmanız gerekir. Kullanıcılar bu kaynağın URL'si üzerinden kimlik sağlayıcılarıyla oturum açarak anahtarlarını alabilirler, bu girişten sonra gösterilecektir.",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "Her kullanıcının zaten bir kimlik API anahtarı vardır, bu nedenle yalnızca kullanıcı olmayan istemciler veya ortak erişim için sanal API anahtarları oluşturmanız gerekir. Kullanıcılar burada kimlik sağlayıcılarıyla giriş yaptıktan sonra anahtarlarını alırlar.",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} kullanıcısı, {roles} rolü",
|
"policyAuthSsoSummary": "{idp} · {users} kullanıcısı, {roles} rolü",
|
||||||
"policyAuthSsoDefaultIdp": "Varsayılan sağlayıcı",
|
"policyAuthSsoDefaultIdp": "Varsayılan sağlayıcı",
|
||||||
"policyAuthAddDefaultIdentityProvider": "Varsayılan Kimlik Sağlayıcı Ekle",
|
"policyAuthAddDefaultIdentityProvider": "Varsayılan Kimlik Sağlayıcı Ekle",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "Sürüm",
|
"newtVersion": "Sürüm",
|
||||||
"architecture": "Mimari",
|
"architecture": "Mimari",
|
||||||
"sites": "Siteler",
|
"sites": "Siteler",
|
||||||
"siteWgAnyClients": "Herhangi bir WireGuard istemcisi kullanarak bağlanın. Dahili kaynaklara eş IP adresini kullanarak erişmeniz gerekecek.",
|
"siteWgAnyClients": "Bağlanmak için herhangi bir WireGuard istemcisi kullanın. Özel kaynaklara eş IP adresini kullanarak erişmeniz gerekecek.",
|
||||||
"siteWgCompatibleAllClients": "Tüm WireGuard istemcileriyle uyumlu",
|
"siteWgCompatibleAllClients": "Tüm WireGuard istemcileriyle uyumlu",
|
||||||
"siteWgManualConfigurationRequired": "Manuel yapılandırma gerekli",
|
"siteWgManualConfigurationRequired": "Manuel yapılandırma gerekli",
|
||||||
"userErrorNotAdminOrOwner": "Kullanıcı yönetici veya sahibi değil",
|
"userErrorNotAdminOrOwner": "Kullanıcı yönetici veya sahibi değil",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "Yeni rol gerekli",
|
"accessRoleErrorNewRequired": "Yeni rol gerekli",
|
||||||
"accessRoleErrorRemove": "Rol kaldırılamadı",
|
"accessRoleErrorRemove": "Rol kaldırılamadı",
|
||||||
"accessRoleErrorRemoveDescription": "Rol kaldırılırken bir hata oluştu.",
|
"accessRoleErrorRemoveDescription": "Rol kaldırılırken bir hata oluştu.",
|
||||||
|
"accessRoleInferenceBudget": "AI Bütçesi",
|
||||||
|
"accessRoleInferenceBudgetDescription": "Bu role ait üyelerin harcama veya jeton sınırlarına dayalı AI kullanımını nasıl kısıtlayacaklarını yapılandırın",
|
||||||
"accessRoleName": "Rol Adı",
|
"accessRoleName": "Rol Adı",
|
||||||
"accessRoleQuestionRemove": "{name} rolünü silmek üzeresiniz. Bu eylemi geri alamazsınız.",
|
"accessRoleQuestionRemove": "{name} rolünü silmek üzeresiniz. Bu eylemi geri alamazsınız.",
|
||||||
"accessRoleRemove": "Rolü Kaldır",
|
"accessRoleRemove": "Rolü Kaldır",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "Organizasyon Kullanıcısı Oluştur",
|
"createOrgUser": "Organizasyon Kullanıcısı Oluştur",
|
||||||
"actionUpdateOrg": "Kuruluşu Güncelle",
|
"actionUpdateOrg": "Kuruluşu Güncelle",
|
||||||
"actionRemoveInvitation": "Daveti Kaldır",
|
"actionRemoveInvitation": "Daveti Kaldır",
|
||||||
|
"actionRemoveUserRole": "Kullanıcı Rolünü Kaldır",
|
||||||
"actionUpdateUser": "Kullanıcıyı Güncelle",
|
"actionUpdateUser": "Kullanıcıyı Güncelle",
|
||||||
"actionGetUser": "Kullanıcıyı Getir",
|
"actionGetUser": "Kullanıcıyı Getir",
|
||||||
"actionGetOrgUser": "Kuruluş Kullanıcısını Al",
|
"actionGetOrgUser": "Kuruluş Kullanıcısını Al",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "Siteyi Sil",
|
"actionDeleteSite": "Siteyi Sil",
|
||||||
"actionGetSite": "Siteyi Al",
|
"actionGetSite": "Siteyi Al",
|
||||||
"actionListSites": "Siteleri Listele",
|
"actionListSites": "Siteleri Listele",
|
||||||
|
"actionCreateAiProvider": "AI Sağlayıcı Oluştur",
|
||||||
|
"actionDeleteAiProvider": "AI Sağlayıcı Sil",
|
||||||
|
"actionGetAiProvider": "AI Sağlayıcı Al",
|
||||||
|
"actionListAiProviders": "AI Sağlayıcıları Listele",
|
||||||
|
"actionUpdateAiProvider": "AI Sağlayıcı Güncelle",
|
||||||
|
"actionCreateAiModel": "AI Modeli Oluştur",
|
||||||
|
"actionDeleteAiModel": "AI Modeli Sil",
|
||||||
|
"actionGetAiModel": "AI Modeli Al",
|
||||||
|
"actionListAiModels": "AI Modellerini Listele",
|
||||||
|
"actionUpdateAiModel": "AI Modelini Güncelle",
|
||||||
|
"actionCreateAiBudget": "AI Bütçesi Oluştur",
|
||||||
|
"actionDeleteAiBudget": "AI Bütçesini Sil",
|
||||||
|
"actionGetAiBudget": "AI Bütçesi Al",
|
||||||
|
"actionListAiBudgets": "AI Bütçelerini Listele",
|
||||||
|
"actionUpdateAiBudget": "AI Bütçesi Güncelle",
|
||||||
|
"actionListResourceAiModels": "Kaynak AI Modellerini Listele",
|
||||||
|
"actionSetResourceAiModels": "Kaynak AI Modellerini Ayarla",
|
||||||
|
"actionCreateVirtualApiKey": "Sanal API Anahtarı Oluştur",
|
||||||
|
"actionDeleteVirtualApiKey": "Sanal API Anahtarını Sil",
|
||||||
|
"actionGetVirtualApiKey": "Sanal API Anahtarı Al",
|
||||||
|
"actionListVirtualApiKeys": "Sanal API Anahtarlarını Listele",
|
||||||
|
"actionUpdateVirtualApiKey": "Sanal API Anahtarı Güncelle",
|
||||||
"actionApplyBlueprint": "Planı Uygula",
|
"actionApplyBlueprint": "Planı Uygula",
|
||||||
"actionListBlueprints": "Plan Listesini Görüntüle",
|
"actionListBlueprints": "Plan Listesini Görüntüle",
|
||||||
"actionGetBlueprint": "Planı Elde Et",
|
"actionGetBlueprint": "Planı Elde Et",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "Sunucu konsolundan kurulum simgesini girin.",
|
"setupTokenDescription": "Sunucu konsolundan kurulum simgesini girin.",
|
||||||
"setupTokenRequired": "Kurulum simgesi gerekli",
|
"setupTokenRequired": "Kurulum simgesi gerekli",
|
||||||
"actionUpdateSite": "Siteyi Güncelle",
|
"actionUpdateSite": "Siteyi Güncelle",
|
||||||
|
"actionApproveSite": "Siteyi Onayla",
|
||||||
|
"actionRejectSite": "Siteyi Reddet",
|
||||||
"actionResetSiteBandwidth": "Organizasyon Bant Genişliğini Sıfırla",
|
"actionResetSiteBandwidth": "Organizasyon Bant Genişliğini Sıfırla",
|
||||||
"actionListSiteRoles": "İzin Verilen Site Rolleri Listele",
|
"actionListSiteRoles": "İzin Verilen Site Rolleri Listele",
|
||||||
"actionCreateResource": "Kaynak Oluştur",
|
"actionCreateResource": "Kaynak Oluştur",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "Kaynak PIN Kodunu Ayarla",
|
"actionSetResourcePincode": "Kaynak PIN Kodunu Ayarla",
|
||||||
"actionSetResourceEmailWhitelist": "Kaynak E-posta Beyaz Listesi Ayarla",
|
"actionSetResourceEmailWhitelist": "Kaynak E-posta Beyaz Listesi Ayarla",
|
||||||
"actionGetResourceEmailWhitelist": "Kaynak E-posta Beyaz Listesini Al",
|
"actionGetResourceEmailWhitelist": "Kaynak E-posta Beyaz Listesini Al",
|
||||||
|
"actionListResourcePolicies": "Kaynak Politikalarını Listele",
|
||||||
|
"actionCreateResourcePolicy": "Kaynak Politikası Oluştur",
|
||||||
"actionGetResourcePolicy": "Kaynak Politikasını Al",
|
"actionGetResourcePolicy": "Kaynak Politikasını Al",
|
||||||
"actionUpdateResourcePolicy": "Kaynak Politikasını Güncelle",
|
"actionUpdateResourcePolicy": "Kaynak Politikasını Güncelle",
|
||||||
|
"actionDeleteResourcePolicy": "Kaynak Politikasını Sil",
|
||||||
"actionSetResourcePolicyUsers": "Kaynak Politika Kullanıcılarını Ayarla",
|
"actionSetResourcePolicyUsers": "Kaynak Politika Kullanıcılarını Ayarla",
|
||||||
"actionSetResourcePolicyRoles": "Kaynak Politika Rolleri Ayarla",
|
"actionSetResourcePolicyRoles": "Kaynak Politika Rolleri Ayarla",
|
||||||
"actionSetResourcePolicyPassword": "Kaynak Politika Şifresini Ayarla",
|
"actionSetResourcePolicyPassword": "Kaynak Politika Şifresini Ayarla",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "Davetiyeleri Listele",
|
"actionListInvitations": "Davetiyeleri Listele",
|
||||||
"actionExportLogs": "Kayıtları Dışa Aktar",
|
"actionExportLogs": "Kayıtları Dışa Aktar",
|
||||||
"actionViewLogs": "Kayıtları Görüntüle",
|
"actionViewLogs": "Kayıtları Görüntüle",
|
||||||
|
"actionCreateSiteProvisioningKey": "Site Sağlama Anahtarı Oluştur",
|
||||||
|
"actionListSiteProvisioningKeys": "Site Sağlama Anahtarlarını Listele",
|
||||||
|
"actionUpdateSiteProvisioningKey": "Site Sağlama Anahtarını Güncelle",
|
||||||
|
"actionDeleteSiteProvisioningKey": "Site Sağlama Anahtarını Sil",
|
||||||
"noneSelected": "Hiçbiri seçili değil",
|
"noneSelected": "Hiçbiri seçili değil",
|
||||||
"orgNotFound2": "Hiçbir organizasyon bulunamadı.",
|
"orgNotFound2": "Hiçbir organizasyon bulunamadı.",
|
||||||
"search": "Ara…",
|
"search": "Ara…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "Authenticator uygulamanızdan veya tek kullanımlık yedek kodlarınızdan birini girin.",
|
"otpAuthDescription": "Authenticator uygulamanızdan veya tek kullanımlık yedek kodlarınızdan birini girin.",
|
||||||
"otpAuthSubmit": "Kodu Gönder",
|
"otpAuthSubmit": "Kodu Gönder",
|
||||||
"idpContinue": "Veya devam et:",
|
"idpContinue": "Veya devam et:",
|
||||||
|
"idpLastUsed": "Son Kullanılan",
|
||||||
"otpAuthBack": "Şifreye Geri Dön",
|
"otpAuthBack": "Şifreye Geri Dön",
|
||||||
"navbar": "Navigasyon Menüsü",
|
"navbar": "Navigasyon Menüsü",
|
||||||
"navbarDescription": "Uygulamanın ana navigasyon menüsü",
|
"navbarDescription": "Uygulamanın ana navigasyon menüsü",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "Makine İstemcisi Oluştur",
|
"commandPaletteCreateMachineClient": "Makine İstemcisi Oluştur",
|
||||||
"commandPaletteCreateAlertRule": "Uyarı Kuralı Oluştur",
|
"commandPaletteCreateAlertRule": "Uyarı Kuralı Oluştur",
|
||||||
"commandPaletteCreateIdentityProvider": "Kimlik Sağlayıcı Oluştur",
|
"commandPaletteCreateIdentityProvider": "Kimlik Sağlayıcı Oluştur",
|
||||||
|
"commandPaletteCreateAiProvider": "Yapay Zeka Sağlayıcısı Oluştur",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "Sanal API Anahtarı Oluştur",
|
||||||
"commandPaletteToggleTheme": "Temayı Aç/Kapat",
|
"commandPaletteToggleTheme": "Temayı Aç/Kapat",
|
||||||
"commandPaletteChooseOrganization": "Organizasyon Seç",
|
"commandPaletteChooseOrganization": "Organizasyon Seç",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "Davetiye",
|
"sidebarInvitations": "Davetiye",
|
||||||
"sidebarRoles": "Roller",
|
"sidebarRoles": "Roller",
|
||||||
"sidebarShareableLinks": "Paylaşılabilir Bağlantılar",
|
"sidebarShareableLinks": "Paylaşılabilir Bağlantılar",
|
||||||
|
"sidebarAiGateway": "AI Geçidi",
|
||||||
|
"sidebarAiProviders": "Sağlayıcılar",
|
||||||
|
"commandAiProviders": "AI Sağlayıcıları",
|
||||||
|
"sidebarVirtualApiKeys": "Sanal API Anahtarları",
|
||||||
|
"sidebarMyApiKeys": "API Anahtarlarınız",
|
||||||
|
"sidebarAccount": "Başlatıcı",
|
||||||
|
"commandVirtualApiKeys": "Sanal API Anahtarları",
|
||||||
|
"virtualApiKeysTitle": "Sanal API Anahtarlarını Yönet",
|
||||||
|
"virtualApiKeysDescription": "AI Geçitlerine erişim için manuel API anahtarları oluşturun ve yönetin",
|
||||||
|
"virtualApiKeysTabIdentity": "Kimlik Anahtarları",
|
||||||
|
"virtualApiKeysTabVirtual": "Sanal Anahtarlar",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "Her Kullanıcı İçin Kimlik Anahtarları",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "Her kullanıcının bu organizasyon için zaten bir Pangolin kimlik anahtarı var. Hesaplarına özgüdür ve erişebilecekleri AI geçitlerine kimlik doğrulama sağlar.",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "Örnek",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "Kullanıcıların Anahtarlarını Nasıl Aldığı",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "Tarayıcıda herkese açık bir AI geçit URL'sini ziyaret edin ve hesaplarıyla giriş yapın.",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "Veya giriş yaparken <url></url> adresine gidin.",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "Sanal Anahtarlar sekmesinde ek sanal API anahtarları oluşturabilirsiniz. Bu anahtarlar belirli herkese açık AI geçitlerine göre kapsamlandırılabilir ve isteğe bağlı olarak bir kullanıcıyla ilişkilendirilebilir. Bir anahtar oluşturmak seçilen kamu AI geçitlerine erişim sağlar.",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "Anahtarı Manuel Olarak Oluştur",
|
||||||
|
"virtualApiKeysEmailIdentity": "Kimlik Anahtarlarını E-posta Gönder",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "Seçilen her kullanıcıya veya role Pangolin kimlik anahtarlarını gönderin.",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "Tüm kullanıcılara gönder",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "Bir hesap e-posta adresi olan her organizasyon üyesine e-posta gönderin.",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "Kullanıcılar",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "Roller",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "E-postaları Gönder",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "Kimlik anahtarları e-posta ile gönderildi",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "{sent} e-posta gönderildi.",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "E-posta adresine sahip olmayan {skipped} kullanıcılar atlandı.",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "En az bir kullanıcı veya rol seçin ya da tüm kullanıcılara gönderin.",
|
||||||
|
"virtualApiKeysEmailIdentityError": "Kimlik anahtarlarını gönderme hatası",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "Kimlik anahtarları e-posta ile gönderilemiyor",
|
||||||
|
"virtualApiKeysBannerTitle": "Her Kullanıcı İçin Kimlik Anahtarları",
|
||||||
|
"virtualApiKeysBannerDescription": "Her kullanıcı {keysUrl}'de kullanılabilir bir kimlik anahtarına sahiptir. Burada genel AI geçitlerine doğrudan erişim sağlayan anahtarlar da oluşturabilirsiniz.",
|
||||||
|
"virtualApiKeysBannerButtonText": "Kimlik Anahtarlarını Görüntüle",
|
||||||
|
"virtualApiKeys": "Sanal API Anahtarları",
|
||||||
|
"virtualApiKeysSearch": "Anahtarları ara...",
|
||||||
|
"virtualApiKeysCreate": "Sanal API Anahtarı Oluştur",
|
||||||
|
"virtualApiKeysCreateDescription": "Bu organizasyonda genel AI geçitlerini arayabilecek manuel bir anahtar mint edin",
|
||||||
|
"virtualApiKeysCreateButton": "Anahtar Oluştur",
|
||||||
|
"virtualApiKeysEmpty": "Henüz sanal API anahtarı yok",
|
||||||
|
"virtualApiKeysName": "Ad",
|
||||||
|
"virtualApiKeysDescriptionOptional": "Açıklama (isteğe bağlı)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "Kullanıcıyla İlişkilendir (isteğe bağlı)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "Bu anahtarı bir kullanıcıyla ilişkilendirerek kullanım takibini yapın. Oluşturulduktan hemen sonra bu anahtar seçilen kamu AI geçitlerine erişim sağlar. Anahtar, kullanıcının profilinde de gösterilebilir.",
|
||||||
|
"virtualApiKeysAllResources": "Tüm kamu AI geçitleri",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "Bu anahtara organizasyondaki tüm genel AI geçitlerine erişim izni ver",
|
||||||
|
"virtualApiKeysSelectResources": "Genel AI Geçitleri",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "Kaynakları seçin",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "Bu anahtarın hangi kamu AI geçitlerine erişebileceğini seçin",
|
||||||
|
"virtualApiKeysNoResources": "Kaynak yok",
|
||||||
|
"virtualApiKeysSecret": "Anahtar",
|
||||||
|
"virtualApiKeysCopyKey": "Bu anahtarı kopyalayın. Tablo veya düzenlemede tekrar görebilirsiniz.",
|
||||||
|
"virtualApiKeysViewSecret": "Gizliyi Görüntüle",
|
||||||
|
"virtualApiKeysViewSecretTitle": "Sanal API Anahtarı Gizli",
|
||||||
|
"virtualApiKeysViewSecretDescription": "Bu gizli, bu anahtara atanmış kamu AI geçitlerine erişim sağlar",
|
||||||
|
"virtualApiKeysEdit": "Sanal API Anahtarı Düzenle",
|
||||||
|
"virtualApiKeysEditDescription": "Bu anahtar için ilişkili kullanıcı ve kamu AI geçidine erişimi güncelle",
|
||||||
|
"virtualApiKeysSaveButton": "Değişiklikleri Kaydet",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "En az bir kamu AI geçidi seçin veya tüm kamu AI geçitlerini etkinleştirin",
|
||||||
|
"virtualApiKeysUpdated": "Sanal API anahtarı güncellendi",
|
||||||
|
"virtualApiKeysUpdatedDescription": "Sanal API anahtarı güncellendi",
|
||||||
|
"virtualApiKeysErrorUpdate": "Sanal API anahtarı güncellenirken hata",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "Sanal API anahtarı güncellenemedi",
|
||||||
|
"virtualApiKeysErrorCreate": "Sanal API anahtarı oluşturulurken hata",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "Sanal API anahtarı oluşturulamadı",
|
||||||
|
"virtualApiKeysErrorDelete": "Sanal API anahtarı silinirken hata",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "Sanal API anahtarı silinemedi",
|
||||||
|
"virtualApiKeysDeleted": "Sanal API anahtarı silindi",
|
||||||
|
"virtualApiKeysDeletedDescription": "Sanal API anahtarı silinmiştir",
|
||||||
|
"virtualApiKeysDelete": "Sanal API Anahtarını Sil",
|
||||||
|
"virtualApiKeysDeleteConfirm": "Anahtarı Sil",
|
||||||
|
"virtualApiKeysQuestionRemove": "Bu sanal API anahtarını silmek istediğinizden emin misiniz?",
|
||||||
|
"virtualApiKeysMessageRemove": "Bu anahtarı kullanan müşteriler hemen erişimlerini kaybedecektir.",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "Gizli yüklenirken hata",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "Sanal API anahtarı gizli yüklenemedi",
|
||||||
|
"virtualApiKeysFilterUnassigned": "Atanmamış",
|
||||||
|
"virtualApiKeysInferenceBudget": "Bütçe",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "Bu anahtarın AI kullanımını harcama veya jeton sınırlarına göre nasıl kısıtladığını yapılandırın",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "Anahtar oluşturulduğunda e-posta gönder",
|
||||||
|
"virtualApiKeysEmailThisKey": "Bu anahtarı e-posta gönder",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "Anahtar oluşturulduktan sonra ilişkili kullanıcıya ve ek adreslere gönderin",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "Geçerli anahtarı ilişkili kullanıcıya ve ek adreslere gönderin",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "Bu sunucuda e-posta yapılandırılmamış",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "SMTP yapılandırmasını yaparak sanal API anahtarlarını e-posta gönderin.",
|
||||||
|
"virtualApiKeysEmailSendToUser": "İlişkili kullanıcıya gönder",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "Anahtarı ilişkili kullanıcının hesabını alın ve e-posta gönderin",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "İlişkili bir kullanıcı seçin ve o kullanıcıya anahtarı gönder",
|
||||||
|
"virtualApiKeysEmailAdditional": "Ek e-postalar",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "E-posta ekle ve Enter tuşuna basın",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "İlişkili kullanıcının hesabını seçin veya en az bir e-posta adresi ekleyin",
|
||||||
|
"myVirtualApiKeysTitle": "API Anahtarlarınız",
|
||||||
|
"myVirtualApiKeysDescription": "Bu organizasyonda size atanmış kimlik anahtarınızı ve sanal API anahtarlarınızı görüntüleyin",
|
||||||
|
"myVirtualApiKeysResourceTitle": "{resourceName} için API Anahtarlarınız",
|
||||||
|
"myVirtualApiKeysResourceDescription": "{resourceName} erişebileceğiniz kimlik anahtarınızı ve size atanmış sanal API anahtarlarını görüntüleyin",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "Kimlik Anahtarı",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "Kişisel API Anahtarınız",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "Bu organizasyon için kişisel anahtarınız. Hesabınıza özeldir ve AI Gateway kaynaklarına çağrı yaptığınızda sizi tanımlar.",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "{resourceName} için Kişisel API Anahtarınız",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "Bu organizasyon için kişisel anahtarınız. {resourceName} 'e çağrı yaparken kullanın.",
|
||||||
|
"myVirtualApiKeysManualTitle": "Atanmış Anahtarlar",
|
||||||
|
"myVirtualApiKeysManualDescription": "Hesabınıza yönetici tarafından atanmış manuel sanal API anahtarları",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "{resourceName} erişebilecek hesabınıza atanmış manuel sanal API anahtarları",
|
||||||
|
"myVirtualApiKeysManualEmpty": "Henüz atanmış anahtar bulunmamaktadır",
|
||||||
|
"myVirtualApiKeysKindUser": "Kimlik",
|
||||||
|
"myVirtualApiKeysKindManual": "Manuel",
|
||||||
|
"myVirtualApiKeysUnnamed": "İsimsiz anahtar",
|
||||||
|
"myVirtualApiKeysRevealSecret": "Gizliyi Açıklayın",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "Bu gizli, sizi AI Gateway kaynaklarına kimlik doğrular",
|
||||||
|
"aiClientConfigTitle": "Kodlama Aracılarını Yapılandır",
|
||||||
|
"aiClientConfigDescription": "Yaygın kodlama aracılarının yapılandırmalarını kopyalayın veya Pangolin CLI sizin için otomatik olarak kurmasını sağlayın.",
|
||||||
|
"aiClientConfigDescriptionClaude": "Anthropic'in terminal için aracılık kodlama aracı.",
|
||||||
|
"aiClientConfigDescriptionCodex": "OpenAI'nin terminal için aracılık kodlama aracı.",
|
||||||
|
"aiClientConfigDescriptionOpencode": "Açık kaynak terminal kodlama aracı.",
|
||||||
|
"aiClientConfigDescriptionCursor": "VS Code üzerine kurulu yapay zeka kod editörü.",
|
||||||
|
"aiClientConfigSetup": "Kurulum",
|
||||||
|
"aiClientConfigTabCli": "Otomatik (CLI)",
|
||||||
|
"aiClientConfigTabManual": "Manuel Yapılandırma",
|
||||||
|
"aiClientConfigPreset": "Yapılandırma",
|
||||||
|
"aiClientConfigStep": "Adım {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "Bu kod parçası, model adı veya kaynak URL'si gibi örnek değerler içerir. Kullanmadan önce bunları kendi değerlerinizle değiştirin.",
|
||||||
|
"aiClientConfigRevealError": "API anahtarınızı yükleyemedik.",
|
||||||
|
"aiClientConfigRevealRetry": "Tekrar deneyin",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "Bu kaynak, Claude Code ve OpenCode gibi yaygın istemcilerden kullanılabilir. <configLink>Daha fazla bilgi edinin</configLink>",
|
||||||
|
"aiProvidersTitle": "AI Sağlayıcıları",
|
||||||
|
"aiProvidersDescription": "Bu organizasyonda AI iş yükleri için model sağlayıcılarla bağlantı kurun",
|
||||||
|
"aiProvidersBannerTitle": "Model Sağlayıcılarla Bağlan",
|
||||||
|
"aiProvidersBannerDescription": "Sağlayıcılar, Pangolin'in AI iş yükleri için kullandığı model arka uçlarıdır. Burada OpenAI, Anthropic ve diğer sağlayıcıları bağlayın, ardından bu sağlayıcıları genel AI geçitlerine ekleyin, böylece kullanıcılar modelleri kimlik farkındalığı ile erişebilir.",
|
||||||
|
"aiProvidersAdd": "Sağlayıcı Ekle",
|
||||||
|
"aiProvidersSearch": "Sağlayıcıları ara...",
|
||||||
|
"aiProvidersEmpty": "Henüz AI sağlayıcısı yok",
|
||||||
|
"aiProviderCreate": "AI Sağlayıcı Oluştur",
|
||||||
|
"aiProviderCreateDescription": "Bu organizasyon için bir model sağlayıcı ekleyin",
|
||||||
|
"aiProviderSeeAll": "Tüm Sağlayıcıları Gör",
|
||||||
|
"aiProviderSetting": "{providerName} için Sağlayıcı Ayarları",
|
||||||
|
"aiProviderSettingDescription": "Bu AI sağlayıcısını yapılandırın",
|
||||||
|
"aiProviderGeneral": "Genel",
|
||||||
|
"aiProviderGeneralDescription": "Bu sağlayıcı için temel ayarlar",
|
||||||
|
"aiProviderConfiguration": "Yapılandırma",
|
||||||
|
"aiProviderConfigurationDescription": "Bu sağlayıcının ağ yönlendirme ve kimlik doğrulaması",
|
||||||
|
"aiProviderNetworkSettings": "Ağ Ayarları",
|
||||||
|
"aiProviderNetworkSettingsDescription": "Trafiğin bu sağlayıcıya nasıl ulaşacağını seçin",
|
||||||
|
"aiProviderAuthSettings": "Kimlik Doğrulama",
|
||||||
|
"aiProviderAuthSettingsDescription": "Bu sağlayıcının URL'sine gelen isteklerde kimlik doğrulamalarını yapılandırın",
|
||||||
|
"aiProviderBudgetSettings": "Bütçe",
|
||||||
|
"aiProviderBudgetSettingsDescription": "Bu sağlayıcının harcama veya jeton sınırlamalarına dayalı olarak kullanımını nasıl kısıtlayacağını yapılandırın",
|
||||||
|
"aiBudgetAdd": "Bütçe Ekle",
|
||||||
|
"aiBudgetEmpty": "Henüz bütçe ayarlanmamış. Harcama veya jeton sınırını ayarlamak için Bütçe Ekle'ye tıklayın.",
|
||||||
|
"aiBudgetUnit": "Harcama Türü",
|
||||||
|
"aiBudgetPeriod": "Sıfırlama Dönemi",
|
||||||
|
"aiBudgetAmount": "Maksimum Harcama",
|
||||||
|
"aiBudgetAmountPlaceholder": "Maksimum harcama",
|
||||||
|
"aiBudgetPeriodHourly": "Saatlik",
|
||||||
|
"aiBudgetPeriodDaily": "Günlük",
|
||||||
|
"aiBudgetPeriodWeekly": "Haftalık",
|
||||||
|
"aiBudgetPeriodMonthly": "Aylık",
|
||||||
|
"aiBudgetPeriodYearly": "Yıllık",
|
||||||
|
"aiBudgetPeriodLifetime": "Ömür Boyu",
|
||||||
|
"aiBudgetUnitUsd": "USD",
|
||||||
|
"aiBudgetUnitTokens": "Jetonlar",
|
||||||
|
"aiBudgetConflictError": "Bu sıfırlama dönemi ve harcama türü için zaten bir bütçe var",
|
||||||
|
"aiBudgetInvalidAmountError": "0'dan büyük bir maksimum harcama girin",
|
||||||
|
"aiBudgetUpdated": "Bütçeler Güncellendi",
|
||||||
|
"aiBudgetErrorSave": "Bütçeleri güncelleme başarısız",
|
||||||
|
"aiProviderType": "Sağlayıcı Türü",
|
||||||
|
"aiProviderTypeSearch": "Sağlayıcıları ara...",
|
||||||
|
"aiProviderTypeNotFound": "Hiçbir sağlayıcı türü bulunamadı",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Geçidi",
|
||||||
|
"aiProviderTypeCustom": "Özel",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock Runtime API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Geçidi API",
|
||||||
|
"aiProviderTypeCustomDescription": "Kendi uç noktanızı getirin veya site hedefleri üzerinden yönlendirin",
|
||||||
|
"aiProviderUpstreamUrl": "Yukarı Akış URL'si",
|
||||||
|
"aiProviderUpstreamUrlDescription": "Sağlayıcı API için Temel URL",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "Bu sağlayıcı için varsayılan yukarı akış URL'sini kullanmak için boş bırakın",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "Etkili Yukarı Akış URL'si",
|
||||||
|
"aiProviderApiKey": "API Anahtarı",
|
||||||
|
"aiProviderApiKeyDescription": "Bu sağlayıcıya yapılan istekleri kimlik doğrulamak için kullanılan API anahtarı",
|
||||||
|
"aiProviderCustomHeadersDescription": "Bu sağlayıcıya yapılan her istekte gönderilen başlıklar. Yeni satır ile ayrılmış: Başlık-Adı: değer",
|
||||||
|
"aiProviderApiKeyLastChars": "API Anahtarı",
|
||||||
|
"aiProviderAuthType": "Kimlik Doğrulama Türü",
|
||||||
|
"aiProviderAuthTypeSearch": "Kimlik doğrulama türlerini ara...",
|
||||||
|
"aiProviderAuthTypeNotFound": "Kimlik doğrulama türü bulunamadı",
|
||||||
|
"aiProviderAuthTypeBearer": "Taşıyıcı",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "Yetkilendirme: Bearer anahtarı. OpenAI ve çoğu sağlayıcı tarafından kullanılır",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-key başlığı. Anthropic tarafından kullanılır",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-key başlığı. Google Gemini tarafından kullanılır",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "Yetkilendirme: Splunk anahtarı. Splunk HTTP Olay Toplayıcı tarafından kullanılır",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Geçidi",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-yetkilendirme: Bearer anahtarı. Cloudflare AI Gateway tarafından kullanılır",
|
||||||
|
"aiProviderAuthTypeNone": "Kimlik Doğrulama Yok",
|
||||||
|
"aiProviderAuthTypePassthrough": "Geçir",
|
||||||
|
"aiProviderAuthTypeDescription": "Yukarıdaki API, istekleri nasıl kimlik doğrular",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "Arayanın API anahtarı başlıklarını yukarı akışa iletin",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "Yukarı akışa kimlik doğrulama başlıkları göndermeyin",
|
||||||
|
"aiProviderRoutingMode": "Yönlendirme Modu",
|
||||||
|
"aiProviderRoutingModeDescription": "Trafiği bir yukarı akış URL'sine veya sitenizdeki HTTP hedeflerine gönderin",
|
||||||
|
"aiProviderRoutingModeUrl": "Yukarı Akış URL'si",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "Bir kamuya açık ya da özel API temel URL'si çağırın",
|
||||||
|
"aiProviderRoutingModeTarget": "Site Hedefleri",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "Siteniz üzerindeki hedefler üzerinden yönlendirin",
|
||||||
|
"aiProviderRoutingModeTargetNote": "Bu sağlayıcıyı oluşturduktan sonra, site hedeflerini Ağ Ayarları sekmesinde yapılandırın.",
|
||||||
|
"aiProviderTargetNoOne": "Bu sağlayıcının herhangi bir hedefi yok. Sitemiz üzerinden istekleri yönlendirmek için bir hedef ekleyin.",
|
||||||
|
"aiProviderSkipTlsVerification": "TLS Doğrulamayı Atla",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "Yukarı akış bağlantısı için TLS sertifika doğrulamasını devre dışı bırakın",
|
||||||
|
"aiProviderBudget": "Bütçe",
|
||||||
|
"aiProviderBudgetDescription": "Bu sağlayıcı için isteğe bağlı harcama veya jeton bütçesi",
|
||||||
|
"aiProviderBudgetAmount": "Bütçe Miktarı",
|
||||||
|
"aiProviderBudgetUnit": "Bütçe Birimi",
|
||||||
|
"aiProviderBudgetUnitUsd": "USD",
|
||||||
|
"aiProviderBudgetUnitTokens": "Jetonlar",
|
||||||
|
"aiProviderEnabled": "Etkin",
|
||||||
|
"aiProviderEnabledDescription": "Bu sağlayıcıyı tüm kaynaklarda tamamen devre dışı bırakın",
|
||||||
|
"aiProviderErrorCreate": "AI sağlayıcı oluşturma başarısız",
|
||||||
|
"aiProviderErrorUpdate": "AI sağlayıcı güncelleme başarısız",
|
||||||
|
"aiProviderErrorDelete": "AI sağlayıcı silme başarısız",
|
||||||
|
"aiProviderErrorLoad": "AI sağlayıcı yükleme başarısız",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "Geçerli bir yukarı akış URL'si girin",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "Bu sağlayıcı için yukarı akış URL'si gereklidir",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "Kimlik doğrulama türü zorunludur",
|
||||||
|
"aiProviderErrorApiKeyRequired": "API anahtarı zorunludur",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "Site hedefleri yönlendirme sadece özel sağlayıcılar için geçerlidir",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "En az bir API yetenek seçin",
|
||||||
|
"aiProviderCapabilities": "API Yetenekleri",
|
||||||
|
"aiProviderCapabilitiesDescription": "Bu sağlayıcının hangi API formatlarını kullanabileceğini seçin. Bilinen sağlayıcılar, önerilen varsayılanlarla başlar.",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "Bu özel sağlayıcının hangi API formatlarını işleyebileceğini seçin",
|
||||||
|
"aiProviderCapabilitiesSelect": "Yetenekleri seçin",
|
||||||
|
"aiProviderCapabilitiesEmpty": "Hiçbir yetenek bulunamadı",
|
||||||
|
"aiProviderCapabilitiesSearch": "Yetenekleri ara...",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI Sohbet Tamamlama",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "/v1/chat/tamamlama desteği sağlar",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI Yanıtları",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "/v1/yanıtlar desteği sağlar",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic Mesajlar",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "/v1/mesajlar desteği sağlar",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini İçerik Üret",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "Doğrudan Gemini API desteği sağlar",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Bedrock Modeli Çağır",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "Amazon Bedrock InvokeModel desteği sağlar",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex İçerik Üret",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "Vertex AI Gemini formatı desteği sağlar",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex Ham Tahmin",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "Vertex AI HamTahmin desteği sağlar",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock Sohbet",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "Amazon Bedrock Sohbet API desteği sağlar",
|
||||||
|
"aiProviderCreated": "AI sağlayıcı yaratıldı",
|
||||||
|
"aiProviderUpdated": "AI sağlayıcı güncellendi",
|
||||||
|
"aiProviderDeleted": "AI sağlayıcı silindi",
|
||||||
|
"aiProviderDelete": "Sağlayıcıyı Sil",
|
||||||
|
"aiProviderDeleteConfirm": "Sağlayıcıyı Sil",
|
||||||
|
"aiProviderQuestionRemove": "Bu AI sağlayıcıyı silmek istediğinizden emin misiniz?",
|
||||||
|
"aiProviderMessageRemove": "Bu, sağlayıcıyı ve modellerini ve hedeflerini kalıcı olarak silecektir. Geri alınamaz.",
|
||||||
|
"aiProviderErrorNoUpdate": "AI sağlayıcı güncellenemiyor",
|
||||||
|
"aiProviderModels": "Modeller",
|
||||||
|
"aiProviderModelsDescription": "Bu sağlayıcı için izin ve engelleme listelerini tanımlayın. İstekler bir izin girişini karşılamalı ve bir engelleme girişini karşılamamalıdır.",
|
||||||
|
"aiProviderCreateModelsDescription": "Bu sağlayıcının hizmet verebileceği modelleri seçin. Boş bir izin listesi tüm trafiği reddeder. Modelleri daha sonra ekleyebilir veya değiştirebilirsiniz.",
|
||||||
|
"aiProviderModelsPlaceholder": "Modelleri arayın veya özel bir anahtar yazın",
|
||||||
|
"aiProviderModelsAllow": "İzin Listesi",
|
||||||
|
"aiProviderModelsAllowDescription": "Bu sağlayıcı aracılığıyla kullanılabilecek modeller. Boş, tümünü reddet anlamına gelir.",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "Model anahtarını girin",
|
||||||
|
"aiProviderModelsAllowEmpty": "Henüz model eklenmedi.",
|
||||||
|
"aiProviderModelsBlock": "Engelleme Listesi",
|
||||||
|
"aiProviderModelsBlockDescription": "Bir izin girdisiyle eşleşseler bile reddedilecek modeller.",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "Model anahtarını girin",
|
||||||
|
"aiProviderModelsBlockEmpty": "Henüz model eklenmedi.",
|
||||||
|
"aiProviderModelsAdd": "Modelleri Ekle",
|
||||||
|
"aiProviderModelsClearAll": "Hepsini Temizle",
|
||||||
|
"aiProviderModelsAddCustom": "\"{key}\" ekle",
|
||||||
|
"aiProviderModelsAddCustomHint": "Bu özel model anahtarını eklemek için Enter'a basın.",
|
||||||
|
"aiProviderModelsAddBulk": "{count} özel anahtar ekle",
|
||||||
|
"aiProviderModelsAddBulkHint": "{count} özel anahtarı eklemek için Enter'a basın.",
|
||||||
|
"aiProviderModelsAddOne": "Şimdi {key} ekle",
|
||||||
|
"aiProviderModelsAddSelected": "Seçileni Ekle",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} seçildi",
|
||||||
|
"aiProviderModelsSelectAll": "Hepsini seç",
|
||||||
|
"aiProviderModelsClearSelected": "Temizle",
|
||||||
|
"aiProviderModelsBulkHint": "Bilinen modelleri seçin veya özel bir anahtar yazın.",
|
||||||
|
"aiProviderModelsCatalogEmpty": "Eşleşen katalog modeli yok.",
|
||||||
|
"aiProviderModelsCatalogHeading": "Bilinen Modeller",
|
||||||
|
"aiProviderModelsAllLabel": "Tüm modeller",
|
||||||
|
"aiProviderModelsAllPatternHint": "Genel arama deseni: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "Tüm modellere izin ver",
|
||||||
|
"aiProviderModelsAddAllBlock": "Tüm modelleri engelle",
|
||||||
|
"aiProviderModelsAddAllDescription": "* arama desenini kullanarak her model anahtarı eşleşir.",
|
||||||
|
"aiProviderModelsViewMore": "Daha fazla göster ({count})",
|
||||||
|
"aiProviderModelsViewLess": "Daha az göster",
|
||||||
|
"aiProviderModelsRemove": "Modeli kaldır",
|
||||||
|
"aiProviderModelsEditHint": "Model ayarlarını düzenlemek için tıklayın",
|
||||||
|
"aiProviderModelsSourceCatalog": "Bilinen katalog modeli",
|
||||||
|
"aiProviderModelsSourceCustom": "Özel model anahtarı",
|
||||||
|
"aiProviderModelsSourcePattern": "Genel arama deseni",
|
||||||
|
"aiProviderModelsSourceAll": "Her model anahtarı ile eşleşir",
|
||||||
|
"aiProviderModelsBudgetConfigured": "Bütçe yapılandırılmış",
|
||||||
|
"aiProviderModelsEditTitle": "Modeli düzenle",
|
||||||
|
"aiProviderModelsEditDescription": "Model anahtarını güncelleyin veya bütçesini yapılandırın.",
|
||||||
|
"aiProviderModelsBudgetTab": "Bütçe",
|
||||||
|
"aiProviderModelsKeyLabel": "Model Anahtarı",
|
||||||
|
"aiProviderModelsKeyRequired": "Bir model anahtarı girin",
|
||||||
|
"aiProviderModelsKeyDuplicate": "Bu model anahtarı zaten bir listede var",
|
||||||
|
"aiProviderModelsOverlapError": "Bu desenler her iki listede de olamaz: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "Modeller güncellendi",
|
||||||
|
"aiProviderModelsErrorUpdate": "Modeller güncellenemedi",
|
||||||
|
"aiResourceProviders": "Sağlayıcılar",
|
||||||
|
"aiResourceProvidersDescription": "Bu AI ağ geçidi kullanabileceği AI sağlayıcılarını seçin",
|
||||||
|
"aiResourceProvidersHelp": "Sağlayıcıları ekle ve miras almayı (her sağlayıcının listesini kullanmayı) ya da seçmeyi (bu kaynak için bir izin listesini seç) seçin. Birbirine zıt sağlayıcıların izin desenleri izin verilmez.",
|
||||||
|
"aiResourceProvidersSelect": "Sağlayıcıları seçin",
|
||||||
|
"aiResourceProvidersEmpty": "Hiçbir AI sağlayıcı bulunamadı",
|
||||||
|
"aiResourceProvidersNoneAttached": "Henüz hiç sağlayıcı eklenmedi.",
|
||||||
|
"aiResourceProvidersAdd": "Sağlayıcı ekle",
|
||||||
|
"aiResourceProvidersRemove": "Sağlayıcıyı kaldır",
|
||||||
|
"aiResourceProviderToggleEnabled": "Bu kaynaktaki sağlayıcıyı etkinleştir veya devre dışı bırak",
|
||||||
|
"aiResourceProviderDisabled": "Devre Dışı",
|
||||||
|
"aiResourceProvidersUpdated": "Sağlayıcılar güncellendi",
|
||||||
|
"aiResourceProvidersErrorUpdate": "Sağlayıcılar güncellenemedi",
|
||||||
|
"aiResourceProviderEditDescription": "Bu sağlayıcının modellerinin bu kaynakta nasıl göstereceğini seçin.",
|
||||||
|
"viewProviderSettings": "Sağlayıcı Ayarlarını Görüntüle",
|
||||||
|
"aiResourceProviderMode": "Erişim modu",
|
||||||
|
"aiResourceProviderModeInherit": "Miras Al",
|
||||||
|
"aiResourceProviderModeSelect": "Seç",
|
||||||
|
"aiResourceProviderModeSelectSummary": "Seç · {count} modeller",
|
||||||
|
"aiResourceProviderModeInheritHelp": "Bu sağlayıcıda yapılandırıldığı gibi izin ve engelleme listelerini kullanın.",
|
||||||
|
"aiResourceProviderModeSelectHelp": "Bu kaynak için bu sağlayıcının izin listesi modellerinin bir alt kümesini seçin.",
|
||||||
|
"aiResourceProviderAllowModels": "İzin listesi",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "Modelleri seçin",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "Modelleri ara...",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "Hiçbir model bulunamadı",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "Sadece sağlayıcının izin listesindeki modeller seçilebilir.",
|
||||||
|
"aiResourceAliasRequired": "AI ağ geçitleri için takma ad gereklidir",
|
||||||
|
"aiResourceDomainConfiguration": "Alan Adı Yapılandırması",
|
||||||
|
"aiResourceDomainConfigurationDescription": "Bu AI ağ geçidine ulaşmak için müşterilerin kullanacağı alan adını seçin.",
|
||||||
|
"aiUsageAnalyticsTitle": "AI Kullanım Analizi",
|
||||||
|
"aiUsageAnalyticsDescription": "AI ağ geçidi maliyetini, token kullanımını ve sağlayıcılar, kaynaklar, roller ve kullanıcılar genelindeki aktiviteyi analiz edin",
|
||||||
|
"aiUsageTabOverview": "Genel Bakış",
|
||||||
|
"aiUsageTabProviders": "Sağlayıcılar",
|
||||||
|
"aiUsageTabResources": "Kaynaklar",
|
||||||
|
"aiUsageFilterProvider": "Sağlayıcı",
|
||||||
|
"aiUsageFilterModel": "Model",
|
||||||
|
"aiUsageFilterResource": "Kaynak",
|
||||||
|
"aiUsageFilterRole": "Rol",
|
||||||
|
"aiUsageFilterUser": "Kullanıcı",
|
||||||
|
"aiUsageFilterAllProviders": "Tüm Sağlayıcılar",
|
||||||
|
"aiUsageFilterAllModels": "Tüm Modeller",
|
||||||
|
"aiUsageFilterAllResources": "Tüm Kaynaklar",
|
||||||
|
"aiUsageFilterAllRoles": "Tüm Roller",
|
||||||
|
"aiUsageFilterAllUsers": "Tüm Kullanıcılar",
|
||||||
|
"aiUsageFilterSearch": "Ara...",
|
||||||
|
"aiUsageFilterNotFound": "Hiçbir seçenek bulunamadı",
|
||||||
|
"aiUsageResetFilters": "Filtreleri Sıfırla",
|
||||||
|
"aiUsageRefresh": "Yenile",
|
||||||
|
"aiUsageTokenTypePrompt": "Yazım",
|
||||||
|
"aiUsageTokenTypeCacheRead": "Önbellek okuma",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "Önbellek yazma",
|
||||||
|
"aiUsageTokenTypeCompletion": "Tamamlama",
|
||||||
|
"aiUsageTokenTypeReasoning": "Muhakeme",
|
||||||
|
"aiUsageRequests": "İstekler",
|
||||||
|
"aiUsageCost": "Maliyet",
|
||||||
|
"aiUsageTokens": "Jetonlar",
|
||||||
|
"aiUsageOther": "Diğer",
|
||||||
|
"aiUsageTotalRequests": "Toplam İstekler",
|
||||||
|
"aiUsageTotalTokens": "Toplam Jetonlar",
|
||||||
|
"aiUsageTotalCost": "Toplam Maliyet",
|
||||||
|
"aiUsageEstimated": "Tahmini",
|
||||||
|
"aiUsageRequestVolume": "İstek Hacmi",
|
||||||
|
"aiUsageTokenUsage": "Jeton Kullanımı",
|
||||||
|
"aiUsageModelCost": "Model Maliyeti",
|
||||||
|
"aiUsageModelTokens": "Model Jetonları",
|
||||||
|
"aiUsageTopModels": "En İyi Modeller",
|
||||||
|
"aiUsageTopProviders": "En İyi Sağlayıcılar",
|
||||||
|
"aiUsageProviderCost": "Sağlayıcı Maliyeti",
|
||||||
|
"aiUsageProviderTokenUsage": "Sağlayıcı Jeton Kullanımı",
|
||||||
|
"aiUsageTopResources": "En İyi Kaynaklar",
|
||||||
|
"aiUsageResourceCost": "Kaynak Maliyeti",
|
||||||
|
"aiUsageResourceTokenUsage": "Kaynak Jeton Kullanımı",
|
||||||
|
"aiUsageResourceTypePublic": "Kamusal Kaynak",
|
||||||
|
"aiUsageResourceTypeSite": "Özel Kaynak",
|
||||||
|
"aiUsageNoResource": "Kaynak yok",
|
||||||
|
"aiUsageRolesTab": "Roller",
|
||||||
|
"aiUsageUsersTab": "Kullanıcılar",
|
||||||
|
"aiUsageTopRoles": "En İyi Roller",
|
||||||
|
"aiUsageRoleCost": "Rol Maliyeti",
|
||||||
|
"aiUsageRoleTokenUsage": "Rol Jeton Kullanımı",
|
||||||
|
"aiUsageTopUsers": "En İyi Kullanıcılar",
|
||||||
|
"aiUsageUserCost": "Kullanıcı Maliyeti",
|
||||||
|
"aiUsageUserTokenUsage": "Kullanıcı Jeton Kullanımı",
|
||||||
|
"aiUsageUnknownUser": "Bilinmeyen kullanıcı",
|
||||||
|
"aiUsageVirtualApiKeysTab": "Sanal API Anahtarları",
|
||||||
|
"aiUsageFilterVirtualApiKey": "Sanal API Anahtarı",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "Tüm Sanal API Anahtarları",
|
||||||
|
"aiUsageTopVirtualApiKeys": "En İyi Sanal API Anahtarları",
|
||||||
|
"aiUsageVirtualApiKeyCost": "Sanal API Anahtar Maliyeti",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "Sanal API Anahtar Jeton Kullanımı",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "Sanal API anahtarı yok",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "İsimsiz anahtar",
|
||||||
|
"aiUsageLoading": "Yükleniyor...",
|
||||||
|
"aiUsageNoData": "Veri yok",
|
||||||
|
"resourceBudgetSettings": "Bütçe",
|
||||||
|
"resourceBudgetSettingsDescription": "Bu AI ağ geçidi harcama veya jeton limitlerine göre kullanım nasıl sınırlayacağını yapılandırın",
|
||||||
"sidebarApiKeys": "API Anahtarları",
|
"sidebarApiKeys": "API Anahtarları",
|
||||||
"sidebarProvisioning": "Tedarik",
|
"sidebarProvisioning": "Tedarik",
|
||||||
"sidebarSettings": "Ayarlar",
|
"sidebarSettings": "Ayarlar",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "Uyarı kuralı kaydedildi",
|
"alertingRuleSaved": "Uyarı kuralı kaydedildi",
|
||||||
"alertingRuleSavedCreatedDescription": "Yeni uyarı kuralınız oluşturuldu. Bu sayfada düzenlemeye devam edebilirsiniz.",
|
"alertingRuleSavedCreatedDescription": "Yeni uyarı kuralınız oluşturuldu. Bu sayfada düzenlemeye devam edebilirsiniz.",
|
||||||
"alertingRuleSavedUpdatedDescription": "Bu uyarı kuralındaki değişiklikleriniz kaydedildi.",
|
"alertingRuleSavedUpdatedDescription": "Bu uyarı kuralındaki değişiklikleriniz kaydedildi.",
|
||||||
|
"alertingTestAlertSent": "Test uyarısı gönderildi",
|
||||||
|
"alertingTestAlertSentDescription": "Bu kurala yapılandırılmış eylemlere bir test uyarısı gönderildi.",
|
||||||
"alertingEditRule": "Uyarı Kuralını Düzenle",
|
"alertingEditRule": "Uyarı Kuralını Düzenle",
|
||||||
"alertingCreateRule": "Uyarı Kuralı Oluştur",
|
"alertingCreateRule": "Uyarı Kuralı Oluştur",
|
||||||
"alertingRuleCredenzaDescription": "Ne izlenecek, ne zaman tetiklenecek ve nasıl bildirilecek, bunları seçin",
|
"alertingRuleCredenzaDescription": "Ne izlenecek, ne zaman tetiklenecek ve nasıl bildirilecek, bunları seçin",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "Her kural neyin izleneceğini (bir site, sağlık kontrolü veya kaynak), ne zaman tetikleneceğini (örneğin çevrimdışı veya sağlıksız) ve ekibinize e-posta, web kancaları veya entegrasyonlar aracılığıyla nasıl bildirileceğini bağlar. Bu listeyi kullanarak kuralları oluşturun, etkinleştirin ve yönetin.",
|
"alertingRulesBannerDescription": "Her kural neyin izleneceğini (bir site, sağlık kontrolü veya kaynak), ne zaman tetikleneceğini (örneğin çevrimdışı veya sağlıksız) ve ekibinize e-posta, web kancaları veya entegrasyonlar aracılığıyla nasıl bildirileceğini bağlar. Bu listeyi kullanarak kuralları oluşturun, etkinleştirin ve yönetin.",
|
||||||
"alertingHealthChecksBannerTitle": "Sağlık ve Kaynakları İzleyin",
|
"alertingHealthChecksBannerTitle": "Sağlık ve Kaynakları İzleyin",
|
||||||
"alertingHealthChecksBannerDescription": "Sağlık kontrolleri bir kez tanımladığınız HTTP veya TCP monitörleridir. Ardından hedef sağlıklı veya sağlıksız olduğunda bildirilmeniz için onları uyarı kurallarında kaynak olarak kullanabilirsiniz. Kaynaklar üzerindeki sağlık kontrolleri de burada görünür.",
|
"alertingHealthChecksBannerDescription": "Sağlık kontrolleri bir kez tanımladığınız HTTP veya TCP monitörleridir. Ardından hedef sağlıklı veya sağlıksız olduğunda bildirilmeniz için onları uyarı kurallarında kaynak olarak kullanabilirsiniz. Kaynaklar üzerindeki sağlık kontrolleri de burada görünür.",
|
||||||
|
"alertingTestRule": "Test Uyarı Kuralı",
|
||||||
|
"alertingAddActionHeading": "Yeni Eylem Ekle",
|
||||||
|
"alertingSelectActionType": "Bir Eylem Seçin",
|
||||||
|
"alertingNoActionsTitle": "Eylem yapılandırılmamış",
|
||||||
|
"alertingNoActionsSaveDescription": "Bu kuralın tetiklendiğinde birini bilgilendirebilmesi için en az bir eylem ekleyin.",
|
||||||
|
"alertingNoActionsTestDescription": "Bu kuralı test etmeden önce en az bir eylem ekleyin.",
|
||||||
"standaloneHcTableTitle": "Sağlık Kontrolleri",
|
"standaloneHcTableTitle": "Sağlık Kontrolleri",
|
||||||
"standaloneHcSearchPlaceholder": "Sağlık kontrollerini ara…",
|
"standaloneHcSearchPlaceholder": "Sağlık kontrollerini ara…",
|
||||||
"standaloneHcAddButton": "Sağlık Kontrolü Oluştur",
|
"standaloneHcAddButton": "Sağlık Kontrolü Oluştur",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "Alt Alan: {subdomain}",
|
"domainPickerSubdomain": "Alt Alan: {subdomain}",
|
||||||
"domainPickerNamespace": "Ad Alanı: {namespace}",
|
"domainPickerNamespace": "Ad Alanı: {namespace}",
|
||||||
"domainPickerShowMore": "Daha Fazla Göster",
|
"domainPickerShowMore": "Daha Fazla Göster",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "Kullanılacak alan adı yok",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "Henüz ayarlanmış bir alan adınız yok. Devam etmek için bir alan adı oluşturun.",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "Alan Adlarına Git",
|
||||||
"regionSelectorTitle": "Bölge Seç",
|
"regionSelectorTitle": "Bölge Seç",
|
||||||
"domainPickerRemoteExitNodeWarning": "Belirtilen alan adları, siteler uzak çıkış düğümlerine bağlandığında desteklenmez. Kaynakların uzak düğümlerde kullanılabilir olması için özel bir alan adı kullanın.",
|
"domainPickerRemoteExitNodeWarning": "Belirtilen alan adları, siteler uzak çıkış düğümlerine bağlandığında desteklenmez. Kaynakların uzak düğümlerde kullanılabilir olması için özel bir alan adı kullanın.",
|
||||||
"regionSelectorInfo": "Bir bölge seçmek, konumunuz için daha iyi performans sağlamamıza yardımcı olur. Sunucunuzla aynı bölgede olmanıza gerek yoktur.",
|
"regionSelectorInfo": "Bir bölge seçmek, konumunuz için daha iyi performans sağlamamıza yardımcı olur. Sunucunuzla aynı bölgede olmanıza gerek yoktur.",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "Alt ağ",
|
"subnetPlaceholder": "Alt ağ",
|
||||||
"addressDescription": "İstemcinin dahili adresi. Organizasyon alt ağı içinde olmalıdır.",
|
"addressDescription": "İstemcinin dahili adresi. Organizasyon alt ağı içinde olmalıdır.",
|
||||||
"selectSites": "Siteleri seçin",
|
"selectSites": "Siteleri seçin",
|
||||||
|
"selectResources": "Kaynakları seçin",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, one {# kaynak} other {# kaynaklar}}",
|
||||||
"selectLabels": "Etiketleri seçin",
|
"selectLabels": "Etiketleri seçin",
|
||||||
"sitesDescription": "Müşteri seçilen sitelere bağlantı kuracaktır",
|
"sitesDescription": "Müşteri seçilen sitelere bağlantı kuracaktır",
|
||||||
"clientInstallOlm": "Olm Yükle",
|
"clientInstallOlm": "Olm Yükle",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "Zaman saniye cinsindendir",
|
"timeIsInSeconds": "Zaman saniye cinsindendir",
|
||||||
"requireDeviceApproval": "Cihaz Onaylarını Gerektir",
|
"requireDeviceApproval": "Cihaz Onaylarını Gerektir",
|
||||||
"requireDeviceApprovalDescription": "Bu role sahip kullanıcıların yeni cihazlarının bağlanabilmesi ve kaynaklara erişebilmesi için bir yönetici tarafından onaylanması gerekiyor.",
|
"requireDeviceApprovalDescription": "Bu role sahip kullanıcıların yeni cihazlarının bağlanabilmesi ve kaynaklara erişebilmesi için bir yönetici tarafından onaylanması gerekiyor.",
|
||||||
"sshSettings": "SSH Ayarları",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI Ağ Geçidi",
|
||||||
"sshAccess": "SSH Erişimi",
|
"sshAccess": "SSH Erişimi",
|
||||||
"rdpSettings": "RDP Ayarları",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "VNC Ayarları",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH Sunucusu",
|
"sshServer": "SSH Sunucusu",
|
||||||
"rdpServer": "RDP Sunucusu",
|
"rdpServer": "RDP Sunucusu",
|
||||||
"vncServer": "VNC Sunucusu",
|
"vncServer": "VNC Sunucusu",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "Herkese Açık",
|
"resourcesTableProxyResources": "Herkese Açık",
|
||||||
"resourcesTableClientResources": "Özel",
|
"resourcesTableClientResources": "Özel",
|
||||||
"resourcesTableNoProxyResourcesFound": "Hiçbir proxy kaynağı bulunamadı.",
|
"resourcesTableNoProxyResourcesFound": "Hiçbir proxy kaynağı bulunamadı.",
|
||||||
"resourcesTableNoInternalResourcesFound": "Hiçbir dahili kaynak bulunamadı.",
|
"resourcesTableNoInternalResourcesFound": "Özel kaynak bulunamadı.",
|
||||||
"resourcesTableDestination": "Hedef",
|
"resourcesTableDestination": "Hedef",
|
||||||
"resourcesTableAlias": "Takma Ad",
|
"resourcesTableAlias": "Takma Ad",
|
||||||
"resourcesTableAliasAddress": "Alias Adresi",
|
"resourcesTableAliasAddress": "Alias Adresi",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "İptal",
|
"editInternalResourceDialogCancel": "İptal",
|
||||||
"editInternalResourceDialogSaveResource": "Kaynağı Kaydet",
|
"editInternalResourceDialogSaveResource": "Kaynağı Kaydet",
|
||||||
"editInternalResourceDialogSuccess": "Başarı",
|
"editInternalResourceDialogSuccess": "Başarı",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Dahili kaynak başarıyla güncellendi",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Özel kaynak başarıyla güncellendi",
|
||||||
"editInternalResourceDialogError": "Hata",
|
"editInternalResourceDialogError": "Hata",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Dahili kaynak güncellenemedi",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "Özel kaynak güncellenemedi",
|
||||||
"editInternalResourceDialogNameRequired": "Ad gerekli",
|
"editInternalResourceDialogNameRequired": "Ad gerekli",
|
||||||
"editInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
|
"editInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
|
||||||
"editInternalResourceDialogProxyPortMin": "Proxy bağlantı noktası en az 1 olmalıdır",
|
"editInternalResourceDialogProxyPortMin": "Proxy bağlantı noktası en az 1 olmalıdır",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI Ağ Geçidi",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "Şema",
|
"editInternalResourceDialogScheme": "Şema",
|
||||||
"editInternalResourceDialogEnableSsl": "TLS'yi Etkinleştir",
|
"editInternalResourceDialogEnableSsl": "TLS'yi Etkinleştir",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Takma Ad",
|
"editInternalResourceDialogAlias": "Takma Ad",
|
||||||
"editInternalResourceDialogAliasDescription": "Bu kaynak için isteğe bağlı dahili DNS takma adı.",
|
"editInternalResourceDialogAliasDescription": "Bu kaynak için isteğe bağlı dahili DNS takma adı.",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "Site Bulunamadı",
|
"createInternalResourceDialogNoSitesAvailable": "Site Bulunamadı",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "Dahili kaynak oluşturmak için en az bir Newt sitesine ve alt ağa sahip olmalısınız.",
|
"createInternalResourceDialogNoSitesAvailableDescription": "Özel kaynaklar oluşturmak için alt ağı yapılandırılmış en az bir Newt sitesine sahip olmalısınız.",
|
||||||
"createInternalResourceDialogClose": "Kapat",
|
"createInternalResourceDialogClose": "Kapat",
|
||||||
"createInternalResourceDialogCreateClientResource": "Özel Kaynak Oluştur",
|
"createInternalResourceDialogCreateClientResource": "Özel Kaynak Oluştur",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "Seçilen siteye bağlı istemcilere erişilebilir olacak yeni bir kaynak oluşturun",
|
"createInternalResourceDialogCreateClientResourceDescription": "Seçilen siteye bağlı istemcilere erişilebilir olacak yeni bir kaynak oluşturun",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "ICMP Ping İzne Ver",
|
"privateResourceAllowIcmpPing": "ICMP Ping İzne Ver",
|
||||||
"privateResourceNetworkAccess": "Ağ Erişimi",
|
"privateResourceNetworkAccess": "Ağ Erişimi",
|
||||||
"privateResourceNetworkAccessDescription": "Bu kaynak için TCP/UDP port erişimini kontrol edin ve ICMP ping'in izin verilip verilmediğini kontrol edin.",
|
"privateResourceNetworkAccessDescription": "Bu kaynak için TCP/UDP port erişimini kontrol edin ve ICMP ping'in izin verilip verilmediğini kontrol edin.",
|
||||||
"hostSettings": "Sunucu Ayarları",
|
"hostSettings": "Sunucu",
|
||||||
"cidrSettings": "CIDR Ayarları",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "Kaynak Özellikleri",
|
"createInternalResourceDialogResourceProperties": "Kaynak Özellikleri",
|
||||||
"createInternalResourceDialogName": "Ad",
|
"createInternalResourceDialogName": "Ad",
|
||||||
"createInternalResourceDialogSite": "Site",
|
"createInternalResourceDialogSite": "Site",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "İptal",
|
"createInternalResourceDialogCancel": "İptal",
|
||||||
"createInternalResourceDialogCreateResource": "Kaynak Oluştur",
|
"createInternalResourceDialogCreateResource": "Kaynak Oluştur",
|
||||||
"createInternalResourceDialogSuccess": "Başarı",
|
"createInternalResourceDialogSuccess": "Başarı",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Dahili kaynak başarıyla oluşturuldu",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Özel kaynak başarıyla oluşturuldu",
|
||||||
"createInternalResourceDialogError": "Hata",
|
"createInternalResourceDialogError": "Hata",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "Dahili kaynak oluşturulamadı",
|
"createInternalResourceDialogFailedToCreateInternalResource": "Özel kaynak oluşturulamadı",
|
||||||
"createInternalResourceDialogNameRequired": "Ad gerekli",
|
"createInternalResourceDialogNameRequired": "Ad gerekli",
|
||||||
"createInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
|
"createInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "Lütfen bir site seçin",
|
"createInternalResourceDialogPleaseSelectSite": "Lütfen bir site seçin",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI Ağ Geçidi",
|
||||||
"scheme": "Şema",
|
"scheme": "Şema",
|
||||||
"createInternalResourceDialogScheme": "Şema",
|
"createInternalResourceDialogScheme": "Şema",
|
||||||
"createInternalResourceDialogEnableSsl": "TLS'yi Etkinleştir",
|
"createInternalResourceDialogEnableSsl": "TLS'yi Etkinleştir",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "Geçerli Şifre",
|
"validPassword": "Geçerli Şifre",
|
||||||
"validEmail": "Geçerli E-posta",
|
"validEmail": "Geçerli E-posta",
|
||||||
"validSSO": "Geçerli SSO",
|
"validSSO": "Geçerli SSO",
|
||||||
|
"validVirtualAPIKey": "Geçerli Sanal API Anahtarı",
|
||||||
"view": "Görüntüle",
|
"view": "Görüntüle",
|
||||||
"configManaged": "Yapılandırma Yönetildi",
|
"configManaged": "Yapılandırma Yönetildi",
|
||||||
"connectedClient": "Bağlı İstemci",
|
"connectedClient": "Bağlı İstemci",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "Kayıt Saklama",
|
"logRetention": "Kayıt Saklama",
|
||||||
"logRetentionDescription": "Bu organizasyon için farklı türdeki günlüklerin ne kadar süre saklanacağını yönetin veya devre dışı bırakın",
|
"logRetentionDescription": "Bu organizasyon için farklı türdeki günlüklerin ne kadar süre saklanacağını yönetin veya devre dışı bırakın",
|
||||||
"requestLogsDescription": "Bu organizasyondaki kaynaklar için ayrıntılı istek günlüklerini görüntüleyin",
|
"requestLogsDescription": "Bu organizasyondaki kaynaklar için ayrıntılı istek günlüklerini görüntüleyin",
|
||||||
|
"aiSessionLogs": "AI Ağ Geçidi Oturum Günlükleri",
|
||||||
|
"aiSessionLogsDescription": "Bu organizasyondaki AI ağ geçidi isteklerinin istem ve yanıt transkriptlerini görüntüleyin",
|
||||||
|
"sidebarLogsAi": "Oturum Günlükleri",
|
||||||
|
"commandLogsAi": "Oturum Günlükleri",
|
||||||
|
"sidebarLogsAiUsage": "Kullanım Analizi",
|
||||||
|
"commandLogsAiUsage": "Kullanım Analizi",
|
||||||
|
"provider": "Sağlayıcı",
|
||||||
|
"capability": "Yetenek",
|
||||||
|
"model": "Model",
|
||||||
|
"virtualApiKey": "Sanal API Anahtarı",
|
||||||
|
"noVirtualApiKey": "Sanal API anahtarı yok",
|
||||||
|
"stream": "Akış",
|
||||||
|
"streaming": "Akış",
|
||||||
|
"nonStreaming": "Akış Dışı",
|
||||||
|
"statusCode": "Durum Kodu",
|
||||||
|
"aiSessionId": "Oturum ID",
|
||||||
|
"aiSessionRequest": "İstek",
|
||||||
|
"aiSessionResponse": "Yanıt",
|
||||||
|
"aiSessionNoData": "Hiçbir veri yakalanmadı",
|
||||||
|
"aiSessionCouldNotParse": "(ham, döküm çözümlenemedi)",
|
||||||
|
"aiSessionLogTruncated": "Bu oturum saklama öncesi kısaltıldı ve eksik olabilir.",
|
||||||
|
"aiSessionViewRaw": "Ham JSON Görüntüle",
|
||||||
|
"aiSessionViewChat": "Sohbet Görüntüle",
|
||||||
|
"cost": "Maliyet",
|
||||||
|
"estimated": "Tahmini",
|
||||||
|
"tokenUsage": "Jeton Kullanımı",
|
||||||
|
"promptTokens": "Yazım Jetonları",
|
||||||
|
"cacheReadTokens": "Önbellek Okuma Jetonları",
|
||||||
|
"cacheWriteTokens": "Önbellek Yazma Jetonları",
|
||||||
|
"completionTokens": "Tamamlama Jetonları",
|
||||||
|
"reasoningTokens": "Muhakeme Jetonları",
|
||||||
|
"totalTokens": "Toplam Jetonlar",
|
||||||
"requestAnalyticsDescription": "Bu organizasyondaki kaynaklar için ayrıntılı istek analizlerini görüntüleyin.",
|
"requestAnalyticsDescription": "Bu organizasyondaki kaynaklar için ayrıntılı istek analizlerini görüntüleyin.",
|
||||||
"logRetentionRequestLabel": "HTTP İstek Günlüğü Saklama",
|
"logRetentionRequestLabel": "HTTP İstek Günlüğü Saklama",
|
||||||
"logRetentionRequestDescription": "İstek günlüklerini ne kadar süre tutacağını belirle",
|
"logRetentionRequestDescription": "İstek günlüklerini ne kadar süre tutacağını belirle",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "Eylem günlüklerini ne kadar süre tutacağını belirle",
|
"logRetentionActionDescription": "Eylem günlüklerini ne kadar süre tutacağını belirle",
|
||||||
"logRetentionConnectionLabel": "Bağlantı kayıtlarını ne kadar süre saklayacağınız",
|
"logRetentionConnectionLabel": "Bağlantı kayıtlarını ne kadar süre saklayacağınız",
|
||||||
"logRetentionConnectionDescription": "Bağlantı kayıtlarını ne kadar süre saklayacağınız",
|
"logRetentionConnectionDescription": "Bağlantı kayıtlarını ne kadar süre saklayacağınız",
|
||||||
|
"logRetentionAISessionsLabel": "AI Ağ Geçidi Oturum Günlüğü Saklama Süresi",
|
||||||
|
"logRetentionAISessionsDescription": "AI ağ geçidi istem/yanıt oturum günlüklerinin ne kadar süreyle saklanacağını belirleyin",
|
||||||
"logRetentionDisabled": "Devre Dışı",
|
"logRetentionDisabled": "Devre Dışı",
|
||||||
"logRetention3Days": "3 gün",
|
"logRetention3Days": "3 gün",
|
||||||
"logRetention7Days": "7 gün",
|
"logRetention7Days": "7 gün",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "Kaynak Adresi",
|
"sourceAddress": "Kaynak Adresi",
|
||||||
"destinationAddress": "Hedef Adresi",
|
"destinationAddress": "Hedef Adresi",
|
||||||
"duration": "Süre",
|
"duration": "Süre",
|
||||||
"licenseRequiredToUse": "Bu özelliği kullanmak için bir <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> lisansı veya <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> gereklidir. <bookADemoLink>Tanıtım veya POC denemesi ayarlayın</bookADemoLink>.",
|
"licenseRequiredToUse": "<enterpriseEditionLink>Kurumsal Sürüm lisansı</enterpriseEditionLink> gereklidir. <bookADemoLink>Bir demo veya deneme rezervasyonu yapın</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "Bu özelliği kullanmak için <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> gereklidir. Bu özellik ayrıca <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>’da da mevcuttur. <bookADemoLink>Tanıtım veya POC denemesi ayarlayın</bookADemoLink>.",
|
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Kurumsal Sürüm lisansı</enterpriseEditionLink> gereklidir. <bookADemoLink>Bir demo veya deneme rezervasyonu yapın</bookADemoLink>",
|
||||||
"certResolver": "Sertifika Çözücü",
|
"certResolver": "Sertifika Çözücü",
|
||||||
"certResolverDescription": "Bu kaynak için kullanılacak sertifika çözücüsünü seçin.",
|
"certResolverDescription": "Bu kaynak için kullanılacak sertifika çözücüsünü seçin.",
|
||||||
"selectCertResolver": "Sertifika Çözücü Seçin",
|
"selectCertResolver": "Sertifika Çözücü Seçin",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "Birden fazla site seçmek, yüksek kullanılabilirlik için dirençli yönlendirme ve yedeklik sağlar.",
|
"internalResourceFormMultiSiteRoutingHelp": "Birden fazla site seçmek, yüksek kullanılabilirlik için dirençli yönlendirme ve yedeklik sağlar.",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Daha fazla bilgi",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Daha fazla bilgi",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "Belirtilen TCP/UDP portlarına erişimi kısıtlayın veya tüm portlara izin/engelleme verin.",
|
"editInternalResourceDialogPortRestrictionsDescription": "Belirtilen TCP/UDP portlarına erişimi kısıtlayın veya tüm portlara izin/engelleme verin.",
|
||||||
"createInternalResourceDialogHttpConfiguration": "HTTP yapılandırması",
|
"createInternalResourceDialogHttpConfiguration": "Alan Adı Yapılandırması",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "HTTP veya HTTPS üzerinden bu kaynağa ulaşmak için istemcilerin kullanacağı alan adını seçin.",
|
"createInternalResourceDialogHttpConfigurationDescription": "HTTP veya HTTPS üzerinden bu kaynağa ulaşmak için istemcilerin kullanacağı alan adını seçin.",
|
||||||
"editInternalResourceDialogHttpConfiguration": "HTTP yapılandırması",
|
"editInternalResourceDialogHttpConfiguration": "Alan Adı Yapılandırması",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "HTTP veya HTTPS üzerinden bu kaynağa ulaşmak için istemcilerin kullanacağı alan adını seçin.",
|
"editInternalResourceDialogHttpConfigurationDescription": "HTTP veya HTTPS üzerinden bu kaynağa ulaşmak için istemcilerin kullanacağı alan adını seçin.",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "Etiketsiz",
|
"resourceLauncherUnlabeled": "Etiketsiz",
|
||||||
|
"resourceLauncherAiGateway": "AI Ağ Geçidi",
|
||||||
"resourceLauncherNoSite": "Site Yok",
|
"resourceLauncherNoSite": "Site Yok",
|
||||||
|
"resourceLauncherAvailableModels": "Mevcut Modeller",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "Bu AI ağ geçidiyle kullanabileceğiniz modeller.",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "Bu kaynak için hiçbir model mevcut değil.",
|
||||||
|
"resourceLauncherAvailableModelsError": "Mevcut modeller yüklenemedi.",
|
||||||
|
"resourceLauncherApiKeys": "API Anahtarları",
|
||||||
|
"resourceLauncherApiKeysDescription": "Bu kaynakla kimlik doğrulamak için kimlik anahtarınızı veya atanmış bir anahtarı kullanın.",
|
||||||
|
"resourceLauncherApiKeysIdentity": "Kimlik Anahtarı",
|
||||||
|
"resourceLauncherApiKeysManual": "Atanmış Anahtarlar",
|
||||||
|
"resourceLauncherApiKeysEmpty": "Bu kaynak için hiçbir API anahtarı mevcut değil.",
|
||||||
|
"resourceLauncherApiKeysError": "API anahtarları yüklenemedi.",
|
||||||
"resourceLauncherNoResourcesInGroup": "Bu grupta kaynak yok",
|
"resourceLauncherNoResourcesInGroup": "Bu grupta kaynak yok",
|
||||||
"resourceLauncherEmptyStateTitle": "Kullanılabilir Kaynak Yok",
|
"resourceLauncherEmptyStateTitle": "Kullanılabilir Kaynak Yok",
|
||||||
"resourceLauncherEmptyStateDescription": "Henüz hiçbir kaynağa erişiminiz yok. Erişim istemek için yöneticinizle iletişime geçin.",
|
"resourceLauncherEmptyStateDescription": "Henüz hiçbir kaynağa erişiminiz yok. Erişim istemek için yöneticinizle iletişime geçin.",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "Başlatıcı görünümü silinemedi. Lütfen tekrar deneyin.",
|
"resourceLauncherViewDeleteFailedDescription": "Başlatıcı görünümü silinemedi. Lütfen tekrar deneyin.",
|
||||||
"memberPortalPrevious": "Önceki",
|
"memberPortalPrevious": "Önceki",
|
||||||
"memberPortalNext": "Sonraki",
|
"memberPortalNext": "Sonraki",
|
||||||
"httpSettings": "HTTP Ayarları",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "TCP Ayarları",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "UDP Ayarları",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "Güvenli bir bağlantı kuruluyor…",
|
"sshConnectingDescription": "Güvenli bir bağlantı kuruluyor…",
|
||||||
"sshConnecting": "Bağlanılıyor…",
|
"sshConnecting": "Bağlanılıyor…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "Yükleme başarısız",
|
"rdpUploadFailed": "Yükleme başarısız",
|
||||||
"rdpUnicodeKeyboardMode": "Unicode klavye modu",
|
"rdpUnicodeKeyboardMode": "Unicode klavye modu",
|
||||||
"sessionToolbarShow": "Araç çubuğunu göster",
|
"sessionToolbarShow": "Araç çubuğunu göster",
|
||||||
"sessionToolbarHide": "Araç çubuğunu gizle"
|
"sessionToolbarHide": "Araç çubuğunu gizle",
|
||||||
|
"actionUpdateSiteApprovals": "Site Onaylarını Güncelle"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"inviteLoginUser": "请确保您以正确的用户登录。",
|
"inviteLoginUser": "请确保您以正确的用户登录。",
|
||||||
"inviteErrorNoUser": "很抱歉,但看起来你想访问的邀请不是一个存在的用户。",
|
"inviteErrorNoUser": "很抱歉,但看起来你想访问的邀请不是一个存在的用户。",
|
||||||
"inviteCreateUser": "请先创建一个帐户。",
|
"inviteCreateUser": "请先创建一个帐户。",
|
||||||
|
"inviteErrorOidcNotAllowed": "邀请只能由内部账户接受。退出登录,使用该电子邮件的密码登录。",
|
||||||
|
"inviteLoginInternalOnly": "邀请需要具有密码的内部账户。请创建账户或使用密码登录。",
|
||||||
"goHome": "返回首页",
|
"goHome": "返回首页",
|
||||||
"inviteLogInOtherUser": "以不同的用户登录",
|
"inviteLogInOtherUser": "以不同的用户登录",
|
||||||
"createAnAccount": "创建帐户",
|
"createAnAccount": "创建帐户",
|
||||||
@@ -178,7 +180,7 @@
|
|||||||
"shareDeleteConfirm": "确认删除共享链接",
|
"shareDeleteConfirm": "确认删除共享链接",
|
||||||
"shareQuestionRemove": "您确定要删除这个共享链接吗?",
|
"shareQuestionRemove": "您确定要删除这个共享链接吗?",
|
||||||
"shareMessageRemove": "删除后,该链接将不再可用,使用它的任何人将失去对资源的访问权限。",
|
"shareMessageRemove": "删除后,该链接将不再可用,使用它的任何人将失去对资源的访问权限。",
|
||||||
"shareTokenDescription": "访问令牌可以通过两种方式传递:作为查询参数或请求标题。 每次验证访问请求都必须从客户端传递。",
|
"shareTokenDescription": "访问令牌可以作为查询参数或请求头传递。默认情况下,它必须在每次请求时发送。如果启用了会话持久性,则第一个请求会将其交换为会话cookie。",
|
||||||
"accessToken": "访问令牌",
|
"accessToken": "访问令牌",
|
||||||
"usageExamples": "用法示例",
|
"usageExamples": "用法示例",
|
||||||
"tokenId": "令牌 ID",
|
"tokenId": "令牌 ID",
|
||||||
@@ -196,8 +198,14 @@
|
|||||||
"shareTitleOptional": "标题 (可选)",
|
"shareTitleOptional": "标题 (可选)",
|
||||||
"sharePathOptional": "路径(可选)",
|
"sharePathOptional": "路径(可选)",
|
||||||
"sharePathDescription": "认证后,链接将把用户重定向到此路径。",
|
"sharePathDescription": "认证后,链接将把用户重定向到此路径。",
|
||||||
|
"shareAssociateUserOptional": "关联用户(可选)",
|
||||||
|
"shareAssociateUserDescription": "设置后,使用此链接的请求将在访问日志和身份头中归属于用户。如果用户离开组织,则该链接将被删除。",
|
||||||
|
"userSelect": "选择用户",
|
||||||
|
"usersNotFound": "未找到用户",
|
||||||
"expireIn": "过期时间",
|
"expireIn": "过期时间",
|
||||||
"neverExpire": "永不过期",
|
"neverExpire": "永不过期",
|
||||||
|
"sharePersistSession": "首次使用后会话持久化",
|
||||||
|
"sharePersistSessionDescription": "启用后,通过查询参数或头部携带此令牌的首次请求会设置会话cookie,因此后续请求不需要令牌。对于应在每次请求中发送令牌的API客户端,请保持关闭。",
|
||||||
"shareExpireDescription": "过期时间是链接可以使用并提供对资源的访问时间。 此时间后,链接将不再工作,使用此链接的用户将失去对资源的访问。",
|
"shareExpireDescription": "过期时间是链接可以使用并提供对资源的访问时间。 此时间后,链接将不再工作,使用此链接的用户将失去对资源的访问。",
|
||||||
"shareSeeOnce": "您只能看到一次此链接。请确保复制它。",
|
"shareSeeOnce": "您只能看到一次此链接。请确保复制它。",
|
||||||
"shareAccessHint": "任何具有此链接的人都可以访问该资源。小心地分享它。",
|
"shareAccessHint": "任何具有此链接的人都可以访问该资源。小心地分享它。",
|
||||||
@@ -280,7 +288,21 @@
|
|||||||
"noCountryFound": "找不到国家。",
|
"noCountryFound": "找不到国家。",
|
||||||
"siteSelectionDescription": "此站点将为目标提供连接。",
|
"siteSelectionDescription": "此站点将为目标提供连接。",
|
||||||
"resourceType": "资源类型",
|
"resourceType": "资源类型",
|
||||||
"resourceTypeDescription": "这会控制资源协议及其在浏览器中的渲染方式。之后不能更改。",
|
"resourceTypeDescription": "此功能控制资源协议,之后无法更改。",
|
||||||
|
"resourceTypeSearch": "搜索资源类型……",
|
||||||
|
"resourceTypeNotFound": "未找到资源类型",
|
||||||
|
"resourceTypeHttpDescription": "使用域名通过HTTPS代理网络流量",
|
||||||
|
"resourceTypeInferenceDescription": "通过附加的提供者处理AI请求",
|
||||||
|
"resourceTypeSshDescription": "从浏览器访问SSH服务器",
|
||||||
|
"resourceTypeRdpDescription": "从浏览器访问远程桌面",
|
||||||
|
"resourceTypeVncDescription": "从浏览器访问VNC桌面",
|
||||||
|
"resourceTypeTcpDescription": "使用端口号代理原始TCP流量",
|
||||||
|
"resourceTypeUdpDescription": "使用端口号代理原始UDP流量",
|
||||||
|
"privateResourceTypeDescription": "此功能控制客户端访问资源的方式,之后无法更改。",
|
||||||
|
"privateResourceTypeHostDescription": "在站点网络上向连接的客户端暴露单个主机",
|
||||||
|
"privateResourceTypeCidrDescription": "在站点网络上向连接的客户端暴露CIDR范围",
|
||||||
|
"privateResourceTypeHttpDescription": "通过域访问HTTP或HTTPS服务",
|
||||||
|
"privateResourceTypeSshDescription": "从连接的客户端访问SSH服务器",
|
||||||
"resourceDomainDescription": "资源将在此完全限定的域名上提供。",
|
"resourceDomainDescription": "资源将在此完全限定的域名上提供。",
|
||||||
"resourceHTTPSSettings": "HTTPS 设置",
|
"resourceHTTPSSettings": "HTTPS 设置",
|
||||||
"resourceHTTPSSettingsDescription": "配置如何通过 HTTPS 访问资源",
|
"resourceHTTPSSettingsDescription": "配置如何通过 HTTPS 访问资源",
|
||||||
@@ -449,8 +471,14 @@
|
|||||||
"provisioningManage": "预配",
|
"provisioningManage": "预配",
|
||||||
"provisioningDescription": "管理预配密钥,并审核待批准的站点。",
|
"provisioningDescription": "管理预配密钥,并审核待批准的站点。",
|
||||||
"pendingSites": "待审批站点",
|
"pendingSites": "待审批站点",
|
||||||
"siteApproveSuccess": "站点批准成功",
|
"siteApproveSuccess": "站点及相关资源已成功审批",
|
||||||
"siteApproveError": "批准站点出错",
|
"siteApproveError": "批准站点出错",
|
||||||
|
"siteReject": "拒绝站点",
|
||||||
|
"siteQuestionReject": "您确定要拒绝此站点吗?",
|
||||||
|
"siteMessageReject": "这将永久删除站点及所有尚未处理的相关资源。",
|
||||||
|
"siteConfirmReject": "确认拒绝站点",
|
||||||
|
"siteRejectSuccess": "站点已被成功拒绝",
|
||||||
|
"siteRejectError": "拒绝站点时出错",
|
||||||
"provisioningKeys": "置备键",
|
"provisioningKeys": "置备键",
|
||||||
"searchProvisioningKeys": "搜索配备密钥...",
|
"searchProvisioningKeys": "搜索配备密钥...",
|
||||||
"provisioningKeysAdd": "生成预配密钥",
|
"provisioningKeysAdd": "生成预配密钥",
|
||||||
@@ -466,8 +494,8 @@
|
|||||||
"provisioningKeysSave": "保存预配键",
|
"provisioningKeysSave": "保存预配键",
|
||||||
"provisioningKeysSaveDescription": "您只能看到一次。复制它到一个安全的地方。",
|
"provisioningKeysSaveDescription": "您只能看到一次。复制它到一个安全的地方。",
|
||||||
"provisioningKeysErrorCreate": "创建预配键时出错",
|
"provisioningKeysErrorCreate": "创建预配键时出错",
|
||||||
"provisioningKeysList": "新建预配键",
|
"provisioningKeysList": "新预配密钥",
|
||||||
"provisioningKeysMaxBatchSize": "最大批量大小",
|
"provisioningKeysMaxBatchSize": "最大批次大小",
|
||||||
"provisioningKeysUnlimitedBatchSize": "无限批量大小(无限制)",
|
"provisioningKeysUnlimitedBatchSize": "无限批量大小(无限制)",
|
||||||
"provisioningKeysMaxBatchUnlimited": "无限制",
|
"provisioningKeysMaxBatchUnlimited": "无限制",
|
||||||
"provisioningKeysMaxBatchSizeInvalid": "输入一个有效的最大批处理大小(1-1,000,000)。",
|
"provisioningKeysMaxBatchSizeInvalid": "输入一个有效的最大批处理大小(1-1,000,000)。",
|
||||||
@@ -480,7 +508,7 @@
|
|||||||
"provisioningKeysNeverUsed": "永不过期",
|
"provisioningKeysNeverUsed": "永不过期",
|
||||||
"provisioningKeysEdit": "编辑置备键",
|
"provisioningKeysEdit": "编辑置备键",
|
||||||
"provisioningKeysEditDescription": "更新此密钥的最大批量大小和过期时间。",
|
"provisioningKeysEditDescription": "更新此密钥的最大批量大小和过期时间。",
|
||||||
"provisioningKeysApproveNewSites": "批准新节点",
|
"provisioningKeysApproveNewSites": "批准新站点",
|
||||||
"provisioningKeysApproveNewSitesDescription": "自动批准使用此密钥注册的节点。",
|
"provisioningKeysApproveNewSitesDescription": "自动批准使用此密钥注册的节点。",
|
||||||
"provisioningKeysUpdateError": "更新预配键时出错",
|
"provisioningKeysUpdateError": "更新预配键时出错",
|
||||||
"provisioningKeysUpdated": "置备密钥已更新",
|
"provisioningKeysUpdated": "置备密钥已更新",
|
||||||
@@ -843,12 +871,16 @@
|
|||||||
"authMethodsSave": "保存设置",
|
"authMethodsSave": "保存设置",
|
||||||
"policyAuthStackTitle": "身份验证",
|
"policyAuthStackTitle": "身份验证",
|
||||||
"policyAuthStackDescription": "控制哪些身份验证方法需由用户执行才能访问资源",
|
"policyAuthStackDescription": "控制哪些身份验证方法需由用户执行才能访问资源",
|
||||||
|
"policyAuthInferenceStackDescription": "选择哪些用户和角色可以对这个AI网关进行验证",
|
||||||
"policyAuthOrLogicTitle": "多种身份验证方法处于激活状态",
|
"policyAuthOrLogicTitle": "多种身份验证方法处于激活状态",
|
||||||
"policyAuthOrLogicBanner": "访问者可以使用下列任意激活的方法进行身份验证。无需完成全部过程。",
|
"policyAuthOrLogicBanner": "访问者可以使用下列任意激活的方法进行身份验证。无需完成全部过程。",
|
||||||
"policyAuthMethodActive": "激活",
|
"policyAuthMethodActive": "激活",
|
||||||
"policyAuthMethodOff": "关闭",
|
"policyAuthMethodOff": "关闭",
|
||||||
"policyAuthSsoTitle": "平台单点登录 SSO",
|
"policyAuthSsoTitle": "平台单点登录 SSO",
|
||||||
"policyAuthSsoDescription": "要求通过您组织的身份提供商登录",
|
"policyAuthSsoDescription": "要求通过您组织的身份提供商登录",
|
||||||
|
"policyAuthInferenceIdentityKeySignInUrl": "登录URL",
|
||||||
|
"policyAuthInferenceIdentityKeyHelpNoUrl": "每个用户已经拥有一个身份API密钥,因此您只需要为非用户客户端或共享访问创建虚拟API密钥。用户可以通过在此资源的URL中登录其身份提供者来检索其密钥,登录后将显示。",
|
||||||
|
"policyAuthInferenceIdentityKeyHelp": "每个用户已经拥有一个身份API密钥,因此您只需要为非用户客户端或共享访问创建虚拟API密钥。用户可在登录其身份提供者后在此处获取其密钥。",
|
||||||
"policyAuthSsoSummary": "{idp} · {users} 个用户, {roles} 个角色",
|
"policyAuthSsoSummary": "{idp} · {users} 个用户, {roles} 个角色",
|
||||||
"policyAuthSsoDefaultIdp": "默认提供商",
|
"policyAuthSsoDefaultIdp": "默认提供商",
|
||||||
"policyAuthAddDefaultIdentityProvider": "添加默认身份提供商",
|
"policyAuthAddDefaultIdentityProvider": "添加默认身份提供商",
|
||||||
@@ -922,7 +954,7 @@
|
|||||||
"newtVersion": "版本",
|
"newtVersion": "版本",
|
||||||
"architecture": "架构",
|
"architecture": "架构",
|
||||||
"sites": "站点",
|
"sites": "站点",
|
||||||
"siteWgAnyClients": "使用任何 WireGuard 客户端连接。您必须使用对等IP解决内部资源问题。",
|
"siteWgAnyClients": "使用任何WireGuard客户端进行连接。您必须使用对等IP来处理私有资源。",
|
||||||
"siteWgCompatibleAllClients": "与所有WireGuard客户端兼容",
|
"siteWgCompatibleAllClients": "与所有WireGuard客户端兼容",
|
||||||
"siteWgManualConfigurationRequired": "需要手动配置",
|
"siteWgManualConfigurationRequired": "需要手动配置",
|
||||||
"userErrorNotAdminOrOwner": "用户不是管理员或所有者",
|
"userErrorNotAdminOrOwner": "用户不是管理员或所有者",
|
||||||
@@ -1067,6 +1099,8 @@
|
|||||||
"accessRoleErrorNewRequired": "需要新角色",
|
"accessRoleErrorNewRequired": "需要新角色",
|
||||||
"accessRoleErrorRemove": "删除角色失败",
|
"accessRoleErrorRemove": "删除角色失败",
|
||||||
"accessRoleErrorRemoveDescription": "删除角色时出错。",
|
"accessRoleErrorRemoveDescription": "删除角色时出错。",
|
||||||
|
"accessRoleInferenceBudget": "AI预算",
|
||||||
|
"accessRoleInferenceBudgetDescription": "配置此角色成员如何根据支出或令牌限制来限制AI使用",
|
||||||
"accessRoleName": "角色名称",
|
"accessRoleName": "角色名称",
|
||||||
"accessRoleQuestionRemove": "您即将删除 `{name}` 角色。此操作无法撤销。",
|
"accessRoleQuestionRemove": "您即将删除 `{name}` 角色。此操作无法撤销。",
|
||||||
"accessRoleRemove": "删除角色",
|
"accessRoleRemove": "删除角色",
|
||||||
@@ -1397,6 +1431,7 @@
|
|||||||
"createOrgUser": "创建组织用户",
|
"createOrgUser": "创建组织用户",
|
||||||
"actionUpdateOrg": "更新组织",
|
"actionUpdateOrg": "更新组织",
|
||||||
"actionRemoveInvitation": "移除邀请",
|
"actionRemoveInvitation": "移除邀请",
|
||||||
|
"actionRemoveUserRole": "移除用户角色",
|
||||||
"actionUpdateUser": "更新用户",
|
"actionUpdateUser": "更新用户",
|
||||||
"actionGetUser": "获取用户",
|
"actionGetUser": "获取用户",
|
||||||
"actionGetOrgUser": "获取组织用户",
|
"actionGetOrgUser": "获取组织用户",
|
||||||
@@ -1411,6 +1446,28 @@
|
|||||||
"actionDeleteSite": "删除站点",
|
"actionDeleteSite": "删除站点",
|
||||||
"actionGetSite": "获取站点",
|
"actionGetSite": "获取站点",
|
||||||
"actionListSites": "站点列表",
|
"actionListSites": "站点列表",
|
||||||
|
"actionCreateAiProvider": "创建AI提供者",
|
||||||
|
"actionDeleteAiProvider": "删除AI提供者",
|
||||||
|
"actionGetAiProvider": "获取AI提供者",
|
||||||
|
"actionListAiProviders": "列出AI提供者",
|
||||||
|
"actionUpdateAiProvider": "更新AI提供者",
|
||||||
|
"actionCreateAiModel": "创建AI模型",
|
||||||
|
"actionDeleteAiModel": "删除AI模型",
|
||||||
|
"actionGetAiModel": "获取AI模型",
|
||||||
|
"actionListAiModels": "列出AI模型",
|
||||||
|
"actionUpdateAiModel": "更新AI模型",
|
||||||
|
"actionCreateAiBudget": "创建AI预算",
|
||||||
|
"actionDeleteAiBudget": "删除AI预算",
|
||||||
|
"actionGetAiBudget": "获取AI预算",
|
||||||
|
"actionListAiBudgets": "列出AI预算",
|
||||||
|
"actionUpdateAiBudget": "更新AI预算",
|
||||||
|
"actionListResourceAiModels": "列出资源AI模型",
|
||||||
|
"actionSetResourceAiModels": "设置资源AI模型",
|
||||||
|
"actionCreateVirtualApiKey": "创建虚拟API密钥",
|
||||||
|
"actionDeleteVirtualApiKey": "删除虚拟API密钥",
|
||||||
|
"actionGetVirtualApiKey": "获取虚拟API密钥",
|
||||||
|
"actionListVirtualApiKeys": "列出虚拟API密钥",
|
||||||
|
"actionUpdateVirtualApiKey": "更新虚拟API密钥",
|
||||||
"actionApplyBlueprint": "应用蓝图",
|
"actionApplyBlueprint": "应用蓝图",
|
||||||
"actionListBlueprints": "列表蓝图",
|
"actionListBlueprints": "列表蓝图",
|
||||||
"actionGetBlueprint": "获取蓝图",
|
"actionGetBlueprint": "获取蓝图",
|
||||||
@@ -1419,6 +1476,8 @@
|
|||||||
"setupTokenDescription": "从服务器控制台输入设置令牌。",
|
"setupTokenDescription": "从服务器控制台输入设置令牌。",
|
||||||
"setupTokenRequired": "需要设置令牌",
|
"setupTokenRequired": "需要设置令牌",
|
||||||
"actionUpdateSite": "更新站点",
|
"actionUpdateSite": "更新站点",
|
||||||
|
"actionApproveSite": "批准站点",
|
||||||
|
"actionRejectSite": "拒绝站点",
|
||||||
"actionResetSiteBandwidth": "重置组织带宽",
|
"actionResetSiteBandwidth": "重置组织带宽",
|
||||||
"actionListSiteRoles": "允许站点角色列表",
|
"actionListSiteRoles": "允许站点角色列表",
|
||||||
"actionCreateResource": "创建资源",
|
"actionCreateResource": "创建资源",
|
||||||
@@ -1434,8 +1493,11 @@
|
|||||||
"actionSetResourcePincode": "设置资源粉码",
|
"actionSetResourcePincode": "设置资源粉码",
|
||||||
"actionSetResourceEmailWhitelist": "设置资源电子邮件白名单",
|
"actionSetResourceEmailWhitelist": "设置资源电子邮件白名单",
|
||||||
"actionGetResourceEmailWhitelist": "获取资源电子邮件白名单",
|
"actionGetResourceEmailWhitelist": "获取资源电子邮件白名单",
|
||||||
|
"actionListResourcePolicies": "列出资源策略",
|
||||||
|
"actionCreateResourcePolicy": "创建资源策略",
|
||||||
"actionGetResourcePolicy": "获取资源策略",
|
"actionGetResourcePolicy": "获取资源策略",
|
||||||
"actionUpdateResourcePolicy": "更新资源策略",
|
"actionUpdateResourcePolicy": "更新资源策略",
|
||||||
|
"actionDeleteResourcePolicy": "删除资源策略",
|
||||||
"actionSetResourcePolicyUsers": "设置资源策略用户",
|
"actionSetResourcePolicyUsers": "设置资源策略用户",
|
||||||
"actionSetResourcePolicyRoles": "设置资源策略角色",
|
"actionSetResourcePolicyRoles": "设置资源策略角色",
|
||||||
"actionSetResourcePolicyPassword": "设置资源策略密码",
|
"actionSetResourcePolicyPassword": "设置资源策略密码",
|
||||||
@@ -1502,6 +1564,10 @@
|
|||||||
"actionListInvitations": "邀请列表",
|
"actionListInvitations": "邀请列表",
|
||||||
"actionExportLogs": "导出日志",
|
"actionExportLogs": "导出日志",
|
||||||
"actionViewLogs": "查看日志",
|
"actionViewLogs": "查看日志",
|
||||||
|
"actionCreateSiteProvisioningKey": "创建站点预配密钥",
|
||||||
|
"actionListSiteProvisioningKeys": "列出站点预配密钥",
|
||||||
|
"actionUpdateSiteProvisioningKey": "更新站点预配密钥",
|
||||||
|
"actionDeleteSiteProvisioningKey": "删除站点预配密钥",
|
||||||
"noneSelected": "未选择",
|
"noneSelected": "未选择",
|
||||||
"orgNotFound2": "未找到组织。",
|
"orgNotFound2": "未找到组织。",
|
||||||
"search": "搜索…",
|
"search": "搜索…",
|
||||||
@@ -1516,6 +1582,7 @@
|
|||||||
"otpAuthDescription": "从您的身份验证程序中输入代码或您的单次备份代码。",
|
"otpAuthDescription": "从您的身份验证程序中输入代码或您的单次备份代码。",
|
||||||
"otpAuthSubmit": "提交代码",
|
"otpAuthSubmit": "提交代码",
|
||||||
"idpContinue": "或者继续",
|
"idpContinue": "或者继续",
|
||||||
|
"idpLastUsed": "上次使用",
|
||||||
"otpAuthBack": "回到密码",
|
"otpAuthBack": "回到密码",
|
||||||
"navbar": "导航菜单",
|
"navbar": "导航菜单",
|
||||||
"navbarDescription": "应用程序的主导航菜单",
|
"navbarDescription": "应用程序的主导航菜单",
|
||||||
@@ -1540,6 +1607,8 @@
|
|||||||
"commandPaletteCreateMachineClient": "创建机器客户端",
|
"commandPaletteCreateMachineClient": "创建机器客户端",
|
||||||
"commandPaletteCreateAlertRule": "创建警报规则",
|
"commandPaletteCreateAlertRule": "创建警报规则",
|
||||||
"commandPaletteCreateIdentityProvider": "创建身份提供商",
|
"commandPaletteCreateIdentityProvider": "创建身份提供商",
|
||||||
|
"commandPaletteCreateAiProvider": "创建 AI 提供商",
|
||||||
|
"commandPaletteCreateVirtualApiKey": "创建虚拟 API 密钥",
|
||||||
"commandPaletteToggleTheme": "切换主题",
|
"commandPaletteToggleTheme": "切换主题",
|
||||||
"commandPaletteChooseOrganization": "选择组织",
|
"commandPaletteChooseOrganization": "选择组织",
|
||||||
"commandPaletteShortcutMac": "⌘K",
|
"commandPaletteShortcutMac": "⌘K",
|
||||||
@@ -1602,6 +1671,420 @@
|
|||||||
"sidebarInvitations": "邀请",
|
"sidebarInvitations": "邀请",
|
||||||
"sidebarRoles": "角色",
|
"sidebarRoles": "角色",
|
||||||
"sidebarShareableLinks": "共享链接",
|
"sidebarShareableLinks": "共享链接",
|
||||||
|
"sidebarAiGateway": "AI网关",
|
||||||
|
"sidebarAiProviders": "提供者",
|
||||||
|
"commandAiProviders": "AI提供者",
|
||||||
|
"sidebarVirtualApiKeys": "虚拟API密钥",
|
||||||
|
"sidebarMyApiKeys": "您的API密钥",
|
||||||
|
"sidebarAccount": "启动器",
|
||||||
|
"commandVirtualApiKeys": "虚拟API密钥",
|
||||||
|
"virtualApiKeysTitle": "管理虚拟API密钥",
|
||||||
|
"virtualApiKeysDescription": "创建和管理AI网关访问到公共AI网关的手动API密钥",
|
||||||
|
"virtualApiKeysTabIdentity": "身份密钥",
|
||||||
|
"virtualApiKeysTabVirtual": "虚拟密钥",
|
||||||
|
"virtualApiKeysIdentitySplashTitle": "每个用户的身份密钥",
|
||||||
|
"virtualApiKeysIdentitySplashDescription": "每个用户已经拥有此组织的Pangolin身份密钥。它是唯一的,并能够认证他们访问AI网关。",
|
||||||
|
"virtualApiKeysIdentitySplashExample": "示例",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveTitle": "用户如何获取他们的密钥",
|
||||||
|
"virtualApiKeysIdentitySplashRetrieveResource": "访问公共AI网关URL并使用其账户登录。",
|
||||||
|
"virtualApiKeysIdentitySplashRetrievePage": "或在登录时访问<url></url> 。",
|
||||||
|
"virtualApiKeysIdentitySplashManual": "您可以在虚拟密钥标签中创建其他虚拟API密钥。那些密钥可以限定为特定的公共AI网关,并可以选择是否与用户相关联。创建密钥后立即授予对选定公共AI网关的访问权限。",
|
||||||
|
"virtualApiKeysIdentitySplashGoToVirtual": "手动创建密钥",
|
||||||
|
"virtualApiKeysEmailIdentity": "电子邮件身份密钥",
|
||||||
|
"virtualApiKeysEmailIdentityDescription": "向选择的用户或角色发送他们的Pangolin身份密钥。",
|
||||||
|
"virtualApiKeysEmailIdentitySendAll": "发送给所有用户",
|
||||||
|
"virtualApiKeysEmailIdentitySendAllDescription": "向所有有电子邮件账户的组织成员发送电子邮件。",
|
||||||
|
"virtualApiKeysEmailIdentitySelectUsers": "用户",
|
||||||
|
"virtualApiKeysEmailIdentitySelectRoles": "角色",
|
||||||
|
"virtualApiKeysEmailIdentitySubmit": "发送邮件",
|
||||||
|
"virtualApiKeysEmailIdentitySuccess": "身份密钥已发送",
|
||||||
|
"virtualApiKeysEmailIdentitySuccessDescription": "已发送 {sent} 封电子邮件。",
|
||||||
|
"virtualApiKeysEmailIdentitySkipped": "{skipped} 个用户已被跳过,因为他们没有电子邮件地址。",
|
||||||
|
"virtualApiKeysEmailIdentityRecipientsRequired": "至少选择一个用户或角色,或发送给所有用户。",
|
||||||
|
"virtualApiKeysEmailIdentityError": "发送身份密钥出错",
|
||||||
|
"virtualApiKeysEmailIdentityErrorDescription": "未能发送身份密钥邮件",
|
||||||
|
"virtualApiKeysBannerTitle": "每个用户的身份密钥",
|
||||||
|
"virtualApiKeysBannerDescription": "每个用户都可以在{keysUrl}获取一个身份密钥。您也可以在这里手动生成密钥以直接访问公共AI网关。",
|
||||||
|
"virtualApiKeysBannerButtonText": "查看身份密钥",
|
||||||
|
"virtualApiKeys": "虚拟API 密钥",
|
||||||
|
"virtualApiKeysSearch": "搜索密钥……",
|
||||||
|
"virtualApiKeysCreate": "创建虚拟API密钥",
|
||||||
|
"virtualApiKeysCreateDescription": "创建一个手动密钥,用于调用本组织内的公共AI网关",
|
||||||
|
"virtualApiKeysCreateButton": "创建密钥",
|
||||||
|
"virtualApiKeysEmpty": "尚无虚拟API密钥",
|
||||||
|
"virtualApiKeysName": "名称",
|
||||||
|
"virtualApiKeysDescriptionOptional": "描述(可选)",
|
||||||
|
"virtualApiKeysAssociateUserOptional": "关联用户(可选)",
|
||||||
|
"virtualApiKeysAssociateUserDescription": "将此密钥与用户相关联以跟踪使用情况。创建后,此密钥立即授予对所选公共AI网关的访问权限。无需手动将用户与资源相关联。该密钥还会在用户的个人资料中显示。",
|
||||||
|
"virtualApiKeysAllResources": "所有公共AI网关",
|
||||||
|
"virtualApiKeysAllResourcesDescription": "允许此密钥访问组织中的所有公共AI网关",
|
||||||
|
"virtualApiKeysSelectResources": "公共AI网关",
|
||||||
|
"virtualApiKeysSelectResourcesPlaceholder": "选择资源",
|
||||||
|
"virtualApiKeysSelectResourcesDescription": "选择此密钥可以访问的公共AI网关",
|
||||||
|
"virtualApiKeysNoResources": "无资源",
|
||||||
|
"virtualApiKeysSecret": "密钥",
|
||||||
|
"virtualApiKeysCopyKey": "复制此密钥。您可以稍后从表或编辑时查看。",
|
||||||
|
"virtualApiKeysViewSecret": "查看密钥",
|
||||||
|
"virtualApiKeysViewSecretTitle": "虚拟API密钥密钥",
|
||||||
|
"virtualApiKeysViewSecretDescription": "此密钥允许访问分配给此密钥的公共AI网关",
|
||||||
|
"virtualApiKeysEdit": "编辑虚拟API密钥",
|
||||||
|
"virtualApiKeysEditDescription": "更新该密钥的关联用户和公共AI网关访问",
|
||||||
|
"virtualApiKeysSaveButton": "保存更改",
|
||||||
|
"virtualApiKeysSelectResourcesRequired": "选择至少一个公共AI网关,或启用所有公共AI网关",
|
||||||
|
"virtualApiKeysUpdated": "虚拟API密钥已更新",
|
||||||
|
"virtualApiKeysUpdatedDescription": "虚拟API密钥已更新",
|
||||||
|
"virtualApiKeysErrorUpdate": "更新虚拟API密钥出错",
|
||||||
|
"virtualApiKeysErrorUpdateDescription": "未能更新虚拟API密钥",
|
||||||
|
"virtualApiKeysErrorCreate": "创建虚拟API密钥出错",
|
||||||
|
"virtualApiKeysErrorCreateDescription": "未能创建虚拟API密钥",
|
||||||
|
"virtualApiKeysErrorDelete": "删除虚拟API密钥出错",
|
||||||
|
"virtualApiKeysErrorDeleteMessage": "未能删除虚拟API密钥",
|
||||||
|
"virtualApiKeysDeleted": "虚拟API密钥已删除",
|
||||||
|
"virtualApiKeysDeletedDescription": "虚拟API密钥已删除",
|
||||||
|
"virtualApiKeysDelete": "删除虚拟API密钥",
|
||||||
|
"virtualApiKeysDeleteConfirm": "删除密钥",
|
||||||
|
"virtualApiKeysQuestionRemove": "您确定要删除此虚拟 API 密钥吗?",
|
||||||
|
"virtualApiKeysMessageRemove": "使用此密钥的客户端将立即失去访问权限。",
|
||||||
|
"virtualApiKeysErrorFetchSecret": "加载密钥出错",
|
||||||
|
"virtualApiKeysErrorFetchSecretDescription": "未能加载虚拟API密钥",
|
||||||
|
"virtualApiKeysFilterUnassigned": "未分配",
|
||||||
|
"virtualApiKeysInferenceBudget": "预算",
|
||||||
|
"virtualApiKeysInferenceBudgetDescription": "根据支出或令牌限制配置此密钥限制AI使用的方法",
|
||||||
|
"virtualApiKeysEmailOnGenerate": "生成密钥后发送邮件",
|
||||||
|
"virtualApiKeysEmailThisKey": "发送密钥邮件",
|
||||||
|
"virtualApiKeysEmailOnGenerateDescription": "密钥创建后将其发送给关联用户及其他地址",
|
||||||
|
"virtualApiKeysEmailThisKeyDescription": "将当前密钥发送给关联用户及其他地址",
|
||||||
|
"virtualApiKeysEmailSmtpRequired": "此服务器上未配置邮件",
|
||||||
|
"virtualApiKeysEmailSmtpRequiredDescription": "配置SMTP以发送虚拟API密钥。",
|
||||||
|
"virtualApiKeysEmailSendToUser": "发送给关联用户",
|
||||||
|
"virtualApiKeysEmailSendToUserDescription": "将密钥发送到与关联用户的账户邮箱",
|
||||||
|
"virtualApiKeysEmailSendToUserDisabled": "关联一个用户以将密钥发送给该用户",
|
||||||
|
"virtualApiKeysEmailAdditional": "附加电子邮件",
|
||||||
|
"virtualApiKeysEmailAdditionalPlaceholder": "添加电子邮件,然后按回车键",
|
||||||
|
"virtualApiKeysEmailRecipientsRequired": "选择关联用户,或至少添加一个电子邮件地址",
|
||||||
|
"myVirtualApiKeysTitle": "您的API密钥",
|
||||||
|
"myVirtualApiKeysDescription": "查看属于您的身份密钥和任何虚拟API密钥",
|
||||||
|
"myVirtualApiKeysResourceTitle": "与{resourceName}有关的您的API密钥",
|
||||||
|
"myVirtualApiKeysResourceDescription": "查看属于您的身份密钥和可访问{resourceName}的虚拟API密钥",
|
||||||
|
"myVirtualApiKeysIdentityTitle": "身份密钥",
|
||||||
|
"myVirtualApiKeysIdentityHeadline": "您的个人API密钥",
|
||||||
|
"myVirtualApiKeysIdentityDescription": "这是此组织的个人密钥。它是独一无二的并且用于在调用AI网关资源时识别您。",
|
||||||
|
"myVirtualApiKeysIdentityResourceHeadline": "与{resourceName}有关的您的个人API密钥",
|
||||||
|
"myVirtualApiKeysIdentityResourceDescription": "这是此组织的个人密钥。用于调用{resourceName}。",
|
||||||
|
"myVirtualApiKeysManualTitle": "分配的密钥",
|
||||||
|
"myVirtualApiKeysManualDescription": "管理员与您的账户相关的手动虚拟API密钥",
|
||||||
|
"myVirtualApiKeysManualResourceDescription": "手动虚拟API密钥与您的账户相关并可以访问{resourceName}",
|
||||||
|
"myVirtualApiKeysManualEmpty": "尚无分配的密钥",
|
||||||
|
"myVirtualApiKeysKindUser": "身份",
|
||||||
|
"myVirtualApiKeysKindManual": "手动",
|
||||||
|
"myVirtualApiKeysUnnamed": "未命名的密钥",
|
||||||
|
"myVirtualApiKeysRevealSecret": "显示密钥",
|
||||||
|
"myVirtualApiKeysViewSecretDescription": "此密钥认证您访问AI网关资源",
|
||||||
|
"aiClientConfigTitle": "配置编码代理",
|
||||||
|
"aiClientConfigDescription": "复制流行编码代理的配置,或让 Pangolin CLI 为您自动设置。",
|
||||||
|
"aiClientConfigDescriptionClaude": "Anthropic 的终端代理编码工具。",
|
||||||
|
"aiClientConfigDescriptionCodex": "OpenAI 的终端代理编码工具。",
|
||||||
|
"aiClientConfigDescriptionOpencode": "开源终端编码代理。",
|
||||||
|
"aiClientConfigDescriptionCursor": "基于 VS Code 的 AI 代码编辑器。",
|
||||||
|
"aiClientConfigSetup": "设置",
|
||||||
|
"aiClientConfigTabCli": "自动 (CLI)",
|
||||||
|
"aiClientConfigTabManual": "手动配置",
|
||||||
|
"aiClientConfigPreset": "配置",
|
||||||
|
"aiClientConfigStep": "步骤 {number}",
|
||||||
|
"aiClientConfigEndpointPlaceholder": "https://example.resource.url.com",
|
||||||
|
"aiClientConfigPlaceholderWarning": "此片段包含示例值,如模型名称或资源 URL。在使用前代替它们为您自己的值。",
|
||||||
|
"aiClientConfigRevealError": "无法加载您的 API 密钥。",
|
||||||
|
"aiClientConfigRevealRetry": "再试一次",
|
||||||
|
"resourceGeneralAiClientConfigDescription": "此资源可用于通用客户端,例如 Claude Code 和 OpenCode。<configLink>了解更多</configLink>",
|
||||||
|
"aiProvidersTitle": "AI提供者",
|
||||||
|
"aiProvidersDescription": "连接模型提供者用于本组织的AI工作负载",
|
||||||
|
"aiProvidersBannerTitle": "连接模型提供者",
|
||||||
|
"aiProvidersBannerDescription": "提供商是Pangolin用于AI工作负载的模型后端。在此处连接OpenAI、Anthropic和其他提供者,然后将其附加到公共AI网关,以便用户可以进行身份识别访问、设置预算并记录日志。",
|
||||||
|
"aiProvidersAdd": "添加提供者",
|
||||||
|
"aiProvidersSearch": "搜索提供者……",
|
||||||
|
"aiProvidersEmpty": "尚无AI提供者",
|
||||||
|
"aiProviderCreate": "创建AI提供者",
|
||||||
|
"aiProviderCreateDescription": "为此组织添加一个模型提供者",
|
||||||
|
"aiProviderSeeAll": "查看所有提供者",
|
||||||
|
"aiProviderSetting": "{providerName}的提供者设置",
|
||||||
|
"aiProviderSettingDescription": "配置此AI提供者",
|
||||||
|
"aiProviderGeneral": "概览",
|
||||||
|
"aiProviderGeneralDescription": "此提供者的基础设置",
|
||||||
|
"aiProviderConfiguration": "配置",
|
||||||
|
"aiProviderConfigurationDescription": "此提供者的网络路由和认证",
|
||||||
|
"aiProviderNetworkSettings": "网络设置",
|
||||||
|
"aiProviderNetworkSettingsDescription": "选择流量到达此提供者的方式",
|
||||||
|
"aiProviderAuthSettings": "认证",
|
||||||
|
"aiProviderAuthSettingsDescription": "配置此提供者如何认证其上游URL的请求",
|
||||||
|
"aiProviderBudgetSettings": "预算",
|
||||||
|
"aiProviderBudgetSettingsDescription": "根据支出或令牌限制配置此提供者限制使用的方法",
|
||||||
|
"aiBudgetAdd": "添加预算",
|
||||||
|
"aiBudgetEmpty": "尚未设置预算。单击“添加预算”以设置支出或令牌限制。",
|
||||||
|
"aiBudgetUnit": "支出类型",
|
||||||
|
"aiBudgetPeriod": "重置周期",
|
||||||
|
"aiBudgetAmount": "最大发电",
|
||||||
|
"aiBudgetAmountPlaceholder": "最大发电",
|
||||||
|
"aiBudgetPeriodHourly": "每小时",
|
||||||
|
"aiBudgetPeriodDaily": "每日",
|
||||||
|
"aiBudgetPeriodWeekly": "每周",
|
||||||
|
"aiBudgetPeriodMonthly": "每月",
|
||||||
|
"aiBudgetPeriodYearly": "每年",
|
||||||
|
"aiBudgetPeriodLifetime": "终身",
|
||||||
|
"aiBudgetUnitUsd": "美元",
|
||||||
|
"aiBudgetUnitTokens": "令牌",
|
||||||
|
"aiBudgetConflictError": "此重置周期和支出类型的预算已存在",
|
||||||
|
"aiBudgetInvalidAmountError": "输入大于0的最大支出",
|
||||||
|
"aiBudgetUpdated": "预算已更新",
|
||||||
|
"aiBudgetErrorSave": "未能更新预算",
|
||||||
|
"aiProviderType": "提供者类型",
|
||||||
|
"aiProviderTypeSearch": "搜索提供者……",
|
||||||
|
"aiProviderTypeNotFound": "未找到提供者类型",
|
||||||
|
"aiProviderTypeOpenai": "OpenAI",
|
||||||
|
"aiProviderTypeAnthropic": "Anthropic",
|
||||||
|
"aiProviderTypeGoogleGemini": "Google Gemini",
|
||||||
|
"aiProviderTypeVertexAi": "Vertex AI",
|
||||||
|
"aiProviderTypeBedrock": "Amazon Bedrock",
|
||||||
|
"aiProviderTypeMicrosoftFoundry": "Microsoft Foundry",
|
||||||
|
"aiProviderTypeOpenRouter": "OpenRouter",
|
||||||
|
"aiProviderTypeVercelAiGateway": "Vercel AI Gateway",
|
||||||
|
"aiProviderTypeCustom": "自定义",
|
||||||
|
"aiProviderTypeOpenaiDescription": "OpenAI API",
|
||||||
|
"aiProviderTypeAnthropicDescription": "Anthropic API",
|
||||||
|
"aiProviderTypeGoogleGeminiDescription": "Google Gemini API",
|
||||||
|
"aiProviderTypeVertexAiDescription": "Google Vertex AI API",
|
||||||
|
"aiProviderTypeBedrockDescription": "Amazon Bedrock 运行时 API",
|
||||||
|
"aiProviderTypeMicrosoftFoundryDescription": "Microsoft Foundry API",
|
||||||
|
"aiProviderTypeOpenRouterDescription": "OpenRouter API",
|
||||||
|
"aiProviderTypeVercelAiGatewayDescription": "Vercel AI Gateway API",
|
||||||
|
"aiProviderTypeCustomDescription": "使用您自己的端点或通过站点目标进行路由",
|
||||||
|
"aiProviderUpstreamUrl": "上游URL",
|
||||||
|
"aiProviderUpstreamUrlDescription": "提供商API的基础URL",
|
||||||
|
"aiProviderUpstreamUrlOptionalDescription": "留空以使用此提供商的默认上游URL",
|
||||||
|
"aiProviderEffectiveUpstreamUrl": "有效上游URL",
|
||||||
|
"aiProviderApiKey": "API密钥",
|
||||||
|
"aiProviderApiKeyDescription": "用于对请求进行身份验证的API密钥",
|
||||||
|
"aiProviderCustomHeadersDescription": "每次请求时发送的头部。换行分隔:头部名称:值",
|
||||||
|
"aiProviderApiKeyLastChars": "API密钥",
|
||||||
|
"aiProviderAuthType": "身份验证类型",
|
||||||
|
"aiProviderAuthTypeSearch": "搜索身份验证类型……",
|
||||||
|
"aiProviderAuthTypeNotFound": "未找到身份验证类型",
|
||||||
|
"aiProviderAuthTypeBearer": "Bearer",
|
||||||
|
"aiProviderAuthTypeBearerDescription": "授权:Bearer key。 由 OpenAI 及大多数提供商使用",
|
||||||
|
"aiProviderAuthTypeXApiKey": "x-api-key",
|
||||||
|
"aiProviderAuthTypeXApiKeyDescription": "x-api-key头部。由Anthropic使用",
|
||||||
|
"aiProviderAuthTypeXGoogApiKey": "x-goog-api-key",
|
||||||
|
"aiProviderAuthTypeXGoogApiKeyDescription": "x-goog-api-key头部。由Google Gemini使用",
|
||||||
|
"aiProviderAuthTypeHec": "Splunk HEC",
|
||||||
|
"aiProviderAuthTypeHecDescription": "授权:Splunk密钥。由Splunk HTTP事件收集器使用",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorization": "Cloudflare AI Gateway",
|
||||||
|
"aiProviderAuthTypeCfAigAuthorizationDescription": "cf-aig-authorization:Bearer key。由Cloudflare AI Gateway使用",
|
||||||
|
"aiProviderAuthTypeNone": "无身份验证",
|
||||||
|
"aiProviderAuthTypePassthrough": "透传",
|
||||||
|
"aiProviderAuthTypeDescription": "上游API如何验证请求",
|
||||||
|
"aiProviderAuthTypePassthroughDescription": "将调用者的API密钥头部转发到上游",
|
||||||
|
"aiProviderAuthTypeNoneDescription": "不向上游发送身份验证头部",
|
||||||
|
"aiProviderRoutingMode": "路由模式",
|
||||||
|
"aiProviderRoutingModeDescription": "将流量发送到上游URL或您站点上的HTTP目标",
|
||||||
|
"aiProviderRoutingModeUrl": "上游URL",
|
||||||
|
"aiProviderRoutingModeUrlDescription": "调用公共或私人API基础URL",
|
||||||
|
"aiProviderRoutingModeTarget": "站点目标",
|
||||||
|
"aiProviderRoutingModeTargetDescription": "通过您站点上的目标进行路由",
|
||||||
|
"aiProviderRoutingModeTargetNote": "创建此提供商后,在“网络设置”选项卡中配置站点目标。",
|
||||||
|
"aiProviderTargetNoOne": "该提供商没有任何目标。 添加目标以通过您的站点路由请求。",
|
||||||
|
"aiProviderSkipTlsVerification": "跳过TLS验证",
|
||||||
|
"aiProviderSkipTlsVerificationDescription": "禁用上游连接的TLS证书验证",
|
||||||
|
"aiProviderBudget": "预算",
|
||||||
|
"aiProviderBudgetDescription": "此提供商的可选支出或令牌预算",
|
||||||
|
"aiProviderBudgetAmount": "预算金额",
|
||||||
|
"aiProviderBudgetUnit": "预算单位",
|
||||||
|
"aiProviderBudgetUnitUsd": "美元",
|
||||||
|
"aiProviderBudgetUnitTokens": "令牌",
|
||||||
|
"aiProviderEnabled": "已启用",
|
||||||
|
"aiProviderEnabledDescription": "彻底禁用此提供商的所有资源",
|
||||||
|
"aiProviderErrorCreate": "创建AI提供商失败",
|
||||||
|
"aiProviderErrorUpdate": "更新AI提供商失败",
|
||||||
|
"aiProviderErrorDelete": "删除AI提供商失败",
|
||||||
|
"aiProviderErrorLoad": "加载AI提供商失败",
|
||||||
|
"aiProviderErrorUpstreamUrlInvalid": "输入有效的上游URL",
|
||||||
|
"aiProviderErrorUpstreamUrlRequired": "此提供商需要上游URL",
|
||||||
|
"aiProviderErrorAuthTypeRequired": "需要身份验证类型",
|
||||||
|
"aiProviderErrorApiKeyRequired": "需要API密钥",
|
||||||
|
"aiProviderErrorRoutingModeTarget": "站点目标路由仅适用于自定义提供商",
|
||||||
|
"aiProviderErrorCapabilitiesRequired": "选择至少一个API功能",
|
||||||
|
"aiProviderCapabilities": "API功能",
|
||||||
|
"aiProviderCapabilitiesDescription": "选择此提供商可以处理的API格式。已知提供商从推荐的默认值开始。",
|
||||||
|
"aiProviderCapabilitiesCustomDescription": "选择此自定义提供程序可以处理的API格式",
|
||||||
|
"aiProviderCapabilitiesSelect": "选择功能",
|
||||||
|
"aiProviderCapabilitiesEmpty": "未找到功能",
|
||||||
|
"aiProviderCapabilitiesSearch": "搜索功能……",
|
||||||
|
"aiCapabilityOpenaiChat": "OpenAI 聊天完成",
|
||||||
|
"aiCapabilityOpenaiChatDescription": "支持 /v1/chat/completions",
|
||||||
|
"aiCapabilityOpenaiResponses": "OpenAI 回应",
|
||||||
|
"aiCapabilityOpenaiResponsesDescription": "支持 /v1/responses",
|
||||||
|
"aiCapabilityAnthropicMessages": "Anthropic 消息",
|
||||||
|
"aiCapabilityAnthropicMessagesDescription": "支持 /v1/messages",
|
||||||
|
"aiCapabilityGeminiGenerateContent": "Gemini 生成内容",
|
||||||
|
"aiCapabilityGeminiGenerateContentDescription": "支持直接Gemini API",
|
||||||
|
"aiCapabilityBedrockModelInvoke": "Bedrock 模型调用",
|
||||||
|
"aiCapabilityBedrockModelInvokeDescription": "支持 Amazon Bedrock InvokeModel",
|
||||||
|
"aiCapabilityGoogleGenerateContent": "Vertex 生成内容",
|
||||||
|
"aiCapabilityGoogleGenerateContentDescription": "支持 Vertex AI Gemini 格式",
|
||||||
|
"aiCapabilityGoogleRawPredict": "Vertex 原始预测",
|
||||||
|
"aiCapabilityGoogleRawPredictDescription": "支持 Vertex AI 原始预测适用于 Anthropic 模型",
|
||||||
|
"aiCapabilityBedrockConverse": "Bedrock 会话",
|
||||||
|
"aiCapabilityBedrockConverseDescription": "支持 Amazon Bedrock Converse API",
|
||||||
|
"aiProviderCreated": "AI 提供者已创建",
|
||||||
|
"aiProviderUpdated": "AI 提供者已更新",
|
||||||
|
"aiProviderDeleted": "AI 提供者已删除",
|
||||||
|
"aiProviderDelete": "删除提供者",
|
||||||
|
"aiProviderDeleteConfirm": "删除提供者",
|
||||||
|
"aiProviderQuestionRemove": "您确定要删除此AI提供者吗?",
|
||||||
|
"aiProviderMessageRemove": "这将永久删除提供者及其模型和目标。无法撤销。",
|
||||||
|
"aiProviderErrorNoUpdate": "AI 提供者不可用于更新",
|
||||||
|
"aiProviderModels": "模型",
|
||||||
|
"aiProviderModelsDescription": "为此提供者定义允许和拒绝列表。请求必须匹配允许条目,并且不得匹配拒绝条目。",
|
||||||
|
"aiProviderCreateModelsDescription": "选择该提供者可以服务的模型。空白允许列表会拒绝所有流量。您可以稍后添加或更改模型。",
|
||||||
|
"aiProviderModelsPlaceholder": "搜索模型或键入自定义密钥",
|
||||||
|
"aiProviderModelsAllow": "允许列表",
|
||||||
|
"aiProviderModelsAllowDescription": "可通过此提供者使用的模型。空白表示拒绝所有。",
|
||||||
|
"aiProviderModelsAllowPlaceholder": "输入模型密钥",
|
||||||
|
"aiProviderModelsAllowEmpty": "尚未添加任何模型。",
|
||||||
|
"aiProviderModelsBlock": "拒绝列表",
|
||||||
|
"aiProviderModelsBlockDescription": "即使匹配允许条目的模型也要拒绝。",
|
||||||
|
"aiProviderModelsBlockPlaceholder": "输入模型密钥",
|
||||||
|
"aiProviderModelsBlockEmpty": "尚未添加任何模型。",
|
||||||
|
"aiProviderModelsAdd": "添加模型",
|
||||||
|
"aiProviderModelsClearAll": "清除所有",
|
||||||
|
"aiProviderModelsAddCustom": "添加 \"{key}\"",
|
||||||
|
"aiProviderModelsAddCustomHint": "按 Enter 键以添加此自定义模型密钥。",
|
||||||
|
"aiProviderModelsAddBulk": "添加 {count} 个自定义密钥",
|
||||||
|
"aiProviderModelsAddBulkHint": "按 Enter 键以添加 {count} 个自定义密钥。",
|
||||||
|
"aiProviderModelsAddOne": "立即添加 {key}",
|
||||||
|
"aiProviderModelsAddSelected": "添加所选",
|
||||||
|
"aiProviderModelsSelectedCount": "{count} 已选择",
|
||||||
|
"aiProviderModelsSelectAll": "选择所有",
|
||||||
|
"aiProviderModelsClearSelected": "清除",
|
||||||
|
"aiProviderModelsBulkHint": "选择已知模型或键入自定义密钥。",
|
||||||
|
"aiProviderModelsCatalogEmpty": "没有匹配的目录模型。",
|
||||||
|
"aiProviderModelsCatalogHeading": "已知模型",
|
||||||
|
"aiProviderModelsAllLabel": "所有模型",
|
||||||
|
"aiProviderModelsAllPatternHint": "通配符: *",
|
||||||
|
"aiProviderModelsAddAllAllow": "允许所有模型",
|
||||||
|
"aiProviderModelsAddAllBlock": "拒绝所有模型",
|
||||||
|
"aiProviderModelsAddAllDescription": "使用 * 通配符,因此每个模型密钥都匹配。",
|
||||||
|
"aiProviderModelsViewMore": "查看更多 ({count})",
|
||||||
|
"aiProviderModelsViewLess": "查看更少",
|
||||||
|
"aiProviderModelsRemove": "删除模型",
|
||||||
|
"aiProviderModelsEditHint": "单击以编辑模型设置",
|
||||||
|
"aiProviderModelsSourceCatalog": "已知目录模型",
|
||||||
|
"aiProviderModelsSourceCustom": "自定义模型密钥",
|
||||||
|
"aiProviderModelsSourcePattern": "通配符模式",
|
||||||
|
"aiProviderModelsSourceAll": "匹配每个模型密钥",
|
||||||
|
"aiProviderModelsBudgetConfigured": "预算已配置",
|
||||||
|
"aiProviderModelsEditTitle": "编辑模型",
|
||||||
|
"aiProviderModelsEditDescription": "更新模型密钥或配置其预算。",
|
||||||
|
"aiProviderModelsBudgetTab": "预算",
|
||||||
|
"aiProviderModelsKeyLabel": "模型密钥",
|
||||||
|
"aiProviderModelsKeyRequired": "输入一个模型密钥",
|
||||||
|
"aiProviderModelsKeyDuplicate": "此模型密钥已在列表中",
|
||||||
|
"aiProviderModelsOverlapError": "这些模式不能同时在两个列表中: {keys}",
|
||||||
|
"aiProviderModelsUpdated": "模型已更新",
|
||||||
|
"aiProviderModelsErrorUpdate": "更新模型失败",
|
||||||
|
"aiResourceProviders": "提供者",
|
||||||
|
"aiResourceProvidersDescription": "选择此AI网关可使用的AI提供者",
|
||||||
|
"aiResourceProvidersHelp": "附加提供者并选择继承(使用每个提供者的列表)或选择(为此资源选择允许列表)。不允许附加提供者之间冲突的允许模式。",
|
||||||
|
"aiResourceProvidersSelect": "选择提供者",
|
||||||
|
"aiResourceProvidersEmpty": "未找到AI提供者",
|
||||||
|
"aiResourceProvidersNoneAttached": "尚未附加任何提供者。",
|
||||||
|
"aiResourceProvidersAdd": "添加提供者",
|
||||||
|
"aiResourceProvidersRemove": "删除提供者",
|
||||||
|
"aiResourceProviderToggleEnabled": "在资源上启用或禁用此提供者",
|
||||||
|
"aiResourceProviderDisabled": "已禁用",
|
||||||
|
"aiResourceProvidersUpdated": "提供者已更新",
|
||||||
|
"aiResourceProvidersErrorUpdate": "更新提供者失败",
|
||||||
|
"aiResourceProviderEditDescription": "选择如何在此资源上公开此提供者的模型。",
|
||||||
|
"viewProviderSettings": "查看提供者设置",
|
||||||
|
"aiResourceProviderMode": "访问模式",
|
||||||
|
"aiResourceProviderModeInherit": "继承",
|
||||||
|
"aiResourceProviderModeSelect": "选择",
|
||||||
|
"aiResourceProviderModeSelectSummary": "选择 · {count} 模型",
|
||||||
|
"aiResourceProviderModeInheritHelp": "按照提供者上配置的那样使用提供者的允许和拒绝列表。",
|
||||||
|
"aiResourceProviderModeSelectHelp": "为此资源选择提供者允许列表模型的子集。",
|
||||||
|
"aiResourceProviderAllowModels": "允许列表",
|
||||||
|
"aiResourceProviderAllowModelsSelect": "选择模型",
|
||||||
|
"aiResourceProviderAllowModelsSearch": "搜索模型……",
|
||||||
|
"aiResourceProviderAllowModelsEmpty": "未找到模型",
|
||||||
|
"aiResourceProviderAllowModelsHelp": "只有此提供者的允许列表中的模型可以被选择。",
|
||||||
|
"aiResourceAliasRequired": "AI网关需要别名",
|
||||||
|
"aiResourceDomainConfiguration": "域配置",
|
||||||
|
"aiResourceDomainConfigurationDescription": "选择客户端将用于访问此AI网关的域。",
|
||||||
|
"aiUsageAnalyticsTitle": "AI 使用分析",
|
||||||
|
"aiUsageAnalyticsDescription": "分析 AI 网关的成本、令牌使用情况以及在提供者、资源、角色和用户中的活动",
|
||||||
|
"aiUsageTabOverview": "概览",
|
||||||
|
"aiUsageTabProviders": "提供者",
|
||||||
|
"aiUsageTabResources": "资源",
|
||||||
|
"aiUsageFilterProvider": "提供者",
|
||||||
|
"aiUsageFilterModel": "模型",
|
||||||
|
"aiUsageFilterResource": "资源",
|
||||||
|
"aiUsageFilterRole": "角色",
|
||||||
|
"aiUsageFilterUser": "用户",
|
||||||
|
"aiUsageFilterAllProviders": "所有提供者",
|
||||||
|
"aiUsageFilterAllModels": "所有模型",
|
||||||
|
"aiUsageFilterAllResources": "所有资源",
|
||||||
|
"aiUsageFilterAllRoles": "所有角色",
|
||||||
|
"aiUsageFilterAllUsers": "所有用户",
|
||||||
|
"aiUsageFilterSearch": "搜索……",
|
||||||
|
"aiUsageFilterNotFound": "未找到选项",
|
||||||
|
"aiUsageResetFilters": "重置过滤器",
|
||||||
|
"aiUsageRefresh": "刷新",
|
||||||
|
"aiUsageTokenTypePrompt": "提示",
|
||||||
|
"aiUsageTokenTypeCacheRead": "缓存读取",
|
||||||
|
"aiUsageTokenTypeCacheWrite": "缓存写入",
|
||||||
|
"aiUsageTokenTypeCompletion": "完成",
|
||||||
|
"aiUsageTokenTypeReasoning": "推理",
|
||||||
|
"aiUsageRequests": "请求",
|
||||||
|
"aiUsageCost": "成本",
|
||||||
|
"aiUsageTokens": "令牌",
|
||||||
|
"aiUsageOther": "其他",
|
||||||
|
"aiUsageTotalRequests": "总请求数",
|
||||||
|
"aiUsageTotalTokens": "总令牌数",
|
||||||
|
"aiUsageTotalCost": "总成本",
|
||||||
|
"aiUsageEstimated": "估计",
|
||||||
|
"aiUsageRequestVolume": "请求量",
|
||||||
|
"aiUsageTokenUsage": "令牌使用情况",
|
||||||
|
"aiUsageModelCost": "模型成本",
|
||||||
|
"aiUsageModelTokens": "模型令牌",
|
||||||
|
"aiUsageTopModels": "热门模型",
|
||||||
|
"aiUsageTopProviders": "热门提供者",
|
||||||
|
"aiUsageProviderCost": "提供者成本",
|
||||||
|
"aiUsageProviderTokenUsage": "提供者令牌使用情况",
|
||||||
|
"aiUsageTopResources": "热门资源",
|
||||||
|
"aiUsageResourceCost": "资源成本",
|
||||||
|
"aiUsageResourceTokenUsage": "资源令牌使用情况",
|
||||||
|
"aiUsageResourceTypePublic": "公共资源",
|
||||||
|
"aiUsageResourceTypeSite": "私有资源",
|
||||||
|
"aiUsageNoResource": "没有资源",
|
||||||
|
"aiUsageRolesTab": "角色",
|
||||||
|
"aiUsageUsersTab": "用户",
|
||||||
|
"aiUsageTopRoles": "热门角色",
|
||||||
|
"aiUsageRoleCost": "角色成本",
|
||||||
|
"aiUsageRoleTokenUsage": "角色令牌使用情况",
|
||||||
|
"aiUsageTopUsers": "热门用户",
|
||||||
|
"aiUsageUserCost": "用户成本",
|
||||||
|
"aiUsageUserTokenUsage": "用户令牌使用情况",
|
||||||
|
"aiUsageUnknownUser": "未知用户",
|
||||||
|
"aiUsageVirtualApiKeysTab": "虚拟 API 密钥",
|
||||||
|
"aiUsageFilterVirtualApiKey": "虚拟 API 密钥",
|
||||||
|
"aiUsageFilterAllVirtualApiKeys": "所有虚拟 API 密钥",
|
||||||
|
"aiUsageTopVirtualApiKeys": "热门虚拟 API 密钥",
|
||||||
|
"aiUsageVirtualApiKeyCost": "虚拟 API 密钥成本",
|
||||||
|
"aiUsageVirtualApiKeyTokenUsage": "虚拟 API 密钥令牌使用情况",
|
||||||
|
"aiUsageUnknownVirtualApiKey": "无虚拟 API 密钥",
|
||||||
|
"aiUsageUnnamedVirtualApiKey": "未命名密钥",
|
||||||
|
"aiUsageLoading": "加载中……",
|
||||||
|
"aiUsageNoData": "没有数据",
|
||||||
|
"resourceBudgetSettings": "预算",
|
||||||
|
"resourceBudgetSettingsDescription": "配置此 AI 网关如何根据支出或令牌限制来限制使用",
|
||||||
"sidebarApiKeys": "API密钥",
|
"sidebarApiKeys": "API密钥",
|
||||||
"sidebarProvisioning": "预配",
|
"sidebarProvisioning": "预配",
|
||||||
"sidebarSettings": "设置",
|
"sidebarSettings": "设置",
|
||||||
@@ -1675,6 +2158,8 @@
|
|||||||
"alertingRuleSaved": "告警规则已保存",
|
"alertingRuleSaved": "告警规则已保存",
|
||||||
"alertingRuleSavedCreatedDescription": "您的新告警规则已创建。您可以在此页面继续编辑它。",
|
"alertingRuleSavedCreatedDescription": "您的新告警规则已创建。您可以在此页面继续编辑它。",
|
||||||
"alertingRuleSavedUpdatedDescription": "对此告警规则的更改已保存。",
|
"alertingRuleSavedUpdatedDescription": "对此告警规则的更改已保存。",
|
||||||
|
"alertingTestAlertSent": "测试警报已发送",
|
||||||
|
"alertingTestAlertSentDescription": "已向此规则配置的操作发送了测试警报。",
|
||||||
"alertingEditRule": "编辑告警规则",
|
"alertingEditRule": "编辑告警规则",
|
||||||
"alertingCreateRule": "创建告警规则",
|
"alertingCreateRule": "创建告警规则",
|
||||||
"alertingRuleCredenzaDescription": "选择要监视的内容、何时触发以及如何通知",
|
"alertingRuleCredenzaDescription": "选择要监视的内容、何时触发以及如何通知",
|
||||||
@@ -1784,6 +2269,12 @@
|
|||||||
"alertingRulesBannerDescription": "每条规则都连接要监视的对象(站点、健康检查或资源),触发时间(例如离线或不健康),以及如何通过电子邮件、Webhooks 或集成将通知发送给团队。使用此列表创建、启用和管理这些规则。",
|
"alertingRulesBannerDescription": "每条规则都连接要监视的对象(站点、健康检查或资源),触发时间(例如离线或不健康),以及如何通过电子邮件、Webhooks 或集成将通知发送给团队。使用此列表创建、启用和管理这些规则。",
|
||||||
"alertingHealthChecksBannerTitle": "资源与健康监控",
|
"alertingHealthChecksBannerTitle": "资源与健康监控",
|
||||||
"alertingHealthChecksBannerDescription": "通过 HTTP 或 TCP 检查目标状态,并在服务异常或恢复时发送通知。资源中配置的健康检查也会显示在这里。",
|
"alertingHealthChecksBannerDescription": "通过 HTTP 或 TCP 检查目标状态,并在服务异常或恢复时发送通知。资源中配置的健康检查也会显示在这里。",
|
||||||
|
"alertingTestRule": "测试警报规则",
|
||||||
|
"alertingAddActionHeading": "添加新操作",
|
||||||
|
"alertingSelectActionType": "选择一个操作",
|
||||||
|
"alertingNoActionsTitle": "未配置操作",
|
||||||
|
"alertingNoActionsSaveDescription": "添加至少一个操作,以便在规则触发时通知某人。",
|
||||||
|
"alertingNoActionsTestDescription": "在您能测试此规则之前,请至少添加一个操作。",
|
||||||
"standaloneHcTableTitle": "健康检查",
|
"standaloneHcTableTitle": "健康检查",
|
||||||
"standaloneHcSearchPlaceholder": "搜索健康检查…",
|
"standaloneHcSearchPlaceholder": "搜索健康检查…",
|
||||||
"standaloneHcAddButton": "创建健康检查",
|
"standaloneHcAddButton": "创建健康检查",
|
||||||
@@ -1975,6 +2466,9 @@
|
|||||||
"domainPickerSubdomain": "子域:{subdomain}",
|
"domainPickerSubdomain": "子域:{subdomain}",
|
||||||
"domainPickerNamespace": "命名空间:{namespace}",
|
"domainPickerNamespace": "命名空间:{namespace}",
|
||||||
"domainPickerShowMore": "显示更多",
|
"domainPickerShowMore": "显示更多",
|
||||||
|
"domainPickerNoDomainsAvailableTitle": "无可用域",
|
||||||
|
"domainPickerNoDomainsAvailableDescription": "您还没有设置任何域。创建一个域以继续。",
|
||||||
|
"domainPickerNoDomainsAvailableAction": "转到域",
|
||||||
"regionSelectorTitle": "选择区域",
|
"regionSelectorTitle": "选择区域",
|
||||||
"domainPickerRemoteExitNodeWarning": "当站点连接到远程退出节点时不支持所提供的域。为了资源可在远程节点上使用,请使用自定义域名。",
|
"domainPickerRemoteExitNodeWarning": "当站点连接到远程退出节点时不支持所提供的域。为了资源可在远程节点上使用,请使用自定义域名。",
|
||||||
"regionSelectorInfo": "选择区域以帮助提升您所在地的性能。您不必与服务器在相同的区域。",
|
"regionSelectorInfo": "选择区域以帮助提升您所在地的性能。您不必与服务器在相同的区域。",
|
||||||
@@ -2170,6 +2664,8 @@
|
|||||||
"subnetPlaceholder": "子网",
|
"subnetPlaceholder": "子网",
|
||||||
"addressDescription": "客户的内部地址。必须属于组织的子网。",
|
"addressDescription": "客户的内部地址。必须属于组织的子网。",
|
||||||
"selectSites": "选择站点",
|
"selectSites": "选择站点",
|
||||||
|
"selectResources": "选择资源",
|
||||||
|
"multiResourcesSelectorResourcesCount": "{count, plural, other {# 个资源}}",
|
||||||
"selectLabels": "选择标签",
|
"selectLabels": "选择标签",
|
||||||
"sitesDescription": "客户端将与所选站点进行连接",
|
"sitesDescription": "客户端将与所选站点进行连接",
|
||||||
"clientInstallOlm": "安装 Olm",
|
"clientInstallOlm": "安装 Olm",
|
||||||
@@ -2222,10 +2718,11 @@
|
|||||||
"timeIsInSeconds": "时间以秒为单位",
|
"timeIsInSeconds": "时间以秒为单位",
|
||||||
"requireDeviceApproval": "需要设备批准",
|
"requireDeviceApproval": "需要设备批准",
|
||||||
"requireDeviceApprovalDescription": "具有此角色的用户需要管理员批准的新设备才能连接和访问资源。",
|
"requireDeviceApprovalDescription": "具有此角色的用户需要管理员批准的新设备才能连接和访问资源。",
|
||||||
"sshSettings": "SSH 设置",
|
"sshSettings": "SSH",
|
||||||
|
"inferenceSettings": "AI 网关",
|
||||||
"sshAccess": "SSH 访问",
|
"sshAccess": "SSH 访问",
|
||||||
"rdpSettings": "RDP 设置",
|
"rdpSettings": "RDP",
|
||||||
"vncSettings": "VNC 设置",
|
"vncSettings": "VNC",
|
||||||
"sshServer": "SSH 服务器",
|
"sshServer": "SSH 服务器",
|
||||||
"rdpServer": "RDP 服务器",
|
"rdpServer": "RDP 服务器",
|
||||||
"vncServer": "VNC 服务器",
|
"vncServer": "VNC 服务器",
|
||||||
@@ -2338,7 +2835,7 @@
|
|||||||
"resourcesTableProxyResources": "",
|
"resourcesTableProxyResources": "",
|
||||||
"resourcesTableClientResources": "私有资源",
|
"resourcesTableClientResources": "私有资源",
|
||||||
"resourcesTableNoProxyResourcesFound": "未找到代理资源。",
|
"resourcesTableNoProxyResourcesFound": "未找到代理资源。",
|
||||||
"resourcesTableNoInternalResourcesFound": "未找到内部资源。",
|
"resourcesTableNoInternalResourcesFound": "未找到私有资源。",
|
||||||
"resourcesTableDestination": "目标",
|
"resourcesTableDestination": "目标",
|
||||||
"resourcesTableAlias": "Alias",
|
"resourcesTableAlias": "Alias",
|
||||||
"resourcesTableAliasAddress": "别名地址",
|
"resourcesTableAliasAddress": "别名地址",
|
||||||
@@ -2361,9 +2858,9 @@
|
|||||||
"editInternalResourceDialogCancel": "取消",
|
"editInternalResourceDialogCancel": "取消",
|
||||||
"editInternalResourceDialogSaveResource": "保存资源",
|
"editInternalResourceDialogSaveResource": "保存资源",
|
||||||
"editInternalResourceDialogSuccess": "成功",
|
"editInternalResourceDialogSuccess": "成功",
|
||||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "内部资源更新成功",
|
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "私有资源更新成功",
|
||||||
"editInternalResourceDialogError": "错误",
|
"editInternalResourceDialogError": "错误",
|
||||||
"editInternalResourceDialogFailedToUpdateInternalResource": "更新内部资源失败",
|
"editInternalResourceDialogFailedToUpdateInternalResource": "更新私有资源失败",
|
||||||
"editInternalResourceDialogNameRequired": "名称为必填项",
|
"editInternalResourceDialogNameRequired": "名称为必填项",
|
||||||
"editInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
|
"editInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
|
||||||
"editInternalResourceDialogProxyPortMin": "代理端口必须至少为1",
|
"editInternalResourceDialogProxyPortMin": "代理端口必须至少为1",
|
||||||
@@ -2378,6 +2875,7 @@
|
|||||||
"editInternalResourceDialogModeCidr": "CIDR",
|
"editInternalResourceDialogModeCidr": "CIDR",
|
||||||
"editInternalResourceDialogModeHttp": "HTTP",
|
"editInternalResourceDialogModeHttp": "HTTP",
|
||||||
"editInternalResourceDialogModeHttps": "HTTPS",
|
"editInternalResourceDialogModeHttps": "HTTPS",
|
||||||
|
"editInternalResourceDialogModeInference": "AI 网关",
|
||||||
"editInternalResourceDialogModeSsh": "SSH",
|
"editInternalResourceDialogModeSsh": "SSH",
|
||||||
"editInternalResourceDialogScheme": "方案",
|
"editInternalResourceDialogScheme": "方案",
|
||||||
"editInternalResourceDialogEnableSsl": "启用 TLS",
|
"editInternalResourceDialogEnableSsl": "启用 TLS",
|
||||||
@@ -2389,7 +2887,7 @@
|
|||||||
"editInternalResourceDialogAlias": "Alias",
|
"editInternalResourceDialogAlias": "Alias",
|
||||||
"editInternalResourceDialogAliasDescription": "此资源可选的内部DNS别名。",
|
"editInternalResourceDialogAliasDescription": "此资源可选的内部DNS别名。",
|
||||||
"createInternalResourceDialogNoSitesAvailable": "暂无可用站点",
|
"createInternalResourceDialogNoSitesAvailable": "暂无可用站点",
|
||||||
"createInternalResourceDialogNoSitesAvailableDescription": "您需要至少配置一个子网的Newt站点来创建内部资源。",
|
"createInternalResourceDialogNoSitesAvailableDescription": "您需要至少配置一个子网的Newt站点来创建私有资源。",
|
||||||
"createInternalResourceDialogClose": "关闭",
|
"createInternalResourceDialogClose": "关闭",
|
||||||
"createInternalResourceDialogCreateClientResource": "创建私有资源",
|
"createInternalResourceDialogCreateClientResource": "创建私有资源",
|
||||||
"createInternalResourceDialogCreateClientResourceDescription": "创建一个新资源只能为连接到组织的客户端访问",
|
"createInternalResourceDialogCreateClientResourceDescription": "创建一个新资源只能为连接到组织的客户端访问",
|
||||||
@@ -2398,8 +2896,8 @@
|
|||||||
"privateResourceAllowIcmpPing": "允许 ICMP Ping",
|
"privateResourceAllowIcmpPing": "允许 ICMP Ping",
|
||||||
"privateResourceNetworkAccess": "网络访问",
|
"privateResourceNetworkAccess": "网络访问",
|
||||||
"privateResourceNetworkAccessDescription": "控制此资源的 TCP/UDP 端口访问以及是否允许 ICMP ping。",
|
"privateResourceNetworkAccessDescription": "控制此资源的 TCP/UDP 端口访问以及是否允许 ICMP ping。",
|
||||||
"hostSettings": "主机设置",
|
"hostSettings": "主机",
|
||||||
"cidrSettings": "CIDR 设置",
|
"cidrSettings": "CIDR",
|
||||||
"createInternalResourceDialogResourceProperties": "资源属性",
|
"createInternalResourceDialogResourceProperties": "资源属性",
|
||||||
"createInternalResourceDialogName": "名称",
|
"createInternalResourceDialogName": "名称",
|
||||||
"createInternalResourceDialogSite": "站点",
|
"createInternalResourceDialogSite": "站点",
|
||||||
@@ -2418,9 +2916,9 @@
|
|||||||
"createInternalResourceDialogCancel": "取消",
|
"createInternalResourceDialogCancel": "取消",
|
||||||
"createInternalResourceDialogCreateResource": "创建资源",
|
"createInternalResourceDialogCreateResource": "创建资源",
|
||||||
"createInternalResourceDialogSuccess": "成功",
|
"createInternalResourceDialogSuccess": "成功",
|
||||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "内部资源创建成功",
|
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "私有资源创建成功",
|
||||||
"createInternalResourceDialogError": "错误",
|
"createInternalResourceDialogError": "错误",
|
||||||
"createInternalResourceDialogFailedToCreateInternalResource": "创建内部资源失败",
|
"createInternalResourceDialogFailedToCreateInternalResource": "创建私有资源失败",
|
||||||
"createInternalResourceDialogNameRequired": "名称为必填项",
|
"createInternalResourceDialogNameRequired": "名称为必填项",
|
||||||
"createInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
|
"createInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
|
||||||
"createInternalResourceDialogPleaseSelectSite": "请选择一个站点",
|
"createInternalResourceDialogPleaseSelectSite": "请选择一个站点",
|
||||||
@@ -2437,6 +2935,7 @@
|
|||||||
"createInternalResourceDialogModeHttp": "HTTP",
|
"createInternalResourceDialogModeHttp": "HTTP",
|
||||||
"createInternalResourceDialogModeHttps": "HTTPS",
|
"createInternalResourceDialogModeHttps": "HTTPS",
|
||||||
"createInternalResourceDialogModeSsh": "SSH",
|
"createInternalResourceDialogModeSsh": "SSH",
|
||||||
|
"createInternalResourceDialogModeInference": "AI 网关",
|
||||||
"scheme": "方案",
|
"scheme": "方案",
|
||||||
"createInternalResourceDialogScheme": "方案",
|
"createInternalResourceDialogScheme": "方案",
|
||||||
"createInternalResourceDialogEnableSsl": "启用 TLS",
|
"createInternalResourceDialogEnableSsl": "启用 TLS",
|
||||||
@@ -3028,6 +3527,7 @@
|
|||||||
"validPassword": "有效密码",
|
"validPassword": "有效密码",
|
||||||
"validEmail": "Valid email",
|
"validEmail": "Valid email",
|
||||||
"validSSO": "Valid SSO",
|
"validSSO": "Valid SSO",
|
||||||
|
"validVirtualAPIKey": "有效虚拟 API 密钥",
|
||||||
"view": "查看",
|
"view": "查看",
|
||||||
"configManaged": "配置已管理",
|
"configManaged": "配置已管理",
|
||||||
"connectedClient": "已连接客户端",
|
"connectedClient": "已连接客户端",
|
||||||
@@ -3049,6 +3549,38 @@
|
|||||||
"logRetention": "日志保留",
|
"logRetention": "日志保留",
|
||||||
"logRetentionDescription": "管理不同类型的日志为这个机构保留多长时间或禁用这些日志",
|
"logRetentionDescription": "管理不同类型的日志为这个机构保留多长时间或禁用这些日志",
|
||||||
"requestLogsDescription": "查看此机构资源的详细请求日志",
|
"requestLogsDescription": "查看此机构资源的详细请求日志",
|
||||||
|
"aiSessionLogs": "AI 网关会话日志",
|
||||||
|
"aiSessionLogsDescription": "查看此组织中AI网关请求的提示和响应记录",
|
||||||
|
"sidebarLogsAi": "会话日志",
|
||||||
|
"commandLogsAi": "会话日志",
|
||||||
|
"sidebarLogsAiUsage": "使用分析",
|
||||||
|
"commandLogsAiUsage": "使用分析",
|
||||||
|
"provider": "提供者",
|
||||||
|
"capability": "能力",
|
||||||
|
"model": "模型",
|
||||||
|
"virtualApiKey": "虚拟 API 密钥",
|
||||||
|
"noVirtualApiKey": "无虚拟 API 密钥",
|
||||||
|
"stream": "流",
|
||||||
|
"streaming": "流媒体",
|
||||||
|
"nonStreaming": "非流",
|
||||||
|
"statusCode": "状态码",
|
||||||
|
"aiSessionId": "会话 ID",
|
||||||
|
"aiSessionRequest": "请求",
|
||||||
|
"aiSessionResponse": "响应",
|
||||||
|
"aiSessionNoData": "未捕获数据",
|
||||||
|
"aiSessionCouldNotParse": "(原始,无法解析记录)",
|
||||||
|
"aiSessionLogTruncated": "此会话在存储之前被截断,可能不完整。",
|
||||||
|
"aiSessionViewRaw": "查看原始 JSON",
|
||||||
|
"aiSessionViewChat": "查看聊天",
|
||||||
|
"cost": "成本",
|
||||||
|
"estimated": "估计",
|
||||||
|
"tokenUsage": "令牌使用情况",
|
||||||
|
"promptTokens": "提示令牌",
|
||||||
|
"cacheReadTokens": "缓存读取令牌",
|
||||||
|
"cacheWriteTokens": "缓存写入令牌",
|
||||||
|
"completionTokens": "完成令牌",
|
||||||
|
"reasoningTokens": "推理令牌",
|
||||||
|
"totalTokens": "总令牌数",
|
||||||
"requestAnalyticsDescription": "查看此机构资源的详细请求分析",
|
"requestAnalyticsDescription": "查看此机构资源的详细请求分析",
|
||||||
"logRetentionRequestLabel": "HTTP 请求日志保留",
|
"logRetentionRequestLabel": "HTTP 请求日志保留",
|
||||||
"logRetentionRequestDescription": "保留请求日志的时间",
|
"logRetentionRequestDescription": "保留请求日志的时间",
|
||||||
@@ -3058,6 +3590,8 @@
|
|||||||
"logRetentionActionDescription": "保留操作日志的时间",
|
"logRetentionActionDescription": "保留操作日志的时间",
|
||||||
"logRetentionConnectionLabel": "连接日志保留",
|
"logRetentionConnectionLabel": "连接日志保留",
|
||||||
"logRetentionConnectionDescription": "保留连接日志的时间",
|
"logRetentionConnectionDescription": "保留连接日志的时间",
|
||||||
|
"logRetentionAISessionsLabel": "AI 网关会话日志保留",
|
||||||
|
"logRetentionAISessionsDescription": "保留AI网关提示/响应会话日志的时间",
|
||||||
"logRetentionDisabled": "已禁用",
|
"logRetentionDisabled": "已禁用",
|
||||||
"logRetention3Days": "3 天",
|
"logRetention3Days": "3 天",
|
||||||
"logRetention7Days": "7 天",
|
"logRetention7Days": "7 天",
|
||||||
@@ -3075,8 +3609,8 @@
|
|||||||
"sourceAddress": "源地址",
|
"sourceAddress": "源地址",
|
||||||
"destinationAddress": "目的地址",
|
"destinationAddress": "目的地址",
|
||||||
"duration": "期限",
|
"duration": "期限",
|
||||||
"licenseRequiredToUse": "使用此功能需要<enterpriseLicenseLink>企业版</enterpriseLicenseLink>许可证或<pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>。<bookADemoLink>预约演示或POC试用</bookADemoLink>。",
|
"licenseRequiredToUse": "需要<enterpriseEditionLink>企业版许可证</enterpriseEditionLink>。 <bookADemoLink>预约演示或试用</bookADemoLink>",
|
||||||
"ossEnterpriseEditionRequired": "需要 <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> 才能使用此功能。 此功能也可在 <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>上获取。 <bookADemoLink>预订演示或POC 试用</bookADemoLink>。",
|
"ossEnterpriseEditionRequired": "需要<enterpriseEditionLink>企业版许可证</enterpriseEditionLink>。 <bookADemoLink>预约演示或试用</bookADemoLink>",
|
||||||
"certResolver": "证书解决器",
|
"certResolver": "证书解决器",
|
||||||
"certResolverDescription": "选择用于此资源的证书解析器。",
|
"certResolverDescription": "选择用于此资源的证书解析器。",
|
||||||
"selectCertResolver": "选择证书解析",
|
"selectCertResolver": "选择证书解析",
|
||||||
@@ -3274,9 +3808,9 @@
|
|||||||
"internalResourceFormMultiSiteRoutingHelp": "选择多个站点可以实现高可用性的弹性路由和故障转移。",
|
"internalResourceFormMultiSiteRoutingHelp": "选择多个站点可以实现高可用性的弹性路由和故障转移。",
|
||||||
"internalResourceFormMultiSiteRoutingHelpLearnMore": "了解更多",
|
"internalResourceFormMultiSiteRoutingHelpLearnMore": "了解更多",
|
||||||
"editInternalResourceDialogPortRestrictionsDescription": "限制访问特定的TCP/UDP端口或允许/阻止所有端口。",
|
"editInternalResourceDialogPortRestrictionsDescription": "限制访问特定的TCP/UDP端口或允许/阻止所有端口。",
|
||||||
"createInternalResourceDialogHttpConfiguration": "HTTP 配置",
|
"createInternalResourceDialogHttpConfiguration": "域配置",
|
||||||
"createInternalResourceDialogHttpConfigurationDescription": "选择客户将使用的域名通过 HTTP 或 HTTPS 访问此资源。",
|
"createInternalResourceDialogHttpConfigurationDescription": "选择客户将使用的域名通过 HTTP 或 HTTPS 访问此资源。",
|
||||||
"editInternalResourceDialogHttpConfiguration": "HTTP 配置",
|
"editInternalResourceDialogHttpConfiguration": "域配置",
|
||||||
"editInternalResourceDialogHttpConfigurationDescription": "选择客户将使用的域名通过 HTTP 或 HTTPS 访问此资源。",
|
"editInternalResourceDialogHttpConfigurationDescription": "选择客户将使用的域名通过 HTTP 或 HTTPS 访问此资源。",
|
||||||
"editInternalResourceDialogTcp": "TCP",
|
"editInternalResourceDialogTcp": "TCP",
|
||||||
"editInternalResourceDialogUdp": "UDP",
|
"editInternalResourceDialogUdp": "UDP",
|
||||||
@@ -3712,7 +4246,18 @@
|
|||||||
"resourceLauncherTcp": "TCP",
|
"resourceLauncherTcp": "TCP",
|
||||||
"resourceLauncherUdp": "UDP",
|
"resourceLauncherUdp": "UDP",
|
||||||
"resourceLauncherUnlabeled": "未标记",
|
"resourceLauncherUnlabeled": "未标记",
|
||||||
|
"resourceLauncherAiGateway": "AI 网关",
|
||||||
"resourceLauncherNoSite": "无站点",
|
"resourceLauncherNoSite": "无站点",
|
||||||
|
"resourceLauncherAvailableModels": "可用模型",
|
||||||
|
"resourceLauncherAvailableModelsDescription": "您可以在此 AI 网关中使用的模型。",
|
||||||
|
"resourceLauncherAvailableModelsEmpty": "此资源没有可用的模型。",
|
||||||
|
"resourceLauncherAvailableModelsError": "无法加载可用模型。",
|
||||||
|
"resourceLauncherApiKeys": "API 密钥",
|
||||||
|
"resourceLauncherApiKeysDescription": "使用您的身份密钥或归属密钥进行身份验证。",
|
||||||
|
"resourceLauncherApiKeysIdentity": "身份密钥",
|
||||||
|
"resourceLauncherApiKeysManual": "归属密钥",
|
||||||
|
"resourceLauncherApiKeysEmpty": "此资源没有可用的 API 密钥。",
|
||||||
|
"resourceLauncherApiKeysError": "无法加载 API 密钥。",
|
||||||
"resourceLauncherNoResourcesInGroup": "此组中没有资源",
|
"resourceLauncherNoResourcesInGroup": "此组中没有资源",
|
||||||
"resourceLauncherEmptyStateTitle": "没有可用资源",
|
"resourceLauncherEmptyStateTitle": "没有可用资源",
|
||||||
"resourceLauncherEmptyStateDescription": "您还没有访问任何资源。请联系您的管理员以请求访问。",
|
"resourceLauncherEmptyStateDescription": "您还没有访问任何资源。请联系您的管理员以请求访问。",
|
||||||
@@ -3739,9 +4284,9 @@
|
|||||||
"resourceLauncherViewDeleteFailedDescription": "无法删除启动器视图。请再试一次。",
|
"resourceLauncherViewDeleteFailedDescription": "无法删除启动器视图。请再试一次。",
|
||||||
"memberPortalPrevious": "上一页",
|
"memberPortalPrevious": "上一页",
|
||||||
"memberPortalNext": "下一页",
|
"memberPortalNext": "下一页",
|
||||||
"httpSettings": "HTTP 设置",
|
"httpSettings": "HTTP",
|
||||||
"tcpSettings": "TCP 设置",
|
"tcpSettings": "TCP",
|
||||||
"udpSettings": "UDP 设置",
|
"udpSettings": "UDP",
|
||||||
"sshTitle": "SSH",
|
"sshTitle": "SSH",
|
||||||
"sshConnectingDescription": "正在建立安全连接…",
|
"sshConnectingDescription": "正在建立安全连接…",
|
||||||
"sshConnecting": "正在连接…",
|
"sshConnecting": "正在连接…",
|
||||||
@@ -3801,5 +4346,6 @@
|
|||||||
"rdpUploadFailed": "上传失败",
|
"rdpUploadFailed": "上传失败",
|
||||||
"rdpUnicodeKeyboardMode": "Unicode 键盘模式",
|
"rdpUnicodeKeyboardMode": "Unicode 键盘模式",
|
||||||
"sessionToolbarShow": "显示工具栏",
|
"sessionToolbarShow": "显示工具栏",
|
||||||
"sessionToolbarHide": "隐藏工具栏"
|
"sessionToolbarHide": "隐藏工具栏",
|
||||||
|
"actionUpdateSiteApprovals": "更新站点审批"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@asteasolutions/zod-to-openapi": "8.5.0",
|
"@asteasolutions/zod-to-openapi": "8.5.0",
|
||||||
|
"@aws-sdk/client-s3": "3.1056.0",
|
||||||
"@devolutions/iron-remote-desktop": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-0.0.0.tgz",
|
"@devolutions/iron-remote-desktop": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-0.0.0.tgz",
|
||||||
"@devolutions/iron-remote-desktop-rdp": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.1.tgz",
|
"@devolutions/iron-remote-desktop-rdp": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.1.tgz",
|
||||||
"@aws-sdk/client-s3": "3.1056.0",
|
|
||||||
"@headlessui/react": "2.2.10",
|
"@headlessui/react": "2.2.10",
|
||||||
"@hookform/resolvers": "5.4.0",
|
"@hookform/resolvers": "5.4.0",
|
||||||
"@monaco-editor/react": "4.7.0",
|
"@monaco-editor/react": "4.7.0",
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
"@xterm/addon-web-links": "^0.12.0",
|
"@xterm/addon-web-links": "^0.12.0",
|
||||||
"@xterm/xterm": "^6.0.0",
|
"@xterm/xterm": "^6.0.0",
|
||||||
"arctic": "3.7.0",
|
"arctic": "3.7.0",
|
||||||
"axios": "1.16.1",
|
"axios": "1.18.0",
|
||||||
"better-sqlite3": "11.9.1",
|
"better-sqlite3": "11.9.1",
|
||||||
"canvas-confetti": "1.9.4",
|
"canvas-confetti": "1.9.4",
|
||||||
"class-variance-authority": "0.7.1",
|
"class-variance-authority": "0.7.1",
|
||||||
@@ -88,17 +88,18 @@
|
|||||||
"express": "5.2.1",
|
"express": "5.2.1",
|
||||||
"express-rate-limit": "8.5.2",
|
"express-rate-limit": "8.5.2",
|
||||||
"glob": "13.0.6",
|
"glob": "13.0.6",
|
||||||
|
"gpt-tokenizer": "^3.4.0",
|
||||||
"helmet": "8.2.0",
|
"helmet": "8.2.0",
|
||||||
"http-errors": "2.0.1",
|
"http-errors": "2.0.1",
|
||||||
"input-otp": "1.4.2",
|
"input-otp": "1.4.2",
|
||||||
"ioredis": "5.11.0",
|
"ioredis": "5.11.0",
|
||||||
"jmespath": "0.16.0",
|
"jmespath": "0.16.0",
|
||||||
"js-yaml": "4.2.0",
|
"js-yaml": "4.3.1",
|
||||||
"jsonwebtoken": "9.0.3",
|
"jsonwebtoken": "9.0.3",
|
||||||
"lucide-react": "1.17.0",
|
"lucide-react": "1.17.0",
|
||||||
"maxmind": "5.0.6",
|
"maxmind": "5.0.6",
|
||||||
"moment": "2.30.1",
|
"moment": "2.30.1",
|
||||||
"next": "16.2.6",
|
"next": "16.3.1",
|
||||||
"next-intl": "4.13.0",
|
"next-intl": "4.13.0",
|
||||||
"next-themes": "0.4.6",
|
"next-themes": "0.4.6",
|
||||||
"nextjs-toploader": "3.9.17",
|
"nextjs-toploader": "3.9.17",
|
||||||
@@ -138,7 +139,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@dotenvx/dotenvx": "1.69.1",
|
"@dotenvx/dotenvx": "1.69.1",
|
||||||
"@esbuild-plugins/tsconfig-paths": "0.1.2",
|
"@esbuild-plugins/tsconfig-paths": "0.1.2",
|
||||||
"@react-email/ui": "^6.5.0",
|
"@react-email/ui": "^6.9.2",
|
||||||
"@tailwindcss/postcss": "4.3.0",
|
"@tailwindcss/postcss": "4.3.0",
|
||||||
"@tanstack/react-query-devtools": "5.100.14",
|
"@tanstack/react-query-devtools": "5.100.14",
|
||||||
"@types/better-sqlite3": "7.6.13",
|
"@types/better-sqlite3": "7.6.13",
|
||||||
@@ -165,11 +166,11 @@
|
|||||||
"@types/yargs": "17.0.35",
|
"@types/yargs": "17.0.35",
|
||||||
"babel-plugin-react-compiler": "1.0.0",
|
"babel-plugin-react-compiler": "1.0.0",
|
||||||
"drizzle-kit": "0.31.10",
|
"drizzle-kit": "0.31.10",
|
||||||
"esbuild": "0.28.1",
|
"esbuild": "0.28.0",
|
||||||
"esbuild-node-externals": "1.22.0",
|
"esbuild-node-externals": "1.22.0",
|
||||||
"eslint": "10.4.0",
|
"eslint": "10.4.0",
|
||||||
"eslint-config-next": "16.2.6",
|
"eslint-config-next": "16.2.6",
|
||||||
"postcss": "8.5.15",
|
"postcss": "8.5.23",
|
||||||
"prettier": "3.8.3",
|
"prettier": "3.8.3",
|
||||||
"react-email": "6.5.0",
|
"react-email": "6.5.0",
|
||||||
"tailwindcss": "4.3.0",
|
"tailwindcss": "4.3.0",
|
||||||
@@ -179,8 +180,8 @@
|
|||||||
"typescript-eslint": "8.60.0"
|
"typescript-eslint": "8.60.0"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"esbuild": "0.28.1",
|
"esbuild": "0.28.0",
|
||||||
"dompurify": "3.4.0",
|
"dompurify": "3.4.0",
|
||||||
"postcss": "8.5.15"
|
"postcss": "8.5.23"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 556 KiB |
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="256" height="257" viewBox="0 0 256 257" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_29_2)">
|
||||||
|
<path d="M50.2278 170.321L100.585 142.064L101.428 139.601L100.585 138.24H98.1225L89.6972 137.722L60.9215 136.944L35.9696 135.907L11.7954 134.611L5.70329 133.314L0 125.796L0.583291 122.037L5.70329 118.603L13.0268 119.251L29.2294 120.352L53.5332 122.037L71.1615 123.074L97.28 125.796H101.428L102.011 124.111L100.585 123.074L99.4835 122.037L74.3372 104.992L47.117 86.9752L32.8587 76.6056L25.1463 71.3559L21.2577 66.4304L19.5727 55.6719L26.5722 47.9595L35.9696 48.6076L38.3676 49.2557L47.8947 56.5792L68.2451 72.3281L94.8172 91.9008L98.7058 95.1413L100.261 94.0395L100.456 93.2618L98.7058 90.3453L84.2532 64.2268L68.8284 37.6547L61.9585 26.637L60.1438 20.0263C59.4957 17.3043 59.042 15.0359 59.042 12.2491L67.0137 1.42582L71.4208 0L82.0496 1.42582L86.5215 5.31443L93.1321 20.4152L103.826 44.2005L120.417 76.5408L125.278 86.1327L127.87 95.0116L128.843 97.7337H130.528V96.1782L131.889 77.9666L134.416 55.6071L136.879 26.8314L137.722 18.7301L141.74 9.00861L149.711 3.75899L155.933 6.74025L161.053 14.0638L160.34 18.7949L157.294 38.562L151.332 69.5413L147.443 90.2805H149.711L152.304 87.6881L162.803 73.7539L180.431 51.7185L188.209 42.9691L197.282 33.3124L203.115 28.7109H214.133L222.234 40.7656L218.605 53.2091L207.263 67.597L197.865 79.7813L184.385 97.9281L175.959 112.446L176.737 113.612L178.746 113.418L209.207 106.937L225.669 103.955L245.306 100.585L254.185 104.733L255.157 108.946L251.658 117.566L230.659 122.75L206.031 127.676L169.349 136.361L168.895 136.685L169.414 137.333L185.94 138.888L193.005 139.277H210.309L242.52 141.675L250.945 147.249L256 154.054L255.157 159.238L242.195 165.849L224.697 161.701L183.866 151.98L169.867 148.48H167.923V149.647L179.589 161.053L200.976 180.367L227.743 205.254L229.104 211.411L225.669 216.271L222.039 215.753L198.513 198.06L189.44 190.088L168.895 172.784H167.534V174.598L172.265 181.533L197.282 219.123L198.578 230.659L196.764 234.418L190.283 236.687L183.153 235.39L168.506 214.846L153.406 191.708L141.221 170.969L139.731 171.812L132.537 249.26L129.167 253.213L121.389 256.194L114.908 251.269L111.473 243.297L114.908 227.548L119.056 207.004L122.426 190.671L125.472 170.386L127.287 163.646L127.157 163.192L125.667 163.386L110.372 184.385L87.1048 215.818L68.6987 235.52L64.2916 237.27L56.6441 233.316L57.357 226.252L61.6344 219.966L87.1048 187.561L102.465 167.469L112.381 155.868L112.316 154.183H111.733L44.0709 198.125L32.0162 199.68L26.8314 194.819L27.4795 186.848L29.9423 184.255L50.2927 170.256L50.2278 170.321Z" fill="#0B0B0B"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_29_2">
|
||||||
|
<rect width="256" height="257" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="256" height="257" viewBox="0 0 256 257" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_29_2)">
|
||||||
|
<path d="M50.2278 170.321L100.585 142.064L101.428 139.601L100.585 138.24H98.1225L89.6972 137.722L60.9215 136.944L35.9696 135.907L11.7954 134.611L5.70329 133.314L0 125.796L0.583291 122.037L5.70329 118.603L13.0268 119.251L29.2294 120.352L53.5332 122.037L71.1615 123.074L97.28 125.796H101.428L102.011 124.111L100.585 123.074L99.4835 122.037L74.3372 104.992L47.117 86.9752L32.8587 76.6056L25.1463 71.3559L21.2577 66.4304L19.5727 55.6719L26.5722 47.9595L35.9696 48.6076L38.3676 49.2557L47.8947 56.5792L68.2451 72.3281L94.8172 91.9008L98.7058 95.1413L100.261 94.0395L100.456 93.2618L98.7058 90.3453L84.2532 64.2268L68.8284 37.6547L61.9585 26.637L60.1438 20.0263C59.4957 17.3043 59.042 15.0359 59.042 12.2491L67.0137 1.42582L71.4208 0L82.0496 1.42582L86.5215 5.31443L93.1321 20.4152L103.826 44.2005L120.417 76.5408L125.278 86.1327L127.87 95.0116L128.843 97.7337H130.528V96.1782L131.889 77.9666L134.416 55.6071L136.879 26.8314L137.722 18.7301L141.74 9.00861L149.711 3.75899L155.933 6.74025L161.053 14.0638L160.34 18.7949L157.294 38.562L151.332 69.5413L147.443 90.2805H149.711L152.304 87.6881L162.803 73.7539L180.431 51.7185L188.209 42.9691L197.282 33.3124L203.115 28.7109H214.133L222.234 40.7656L218.605 53.2091L207.263 67.597L197.865 79.7813L184.385 97.9281L175.959 112.446L176.737 113.612L178.746 113.418L209.207 106.937L225.669 103.955L245.306 100.585L254.185 104.733L255.157 108.946L251.658 117.566L230.659 122.75L206.031 127.676L169.349 136.361L168.895 136.685L169.414 137.333L185.94 138.888L193.005 139.277H210.309L242.52 141.675L250.945 147.249L256 154.054L255.157 159.238L242.195 165.849L224.697 161.701L183.866 151.98L169.867 148.48H167.923V149.647L179.589 161.053L200.976 180.367L227.743 205.254L229.104 211.411L225.669 216.271L222.039 215.753L198.513 198.06L189.44 190.088L168.895 172.784H167.534V174.598L172.265 181.533L197.282 219.123L198.578 230.659L196.764 234.418L190.283 236.687L183.153 235.39L168.506 214.846L153.406 191.708L141.221 170.969L139.731 171.812L132.537 249.26L129.167 253.213L121.389 256.194L114.908 251.269L111.473 243.297L114.908 227.548L119.056 207.004L122.426 190.671L125.472 170.386L127.287 163.646L127.157 163.192L125.667 163.386L110.372 184.385L87.1048 215.818L68.6987 235.52L64.2916 237.27L56.6441 233.316L57.357 226.252L61.6344 219.966L87.1048 187.561L102.465 167.469L112.381 155.868L112.316 154.183H111.733L44.0709 198.125L32.0162 199.68L26.8314 194.819L27.4795 186.848L29.9423 184.255L50.2927 170.256L50.2278 170.321Z" fill="#F0EFEC"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_29_2">
|
||||||
|
<rect width="256" height="257" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg id="Ebene_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 466.73 532.09">
|
||||||
|
<!-- Generator: Adobe Illustrator 29.6.1, SVG Export Plug-In . SVG Version: 2.1.1 Build 9) -->
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.st0 {
|
||||||
|
fill: #26251e;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path class="st0" d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 793 B |
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg id="Ebene_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 466.73 532.09">
|
||||||
|
<!-- Generator: Adobe Illustrator 29.6.1, SVG Export Plug-In . SVG Version: 2.1.1 Build 9) -->
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.st0 {
|
||||||
|
fill: #edecec;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path class="st0" d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 793 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="716" height="716" viewBox="157 157 402 402" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M508.749 317.399C516.777 287.314 508.991 253.884 485.389 230.282C461.788 206.681 428.36 198.895 398.273 206.923C376.231 184.928 343.39 174.956 311.148 183.596C278.906 192.234 255.45 217.292 247.36 247.361C217.291 255.451 192.233 278.91 183.595 311.149C174.957 343.391 184.927 376.232 206.924 398.274C198.896 428.359 206.683 461.789 230.284 485.391C253.885 508.992 287.313 516.779 317.401 508.75C339.442 530.745 372.286 540.717 404.525 532.079C436.767 523.441 460.223 498.384 468.313 468.315C498.383 460.224 523.44 436.766 532.078 404.526C540.716 372.285 530.747 339.443 508.749 317.402V317.399ZM470.899 244.776C486.892 260.77 493.488 282.601 490.687 303.412L415.577 260.046C412.411 258.218 408.509 258.218 405.345 260.046L317.401 310.82V277.526C317.401 275.191 318.652 273.005 320.676 271.837L387.644 233.174C414.178 218.353 448.346 222.223 470.901 244.776H470.899ZM357.837 311.144L398.275 334.491V381.185L357.837 404.532L317.398 381.185V334.491L357.837 311.144ZM264.776 269.693C265.207 239.305 285.644 211.649 316.453 203.393C338.3 197.54 360.505 202.744 377.127 215.573L302.014 258.937C298.848 260.764 296.898 264.144 296.898 267.798V369.346L268.065 352.699C266.043 351.531 264.776 349.353 264.776 347.017V269.691V269.693ZM203.391 316.454C209.244 294.608 224.854 277.978 244.276 269.999V356.73C244.276 360.384 246.226 363.763 249.392 365.591L337.337 416.365L308.503 433.013C306.481 434.181 303.961 434.188 301.939 433.02L234.971 394.357C208.868 378.789 195.138 347.261 203.391 316.454ZM244.775 470.9C228.781 454.906 222.186 433.075 224.986 412.264L300.096 455.63C303.263 457.457 307.164 457.457 310.328 455.63L398.273 404.856V438.149C398.273 440.485 397.022 442.671 394.997 443.839L328.029 482.502C301.495 497.322 267.327 493.452 244.772 470.9H244.775ZM450.897 445.982C450.466 476.371 430.029 504.027 399.22 512.283C377.373 518.136 355.168 512.932 338.547 500.102L413.659 456.738C416.826 454.911 418.775 451.532 418.775 447.877V346.329L447.609 362.977C449.631 364.145 450.897 366.323 450.897 368.659V445.985V445.982ZM512.282 399.221C506.429 421.068 490.819 437.697 471.397 445.676V358.946C471.397 355.292 469.448 351.912 466.281 350.085L378.336 299.311L407.17 282.663C409.192 281.495 411.712 281.487 413.734 282.655L480.702 321.318C506.805 336.887 520.536 368.415 512.282 399.221Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="716" height="716" viewBox="157 157 402 402" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M508.749 317.399C516.777 287.314 508.991 253.884 485.389 230.282C461.788 206.681 428.36 198.895 398.273 206.923C376.231 184.928 343.39 174.956 311.148 183.596C278.906 192.234 255.45 217.292 247.36 247.361C217.291 255.451 192.233 278.91 183.595 311.149C174.957 343.391 184.927 376.232 206.924 398.274C198.896 428.359 206.683 461.789 230.284 485.391C253.885 508.992 287.313 516.779 317.401 508.75C339.442 530.745 372.286 540.717 404.525 532.079C436.767 523.441 460.223 498.384 468.313 468.315C498.383 460.224 523.44 436.766 532.078 404.526C540.716 372.285 530.747 339.443 508.749 317.402V317.399ZM470.899 244.776C486.892 260.77 493.488 282.601 490.687 303.412L415.577 260.046C412.411 258.218 408.509 258.218 405.345 260.046L317.401 310.82V277.526C317.401 275.191 318.652 273.005 320.676 271.837L387.644 233.174C414.178 218.353 448.346 222.223 470.901 244.776H470.899ZM357.837 311.144L398.275 334.491V381.185L357.837 404.532L317.398 381.185V334.491L357.837 311.144ZM264.776 269.693C265.207 239.305 285.644 211.649 316.453 203.393C338.3 197.54 360.505 202.744 377.127 215.573L302.014 258.937C298.848 260.764 296.898 264.144 296.898 267.798V369.346L268.065 352.699C266.043 351.531 264.776 349.353 264.776 347.017V269.691V269.693ZM203.391 316.454C209.244 294.608 224.854 277.978 244.276 269.999V356.73C244.276 360.384 246.226 363.763 249.392 365.591L337.337 416.365L308.503 433.013C306.481 434.181 303.961 434.188 301.939 433.02L234.971 394.357C208.868 378.789 195.138 347.261 203.391 316.454ZM244.775 470.9C228.781 454.906 222.186 433.075 224.986 412.264L300.096 455.63C303.263 457.457 307.164 457.457 310.328 455.63L398.273 404.856V438.149C398.273 440.485 397.022 442.671 394.997 443.839L328.029 482.502C301.495 497.322 267.327 493.452 244.772 470.9H244.775ZM450.897 445.982C450.466 476.371 430.029 504.027 399.22 512.283C377.373 518.136 355.168 512.932 338.547 500.102L413.659 456.738C416.826 454.911 418.775 451.532 418.775 447.877V346.329L447.609 362.977C449.631 364.145 450.897 366.323 450.897 368.659V445.985V445.982ZM512.282 399.221C506.429 421.068 490.819 437.697 471.397 445.676V358.946C471.397 355.292 469.448 351.912 466.281 350.085L378.336 299.311L407.17 282.663C409.192 281.495 411.712 281.487 413.734 282.655L480.702 321.318C506.805 336.887 520.536 368.415 512.282 399.221Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width='240' height='300' viewBox='0 0 240 300' fill='none' xmlns='http://www.w3.org/2000/svg'><g clip-path='url(#clip0_1401_86274)'><mask id='mask0_1401_86274' style='mask-type:luminance' maskUnits='userSpaceOnUse' x='0' y='0' width='240' height='300'><path d='M240 0H0V300H240V0Z' fill='white'/></mask><g mask='url(#mask0_1401_86274)'><path d='M180 240H60V120H180V240Z' fill='#CFCECD'/><path d='M180 60H60V240H180V60ZM240 300H0V0H240V300Z' fill='#211E1E'/></g></g><defs><clipPath id='clip0_1401_86274'><rect width='240' height='300' fill='white'/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 577 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width='240' height='300' viewBox='0 0 240 300' fill='none' xmlns='http://www.w3.org/2000/svg'><g clip-path='url(#clip0_1401_86283)'><mask id='mask0_1401_86283' style='mask-type:luminance' maskUnits='userSpaceOnUse' x='0' y='0' width='240' height='300'><path d='M240 0H0V300H240V0Z' fill='white'/></mask><g mask='url(#mask0_1401_86283)'><path d='M180 240H60V120H180V240Z' fill='#4B4646'/><path d='M180 60H60V240H180V60ZM240 300H0V0H240V300Z' fill='#F1ECEC'/></g></g><defs><clipPath id='clip0_1401_86283'><rect width='240' height='300' fill='white'/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 577 B |
@@ -0,0 +1,39 @@
|
|||||||
|
import express from "express";
|
||||||
|
import helmet from "helmet";
|
||||||
|
import cors from "cors";
|
||||||
|
import config from "@server/lib/config";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import {
|
||||||
|
errorHandlerMiddleware,
|
||||||
|
notFoundMiddleware
|
||||||
|
} from "@server/middlewares";
|
||||||
|
import { createAiGatewayRouter } from "@server/routers/aiGateway";
|
||||||
|
|
||||||
|
const aiGatewayPort = config.getRawConfig().server.ai_gateway_port;
|
||||||
|
|
||||||
|
export function createAiGatewayServer() {
|
||||||
|
const aiGatewayServer = express();
|
||||||
|
|
||||||
|
const trustProxy = config.getRawConfig().server.trust_proxy;
|
||||||
|
if (trustProxy) {
|
||||||
|
aiGatewayServer.set("trust proxy", trustProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
aiGatewayServer.use(helmet());
|
||||||
|
aiGatewayServer.use(cors());
|
||||||
|
aiGatewayServer.use(express.json());
|
||||||
|
|
||||||
|
aiGatewayServer.use(createAiGatewayRouter());
|
||||||
|
|
||||||
|
aiGatewayServer.use(notFoundMiddleware);
|
||||||
|
aiGatewayServer.use(errorHandlerMiddleware);
|
||||||
|
|
||||||
|
aiGatewayServer.listen(aiGatewayPort, (err?: any) => {
|
||||||
|
if (err) throw err;
|
||||||
|
logger.info(
|
||||||
|
`AI gateway server is running on http://localhost:${aiGatewayPort}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return aiGatewayServer;
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ export enum ActionsEnum {
|
|||||||
getSite = "getSite",
|
getSite = "getSite",
|
||||||
listSites = "listSites",
|
listSites = "listSites",
|
||||||
updateSite = "updateSite",
|
updateSite = "updateSite",
|
||||||
|
updateSiteApprovals = "updateSiteApprovals",
|
||||||
restartSite = "restartSite",
|
restartSite = "restartSite",
|
||||||
resetSiteBandwidth = "resetSiteBandwidth",
|
resetSiteBandwidth = "resetSiteBandwidth",
|
||||||
reGenerateSecret = "reGenerateSecret",
|
reGenerateSecret = "reGenerateSecret",
|
||||||
@@ -49,6 +50,8 @@ export enum ActionsEnum {
|
|||||||
setResourceUsers = "setResourceUsers",
|
setResourceUsers = "setResourceUsers",
|
||||||
setResourceRoles = "setResourceRoles",
|
setResourceRoles = "setResourceRoles",
|
||||||
listResourceUsers = "listResourceUsers",
|
listResourceUsers = "listResourceUsers",
|
||||||
|
listResourceAiModels = "listResourceAiModels",
|
||||||
|
setResourceAiModels = "setResourceAiModels",
|
||||||
// removeRoleSite = "removeRoleSite",
|
// removeRoleSite = "removeRoleSite",
|
||||||
// addRoleAction = "addRoleAction",
|
// addRoleAction = "addRoleAction",
|
||||||
// removeRoleAction = "removeRoleAction",
|
// removeRoleAction = "removeRoleAction",
|
||||||
@@ -150,6 +153,7 @@ export enum ActionsEnum {
|
|||||||
createAlertRule = "createAlertRule",
|
createAlertRule = "createAlertRule",
|
||||||
updateAlertRule = "updateAlertRule",
|
updateAlertRule = "updateAlertRule",
|
||||||
deleteAlertRule = "deleteAlertRule",
|
deleteAlertRule = "deleteAlertRule",
|
||||||
|
testAlertRule = "testAlertRule",
|
||||||
listAlertRules = "listAlertRules",
|
listAlertRules = "listAlertRules",
|
||||||
listOrgLabels = "listOrgLabels",
|
listOrgLabels = "listOrgLabels",
|
||||||
createOrgLabel = "createOrgLabel",
|
createOrgLabel = "createOrgLabel",
|
||||||
@@ -181,7 +185,27 @@ export enum ActionsEnum {
|
|||||||
setResourcePolicyHeaderAuth = "setResourcePolicyHeaderAuth",
|
setResourcePolicyHeaderAuth = "setResourcePolicyHeaderAuth",
|
||||||
setResourcePolicyWhitelist = "setResourcePolicyWhitelist",
|
setResourcePolicyWhitelist = "setResourcePolicyWhitelist",
|
||||||
setResourcePolicyRules = "setResourcePolicyRules",
|
setResourcePolicyRules = "setResourcePolicyRules",
|
||||||
createOrgWideLauncherView = "createOrgWideLauncherView"
|
createOrgWideLauncherView = "createOrgWideLauncherView",
|
||||||
|
createAiProvider = "createAiProvider",
|
||||||
|
deleteAiProvider = "deleteAiProvider",
|
||||||
|
getAiProvider = "getAiProvider",
|
||||||
|
listAiProviders = "listAiProviders",
|
||||||
|
updateAiProvider = "updateAiProvider",
|
||||||
|
createAiModel = "createAiModel",
|
||||||
|
deleteAiModel = "deleteAiModel",
|
||||||
|
getAiModel = "getAiModel",
|
||||||
|
listAiModels = "listAiModels",
|
||||||
|
updateAiModel = "updateAiModel",
|
||||||
|
createAiBudget = "createAiBudget",
|
||||||
|
deleteAiBudget = "deleteAiBudget",
|
||||||
|
getAiBudget = "getAiBudget",
|
||||||
|
listAiBudgets = "listAiBudgets",
|
||||||
|
updateAiBudget = "updateAiBudget",
|
||||||
|
createVirtualApiKey = "createVirtualApiKey",
|
||||||
|
deleteVirtualApiKey = "deleteVirtualApiKey",
|
||||||
|
getVirtualApiKey = "getVirtualApiKey",
|
||||||
|
listVirtualApiKeys = "listVirtualApiKeys",
|
||||||
|
updateVirtualApiKey = "updateVirtualApiKey"
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkUserActionPermission(
|
export async function checkUserActionPermission(
|
||||||
|
|||||||
@@ -0,0 +1,311 @@
|
|||||||
|
import { canUserAccessResource } from "@server/auth/canUserAccessResource";
|
||||||
|
import {
|
||||||
|
db,
|
||||||
|
users,
|
||||||
|
virtualApiKeyResources,
|
||||||
|
virtualApiKeys,
|
||||||
|
type VirtualApiKey
|
||||||
|
} from "@server/db";
|
||||||
|
import config from "@server/lib/config";
|
||||||
|
import {
|
||||||
|
decryptVirtualApiKeyToken,
|
||||||
|
VIRTUAL_API_KEY_PREFIX,
|
||||||
|
looksLikeVirtualApiKeyCredential
|
||||||
|
} from "@server/lib/virtualApiKey";
|
||||||
|
import { getUserOrgRoles } from "@server/lib/userOrgRoles";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import { isWithinExpirationDate } from "oslo";
|
||||||
|
|
||||||
|
export type VirtualApiKeyCredential = {
|
||||||
|
virtualApiKeyId: string;
|
||||||
|
secret: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type VirtualApiKeyUserData = {
|
||||||
|
userId: string;
|
||||||
|
username: string;
|
||||||
|
email: string | null;
|
||||||
|
name: string | null;
|
||||||
|
role: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function getHeader(
|
||||||
|
headers: Record<string, string> | undefined,
|
||||||
|
name: string
|
||||||
|
): string | undefined {
|
||||||
|
if (!headers) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (headers[name] !== undefined) {
|
||||||
|
return headers[name];
|
||||||
|
}
|
||||||
|
const lower = name.toLowerCase();
|
||||||
|
for (const [key, value] of Object.entries(headers)) {
|
||||||
|
if (key.toLowerCase() === lower) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseVkCredential(
|
||||||
|
raw: string | undefined
|
||||||
|
): VirtualApiKeyCredential | null {
|
||||||
|
if (!raw || !looksLikeVirtualApiKeyCredential(raw)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const withoutPrefix = raw.trim().slice(VIRTUAL_API_KEY_PREFIX.length);
|
||||||
|
const dot = withoutPrefix.indexOf(".");
|
||||||
|
return {
|
||||||
|
virtualApiKeyId: withoutPrefix.slice(0, dot),
|
||||||
|
secret: withoutPrefix.slice(dot + 1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractVirtualApiKeyCredential(
|
||||||
|
headers: Record<string, string> | undefined
|
||||||
|
): VirtualApiKeyCredential | null {
|
||||||
|
if (!headers) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorization = getHeader(headers, "authorization");
|
||||||
|
if (authorization) {
|
||||||
|
const bearerMatch = authorization.match(/^Bearer\s+(.+)$/i);
|
||||||
|
if (bearerMatch) {
|
||||||
|
const credential = parseVkCredential(bearerMatch[1]);
|
||||||
|
if (credential) {
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const splunkMatch = authorization.match(/^Splunk\s+(.+)$/i);
|
||||||
|
if (splunkMatch) {
|
||||||
|
const credential = parseVkCredential(splunkMatch[1]);
|
||||||
|
if (credential) {
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cfAig = getHeader(headers, "cf-aig-authorization");
|
||||||
|
if (cfAig) {
|
||||||
|
const bearerMatch = cfAig.match(/^Bearer\s+(.+)$/i);
|
||||||
|
const credential = parseVkCredential(
|
||||||
|
bearerMatch ? bearerMatch[1] : cfAig
|
||||||
|
);
|
||||||
|
if (credential) {
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const name of ["x-api-key", "x-goog-api-key"] as const) {
|
||||||
|
const credential = parseVkCredential(getHeader(headers, name));
|
||||||
|
if (credential) {
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildUserData(
|
||||||
|
userId: string,
|
||||||
|
orgId: string
|
||||||
|
): Promise<VirtualApiKeyUserData | undefined> {
|
||||||
|
const [user] = await db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.userId, userId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
config.getRawConfig().flags?.require_email_verification &&
|
||||||
|
!user.emailVerified
|
||||||
|
) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userOrgRoles = await getUserOrgRoles(user.userId, orgId);
|
||||||
|
if (userOrgRoles.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId: user.userId,
|
||||||
|
username: user.username,
|
||||||
|
email: user.email,
|
||||||
|
name: user.name,
|
||||||
|
role: userOrgRoles.map((r) => r.roleName).join(", ") || null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function userHasResourceAccess(
|
||||||
|
userId: string,
|
||||||
|
resourceId: number,
|
||||||
|
orgId: string
|
||||||
|
): Promise<{ allowed: boolean; userData?: VirtualApiKeyUserData }> {
|
||||||
|
const [user] = await db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.userId, userId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return { allowed: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
config.getRawConfig().flags?.require_email_verification &&
|
||||||
|
!user.emailVerified
|
||||||
|
) {
|
||||||
|
return { allowed: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
const userOrgRoles = await getUserOrgRoles(user.userId, orgId);
|
||||||
|
if (userOrgRoles.length === 0) {
|
||||||
|
return { allowed: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowed = await canUserAccessResource({
|
||||||
|
userId,
|
||||||
|
resourceId,
|
||||||
|
roleIds: userOrgRoles.map((r) => r.roleId)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return { allowed: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
allowed: true,
|
||||||
|
userData: {
|
||||||
|
userId: user.userId,
|
||||||
|
username: user.username,
|
||||||
|
email: user.email,
|
||||||
|
name: user.name,
|
||||||
|
role: userOrgRoles.map((r) => r.roleName).join(", ") || null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function manualKeyHasResourceAccess(
|
||||||
|
key: VirtualApiKey,
|
||||||
|
resourceId: number
|
||||||
|
): Promise<boolean> {
|
||||||
|
if (key.allResources) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [row] = await db
|
||||||
|
.select({ resourceId: virtualApiKeyResources.resourceId })
|
||||||
|
.from(virtualApiKeyResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(virtualApiKeyResources.virtualApiKeyId, key.virtualApiKeyId),
|
||||||
|
eq(virtualApiKeyResources.resourceId, resourceId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
return Boolean(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function touchLastUsedAt(virtualApiKeyId: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.update(virtualApiKeys)
|
||||||
|
.set({ lastUsedAt: Date.now() })
|
||||||
|
.where(eq(virtualApiKeys.virtualApiKeyId, virtualApiKeyId));
|
||||||
|
} catch {
|
||||||
|
// Best-effort; do not fail auth on audit timestamp updates.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function verifyVirtualApiKey({
|
||||||
|
credential,
|
||||||
|
resourceId,
|
||||||
|
orgId
|
||||||
|
}: {
|
||||||
|
credential: VirtualApiKeyCredential;
|
||||||
|
resourceId: number;
|
||||||
|
orgId: string;
|
||||||
|
}): Promise<{
|
||||||
|
valid: boolean;
|
||||||
|
error?: string;
|
||||||
|
key?: VirtualApiKey;
|
||||||
|
userData?: VirtualApiKeyUserData;
|
||||||
|
}> {
|
||||||
|
const [key] = await db
|
||||||
|
.select()
|
||||||
|
.from(virtualApiKeys)
|
||||||
|
.where(eq(virtualApiKeys.virtualApiKeyId, credential.virtualApiKeyId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
return { valid: false, error: "Virtual API key not found" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.orgId !== orgId) {
|
||||||
|
return { valid: false, error: "Virtual API key org mismatch" };
|
||||||
|
}
|
||||||
|
|
||||||
|
let plaintext: string;
|
||||||
|
try {
|
||||||
|
plaintext = decryptVirtualApiKeyToken(key.token);
|
||||||
|
} catch {
|
||||||
|
return { valid: false, error: "Virtual API key secret is invalid" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plaintext !== credential.secret) {
|
||||||
|
return { valid: false, error: "Invalid virtual API key secret" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.expiresAt && !isWithinExpirationDate(new Date(key.expiresAt))) {
|
||||||
|
return { valid: false, error: "Virtual API key has expired" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.kind === "manual") {
|
||||||
|
const scoped = await manualKeyHasResourceAccess(key, resourceId);
|
||||||
|
if (!scoped) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
error: "Virtual API key is not scoped to this resource"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let userData: VirtualApiKeyUserData | undefined;
|
||||||
|
if (key.userId) {
|
||||||
|
userData = await buildUserData(key.userId, orgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
await touchLastUsedAt(key.virtualApiKeyId);
|
||||||
|
return { valid: true, key, userData };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.kind === "user") {
|
||||||
|
if (!key.userId) {
|
||||||
|
return { valid: false, error: "User virtual API key has no user" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const access = await userHasResourceAccess(
|
||||||
|
key.userId,
|
||||||
|
resourceId,
|
||||||
|
orgId
|
||||||
|
);
|
||||||
|
if (!access.allowed || !access.userData) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
error: "User is not allowed to access this resource"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await touchLastUsedAt(key.virtualApiKeyId);
|
||||||
|
return { valid: true, key, userData: access.userData };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { valid: false, error: "Unknown virtual API key kind" };
|
||||||
|
}
|
||||||
@@ -3,12 +3,16 @@ import { flushConnectionLogToDb } from "#dynamic/routers/newt";
|
|||||||
import { flushSiteBandwidthToDb } from "@server/routers/gerbil/receiveBandwidth";
|
import { flushSiteBandwidthToDb } from "@server/routers/gerbil/receiveBandwidth";
|
||||||
import { stopPingAccumulator } from "@server/routers/newt/pingAccumulator";
|
import { stopPingAccumulator } from "@server/routers/newt/pingAccumulator";
|
||||||
import { cleanup as wsCleanup } from "#dynamic/routers/ws";
|
import { cleanup as wsCleanup } from "#dynamic/routers/ws";
|
||||||
|
import { shutdownUsageRecorder } from "@server/lib/aiBudgetEnforcement";
|
||||||
|
import { shutdownAiSessionLogger } from "@server/routers/aiGateway/logAiSession";
|
||||||
|
|
||||||
async function cleanup() {
|
async function cleanup() {
|
||||||
await stopPingAccumulator();
|
await stopPingAccumulator();
|
||||||
await flushBandwidthToDb();
|
await flushBandwidthToDb();
|
||||||
await flushConnectionLogToDb();
|
await flushConnectionLogToDb();
|
||||||
await flushSiteBandwidthToDb();
|
await flushSiteBandwidthToDb();
|
||||||
|
await shutdownUsageRecorder();
|
||||||
|
await shutdownAiSessionLogger();
|
||||||
await wsCleanup();
|
await wsCleanup();
|
||||||
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import {
|
import {
|
||||||
|
aiProviders,
|
||||||
clients,
|
clients,
|
||||||
db,
|
db,
|
||||||
resourcePolicies,
|
resourcePolicies,
|
||||||
@@ -113,6 +114,32 @@ export async function getUniqueResourceName(orgId: string): Promise<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getUniqueProviderName(orgId: string): Promise<string> {
|
||||||
|
let loops = 0;
|
||||||
|
while (true) {
|
||||||
|
if (loops > 100) {
|
||||||
|
throw new Error("Could not generate a unique name");
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = generateName();
|
||||||
|
|
||||||
|
const aiProviderCount = await db
|
||||||
|
.select({
|
||||||
|
niceId: aiProviders.niceId,
|
||||||
|
orgId: aiProviders.orgId
|
||||||
|
})
|
||||||
|
.from(aiProviders)
|
||||||
|
.where(
|
||||||
|
and(eq(aiProviders.niceId, name), eq(aiProviders.orgId, orgId))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (aiProviderCount.length === 0) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
loops++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getUniqueResourcePolicyName(
|
export async function getUniqueResourcePolicyName(
|
||||||
orgId: string
|
orgId: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
|||||||
@@ -29,25 +29,6 @@ import {
|
|||||||
labels
|
labels
|
||||||
} from "./schema";
|
} from "./schema";
|
||||||
|
|
||||||
export const certificates = pgTable("certificates", {
|
|
||||||
certId: serial("certId").primaryKey(),
|
|
||||||
domain: varchar("domain", { length: 255 }).notNull().unique(),
|
|
||||||
domainId: varchar("domainId").references(() => domains.domainId, {
|
|
||||||
onDelete: "cascade"
|
|
||||||
}),
|
|
||||||
wildcard: boolean("wildcard").default(false),
|
|
||||||
status: varchar("status", { length: 50 }).notNull().default("pending"), // pending, requested, valid, expired, failed
|
|
||||||
expiresAt: bigint("expiresAt", { mode: "number" }),
|
|
||||||
lastRenewalAttempt: bigint("lastRenewalAttempt", { mode: "number" }),
|
|
||||||
createdAt: bigint("createdAt", { mode: "number" }).notNull(),
|
|
||||||
updatedAt: bigint("updatedAt", { mode: "number" }).notNull(),
|
|
||||||
orderId: varchar("orderId", { length: 500 }),
|
|
||||||
errorMessage: text("errorMessage"),
|
|
||||||
renewalCount: integer("renewalCount").default(0),
|
|
||||||
certFile: text("certFile"),
|
|
||||||
keyFile: text("keyFile")
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dnsChallenge = pgTable("dnsChallenges", {
|
export const dnsChallenge = pgTable("dnsChallenges", {
|
||||||
dnsChallengeId: serial("dnsChallengeId").primaryKey(),
|
dnsChallengeId: serial("dnsChallengeId").primaryKey(),
|
||||||
domain: varchar("domain", { length: 255 }).notNull(),
|
domain: varchar("domain", { length: 255 }).notNull(),
|
||||||
@@ -95,7 +76,8 @@ export const subscriptions = pgTable("subscriptions", {
|
|||||||
billingCycleAnchor: bigint("billingCycleAnchor", { mode: "number" }),
|
billingCycleAnchor: bigint("billingCycleAnchor", { mode: "number" }),
|
||||||
expiresAt: bigint("expiresAt", { mode: "number" }),
|
expiresAt: bigint("expiresAt", { mode: "number" }),
|
||||||
trial: boolean("trial").default(false),
|
trial: boolean("trial").default(false),
|
||||||
type: varchar("type", { length: 50 }) // tier1, tier2, tier3, or license
|
type: varchar("type", { length: 50 }), // tier1, tier2, tier3, or license
|
||||||
|
override: boolean("override").default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
export const subscriptionItems = pgTable("subscriptionItems", {
|
export const subscriptionItems = pgTable("subscriptionItems", {
|
||||||
@@ -632,7 +614,6 @@ export const trialNotifications = pgTable("trialNotifications", {
|
|||||||
export type Approval = InferSelectModel<typeof approvals>;
|
export type Approval = InferSelectModel<typeof approvals>;
|
||||||
export type Limit = InferSelectModel<typeof limits>;
|
export type Limit = InferSelectModel<typeof limits>;
|
||||||
export type Account = InferSelectModel<typeof account>;
|
export type Account = InferSelectModel<typeof account>;
|
||||||
export type Certificate = InferSelectModel<typeof certificates>;
|
|
||||||
export type DnsChallenge = InferSelectModel<typeof dnsChallenge>;
|
export type DnsChallenge = InferSelectModel<typeof dnsChallenge>;
|
||||||
export type Customer = InferSelectModel<typeof customers>;
|
export type Customer = InferSelectModel<typeof customers>;
|
||||||
export type Subscription = InferSelectModel<typeof subscriptions>;
|
export type Subscription = InferSelectModel<typeof subscriptions>;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { InferSelectModel, sql } from "drizzle-orm";
|
|||||||
import {
|
import {
|
||||||
bigint,
|
bigint,
|
||||||
boolean,
|
boolean,
|
||||||
|
check,
|
||||||
index,
|
index,
|
||||||
integer,
|
integer,
|
||||||
pgTable,
|
pgTable,
|
||||||
@@ -11,6 +12,7 @@ import {
|
|||||||
serial,
|
serial,
|
||||||
text,
|
text,
|
||||||
unique,
|
unique,
|
||||||
|
uniqueIndex,
|
||||||
varchar
|
varchar
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ export const domains = pgTable("domains", {
|
|||||||
domainId: varchar("domainId").primaryKey(),
|
domainId: varchar("domainId").primaryKey(),
|
||||||
baseDomain: varchar("baseDomain").notNull(),
|
baseDomain: varchar("baseDomain").notNull(),
|
||||||
configManaged: boolean("configManaged").notNull().default(false),
|
configManaged: boolean("configManaged").notNull().default(false),
|
||||||
type: varchar("type"), // "ns", "cname", "wildcard"
|
type: varchar("type").$type<"ns" | "cname" | "wildcard">(),
|
||||||
verified: boolean("verified").notNull().default(false),
|
verified: boolean("verified").notNull().default(false),
|
||||||
failed: boolean("failed").notNull().default(false),
|
failed: boolean("failed").notNull().default(false),
|
||||||
tries: integer("tries").notNull().default(0),
|
tries: integer("tries").notNull().default(0),
|
||||||
@@ -63,6 +65,11 @@ export const orgs = pgTable("orgs", {
|
|||||||
) // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
|
) // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
|
||||||
.notNull()
|
.notNull()
|
||||||
.default(0),
|
.default(0),
|
||||||
|
settingsLogRetentionDaysAISessions: integer(
|
||||||
|
"settingsLogRetentionDaysAISessions"
|
||||||
|
) // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
|
||||||
|
.notNull()
|
||||||
|
.default(7),
|
||||||
sshCaPrivateKey: text("sshCaPrivateKey"), // Encrypted SSH CA private key (PEM format)
|
sshCaPrivateKey: text("sshCaPrivateKey"), // Encrypted SSH CA private key (PEM format)
|
||||||
sshCaPublicKey: text("sshCaPublicKey"), // SSH CA public key (OpenSSH format)
|
sshCaPublicKey: text("sshCaPublicKey"), // SSH CA public key (OpenSSH format)
|
||||||
isBillingOrg: boolean("isBillingOrg"),
|
isBillingOrg: boolean("isBillingOrg"),
|
||||||
@@ -98,7 +105,7 @@ export const sites = pgTable(
|
|||||||
}),
|
}),
|
||||||
name: varchar("name").notNull(),
|
name: varchar("name").notNull(),
|
||||||
pubKey: varchar("pubKey"),
|
pubKey: varchar("pubKey"),
|
||||||
subnet: varchar("subnet"),
|
exitNodeSubnet: text("exitNodeSubnet"), // this is the subnet when connecting to an exit node and INCLUDES THE CIDR
|
||||||
megabytesIn: real("bytesIn").default(0),
|
megabytesIn: real("bytesIn").default(0),
|
||||||
megabytesOut: real("bytesOut").default(0),
|
megabytesOut: real("bytesOut").default(0),
|
||||||
lastBandwidthUpdate: varchar("lastBandwidthUpdate"),
|
lastBandwidthUpdate: varchar("lastBandwidthUpdate"),
|
||||||
@@ -107,6 +114,7 @@ export const sites = pgTable(
|
|||||||
lastPing: integer("lastPing"),
|
lastPing: integer("lastPing"),
|
||||||
address: varchar("address"),
|
address: varchar("address"),
|
||||||
endpoint: varchar("endpoint"),
|
endpoint: varchar("endpoint"),
|
||||||
|
localEndpoints: varchar("localEndpoints"), // JSON encoded list of string ips on the local machine to try to connect to
|
||||||
publicKey: varchar("publicKey"),
|
publicKey: varchar("publicKey"),
|
||||||
lastHolePunch: bigint("lastHolePunch", { mode: "number" }),
|
lastHolePunch: bigint("lastHolePunch", { mode: "number" }),
|
||||||
listenPort: integer("listenPort"),
|
listenPort: integer("listenPort"),
|
||||||
@@ -193,14 +201,22 @@ export const resources = pgTable(
|
|||||||
postAuthPath: text("postAuthPath"),
|
postAuthPath: text("postAuthPath"),
|
||||||
health: varchar("health").default("unknown"), // "healthy", "unhealthy", "unknown"
|
health: varchar("health").default("unknown"), // "healthy", "unhealthy", "unknown"
|
||||||
wildcard: boolean("wildcard").notNull().default(false),
|
wildcard: boolean("wildcard").notNull().default(false),
|
||||||
mode: text("mode").default("http").notNull(), // rdp, ssh, http, vnc
|
mode: text("mode")
|
||||||
|
.default("http")
|
||||||
|
.$type<
|
||||||
|
"rdp" | "ssh" | "http" | "vnc" | "inference" | "tcp" | "udp"
|
||||||
|
>()
|
||||||
|
.notNull(),
|
||||||
pamMode: varchar("pamMode", { length: 32 })
|
pamMode: varchar("pamMode", { length: 32 })
|
||||||
.$type<"passthrough" | "push">()
|
.$type<"passthrough" | "push">()
|
||||||
.default("passthrough"),
|
.default("passthrough"),
|
||||||
authDaemonMode: varchar("authDaemonMode", { length: 32 })
|
authDaemonMode: varchar("authDaemonMode", { length: 32 })
|
||||||
.$type<"site" | "remote" | "native">()
|
.$type<"site" | "remote" | "native">()
|
||||||
.default("site"),
|
.default("site"),
|
||||||
authDaemonPort: integer("authDaemonPort").default(22123)
|
authDaemonPort: integer("authDaemonPort").default(22123),
|
||||||
|
status: varchar("status")
|
||||||
|
.$type<"pending" | "approved">()
|
||||||
|
.default("approved")
|
||||||
},
|
},
|
||||||
(t) => [
|
(t) => [
|
||||||
index("idx_resources_fulldomain")
|
index("idx_resources_fulldomain")
|
||||||
@@ -211,6 +227,41 @@ export const resources = pgTable(
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const resourceAiProviders = pgTable(
|
||||||
|
"resourceAiProviders",
|
||||||
|
{
|
||||||
|
resourceId: integer("resourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||||
|
providerId: integer("providerId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiProviders.providerId, { onDelete: "cascade" }),
|
||||||
|
accessMode: varchar("accessMode")
|
||||||
|
.$type<"inherit" | "select">()
|
||||||
|
.notNull()
|
||||||
|
.default("inherit"),
|
||||||
|
enabled: boolean("enabled").notNull().default(true)
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.resourceId, t.providerId] })]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const resourceAiModels = pgTable(
|
||||||
|
"resourceAiModels",
|
||||||
|
{
|
||||||
|
resourceId: integer("resourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||||
|
modelId: integer("modelId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiModels.modelId, { onDelete: "cascade" }),
|
||||||
|
listType: varchar("listType")
|
||||||
|
.$type<"allow" | "block">()
|
||||||
|
.notNull()
|
||||||
|
.default("allow")
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.resourceId, t.modelId] })]
|
||||||
|
);
|
||||||
|
|
||||||
export const labels = pgTable("labels", {
|
export const labels = pgTable("labels", {
|
||||||
labelId: serial("labelId").primaryKey(),
|
labelId: serial("labelId").primaryKey(),
|
||||||
name: varchar("name").notNull(),
|
name: varchar("name").notNull(),
|
||||||
@@ -313,11 +364,18 @@ export const targets = pgTable(
|
|||||||
"targets",
|
"targets",
|
||||||
{
|
{
|
||||||
targetId: serial("targetId").primaryKey(),
|
targetId: serial("targetId").primaryKey(),
|
||||||
resourceId: integer("resourceId")
|
resourceId: integer("resourceId").references(
|
||||||
.references(() => resources.resourceId, {
|
() => resources.resourceId,
|
||||||
|
{
|
||||||
onDelete: "cascade"
|
onDelete: "cascade"
|
||||||
})
|
}
|
||||||
.notNull(),
|
),
|
||||||
|
providerId: integer("providerId").references(
|
||||||
|
() => aiProviders.providerId,
|
||||||
|
{
|
||||||
|
onDelete: "cascade"
|
||||||
|
}
|
||||||
|
),
|
||||||
siteId: integer("siteId")
|
siteId: integer("siteId")
|
||||||
.references(() => sites.siteId, {
|
.references(() => sites.siteId, {
|
||||||
onDelete: "cascade"
|
onDelete: "cascade"
|
||||||
@@ -341,6 +399,7 @@ export const targets = pgTable(
|
|||||||
},
|
},
|
||||||
(t) => [
|
(t) => [
|
||||||
index("idx_targets_resourceid_siteid").on(t.resourceId, t.siteId),
|
index("idx_targets_resourceid_siteid").on(t.resourceId, t.siteId),
|
||||||
|
index("idx_targets_providerid_siteid").on(t.providerId, t.siteId),
|
||||||
index("idx_targets_site_enabled_priority_target_resource")
|
index("idx_targets_site_enabled_priority_target_resource")
|
||||||
.on(t.siteId, t.priority.desc(), t.targetId, t.resourceId)
|
.on(t.siteId, t.priority.desc(), t.targetId, t.resourceId)
|
||||||
.where(sql`${t.enabled} = true`)
|
.where(sql`${t.enabled} = true`)
|
||||||
@@ -420,11 +479,14 @@ export const siteResources = pgTable(
|
|||||||
onDelete: "restrict"
|
onDelete: "restrict"
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
requiresExitNodeConnection: boolean("requiresExitNodeConnection")
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
niceId: varchar("niceId").notNull(),
|
niceId: varchar("niceId").notNull(),
|
||||||
name: varchar("name").notNull(),
|
name: varchar("name").notNull(),
|
||||||
ssl: boolean("ssl").notNull().default(false),
|
ssl: boolean("ssl").notNull().default(false),
|
||||||
mode: varchar("mode")
|
mode: varchar("mode")
|
||||||
.$type<"host" | "cidr" | "http" | "ssh">()
|
.$type<"host" | "cidr" | "http" | "ssh" | "inference">()
|
||||||
.notNull(), // "host" | "cidr" | "http"
|
.notNull(), // "host" | "cidr" | "http"
|
||||||
scheme: varchar("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
|
scheme: varchar("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
|
||||||
proxyPort: integer("proxyPort"), // only for port mode
|
proxyPort: integer("proxyPort"), // only for port mode
|
||||||
@@ -451,11 +513,53 @@ export const siteResources = pgTable(
|
|||||||
onDelete: "set null"
|
onDelete: "set null"
|
||||||
}),
|
}),
|
||||||
subdomain: varchar("subdomain"),
|
subdomain: varchar("subdomain"),
|
||||||
fullDomain: varchar("fullDomain")
|
fullDomain: varchar("fullDomain"),
|
||||||
|
status: varchar("status")
|
||||||
|
.$type<"pending" | "approved">()
|
||||||
|
.default("approved")
|
||||||
},
|
},
|
||||||
(t) => [index("idx_siteresources_orgid_niceid").on(t.orgId, t.niceId)]
|
(t) => [index("idx_siteresources_orgid_niceid").on(t.orgId, t.niceId)]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const siteResourceAiProviders = pgTable(
|
||||||
|
"siteResourceAiProviders",
|
||||||
|
{
|
||||||
|
siteResourceId: integer("siteResourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => siteResources.siteResourceId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
providerId: integer("providerId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiProviders.providerId, { onDelete: "cascade" }),
|
||||||
|
accessMode: varchar("accessMode")
|
||||||
|
.$type<"inherit" | "select">()
|
||||||
|
.notNull()
|
||||||
|
.default("inherit"),
|
||||||
|
enabled: boolean("enabled").notNull().default(true)
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.siteResourceId, t.providerId] })]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const siteResourceAiModels = pgTable(
|
||||||
|
"siteResourceAiModels",
|
||||||
|
{
|
||||||
|
siteResourceId: integer("siteResourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => siteResources.siteResourceId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
modelId: integer("modelId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiModels.modelId, { onDelete: "cascade" }),
|
||||||
|
listType: varchar("listType")
|
||||||
|
.$type<"allow" | "block">()
|
||||||
|
.notNull()
|
||||||
|
.default("allow")
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.siteResourceId, t.modelId] })]
|
||||||
|
);
|
||||||
|
|
||||||
export const networks = pgTable(
|
export const networks = pgTable(
|
||||||
"networks",
|
"networks",
|
||||||
{
|
{
|
||||||
@@ -658,7 +762,7 @@ export const roles = pgTable("roles", {
|
|||||||
name: varchar("name").notNull(),
|
name: varchar("name").notNull(),
|
||||||
description: varchar("description"),
|
description: varchar("description"),
|
||||||
requireDeviceApproval: boolean("requireDeviceApproval").default(false),
|
requireDeviceApproval: boolean("requireDeviceApproval").default(false),
|
||||||
sshSudoMode: varchar("sshSudoMode", { length: 32 }).default("none"), // "none" | "full" | "commands"
|
sshSudoMode: varchar("sshSudoMode", { length: 32 }).default("full"), // "none" | "full" | "commands"
|
||||||
sshSudoCommands: text("sshSudoCommands").default("[]"),
|
sshSudoCommands: text("sshSudoCommands").default("[]"),
|
||||||
sshCreateHomeDir: boolean("sshCreateHomeDir").default(true),
|
sshCreateHomeDir: boolean("sshCreateHomeDir").default(true),
|
||||||
sshUnixGroups: text("sshUnixGroups").default("[]")
|
sshUnixGroups: text("sshUnixGroups").default("[]")
|
||||||
@@ -899,12 +1003,16 @@ export const resourceAccessToken = pgTable("resourceAccessToken", {
|
|||||||
resourceId: integer("resourceId")
|
resourceId: integer("resourceId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||||
|
userId: varchar("userId").references(() => users.userId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
path: varchar("path"),
|
path: varchar("path"),
|
||||||
tokenHash: varchar("tokenHash").notNull(),
|
tokenHash: varchar("tokenHash").notNull(),
|
||||||
sessionLength: bigint("sessionLength", { mode: "number" }).notNull(),
|
sessionLength: bigint("sessionLength", { mode: "number" }).notNull(),
|
||||||
expiresAt: bigint("expiresAt", { mode: "number" }),
|
expiresAt: bigint("expiresAt", { mode: "number" }),
|
||||||
title: varchar("title"),
|
title: varchar("title"),
|
||||||
description: varchar("description"),
|
description: varchar("description"),
|
||||||
|
persistSession: boolean("persistSession").notNull().default(false),
|
||||||
createdAt: bigint("createdAt", { mode: "number" }).notNull()
|
createdAt: bigint("createdAt", { mode: "number" }).notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1139,6 +1247,52 @@ export const apiKeyOrg = pgTable("apiKeyOrg", {
|
|||||||
.notNull()
|
.notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const virtualApiKeys = pgTable(
|
||||||
|
"virtualApiKeys",
|
||||||
|
{
|
||||||
|
virtualApiKeyId: varchar("virtualApiKeyId").primaryKey(),
|
||||||
|
orgId: varchar("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
kind: varchar("kind").$type<"user" | "manual">().notNull(),
|
||||||
|
userId: varchar("userId").references(() => users.userId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
name: varchar("name"),
|
||||||
|
description: varchar("description"),
|
||||||
|
token: varchar("token").notNull(),
|
||||||
|
lastChars: varchar("lastChars").notNull(),
|
||||||
|
allResources: boolean("allResources").notNull().default(false),
|
||||||
|
expiresAt: bigint("expiresAt", { mode: "number" }),
|
||||||
|
lastUsedAt: bigint("lastUsedAt", { mode: "number" }),
|
||||||
|
createdAt: bigint("createdAt", { mode: "number" }).notNull(),
|
||||||
|
createdByUserId: varchar("createdByUserId").references(
|
||||||
|
() => users.userId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
uniqueIndex("virtual_api_key_user_identity_uniq")
|
||||||
|
.on(t.orgId, t.userId)
|
||||||
|
.where(sql`${t.kind} = 'user'`)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const virtualApiKeyResources = pgTable(
|
||||||
|
"virtualApiKeyResources",
|
||||||
|
{
|
||||||
|
virtualApiKeyId: varchar("virtualApiKeyId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => virtualApiKeys.virtualApiKeyId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
resourceId: integer("resourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => resources.resourceId, { onDelete: "cascade" })
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.virtualApiKeyId, t.resourceId] })]
|
||||||
|
);
|
||||||
|
|
||||||
export const idpOrg = pgTable("idpOrg", {
|
export const idpOrg = pgTable("idpOrg", {
|
||||||
idpId: integer("idpId")
|
idpId: integer("idpId")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -1171,6 +1325,7 @@ export const clients = pgTable(
|
|||||||
name: varchar("name").notNull(),
|
name: varchar("name").notNull(),
|
||||||
pubKey: varchar("pubKey"),
|
pubKey: varchar("pubKey"),
|
||||||
subnet: varchar("subnet").notNull(),
|
subnet: varchar("subnet").notNull(),
|
||||||
|
exitNodeSubnet: varchar("exitNodeSubnet"), // INCLUDES THE CIDR
|
||||||
megabytesIn: real("bytesIn"),
|
megabytesIn: real("bytesIn"),
|
||||||
megabytesOut: real("bytesOut"),
|
megabytesOut: real("bytesOut"),
|
||||||
lastBandwidthUpdate: varchar("lastBandwidthUpdate"),
|
lastBandwidthUpdate: varchar("lastBandwidthUpdate"),
|
||||||
@@ -1529,6 +1684,358 @@ export const statusHistory = pgTable(
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const aiProviders = pgTable(
|
||||||
|
"aiProviders",
|
||||||
|
{
|
||||||
|
providerId: serial("providerId").primaryKey(),
|
||||||
|
orgId: varchar("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
name: varchar("name").notNull(),
|
||||||
|
niceId: varchar("niceId").notNull(),
|
||||||
|
type: varchar("type")
|
||||||
|
.$type<
|
||||||
|
| "openai"
|
||||||
|
| "anthropic"
|
||||||
|
| "googleGemini"
|
||||||
|
| "vertexAi"
|
||||||
|
| "bedrock"
|
||||||
|
| "microsoftFoundry"
|
||||||
|
| "openRouter"
|
||||||
|
| "vercelAiGateway"
|
||||||
|
| "custom"
|
||||||
|
>()
|
||||||
|
.notNull(),
|
||||||
|
upstreamUrl: text("upstreamUrl"),
|
||||||
|
apiKey: text("apiKey"),
|
||||||
|
apiKeyLastChars: varchar("apiKeyLastChars"),
|
||||||
|
authType: varchar("authType")
|
||||||
|
.$type<
|
||||||
|
| "bearer"
|
||||||
|
| "x-api-key"
|
||||||
|
| "x-goog-api-key"
|
||||||
|
| "hec"
|
||||||
|
| "cf-aig-authorization"
|
||||||
|
| "none"
|
||||||
|
| "passthrough"
|
||||||
|
>()
|
||||||
|
.notNull(),
|
||||||
|
routingMode: varchar("routingMode")
|
||||||
|
.$type<"url" | "target">()
|
||||||
|
.notNull()
|
||||||
|
.default("url"),
|
||||||
|
capabilities: text("capabilities").notNull().default("[]"),
|
||||||
|
headers: text("headers"), // JSON array of { name, value }
|
||||||
|
skipTlsVerification: boolean("skipTlsVerification")
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
enabled: boolean("enabled").notNull().default(true),
|
||||||
|
createdAt: bigint("createdAt", { mode: "number" }).notNull(),
|
||||||
|
updatedAt: bigint("updatedAt", { mode: "number" }).notNull()
|
||||||
|
},
|
||||||
|
(t) => [index("idx_aiProviders_orgId_niceId").on(t.orgId, t.niceId)]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const aiModels = pgTable(
|
||||||
|
"aiModels",
|
||||||
|
{
|
||||||
|
modelId: serial("modelId").primaryKey(),
|
||||||
|
providerId: integer("providerId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiProviders.providerId, { onDelete: "cascade" }),
|
||||||
|
modelKey: varchar("modelKey").notNull(),
|
||||||
|
name: varchar("name").notNull(),
|
||||||
|
listType: varchar("listType")
|
||||||
|
.$type<"allow" | "block">()
|
||||||
|
.notNull()
|
||||||
|
.default("allow"),
|
||||||
|
enabled: boolean("enabled").notNull().default(true),
|
||||||
|
createdAt: bigint("createdAt", { mode: "number" }).notNull(),
|
||||||
|
updatedAt: bigint("updatedAt", { mode: "number" }).notNull()
|
||||||
|
},
|
||||||
|
(t) => [unique("ai_model_provider_key_uniq").on(t.providerId, t.modelKey)]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const aiBudgets = pgTable(
|
||||||
|
"aiBudgets",
|
||||||
|
{
|
||||||
|
budgetId: serial("budgetId").primaryKey(),
|
||||||
|
orgId: varchar("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
providerId: integer("providerId").references(
|
||||||
|
() => aiProviders.providerId,
|
||||||
|
{ onDelete: "cascade" }
|
||||||
|
),
|
||||||
|
modelId: integer("modelId").references(() => aiModels.modelId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
resourceId: integer("resourceId").references(
|
||||||
|
() => resources.resourceId,
|
||||||
|
{ onDelete: "cascade" }
|
||||||
|
),
|
||||||
|
siteResourceId: integer("siteResourceId").references(
|
||||||
|
() => siteResources.siteResourceId,
|
||||||
|
{ onDelete: "cascade" }
|
||||||
|
),
|
||||||
|
roleId: integer("roleId").references(() => roles.roleId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
virtualApiKeyId: varchar("virtualApiKeyId").references(
|
||||||
|
() => virtualApiKeys.virtualApiKeyId,
|
||||||
|
{ onDelete: "cascade" }
|
||||||
|
),
|
||||||
|
amount: real("amount").notNull(),
|
||||||
|
unit: varchar("unit").$type<"usd" | "tokens">().notNull(),
|
||||||
|
period: varchar("period")
|
||||||
|
.$type<
|
||||||
|
| "monthly"
|
||||||
|
| "yearly"
|
||||||
|
| "lifetime"
|
||||||
|
| "daily"
|
||||||
|
| "hourly"
|
||||||
|
| "weekly"
|
||||||
|
>()
|
||||||
|
.notNull()
|
||||||
|
.default("monthly"),
|
||||||
|
enforcement: varchar("enforcement")
|
||||||
|
.$type<"hard" | "soft">()
|
||||||
|
.notNull()
|
||||||
|
.default("hard"),
|
||||||
|
enabled: boolean("enabled").notNull().default(true),
|
||||||
|
createdAt: bigint("createdAt", { mode: "number" }).notNull(),
|
||||||
|
updatedAt: bigint("updatedAt", { mode: "number" }).notNull()
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
unique("ai_budget_provider_uniq").on(t.providerId, t.unit, t.period),
|
||||||
|
unique("ai_budget_model_uniq").on(t.modelId, t.unit, t.period),
|
||||||
|
unique("ai_budget_resource_uniq").on(t.resourceId, t.unit, t.period),
|
||||||
|
unique("ai_budget_site_resource_uniq").on(
|
||||||
|
t.siteResourceId,
|
||||||
|
t.unit,
|
||||||
|
t.period
|
||||||
|
),
|
||||||
|
unique("ai_budget_role_uniq").on(t.roleId, t.unit, t.period),
|
||||||
|
unique("ai_budget_virtual_api_key_uniq").on(
|
||||||
|
t.virtualApiKeyId,
|
||||||
|
t.unit,
|
||||||
|
t.period
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const aiUsageRecords = pgTable(
|
||||||
|
"aiUsageRecords",
|
||||||
|
{
|
||||||
|
id: serial("id").primaryKey(),
|
||||||
|
orgId: varchar("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
providerId: integer("providerId").references(
|
||||||
|
() => aiProviders.providerId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
resourceId: integer("resourceId").references(
|
||||||
|
() => resources.resourceId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
siteResourceId: integer("siteResourceId").references(
|
||||||
|
() => siteResources.siteResourceId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
userId: varchar("userId").references(() => users.userId, {
|
||||||
|
onDelete: "set null"
|
||||||
|
}),
|
||||||
|
virtualApiKeyId: varchar("virtualApiKeyId").references(
|
||||||
|
() => virtualApiKeys.virtualApiKeyId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
// Links this usage record back to the aiSessionLog row for the same
|
||||||
|
// request (aiSessionLog.sessionId), so token/cost usage can be shown
|
||||||
|
// alongside the session transcript. Not a DB-level FK - aiSessionLog
|
||||||
|
// lives in the separate logs database. Nullable because the session
|
||||||
|
// log may be disabled (retention set to 0) while usage tracking
|
||||||
|
// stays on.
|
||||||
|
sessionId: varchar("sessionId"),
|
||||||
|
requestedModel: varchar("requestedModel").notNull(),
|
||||||
|
promptTokens: integer("promptTokens").notNull().default(0),
|
||||||
|
cacheReadTokens: integer("cacheReadTokens").notNull().default(0),
|
||||||
|
cacheWriteTokens: integer("cacheWriteTokens").notNull().default(0),
|
||||||
|
completionTokens: integer("completionTokens").notNull().default(0),
|
||||||
|
reasoningTokens: integer("reasoningTokens").notNull().default(0),
|
||||||
|
totalTokens: integer("totalTokens").notNull().default(0),
|
||||||
|
costUsd: real("costUsd"),
|
||||||
|
estimated: boolean("estimated").notNull().default(false),
|
||||||
|
createdAt: bigint("createdAt", { mode: "number" }).notNull()
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
index("idx_ai_usage_records_org_provider_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.providerId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_org_resource_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.resourceId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_org_site_resource_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.siteResourceId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_org_user_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.userId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_org_virtual_api_key_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.virtualApiKeyId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_session").on(t.sessionId)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const aiBudgetBreachEvents = pgTable(
|
||||||
|
"aiBudgetBreachEvents",
|
||||||
|
{
|
||||||
|
id: serial("id").primaryKey(),
|
||||||
|
orgId: varchar("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
budgetId: integer("budgetId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiBudgets.budgetId, { onDelete: "cascade" }),
|
||||||
|
enforcement: varchar("enforcement").$type<"hard" | "soft">().notNull(),
|
||||||
|
unit: varchar("unit").$type<"usd" | "tokens">().notNull(),
|
||||||
|
period: varchar("period")
|
||||||
|
.$type<
|
||||||
|
| "monthly"
|
||||||
|
| "yearly"
|
||||||
|
| "lifetime"
|
||||||
|
| "daily"
|
||||||
|
| "hourly"
|
||||||
|
| "weekly"
|
||||||
|
>()
|
||||||
|
.notNull(),
|
||||||
|
amount: real("amount").notNull(),
|
||||||
|
usageAmount: real("usageAmount").notNull(),
|
||||||
|
blocked: boolean("blocked").notNull(),
|
||||||
|
requestUserId: varchar("requestUserId").references(() => users.userId, {
|
||||||
|
onDelete: "set null"
|
||||||
|
}),
|
||||||
|
createdAt: bigint("createdAt", { mode: "number" }).notNull()
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
index("idx_ai_budget_breach_events_budget_created").on(
|
||||||
|
t.budgetId,
|
||||||
|
t.createdAt
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Logs the aggregated prompt + response for a single AI gateway request, for
|
||||||
|
// session replay. One row per request (not per streaming chunk). `sessionId`
|
||||||
|
// is a fresh random id per row for now - no cross-request correlation yet,
|
||||||
|
// but the column exists so a future pass can link multiple rows into a real
|
||||||
|
// multi-turn session.
|
||||||
|
export const aiSessionLog = pgTable(
|
||||||
|
"aiSessionLog",
|
||||||
|
{
|
||||||
|
id: serial("id").primaryKey(),
|
||||||
|
sessionId: varchar("sessionId").notNull(),
|
||||||
|
orgId: varchar("orgId").references(() => orgs.orgId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
providerId: integer("providerId").references(
|
||||||
|
() => aiProviders.providerId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
capability: varchar("capability").notNull(),
|
||||||
|
resourceId: integer("resourceId").references(
|
||||||
|
() => resources.resourceId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
siteResourceId: integer("siteResourceId").references(
|
||||||
|
() => siteResources.siteResourceId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
userId: varchar("userId").references(() => users.userId, {
|
||||||
|
onDelete: "set null"
|
||||||
|
}),
|
||||||
|
virtualApiKeyId: varchar("virtualApiKeyId").references(
|
||||||
|
() => virtualApiKeys.virtualApiKeyId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
requestedModel: varchar("requestedModel"),
|
||||||
|
isStream: boolean("isStream").notNull().default(false),
|
||||||
|
requestBody: text("requestBody"),
|
||||||
|
responseBody: text("responseBody"),
|
||||||
|
// Capability-agnostic message transcript (JSON-encoded
|
||||||
|
// NormalizedAiMessage[] from server/lib/aiMessageNormalization.ts),
|
||||||
|
// computed at write time so search/display never need per-capability
|
||||||
|
// parsing logic. Null when normalization couldn't recognize the
|
||||||
|
// shape - callers fall back to requestBody/responseBody.
|
||||||
|
normalizedRequest: text("normalizedRequest"),
|
||||||
|
normalizedResponse: text("normalizedResponse"),
|
||||||
|
// True if any of the request/response (raw or normalized) fields
|
||||||
|
// were cut short at AI_SESSION_LOG_MAX_BODY_CHARS before storage.
|
||||||
|
truncated: boolean("truncated").notNull().default(false),
|
||||||
|
statusCode: integer("statusCode"),
|
||||||
|
createdAt: bigint("createdAt", { mode: "number" }).notNull() // epoch ms
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
index("idx_ai_session_log_org_created").on(t.orgId, t.createdAt),
|
||||||
|
index("idx_ai_session_log_org_provider_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.providerId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_org_resource_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.resourceId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_org_site_resource_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.siteResourceId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_org_user_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.userId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_org_virtual_api_key_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.virtualApiKeyId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_session").on(t.sessionId)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const certificates = pgTable("certificates", {
|
||||||
|
certId: serial("certId").primaryKey(),
|
||||||
|
domain: varchar("domain", { length: 255 }).notNull().unique(),
|
||||||
|
domainId: varchar("domainId").references(() => domains.domainId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
wildcard: boolean("wildcard").default(false),
|
||||||
|
status: varchar("status", { length: 50 }).notNull().default("pending"), // pending, requested, valid, expired, failed
|
||||||
|
expiresAt: bigint("expiresAt", { mode: "number" }),
|
||||||
|
lastRenewalAttempt: bigint("lastRenewalAttempt", { mode: "number" }),
|
||||||
|
createdAt: bigint("createdAt", { mode: "number" }).notNull(),
|
||||||
|
updatedAt: bigint("updatedAt", { mode: "number" }).notNull(),
|
||||||
|
orderId: varchar("orderId", { length: 500 }),
|
||||||
|
errorMessage: text("errorMessage"),
|
||||||
|
renewalCount: integer("renewalCount").default(0),
|
||||||
|
certFile: text("certFile"),
|
||||||
|
keyFile: text("keyFile")
|
||||||
|
});
|
||||||
|
|
||||||
export type Org = InferSelectModel<typeof orgs>;
|
export type Org = InferSelectModel<typeof orgs>;
|
||||||
export type User = InferSelectModel<typeof users>;
|
export type User = InferSelectModel<typeof users>;
|
||||||
export type Site = InferSelectModel<typeof sites>;
|
export type Site = InferSelectModel<typeof sites>;
|
||||||
@@ -1584,6 +2091,10 @@ export type Idp = InferSelectModel<typeof idp>;
|
|||||||
export type ApiKey = InferSelectModel<typeof apiKeys>;
|
export type ApiKey = InferSelectModel<typeof apiKeys>;
|
||||||
export type ApiKeyAction = InferSelectModel<typeof apiKeyActions>;
|
export type ApiKeyAction = InferSelectModel<typeof apiKeyActions>;
|
||||||
export type ApiKeyOrg = InferSelectModel<typeof apiKeyOrg>;
|
export type ApiKeyOrg = InferSelectModel<typeof apiKeyOrg>;
|
||||||
|
export type VirtualApiKey = InferSelectModel<typeof virtualApiKeys>;
|
||||||
|
export type VirtualApiKeyResource = InferSelectModel<
|
||||||
|
typeof virtualApiKeyResources
|
||||||
|
>;
|
||||||
export type Client = InferSelectModel<typeof clients>;
|
export type Client = InferSelectModel<typeof clients>;
|
||||||
export type ClientSite = InferSelectModel<typeof clientSitesAssociationsCache>;
|
export type ClientSite = InferSelectModel<typeof clientSitesAssociationsCache>;
|
||||||
export type Olm = InferSelectModel<typeof olms>;
|
export type Olm = InferSelectModel<typeof olms>;
|
||||||
@@ -1613,3 +2124,16 @@ export type ResourcePolicy = InferSelectModel<typeof resourcePolicies>;
|
|||||||
export type RolePolicy = InferSelectModel<typeof rolePolicies>;
|
export type RolePolicy = InferSelectModel<typeof rolePolicies>;
|
||||||
export type UserPolicy = InferSelectModel<typeof userPolicies>;
|
export type UserPolicy = InferSelectModel<typeof userPolicies>;
|
||||||
export type ResourcePolicyRule = InferSelectModel<typeof resourcePolicyRules>;
|
export type ResourcePolicyRule = InferSelectModel<typeof resourcePolicyRules>;
|
||||||
|
export type AiProvider = InferSelectModel<typeof aiProviders>;
|
||||||
|
export type AiModel = InferSelectModel<typeof aiModels>;
|
||||||
|
export type AiBudget = InferSelectModel<typeof aiBudgets>;
|
||||||
|
export type AiUsageRecord = InferSelectModel<typeof aiUsageRecords>;
|
||||||
|
export type AiBudgetBreachEvent = InferSelectModel<typeof aiBudgetBreachEvents>;
|
||||||
|
export type AiSessionLog = InferSelectModel<typeof aiSessionLog>;
|
||||||
|
export type ResourceAiProvider = InferSelectModel<typeof resourceAiProviders>;
|
||||||
|
export type SiteResourceAiProvider = InferSelectModel<
|
||||||
|
typeof siteResourceAiProviders
|
||||||
|
>;
|
||||||
|
export type ResourceAiModel = InferSelectModel<typeof resourceAiModels>;
|
||||||
|
export type SiteResourceAiModel = InferSelectModel<typeof siteResourceAiModels>;
|
||||||
|
export type Certificate = InferSelectModel<typeof certificates>;
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ import {
|
|||||||
resourcePolicyPassword,
|
resourcePolicyPassword,
|
||||||
ResourcePolicyPassword,
|
ResourcePolicyPassword,
|
||||||
resourcePolicyHeaderAuth,
|
resourcePolicyHeaderAuth,
|
||||||
ResourcePolicyHeaderAuth
|
ResourcePolicyHeaderAuth,
|
||||||
|
resourceWhitelist,
|
||||||
|
resourcePolicyWhiteList
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { alias } from "@server/db";
|
import { alias } from "@server/db";
|
||||||
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
||||||
@@ -448,6 +450,36 @@ export async function getResourceRules(
|
|||||||
return [...directRules, ...offsetPolicyRules] as ResourceRule[];
|
return [...directRules, ...offsetPolicyRules] as ResourceRule[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the whitelisted email associated with a resource session's whitelist
|
||||||
|
* match (either a direct resource whitelist entry or a resource policy
|
||||||
|
* whitelist entry).
|
||||||
|
*/
|
||||||
|
export async function getWhitelistEmail(
|
||||||
|
whitelistId?: number | null,
|
||||||
|
policyWhitelistId?: number | null
|
||||||
|
): Promise<string | null> {
|
||||||
|
if (whitelistId) {
|
||||||
|
const [row] = await db
|
||||||
|
.select({ email: resourceWhitelist.email })
|
||||||
|
.from(resourceWhitelist)
|
||||||
|
.where(eq(resourceWhitelist.whitelistId, whitelistId))
|
||||||
|
.limit(1);
|
||||||
|
return row?.email ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (policyWhitelistId) {
|
||||||
|
const [row] = await db
|
||||||
|
.select({ email: resourcePolicyWhiteList.email })
|
||||||
|
.from(resourcePolicyWhiteList)
|
||||||
|
.where(eq(resourcePolicyWhiteList.whitelistId, policyWhitelistId))
|
||||||
|
.limit(1);
|
||||||
|
return row?.email ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get organization login page
|
* Get organization login page
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import path from "path";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { APP_PATH } from "@server/lib/consts";
|
import { APP_PATH } from "@server/lib/consts";
|
||||||
import { existsSync, mkdirSync } from "fs";
|
import { existsSync, mkdirSync } from "fs";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
|
||||||
export const location = path.join(APP_PATH, "db", "db.sqlite");
|
export const location = path.join(APP_PATH, "db", "db.sqlite");
|
||||||
export const exists = checkFileExists(location);
|
export const exists = checkFileExists(location);
|
||||||
@@ -12,7 +13,11 @@ export const exists = checkFileExists(location);
|
|||||||
bootstrapVolume();
|
bootstrapVolume();
|
||||||
|
|
||||||
function createDb() {
|
function createDb() {
|
||||||
const sqlite = new Database(location);
|
const verbose =
|
||||||
|
process.env.QUERY_LOGGING == "true"
|
||||||
|
? (message: unknown) => logger.debug(String(message))
|
||||||
|
: undefined;
|
||||||
|
const sqlite = new Database(location, { verbose });
|
||||||
|
|
||||||
if (process.env.ENABLE_SQLITE_WAL_MODE == "true") {
|
if (process.env.ENABLE_SQLITE_WAL_MODE == "true") {
|
||||||
// Enable WAL mode — allows concurrent readers + single writer, preventing
|
// Enable WAL mode — allows concurrent readers + single writer, preventing
|
||||||
|
|||||||
@@ -23,25 +23,6 @@ import {
|
|||||||
users
|
users
|
||||||
} from "./schema";
|
} from "./schema";
|
||||||
|
|
||||||
export const certificates = sqliteTable("certificates", {
|
|
||||||
certId: integer("certId").primaryKey({ autoIncrement: true }),
|
|
||||||
domain: text("domain").notNull().unique(),
|
|
||||||
domainId: text("domainId").references(() => domains.domainId, {
|
|
||||||
onDelete: "cascade"
|
|
||||||
}),
|
|
||||||
wildcard: integer("wildcard", { mode: "boolean" }).default(false),
|
|
||||||
status: text("status").notNull().default("pending"), // pending, requested, valid, expired, failed
|
|
||||||
expiresAt: integer("expiresAt"),
|
|
||||||
lastRenewalAttempt: integer("lastRenewalAttempt"),
|
|
||||||
createdAt: integer("createdAt").notNull(),
|
|
||||||
updatedAt: integer("updatedAt").notNull(),
|
|
||||||
orderId: text("orderId"),
|
|
||||||
errorMessage: text("errorMessage"),
|
|
||||||
renewalCount: integer("renewalCount").default(0),
|
|
||||||
certFile: text("certFile"),
|
|
||||||
keyFile: text("keyFile")
|
|
||||||
});
|
|
||||||
|
|
||||||
export const dnsChallenge = sqliteTable("dnsChallenges", {
|
export const dnsChallenge = sqliteTable("dnsChallenges", {
|
||||||
dnsChallengeId: integer("dnsChallengeId").primaryKey({
|
dnsChallengeId: integer("dnsChallengeId").primaryKey({
|
||||||
autoIncrement: true
|
autoIncrement: true
|
||||||
@@ -89,7 +70,8 @@ export const subscriptions = sqliteTable("subscriptions", {
|
|||||||
expiresAt: integer("expiresAt"),
|
expiresAt: integer("expiresAt"),
|
||||||
trial: integer("trial", { mode: "boolean" }).default(false),
|
trial: integer("trial", { mode: "boolean" }).default(false),
|
||||||
billingCycleAnchor: integer("billingCycleAnchor"),
|
billingCycleAnchor: integer("billingCycleAnchor"),
|
||||||
type: text("type") // tier1, tier2, tier3, or license
|
type: text("type"), // tier1, tier2, tier3, or license
|
||||||
|
override: integer("override", { mode: "boolean" }).default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
export const subscriptionItems = sqliteTable("subscriptionItems", {
|
export const subscriptionItems = sqliteTable("subscriptionItems", {
|
||||||
@@ -627,7 +609,6 @@ export const trialNotifications = sqliteTable("trialNotifications", {
|
|||||||
export type Approval = InferSelectModel<typeof approvals>;
|
export type Approval = InferSelectModel<typeof approvals>;
|
||||||
export type Limit = InferSelectModel<typeof limits>;
|
export type Limit = InferSelectModel<typeof limits>;
|
||||||
export type Account = InferSelectModel<typeof account>;
|
export type Account = InferSelectModel<typeof account>;
|
||||||
export type Certificate = InferSelectModel<typeof certificates>;
|
|
||||||
export type DnsChallenge = InferSelectModel<typeof dnsChallenge>;
|
export type DnsChallenge = InferSelectModel<typeof dnsChallenge>;
|
||||||
export type Customer = InferSelectModel<typeof customers>;
|
export type Customer = InferSelectModel<typeof customers>;
|
||||||
export type Subscription = InferSelectModel<typeof subscriptions>;
|
export type Subscription = InferSelectModel<typeof subscriptions>;
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import { randomUUID } from "crypto";
|
import { randomUUID } from "crypto";
|
||||||
import { InferSelectModel } from "drizzle-orm";
|
import { InferSelectModel, sql } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
|
check,
|
||||||
index,
|
index,
|
||||||
integer,
|
integer,
|
||||||
primaryKey,
|
primaryKey,
|
||||||
|
real,
|
||||||
sqliteTable,
|
sqliteTable,
|
||||||
text,
|
text,
|
||||||
unique
|
unique,
|
||||||
|
uniqueIndex
|
||||||
} from "drizzle-orm/sqlite-core";
|
} from "drizzle-orm/sqlite-core";
|
||||||
|
|
||||||
export const domains = sqliteTable("domains", {
|
export const domains = sqliteTable("domains", {
|
||||||
@@ -15,7 +18,7 @@ export const domains = sqliteTable("domains", {
|
|||||||
configManaged: integer("configManaged", { mode: "boolean" })
|
configManaged: integer("configManaged", { mode: "boolean" })
|
||||||
.notNull()
|
.notNull()
|
||||||
.default(false),
|
.default(false),
|
||||||
type: text("type"), // "ns", "cname", "wildcard"
|
type: text("type").$type<"ns" | "cname" | "wildcard">(),
|
||||||
verified: integer("verified", { mode: "boolean" }).notNull().default(false),
|
verified: integer("verified", { mode: "boolean" }).notNull().default(false),
|
||||||
failed: integer("failed", { mode: "boolean" }).notNull().default(false),
|
failed: integer("failed", { mode: "boolean" }).notNull().default(false),
|
||||||
tries: integer("tries").notNull().default(0),
|
tries: integer("tries").notNull().default(0),
|
||||||
@@ -61,6 +64,11 @@ export const orgs = sqliteTable("orgs", {
|
|||||||
) // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
|
) // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
|
||||||
.notNull()
|
.notNull()
|
||||||
.default(0),
|
.default(0),
|
||||||
|
settingsLogRetentionDaysAISessions: integer(
|
||||||
|
"settingsLogRetentionDaysAISessions"
|
||||||
|
) // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
|
||||||
|
.notNull()
|
||||||
|
.default(7),
|
||||||
sshCaPrivateKey: text("sshCaPrivateKey"), // Encrypted SSH CA private key (PEM format)
|
sshCaPrivateKey: text("sshCaPrivateKey"), // Encrypted SSH CA private key (PEM format)
|
||||||
sshCaPublicKey: text("sshCaPublicKey"), // SSH CA public key (OpenSSH format)
|
sshCaPublicKey: text("sshCaPublicKey"), // SSH CA public key (OpenSSH format)
|
||||||
isBillingOrg: integer("isBillingOrg", { mode: "boolean" }),
|
isBillingOrg: integer("isBillingOrg", { mode: "boolean" }),
|
||||||
@@ -107,7 +115,7 @@ export const sites = sqliteTable("sites", {
|
|||||||
}),
|
}),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
pubKey: text("pubKey"),
|
pubKey: text("pubKey"),
|
||||||
subnet: text("subnet"),
|
exitNodeSubnet: text("exitNodeSubnet"),
|
||||||
megabytesIn: integer("bytesIn").default(0),
|
megabytesIn: integer("bytesIn").default(0),
|
||||||
megabytesOut: integer("bytesOut").default(0),
|
megabytesOut: integer("bytesOut").default(0),
|
||||||
lastBandwidthUpdate: text("lastBandwidthUpdate"),
|
lastBandwidthUpdate: text("lastBandwidthUpdate"),
|
||||||
@@ -118,6 +126,7 @@ export const sites = sqliteTable("sites", {
|
|||||||
// exit node stuff that is how to connect to the site when it has a wg server
|
// exit node stuff that is how to connect to the site when it has a wg server
|
||||||
address: text("address"), // this is the address of the wireguard interface in newt
|
address: text("address"), // this is the address of the wireguard interface in newt
|
||||||
endpoint: text("endpoint"), // this is how to reach gerbil externally - gets put into the wireguard config
|
endpoint: text("endpoint"), // this is how to reach gerbil externally - gets put into the wireguard config
|
||||||
|
localEndpoints: text("localEndpoints"), // JSON encoded list of string ips on the local machine to try to connect to
|
||||||
publicKey: text("publicKey"), // TODO: Fix typo in publicKey
|
publicKey: text("publicKey"), // TODO: Fix typo in publicKey
|
||||||
lastHolePunch: integer("lastHolePunch"),
|
lastHolePunch: integer("lastHolePunch"),
|
||||||
listenPort: integer("listenPort"),
|
listenPort: integer("listenPort"),
|
||||||
@@ -202,16 +211,55 @@ export const resources = sqliteTable("resources", {
|
|||||||
postAuthPath: text("postAuthPath"),
|
postAuthPath: text("postAuthPath"),
|
||||||
health: text("health").default("unknown"), // "healthy", "unhealthy", "unknown"
|
health: text("health").default("unknown"), // "healthy", "unhealthy", "unknown"
|
||||||
wildcard: integer("wildcard", { mode: "boolean" }).notNull().default(false),
|
wildcard: integer("wildcard", { mode: "boolean" }).notNull().default(false),
|
||||||
mode: text("mode").default("http").notNull(), // rdp, ssh, http, vnc
|
mode: text("mode")
|
||||||
|
.default("http")
|
||||||
|
.$type<"rdp" | "ssh" | "http" | "vnc" | "inference" | "tcp" | "udp">()
|
||||||
|
.notNull(), // rdp, ssh, http, vnc, inference
|
||||||
pamMode: text("pamMode")
|
pamMode: text("pamMode")
|
||||||
.$type<"passthrough" | "push">()
|
.$type<"passthrough" | "push">()
|
||||||
.default("passthrough"),
|
.default("passthrough"),
|
||||||
authDaemonMode: text("authDaemonMode")
|
authDaemonMode: text("authDaemonMode")
|
||||||
.$type<"site" | "remote" | "native">()
|
.$type<"site" | "remote" | "native">()
|
||||||
.default("site"),
|
.default("site"),
|
||||||
authDaemonPort: integer("authDaemonPort").default(22123)
|
authDaemonPort: integer("authDaemonPort").default(22123),
|
||||||
|
status: text("status").$type<"pending" | "approved">().default("approved")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const resourceAiProviders = sqliteTable(
|
||||||
|
"resourceAiProviders",
|
||||||
|
{
|
||||||
|
resourceId: integer("resourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||||
|
providerId: integer("providerId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiProviders.providerId, { onDelete: "cascade" }),
|
||||||
|
accessMode: text("accessMode")
|
||||||
|
.$type<"inherit" | "select">()
|
||||||
|
.notNull()
|
||||||
|
.default("inherit"),
|
||||||
|
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true)
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.resourceId, t.providerId] })]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const resourceAiModels = sqliteTable(
|
||||||
|
"resourceAiModels",
|
||||||
|
{
|
||||||
|
resourceId: integer("resourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||||
|
modelId: integer("modelId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiModels.modelId, { onDelete: "cascade" }),
|
||||||
|
listType: text("listType")
|
||||||
|
.$type<"allow" | "block">()
|
||||||
|
.notNull()
|
||||||
|
.default("allow")
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.resourceId, t.modelId] })]
|
||||||
|
);
|
||||||
|
|
||||||
export const labels = sqliteTable("labels", {
|
export const labels = sqliteTable("labels", {
|
||||||
labelId: integer("labelId").primaryKey({ autoIncrement: true }),
|
labelId: integer("labelId").primaryKey({ autoIncrement: true }),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
@@ -320,11 +368,12 @@ export const clientLabels = sqliteTable(
|
|||||||
|
|
||||||
export const targets = sqliteTable("targets", {
|
export const targets = sqliteTable("targets", {
|
||||||
targetId: integer("targetId").primaryKey({ autoIncrement: true }),
|
targetId: integer("targetId").primaryKey({ autoIncrement: true }),
|
||||||
resourceId: integer("resourceId")
|
resourceId: integer("resourceId").references(() => resources.resourceId, {
|
||||||
.references(() => resources.resourceId, {
|
onDelete: "cascade"
|
||||||
onDelete: "cascade"
|
}),
|
||||||
})
|
providerId: integer("providerId").references(() => aiProviders.providerId, {
|
||||||
.notNull(),
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
siteId: integer("siteId")
|
siteId: integer("siteId")
|
||||||
.references(() => sites.siteId, {
|
.references(() => sites.siteId, {
|
||||||
onDelete: "cascade"
|
onDelete: "cascade"
|
||||||
@@ -420,10 +469,17 @@ export const siteResources = sqliteTable("siteResources", {
|
|||||||
() => networks.networkId,
|
() => networks.networkId,
|
||||||
{ onDelete: "restrict" }
|
{ onDelete: "restrict" }
|
||||||
),
|
),
|
||||||
|
requiresExitNodeConnection: integer("requiresExitNodeConnection", {
|
||||||
|
mode: "boolean"
|
||||||
|
})
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
niceId: text("niceId").notNull(),
|
niceId: text("niceId").notNull(),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
ssl: integer("ssl", { mode: "boolean" }).notNull().default(false),
|
ssl: integer("ssl", { mode: "boolean" }).notNull().default(false),
|
||||||
mode: text("mode").$type<"host" | "cidr" | "http" | "ssh">().notNull(), // "host" | "cidr" | "http"
|
mode: text("mode")
|
||||||
|
.$type<"host" | "cidr" | "http" | "ssh" | "inference">()
|
||||||
|
.notNull(), // "host" | "cidr" | "http"
|
||||||
scheme: text("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
|
scheme: text("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
|
||||||
proxyPort: integer("proxyPort"), // only for port mode
|
proxyPort: integer("proxyPort"), // only for port mode
|
||||||
destinationPort: integer("destinationPort"), // only for port mode
|
destinationPort: integer("destinationPort"), // only for port mode
|
||||||
@@ -447,9 +503,49 @@ export const siteResources = sqliteTable("siteResources", {
|
|||||||
onDelete: "set null"
|
onDelete: "set null"
|
||||||
}),
|
}),
|
||||||
subdomain: text("subdomain"),
|
subdomain: text("subdomain"),
|
||||||
fullDomain: text("fullDomain")
|
fullDomain: text("fullDomain"),
|
||||||
|
status: text("status").$type<"pending" | "approved">().default("approved")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const siteResourceAiProviders = sqliteTable(
|
||||||
|
"siteResourceAiProviders",
|
||||||
|
{
|
||||||
|
siteResourceId: integer("siteResourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => siteResources.siteResourceId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
providerId: integer("providerId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiProviders.providerId, { onDelete: "cascade" }),
|
||||||
|
accessMode: text("accessMode")
|
||||||
|
.$type<"inherit" | "select">()
|
||||||
|
.notNull()
|
||||||
|
.default("inherit"),
|
||||||
|
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true)
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.siteResourceId, t.providerId] })]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const siteResourceAiModels = sqliteTable(
|
||||||
|
"siteResourceAiModels",
|
||||||
|
{
|
||||||
|
siteResourceId: integer("siteResourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => siteResources.siteResourceId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
modelId: integer("modelId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiModels.modelId, { onDelete: "cascade" }),
|
||||||
|
listType: text("listType")
|
||||||
|
.$type<"allow" | "block">()
|
||||||
|
.notNull()
|
||||||
|
.default("allow")
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.siteResourceId, t.modelId] })]
|
||||||
|
);
|
||||||
|
|
||||||
export const networks = sqliteTable("networks", {
|
export const networks = sqliteTable("networks", {
|
||||||
networkId: integer("networkId").primaryKey({ autoIncrement: true }),
|
networkId: integer("networkId").primaryKey({ autoIncrement: true }),
|
||||||
niceId: text("niceId"),
|
niceId: text("niceId"),
|
||||||
@@ -596,6 +692,7 @@ export const clients = sqliteTable("clients", {
|
|||||||
pubKey: text("pubKey"),
|
pubKey: text("pubKey"),
|
||||||
olmId: text("olmId"), // to lock it to a specific olm optionally
|
olmId: text("olmId"), // to lock it to a specific olm optionally
|
||||||
subnet: text("subnet").notNull(),
|
subnet: text("subnet").notNull(),
|
||||||
|
exitNodeSubnet: text("exitNodeSubnet"), // this is the subnet when connecting to an exit node
|
||||||
megabytesIn: integer("bytesIn"),
|
megabytesIn: integer("bytesIn"),
|
||||||
megabytesOut: integer("bytesOut"),
|
megabytesOut: integer("bytesOut"),
|
||||||
lastBandwidthUpdate: text("lastBandwidthUpdate"),
|
lastBandwidthUpdate: text("lastBandwidthUpdate"),
|
||||||
@@ -898,7 +995,7 @@ export const roles = sqliteTable("roles", {
|
|||||||
requireDeviceApproval: integer("requireDeviceApproval", {
|
requireDeviceApproval: integer("requireDeviceApproval", {
|
||||||
mode: "boolean"
|
mode: "boolean"
|
||||||
}).default(false),
|
}).default(false),
|
||||||
sshSudoMode: text("sshSudoMode").default("none"), // "none" | "full" | "commands"
|
sshSudoMode: text("sshSudoMode").default("full"), // "none" | "full" | "commands"
|
||||||
sshSudoCommands: text("sshSudoCommands").default("[]"),
|
sshSudoCommands: text("sshSudoCommands").default("[]"),
|
||||||
sshCreateHomeDir: integer("sshCreateHomeDir", { mode: "boolean" }).default(
|
sshCreateHomeDir: integer("sshCreateHomeDir", { mode: "boolean" }).default(
|
||||||
true
|
true
|
||||||
@@ -1123,12 +1220,18 @@ export const resourceAccessToken = sqliteTable("resourceAccessToken", {
|
|||||||
resourceId: integer("resourceId")
|
resourceId: integer("resourceId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
.references(() => resources.resourceId, { onDelete: "cascade" }),
|
||||||
|
userId: text("userId").references(() => users.userId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
path: text("path"),
|
path: text("path"),
|
||||||
tokenHash: text("tokenHash").notNull(),
|
tokenHash: text("tokenHash").notNull(),
|
||||||
sessionLength: integer("sessionLength").notNull(),
|
sessionLength: integer("sessionLength").notNull(),
|
||||||
expiresAt: integer("expiresAt"),
|
expiresAt: integer("expiresAt"),
|
||||||
title: text("title"),
|
title: text("title"),
|
||||||
description: text("description"),
|
description: text("description"),
|
||||||
|
persistSession: integer("persistSession", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
createdAt: integer("createdAt").notNull()
|
createdAt: integer("createdAt").notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1402,6 +1505,54 @@ export const apiKeyOrg = sqliteTable("apiKeyOrg", {
|
|||||||
.notNull()
|
.notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const virtualApiKeys = sqliteTable(
|
||||||
|
"virtualApiKeys",
|
||||||
|
{
|
||||||
|
virtualApiKeyId: text("virtualApiKeyId").primaryKey(),
|
||||||
|
orgId: text("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
kind: text("kind").$type<"user" | "manual">().notNull(),
|
||||||
|
userId: text("userId").references(() => users.userId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
name: text("name"),
|
||||||
|
description: text("description"),
|
||||||
|
token: text("token").notNull(),
|
||||||
|
lastChars: text("lastChars").notNull(),
|
||||||
|
allResources: integer("allResources", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
expiresAt: integer("expiresAt"),
|
||||||
|
lastUsedAt: integer("lastUsedAt"),
|
||||||
|
createdAt: integer("createdAt").notNull(),
|
||||||
|
createdByUserId: text("createdByUserId").references(
|
||||||
|
() => users.userId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
uniqueIndex("virtual_api_key_user_identity_uniq")
|
||||||
|
.on(t.orgId, t.userId)
|
||||||
|
.where(sql`${t.kind} = 'user'`)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const virtualApiKeyResources = sqliteTable(
|
||||||
|
"virtualApiKeyResources",
|
||||||
|
{
|
||||||
|
virtualApiKeyId: text("virtualApiKeyId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => virtualApiKeys.virtualApiKeyId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
resourceId: integer("resourceId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => resources.resourceId, { onDelete: "cascade" })
|
||||||
|
},
|
||||||
|
(t) => [primaryKey({ columns: [t.virtualApiKeyId, t.resourceId] })]
|
||||||
|
);
|
||||||
|
|
||||||
export const idpOrg = sqliteTable("idpOrg", {
|
export const idpOrg = sqliteTable("idpOrg", {
|
||||||
idpId: integer("idpId")
|
idpId: integer("idpId")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -1517,6 +1668,370 @@ export const statusHistory = sqliteTable(
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const aiProviders = sqliteTable(
|
||||||
|
"aiProviders",
|
||||||
|
{
|
||||||
|
providerId: integer("providerId").primaryKey({ autoIncrement: true }),
|
||||||
|
orgId: text("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
niceId: text("niceId").notNull(),
|
||||||
|
type: text("type")
|
||||||
|
.$type<
|
||||||
|
| "openai"
|
||||||
|
| "anthropic"
|
||||||
|
| "googleGemini"
|
||||||
|
| "vertexAi"
|
||||||
|
| "bedrock"
|
||||||
|
| "microsoftFoundry"
|
||||||
|
| "openRouter"
|
||||||
|
| "vercelAiGateway"
|
||||||
|
| "custom"
|
||||||
|
>()
|
||||||
|
.notNull(),
|
||||||
|
upstreamUrl: text("upstreamUrl"),
|
||||||
|
apiKey: text("apiKey"),
|
||||||
|
apiKeyLastChars: text("apiKeyLastChars"),
|
||||||
|
authType: text("authType")
|
||||||
|
.$type<
|
||||||
|
| "bearer"
|
||||||
|
| "x-api-key"
|
||||||
|
| "x-goog-api-key"
|
||||||
|
| "hec"
|
||||||
|
| "cf-aig-authorization"
|
||||||
|
| "none"
|
||||||
|
| "passthrough"
|
||||||
|
>()
|
||||||
|
.notNull(),
|
||||||
|
routingMode: text("routingMode")
|
||||||
|
.$type<"url" | "target">()
|
||||||
|
.notNull()
|
||||||
|
.default("url"),
|
||||||
|
capabilities: text("capabilities").notNull().default("[]"),
|
||||||
|
headers: text("headers"), // JSON array of { name, value }
|
||||||
|
skipTlsVerification: integer("skipTlsVerification", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
enabled: integer("enabled", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(true),
|
||||||
|
createdAt: integer("createdAt").notNull(),
|
||||||
|
updatedAt: integer("updatedAt").notNull()
|
||||||
|
},
|
||||||
|
(t) => [index("idx_aiProviders_orgId_niceId").on(t.orgId, t.niceId)]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const aiModels = sqliteTable(
|
||||||
|
"aiModels",
|
||||||
|
{
|
||||||
|
modelId: integer("modelId").primaryKey({ autoIncrement: true }),
|
||||||
|
providerId: integer("providerId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiProviders.providerId, { onDelete: "cascade" }),
|
||||||
|
modelKey: text("modelKey").notNull(),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
listType: text("listType")
|
||||||
|
.$type<"allow" | "block">()
|
||||||
|
.notNull()
|
||||||
|
.default("allow"),
|
||||||
|
enabled: integer("enabled", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(true),
|
||||||
|
createdAt: integer("createdAt").notNull(),
|
||||||
|
updatedAt: integer("updatedAt").notNull()
|
||||||
|
},
|
||||||
|
(t) => [unique("ai_model_provider_key_uniq").on(t.providerId, t.modelKey)]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const aiBudgets = sqliteTable(
|
||||||
|
"aiBudgets",
|
||||||
|
{
|
||||||
|
budgetId: integer("budgetId").primaryKey({ autoIncrement: true }),
|
||||||
|
orgId: text("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
providerId: integer("providerId").references(
|
||||||
|
() => aiProviders.providerId,
|
||||||
|
{ onDelete: "cascade" }
|
||||||
|
),
|
||||||
|
modelId: integer("modelId").references(() => aiModels.modelId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
resourceId: integer("resourceId").references(
|
||||||
|
() => resources.resourceId,
|
||||||
|
{ onDelete: "cascade" }
|
||||||
|
),
|
||||||
|
siteResourceId: integer("siteResourceId").references(
|
||||||
|
() => siteResources.siteResourceId,
|
||||||
|
{ onDelete: "cascade" }
|
||||||
|
),
|
||||||
|
roleId: integer("roleId").references(() => roles.roleId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
virtualApiKeyId: text("virtualApiKeyId").references(
|
||||||
|
() => virtualApiKeys.virtualApiKeyId,
|
||||||
|
{ onDelete: "cascade" }
|
||||||
|
),
|
||||||
|
amount: real("amount").notNull(),
|
||||||
|
unit: text("unit").$type<"usd" | "tokens">().notNull(),
|
||||||
|
period: text("period")
|
||||||
|
.$type<
|
||||||
|
| "monthly"
|
||||||
|
| "yearly"
|
||||||
|
| "lifetime"
|
||||||
|
| "daily"
|
||||||
|
| "hourly"
|
||||||
|
| "weekly"
|
||||||
|
>()
|
||||||
|
.notNull()
|
||||||
|
.default("monthly"),
|
||||||
|
enforcement: text("enforcement")
|
||||||
|
.$type<"hard" | "soft">()
|
||||||
|
.notNull()
|
||||||
|
.default("hard"),
|
||||||
|
enabled: integer("enabled", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(true),
|
||||||
|
createdAt: integer("createdAt").notNull(),
|
||||||
|
updatedAt: integer("updatedAt").notNull()
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
unique("ai_budget_provider_uniq").on(t.providerId, t.unit, t.period),
|
||||||
|
unique("ai_budget_model_uniq").on(t.modelId, t.unit, t.period),
|
||||||
|
unique("ai_budget_resource_uniq").on(t.resourceId, t.unit, t.period),
|
||||||
|
unique("ai_budget_site_resource_uniq").on(
|
||||||
|
t.siteResourceId,
|
||||||
|
t.unit,
|
||||||
|
t.period
|
||||||
|
),
|
||||||
|
unique("ai_budget_role_uniq").on(t.roleId, t.unit, t.period),
|
||||||
|
unique("ai_budget_virtual_api_key_uniq").on(
|
||||||
|
t.virtualApiKeyId,
|
||||||
|
t.unit,
|
||||||
|
t.period
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const aiUsageRecords = sqliteTable(
|
||||||
|
"aiUsageRecords",
|
||||||
|
{
|
||||||
|
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||||
|
orgId: text("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
providerId: integer("providerId").references(
|
||||||
|
() => aiProviders.providerId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
resourceId: integer("resourceId").references(
|
||||||
|
() => resources.resourceId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
siteResourceId: integer("siteResourceId").references(
|
||||||
|
() => siteResources.siteResourceId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
userId: text("userId").references(() => users.userId, {
|
||||||
|
onDelete: "set null"
|
||||||
|
}),
|
||||||
|
virtualApiKeyId: text("virtualApiKeyId").references(
|
||||||
|
() => virtualApiKeys.virtualApiKeyId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
// Links this usage record back to the aiSessionLog row for the same
|
||||||
|
// request (aiSessionLog.sessionId), so token/cost usage can be shown
|
||||||
|
// alongside the session transcript. Not a DB-level FK - aiSessionLog
|
||||||
|
// lives in the separate logs database. Nullable because the session
|
||||||
|
// log may be disabled (retention set to 0) while usage tracking
|
||||||
|
// stays on.
|
||||||
|
sessionId: text("sessionId"),
|
||||||
|
requestedModel: text("requestedModel").notNull(),
|
||||||
|
promptTokens: integer("promptTokens").notNull().default(0),
|
||||||
|
cacheReadTokens: integer("cacheReadTokens").notNull().default(0),
|
||||||
|
cacheWriteTokens: integer("cacheWriteTokens").notNull().default(0),
|
||||||
|
completionTokens: integer("completionTokens").notNull().default(0),
|
||||||
|
reasoningTokens: integer("reasoningTokens").notNull().default(0),
|
||||||
|
totalTokens: integer("totalTokens").notNull().default(0),
|
||||||
|
costUsd: real("costUsd"),
|
||||||
|
estimated: integer("estimated", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
createdAt: integer("createdAt").notNull()
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
index("idx_ai_usage_records_org_provider_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.providerId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_org_resource_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.resourceId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_org_site_resource_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.siteResourceId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_org_user_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.userId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_org_virtual_api_key_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.virtualApiKeyId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_usage_records_session").on(t.sessionId)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const aiBudgetBreachEvents = sqliteTable(
|
||||||
|
"aiBudgetBreachEvents",
|
||||||
|
{
|
||||||
|
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||||
|
orgId: text("orgId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
|
budgetId: integer("budgetId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => aiBudgets.budgetId, { onDelete: "cascade" }),
|
||||||
|
enforcement: text("enforcement").$type<"hard" | "soft">().notNull(),
|
||||||
|
unit: text("unit").$type<"usd" | "tokens">().notNull(),
|
||||||
|
period: text("period")
|
||||||
|
.$type<
|
||||||
|
| "monthly"
|
||||||
|
| "yearly"
|
||||||
|
| "lifetime"
|
||||||
|
| "daily"
|
||||||
|
| "hourly"
|
||||||
|
| "weekly"
|
||||||
|
>()
|
||||||
|
.notNull(),
|
||||||
|
amount: real("amount").notNull(),
|
||||||
|
usageAmount: real("usageAmount").notNull(),
|
||||||
|
blocked: integer("blocked", { mode: "boolean" }).notNull(),
|
||||||
|
requestUserId: text("requestUserId").references(() => users.userId, {
|
||||||
|
onDelete: "set null"
|
||||||
|
}),
|
||||||
|
createdAt: integer("createdAt").notNull()
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
index("idx_ai_budget_breach_events_budget_created").on(
|
||||||
|
t.budgetId,
|
||||||
|
t.createdAt
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Logs the aggregated prompt + response for a single AI gateway request, for
|
||||||
|
// session replay. One row per request (not per streaming chunk). `sessionId`
|
||||||
|
// is a fresh random id per row for now - no cross-request correlation yet,
|
||||||
|
// but the column exists so a future pass can link multiple rows into a real
|
||||||
|
// multi-turn session.
|
||||||
|
export const aiSessionLog = sqliteTable(
|
||||||
|
"aiSessionLog",
|
||||||
|
{
|
||||||
|
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||||
|
sessionId: text("sessionId").notNull(),
|
||||||
|
orgId: text("orgId").references(() => orgs.orgId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
providerId: integer("providerId").references(
|
||||||
|
() => aiProviders.providerId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
capability: text("capability").notNull(),
|
||||||
|
resourceId: integer("resourceId").references(
|
||||||
|
() => resources.resourceId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
siteResourceId: integer("siteResourceId").references(
|
||||||
|
() => siteResources.siteResourceId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
userId: text("userId").references(() => users.userId, {
|
||||||
|
onDelete: "set null"
|
||||||
|
}),
|
||||||
|
virtualApiKeyId: text("virtualApiKeyId").references(
|
||||||
|
() => virtualApiKeys.virtualApiKeyId,
|
||||||
|
{ onDelete: "set null" }
|
||||||
|
),
|
||||||
|
requestedModel: text("requestedModel"),
|
||||||
|
isStream: integer("isStream", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
requestBody: text("requestBody"),
|
||||||
|
responseBody: text("responseBody"),
|
||||||
|
// Capability-agnostic message transcript (JSON-encoded
|
||||||
|
// NormalizedAiMessage[] from server/lib/aiMessageNormalization.ts),
|
||||||
|
// computed at write time so search/display never need per-capability
|
||||||
|
// parsing logic. Null when normalization couldn't recognize the
|
||||||
|
// shape - callers fall back to requestBody/responseBody.
|
||||||
|
normalizedRequest: text("normalizedRequest"),
|
||||||
|
normalizedResponse: text("normalizedResponse"),
|
||||||
|
// True if any of the request/response (raw or normalized) fields
|
||||||
|
// were cut short at AI_SESSION_LOG_MAX_BODY_CHARS before storage.
|
||||||
|
truncated: integer("truncated", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
statusCode: integer("statusCode"),
|
||||||
|
createdAt: integer("createdAt").notNull() // epoch ms
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
index("idx_ai_session_log_org_created").on(t.orgId, t.createdAt),
|
||||||
|
index("idx_ai_session_log_org_provider_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.providerId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_org_resource_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.resourceId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_org_site_resource_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.siteResourceId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_org_user_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.userId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_org_virtual_api_key_created").on(
|
||||||
|
t.orgId,
|
||||||
|
t.virtualApiKeyId,
|
||||||
|
t.createdAt
|
||||||
|
),
|
||||||
|
index("idx_ai_session_log_session").on(t.sessionId)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const certificates = sqliteTable("certificates", {
|
||||||
|
certId: integer("certId").primaryKey({ autoIncrement: true }),
|
||||||
|
domain: text("domain").notNull().unique(),
|
||||||
|
domainId: text("domainId").references(() => domains.domainId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
wildcard: integer("wildcard", { mode: "boolean" }).default(false),
|
||||||
|
status: text("status").notNull().default("pending"), // pending, requested, valid, expired, failed
|
||||||
|
expiresAt: integer("expiresAt"),
|
||||||
|
lastRenewalAttempt: integer("lastRenewalAttempt"),
|
||||||
|
createdAt: integer("createdAt").notNull(),
|
||||||
|
updatedAt: integer("updatedAt").notNull(),
|
||||||
|
orderId: text("orderId"),
|
||||||
|
errorMessage: text("errorMessage"),
|
||||||
|
renewalCount: integer("renewalCount").default(0),
|
||||||
|
certFile: text("certFile"),
|
||||||
|
keyFile: text("keyFile")
|
||||||
|
});
|
||||||
|
|
||||||
export type Org = InferSelectModel<typeof orgs>;
|
export type Org = InferSelectModel<typeof orgs>;
|
||||||
export type User = InferSelectModel<typeof users>;
|
export type User = InferSelectModel<typeof users>;
|
||||||
export type Site = InferSelectModel<typeof sites>;
|
export type Site = InferSelectModel<typeof sites>;
|
||||||
@@ -1568,6 +2083,10 @@ export type Idp = InferSelectModel<typeof idp>;
|
|||||||
export type ApiKey = InferSelectModel<typeof apiKeys>;
|
export type ApiKey = InferSelectModel<typeof apiKeys>;
|
||||||
export type ApiKeyAction = InferSelectModel<typeof apiKeyActions>;
|
export type ApiKeyAction = InferSelectModel<typeof apiKeyActions>;
|
||||||
export type ApiKeyOrg = InferSelectModel<typeof apiKeyOrg>;
|
export type ApiKeyOrg = InferSelectModel<typeof apiKeyOrg>;
|
||||||
|
export type VirtualApiKey = InferSelectModel<typeof virtualApiKeys>;
|
||||||
|
export type VirtualApiKeyResource = InferSelectModel<
|
||||||
|
typeof virtualApiKeyResources
|
||||||
|
>;
|
||||||
export type SiteResource = InferSelectModel<typeof siteResources>;
|
export type SiteResource = InferSelectModel<typeof siteResources>;
|
||||||
export type Network = InferSelectModel<typeof networks>;
|
export type Network = InferSelectModel<typeof networks>;
|
||||||
export type OrgDomains = InferSelectModel<typeof orgDomains>;
|
export type OrgDomains = InferSelectModel<typeof orgDomains>;
|
||||||
@@ -1599,3 +2118,16 @@ export type ResourcePolicyHeaderAuth = InferSelectModel<
|
|||||||
>;
|
>;
|
||||||
export type RolePolicy = InferSelectModel<typeof rolePolicies>;
|
export type RolePolicy = InferSelectModel<typeof rolePolicies>;
|
||||||
export type UserPolicy = InferSelectModel<typeof userPolicies>;
|
export type UserPolicy = InferSelectModel<typeof userPolicies>;
|
||||||
|
export type AiProvider = InferSelectModel<typeof aiProviders>;
|
||||||
|
export type AiModel = InferSelectModel<typeof aiModels>;
|
||||||
|
export type AiBudget = InferSelectModel<typeof aiBudgets>;
|
||||||
|
export type AiUsageRecord = InferSelectModel<typeof aiUsageRecords>;
|
||||||
|
export type AiBudgetBreachEvent = InferSelectModel<typeof aiBudgetBreachEvents>;
|
||||||
|
export type AiSessionLog = InferSelectModel<typeof aiSessionLog>;
|
||||||
|
export type ResourceAiProvider = InferSelectModel<typeof resourceAiProviders>;
|
||||||
|
export type SiteResourceAiProvider = InferSelectModel<
|
||||||
|
typeof siteResourceAiProviders
|
||||||
|
>;
|
||||||
|
export type ResourceAiModel = InferSelectModel<typeof resourceAiModels>;
|
||||||
|
export type SiteResourceAiModel = InferSelectModel<typeof siteResourceAiModels>;
|
||||||
|
export type Certificate = InferSelectModel<typeof certificates>;
|
||||||
|
|||||||
@@ -31,9 +31,24 @@ export type AlertNotificationProps = {
|
|||||||
orgId: string;
|
orgId: string;
|
||||||
data: Record<string, unknown>;
|
data: Record<string, unknown>;
|
||||||
dashboardLink: string;
|
dashboardLink: string;
|
||||||
|
isTestAlert?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getEventMeta(eventType: AlertEventType): {
|
function getEventMeta(
|
||||||
|
eventType: AlertEventType,
|
||||||
|
isTestAlert: boolean = false
|
||||||
|
): {
|
||||||
|
heading: string;
|
||||||
|
previewText: string;
|
||||||
|
summary: string;
|
||||||
|
statusLabel: string | null;
|
||||||
|
statusColor: string | null;
|
||||||
|
} {
|
||||||
|
const meta = getBaseEventMeta(eventType);
|
||||||
|
return isTestAlert ? { ...meta, heading: `[TEST] ${meta.heading}` } : meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBaseEventMeta(eventType: AlertEventType): {
|
||||||
heading: string;
|
heading: string;
|
||||||
previewText: string;
|
previewText: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
@@ -180,8 +195,14 @@ function formatDataItems(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const AlertNotification = (props: AlertNotificationProps) => {
|
export const AlertNotification = (props: AlertNotificationProps) => {
|
||||||
const { eventType, orgId, data, dashboardLink } = props;
|
const {
|
||||||
const meta = getEventMeta(eventType);
|
eventType,
|
||||||
|
orgId,
|
||||||
|
data,
|
||||||
|
dashboardLink,
|
||||||
|
isTestAlert = false
|
||||||
|
} = props;
|
||||||
|
const meta = getEventMeta(eventType, isTestAlert);
|
||||||
const dataItems = formatDataItems(data);
|
const dataItems = formatDataItems(data);
|
||||||
|
|
||||||
const isToggle =
|
const isToggle =
|
||||||
@@ -242,6 +263,12 @@ export const AlertNotification = (props: AlertNotificationProps) => {
|
|||||||
Open your dashboard to view more details and manage
|
Open your dashboard to view more details and manage
|
||||||
your alert rules.
|
your alert rules.
|
||||||
</EmailText>
|
</EmailText>
|
||||||
|
{isTestAlert && (
|
||||||
|
<EmailText>
|
||||||
|
This is a test alert. No action is required,
|
||||||
|
and no real event has occurred.
|
||||||
|
</EmailText>
|
||||||
|
)}
|
||||||
|
|
||||||
<EmailSection>
|
<EmailSection>
|
||||||
<ButtonLink href={dashboardLink}>
|
<ButtonLink href={dashboardLink}>
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Body, Head, Html, Preview, Tailwind } from "@react-email/components";
|
||||||
|
import { themeColors } from "./lib/theme";
|
||||||
|
import {
|
||||||
|
EmailContainer,
|
||||||
|
EmailFooter,
|
||||||
|
EmailGreeting,
|
||||||
|
EmailHeading,
|
||||||
|
EmailInfoSection,
|
||||||
|
EmailLetterHead,
|
||||||
|
EmailSection,
|
||||||
|
EmailSignature,
|
||||||
|
EmailText
|
||||||
|
} from "./components/Email";
|
||||||
|
|
||||||
|
type IdentityApiKeyGeneratedProps = {
|
||||||
|
orgName: string;
|
||||||
|
accountLabel?: string | null;
|
||||||
|
credential: string;
|
||||||
|
resourceUrls: string[];
|
||||||
|
hasMoreResources: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IdentityApiKeyGenerated = ({
|
||||||
|
orgName,
|
||||||
|
accountLabel,
|
||||||
|
credential,
|
||||||
|
resourceUrls,
|
||||||
|
hasMoreResources
|
||||||
|
}: IdentityApiKeyGeneratedProps) => {
|
||||||
|
const previewText = `Your personal identity key for ${orgName}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Html>
|
||||||
|
<Head />
|
||||||
|
<Preview>{previewText}</Preview>
|
||||||
|
<Tailwind config={themeColors}>
|
||||||
|
<Body className="font-sans bg-gray-50">
|
||||||
|
<EmailContainer>
|
||||||
|
<EmailLetterHead />
|
||||||
|
|
||||||
|
<EmailGreeting>Hi there,</EmailGreeting>
|
||||||
|
|
||||||
|
<EmailText>
|
||||||
|
This is your personal identity key for{" "}
|
||||||
|
<strong>{orgName}</strong>. It belongs to your
|
||||||
|
account and identifies you when you use public AI
|
||||||
|
gateways.
|
||||||
|
</EmailText>
|
||||||
|
|
||||||
|
<EmailText>
|
||||||
|
Use it with resources your administrator has granted
|
||||||
|
you, or that your role has access to. Treat this key
|
||||||
|
like a password and do not share it.
|
||||||
|
</EmailText>
|
||||||
|
|
||||||
|
<EmailSection>
|
||||||
|
<EmailText>Your identity key:</EmailText>
|
||||||
|
<div className="inline-block max-w-full">
|
||||||
|
<div className="bg-gray-50 border border-gray-200 rounded-lg px-4 py-3 mx-auto text-left">
|
||||||
|
<span className="text-sm font-mono text-gray-900 break-all">
|
||||||
|
{credential}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</EmailSection>
|
||||||
|
|
||||||
|
<EmailFooter>
|
||||||
|
<EmailSignature />
|
||||||
|
</EmailFooter>
|
||||||
|
</EmailContainer>
|
||||||
|
</Body>
|
||||||
|
</Tailwind>
|
||||||
|
</Html>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default IdentityApiKeyGenerated;
|
||||||
@@ -30,14 +30,14 @@ export const NotifyTrialExpiring = ({
|
|||||||
const isLastDay = daysRemaining === 1;
|
const isLastDay = daysRemaining === 1;
|
||||||
|
|
||||||
const previewText = hasEnded
|
const previewText = hasEnded
|
||||||
? `Your trial for ${orgName} has ended.`
|
? `Your cloud trial for ${orgName} has ended.`
|
||||||
: isLastDay
|
: isLastDay
|
||||||
? `Your trial for ${orgName} ends tomorrow.`
|
? `Your cloud trial for ${orgName} ends tomorrow.`
|
||||||
: `Your trial for ${orgName} ends in ${daysRemaining} days.`;
|
: `Your cloud trial for ${orgName} ends in ${daysRemaining} days.`;
|
||||||
|
|
||||||
const heading = hasEnded
|
const heading = hasEnded
|
||||||
? "Your Trial Ended"
|
? "Your Cloud Trial Ended"
|
||||||
: "Your Trial is Ending Soon";
|
: "Your Cloud Trial is Ending Soon";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
@@ -55,7 +55,7 @@ export const NotifyTrialExpiring = ({
|
|||||||
{hasEnded ? (
|
{hasEnded ? (
|
||||||
<>
|
<>
|
||||||
<EmailText>
|
<EmailText>
|
||||||
Your free trial for{" "}
|
Your cloud free trial for{" "}
|
||||||
<strong>{orgName}</strong> ended on{" "}
|
<strong>{orgName}</strong> ended on{" "}
|
||||||
<strong>{trialEndsAt}</strong>. Your account
|
<strong>{trialEndsAt}</strong>. Your account
|
||||||
has been moved to the free plan, which
|
has been moved to the free plan, which
|
||||||
@@ -64,10 +64,11 @@ export const NotifyTrialExpiring = ({
|
|||||||
|
|
||||||
<EmailText>
|
<EmailText>
|
||||||
Some features and resources may now be
|
Some features and resources may now be
|
||||||
restricted. To restore full
|
restricted. To restore full access and
|
||||||
access and continue using all the features
|
continue using all the features you had
|
||||||
you had during your trial, please upgrade to
|
during your trial, please upgrade to a paid
|
||||||
a paid plan.
|
plan. This does not effect any self hosted
|
||||||
|
licenses.
|
||||||
</EmailText>
|
</EmailText>
|
||||||
|
|
||||||
<EmailText>
|
<EmailText>
|
||||||
@@ -93,7 +94,8 @@ export const NotifyTrialExpiring = ({
|
|||||||
<EmailText>
|
<EmailText>
|
||||||
After your trial ends, your account will be
|
After your trial ends, your account will be
|
||||||
moved to the free plan and some
|
moved to the free plan and some
|
||||||
functionality may be restricted.
|
functionality may be restricted. This does
|
||||||
|
not effect any self hosted licenses.
|
||||||
</EmailText>
|
</EmailText>
|
||||||
|
|
||||||
<EmailText>
|
<EmailText>
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Body, Head, Html, Preview, Tailwind } from "@react-email/components";
|
||||||
|
import { themeColors } from "./lib/theme";
|
||||||
|
import {
|
||||||
|
EmailContainer,
|
||||||
|
EmailFooter,
|
||||||
|
EmailGreeting,
|
||||||
|
EmailInfoSection,
|
||||||
|
EmailLetterHead,
|
||||||
|
EmailSection,
|
||||||
|
EmailSignature,
|
||||||
|
EmailText
|
||||||
|
} from "./components/Email";
|
||||||
|
|
||||||
|
type VirtualApiKeyGeneratedProps = {
|
||||||
|
orgName: string;
|
||||||
|
keyName: string | null;
|
||||||
|
credential: string;
|
||||||
|
resourceUrls: string[];
|
||||||
|
hasMoreResources: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const VirtualApiKeyGenerated = ({
|
||||||
|
orgName,
|
||||||
|
keyName,
|
||||||
|
credential,
|
||||||
|
resourceUrls,
|
||||||
|
hasMoreResources
|
||||||
|
}: VirtualApiKeyGeneratedProps) => {
|
||||||
|
const previewText = `A virtual API key for ${orgName} has been shared with you`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Html>
|
||||||
|
<Head />
|
||||||
|
<Preview>{previewText}</Preview>
|
||||||
|
<Tailwind config={themeColors}>
|
||||||
|
<Body className="font-sans bg-gray-50">
|
||||||
|
<EmailContainer>
|
||||||
|
<EmailLetterHead />
|
||||||
|
|
||||||
|
<EmailGreeting>Hi there,</EmailGreeting>
|
||||||
|
|
||||||
|
<EmailText>
|
||||||
|
A virtual API key for <strong>{orgName}</strong> has
|
||||||
|
been shared with you. This key grants access to the
|
||||||
|
public AI gateways it was created for. Treat this
|
||||||
|
key like a password and do not share it.
|
||||||
|
</EmailText>
|
||||||
|
|
||||||
|
<EmailSection>
|
||||||
|
<EmailText>Your virtual API key:</EmailText>
|
||||||
|
<div className="inline-block max-w-full">
|
||||||
|
<div className="bg-gray-50 border border-gray-200 rounded-lg px-4 py-3 mx-auto text-left">
|
||||||
|
<span className="text-sm font-mono text-gray-900 break-all">
|
||||||
|
{credential}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</EmailSection>
|
||||||
|
|
||||||
|
<EmailInfoSection
|
||||||
|
title="Key details"
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
label: "Organization",
|
||||||
|
value: orgName
|
||||||
|
},
|
||||||
|
...(keyName
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: "Name",
|
||||||
|
value: keyName
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: [])
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{resourceUrls.length > 0 && (
|
||||||
|
<>
|
||||||
|
<EmailText>
|
||||||
|
This key can be used to authenticate to the
|
||||||
|
following AI gateway resources:
|
||||||
|
</EmailText>
|
||||||
|
<div className="px-6 pb-2">
|
||||||
|
{resourceUrls.map((url) => (
|
||||||
|
<p
|
||||||
|
key={url}
|
||||||
|
className="text-base text-gray-700 leading-relaxed"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={url}
|
||||||
|
className="text-primary font-medium break-all"
|
||||||
|
>
|
||||||
|
{url}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{hasMoreResources && (
|
||||||
|
<EmailText>
|
||||||
|
Contact your administrator to get the
|
||||||
|
full list.
|
||||||
|
</EmailText>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<EmailFooter>
|
||||||
|
<EmailSignature />
|
||||||
|
</EmailFooter>
|
||||||
|
</EmailContainer>
|
||||||
|
</Body>
|
||||||
|
</Tailwind>
|
||||||
|
</Html>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VirtualApiKeyGenerated;
|
||||||
@@ -18,7 +18,7 @@ export function EmailLetterHead() {
|
|||||||
<Img
|
<Img
|
||||||
src="https://fossorial-public-assets.s3.us-east-1.amazonaws.com/word_mark_black.png"
|
src="https://fossorial-public-assets.s3.us-east-1.amazonaws.com/word_mark_black.png"
|
||||||
alt="Pangolin Logo"
|
alt="Pangolin Logo"
|
||||||
width="180"
|
width="135"
|
||||||
height="auto"
|
height="auto"
|
||||||
className="mx-auto"
|
className="mx-auto"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,26 +5,29 @@ import { runSetupFunctions } from "./setup";
|
|||||||
import { createApiServer } from "./apiServer";
|
import { createApiServer } from "./apiServer";
|
||||||
import { createNextServer } from "./nextServer";
|
import { createNextServer } from "./nextServer";
|
||||||
import { createInternalServer } from "./internalServer";
|
import { createInternalServer } from "./internalServer";
|
||||||
|
import { createAiGatewayServer } from "./aiGatewayServer";
|
||||||
import { createIntegrationApiServer } from "./integrationApiServer";
|
import { createIntegrationApiServer } from "./integrationApiServer";
|
||||||
import {
|
import {
|
||||||
ApiKey,
|
ApiKey,
|
||||||
ApiKeyOrg,
|
ApiKeyOrg,
|
||||||
|
AiBudget,
|
||||||
|
AiModel,
|
||||||
|
AiProvider,
|
||||||
RemoteExitNode,
|
RemoteExitNode,
|
||||||
Session,
|
Session,
|
||||||
SiteResource,
|
SiteResource,
|
||||||
User,
|
User,
|
||||||
UserOrg
|
UserOrg,
|
||||||
|
VirtualApiKey
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
import { setHostMeta } from "@server/lib/hostMeta";
|
import { setHostMeta } from "@server/lib/hostMeta";
|
||||||
import { initTelemetryClient } from "@server/lib/telemetry";
|
|
||||||
import { TraefikConfigManager } from "@server/lib/traefik/TraefikConfigManager";
|
import { TraefikConfigManager } from "@server/lib/traefik/TraefikConfigManager";
|
||||||
import { initCleanup } from "#dynamic/cleanup";
|
import { initCleanup } from "#dynamic/cleanup";
|
||||||
|
import { startSchedulers } from "#dynamic/startSchedulers";
|
||||||
import license from "#dynamic/license/license";
|
import license from "#dynamic/license/license";
|
||||||
import { initLogCleanupInterval } from "@server/lib/cleanupLogs";
|
|
||||||
import { initAcmeCertSync } from "#dynamic/lib/acmeCertSync";
|
|
||||||
import { fetchServerIp } from "@server/lib/serverIpService";
|
import { fetchServerIp } from "@server/lib/serverIpService";
|
||||||
import { startRebuildQueueProcessor } from "@server/lib/rebuildClientAssociations";
|
import { initAiModelCatalog } from "@server/lib/aiModelCatalog";
|
||||||
|
|
||||||
async function startServers() {
|
async function startServers() {
|
||||||
await setHostMeta();
|
await setHostMeta();
|
||||||
@@ -38,15 +41,14 @@ async function startServers() {
|
|||||||
|
|
||||||
await fetchServerIp();
|
await fetchServerIp();
|
||||||
|
|
||||||
initTelemetryClient();
|
await initAiModelCatalog();
|
||||||
|
|
||||||
initLogCleanupInterval();
|
startSchedulers();
|
||||||
initAcmeCertSync();
|
|
||||||
startRebuildQueueProcessor();
|
|
||||||
|
|
||||||
// Start all servers
|
// Start all servers
|
||||||
const apiServer = createApiServer();
|
const apiServer = createApiServer();
|
||||||
const internalServer = createInternalServer();
|
const internalServer = createInternalServer();
|
||||||
|
const aiGatewayServer = createAiGatewayServer();
|
||||||
|
|
||||||
const nextServer = await createNextServer();
|
const nextServer = await createNextServer();
|
||||||
if (config.getRawConfig().traefik.file_mode) {
|
if (config.getRawConfig().traefik.file_mode) {
|
||||||
@@ -65,6 +67,7 @@ async function startServers() {
|
|||||||
apiServer,
|
apiServer,
|
||||||
nextServer,
|
nextServer,
|
||||||
internalServer,
|
internalServer,
|
||||||
|
aiGatewayServer,
|
||||||
integrationServer
|
integrationServer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -83,6 +86,10 @@ declare global {
|
|||||||
userOrgIds?: string[];
|
userOrgIds?: string[];
|
||||||
remoteExitNode?: RemoteExitNode;
|
remoteExitNode?: RemoteExitNode;
|
||||||
siteResource?: SiteResource;
|
siteResource?: SiteResource;
|
||||||
|
aiProvider?: AiProvider;
|
||||||
|
aiModel?: AiModel;
|
||||||
|
aiBudget?: AiBudget;
|
||||||
|
virtualApiKey?: VirtualApiKey;
|
||||||
orgPolicyAllowed?: boolean;
|
orgPolicyAllowed?: boolean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { logIncomingMiddleware } from "./middlewares/logIncoming";
|
|||||||
import helmet from "helmet";
|
import helmet from "helmet";
|
||||||
import swaggerUi from "swagger-ui-express";
|
import swaggerUi from "swagger-ui-express";
|
||||||
import { OpenApiGeneratorV3 } from "@asteasolutions/zod-to-openapi";
|
import { OpenApiGeneratorV3 } from "@asteasolutions/zod-to-openapi";
|
||||||
import { registry } from "./openApi";
|
import { registry, openApiTags } from "./openApi";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { APP_PATH } from "./lib/consts";
|
import { APP_PATH } from "./lib/consts";
|
||||||
@@ -181,7 +181,8 @@ function getOpenApiDocumentation() {
|
|||||||
version: "v1",
|
version: "v1",
|
||||||
title: "Pangolin Integration API"
|
title: "Pangolin Integration API"
|
||||||
},
|
},
|
||||||
servers: [{ url: "/v1" }]
|
servers: [{ url: "/v1" }],
|
||||||
|
tags: openApiTags
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!process.env.DISABLE_GEN_OPENAPI) {
|
if (!process.env.DISABLE_GEN_OPENAPI) {
|
||||||
|
|||||||
@@ -1,3 +1,866 @@
|
|||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import crypto from "crypto";
|
||||||
|
import {
|
||||||
|
certificates,
|
||||||
|
clients,
|
||||||
|
clientSiteResourcesAssociationsCache,
|
||||||
|
db,
|
||||||
|
domains,
|
||||||
|
newts,
|
||||||
|
siteNetworks,
|
||||||
|
SiteResource,
|
||||||
|
siteResources
|
||||||
|
} from "@server/db";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import { encrypt, decrypt } from "@server/lib/crypto";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import config from "@server/lib/config";
|
||||||
|
import {
|
||||||
|
generateSubnetProxyTargetV2,
|
||||||
|
SubnetProxyTargetV2
|
||||||
|
} from "@server/lib/ip";
|
||||||
|
import { updateTargets } from "@server/routers/client/targets";
|
||||||
|
import cache from "#dynamic/lib/cache";
|
||||||
|
import { build } from "@server/build";
|
||||||
|
|
||||||
|
interface AcmeCert {
|
||||||
|
domain: { main: string; sans?: string[] };
|
||||||
|
certificate: string;
|
||||||
|
key: string;
|
||||||
|
Store: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AcmeJson {
|
||||||
|
[resolver: string]: {
|
||||||
|
Certificates: AcmeCert[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function pushCertUpdateToAffectedNewts(
|
||||||
|
domain: string,
|
||||||
|
domainId: string | null,
|
||||||
|
oldCertPem: string | null,
|
||||||
|
oldKeyPem: string | null
|
||||||
|
): Promise<void> {
|
||||||
|
// Find all SSL-enabled HTTP site resources that use this cert's domain
|
||||||
|
let affectedResources: SiteResource[] = [];
|
||||||
|
|
||||||
|
if (domainId) {
|
||||||
|
affectedResources = await db
|
||||||
|
.select()
|
||||||
|
.from(siteResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(siteResources.domainId, domainId),
|
||||||
|
eq(siteResources.ssl, true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Fallback: match by exact fullDomain when no domainId is available
|
||||||
|
affectedResources = await db
|
||||||
|
.select()
|
||||||
|
.from(siteResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(siteResources.fullDomain, domain),
|
||||||
|
eq(siteResources.ssl, true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (affectedResources.length === 0) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no affected site resources for cert domain "${domain}"`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: pushing cert update to ${affectedResources.length} affected site resource(s) for domain "${domain}"`
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const resource of affectedResources) {
|
||||||
|
try {
|
||||||
|
// Get all sites for this resource via siteNetworks
|
||||||
|
const resourceSiteRows = resource.networkId
|
||||||
|
? await db
|
||||||
|
.select({ siteId: siteNetworks.siteId })
|
||||||
|
.from(siteNetworks)
|
||||||
|
.where(eq(siteNetworks.networkId, resource.networkId))
|
||||||
|
: [];
|
||||||
|
|
||||||
|
if (resourceSiteRows.length === 0) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no sites for resource ${resource.siteResourceId}, skipping`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all clients with access to this resource
|
||||||
|
const resourceClients = await db
|
||||||
|
.select({
|
||||||
|
clientId: clients.clientId,
|
||||||
|
pubKey: clients.pubKey,
|
||||||
|
subnet: clients.subnet
|
||||||
|
})
|
||||||
|
.from(clients)
|
||||||
|
.innerJoin(
|
||||||
|
clientSiteResourcesAssociationsCache,
|
||||||
|
eq(
|
||||||
|
clients.clientId,
|
||||||
|
clientSiteResourcesAssociationsCache.clientId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
eq(
|
||||||
|
clientSiteResourcesAssociationsCache.siteResourceId,
|
||||||
|
resource.siteResourceId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resourceClients.length === 0) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no clients for resource ${resource.siteResourceId}, skipping`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidate the cert cache so generateSubnetProxyTargetV2 fetches fresh data
|
||||||
|
if (resource.fullDomain) {
|
||||||
|
await cache.del(`cert:${resource.fullDomain}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate target once - same cert applies to all sites for this resource
|
||||||
|
const newTargets = await generateSubnetProxyTargetV2(
|
||||||
|
resource,
|
||||||
|
resourceClients
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!newTargets) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not generate target for resource ${resource.siteResourceId}, skipping`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the old targets - same routing shape but with the previous cert/key.
|
||||||
|
// The newt only uses destPrefix/sourcePrefixes for removal, but we keep the
|
||||||
|
// semantics correct so the update message accurately reflects what changed.
|
||||||
|
const oldTargets: SubnetProxyTargetV2[] = newTargets.map((t) => ({
|
||||||
|
...t,
|
||||||
|
tlsCert: oldCertPem ?? undefined,
|
||||||
|
tlsKey: oldKeyPem ?? undefined
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Push update to each site's newt
|
||||||
|
for (const { siteId } of resourceSiteRows) {
|
||||||
|
const [newt] = await db
|
||||||
|
.select()
|
||||||
|
.from(newts)
|
||||||
|
.where(eq(newts.siteId, siteId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!newt) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no newt found for site ${siteId}, skipping resource ${resource.siteResourceId}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateTargets(
|
||||||
|
newt.newtId,
|
||||||
|
{ oldTargets: oldTargets, newTargets: newTargets },
|
||||||
|
newt.version
|
||||||
|
);
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: pushed cert update to newt for site ${siteId}, resource ${resource.siteResourceId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(
|
||||||
|
`acmeCertSync: error pushing cert update for resource ${resource?.siteResourceId}: ${err}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findDomainId(certDomain: string): Promise<string | null> {
|
||||||
|
// Strip wildcard prefix before lookup (*.example.com -> example.com)
|
||||||
|
const lookupDomain = certDomain.startsWith("*.")
|
||||||
|
? certDomain.slice(2)
|
||||||
|
: certDomain;
|
||||||
|
|
||||||
|
// 1. Exact baseDomain match (any domain type)
|
||||||
|
const exactMatch = await db
|
||||||
|
.select({ domainId: domains.domainId })
|
||||||
|
.from(domains)
|
||||||
|
.where(eq(domains.baseDomain, lookupDomain))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (exactMatch.length > 0) {
|
||||||
|
return exactMatch[0].domainId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Walk up the domain hierarchy looking for a wildcard-type domain whose
|
||||||
|
// baseDomain is a suffix of the cert domain. e.g. cert "sub.example.com"
|
||||||
|
// matches a wildcard domain with baseDomain "example.com".
|
||||||
|
const parts = lookupDomain.split(".");
|
||||||
|
for (let i = 1; i < parts.length; i++) {
|
||||||
|
const candidate = parts.slice(i).join(".");
|
||||||
|
if (!candidate) continue;
|
||||||
|
|
||||||
|
const wildcardMatch = await db
|
||||||
|
.select({ domainId: domains.domainId })
|
||||||
|
.from(domains)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(domains.baseDomain, candidate),
|
||||||
|
eq(domains.type, "wildcard")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (wildcardMatch.length > 0) {
|
||||||
|
return wildcardMatch[0].domainId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractFirstCert(pemBundle: string): string | null {
|
||||||
|
const match = pemBundle.match(
|
||||||
|
/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/
|
||||||
|
);
|
||||||
|
return match ? match[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether an ACME cert entry represents a wildcard cert by checking
|
||||||
|
* both the primary domain (`main`) and the SANs. Some ACME clients (notably
|
||||||
|
* Traefik) store the bare apex in `main` and only put the wildcard form in
|
||||||
|
* `sans` (e.g. main="access.example.com", sans=["*.access.example.com"]).
|
||||||
|
*/
|
||||||
|
function detectWildcard(
|
||||||
|
main: string,
|
||||||
|
sans: string[] | undefined
|
||||||
|
): { wildcard: boolean; wildcardSan: string | null } {
|
||||||
|
if (main.startsWith("*.")) {
|
||||||
|
return { wildcard: true, wildcardSan: null };
|
||||||
|
}
|
||||||
|
if (Array.isArray(sans)) {
|
||||||
|
for (const san of sans) {
|
||||||
|
if (typeof san !== "string") continue;
|
||||||
|
if (san === `*.${main}` || san.startsWith("*.")) {
|
||||||
|
return { wildcard: true, wildcardSan: san };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { wildcard: false, wildcardSan: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HttpCert {
|
||||||
|
wildcard: boolean;
|
||||||
|
altName: string;
|
||||||
|
certName: string;
|
||||||
|
commonName: string;
|
||||||
|
certFile: string;
|
||||||
|
keyFile: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function syncAcmeCertsFromHttp(endpoint: string): Promise<void> {
|
||||||
|
let response: Response;
|
||||||
|
try {
|
||||||
|
response = await fetch(endpoint);
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not reach HTTP endpoint ${endpoint}: ${err}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: HTTP endpoint returned status ${response.status}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let httpCerts: HttpCert[];
|
||||||
|
try {
|
||||||
|
httpCerts = await response.json();
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not parse JSON from HTTP endpoint: ${err}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(httpCerts) || httpCerts.length === 0) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no certificates returned from HTTP endpoint`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const cert of httpCerts) {
|
||||||
|
const domain = cert?.certName;
|
||||||
|
|
||||||
|
if (!domain || typeof domain !== "string") {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping HTTP cert with missing certName`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const certPem = cert.certFile;
|
||||||
|
const keyPem = cert.keyFile;
|
||||||
|
|
||||||
|
if (!certPem?.trim() || !keyPem?.trim()) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping HTTP cert for ${domain} - empty certFile or keyFile`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstCertPemForValidation = extractFirstCert(certPem);
|
||||||
|
if (!firstCertPemForValidation) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping HTTP cert for ${domain} - no PEM certificate block found`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let validatedX509: crypto.X509Certificate;
|
||||||
|
try {
|
||||||
|
validatedX509 = new crypto.X509Certificate(
|
||||||
|
firstCertPemForValidation
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping HTTP cert for ${domain} - invalid X.509 certificate: ${err}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
crypto.createPrivateKey(keyPem);
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping HTTP cert for ${domain} - invalid private key: ${err}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wildcard = cert.wildcard ?? false;
|
||||||
|
|
||||||
|
const existing = await db
|
||||||
|
.select()
|
||||||
|
.from(certificates)
|
||||||
|
.where(eq(certificates.domain, domain))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
let oldCertPem: string | null = null;
|
||||||
|
let oldKeyPem: string | null = null;
|
||||||
|
|
||||||
|
if (existing.length > 0 && existing[0].certFile) {
|
||||||
|
try {
|
||||||
|
const storedCertPem = decrypt(
|
||||||
|
existing[0].certFile,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
const wildcardUnchanged = existing[0].wildcard === wildcard;
|
||||||
|
if (storedCertPem === certPem && wildcardUnchanged) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
oldCertPem = storedCertPem;
|
||||||
|
if (existing[0].keyFile) {
|
||||||
|
try {
|
||||||
|
oldKeyPem = decrypt(
|
||||||
|
existing[0].keyFile,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
} catch (keyErr) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not decrypt stored key for ${domain}: ${keyErr}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not decrypt stored cert for ${domain}, will update: ${err}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expiresAt: number | null = null;
|
||||||
|
try {
|
||||||
|
expiresAt = Math.floor(
|
||||||
|
new Date(validatedX509.validTo).getTime() / 1000
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not parse cert expiry for ${domain}: ${err}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptedCert = encrypt(
|
||||||
|
certPem,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
const encryptedKey = encrypt(
|
||||||
|
keyPem,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
|
const domainId = await findDomainId(domain);
|
||||||
|
if (domainId) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: resolved domainId "${domainId}" for HTTP cert domain "${domain}"`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no matching domain record found for HTTP cert domain "${domain}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing.length > 0) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: updating existing certificate (HTTP) for ${domain} (expires ${expiresAt ? new Date(expiresAt * 1000).toISOString() : "unknown"})`
|
||||||
|
);
|
||||||
|
await db
|
||||||
|
.update(certificates)
|
||||||
|
.set({
|
||||||
|
certFile: encryptedCert,
|
||||||
|
keyFile: encryptedKey,
|
||||||
|
status: "valid",
|
||||||
|
expiresAt,
|
||||||
|
updatedAt: now,
|
||||||
|
wildcard,
|
||||||
|
...(domainId !== null && { domainId })
|
||||||
|
})
|
||||||
|
.where(eq(certificates.domain, domain));
|
||||||
|
|
||||||
|
await pushCertUpdateToAffectedNewts(
|
||||||
|
domain,
|
||||||
|
domainId,
|
||||||
|
oldCertPem,
|
||||||
|
oldKeyPem
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: inserting new certificate (HTTP) for ${domain} (expires ${expiresAt ? new Date(expiresAt * 1000).toISOString() : "unknown"})`
|
||||||
|
);
|
||||||
|
await db.insert(certificates).values({
|
||||||
|
domain,
|
||||||
|
domainId,
|
||||||
|
certFile: encryptedCert,
|
||||||
|
keyFile: encryptedKey,
|
||||||
|
status: "valid",
|
||||||
|
expiresAt,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
wildcard
|
||||||
|
});
|
||||||
|
|
||||||
|
await pushCertUpdateToAffectedNewts(domain, domainId, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function storeCertForDomain(
|
||||||
|
domain: string,
|
||||||
|
certPem: string,
|
||||||
|
keyPem: string,
|
||||||
|
validatedX509: crypto.X509Certificate
|
||||||
|
): Promise<void> {
|
||||||
|
const wildcard = domain.startsWith("*.");
|
||||||
|
|
||||||
|
const existing = await db
|
||||||
|
.select()
|
||||||
|
.from(certificates)
|
||||||
|
.where(eq(certificates.domain, domain))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
let oldCertPem: string | null = null;
|
||||||
|
let oldKeyPem: string | null = null;
|
||||||
|
|
||||||
|
if (existing.length > 0 && existing[0].certFile) {
|
||||||
|
try {
|
||||||
|
const storedCertPem = decrypt(
|
||||||
|
existing[0].certFile,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
const wildcardUnchanged = existing[0].wildcard === wildcard;
|
||||||
|
if (storedCertPem === certPem && wildcardUnchanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
oldCertPem = storedCertPem;
|
||||||
|
if (existing[0].keyFile) {
|
||||||
|
try {
|
||||||
|
oldKeyPem = decrypt(
|
||||||
|
existing[0].keyFile,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
} catch (keyErr) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not decrypt stored key for ${domain}: ${keyErr}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not decrypt stored cert for ${domain}, will update: ${err}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expiresAt: number | null = null;
|
||||||
|
try {
|
||||||
|
expiresAt = Math.floor(
|
||||||
|
new Date(validatedX509.validTo).getTime() / 1000
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: could not parse cert expiry for ${domain}: ${err}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptedCert = encrypt(
|
||||||
|
certPem,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
const encryptedKey = encrypt(keyPem, config.getRawConfig().server.secret!);
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
|
const domainId = await findDomainId(domain);
|
||||||
|
if (domainId) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: resolved domainId "${domainId}" for cert domain "${domain}"`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no matching domain record found for cert domain "${domain}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing.length > 0) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: updating existing certificate for ${domain} (expires ${expiresAt ? new Date(expiresAt * 1000).toISOString() : "unknown"})`
|
||||||
|
);
|
||||||
|
await db
|
||||||
|
.update(certificates)
|
||||||
|
.set({
|
||||||
|
certFile: encryptedCert,
|
||||||
|
keyFile: encryptedKey,
|
||||||
|
status: "valid",
|
||||||
|
expiresAt,
|
||||||
|
updatedAt: now,
|
||||||
|
wildcard,
|
||||||
|
...(domainId !== null && { domainId })
|
||||||
|
})
|
||||||
|
.where(eq(certificates.domain, domain));
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: updated certificate for ${domain} (expires ${expiresAt ? new Date(expiresAt * 1000).toISOString() : "unknown"})`
|
||||||
|
);
|
||||||
|
|
||||||
|
await pushCertUpdateToAffectedNewts(
|
||||||
|
domain,
|
||||||
|
domainId,
|
||||||
|
oldCertPem,
|
||||||
|
oldKeyPem
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: inserting new certificate for ${domain} (expires ${expiresAt ? new Date(expiresAt * 1000).toISOString() : "unknown"})`
|
||||||
|
);
|
||||||
|
await db.insert(certificates).values({
|
||||||
|
domain,
|
||||||
|
domainId,
|
||||||
|
certFile: encryptedCert,
|
||||||
|
keyFile: encryptedKey,
|
||||||
|
status: "valid",
|
||||||
|
expiresAt,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
wildcard
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: inserted new certificate for ${domain} (expires ${expiresAt ? new Date(expiresAt * 1000).toISOString() : "unknown"})`
|
||||||
|
);
|
||||||
|
|
||||||
|
await pushCertUpdateToAffectedNewts(domain, domainId, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findAcmeJsonFiles(dirPath: string): string[] {
|
||||||
|
const results: string[] = [];
|
||||||
|
let entries: fs.Dirent[];
|
||||||
|
try {
|
||||||
|
entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(
|
||||||
|
`acmeCertSync: could not read directory "${dirPath}": ${err}`
|
||||||
|
);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
for (const entry of entries) {
|
||||||
|
const fullPath = path.join(dirPath, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
results.push(...findAcmeJsonFiles(fullPath));
|
||||||
|
} else if (entry.isFile()) {
|
||||||
|
// check if it is a json file
|
||||||
|
if (entry.name.endsWith(".json")) {
|
||||||
|
let raw: string;
|
||||||
|
try {
|
||||||
|
raw = fs.readFileSync(fullPath, "utf8");
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(
|
||||||
|
`acmeCertSync: could not read file "${fullPath}": ${err}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsed: any;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(raw);
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(
|
||||||
|
`acmeCertSync: could not parse "${fullPath}" as JSON: ${err}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
results.push(fullPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function syncAcmeCerts(acmeJsonPath: string): Promise<void> {
|
||||||
|
let raw: string;
|
||||||
|
try {
|
||||||
|
raw = fs.readFileSync(acmeJsonPath, "utf8");
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(`acmeCertSync: could not read "${acmeJsonPath}": ${err}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let acmeJson: AcmeJson;
|
||||||
|
try {
|
||||||
|
acmeJson = JSON.parse(raw);
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(
|
||||||
|
`acmeCertSync: could not parse "${acmeJsonPath}" as JSON: ${err}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvers = Object.keys(acmeJson || {});
|
||||||
|
if (resolvers.length === 0) {
|
||||||
|
logger.debug(`acmeCertSync: no resolvers found in acme.json`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect certificates from every resolver. If the same domain appears in
|
||||||
|
// multiple resolvers, the last one wins (resolvers iterated in object order).
|
||||||
|
const allCerts: AcmeCert[] = [];
|
||||||
|
for (const resolver of resolvers) {
|
||||||
|
const resolverData = acmeJson[resolver];
|
||||||
|
if (!resolverData || !Array.isArray(resolverData.Certificates)) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no certificates found for resolver "${resolver}"`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// logger.debug(
|
||||||
|
// `acmeCertSync: found ${resolverData.Certificates.length} certificate(s) for resolver "${resolver}"`
|
||||||
|
// );
|
||||||
|
for (const cert of resolverData.Certificates) {
|
||||||
|
allCerts.push(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const cert of allCerts) {
|
||||||
|
const mainDomain = cert?.domain?.main;
|
||||||
|
|
||||||
|
if (!mainDomain || typeof mainDomain !== "string") {
|
||||||
|
logger.debug(`acmeCertSync: skipping cert with missing domain`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cert.certificate || !cert.key) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping cert for ${mainDomain} - empty certificate or key field`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let certPem: string;
|
||||||
|
let keyPem: string;
|
||||||
|
try {
|
||||||
|
certPem = Buffer.from(cert.certificate, "base64").toString("utf8");
|
||||||
|
keyPem = Buffer.from(cert.key, "base64").toString("utf8");
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping cert for ${mainDomain} - failed to base64-decode cert/key: ${err}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!certPem.trim() || !keyPem.trim()) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping cert for ${mainDomain} - blank PEM after base64 decode`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that the decoded data actually parses as a real X.509 cert
|
||||||
|
// before we touch the database. This prevents importing partially-written
|
||||||
|
// or corrupted entries from acme.json.
|
||||||
|
const firstCertPemForValidation = extractFirstCert(certPem);
|
||||||
|
if (!firstCertPemForValidation) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping cert for ${mainDomain} - no PEM certificate block found`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let validatedX509: crypto.X509Certificate;
|
||||||
|
try {
|
||||||
|
validatedX509 = new crypto.X509Certificate(
|
||||||
|
firstCertPemForValidation
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping cert for ${mainDomain} - invalid X.509 certificate: ${err}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity-check the private key parses too
|
||||||
|
try {
|
||||||
|
crypto.createPrivateKey(keyPem);
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: skipping cert for ${mainDomain} - invalid private key: ${err}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all domains covered by this cert: main + every SAN.
|
||||||
|
// Each domain gets its own row in the certificates table so that
|
||||||
|
// lookups by any hostname on the cert succeed independently.
|
||||||
|
const allDomains = new Set<string>([mainDomain]);
|
||||||
|
if (Array.isArray(cert.domain?.sans)) {
|
||||||
|
for (const san of cert.domain.sans) {
|
||||||
|
if (typeof san === "string" && san.trim()) {
|
||||||
|
allDomains.add(san.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// logger.debug(
|
||||||
|
// `acmeCertSync: cert for ${mainDomain} covers ${allDomains.size} domain(s): ${[...allDomains].join(", ")}`
|
||||||
|
// );
|
||||||
|
|
||||||
|
for (const domain of allDomains) {
|
||||||
|
try {
|
||||||
|
await storeCertForDomain(
|
||||||
|
domain,
|
||||||
|
certPem,
|
||||||
|
keyPem,
|
||||||
|
validatedX509
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(
|
||||||
|
`acmeCertSync: error storing cert for domain "${domain}": ${err}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function initAcmeCertSync(): void {
|
export function initAcmeCertSync(): void {
|
||||||
// stub
|
if (build == "saas") {
|
||||||
}
|
logger.debug(`acmeCertSync: skipping ACME cert sync in SaaS build`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const configData = config.getRawConfig();
|
||||||
|
|
||||||
|
if (!configData.flags?.enable_acme_cert_sync) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: ACME cert sync is disabled by config flag, skipping`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const acmeJsonPath =
|
||||||
|
configData.acme?.acme_json_path ?? "config/letsencrypt/acme.json";
|
||||||
|
const intervalMs = configData.acme?.sync_interval_ms ?? 5000;
|
||||||
|
const httpEndpoint = configData.acme?.acme_http_endpoint;
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: starting ACME cert sync from "${acmeJsonPath}" across all resolvers every ${intervalMs}ms`
|
||||||
|
);
|
||||||
|
if (httpEndpoint) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: also syncing from HTTP endpoint "${httpEndpoint}" every ${intervalMs}ms`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const runSync = () => {
|
||||||
|
if (httpEndpoint) {
|
||||||
|
syncAcmeCertsFromHttp(httpEndpoint).catch((err) => {
|
||||||
|
logger.error(`acmeCertSync: error during HTTP sync: ${err}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// only run the file-based sync if the HTTP endpoint is not configured, to avoid doubling up
|
||||||
|
let stat: fs.Stats | null = null;
|
||||||
|
try {
|
||||||
|
stat = fs.statSync(acmeJsonPath);
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(
|
||||||
|
`acmeCertSync: cannot stat path "${acmeJsonPath}": ${err}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
const files = findAcmeJsonFiles(acmeJsonPath);
|
||||||
|
if (files.length === 0) {
|
||||||
|
logger.debug(
|
||||||
|
`acmeCertSync: no acme.json files found in directory "${acmeJsonPath}"`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// logger.debug(
|
||||||
|
// `acmeCertSync: found ${files.length} acme.json file(s) in directory "${acmeJsonPath}"`
|
||||||
|
// );
|
||||||
|
for (const file of files) {
|
||||||
|
syncAcmeCerts(file).catch((err) => {
|
||||||
|
logger.error(
|
||||||
|
`acmeCertSync: error during sync of "${file}": ${err}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
syncAcmeCerts(acmeJsonPath).catch((err) => {
|
||||||
|
logger.error(`acmeCertSync: error during sync: ${err}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run immediately on init, then on the configured interval
|
||||||
|
runSync();
|
||||||
|
|
||||||
|
setInterval(runSync, intervalMs);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,613 @@
|
|||||||
|
import {
|
||||||
|
and,
|
||||||
|
eq,
|
||||||
|
gte,
|
||||||
|
inArray,
|
||||||
|
isNull,
|
||||||
|
or,
|
||||||
|
sql,
|
||||||
|
SQL,
|
||||||
|
type InferInsertModel
|
||||||
|
} from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
AiBudget,
|
||||||
|
aiBudgetBreachEvents,
|
||||||
|
aiBudgets,
|
||||||
|
aiModels,
|
||||||
|
aiUsageRecords,
|
||||||
|
db,
|
||||||
|
userOrgRoles
|
||||||
|
} from "@server/db";
|
||||||
|
import { modelKeyMatches } from "@server/lib/aiModelKeyMatch";
|
||||||
|
import type { AiUsage } from "@server/lib/aiUsageExtraction";
|
||||||
|
import { regionalCache as cache } from "#dynamic/lib/cache";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
|
||||||
|
type BudgetPeriod = AiBudget["period"];
|
||||||
|
|
||||||
|
const PERIOD_DURATIONS_MS: Record<Exclude<BudgetPeriod, "lifetime">, number> = {
|
||||||
|
hourly: 60 * 60 * 1000,
|
||||||
|
daily: 24 * 60 * 60 * 1000,
|
||||||
|
weekly: 7 * 24 * 60 * 60 * 1000,
|
||||||
|
monthly: 30 * 24 * 60 * 60 * 1000,
|
||||||
|
yearly: 365 * 24 * 60 * 60 * 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
// Budgets are cheap to be a little stale about (enforcement is already
|
||||||
|
// check-then-act, not transactional). Re-derive each budget's usage sum
|
||||||
|
// from aiUsageRecords at most this often; in between, completed requests
|
||||||
|
// just add their own contribution onto the cached sum instead of
|
||||||
|
// re-querying/re-aggregating from scratch.
|
||||||
|
const BUDGET_CACHE_REFRESH_MS = 8_000;
|
||||||
|
// Redis-level TTL is only a safety net for eviction if a budget stops
|
||||||
|
// seeing traffic - the actual staleness check is the computedAt timestamp
|
||||||
|
// stored in the cached value, compared against BUDGET_CACHE_REFRESH_MS.
|
||||||
|
const BUDGET_CACHE_SAFETY_TTL_SEC = 60;
|
||||||
|
|
||||||
|
function applicableBudgetsCacheKey(ctx: BudgetScopeContext): string {
|
||||||
|
const roleKey = [...ctx.roleIds].sort((a, b) => a - b).join(",");
|
||||||
|
return [
|
||||||
|
"aiBudget:applicable",
|
||||||
|
ctx.orgId,
|
||||||
|
ctx.providerId,
|
||||||
|
ctx.requestedModel,
|
||||||
|
ctx.resourceId ?? "",
|
||||||
|
ctx.siteResourceId ?? "",
|
||||||
|
roleKey,
|
||||||
|
ctx.virtualApiKeyId ?? ""
|
||||||
|
].join(":");
|
||||||
|
}
|
||||||
|
|
||||||
|
function budgetUsageCacheKey(budgetId: number): string {
|
||||||
|
return `aiBudget:usage:${budgetId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
type CachedBudgetUsage = {
|
||||||
|
sum: number;
|
||||||
|
computedAt: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Budget periods are trailing windows from "now", not calendar-aligned
|
||||||
|
// (e.g. "daily" = last 24h). "lifetime" has no lower bound.
|
||||||
|
function windowStart(period: BudgetPeriod, now: number): number {
|
||||||
|
if (period === "lifetime") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return now - PERIOD_DURATIONS_MS[period];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BudgetScopeContext = {
|
||||||
|
orgId: string;
|
||||||
|
providerId: number;
|
||||||
|
requestedModel: string;
|
||||||
|
resourceId: number | null;
|
||||||
|
siteResourceId: number | null;
|
||||||
|
roleIds: number[];
|
||||||
|
requestUserId: string | null;
|
||||||
|
virtualApiKeyId: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every budget that could apply to this request: the provider itself, any
|
||||||
|
* model on that provider whose (possibly wildcarded) modelKey matches the
|
||||||
|
* requested model, the target resource/site-resource, and any role the
|
||||||
|
* requesting user holds in the org. Cached for BUDGET_CACHE_REFRESH_MS since
|
||||||
|
* budget/model config changes are rare and a request-scoped org/provider/
|
||||||
|
* model/resource/role combination repeats constantly under real traffic.
|
||||||
|
*/
|
||||||
|
export async function resolveApplicableBudgets(
|
||||||
|
ctx: BudgetScopeContext
|
||||||
|
): Promise<AiBudget[]> {
|
||||||
|
const cacheKey = applicableBudgetsCacheKey(ctx);
|
||||||
|
const cached = await cache.get<AiBudget[]>(cacheKey);
|
||||||
|
if (cached !== undefined) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
const budgets = await fetchApplicableBudgets(ctx);
|
||||||
|
await cache.set(cacheKey, budgets, BUDGET_CACHE_REFRESH_MS / 1000);
|
||||||
|
return budgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchApplicableBudgets(
|
||||||
|
ctx: BudgetScopeContext
|
||||||
|
): Promise<AiBudget[]> {
|
||||||
|
const providerModels = await db
|
||||||
|
.select({ modelId: aiModels.modelId, modelKey: aiModels.modelKey })
|
||||||
|
.from(aiModels)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(aiModels.providerId, ctx.providerId),
|
||||||
|
eq(aiModels.enabled, true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const matchingModelIds = providerModels
|
||||||
|
.filter((m) => modelKeyMatches(m.modelKey, ctx.requestedModel))
|
||||||
|
.map((m) => m.modelId);
|
||||||
|
|
||||||
|
const scopeConditions: SQL[] = [
|
||||||
|
and(
|
||||||
|
eq(aiBudgets.providerId, ctx.providerId),
|
||||||
|
isNull(aiBudgets.modelId)
|
||||||
|
)!
|
||||||
|
];
|
||||||
|
if (matchingModelIds.length > 0) {
|
||||||
|
scopeConditions.push(inArray(aiBudgets.modelId, matchingModelIds));
|
||||||
|
}
|
||||||
|
if (ctx.resourceId != null) {
|
||||||
|
scopeConditions.push(eq(aiBudgets.resourceId, ctx.resourceId));
|
||||||
|
}
|
||||||
|
if (ctx.siteResourceId != null) {
|
||||||
|
scopeConditions.push(eq(aiBudgets.siteResourceId, ctx.siteResourceId));
|
||||||
|
}
|
||||||
|
if (ctx.roleIds.length > 0) {
|
||||||
|
scopeConditions.push(inArray(aiBudgets.roleId, ctx.roleIds));
|
||||||
|
}
|
||||||
|
if (ctx.virtualApiKeyId != null) {
|
||||||
|
scopeConditions.push(
|
||||||
|
eq(aiBudgets.virtualApiKeyId, ctx.virtualApiKeyId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
.select()
|
||||||
|
.from(aiBudgets)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(aiBudgets.orgId, ctx.orgId),
|
||||||
|
eq(aiBudgets.enabled, true),
|
||||||
|
or(...scopeConditions)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sumUsageAmount(
|
||||||
|
where: SQL,
|
||||||
|
unit: AiBudget["unit"]
|
||||||
|
): Promise<number> {
|
||||||
|
const column =
|
||||||
|
unit === "usd" ? aiUsageRecords.costUsd : aiUsageRecords.totalTokens;
|
||||||
|
const [row] = await db
|
||||||
|
.select({ total: sql<number>`coalesce(sum(${column}), 0)` })
|
||||||
|
.from(aiUsageRecords)
|
||||||
|
.where(where);
|
||||||
|
return Number(row?.total ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sums recorded usage for a single budget's scope + rolling window. Model
|
||||||
|
* budgets can't be pushed down to SQL because the model's key may itself be
|
||||||
|
* a glob, so those rows are fetched for the provider+window and matched in
|
||||||
|
* JS the same way access-control matching does.
|
||||||
|
*/
|
||||||
|
export async function sumUsageForBudget(
|
||||||
|
budget: AiBudget,
|
||||||
|
ctx: BudgetScopeContext,
|
||||||
|
now: number
|
||||||
|
): Promise<number> {
|
||||||
|
const start = windowStart(budget.period, now);
|
||||||
|
|
||||||
|
if (budget.modelId != null) {
|
||||||
|
const [model] = await db
|
||||||
|
.select({
|
||||||
|
providerId: aiModels.providerId,
|
||||||
|
modelKey: aiModels.modelKey
|
||||||
|
})
|
||||||
|
.from(aiModels)
|
||||||
|
.where(eq(aiModels.modelId, budget.modelId))
|
||||||
|
.limit(1);
|
||||||
|
if (!model) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const rows = await db
|
||||||
|
.select({
|
||||||
|
requestedModel: aiUsageRecords.requestedModel,
|
||||||
|
costUsd: aiUsageRecords.costUsd,
|
||||||
|
totalTokens: aiUsageRecords.totalTokens
|
||||||
|
})
|
||||||
|
.from(aiUsageRecords)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(aiUsageRecords.orgId, ctx.orgId),
|
||||||
|
eq(aiUsageRecords.providerId, model.providerId),
|
||||||
|
gte(aiUsageRecords.createdAt, start)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return rows
|
||||||
|
.filter((r) => modelKeyMatches(model.modelKey, r.requestedModel))
|
||||||
|
.reduce(
|
||||||
|
(sum, r) =>
|
||||||
|
sum +
|
||||||
|
(budget.unit === "usd" ? (r.costUsd ?? 0) : r.totalTokens),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (budget.providerId != null) {
|
||||||
|
return sumUsageAmount(
|
||||||
|
and(
|
||||||
|
eq(aiUsageRecords.orgId, ctx.orgId),
|
||||||
|
eq(aiUsageRecords.providerId, budget.providerId),
|
||||||
|
gte(aiUsageRecords.createdAt, start)
|
||||||
|
)!,
|
||||||
|
budget.unit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (budget.resourceId != null) {
|
||||||
|
return sumUsageAmount(
|
||||||
|
and(
|
||||||
|
eq(aiUsageRecords.orgId, ctx.orgId),
|
||||||
|
eq(aiUsageRecords.resourceId, budget.resourceId),
|
||||||
|
gte(aiUsageRecords.createdAt, start)
|
||||||
|
)!,
|
||||||
|
budget.unit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (budget.siteResourceId != null) {
|
||||||
|
return sumUsageAmount(
|
||||||
|
and(
|
||||||
|
eq(aiUsageRecords.orgId, ctx.orgId),
|
||||||
|
eq(aiUsageRecords.siteResourceId, budget.siteResourceId),
|
||||||
|
gte(aiUsageRecords.createdAt, start)
|
||||||
|
)!,
|
||||||
|
budget.unit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (budget.roleId != null) {
|
||||||
|
const members = await db
|
||||||
|
.select({ userId: userOrgRoles.userId })
|
||||||
|
.from(userOrgRoles)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userOrgRoles.roleId, budget.roleId),
|
||||||
|
eq(userOrgRoles.orgId, ctx.orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const userIds = members.map((m) => m.userId);
|
||||||
|
if (userIds.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return sumUsageAmount(
|
||||||
|
and(
|
||||||
|
eq(aiUsageRecords.orgId, ctx.orgId),
|
||||||
|
inArray(aiUsageRecords.userId, userIds),
|
||||||
|
gte(aiUsageRecords.createdAt, start)
|
||||||
|
)!,
|
||||||
|
budget.unit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (budget.virtualApiKeyId != null) {
|
||||||
|
return sumUsageAmount(
|
||||||
|
and(
|
||||||
|
eq(aiUsageRecords.orgId, ctx.orgId),
|
||||||
|
eq(aiUsageRecords.virtualApiKeyId, budget.virtualApiKeyId),
|
||||||
|
gte(aiUsageRecords.createdAt, start)
|
||||||
|
)!,
|
||||||
|
budget.unit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached wrapper around sumUsageForBudget. Reuses a per-budget cached sum
|
||||||
|
* for up to BUDGET_CACHE_REFRESH_MS, and otherwise falls through to the DB
|
||||||
|
* aggregation and reseeds the cache. Completed requests within that window
|
||||||
|
* top the cached sum up via applyUsageToBudgetCache below rather than
|
||||||
|
* forcing a re-aggregation on every request.
|
||||||
|
*/
|
||||||
|
async function getBudgetUsage(
|
||||||
|
budget: AiBudget,
|
||||||
|
ctx: BudgetScopeContext,
|
||||||
|
now: number
|
||||||
|
): Promise<number> {
|
||||||
|
const cacheKey = budgetUsageCacheKey(budget.budgetId);
|
||||||
|
const cached = await cache.get<CachedBudgetUsage>(cacheKey);
|
||||||
|
if (cached && now - cached.computedAt < BUDGET_CACHE_REFRESH_MS) {
|
||||||
|
return cached.sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sum = await sumUsageForBudget(budget, ctx, now);
|
||||||
|
await cache.set(
|
||||||
|
cacheKey,
|
||||||
|
{ sum, computedAt: now } satisfies CachedBudgetUsage,
|
||||||
|
BUDGET_CACHE_SAFETY_TTL_SEC
|
||||||
|
);
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called once a request's actual usage is known, for every budget that was
|
||||||
|
* resolved as applicable to it (i.e. checkBudgets' returned `budgets`).
|
||||||
|
* Adds this request's contribution directly onto each budget's cached sum
|
||||||
|
* so the next request in the same refresh window doesn't need to re-query
|
||||||
|
* or re-aggregate. If there's no warm cache entry, or it's already due for
|
||||||
|
* a refresh, this is a no-op - the next reader re-derives from the DB,
|
||||||
|
* which by then already includes this request's row via recordUsage.
|
||||||
|
*/
|
||||||
|
export async function applyUsageToBudgetCache(
|
||||||
|
budgets: AiBudget[],
|
||||||
|
usage: { usd: number; tokens: number }
|
||||||
|
): Promise<void> {
|
||||||
|
await Promise.all(
|
||||||
|
budgets.map(async (budget) => {
|
||||||
|
const delta = budget.unit === "usd" ? usage.usd : usage.tokens;
|
||||||
|
if (!delta) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheKey = budgetUsageCacheKey(budget.budgetId);
|
||||||
|
const cached = await cache.get<CachedBudgetUsage>(cacheKey);
|
||||||
|
if (
|
||||||
|
!cached ||
|
||||||
|
Date.now() - cached.computedAt >= BUDGET_CACHE_REFRESH_MS
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await cache.set(
|
||||||
|
cacheKey,
|
||||||
|
{
|
||||||
|
sum: cached.sum + delta,
|
||||||
|
computedAt: cached.computedAt
|
||||||
|
} satisfies CachedBudgetUsage,
|
||||||
|
BUDGET_CACHE_SAFETY_TTL_SEC
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throttled to one durable event per budget per breach window, so a soft
|
||||||
|
// budget being exceeded doesn't write a row on every subsequent request
|
||||||
|
// while it stays over.
|
||||||
|
async function recordBreachEventIfNew(
|
||||||
|
budget: AiBudget,
|
||||||
|
ctx: BudgetScopeContext,
|
||||||
|
usageAmount: number,
|
||||||
|
now: number
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
const start = windowStart(budget.period, now);
|
||||||
|
const [existing] = await db
|
||||||
|
.select({ id: aiBudgetBreachEvents.id })
|
||||||
|
.from(aiBudgetBreachEvents)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(aiBudgetBreachEvents.budgetId, budget.budgetId),
|
||||||
|
gte(aiBudgetBreachEvents.createdAt, start)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
if (existing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.insert(aiBudgetBreachEvents).values({
|
||||||
|
orgId: ctx.orgId,
|
||||||
|
budgetId: budget.budgetId,
|
||||||
|
enforcement: budget.enforcement,
|
||||||
|
unit: budget.unit,
|
||||||
|
period: budget.period,
|
||||||
|
amount: budget.amount,
|
||||||
|
usageAmount,
|
||||||
|
blocked: budget.enforcement === "hard",
|
||||||
|
requestUserId: ctx.requestUserId,
|
||||||
|
createdAt: now
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("Failed to record AI budget breach event", {
|
||||||
|
error,
|
||||||
|
budgetId: budget.budgetId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BudgetCheckResult = {
|
||||||
|
blocked: boolean;
|
||||||
|
blockingBudget?: AiBudget;
|
||||||
|
// Every budget resolved as applicable to this request, regardless of
|
||||||
|
// whether it was breached - pass to applyUsageToBudgetCache once this
|
||||||
|
// request's actual usage is known.
|
||||||
|
budgets: AiBudget[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function checkBudgets(
|
||||||
|
ctx: BudgetScopeContext
|
||||||
|
): Promise<BudgetCheckResult> {
|
||||||
|
const budgets = await resolveApplicableBudgets(ctx);
|
||||||
|
if (budgets.length === 0) {
|
||||||
|
return { blocked: false, budgets: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
let blockingBudget: AiBudget | undefined;
|
||||||
|
|
||||||
|
for (const budget of budgets) {
|
||||||
|
const usage = await getBudgetUsage(budget, ctx, now);
|
||||||
|
if (usage < budget.amount) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await recordBreachEventIfNew(budget, ctx, usage, now);
|
||||||
|
|
||||||
|
if (budget.enforcement === "hard" && !blockingBudget) {
|
||||||
|
blockingBudget = budget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockingBudget
|
||||||
|
? { blocked: true, blockingBudget, budgets }
|
||||||
|
: { blocked: false, budgets };
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UsageRecordInput = {
|
||||||
|
orgId: string;
|
||||||
|
providerId: number;
|
||||||
|
resourceId: number | null;
|
||||||
|
siteResourceId: number | null;
|
||||||
|
userId: string | null;
|
||||||
|
virtualApiKeyId: string | null;
|
||||||
|
requestedModel: string;
|
||||||
|
usage: AiUsage;
|
||||||
|
costUsd: number | null;
|
||||||
|
createdAt?: number;
|
||||||
|
// Same id as the aiSessionLog row logged for this request, so the two
|
||||||
|
// can be joined to show token/cost usage alongside the session
|
||||||
|
// transcript. Undefined when the session wasn't logged (e.g. session
|
||||||
|
// log retention disabled for the org).
|
||||||
|
sessionId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AiUsageRecordInsert = InferInsertModel<typeof aiUsageRecords>;
|
||||||
|
|
||||||
|
// In-memory buffer for batching AI usage record inserts, mirroring the
|
||||||
|
// approach in server/routers/badger/logRequestAudit.ts. Usage rows are read
|
||||||
|
// back on every budget-cache miss (see getBudgetUsage above), which happens
|
||||||
|
// at least every BUDGET_CACHE_REFRESH_MS, so this buffer is flushed much
|
||||||
|
// more aggressively than the request audit log to keep the table from
|
||||||
|
// lagging behind what budget enforcement needs. Unlike the audit log, there
|
||||||
|
// is no retention/cleanup job for this table - usage history is kept
|
||||||
|
// indefinitely for billing and historical reporting.
|
||||||
|
const usageRecordBuffer: AiUsageRecordInsert[] = [];
|
||||||
|
|
||||||
|
const USAGE_BATCH_SIZE = 20; // Write to DB every 20 records
|
||||||
|
const USAGE_BATCH_INTERVAL_MS = 1000; // Or every 1 second, whichever comes first
|
||||||
|
const USAGE_MAX_BUFFER_SIZE = 5000; // Prevent unbounded memory growth
|
||||||
|
let usageFlushTimer: NodeJS.Timeout | null = null;
|
||||||
|
let isUsageFlushInProgress = false;
|
||||||
|
|
||||||
|
async function flushUsageRecords() {
|
||||||
|
if (usageRecordBuffer.length === 0 || isUsageFlushInProgress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isUsageFlushInProgress = true;
|
||||||
|
|
||||||
|
const recordsToWrite = usageRecordBuffer.splice(
|
||||||
|
0,
|
||||||
|
usageRecordBuffer.length
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use a transaction to ensure all inserts succeed or fail together
|
||||||
|
await db.transaction(async (tx) => {
|
||||||
|
// Batch insert in groups to avoid overwhelming the database
|
||||||
|
const DB_BATCH_SIZE = 25;
|
||||||
|
for (let i = 0; i < recordsToWrite.length; i += DB_BATCH_SIZE) {
|
||||||
|
const batch = recordsToWrite.slice(i, i + DB_BATCH_SIZE);
|
||||||
|
await tx.insert(aiUsageRecords).values(batch);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
logger.debug(
|
||||||
|
`Flushed ${recordsToWrite.length} AI usage records to database`
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("Error flushing AI usage records:", error);
|
||||||
|
// On transaction error, put records back at the front of the buffer
|
||||||
|
// to retry, but only if the buffer isn't too large
|
||||||
|
if (
|
||||||
|
usageRecordBuffer.length <
|
||||||
|
USAGE_MAX_BUFFER_SIZE - recordsToWrite.length
|
||||||
|
) {
|
||||||
|
usageRecordBuffer.unshift(...recordsToWrite);
|
||||||
|
logger.info(
|
||||||
|
`Re-queued ${recordsToWrite.length} AI usage records for retry`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
logger.error(
|
||||||
|
`Buffer full, dropped ${recordsToWrite.length} AI usage records`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
isUsageFlushInProgress = false;
|
||||||
|
// If buffer filled up while we were flushing, flush again
|
||||||
|
if (usageRecordBuffer.length >= USAGE_BATCH_SIZE) {
|
||||||
|
flushUsageRecords().catch((err) =>
|
||||||
|
logger.error("Error in follow-up AI usage flush:", err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleUsageFlush() {
|
||||||
|
if (usageFlushTimer === null) {
|
||||||
|
usageFlushTimer = setTimeout(() => {
|
||||||
|
usageFlushTimer = null;
|
||||||
|
flushUsageRecords().catch((err) =>
|
||||||
|
logger.error("Error in scheduled AI usage flush:", err)
|
||||||
|
);
|
||||||
|
}, USAGE_BATCH_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gracefully flush all pending AI usage records (call this on shutdown).
|
||||||
|
*/
|
||||||
|
export async function shutdownUsageRecorder() {
|
||||||
|
if (usageFlushTimer) {
|
||||||
|
clearTimeout(usageFlushTimer);
|
||||||
|
usageFlushTimer = null;
|
||||||
|
}
|
||||||
|
// Force flush even if one is in progress by waiting and retrying
|
||||||
|
while (isUsageFlushInProgress) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
|
}
|
||||||
|
await flushUsageRecords();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function recordUsage(input: UsageRecordInput): Promise<void> {
|
||||||
|
try {
|
||||||
|
const { usage } = input;
|
||||||
|
const totalTokens =
|
||||||
|
usage.promptTokens +
|
||||||
|
usage.cacheReadTokens +
|
||||||
|
usage.cacheWriteTokens +
|
||||||
|
usage.completionTokens +
|
||||||
|
usage.reasoningTokens;
|
||||||
|
|
||||||
|
// Prevent unbounded buffer growth - drop oldest entries if buffer is too large
|
||||||
|
if (usageRecordBuffer.length >= USAGE_MAX_BUFFER_SIZE) {
|
||||||
|
const dropped = usageRecordBuffer.splice(0, USAGE_BATCH_SIZE);
|
||||||
|
logger.warn(
|
||||||
|
`AI usage record buffer exceeded max size (${USAGE_MAX_BUFFER_SIZE}), dropped ${dropped.length} oldest entries`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
usageRecordBuffer.push({
|
||||||
|
orgId: input.orgId,
|
||||||
|
providerId: input.providerId,
|
||||||
|
resourceId: input.resourceId,
|
||||||
|
siteResourceId: input.siteResourceId,
|
||||||
|
userId: input.userId,
|
||||||
|
virtualApiKeyId: input.virtualApiKeyId,
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
requestedModel: input.requestedModel,
|
||||||
|
promptTokens: usage.promptTokens,
|
||||||
|
cacheReadTokens: usage.cacheReadTokens,
|
||||||
|
cacheWriteTokens: usage.cacheWriteTokens,
|
||||||
|
completionTokens: usage.completionTokens,
|
||||||
|
reasoningTokens: usage.reasoningTokens,
|
||||||
|
totalTokens,
|
||||||
|
costUsd: input.costUsd,
|
||||||
|
estimated: usage.estimated,
|
||||||
|
createdAt: input.createdAt ?? Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Flush immediately if buffer is full, otherwise schedule a flush
|
||||||
|
if (usageRecordBuffer.length >= USAGE_BATCH_SIZE) {
|
||||||
|
flushUsageRecords().catch((err) =>
|
||||||
|
logger.error("Error flushing AI usage records:", err)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
scheduleUsageFlush();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("Failed to record AI usage", { error });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,339 @@
|
|||||||
|
import type { Request } from "express";
|
||||||
|
import { AI_CAPABILITIES, type AiCapability } from "@app/lib/aiCapabilities";
|
||||||
|
|
||||||
|
export { AI_CAPABILITIES, type AiCapability };
|
||||||
|
|
||||||
|
export type AiCapabilityRoute = {
|
||||||
|
method: "POST";
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AiProtocolFamily = "openai" | "anthropic" | "google" | "bedrock";
|
||||||
|
|
||||||
|
export type AiCapabilityDefinition = {
|
||||||
|
id: AiCapability;
|
||||||
|
protocolFamily: AiProtocolFamily;
|
||||||
|
routes: AiCapabilityRoute[];
|
||||||
|
extractModel: (req: Request) => string | undefined;
|
||||||
|
resolveUpstreamUrl: (
|
||||||
|
baseUrl: string,
|
||||||
|
req: Request,
|
||||||
|
model: string
|
||||||
|
) => string;
|
||||||
|
isStreaming: (req: Request, contentType: string) => boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function bodyModel(req: Request): string | undefined {
|
||||||
|
return typeof req.body?.model === "string" ? req.body.model : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function paramModel(req: Request): string | undefined {
|
||||||
|
const model = req.params?.model;
|
||||||
|
return typeof model === "string" && model.length > 0 ? model : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function joinUpstreamUrl(baseUrl: string, path: string): string {
|
||||||
|
const base = baseUrl.replace(/\/+$/, "");
|
||||||
|
let suffix = path.startsWith("/") ? path : `/${path}`;
|
||||||
|
|
||||||
|
let basePathname = "/";
|
||||||
|
try {
|
||||||
|
basePathname = new URL(base).pathname.replace(/\/+$/, "") || "/";
|
||||||
|
} catch {
|
||||||
|
// Fall through with "/" non-absolute bases are not expected in
|
||||||
|
// production, but keep joining usable for malformed input.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basePathname !== "/") {
|
||||||
|
const baseSegs = basePathname.split("/").filter(Boolean);
|
||||||
|
const pathSegs = suffix.split("/").filter(Boolean);
|
||||||
|
const max = Math.min(baseSegs.length, pathSegs.length);
|
||||||
|
let overlap = 0;
|
||||||
|
for (let n = max; n >= 1; n--) {
|
||||||
|
const baseSuffix = baseSegs.slice(-n);
|
||||||
|
const pathPrefix = pathSegs.slice(0, n);
|
||||||
|
if (baseSuffix.every((seg, i) => seg === pathPrefix[i])) {
|
||||||
|
overlap = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (overlap > 0) {
|
||||||
|
const remaining = pathSegs.slice(overlap);
|
||||||
|
suffix = remaining.length > 0 ? `/${remaining.join("/")}` : "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suffix === "/") {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${base}${suffix}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathFromRequest(req: Request): string {
|
||||||
|
const raw = req.originalUrl || req.url || req.path;
|
||||||
|
return raw.startsWith("/") ? raw : `/${raw}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bodyRequestsStream(req: Request): boolean {
|
||||||
|
return req.body?.stream === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function contentTypeIsSse(contentType: string): boolean {
|
||||||
|
return contentType.includes("text/event-stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
function contentTypeIsAmazonEventStream(contentType: string): boolean {
|
||||||
|
return contentType.includes("application/vnd.amazon.eventstream");
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathIncludes(req: Request, fragment: string): boolean {
|
||||||
|
return pathFromRequest(req).includes(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBodyOrSseStreaming(req: Request, contentType: string): boolean {
|
||||||
|
return bodyRequestsStream(req) || contentTypeIsSse(contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isGeminiStyleStreaming(req: Request, contentType: string): boolean {
|
||||||
|
return (
|
||||||
|
pathIncludes(req, "streamGenerateContent") ||
|
||||||
|
pathIncludes(req, "alt=sse") ||
|
||||||
|
contentTypeIsSse(contentType)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AI_CAPABILITY_DEFS: Record<AiCapability, AiCapabilityDefinition> =
|
||||||
|
{
|
||||||
|
openai_chat: {
|
||||||
|
id: "openai_chat",
|
||||||
|
protocolFamily: "openai",
|
||||||
|
routes: [
|
||||||
|
{ method: "POST", path: "/v1/chat/completions" },
|
||||||
|
{ method: "POST", path: "/chat/completions" }
|
||||||
|
],
|
||||||
|
extractModel: bodyModel,
|
||||||
|
resolveUpstreamUrl: (base, req) =>
|
||||||
|
joinUpstreamUrl(base, pathFromRequest(req)),
|
||||||
|
isStreaming: isBodyOrSseStreaming
|
||||||
|
},
|
||||||
|
openai_responses: {
|
||||||
|
id: "openai_responses",
|
||||||
|
protocolFamily: "openai",
|
||||||
|
routes: [{ method: "POST", path: "/v1/responses" }],
|
||||||
|
extractModel: bodyModel,
|
||||||
|
resolveUpstreamUrl: (base, req) =>
|
||||||
|
joinUpstreamUrl(base, pathFromRequest(req)),
|
||||||
|
isStreaming: isBodyOrSseStreaming
|
||||||
|
},
|
||||||
|
anthropic_messages: {
|
||||||
|
id: "anthropic_messages",
|
||||||
|
protocolFamily: "anthropic",
|
||||||
|
routes: [{ method: "POST", path: "/v1/messages" }],
|
||||||
|
extractModel: bodyModel,
|
||||||
|
resolveUpstreamUrl: (base, req) =>
|
||||||
|
joinUpstreamUrl(base, pathFromRequest(req)),
|
||||||
|
isStreaming: isBodyOrSseStreaming
|
||||||
|
},
|
||||||
|
gemini_generate_content: {
|
||||||
|
id: "gemini_generate_content",
|
||||||
|
protocolFamily: "google",
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
path: "/v1beta/models/:model\\:generateContent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
path: "/v1beta/models/:model\\:streamGenerateContent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
extractModel: paramModel,
|
||||||
|
resolveUpstreamUrl: (base, req) =>
|
||||||
|
joinUpstreamUrl(base, pathFromRequest(req)),
|
||||||
|
isStreaming: isGeminiStyleStreaming
|
||||||
|
},
|
||||||
|
google_generate_content: {
|
||||||
|
id: "google_generate_content",
|
||||||
|
protocolFamily: "google",
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
// Vertex publisher model generateContent
|
||||||
|
path: "/v1/projects/:project/locations/:location/publishers/:publisher/models/:model\\:generateContent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
path: "/v1/projects/:project/locations/:location/publishers/:publisher/models/:model\\:streamGenerateContent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
extractModel: paramModel,
|
||||||
|
resolveUpstreamUrl: (base, req) =>
|
||||||
|
joinUpstreamUrl(base, pathFromRequest(req)),
|
||||||
|
isStreaming: isGeminiStyleStreaming
|
||||||
|
},
|
||||||
|
google_raw_predict: {
|
||||||
|
id: "google_raw_predict",
|
||||||
|
protocolFamily: "google",
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
path: "/v1/projects/:project/locations/:location/publishers/:publisher/models/:model\\:rawPredict"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
path: "/v1/projects/:project/locations/:location/publishers/:publisher/models/:model\\:streamRawPredict"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
extractModel: paramModel,
|
||||||
|
resolveUpstreamUrl: (base, req) =>
|
||||||
|
joinUpstreamUrl(base, pathFromRequest(req)),
|
||||||
|
isStreaming: (req, contentType) =>
|
||||||
|
pathIncludes(req, "streamRawPredict") ||
|
||||||
|
pathIncludes(req, "alt=sse") ||
|
||||||
|
contentTypeIsSse(contentType)
|
||||||
|
},
|
||||||
|
bedrock_model_invoke: {
|
||||||
|
id: "bedrock_model_invoke",
|
||||||
|
protocolFamily: "bedrock",
|
||||||
|
routes: [
|
||||||
|
{ method: "POST", path: "/model/:model/invoke" },
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
path: "/model/:model/invoke-with-response-stream"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
extractModel: paramModel,
|
||||||
|
resolveUpstreamUrl: (base, req) =>
|
||||||
|
joinUpstreamUrl(base, pathFromRequest(req)),
|
||||||
|
isStreaming: (req, contentType) =>
|
||||||
|
pathIncludes(req, "invoke-with-response-stream") ||
|
||||||
|
contentTypeIsAmazonEventStream(contentType) ||
|
||||||
|
contentTypeIsSse(contentType)
|
||||||
|
},
|
||||||
|
bedrock_converse: {
|
||||||
|
id: "bedrock_converse",
|
||||||
|
protocolFamily: "bedrock",
|
||||||
|
routes: [
|
||||||
|
{ method: "POST", path: "/model/:model/converse" },
|
||||||
|
{ method: "POST", path: "/model/:model/converse-stream" }
|
||||||
|
],
|
||||||
|
extractModel: paramModel,
|
||||||
|
resolveUpstreamUrl: (base, req) =>
|
||||||
|
joinUpstreamUrl(base, pathFromRequest(req)),
|
||||||
|
isStreaming: (req, contentType) =>
|
||||||
|
pathIncludes(req, "converse-stream") ||
|
||||||
|
contentTypeIsAmazonEventStream(contentType) ||
|
||||||
|
contentTypeIsSse(contentType)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isAiCapability(value: unknown): value is AiCapability {
|
||||||
|
return (
|
||||||
|
typeof value === "string" &&
|
||||||
|
(AI_CAPABILITIES as readonly string[]).includes(value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an Express-style route path from AI_CAPABILITY_DEFS into a RegExp.
|
||||||
|
* Handles `:param` segments and escaped literal colons (`\:`).
|
||||||
|
*/
|
||||||
|
export function routePatternToRegExp(routePath: string): RegExp {
|
||||||
|
let pattern = "";
|
||||||
|
for (let i = 0; i < routePath.length; i++) {
|
||||||
|
const ch = routePath[i];
|
||||||
|
if (
|
||||||
|
ch === "\\" &&
|
||||||
|
i + 1 < routePath.length &&
|
||||||
|
routePath[i + 1] === ":"
|
||||||
|
) {
|
||||||
|
pattern += ":";
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch === ":") {
|
||||||
|
// Named param: consume until next / or end
|
||||||
|
i++;
|
||||||
|
while (
|
||||||
|
i < routePath.length &&
|
||||||
|
routePath[i] !== "/" &&
|
||||||
|
!(routePath[i] === "\\" && routePath[i + 1] === ":")
|
||||||
|
) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
i--; // loop will ++
|
||||||
|
pattern += "[^/]+";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Escape regex special chars
|
||||||
|
if (/[.*+?^${}()|[\]\\]/.test(ch)) {
|
||||||
|
pattern += "\\" + ch;
|
||||||
|
} else {
|
||||||
|
pattern += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new RegExp(`^${pattern}$`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveAiCapabilityFromPath(path: string): AiCapability | null {
|
||||||
|
const pathname = path.split("?")[0] || "/";
|
||||||
|
const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
||||||
|
|
||||||
|
for (const def of Object.values(AI_CAPABILITY_DEFS)) {
|
||||||
|
for (const route of def.routes) {
|
||||||
|
if (routePatternToRegExp(route.path).test(normalized)) {
|
||||||
|
return def.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseCapabilities(raw: unknown): AiCapability[] {
|
||||||
|
if (raw == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsed: unknown = raw;
|
||||||
|
if (typeof raw === "string") {
|
||||||
|
const trimmed = raw.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(trimmed);
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(parsed)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const out: AiCapability[] = [];
|
||||||
|
const seen = new Set<AiCapability>();
|
||||||
|
for (const item of parsed) {
|
||||||
|
if (isAiCapability(item) && !seen.has(item)) {
|
||||||
|
seen.add(item);
|
||||||
|
out.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serializeCapabilities(capabilities: AiCapability[]): string {
|
||||||
|
return JSON.stringify(capabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function providerHasCapability(
|
||||||
|
capabilities: AiCapability[] | string | null | undefined,
|
||||||
|
capability: AiCapability
|
||||||
|
): boolean {
|
||||||
|
const list =
|
||||||
|
typeof capabilities === "string" || capabilities == null
|
||||||
|
? parseCapabilities(capabilities)
|
||||||
|
: capabilities;
|
||||||
|
return list.includes(capability);
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
import {
|
||||||
|
AI_CAPABILITY_DEFS,
|
||||||
|
type AiCapability,
|
||||||
|
type AiProtocolFamily
|
||||||
|
} from "@server/lib/aiCapabilities";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
|
||||||
|
export type ClientErrorResponse = {
|
||||||
|
statusCode?: number;
|
||||||
|
contentType?: string;
|
||||||
|
body: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AiCapabilityErrorKind =
|
||||||
|
| "authentication"
|
||||||
|
| "invalid_request"
|
||||||
|
| "not_found"
|
||||||
|
| "permission"
|
||||||
|
| "rate_limit"
|
||||||
|
| "internal";
|
||||||
|
|
||||||
|
const AUTH_MESSAGE = "Invalid API key provided.";
|
||||||
|
|
||||||
|
type KindFields = {
|
||||||
|
openaiType: string;
|
||||||
|
openaiCode: string | null;
|
||||||
|
anthropicType: string;
|
||||||
|
googleStatus: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const KIND_FIELDS: Record<AiCapabilityErrorKind, KindFields> = {
|
||||||
|
authentication: {
|
||||||
|
openaiType: "authentication_error",
|
||||||
|
openaiCode: "invalid_api_key",
|
||||||
|
anthropicType: "authentication_error",
|
||||||
|
googleStatus: "UNAUTHENTICATED"
|
||||||
|
},
|
||||||
|
invalid_request: {
|
||||||
|
openaiType: "invalid_request_error",
|
||||||
|
openaiCode: null,
|
||||||
|
anthropicType: "invalid_request_error",
|
||||||
|
googleStatus: "INVALID_ARGUMENT"
|
||||||
|
},
|
||||||
|
not_found: {
|
||||||
|
openaiType: "invalid_request_error",
|
||||||
|
openaiCode: null,
|
||||||
|
anthropicType: "not_found_error",
|
||||||
|
googleStatus: "NOT_FOUND"
|
||||||
|
},
|
||||||
|
permission: {
|
||||||
|
openaiType: "invalid_request_error",
|
||||||
|
openaiCode: null,
|
||||||
|
anthropicType: "permission_error",
|
||||||
|
googleStatus: "PERMISSION_DENIED"
|
||||||
|
},
|
||||||
|
rate_limit: {
|
||||||
|
openaiType: "rate_limit_error",
|
||||||
|
openaiCode: "rate_limit_exceeded",
|
||||||
|
anthropicType: "rate_limit_error",
|
||||||
|
googleStatus: "RESOURCE_EXHAUSTED"
|
||||||
|
},
|
||||||
|
internal: {
|
||||||
|
openaiType: "api_error",
|
||||||
|
openaiCode: null,
|
||||||
|
anthropicType: "api_error",
|
||||||
|
googleStatus: "INTERNAL"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function resolveProtocolFamily(
|
||||||
|
capability: AiCapability | null
|
||||||
|
): AiProtocolFamily {
|
||||||
|
if (capability == null) {
|
||||||
|
return "openai";
|
||||||
|
}
|
||||||
|
return AI_CAPABILITY_DEFS[capability].protocolFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a protocol-native error body for the given capability.
|
||||||
|
* Message stays contextual; only the envelope/machine fields follow the
|
||||||
|
* capability's native API shape.
|
||||||
|
*/
|
||||||
|
export function buildAiCapabilityErrorBody(
|
||||||
|
capability: AiCapability | null,
|
||||||
|
kind: AiCapabilityErrorKind,
|
||||||
|
message: string,
|
||||||
|
httpStatus?: number
|
||||||
|
): Record<string, unknown> {
|
||||||
|
const family = resolveProtocolFamily(capability);
|
||||||
|
const fields = KIND_FIELDS[kind];
|
||||||
|
|
||||||
|
switch (family) {
|
||||||
|
case "openai":
|
||||||
|
return {
|
||||||
|
error: {
|
||||||
|
message,
|
||||||
|
type: fields.openaiType,
|
||||||
|
param: null,
|
||||||
|
code: fields.openaiCode
|
||||||
|
}
|
||||||
|
};
|
||||||
|
case "anthropic":
|
||||||
|
return {
|
||||||
|
type: "error",
|
||||||
|
error: {
|
||||||
|
type: fields.anthropicType,
|
||||||
|
message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
case "google":
|
||||||
|
return {
|
||||||
|
error: {
|
||||||
|
code: httpStatus ?? HttpCode.BAD_REQUEST,
|
||||||
|
message,
|
||||||
|
status: fields.googleStatus
|
||||||
|
}
|
||||||
|
};
|
||||||
|
case "bedrock":
|
||||||
|
return { message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildInferenceAuthClientError(
|
||||||
|
capability: AiCapability | null
|
||||||
|
): ClientErrorResponse {
|
||||||
|
return {
|
||||||
|
statusCode: HttpCode.UNAUTHORIZED,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify(
|
||||||
|
buildAiCapabilityErrorBody(
|
||||||
|
capability,
|
||||||
|
"authentication",
|
||||||
|
AUTH_MESSAGE,
|
||||||
|
HttpCode.UNAUTHORIZED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { createHash } from "crypto";
|
||||||
|
import config from "@server/lib/config";
|
||||||
|
|
||||||
|
export const AI_GATEWAY_TRUST_HEADER = "X-Pangolin-Ai-Gateway-Auth";
|
||||||
|
|
||||||
|
// Injected by the same Traefik trust middleware as AI_GATEWAY_TRUST_HEADER,
|
||||||
|
// but its value differs per router (public inference resource vs. private
|
||||||
|
// siteResource) so the gateway can tell which kind of resource a trusted
|
||||||
|
// request arrived on without re-deriving it from resourceId/siteResourceId.
|
||||||
|
export const AI_GATEWAY_RESOURCE_TYPE_HEADER =
|
||||||
|
"X-Pangolin-Ai-Gateway-Resource-Type";
|
||||||
|
|
||||||
|
export type AiGatewayResourceType = "resource" | "site-resource";
|
||||||
|
|
||||||
|
// Opt-in (server.enable_ai_gateway_client_ip_header): carries the client IP
|
||||||
|
// that Badger resolved at the Traefik hop, so it survives an intermediary
|
||||||
|
// proxy between Traefik and the AI gateway that overwrites
|
||||||
|
// X-Forwarded-For/X-Real-Ip instead of appending to them. Set by a
|
||||||
|
// disableForwardAuth Badger middleware instance (see getTraefikConfig.ts)
|
||||||
|
// on the site-resource inference router only, since that's the sole path
|
||||||
|
// that resolves request identity from the client IP.
|
||||||
|
export const AI_GATEWAY_CLIENT_IP_HEADER = "X-Pangolin-Client-Ip";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive a Traefik-injected trust token from the server secret.
|
||||||
|
* Traefik overwrites this header on inference routes so the AI gateway can
|
||||||
|
* trust Badger-injected Remote-* identity without re-validating credentials.
|
||||||
|
*/
|
||||||
|
export function deriveAiGatewayTrustToken(secret: string): string {
|
||||||
|
return createHash("sha256")
|
||||||
|
.update(`ai-gateway-trust:${secret}`)
|
||||||
|
.digest("hex");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAiGatewayTrustToken(): string {
|
||||||
|
const secret = config.getRawConfig().server.secret;
|
||||||
|
if (!secret) {
|
||||||
|
throw new Error("Server secret is required for AI gateway trust token");
|
||||||
|
}
|
||||||
|
return deriveAiGatewayTrustToken(secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAiGatewayTrustHeaderValid(
|
||||||
|
headers: Record<string, string | string[] | undefined> | undefined,
|
||||||
|
expectedToken?: string
|
||||||
|
): boolean {
|
||||||
|
if (!headers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const expected = expectedToken ?? getAiGatewayTrustToken();
|
||||||
|
const raw =
|
||||||
|
headers[AI_GATEWAY_TRUST_HEADER] ??
|
||||||
|
headers[AI_GATEWAY_TRUST_HEADER.toLowerCase()];
|
||||||
|
const value = Array.isArray(raw) ? raw[0] : raw;
|
||||||
|
return typeof value === "string" && value === expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAiGatewayResourceType(
|
||||||
|
headers: Record<string, string | string[] | undefined> | undefined
|
||||||
|
): AiGatewayResourceType | null {
|
||||||
|
if (!headers) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const raw =
|
||||||
|
headers[AI_GATEWAY_RESOURCE_TYPE_HEADER] ??
|
||||||
|
headers[AI_GATEWAY_RESOURCE_TYPE_HEADER.toLowerCase()];
|
||||||
|
const value = Array.isArray(raw) ? raw[0] : raw;
|
||||||
|
return value === "resource" || value === "site-resource" ? value : null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import http from "node:http";
|
||||||
|
import https from "node:https";
|
||||||
|
import { Readable } from "node:stream";
|
||||||
|
|
||||||
|
type UpstreamFetchInit = {
|
||||||
|
method: string;
|
||||||
|
headers: Record<string, string>;
|
||||||
|
body?: string;
|
||||||
|
skipTlsVerification?: boolean;
|
||||||
|
signal?: AbortSignal;
|
||||||
|
};
|
||||||
|
|
||||||
|
const insecureHttpsAgent = new https.Agent({
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
keepAlive: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export function aiGatewayUpstreamFetch(
|
||||||
|
url: string,
|
||||||
|
init: UpstreamFetchInit
|
||||||
|
): Promise<Response> {
|
||||||
|
const parsed = new URL(url);
|
||||||
|
const isHttps = parsed.protocol === "https:";
|
||||||
|
const lib = isHttps ? https : http;
|
||||||
|
const agent =
|
||||||
|
isHttps && init.skipTlsVerification ? insecureHttpsAgent : undefined;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (init.signal?.aborted) {
|
||||||
|
reject(init.signal.reason ?? new Error("Request aborted"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const req = lib.request(
|
||||||
|
url,
|
||||||
|
{
|
||||||
|
method: init.method,
|
||||||
|
headers: init.headers,
|
||||||
|
agent
|
||||||
|
},
|
||||||
|
(res) => {
|
||||||
|
const headers = new Headers();
|
||||||
|
for (const [key, value] of Object.entries(res.headers)) {
|
||||||
|
if (value === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
for (const entry of value) {
|
||||||
|
headers.append(key, entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
headers.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = Readable.toWeb(res) as ReadableStream<Uint8Array>;
|
||||||
|
resolve(
|
||||||
|
new Response(body, {
|
||||||
|
status: res.statusCode ?? 502,
|
||||||
|
statusText: res.statusMessage,
|
||||||
|
headers
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
req.on("error", reject);
|
||||||
|
|
||||||
|
if (init.signal) {
|
||||||
|
const onAbort = () => req.destroy(init.signal!.reason);
|
||||||
|
init.signal.addEventListener("abort", onAbort, { once: true });
|
||||||
|
req.on("close", () =>
|
||||||
|
init.signal!.removeEventListener("abort", onAbort)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init.body !== undefined) {
|
||||||
|
req.write(init.body);
|
||||||
|
}
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,721 @@
|
|||||||
|
import { and, eq, inArray } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
aiModels,
|
||||||
|
aiProviders,
|
||||||
|
db,
|
||||||
|
resourceAiModels,
|
||||||
|
resourceAiProviders,
|
||||||
|
siteResourceAiModels,
|
||||||
|
siteResourceAiProviders,
|
||||||
|
type Transaction
|
||||||
|
} from "@server/db";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
type DbOrTrx = Transaction | typeof db;
|
||||||
|
|
||||||
|
export const modelListTypeSchema = z.enum(["allow", "block"]);
|
||||||
|
|
||||||
|
export type ModelListType = z.infer<typeof modelListTypeSchema>;
|
||||||
|
|
||||||
|
export const accessModeSchema = z.enum(["inherit", "select"]);
|
||||||
|
|
||||||
|
export type AccessMode = z.infer<typeof accessModeSchema>;
|
||||||
|
|
||||||
|
export const resourceAiProviderAttachmentSchema = z.strictObject({
|
||||||
|
providerId: z.number().int().positive(),
|
||||||
|
accessMode: accessModeSchema.optional().default("inherit"),
|
||||||
|
enabled: z.boolean().optional().default(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ResourceAiProviderInput = z.infer<
|
||||||
|
typeof resourceAiProviderAttachmentSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type ResourceAiProviderAttachment = {
|
||||||
|
providerId: number;
|
||||||
|
accessMode: AccessMode;
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const resourceAiModelEntrySchema = z.strictObject({
|
||||||
|
modelId: z.number().int().positive(),
|
||||||
|
listType: modelListTypeSchema
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ResourceAiModelEntry = z.infer<typeof resourceAiModelEntrySchema>;
|
||||||
|
|
||||||
|
export type InferenceFieldsError = {
|
||||||
|
error: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isInferenceFieldsError(
|
||||||
|
value: { error: string } | object
|
||||||
|
): value is InferenceFieldsError {
|
||||||
|
return "error" in value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve which allow/block patterns apply for an attachment.
|
||||||
|
* inherit → provider lists; select → resource-selected lists (replace).
|
||||||
|
*/
|
||||||
|
export function resolveEffectiveLists(input: {
|
||||||
|
accessMode: AccessMode;
|
||||||
|
providerAllows: string[];
|
||||||
|
providerBlocks: string[];
|
||||||
|
resourceAllows: string[];
|
||||||
|
resourceBlocks: string[];
|
||||||
|
}): { allows: string[]; blocks: string[] } {
|
||||||
|
if (input.accessMode === "select") {
|
||||||
|
return {
|
||||||
|
allows: input.resourceAllows,
|
||||||
|
blocks: input.resourceBlocks
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
allows: input.providerAllows,
|
||||||
|
blocks: input.providerBlocks
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAttachments(
|
||||||
|
inputs: ResourceAiProviderInput[]
|
||||||
|
): ResourceAiProviderAttachment[] {
|
||||||
|
const byProviderId = new Map<
|
||||||
|
number,
|
||||||
|
{ accessMode: AccessMode; enabled: boolean }
|
||||||
|
>();
|
||||||
|
for (const input of inputs) {
|
||||||
|
byProviderId.set(input.providerId, {
|
||||||
|
accessMode: input.accessMode ?? "inherit",
|
||||||
|
enabled: input.enabled ?? true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return [...byProviderId.entries()].map(
|
||||||
|
([providerId, { accessMode, enabled }]) => ({
|
||||||
|
providerId,
|
||||||
|
accessMode,
|
||||||
|
enabled
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate provider attachments for an org.
|
||||||
|
*/
|
||||||
|
export async function resolveProviderAttachments(input: {
|
||||||
|
orgId: string;
|
||||||
|
attachments: ResourceAiProviderInput[];
|
||||||
|
requireAtLeastOne: boolean;
|
||||||
|
}): Promise<ResourceAiProviderAttachment[] | InferenceFieldsError> {
|
||||||
|
const attachments = normalizeAttachments(input.attachments);
|
||||||
|
|
||||||
|
if (input.requireAtLeastOne && attachments.length === 0) {
|
||||||
|
return {
|
||||||
|
error: "At least one AI provider is required for inference-mode resources"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attachments.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerIds = attachments.map((a) => a.providerId);
|
||||||
|
const providers = await db
|
||||||
|
.select({
|
||||||
|
providerId: aiProviders.providerId,
|
||||||
|
orgId: aiProviders.orgId,
|
||||||
|
enabled: aiProviders.enabled
|
||||||
|
})
|
||||||
|
.from(aiProviders)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
inArray(aiProviders.providerId, providerIds),
|
||||||
|
eq(aiProviders.orgId, input.orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (providers.length !== providerIds.length) {
|
||||||
|
return {
|
||||||
|
error: "One or more AI providers were not found in this organization"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const disabled = providers.find((p) => !p.enabled);
|
||||||
|
if (disabled) {
|
||||||
|
return {
|
||||||
|
error: `AI provider with ID ${disabled.providerId} is disabled`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function assertInferenceModeAllowsProviderFields(input: {
|
||||||
|
mode: string;
|
||||||
|
hasProviderAttachments: boolean;
|
||||||
|
}): Promise<InferenceFieldsError | null> {
|
||||||
|
if (input.mode === "inference") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (input.hasProviderAttachments) {
|
||||||
|
return {
|
||||||
|
error: "AI providers can only be attached to inference-mode resources"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach providers to a resource. Inherit attachments use the provider lists
|
||||||
|
* as-is (resource model rows for those providers are pruned). Select
|
||||||
|
* attachments keep resource-selected allow/block subsets.
|
||||||
|
*/
|
||||||
|
export async function setPublicResourceAiProviders(
|
||||||
|
resourceId: number,
|
||||||
|
attachments: ResourceAiProviderAttachment[],
|
||||||
|
trx: DbOrTrx = db
|
||||||
|
): Promise<void> {
|
||||||
|
await trx
|
||||||
|
.delete(resourceAiProviders)
|
||||||
|
.where(eq(resourceAiProviders.resourceId, resourceId));
|
||||||
|
|
||||||
|
if (attachments.length > 0) {
|
||||||
|
await trx.insert(resourceAiProviders).values(
|
||||||
|
attachments.map((a) => ({
|
||||||
|
resourceId,
|
||||||
|
providerId: a.providerId,
|
||||||
|
accessMode: a.accessMode,
|
||||||
|
enabled: a.enabled
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await prunePublicResourceModelsToSelectProviders(
|
||||||
|
resourceId,
|
||||||
|
attachments,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setSiteResourceAiProviders(
|
||||||
|
siteResourceId: number,
|
||||||
|
attachments: ResourceAiProviderAttachment[],
|
||||||
|
trx: DbOrTrx = db
|
||||||
|
): Promise<void> {
|
||||||
|
await trx
|
||||||
|
.delete(siteResourceAiProviders)
|
||||||
|
.where(eq(siteResourceAiProviders.siteResourceId, siteResourceId));
|
||||||
|
|
||||||
|
if (attachments.length > 0) {
|
||||||
|
await trx.insert(siteResourceAiProviders).values(
|
||||||
|
attachments.map((a) => ({
|
||||||
|
siteResourceId,
|
||||||
|
providerId: a.providerId,
|
||||||
|
accessMode: a.accessMode,
|
||||||
|
enabled: a.enabled
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await pruneSiteResourceModelsToSelectProviders(
|
||||||
|
siteResourceId,
|
||||||
|
attachments,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep resource model rows only for providers in select mode.
|
||||||
|
*/
|
||||||
|
async function prunePublicResourceModelsToSelectProviders(
|
||||||
|
resourceId: number,
|
||||||
|
attachments: ResourceAiProviderAttachment[],
|
||||||
|
trx: DbOrTrx
|
||||||
|
): Promise<void> {
|
||||||
|
const selectProviderIds = attachments
|
||||||
|
.filter((a) => a.accessMode === "select")
|
||||||
|
.map((a) => a.providerId);
|
||||||
|
|
||||||
|
if (selectProviderIds.length === 0) {
|
||||||
|
await trx
|
||||||
|
.delete(resourceAiModels)
|
||||||
|
.where(eq(resourceAiModels.resourceId, resourceId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = await trx
|
||||||
|
.select({
|
||||||
|
modelId: resourceAiModels.modelId,
|
||||||
|
providerId: aiModels.providerId
|
||||||
|
})
|
||||||
|
.from(resourceAiModels)
|
||||||
|
.innerJoin(aiModels, eq(resourceAiModels.modelId, aiModels.modelId))
|
||||||
|
.where(eq(resourceAiModels.resourceId, resourceId));
|
||||||
|
|
||||||
|
const allowed = new Set(selectProviderIds);
|
||||||
|
const toRemove = existing
|
||||||
|
.filter((row) => !allowed.has(row.providerId))
|
||||||
|
.map((row) => row.modelId);
|
||||||
|
|
||||||
|
if (toRemove.length > 0) {
|
||||||
|
await trx
|
||||||
|
.delete(resourceAiModels)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(resourceAiModels.resourceId, resourceId),
|
||||||
|
inArray(resourceAiModels.modelId, toRemove)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pruneSiteResourceModelsToSelectProviders(
|
||||||
|
siteResourceId: number,
|
||||||
|
attachments: ResourceAiProviderAttachment[],
|
||||||
|
trx: DbOrTrx
|
||||||
|
): Promise<void> {
|
||||||
|
const selectProviderIds = attachments
|
||||||
|
.filter((a) => a.accessMode === "select")
|
||||||
|
.map((a) => a.providerId);
|
||||||
|
|
||||||
|
if (selectProviderIds.length === 0) {
|
||||||
|
await trx
|
||||||
|
.delete(siteResourceAiModels)
|
||||||
|
.where(eq(siteResourceAiModels.siteResourceId, siteResourceId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = await trx
|
||||||
|
.select({
|
||||||
|
modelId: siteResourceAiModels.modelId,
|
||||||
|
providerId: aiModels.providerId
|
||||||
|
})
|
||||||
|
.from(siteResourceAiModels)
|
||||||
|
.innerJoin(aiModels, eq(siteResourceAiModels.modelId, aiModels.modelId))
|
||||||
|
.where(eq(siteResourceAiModels.siteResourceId, siteResourceId));
|
||||||
|
|
||||||
|
const allowed = new Set(selectProviderIds);
|
||||||
|
const toRemove = existing
|
||||||
|
.filter((row) => !allowed.has(row.providerId))
|
||||||
|
.map((row) => row.modelId);
|
||||||
|
|
||||||
|
if (toRemove.length > 0) {
|
||||||
|
await trx
|
||||||
|
.delete(siteResourceAiModels)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(siteResourceAiModels.siteResourceId, siteResourceId),
|
||||||
|
inArray(siteResourceAiModels.modelId, toRemove)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function clearPublicResourceAiConfig(
|
||||||
|
resourceId: number,
|
||||||
|
trx: DbOrTrx = db
|
||||||
|
): Promise<void> {
|
||||||
|
await trx
|
||||||
|
.delete(resourceAiModels)
|
||||||
|
.where(eq(resourceAiModels.resourceId, resourceId));
|
||||||
|
await trx
|
||||||
|
.delete(resourceAiProviders)
|
||||||
|
.where(eq(resourceAiProviders.resourceId, resourceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function clearSiteResourceAiConfig(
|
||||||
|
siteResourceId: number,
|
||||||
|
trx: DbOrTrx = db
|
||||||
|
): Promise<void> {
|
||||||
|
await trx
|
||||||
|
.delete(siteResourceAiModels)
|
||||||
|
.where(eq(siteResourceAiModels.siteResourceId, siteResourceId));
|
||||||
|
await trx
|
||||||
|
.delete(siteResourceAiProviders)
|
||||||
|
.where(eq(siteResourceAiProviders.siteResourceId, siteResourceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listPublicResourceAiProviders(resourceId: number) {
|
||||||
|
return db
|
||||||
|
.select({
|
||||||
|
providerId: resourceAiProviders.providerId,
|
||||||
|
niceId: aiProviders.niceId,
|
||||||
|
name: aiProviders.name,
|
||||||
|
type: aiProviders.type,
|
||||||
|
enabled: resourceAiProviders.enabled,
|
||||||
|
providerEnabled: aiProviders.enabled,
|
||||||
|
accessMode: resourceAiProviders.accessMode
|
||||||
|
})
|
||||||
|
.from(resourceAiProviders)
|
||||||
|
.innerJoin(
|
||||||
|
aiProviders,
|
||||||
|
eq(resourceAiProviders.providerId, aiProviders.providerId)
|
||||||
|
)
|
||||||
|
.where(eq(resourceAiProviders.resourceId, resourceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listSiteResourceAiProviders(siteResourceId: number) {
|
||||||
|
return db
|
||||||
|
.select({
|
||||||
|
providerId: siteResourceAiProviders.providerId,
|
||||||
|
niceId: aiProviders.niceId,
|
||||||
|
name: aiProviders.name,
|
||||||
|
type: aiProviders.type,
|
||||||
|
enabled: siteResourceAiProviders.enabled,
|
||||||
|
providerEnabled: aiProviders.enabled,
|
||||||
|
accessMode: siteResourceAiProviders.accessMode
|
||||||
|
})
|
||||||
|
.from(siteResourceAiProviders)
|
||||||
|
.innerJoin(
|
||||||
|
aiProviders,
|
||||||
|
eq(siteResourceAiProviders.providerId, aiProviders.providerId)
|
||||||
|
)
|
||||||
|
.where(eq(siteResourceAiProviders.siteResourceId, siteResourceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EffectiveAllowModel = {
|
||||||
|
modelId: number;
|
||||||
|
modelKey: string;
|
||||||
|
name: string;
|
||||||
|
providerId: number;
|
||||||
|
providerName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function listEffectiveAllowModels(options: {
|
||||||
|
resourceId?: number;
|
||||||
|
siteResourceId?: number;
|
||||||
|
}): Promise<EffectiveAllowModel[]> {
|
||||||
|
if (
|
||||||
|
options.resourceId === undefined &&
|
||||||
|
options.siteResourceId === undefined
|
||||||
|
) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachments =
|
||||||
|
options.resourceId !== undefined
|
||||||
|
? await listPublicResourceAiProviders(options.resourceId)
|
||||||
|
: await listSiteResourceAiProviders(options.siteResourceId!);
|
||||||
|
|
||||||
|
const activeAttachments = attachments.filter(
|
||||||
|
(a) => a.enabled && a.providerEnabled
|
||||||
|
);
|
||||||
|
if (activeAttachments.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const inheritProviderIds = activeAttachments
|
||||||
|
.filter((a) => a.accessMode === "inherit")
|
||||||
|
.map((a) => a.providerId);
|
||||||
|
const selectProviderIds = activeAttachments
|
||||||
|
.filter((a) => a.accessMode === "select")
|
||||||
|
.map((a) => a.providerId);
|
||||||
|
|
||||||
|
const providerNameById = new Map(
|
||||||
|
activeAttachments.map((a) => [a.providerId, a.name] as const)
|
||||||
|
);
|
||||||
|
|
||||||
|
const models: EffectiveAllowModel[] = [];
|
||||||
|
|
||||||
|
if (inheritProviderIds.length > 0) {
|
||||||
|
const rows = await db
|
||||||
|
.select({
|
||||||
|
modelId: aiModels.modelId,
|
||||||
|
modelKey: aiModels.modelKey,
|
||||||
|
name: aiModels.name,
|
||||||
|
providerId: aiModels.providerId
|
||||||
|
})
|
||||||
|
.from(aiModels)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
inArray(aiModels.providerId, inheritProviderIds),
|
||||||
|
eq(aiModels.enabled, true),
|
||||||
|
eq(aiModels.listType, "allow")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
for (const row of rows) {
|
||||||
|
models.push({
|
||||||
|
...row,
|
||||||
|
providerName: providerNameById.get(row.providerId) ?? ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectProviderIds.length > 0) {
|
||||||
|
if (options.resourceId !== undefined) {
|
||||||
|
const rows = await db
|
||||||
|
.select({
|
||||||
|
modelId: aiModels.modelId,
|
||||||
|
modelKey: aiModels.modelKey,
|
||||||
|
name: aiModels.name,
|
||||||
|
providerId: aiModels.providerId
|
||||||
|
})
|
||||||
|
.from(resourceAiModels)
|
||||||
|
.innerJoin(
|
||||||
|
aiModels,
|
||||||
|
eq(resourceAiModels.modelId, aiModels.modelId)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(resourceAiModels.resourceId, options.resourceId),
|
||||||
|
inArray(aiModels.providerId, selectProviderIds),
|
||||||
|
eq(resourceAiModels.listType, "allow"),
|
||||||
|
eq(aiModels.enabled, true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
for (const row of rows) {
|
||||||
|
models.push({
|
||||||
|
...row,
|
||||||
|
providerName: providerNameById.get(row.providerId) ?? ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (options.siteResourceId !== undefined) {
|
||||||
|
const rows = await db
|
||||||
|
.select({
|
||||||
|
modelId: aiModels.modelId,
|
||||||
|
modelKey: aiModels.modelKey,
|
||||||
|
name: aiModels.name,
|
||||||
|
providerId: aiModels.providerId
|
||||||
|
})
|
||||||
|
.from(siteResourceAiModels)
|
||||||
|
.innerJoin(
|
||||||
|
aiModels,
|
||||||
|
eq(siteResourceAiModels.modelId, aiModels.modelId)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(
|
||||||
|
siteResourceAiModels.siteResourceId,
|
||||||
|
options.siteResourceId
|
||||||
|
),
|
||||||
|
inArray(aiModels.providerId, selectProviderIds),
|
||||||
|
eq(siteResourceAiModels.listType, "allow"),
|
||||||
|
eq(aiModels.enabled, true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
for (const row of rows) {
|
||||||
|
models.push({
|
||||||
|
...row,
|
||||||
|
providerName: providerNameById.get(row.providerId) ?? ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
models.sort((a, b) => {
|
||||||
|
const byProvider = a.providerName.localeCompare(
|
||||||
|
b.providerName,
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
sensitivity: "base"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (byProvider !== 0) {
|
||||||
|
return byProvider;
|
||||||
|
}
|
||||||
|
return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
|
||||||
|
});
|
||||||
|
|
||||||
|
return models;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model list APIs require an inference resource with at least one select-mode
|
||||||
|
* attached provider.
|
||||||
|
*/
|
||||||
|
export async function assertPublicModelListApiEligible(resource: {
|
||||||
|
resourceId: number;
|
||||||
|
mode: string;
|
||||||
|
}): Promise<string | null> {
|
||||||
|
if (resource.mode !== "inference") {
|
||||||
|
return "AI model lists are only supported on inference-mode resources";
|
||||||
|
}
|
||||||
|
|
||||||
|
const [row] = await db
|
||||||
|
.select({ providerId: resourceAiProviders.providerId })
|
||||||
|
.from(resourceAiProviders)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(resourceAiProviders.resourceId, resource.resourceId),
|
||||||
|
eq(resourceAiProviders.accessMode, "select")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!row) {
|
||||||
|
return "Set at least one attached AI provider to select mode before managing model lists";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function assertSiteModelListApiEligible(siteResource: {
|
||||||
|
siteResourceId: number;
|
||||||
|
mode: string;
|
||||||
|
}): Promise<string | null> {
|
||||||
|
if (siteResource.mode !== "inference") {
|
||||||
|
return "AI model lists are only supported on inference-mode resources";
|
||||||
|
}
|
||||||
|
|
||||||
|
const [row] = await db
|
||||||
|
.select({ providerId: siteResourceAiProviders.providerId })
|
||||||
|
.from(siteResourceAiProviders)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(
|
||||||
|
siteResourceAiProviders.siteResourceId,
|
||||||
|
siteResource.siteResourceId
|
||||||
|
),
|
||||||
|
eq(siteResourceAiProviders.accessMode, "select")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!row) {
|
||||||
|
return "Set at least one attached AI provider to select mode before managing model lists";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource model entries must belong to select-mode attached providers, and
|
||||||
|
* listType must match the provider catalog entry (allow→allow, block→block).
|
||||||
|
*/
|
||||||
|
export async function assertPublicResourceModelEntriesValid(input: {
|
||||||
|
orgId: string;
|
||||||
|
resourceId: number;
|
||||||
|
models: ResourceAiModelEntry[];
|
||||||
|
}): Promise<string | null> {
|
||||||
|
const uniqueModels = dedupeModelEntries(input.models);
|
||||||
|
if (uniqueModels.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachments = await db
|
||||||
|
.select({
|
||||||
|
providerId: resourceAiProviders.providerId,
|
||||||
|
accessMode: resourceAiProviders.accessMode,
|
||||||
|
enabled: resourceAiProviders.enabled
|
||||||
|
})
|
||||||
|
.from(resourceAiProviders)
|
||||||
|
.innerJoin(
|
||||||
|
aiProviders,
|
||||||
|
eq(resourceAiProviders.providerId, aiProviders.providerId)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(resourceAiProviders.resourceId, input.resourceId),
|
||||||
|
eq(aiProviders.orgId, input.orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return assertModelEntriesValid({
|
||||||
|
orgId: input.orgId,
|
||||||
|
modelEntries: uniqueModels,
|
||||||
|
attachments,
|
||||||
|
resourceLabel: "resource"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function assertSiteResourceModelEntriesValid(input: {
|
||||||
|
orgId: string;
|
||||||
|
siteResourceId: number;
|
||||||
|
models: ResourceAiModelEntry[];
|
||||||
|
}): Promise<string | null> {
|
||||||
|
const uniqueModels = dedupeModelEntries(input.models);
|
||||||
|
if (uniqueModels.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachments = await db
|
||||||
|
.select({
|
||||||
|
providerId: siteResourceAiProviders.providerId,
|
||||||
|
accessMode: siteResourceAiProviders.accessMode,
|
||||||
|
enabled: siteResourceAiProviders.enabled
|
||||||
|
})
|
||||||
|
.from(siteResourceAiProviders)
|
||||||
|
.innerJoin(
|
||||||
|
aiProviders,
|
||||||
|
eq(siteResourceAiProviders.providerId, aiProviders.providerId)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(
|
||||||
|
siteResourceAiProviders.siteResourceId,
|
||||||
|
input.siteResourceId
|
||||||
|
),
|
||||||
|
eq(aiProviders.orgId, input.orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return assertModelEntriesValid({
|
||||||
|
orgId: input.orgId,
|
||||||
|
modelEntries: uniqueModels,
|
||||||
|
attachments,
|
||||||
|
resourceLabel: "site resource"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function dedupeModelEntries(
|
||||||
|
models: ResourceAiModelEntry[]
|
||||||
|
): ResourceAiModelEntry[] {
|
||||||
|
const byModelId = new Map(
|
||||||
|
models.map((m) => [m.modelId, m.listType] as const)
|
||||||
|
);
|
||||||
|
return [...byModelId.entries()].map(([modelId, listType]) => ({
|
||||||
|
modelId,
|
||||||
|
listType
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function assertModelEntriesValid(input: {
|
||||||
|
orgId: string;
|
||||||
|
modelEntries: ResourceAiModelEntry[];
|
||||||
|
attachments: ResourceAiProviderAttachment[];
|
||||||
|
resourceLabel: string;
|
||||||
|
}): Promise<string | null> {
|
||||||
|
const selectProviderIds = input.attachments
|
||||||
|
.filter((a) => a.accessMode === "select")
|
||||||
|
.map((a) => a.providerId);
|
||||||
|
|
||||||
|
if (selectProviderIds.length === 0) {
|
||||||
|
return "Set at least one attached AI provider to select mode before managing model lists";
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelIds = input.modelEntries.map((m) => m.modelId);
|
||||||
|
const catalogRows = await db
|
||||||
|
.select({
|
||||||
|
modelId: aiModels.modelId,
|
||||||
|
listType: aiModels.listType,
|
||||||
|
providerId: aiModels.providerId,
|
||||||
|
enabled: aiModels.enabled
|
||||||
|
})
|
||||||
|
.from(aiModels)
|
||||||
|
.innerJoin(aiProviders, eq(aiModels.providerId, aiProviders.providerId))
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
inArray(aiModels.modelId, modelIds),
|
||||||
|
inArray(aiModels.providerId, selectProviderIds),
|
||||||
|
eq(aiProviders.orgId, input.orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (catalogRows.length !== modelIds.length) {
|
||||||
|
return `One or more model IDs do not exist or do not belong to a select-mode provider on this ${input.resourceLabel}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const catalogById = new Map(catalogRows.map((row) => [row.modelId, row]));
|
||||||
|
for (const entry of input.modelEntries) {
|
||||||
|
const catalog = catalogById.get(entry.modelId);
|
||||||
|
if (!catalog) {
|
||||||
|
return `One or more model IDs do not exist or do not belong to a select-mode provider on this ${input.resourceLabel}`;
|
||||||
|
}
|
||||||
|
if (catalog.listType !== entry.listType) {
|
||||||
|
return `Model ${entry.modelId} must use listType "${catalog.listType}" to match the provider catalog entry`;
|
||||||
|
}
|
||||||
|
if (!catalog.enabled) {
|
||||||
|
return `Model ${entry.modelId} is disabled on its provider`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,538 @@
|
|||||||
|
import type { AiCapability } from "@server/lib/aiCapabilities";
|
||||||
|
import { sseDataFrames, tryParseJson } from "@server/lib/aiUsageExtraction";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
|
||||||
|
// Uniform, capability-agnostic representation of a chat message, used so
|
||||||
|
// the AI session log can be searched/displayed the same way regardless of
|
||||||
|
// which provider/capability produced it. Content is flattened to plain text
|
||||||
|
// - non-text parts (images, tool calls/results) are rendered as readable
|
||||||
|
// placeholders rather than preserved as structured data, which is enough for
|
||||||
|
// a transcript-style replay view without a per-capability renderer.
|
||||||
|
export type NormalizedRole = "system" | "user" | "assistant" | "tool";
|
||||||
|
|
||||||
|
export type NormalizedAiMessage = {
|
||||||
|
role: NormalizedRole;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function normalizeRole(role: unknown): NormalizedRole {
|
||||||
|
if (
|
||||||
|
role === "system" ||
|
||||||
|
role === "user" ||
|
||||||
|
role === "assistant" ||
|
||||||
|
role === "tool"
|
||||||
|
) {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
if (role === "model") return "assistant"; // Gemini
|
||||||
|
if (role === "function") return "tool"; // OpenAI legacy function role
|
||||||
|
return "user";
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeJsonStringify(value: unknown): string {
|
||||||
|
try {
|
||||||
|
return JSON.stringify(value ?? {});
|
||||||
|
} catch {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flattens one message "part"/"block" (OpenAI content parts, Anthropic
|
||||||
|
* content blocks, Gemini parts, Bedrock converse content blocks - they all
|
||||||
|
* follow the same rough shape) into readable text.
|
||||||
|
*/
|
||||||
|
function flattenContentPart(part: unknown): string {
|
||||||
|
if (typeof part === "string") return part;
|
||||||
|
if (part == null || typeof part !== "object") return "";
|
||||||
|
const p = part as Record<string, unknown>;
|
||||||
|
|
||||||
|
if (typeof p.text === "string") return p.text;
|
||||||
|
|
||||||
|
if (
|
||||||
|
p.type === "image_url" ||
|
||||||
|
p.type === "image" ||
|
||||||
|
p.type === "input_image" ||
|
||||||
|
p.type === "output_image" ||
|
||||||
|
"inlineData" in p
|
||||||
|
) {
|
||||||
|
return "[image]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anthropic-style tool_use / tool_result blocks
|
||||||
|
if (p.type === "tool_use") {
|
||||||
|
const name = typeof p.name === "string" ? p.name : "tool";
|
||||||
|
return `[tool_call: ${name}(${safeJsonStringify(p.input)})]`;
|
||||||
|
}
|
||||||
|
if (p.type === "tool_result") {
|
||||||
|
const content = p.content;
|
||||||
|
const text =
|
||||||
|
typeof content === "string"
|
||||||
|
? content
|
||||||
|
: Array.isArray(content)
|
||||||
|
? flattenContentParts(content)
|
||||||
|
: "";
|
||||||
|
return `[tool_result: ${text}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gemini-style functionCall / functionResponse parts
|
||||||
|
if (p.functionCall && typeof p.functionCall === "object") {
|
||||||
|
const fc = p.functionCall as Record<string, unknown>;
|
||||||
|
return `[tool_call: ${fc.name}(${safeJsonStringify(fc.args)})]`;
|
||||||
|
}
|
||||||
|
if (p.functionResponse && typeof p.functionResponse === "object") {
|
||||||
|
const fr = p.functionResponse as Record<string, unknown>;
|
||||||
|
return `[tool_result: ${fr.name}(${safeJsonStringify(fr.response)})]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bedrock converse-style toolUse / toolResult content blocks
|
||||||
|
if (p.toolUse && typeof p.toolUse === "object") {
|
||||||
|
const tu = p.toolUse as Record<string, unknown>;
|
||||||
|
return `[tool_call: ${tu.name}(${safeJsonStringify(tu.input)})]`;
|
||||||
|
}
|
||||||
|
if (p.toolResult && typeof p.toolResult === "object") {
|
||||||
|
const tr = p.toolResult as Record<string, unknown>;
|
||||||
|
const content = tr.content;
|
||||||
|
const text = Array.isArray(content) ? flattenContentParts(content) : "";
|
||||||
|
return `[tool_result: ${text}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenContentParts(parts: unknown[]): string {
|
||||||
|
return parts.map(flattenContentPart).join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenContent(content: unknown): string {
|
||||||
|
if (typeof content === "string") return content;
|
||||||
|
if (Array.isArray(content)) return flattenContentParts(content);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Best-effort scan for every `"text":"..."` JSON string value in raw text,
|
||||||
|
* concatenated in order. Fallback for streaming formats we can't fully parse
|
||||||
|
* as JSON/SSE (Gemini's array-JSON stream, Bedrock's binary event-stream
|
||||||
|
* framing) - same spirit as aiUsageExtraction's scanNumericFields.
|
||||||
|
*/
|
||||||
|
function scanTextFragments(text: string): string {
|
||||||
|
const out: string[] = [];
|
||||||
|
const re = /"text"\s*:\s*"((?:[^"\\]|\\.)*)"/g;
|
||||||
|
let match: RegExpExecArray | null;
|
||||||
|
while ((match = re.exec(text)) !== null) {
|
||||||
|
try {
|
||||||
|
out.push(JSON.parse(`"${match[1]}"`));
|
||||||
|
} catch {
|
||||||
|
out.push(match[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Request (input) normalizers - operate on the already-parsed outbound body.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function normalizeOpenAiChatRequest(body: any): NormalizedAiMessage[] {
|
||||||
|
const messages = Array.isArray(body?.messages) ? body.messages : [];
|
||||||
|
return messages.map((m: any) => ({
|
||||||
|
role: normalizeRole(m?.role),
|
||||||
|
content: flattenContent(m?.content)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeOpenAiResponsesRequest(body: any): NormalizedAiMessage[] {
|
||||||
|
const out: NormalizedAiMessage[] = [];
|
||||||
|
if (typeof body?.instructions === "string" && body.instructions) {
|
||||||
|
out.push({ role: "system", content: body.instructions });
|
||||||
|
}
|
||||||
|
const input = body?.input;
|
||||||
|
if (typeof input === "string") {
|
||||||
|
out.push({ role: "user", content: input });
|
||||||
|
} else if (Array.isArray(input)) {
|
||||||
|
for (const item of input) {
|
||||||
|
if (item?.role) {
|
||||||
|
out.push({
|
||||||
|
role: normalizeRole(item.role),
|
||||||
|
content: flattenContent(item.content)
|
||||||
|
});
|
||||||
|
} else if (typeof item?.type === "string") {
|
||||||
|
out.push({ role: "tool", content: `[${item.type}]` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAnthropicRequest(body: any): NormalizedAiMessage[] {
|
||||||
|
const out: NormalizedAiMessage[] = [];
|
||||||
|
if (body?.system) {
|
||||||
|
const sys = flattenContent(body.system);
|
||||||
|
if (sys) out.push({ role: "system", content: sys });
|
||||||
|
}
|
||||||
|
const messages = Array.isArray(body?.messages) ? body.messages : [];
|
||||||
|
for (const m of messages) {
|
||||||
|
out.push({
|
||||||
|
role: normalizeRole(m?.role),
|
||||||
|
content: flattenContent(m?.content)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeGeminiRequest(body: any): NormalizedAiMessage[] {
|
||||||
|
const out: NormalizedAiMessage[] = [];
|
||||||
|
const sysParts = body?.systemInstruction?.parts;
|
||||||
|
if (Array.isArray(sysParts)) {
|
||||||
|
const text = flattenContentParts(sysParts);
|
||||||
|
if (text) out.push({ role: "system", content: text });
|
||||||
|
}
|
||||||
|
const contents = Array.isArray(body?.contents) ? body.contents : [];
|
||||||
|
for (const c of contents) {
|
||||||
|
out.push({
|
||||||
|
role: normalizeRole(c?.role),
|
||||||
|
content: Array.isArray(c?.parts) ? flattenContentParts(c.parts) : ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeBedrockConverseRequest(body: any): NormalizedAiMessage[] {
|
||||||
|
const out: NormalizedAiMessage[] = [];
|
||||||
|
if (Array.isArray(body?.system)) {
|
||||||
|
const text = flattenContentParts(body.system);
|
||||||
|
if (text) out.push({ role: "system", content: text });
|
||||||
|
}
|
||||||
|
const messages = Array.isArray(body?.messages) ? body.messages : [];
|
||||||
|
for (const m of messages) {
|
||||||
|
out.push({
|
||||||
|
role: normalizeRole(m?.role),
|
||||||
|
content: Array.isArray(m?.content)
|
||||||
|
? flattenContentParts(m.content)
|
||||||
|
: ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bedrock_model_invoke and google_raw_predict are passthroughs - the body
|
||||||
|
* shape depends entirely on the underlying model, not the capability. Try
|
||||||
|
* the two shapes we're most likely to see (Anthropic Claude, then plain
|
||||||
|
* OpenAI-style) and give up otherwise, same fallback spirit
|
||||||
|
* aiUsageExtraction.ts uses for these two capabilities' usage extraction.
|
||||||
|
*/
|
||||||
|
function normalizeBestEffortRequest(body: any): NormalizedAiMessage[] | null {
|
||||||
|
if (!Array.isArray(body?.messages)) return null;
|
||||||
|
const looksAnthropicShaped = body.messages.some((m: any) =>
|
||||||
|
Array.isArray(m?.content)
|
||||||
|
);
|
||||||
|
return looksAnthropicShaped
|
||||||
|
? normalizeAnthropicRequest(body)
|
||||||
|
: normalizeOpenAiChatRequest(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Response (output) normalizers - operate on the raw response text, which
|
||||||
|
// may be a single JSON document (non-streaming) or provider-framed streaming
|
||||||
|
// text (SSE `data:` frames, a JSON-array stream, or binary event-stream
|
||||||
|
// framing with JSON payloads embedded in it).
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function normalizeOpenAiChatResponse(
|
||||||
|
text: string,
|
||||||
|
isStream: boolean
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
if (isStream) {
|
||||||
|
let role: unknown = "assistant";
|
||||||
|
let content = "";
|
||||||
|
let found = false;
|
||||||
|
for (const frame of sseDataFrames(text)) {
|
||||||
|
const delta = tryParseJson(frame)?.choices?.[0]?.delta;
|
||||||
|
if (!delta) continue;
|
||||||
|
found = true;
|
||||||
|
if (typeof delta.role === "string") role = delta.role;
|
||||||
|
if (typeof delta.content === "string") content += delta.content;
|
||||||
|
}
|
||||||
|
return found ? [{ role: normalizeRole(role), content }] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = tryParseJson(text)?.choices?.[0]?.message;
|
||||||
|
if (!message) return null;
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
role: normalizeRole(message.role),
|
||||||
|
content: flattenContent(message.content)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractOpenAiResponsesOutputText(response: any): string | null {
|
||||||
|
if (typeof response?.output_text === "string") return response.output_text;
|
||||||
|
const output = Array.isArray(response?.output) ? response.output : [];
|
||||||
|
const pieces: string[] = [];
|
||||||
|
for (const item of output) {
|
||||||
|
if (item?.type === "message" && Array.isArray(item.content)) {
|
||||||
|
pieces.push(flattenContentParts(item.content));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pieces.length > 0 ? pieces.join("") : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeOpenAiResponsesResponse(
|
||||||
|
text: string,
|
||||||
|
isStream: boolean
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
if (isStream) {
|
||||||
|
let content = "";
|
||||||
|
let found = false;
|
||||||
|
for (const frame of sseDataFrames(text)) {
|
||||||
|
const parsed = tryParseJson(frame);
|
||||||
|
if (!parsed) continue;
|
||||||
|
if (
|
||||||
|
parsed.type === "response.output_text.delta" &&
|
||||||
|
typeof parsed.delta === "string"
|
||||||
|
) {
|
||||||
|
content += parsed.delta;
|
||||||
|
found = true;
|
||||||
|
} else if (
|
||||||
|
parsed.type === "response.completed" &&
|
||||||
|
parsed.response
|
||||||
|
) {
|
||||||
|
const outputText = extractOpenAiResponsesOutputText(
|
||||||
|
parsed.response
|
||||||
|
);
|
||||||
|
if (outputText != null) {
|
||||||
|
content = outputText;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found ? [{ role: "assistant", content }] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = tryParseJson(text);
|
||||||
|
const outputText = extractOpenAiResponsesOutputText(
|
||||||
|
parsed?.response ?? parsed
|
||||||
|
);
|
||||||
|
return outputText != null
|
||||||
|
? [{ role: "assistant", content: outputText }]
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAnthropicResponse(
|
||||||
|
text: string,
|
||||||
|
isStream: boolean
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
if (isStream) {
|
||||||
|
let role: unknown = "assistant";
|
||||||
|
let content = "";
|
||||||
|
let found = false;
|
||||||
|
for (const frame of sseDataFrames(text)) {
|
||||||
|
const parsed = tryParseJson(frame);
|
||||||
|
if (!parsed) continue;
|
||||||
|
if (parsed.type === "message_start" && parsed.message?.role) {
|
||||||
|
role = parsed.message.role;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
parsed.type === "content_block_start" &&
|
||||||
|
parsed.content_block?.type === "tool_use"
|
||||||
|
) {
|
||||||
|
const name = parsed.content_block.name ?? "tool";
|
||||||
|
content += `[tool_call: ${name}]`;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
parsed.type === "content_block_delta" &&
|
||||||
|
typeof parsed.delta?.text === "string"
|
||||||
|
) {
|
||||||
|
content += parsed.delta.text;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found ? [{ role: normalizeRole(role), content }] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = tryParseJson(text);
|
||||||
|
if (!parsed || !Array.isArray(parsed.content)) return null;
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
role: normalizeRole(parsed.role ?? "assistant"),
|
||||||
|
content: flattenContentParts(parsed.content)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function geminiCandidateParts(node: any): string {
|
||||||
|
const parts = node?.candidates?.[0]?.content?.parts;
|
||||||
|
return Array.isArray(parts) ? flattenContentParts(parts) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeGeminiResponse(
|
||||||
|
text: string,
|
||||||
|
_isStream: boolean
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
const frames = sseDataFrames(text);
|
||||||
|
let content = "";
|
||||||
|
let role: unknown = "model";
|
||||||
|
let found = false;
|
||||||
|
|
||||||
|
if (frames.length > 0) {
|
||||||
|
for (const frame of frames) {
|
||||||
|
const parsed = tryParseJson(frame);
|
||||||
|
const piece = geminiCandidateParts(parsed);
|
||||||
|
if (piece) {
|
||||||
|
content += piece;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
const r = parsed?.candidates?.[0]?.content?.role;
|
||||||
|
if (r) role = r;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const parsed = tryParseJson(text);
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
for (const chunk of parsed) {
|
||||||
|
const piece = geminiCandidateParts(chunk);
|
||||||
|
if (piece) {
|
||||||
|
content += piece;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
const r = chunk?.candidates?.[0]?.content?.role;
|
||||||
|
if (r) role = r;
|
||||||
|
}
|
||||||
|
} else if (parsed) {
|
||||||
|
const piece = geminiCandidateParts(parsed);
|
||||||
|
if (piece) {
|
||||||
|
content = piece;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
const r = parsed?.candidates?.[0]?.content?.role;
|
||||||
|
if (r) role = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
const scanned = scanTextFragments(text);
|
||||||
|
return scanned
|
||||||
|
? [{ role: normalizeRole(role), content: scanned }]
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
return [{ role: normalizeRole(role), content }];
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeBedrockConverseResponse(
|
||||||
|
text: string,
|
||||||
|
isStream: boolean
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
if (!isStream) {
|
||||||
|
const message = tryParseJson(text)?.output?.message;
|
||||||
|
if (!message) return null;
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
role: normalizeRole(message.role ?? "assistant"),
|
||||||
|
content: Array.isArray(message.content)
|
||||||
|
? flattenContentParts(message.content)
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// converse-stream uses AWS's binary event-stream framing, but the JSON
|
||||||
|
// payload of each event survives intact inside it (same assumption
|
||||||
|
// aiUsageExtraction.ts makes for usage) - scan for the text pieces.
|
||||||
|
const scanned = scanTextFragments(text);
|
||||||
|
return scanned ? [{ role: "assistant", content: scanned }] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeBedrockModelInvokeResponse(
|
||||||
|
text: string,
|
||||||
|
isStream: boolean
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
const anthropicStyle = normalizeAnthropicResponse(text, isStream);
|
||||||
|
if (anthropicStyle) return anthropicStyle;
|
||||||
|
const scanned = scanTextFragments(text);
|
||||||
|
return scanned ? [{ role: "assistant", content: scanned }] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeGoogleRawPredictResponse(
|
||||||
|
text: string,
|
||||||
|
isStream: boolean
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
const anthropicStyle = normalizeAnthropicResponse(text, isStream);
|
||||||
|
if (anthropicStyle) return anthropicStyle;
|
||||||
|
const scanned = scanTextFragments(text);
|
||||||
|
return scanned ? [{ role: "assistant", content: scanned }] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const REQUEST_NORMALIZERS: Record<
|
||||||
|
AiCapability,
|
||||||
|
(body: any) => NormalizedAiMessage[] | null
|
||||||
|
> = {
|
||||||
|
openai_chat: normalizeOpenAiChatRequest,
|
||||||
|
openai_responses: normalizeOpenAiResponsesRequest,
|
||||||
|
anthropic_messages: normalizeAnthropicRequest,
|
||||||
|
gemini_generate_content: normalizeGeminiRequest,
|
||||||
|
google_generate_content: normalizeGeminiRequest,
|
||||||
|
google_raw_predict: normalizeBestEffortRequest,
|
||||||
|
bedrock_model_invoke: normalizeBestEffortRequest,
|
||||||
|
bedrock_converse: normalizeBedrockConverseRequest
|
||||||
|
};
|
||||||
|
|
||||||
|
const RESPONSE_NORMALIZERS: Record<
|
||||||
|
AiCapability,
|
||||||
|
(text: string, isStream: boolean) => NormalizedAiMessage[] | null
|
||||||
|
> = {
|
||||||
|
openai_chat: normalizeOpenAiChatResponse,
|
||||||
|
openai_responses: normalizeOpenAiResponsesResponse,
|
||||||
|
anthropic_messages: normalizeAnthropicResponse,
|
||||||
|
gemini_generate_content: normalizeGeminiResponse,
|
||||||
|
google_generate_content: normalizeGeminiResponse,
|
||||||
|
google_raw_predict: normalizeGoogleRawPredictResponse,
|
||||||
|
bedrock_model_invoke: normalizeBedrockModelInvokeResponse,
|
||||||
|
bedrock_converse: normalizeBedrockConverseResponse
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes an outbound AI gateway request body into a uniform message
|
||||||
|
* transcript, regardless of capability/provider. Returns null if the body
|
||||||
|
* doesn't contain any recognizable messages (or parsing failed) - callers
|
||||||
|
* should fall back to showing the raw request body.
|
||||||
|
*/
|
||||||
|
export function normalizeAiRequest(
|
||||||
|
capability: AiCapability,
|
||||||
|
body: unknown
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
try {
|
||||||
|
const result = REQUEST_NORMALIZERS[capability](body);
|
||||||
|
return result && result.length > 0 ? result : null;
|
||||||
|
} catch (error) {
|
||||||
|
logger.debug("Failed to normalize AI request messages", {
|
||||||
|
capability,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a completed (non-streaming or fully-accumulated streaming) AI
|
||||||
|
* gateway response into a uniform message transcript. Returns null if
|
||||||
|
* nothing recognizable could be extracted - callers should fall back to
|
||||||
|
* showing the raw response body.
|
||||||
|
*/
|
||||||
|
export function normalizeAiResponse(
|
||||||
|
capability: AiCapability,
|
||||||
|
responseText: string,
|
||||||
|
isStream: boolean
|
||||||
|
): NormalizedAiMessage[] | null {
|
||||||
|
try {
|
||||||
|
const result = RESPONSE_NORMALIZERS[capability](responseText, isStream);
|
||||||
|
return result && result.length > 0 ? result : null;
|
||||||
|
} catch (error) {
|
||||||
|
logger.debug("Failed to normalize AI response messages", {
|
||||||
|
capability,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
import fs from "node:fs";
|
||||||
|
import axios from "axios";
|
||||||
|
import { z } from "zod";
|
||||||
|
import config from "@server/lib/config";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import type { AiProviderType } from "@server/lib/aiProviderDefaults";
|
||||||
|
|
||||||
|
export const CATALOG_PROVIDERS = [
|
||||||
|
"openai",
|
||||||
|
"anthropic",
|
||||||
|
"gemini",
|
||||||
|
"vertex",
|
||||||
|
"azure",
|
||||||
|
"bedrock"
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type CatalogProvider = (typeof CATALOG_PROVIDERS)[number];
|
||||||
|
|
||||||
|
const CATALOG_PROVIDER_SET = new Set<string>(CATALOG_PROVIDERS);
|
||||||
|
|
||||||
|
// Each of our provider types maps to at most one catalog provider. Provider
|
||||||
|
// types that proxy arbitrary underlying models (openRouter, vercelAiGateway,
|
||||||
|
// custom) have no mapping.
|
||||||
|
const PROVIDER_CATALOG_MAP: Record<
|
||||||
|
Exclude<AiProviderType, "custom">,
|
||||||
|
CatalogProvider | null
|
||||||
|
> = {
|
||||||
|
openai: "openai",
|
||||||
|
anthropic: "anthropic",
|
||||||
|
googleGemini: "gemini",
|
||||||
|
vertexAi: "vertex",
|
||||||
|
bedrock: "bedrock",
|
||||||
|
microsoftFoundry: "azure",
|
||||||
|
openRouter: null,
|
||||||
|
vercelAiGateway: null
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getCatalogProviderForType(
|
||||||
|
type: AiProviderType
|
||||||
|
): CatalogProvider | null {
|
||||||
|
if (type === "custom") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return PROVIDER_CATALOG_MAP[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AiModelCatalogEntry = {
|
||||||
|
provider: CatalogProvider;
|
||||||
|
model: string;
|
||||||
|
pricing: {
|
||||||
|
in: number | null;
|
||||||
|
out: number | null;
|
||||||
|
cache: number | null;
|
||||||
|
reasoning: number | null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const catalogEntrySchema = z.object({
|
||||||
|
model: z.string(),
|
||||||
|
provider: z.string(),
|
||||||
|
pricing: z
|
||||||
|
.object({
|
||||||
|
in: z.number().nullable().optional(),
|
||||||
|
out: z.number().nullable().optional(),
|
||||||
|
cache: z.number().nullable().optional(),
|
||||||
|
reasoning: z.number().nullable().optional()
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
const catalogFileSchema = z.object({
|
||||||
|
data: z.array(catalogEntrySchema).optional().default([])
|
||||||
|
});
|
||||||
|
|
||||||
|
type RawCatalogEntry = z.infer<typeof catalogEntrySchema>;
|
||||||
|
|
||||||
|
function normalizeCatalogProvider(raw: string): CatalogProvider | null {
|
||||||
|
if (CATALOG_PROVIDER_SET.has(raw)) {
|
||||||
|
return raw as CatalogProvider;
|
||||||
|
}
|
||||||
|
if (raw.startsWith("bedrock")) {
|
||||||
|
return "bedrock";
|
||||||
|
}
|
||||||
|
if (raw.startsWith("vertex")) {
|
||||||
|
return "vertex";
|
||||||
|
}
|
||||||
|
if (raw.startsWith("azure")) {
|
||||||
|
return "azure";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeEntry(raw: RawCatalogEntry): AiModelCatalogEntry | null {
|
||||||
|
const provider = normalizeCatalogProvider(raw.provider);
|
||||||
|
if (!provider) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!raw.model) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
provider,
|
||||||
|
model: raw.model,
|
||||||
|
pricing: {
|
||||||
|
in: raw.pricing?.in ?? null,
|
||||||
|
out: raw.pricing?.out ?? null,
|
||||||
|
cache: raw.pricing?.cache ?? null,
|
||||||
|
reasoning: raw.pricing?.reasoning ?? null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function providerKey(provider: CatalogProvider, key: string): string {
|
||||||
|
return `${provider}\0${key}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AiModelCatalog {
|
||||||
|
private entries: AiModelCatalogEntry[] = [];
|
||||||
|
private byProvider = new Map<CatalogProvider, AiModelCatalogEntry[]>();
|
||||||
|
private byProviderAndKey = new Map<string, AiModelCatalogEntry>();
|
||||||
|
private byKey = new Map<string, AiModelCatalogEntry[]>();
|
||||||
|
private refreshTimer: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the catalog into memory and schedules periodic background refreshes.
|
||||||
|
* Call once at server startup.
|
||||||
|
*/
|
||||||
|
async init(): Promise<void> {
|
||||||
|
await this.refresh();
|
||||||
|
this.scheduleNextRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Exact lookup by catalog provider and model key. */
|
||||||
|
get(
|
||||||
|
provider: CatalogProvider,
|
||||||
|
key: string
|
||||||
|
): AiModelCatalogEntry | undefined {
|
||||||
|
return this.byProviderAndKey.get(providerKey(provider, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** All models for a catalog provider. */
|
||||||
|
list(provider: CatalogProvider): AiModelCatalogEntry[] {
|
||||||
|
return this.byProvider.get(provider) ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** All catalog entries that share a model key, across providers. */
|
||||||
|
listByKey(key: string): AiModelCatalogEntry[] {
|
||||||
|
return this.byKey.get(key) ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Full in-memory catalog. */
|
||||||
|
getAll(): AiModelCatalogEntry[] {
|
||||||
|
return this.entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setEntries(entries: AiModelCatalogEntry[]): void {
|
||||||
|
const byProvider = new Map<CatalogProvider, AiModelCatalogEntry[]>();
|
||||||
|
const byProviderAndKey = new Map<string, AiModelCatalogEntry>();
|
||||||
|
const byKey = new Map<string, AiModelCatalogEntry[]>();
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const list = byProvider.get(entry.provider) ?? [];
|
||||||
|
list.push(entry);
|
||||||
|
byProvider.set(entry.provider, list);
|
||||||
|
|
||||||
|
const mapKey = providerKey(entry.provider, entry.model);
|
||||||
|
if (!byProviderAndKey.has(mapKey)) {
|
||||||
|
byProviderAndKey.set(mapKey, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyList = byKey.get(entry.model) ?? [];
|
||||||
|
keyList.push(entry);
|
||||||
|
byKey.set(entry.model, keyList);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entries = entries;
|
||||||
|
this.byProvider = byProvider;
|
||||||
|
this.byProviderAndKey = byProviderAndKey;
|
||||||
|
this.byKey = byKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchFromFile(
|
||||||
|
filePath: string
|
||||||
|
): Promise<AiModelCatalogEntry[] | null> {
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
logger.warn(
|
||||||
|
`AI model catalog file not found at ${filePath}; cost calculation will fall back to unknown pricing`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const raw = fs.readFileSync(filePath, "utf-8");
|
||||||
|
const result = catalogFileSchema.safeParse(JSON.parse(raw));
|
||||||
|
if (!result.success) {
|
||||||
|
logger.warn(
|
||||||
|
`AI model catalog file at ${filePath} failed validation: ${result.error.message}`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return result.data.data
|
||||||
|
.map(normalizeEntry)
|
||||||
|
.filter((e): e is AiModelCatalogEntry => e != null);
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn("Failed to read AI model catalog file", { error });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchFromUpstream(
|
||||||
|
upstreamUrl: string
|
||||||
|
): Promise<AiModelCatalogEntry[] | null> {
|
||||||
|
try {
|
||||||
|
const res = await axios.get(upstreamUrl, { timeout: 15_000 });
|
||||||
|
const result = catalogFileSchema.safeParse(res.data);
|
||||||
|
if (!result.success) {
|
||||||
|
logger.warn(
|
||||||
|
`AI model catalog response from ${upstreamUrl} failed validation: ${result.error.message}`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return result.data.data
|
||||||
|
.map(normalizeEntry)
|
||||||
|
.filter((e): e is AiModelCatalogEntry => e != null);
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.warn(
|
||||||
|
`Failed to fetch AI model catalog from ${upstreamUrl}: ${error.message || error}`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async refresh(): Promise<void> {
|
||||||
|
const { file, merge_file, upstream_url } =
|
||||||
|
config.getRawConfig().ai.model_catalog;
|
||||||
|
|
||||||
|
const fetched = file
|
||||||
|
? await this.fetchFromFile(file)
|
||||||
|
: await this.fetchFromUpstream(upstream_url);
|
||||||
|
|
||||||
|
if (!fetched) {
|
||||||
|
logger.debug(
|
||||||
|
"AI model catalog refresh failed; keeping previously loaded catalog in memory"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let merged = fetched;
|
||||||
|
if (merge_file) {
|
||||||
|
const mergeEntries = await this.fetchFromFile(merge_file);
|
||||||
|
if (mergeEntries) {
|
||||||
|
// Entries from the base catalog take precedence; the merge
|
||||||
|
// file only adds models not already present.
|
||||||
|
merged = [...fetched, ...mergeEntries];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setEntries(merged);
|
||||||
|
logger.debug(
|
||||||
|
`AI model catalog refreshed: ${this.entries.length} models loaded`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private scheduleNextRefresh(): void {
|
||||||
|
const { refresh_interval_min_hours, refresh_interval_max_hours } =
|
||||||
|
config.getRawConfig().ai.model_catalog;
|
||||||
|
|
||||||
|
// Jittered rather than fixed so that many self-hosted instances don't
|
||||||
|
// all hit the upstream catalog endpoint at the same moment.
|
||||||
|
const minMs = refresh_interval_min_hours * 60 * 60 * 1000;
|
||||||
|
const maxMs = refresh_interval_max_hours * 60 * 60 * 1000;
|
||||||
|
const delayMs = minMs + Math.random() * Math.max(0, maxMs - minMs);
|
||||||
|
|
||||||
|
if (this.refreshTimer) {
|
||||||
|
clearTimeout(this.refreshTimer);
|
||||||
|
}
|
||||||
|
this.refreshTimer = setTimeout(async () => {
|
||||||
|
await this.refresh();
|
||||||
|
this.scheduleNextRefresh();
|
||||||
|
}, delayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const aiModelCatalog = new AiModelCatalog();
|
||||||
|
|
||||||
|
export function listCatalogModelsForType(
|
||||||
|
type: AiProviderType,
|
||||||
|
query?: string
|
||||||
|
): { model: string }[] {
|
||||||
|
const catalogProvider = getCatalogProviderForType(type);
|
||||||
|
|
||||||
|
let models = catalogProvider
|
||||||
|
? aiModelCatalog.list(catalogProvider).map((entry) => ({
|
||||||
|
model: entry.model
|
||||||
|
}))
|
||||||
|
: [];
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
const q = query.toLowerCase();
|
||||||
|
models = models.filter((m) => m.model.toLowerCase().includes(q));
|
||||||
|
}
|
||||||
|
|
||||||
|
const seen = new Set<string>();
|
||||||
|
models = models.filter((m) => {
|
||||||
|
if (seen.has(m.model)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seen.add(m.model);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
models.sort((a, b) => a.model.localeCompare(b.model));
|
||||||
|
return models;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the AI model pricing catalog into memory and schedules periodic
|
||||||
|
* background refreshes. Call once at server startup.
|
||||||
|
*/
|
||||||
|
export async function initAiModelCatalog(): Promise<void> {
|
||||||
|
await aiModelCatalog.init();
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
const modelKeyRegexCache = new Map<string, RegExp>();
|
||||||
|
|
||||||
|
export function isModelKeyPattern(key: string): boolean {
|
||||||
|
return key.includes("*") || key.includes("?");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getModelKeyRegex(pattern: string): RegExp {
|
||||||
|
let regex = modelKeyRegexCache.get(pattern);
|
||||||
|
if (!regex) {
|
||||||
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
||||||
|
regex = new RegExp(
|
||||||
|
`^${escaped.replace(/\*/g, ".*").replace(/\?/g, ".")}$`
|
||||||
|
);
|
||||||
|
modelKeyRegexCache.set(pattern, regex);
|
||||||
|
}
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function modelKeyMatches(
|
||||||
|
pattern: string,
|
||||||
|
requestedModel: string
|
||||||
|
): boolean {
|
||||||
|
return getModelKeyRegex(pattern).test(requestedModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wildcardCharCount(key: string): number {
|
||||||
|
let count = 0;
|
||||||
|
for (const char of key) {
|
||||||
|
if (char === "*" || char === "?") {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function literalLength(key: string): number {
|
||||||
|
return key.replace(/[*?]/g, "").length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort comparator: more specific patterns sort before less specific ones
|
||||||
|
* (negative when `a` is more specific than `b`).
|
||||||
|
*
|
||||||
|
* 1. Exact keys beat patterns
|
||||||
|
* 2. Fewer wildcard characters win
|
||||||
|
* 3. Longer literal length wins
|
||||||
|
*/
|
||||||
|
export function compareModelKeySpecificity(a: string, b: string): number {
|
||||||
|
const aIsPattern = isModelKeyPattern(a);
|
||||||
|
const bIsPattern = isModelKeyPattern(b);
|
||||||
|
|
||||||
|
if (aIsPattern !== bIsPattern) {
|
||||||
|
return aIsPattern ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wildcardDiff = wildcardCharCount(a) - wildcardCharCount(b);
|
||||||
|
if (wildcardDiff !== 0) {
|
||||||
|
return wildcardDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return literalLength(b) - literalLength(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider-layer policy: empty allowlist denies all. Blocklist only applies
|
||||||
|
* after an allow match.
|
||||||
|
*/
|
||||||
|
export function isAllowedByLists(
|
||||||
|
requested: string,
|
||||||
|
allows: string[],
|
||||||
|
blocks: string[]
|
||||||
|
): boolean {
|
||||||
|
if (allows.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!allows.some((pattern) => modelKeyMatches(pattern, requested))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (blocks.some((pattern) => modelKeyMatches(pattern, requested))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Among allow patterns that match `requested`, return the most specific one,
|
||||||
|
* or null if none match.
|
||||||
|
*/
|
||||||
|
export function mostSpecificMatchingAllow(
|
||||||
|
requested: string,
|
||||||
|
allows: string[]
|
||||||
|
): string | null {
|
||||||
|
const matching = allows.filter((pattern) =>
|
||||||
|
modelKeyMatches(pattern, requested)
|
||||||
|
);
|
||||||
|
if (matching.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
matching.sort(compareModelKeySpecificity);
|
||||||
|
return matching[0];
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import type { AiProviderType } from "@server/lib/aiProviderDefaults";
|
||||||
|
import type { AiUsage } from "@server/lib/aiUsageExtraction";
|
||||||
|
import {
|
||||||
|
aiModelCatalog,
|
||||||
|
getCatalogProviderForType,
|
||||||
|
type AiModelCatalogEntry,
|
||||||
|
type CatalogProvider
|
||||||
|
} from "@server/lib/aiModelCatalog";
|
||||||
|
|
||||||
|
export type AiModelPricing = {
|
||||||
|
inputCostPerToken: number | null;
|
||||||
|
outputCostPerToken: number | null;
|
||||||
|
cacheReadInputTokenCost: number | null;
|
||||||
|
outputCostPerReasoningToken: number | null;
|
||||||
|
// True when the match came from a different catalog provider than the
|
||||||
|
// one mapped to this provider's type (e.g. an openRouter/custom model
|
||||||
|
// id that only matched a global search across every provider). Costs
|
||||||
|
// found this way are a best-effort approximation, not a guarantee the
|
||||||
|
// upstream provider bills at the same rate.
|
||||||
|
approximate: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function stripVendorPrefix(modelId: string): string | null {
|
||||||
|
const idx = modelId.indexOf("/");
|
||||||
|
if (idx === -1 || idx === modelId.length - 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return modelId.slice(idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toPricing(
|
||||||
|
entry: AiModelCatalogEntry,
|
||||||
|
approximate: boolean
|
||||||
|
): AiModelPricing {
|
||||||
|
return {
|
||||||
|
inputCostPerToken: entry.pricing.in,
|
||||||
|
outputCostPerToken: entry.pricing.out,
|
||||||
|
cacheReadInputTokenCost: entry.pricing.cache,
|
||||||
|
outputCostPerReasoningToken: entry.pricing.reasoning,
|
||||||
|
approximate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function findEntry(
|
||||||
|
modelId: string,
|
||||||
|
provider: CatalogProvider | null
|
||||||
|
): AiModelCatalogEntry | null {
|
||||||
|
const candidates = [modelId, stripVendorPrefix(modelId)].filter(
|
||||||
|
(v): v is string => v != null
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const key of candidates) {
|
||||||
|
if (provider) {
|
||||||
|
const match = aiModelCatalog.get(provider, key);
|
||||||
|
if (match) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = aiModelCatalog.listByKey(key)[0];
|
||||||
|
if (match) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks up per-token pricing for a model, scoped first to the catalog
|
||||||
|
* provider that corresponds to our provider type, then falling back to a
|
||||||
|
* global search across every provider (marked `approximate`) for provider
|
||||||
|
* types that proxy arbitrary underlying models.
|
||||||
|
*/
|
||||||
|
export function getModelPricing(
|
||||||
|
providerType: AiProviderType,
|
||||||
|
modelId: string | undefined
|
||||||
|
): AiModelPricing | null {
|
||||||
|
if (!modelId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const catalogProvider = getCatalogProviderForType(providerType);
|
||||||
|
|
||||||
|
if (catalogProvider) {
|
||||||
|
const scoped = findEntry(modelId, catalogProvider);
|
||||||
|
if (scoped) {
|
||||||
|
return toPricing(scoped, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fallback = findEntry(modelId, null);
|
||||||
|
if (fallback) {
|
||||||
|
return toPricing(fallback, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AiCostBreakdown = {
|
||||||
|
promptCost: number;
|
||||||
|
cacheReadCost: number;
|
||||||
|
cacheWriteCost: number;
|
||||||
|
completionCost: number;
|
||||||
|
reasoningCost: number;
|
||||||
|
totalCost: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a $ cost breakdown for a usage record given a model's pricing.
|
||||||
|
* Cache writes and reasoning tokens fall back to the normal input/output
|
||||||
|
* rate respectively when the catalog has no dedicated rate for them (the
|
||||||
|
* catalog has no cache-write field at all, and only some models report a
|
||||||
|
* distinct reasoning rate).
|
||||||
|
*/
|
||||||
|
export function calculateAiCost(
|
||||||
|
pricing: AiModelPricing | null,
|
||||||
|
usage: AiUsage
|
||||||
|
): AiCostBreakdown | null {
|
||||||
|
if (!pricing) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputRate = pricing.inputCostPerToken ?? 0;
|
||||||
|
const outputRate = pricing.outputCostPerToken ?? 0;
|
||||||
|
const cacheReadRate = pricing.cacheReadInputTokenCost ?? inputRate;
|
||||||
|
const reasoningRate = pricing.outputCostPerReasoningToken ?? outputRate;
|
||||||
|
|
||||||
|
const promptCost = usage.promptTokens * inputRate;
|
||||||
|
const cacheReadCost = usage.cacheReadTokens * cacheReadRate;
|
||||||
|
const cacheWriteCost = usage.cacheWriteTokens * inputRate;
|
||||||
|
const completionCost = usage.completionTokens * outputRate;
|
||||||
|
const reasoningCost = usage.reasoningTokens * reasoningRate;
|
||||||
|
|
||||||
|
return {
|
||||||
|
promptCost,
|
||||||
|
cacheReadCost,
|
||||||
|
cacheWriteCost,
|
||||||
|
completionCost,
|
||||||
|
reasoningCost,
|
||||||
|
totalCost:
|
||||||
|
promptCost +
|
||||||
|
cacheReadCost +
|
||||||
|
cacheWriteCost +
|
||||||
|
completionCost +
|
||||||
|
reasoningCost
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
import { decrypt, encrypt } from "@server/lib/crypto";
|
||||||
|
import {
|
||||||
|
parseCapabilities,
|
||||||
|
type AiCapability
|
||||||
|
} from "@server/lib/aiCapabilities";
|
||||||
|
import { stripVirtualApiKeyAuthHeaders } from "@app/lib/virtualApiKeyFormat";
|
||||||
|
import {
|
||||||
|
AI_PROVIDER_AUTH_TYPES,
|
||||||
|
AI_PROVIDER_DEFAULTS,
|
||||||
|
authTypeRequiresApiKey,
|
||||||
|
defaultsForProviderType,
|
||||||
|
providerRequiresUpstreamUrl,
|
||||||
|
type AiBudgetUnit,
|
||||||
|
type AiProviderAuthType,
|
||||||
|
type AiProviderRoutingMode,
|
||||||
|
type AiProviderType
|
||||||
|
} from "@app/lib/aiProviderDefaults";
|
||||||
|
|
||||||
|
export {
|
||||||
|
AI_PROVIDER_AUTH_TYPES,
|
||||||
|
AI_PROVIDER_DEFAULTS,
|
||||||
|
authTypeRequiresApiKey,
|
||||||
|
defaultsForProviderType,
|
||||||
|
providerRequiresUpstreamUrl,
|
||||||
|
type AiBudgetUnit,
|
||||||
|
type AiProviderAuthType,
|
||||||
|
type AiProviderRoutingMode,
|
||||||
|
type AiProviderType
|
||||||
|
};
|
||||||
|
|
||||||
|
const CONFLICTING_AUTH_HEADERS = [
|
||||||
|
"authorization",
|
||||||
|
"x-api-key",
|
||||||
|
"x-goog-api-key",
|
||||||
|
"cf-aig-authorization"
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export function resolveAiProviderCreateFields(input: {
|
||||||
|
type: AiProviderType;
|
||||||
|
upstreamUrl?: string | null;
|
||||||
|
authType?: AiProviderAuthType | null;
|
||||||
|
routingMode?: AiProviderRoutingMode | null;
|
||||||
|
}): {
|
||||||
|
upstreamUrl: string | null;
|
||||||
|
authType: AiProviderAuthType;
|
||||||
|
routingMode: AiProviderRoutingMode;
|
||||||
|
} {
|
||||||
|
const routingMode =
|
||||||
|
input.type === "custom" ? (input.routingMode ?? "url") : "url";
|
||||||
|
|
||||||
|
if (routingMode === "target") {
|
||||||
|
return {
|
||||||
|
upstreamUrl: null,
|
||||||
|
authType: input.authType ?? "bearer",
|
||||||
|
routingMode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.type === "custom") {
|
||||||
|
return {
|
||||||
|
upstreamUrl: input.upstreamUrl ?? null,
|
||||||
|
authType: input.authType ?? "bearer",
|
||||||
|
routingMode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaults = AI_PROVIDER_DEFAULTS[input.type];
|
||||||
|
return {
|
||||||
|
upstreamUrl: input.upstreamUrl ?? defaults.upstreamUrl,
|
||||||
|
authType: input.authType ?? defaults.authType,
|
||||||
|
routingMode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AiProviderHeader = { name: string; value: string };
|
||||||
|
|
||||||
|
export function serializeAiProviderHeaders(
|
||||||
|
headers: AiProviderHeader[] | null | undefined,
|
||||||
|
secret: string
|
||||||
|
): string | null {
|
||||||
|
if (!headers || headers.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return encrypt(JSON.stringify(headers), secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseAiProviderHeaders(
|
||||||
|
raw: string | null | undefined,
|
||||||
|
secret: string
|
||||||
|
): AiProviderHeader[] {
|
||||||
|
if (!raw) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const decrypted = decrypt(raw, secret);
|
||||||
|
const parsed = JSON.parse(decrypted);
|
||||||
|
if (!Array.isArray(parsed)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return parsed.filter(
|
||||||
|
(h): h is AiProviderHeader =>
|
||||||
|
h != null &&
|
||||||
|
typeof h === "object" &&
|
||||||
|
typeof h.name === "string" &&
|
||||||
|
typeof h.value === "string"
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyAiProviderCustomHeaders(
|
||||||
|
headers: Record<string, string>,
|
||||||
|
raw: string | null | undefined,
|
||||||
|
secret: string
|
||||||
|
): void {
|
||||||
|
for (const { name, value } of parseAiProviderHeaders(raw, secret)) {
|
||||||
|
headers[name] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply provider auth to upstream headers.
|
||||||
|
* - Always strips Pangolin virtual API key credentials from client auth headers.
|
||||||
|
* - Injected modes: strip conflicting client auth headers, then set the provider key.
|
||||||
|
* - none: strip conflicting client auth headers, send no auth.
|
||||||
|
* - passthrough: leave remaining client auth headers as-is (after VAK strip).
|
||||||
|
*/
|
||||||
|
export function applyAiProviderAuthHeaders(
|
||||||
|
headers: Record<string, string>,
|
||||||
|
authType: AiProviderAuthType,
|
||||||
|
apiKey: string | null
|
||||||
|
): void {
|
||||||
|
stripVirtualApiKeyAuthHeaders(headers);
|
||||||
|
|
||||||
|
if (authType === "passthrough") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const name of CONFLICTING_AUTH_HEADERS) {
|
||||||
|
for (const key of Object.keys(headers)) {
|
||||||
|
if (key.toLowerCase() === name) {
|
||||||
|
delete headers[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authType === "none") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!apiKey) {
|
||||||
|
throw new Error(`API key required for authType ${authType}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (authType) {
|
||||||
|
case "bearer":
|
||||||
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
||||||
|
break;
|
||||||
|
case "x-api-key":
|
||||||
|
headers["x-api-key"] = apiKey;
|
||||||
|
break;
|
||||||
|
case "x-goog-api-key":
|
||||||
|
headers["x-goog-api-key"] = apiKey;
|
||||||
|
break;
|
||||||
|
case "hec":
|
||||||
|
headers["Authorization"] = `Splunk ${apiKey}`;
|
||||||
|
break;
|
||||||
|
case "cf-aig-authorization":
|
||||||
|
headers["cf-aig-authorization"] = `Bearer ${apiKey}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveCapabilitiesForCreate(input: {
|
||||||
|
type: AiProviderType;
|
||||||
|
capabilities?: AiCapability[] | null;
|
||||||
|
}): AiCapability[] {
|
||||||
|
if (input.capabilities != null) {
|
||||||
|
return parseCapabilities(input.capabilities);
|
||||||
|
}
|
||||||
|
if (input.type === "custom") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [...AI_PROVIDER_DEFAULTS[input.type].capabilities];
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import {
|
||||||
|
aiModelCatalog,
|
||||||
|
getCatalogProviderForType,
|
||||||
|
type CatalogProvider
|
||||||
|
} from "@server/lib/aiModelCatalog";
|
||||||
|
import type { AiProviderType } from "@server/lib/aiProviderDefaults";
|
||||||
|
|
||||||
|
function stripVendorPrefix(modelId: string): string | null {
|
||||||
|
const idx = modelId.indexOf("/");
|
||||||
|
if (idx === -1 || idx === modelId.length - 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return modelId.slice(idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function modelKeysToTry(modelId: string): string[] {
|
||||||
|
const keys = [modelId];
|
||||||
|
const stripped = stripVendorPrefix(modelId);
|
||||||
|
if (stripped) {
|
||||||
|
keys.push(stripped);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
function catalogOwnsModel(
|
||||||
|
catalogProvider: CatalogProvider,
|
||||||
|
modelId: string
|
||||||
|
): boolean {
|
||||||
|
for (const key of modelKeysToTry(modelId)) {
|
||||||
|
if (aiModelCatalog.get(catalogProvider, key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function modelKnownInAnyCatalog(modelId: string): boolean {
|
||||||
|
for (const key of modelKeysToTry(modelId)) {
|
||||||
|
if (aiModelCatalog.listByKey(key).length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How strongly a provider "owns" a requested model id via the known catalog.
|
||||||
|
*
|
||||||
|
* 2 - Typed provider whose catalog contains the model
|
||||||
|
* 1 - Aggregator/custom that can proxy a catalog-known model
|
||||||
|
* 0 - No ownership signal (typed miss, or unknown model on aggregator/custom)
|
||||||
|
*/
|
||||||
|
export function catalogOwnershipScore(
|
||||||
|
type: AiProviderType,
|
||||||
|
modelId: string
|
||||||
|
): number {
|
||||||
|
const catalogProvider = getCatalogProviderForType(type);
|
||||||
|
if (catalogProvider != null) {
|
||||||
|
return catalogOwnsModel(catalogProvider, modelId) ? 2 : 0;
|
||||||
|
}
|
||||||
|
return modelKnownInAnyCatalog(modelId) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefer native vendor providers over aggregators over custom when catalog
|
||||||
|
* ownership is tied.
|
||||||
|
*
|
||||||
|
* 2 - Native typed provider (openai, anthropic, gemini, ...)
|
||||||
|
* 1 - Aggregator gateway (openRouter, vercelAiGateway)
|
||||||
|
* 0 - Custom
|
||||||
|
*/
|
||||||
|
export function providerClassRank(type: AiProviderType): number {
|
||||||
|
if (type === "custom") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (type === "openRouter" || type === "vercelAiGateway") {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function keepBestScored<T>(
|
||||||
|
items: T[],
|
||||||
|
scoreFn: (item: T) => number
|
||||||
|
): T[] {
|
||||||
|
if (items.length <= 1) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
let best = Number.NEGATIVE_INFINITY;
|
||||||
|
for (const item of items) {
|
||||||
|
const score = scoreFn(item);
|
||||||
|
if (score > best) {
|
||||||
|
best = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items.filter((item) => scoreFn(item) === best);
|
||||||
|
}
|
||||||
@@ -0,0 +1,482 @@
|
|||||||
|
import { encode } from "gpt-tokenizer";
|
||||||
|
import type { AiCapability } from "@server/lib/aiCapabilities";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
|
||||||
|
export type AiUsage = {
|
||||||
|
// Input tokens billed at the normal input rate (i.e. NOT already
|
||||||
|
// covered by cacheReadTokens/cacheWriteTokens below).
|
||||||
|
promptTokens: number;
|
||||||
|
cacheReadTokens: number;
|
||||||
|
cacheWriteTokens: number;
|
||||||
|
// Output tokens billed at the normal output rate (i.e. NOT already
|
||||||
|
// covered by reasoningTokens below).
|
||||||
|
completionTokens: number;
|
||||||
|
reasoningTokens: number;
|
||||||
|
// True when these numbers are our own best-guess estimate (the upstream
|
||||||
|
// response didn't report usage), rather than provider-reported figures.
|
||||||
|
estimated: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function emptyUsage(): AiUsage {
|
||||||
|
return {
|
||||||
|
promptTokens: 0,
|
||||||
|
cacheReadTokens: 0,
|
||||||
|
cacheWriteTokens: 0,
|
||||||
|
completionTokens: 0,
|
||||||
|
reasoningTokens: 0,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans raw (possibly binary-framed, e.g. Bedrock's vnd.amazon.eventstream)
|
||||||
|
* text for `"fieldName":123` occurrences and returns the last value seen for
|
||||||
|
* each field. Used as a best-effort fallback for response shapes we can't
|
||||||
|
* fully parse as JSON/SSE (streaming Bedrock, raw predict passthroughs).
|
||||||
|
*/
|
||||||
|
function scanNumericFields(
|
||||||
|
text: string,
|
||||||
|
fields: string[]
|
||||||
|
): Record<string, number> {
|
||||||
|
const out: Record<string, number> = {};
|
||||||
|
for (const field of fields) {
|
||||||
|
const re = new RegExp(`"${field}"\\s*:\\s*(\\d+)`, "g");
|
||||||
|
let match: RegExpExecArray | null;
|
||||||
|
while ((match = re.exec(text)) !== null) {
|
||||||
|
out[field] = Number(match[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exported for reuse by server/lib/aiMessageNormalization.ts, which needs
|
||||||
|
// the same SSE-frame/JSON-parsing groundwork to extract message content
|
||||||
|
// instead of usage numbers.
|
||||||
|
export function sseDataFrames(text: string): string[] {
|
||||||
|
const frames: string[] = [];
|
||||||
|
for (const rawFrame of text.split(/\r?\n\r?\n/)) {
|
||||||
|
for (const line of rawFrame.split(/\r?\n/)) {
|
||||||
|
if (!line.startsWith("data:")) continue;
|
||||||
|
const data = line.slice("data:".length).trim();
|
||||||
|
if (data && data !== "[DONE]") {
|
||||||
|
frames.push(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tryParseJson(text: string): any | null {
|
||||||
|
try {
|
||||||
|
return JSON.parse(text);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractOpenAiChat(text: string, isStream: boolean): AiUsage | null {
|
||||||
|
let usage: any = null;
|
||||||
|
|
||||||
|
if (isStream) {
|
||||||
|
for (const frame of sseDataFrames(text)) {
|
||||||
|
const parsed = tryParseJson(frame);
|
||||||
|
if (parsed?.usage) {
|
||||||
|
usage = parsed.usage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
usage = tryParseJson(text)?.usage ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!usage) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheReadTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;
|
||||||
|
const reasoningTokens =
|
||||||
|
usage.completion_tokens_details?.reasoning_tokens ?? 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
promptTokens: Math.max(0, (usage.prompt_tokens ?? 0) - cacheReadTokens),
|
||||||
|
cacheReadTokens,
|
||||||
|
cacheWriteTokens: 0,
|
||||||
|
completionTokens: Math.max(
|
||||||
|
0,
|
||||||
|
(usage.completion_tokens ?? 0) - reasoningTokens
|
||||||
|
),
|
||||||
|
reasoningTokens,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractOpenAiResponses(
|
||||||
|
text: string,
|
||||||
|
isStream: boolean
|
||||||
|
): AiUsage | null {
|
||||||
|
let usage: any = null;
|
||||||
|
|
||||||
|
if (isStream) {
|
||||||
|
for (const frame of sseDataFrames(text)) {
|
||||||
|
const parsed = tryParseJson(frame);
|
||||||
|
if (
|
||||||
|
parsed?.type === "response.completed" &&
|
||||||
|
parsed?.response?.usage
|
||||||
|
) {
|
||||||
|
usage = parsed.response.usage;
|
||||||
|
} else if (parsed?.usage) {
|
||||||
|
usage = parsed.usage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const parsed = tryParseJson(text);
|
||||||
|
usage = parsed?.usage ?? parsed?.response?.usage ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!usage) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheReadTokens = usage.input_tokens_details?.cached_tokens ?? 0;
|
||||||
|
const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
promptTokens: Math.max(0, (usage.input_tokens ?? 0) - cacheReadTokens),
|
||||||
|
cacheReadTokens,
|
||||||
|
cacheWriteTokens: 0,
|
||||||
|
completionTokens: Math.max(
|
||||||
|
0,
|
||||||
|
(usage.output_tokens ?? 0) - reasoningTokens
|
||||||
|
),
|
||||||
|
reasoningTokens,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractAnthropicMessages(
|
||||||
|
text: string,
|
||||||
|
isStream: boolean
|
||||||
|
): AiUsage | null {
|
||||||
|
let inputTokens = 0;
|
||||||
|
let cacheReadTokens = 0;
|
||||||
|
let cacheWriteTokens = 0;
|
||||||
|
let outputTokens = 0;
|
||||||
|
let found = false;
|
||||||
|
|
||||||
|
const applyUsage = (usage: any) => {
|
||||||
|
if (!usage) return;
|
||||||
|
found = true;
|
||||||
|
if (typeof usage.input_tokens === "number") {
|
||||||
|
inputTokens = usage.input_tokens;
|
||||||
|
}
|
||||||
|
if (typeof usage.cache_read_input_tokens === "number") {
|
||||||
|
cacheReadTokens = usage.cache_read_input_tokens;
|
||||||
|
}
|
||||||
|
if (typeof usage.cache_creation_input_tokens === "number") {
|
||||||
|
cacheWriteTokens = usage.cache_creation_input_tokens;
|
||||||
|
}
|
||||||
|
if (typeof usage.output_tokens === "number") {
|
||||||
|
outputTokens = usage.output_tokens;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isStream) {
|
||||||
|
for (const frame of sseDataFrames(text)) {
|
||||||
|
const parsed = tryParseJson(frame);
|
||||||
|
if (!parsed) continue;
|
||||||
|
applyUsage(parsed.message?.usage);
|
||||||
|
applyUsage(parsed.usage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
applyUsage(tryParseJson(text)?.usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
promptTokens: inputTokens,
|
||||||
|
cacheReadTokens,
|
||||||
|
cacheWriteTokens,
|
||||||
|
completionTokens: outputTokens,
|
||||||
|
// Anthropic bills extended-thinking output at the normal output
|
||||||
|
// rate, so there's no separate reasoning bucket to report.
|
||||||
|
reasoningTokens: 0,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractGoogleGenerateContent(
|
||||||
|
text: string,
|
||||||
|
_isStream: boolean
|
||||||
|
): AiUsage | null {
|
||||||
|
// Both the plain-JSON-array stream format and the SSE (?alt=sse) format
|
||||||
|
// repeat a cumulative `usageMetadata` object per chunk; the regex scan
|
||||||
|
// below naturally picks up the last (most complete) one either way.
|
||||||
|
const fields = scanNumericFields(text, [
|
||||||
|
"promptTokenCount",
|
||||||
|
"candidatesTokenCount",
|
||||||
|
"cachedContentTokenCount",
|
||||||
|
"thoughtsTokenCount"
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (fields.promptTokenCount === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheReadTokens = fields.cachedContentTokenCount ?? 0;
|
||||||
|
const reasoningTokens = fields.thoughtsTokenCount ?? 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
promptTokens: Math.max(0, fields.promptTokenCount - cacheReadTokens),
|
||||||
|
cacheReadTokens,
|
||||||
|
cacheWriteTokens: 0,
|
||||||
|
completionTokens: fields.candidatesTokenCount ?? 0,
|
||||||
|
reasoningTokens,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractBedrockConverse(
|
||||||
|
text: string,
|
||||||
|
_isStream: boolean
|
||||||
|
): AiUsage | null {
|
||||||
|
// Non-streaming responses are plain JSON; converse-stream frames the
|
||||||
|
// final `metadata` event's usage object inside binary event-stream
|
||||||
|
// framing, but the JSON text survives intact inside that binary
|
||||||
|
// envelope, so the same field scan works for both.
|
||||||
|
const parsed = tryParseJson(text);
|
||||||
|
const usage = parsed?.usage;
|
||||||
|
if (usage) {
|
||||||
|
const cacheReadTokens = usage.cacheReadInputTokens ?? 0;
|
||||||
|
return {
|
||||||
|
promptTokens: Math.max(
|
||||||
|
0,
|
||||||
|
(usage.inputTokens ?? 0) - cacheReadTokens
|
||||||
|
),
|
||||||
|
cacheReadTokens,
|
||||||
|
cacheWriteTokens: usage.cacheWriteInputTokens ?? 0,
|
||||||
|
completionTokens: usage.outputTokens ?? 0,
|
||||||
|
reasoningTokens: 0,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = scanNumericFields(text, [
|
||||||
|
"inputTokens",
|
||||||
|
"outputTokens",
|
||||||
|
"cacheReadInputTokens",
|
||||||
|
"cacheWriteInputTokens"
|
||||||
|
]);
|
||||||
|
if (fields.inputTokens === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const cacheReadTokens = fields.cacheReadInputTokens ?? 0;
|
||||||
|
return {
|
||||||
|
promptTokens: Math.max(0, fields.inputTokens - cacheReadTokens),
|
||||||
|
cacheReadTokens,
|
||||||
|
cacheWriteTokens: fields.cacheWriteInputTokens ?? 0,
|
||||||
|
completionTokens: fields.outputTokens ?? 0,
|
||||||
|
reasoningTokens: 0,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractBedrockModelInvoke(
|
||||||
|
text: string,
|
||||||
|
_isStream: boolean,
|
||||||
|
headers: Headers
|
||||||
|
): AiUsage | null {
|
||||||
|
// Non-streaming invoke reports counts via response headers regardless
|
||||||
|
// of the underlying model's payload format.
|
||||||
|
const headerInput = headers.get("x-amzn-bedrock-input-token-count");
|
||||||
|
const headerOutput = headers.get("x-amzn-bedrock-output-token-count");
|
||||||
|
if (headerInput !== null || headerOutput !== null) {
|
||||||
|
return {
|
||||||
|
promptTokens: Number(headerInput ?? 0),
|
||||||
|
cacheReadTokens: 0,
|
||||||
|
cacheWriteTokens: 0,
|
||||||
|
completionTokens: Number(headerOutput ?? 0),
|
||||||
|
reasoningTokens: 0,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// invoke-with-response-stream has no equivalent headers; the model's
|
||||||
|
// own usage shape (frequently Anthropic-style on Bedrock) is embedded
|
||||||
|
// inside binary event-stream framing, so fall back to a couple of
|
||||||
|
// known field-name shapes via regex.
|
||||||
|
const anthropicStyle = extractAnthropicMessages(text, true);
|
||||||
|
if (anthropicStyle) {
|
||||||
|
return anthropicStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = scanNumericFields(text, [
|
||||||
|
"inputTokenCount",
|
||||||
|
"outputTokenCount"
|
||||||
|
]);
|
||||||
|
if (fields.inputTokenCount === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
promptTokens: fields.inputTokenCount,
|
||||||
|
cacheReadTokens: 0,
|
||||||
|
cacheWriteTokens: 0,
|
||||||
|
completionTokens: fields.outputTokenCount ?? 0,
|
||||||
|
reasoningTokens: 0,
|
||||||
|
estimated: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const EXTRACTORS: Record<
|
||||||
|
AiCapability,
|
||||||
|
(text: string, isStream: boolean, headers: Headers) => AiUsage | null
|
||||||
|
> = {
|
||||||
|
openai_chat: extractOpenAiChat,
|
||||||
|
openai_responses: extractOpenAiResponses,
|
||||||
|
anthropic_messages: extractAnthropicMessages,
|
||||||
|
gemini_generate_content: extractGoogleGenerateContent,
|
||||||
|
google_generate_content: extractGoogleGenerateContent,
|
||||||
|
// rawPredict is a passthrough to whatever the underlying publisher
|
||||||
|
// model speaks (often Anthropic-shaped on Vertex); try that, then give
|
||||||
|
// up to the token-count estimate.
|
||||||
|
google_raw_predict: (text, isStream) =>
|
||||||
|
extractAnthropicMessages(text, isStream),
|
||||||
|
bedrock_model_invoke: extractBedrockModelInvoke,
|
||||||
|
bedrock_converse: extractBedrockConverse
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to pull provider-reported token usage out of an upstream AI
|
||||||
|
* gateway response. Returns null if the response didn't contain (or we
|
||||||
|
* couldn't find) usage data, in which case callers should fall back to
|
||||||
|
* `estimateUsage`.
|
||||||
|
*/
|
||||||
|
export function extractUsage(
|
||||||
|
capability: AiCapability,
|
||||||
|
responseText: string,
|
||||||
|
isStream: boolean,
|
||||||
|
headers: Headers
|
||||||
|
): AiUsage | null {
|
||||||
|
try {
|
||||||
|
return EXTRACTORS[capability](responseText, isStream, headers);
|
||||||
|
} catch (error) {
|
||||||
|
logger.debug("Failed to extract AI usage from response", {
|
||||||
|
capability,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Best-guess token estimate for when the provider doesn't report usage.
|
||||||
|
* Uses OpenAI's BPE tokenizer as a stand-in for whatever tokenizer the
|
||||||
|
* actual model uses - close enough for an approximate cost figure, not
|
||||||
|
* exact for non-OpenAI models.
|
||||||
|
*/
|
||||||
|
export function estimateUsage(
|
||||||
|
promptText: string,
|
||||||
|
completionText: string
|
||||||
|
): AiUsage {
|
||||||
|
const usage = emptyUsage();
|
||||||
|
usage.estimated = true;
|
||||||
|
try {
|
||||||
|
usage.promptTokens = promptText ? encode(promptText).length : 0;
|
||||||
|
} catch (error) {
|
||||||
|
logger.debug("Failed to estimate prompt tokens", { error });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
usage.completionTokens = completionText
|
||||||
|
? encode(completionText).length
|
||||||
|
: 0;
|
||||||
|
} catch (error) {
|
||||||
|
logger.debug("Failed to estimate completion tokens", { error });
|
||||||
|
}
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenAI's Chat Completions API only includes a `usage` field in a
|
||||||
|
* streaming response when the request opts in via `stream_options:
|
||||||
|
* {include_usage: true}` - unlike the Responses API, Anthropic, Gemini and
|
||||||
|
* Bedrock, which report usage in a streaming response by default. Returns
|
||||||
|
* whether we need to inject that option ourselves to be able to track cost.
|
||||||
|
*/
|
||||||
|
export function needsStreamUsageInjection(
|
||||||
|
capability: AiCapability,
|
||||||
|
body: any
|
||||||
|
): boolean {
|
||||||
|
return (
|
||||||
|
capability === "openai_chat" &&
|
||||||
|
body?.stream === true &&
|
||||||
|
body?.stream_options?.include_usage !== true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a shallow-cloned body with `stream_options.include_usage`
|
||||||
|
* injected, for capabilities/requests where `needsStreamUsageInjection`
|
||||||
|
* is true. Leaves the original body untouched.
|
||||||
|
*/
|
||||||
|
export function withStreamUsageOption(body: any): any {
|
||||||
|
return {
|
||||||
|
...body,
|
||||||
|
stream_options: { ...body.stream_options, include_usage: true }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we injected stream_options.include_usage ourselves (the caller
|
||||||
|
* didn't ask for it), OpenAI appends an extra terminal SSE frame with an
|
||||||
|
* empty `choices: []` array carrying only the usage data. Callers that
|
||||||
|
* don't expect that shape (most minimal SSE parsers assume a non-empty
|
||||||
|
* choices array) shouldn't see it, so it's stripped back out of the bytes
|
||||||
|
* forwarded to the client.
|
||||||
|
*/
|
||||||
|
export function stripInjectedUsageFrame(sseText: string): string {
|
||||||
|
const parts = sseText.split(/(\r?\n\r?\n)/);
|
||||||
|
let out = "";
|
||||||
|
for (let i = 0; i < parts.length; i += 2) {
|
||||||
|
const frame = parts[i];
|
||||||
|
const separator = parts[i + 1] ?? "";
|
||||||
|
const dataLine = frame
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.find((line) => line.startsWith("data:"));
|
||||||
|
if (dataLine) {
|
||||||
|
const data = dataLine.slice("data:".length).trim();
|
||||||
|
const parsed = data !== "[DONE]" ? tryParseJson(data) : null;
|
||||||
|
if (
|
||||||
|
parsed &&
|
||||||
|
Array.isArray(parsed.choices) &&
|
||||||
|
parsed.choices.length === 0 &&
|
||||||
|
parsed.usage
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out += frame + separator;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Best-effort extraction of the model the upstream provider actually
|
||||||
|
* served, which some gateways/routers echo back and which may differ from
|
||||||
|
* the model the caller requested (e.g. an alias resolving to a dated
|
||||||
|
* snapshot). Falls back to the caller's requested model when absent.
|
||||||
|
*/
|
||||||
|
export function extractResponseModel(responseText: string): string | null {
|
||||||
|
const match = responseText.match(/"model"\s*:\s*"([^"]+)"/);
|
||||||
|
return match ? match[1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isUsageEmpty(usage: AiUsage): boolean {
|
||||||
|
return (
|
||||||
|
usage.promptTokens === 0 &&
|
||||||
|
usage.cacheReadTokens === 0 &&
|
||||||
|
usage.cacheWriteTokens === 0 &&
|
||||||
|
usage.completionTokens === 0 &&
|
||||||
|
usage.reasoningTokens === 0
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -202,6 +202,10 @@ async function handleResource(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!target.resourceId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const [resource] = await trx
|
const [resource] = await trx
|
||||||
.select()
|
.select()
|
||||||
.from(resources)
|
.from(resources)
|
||||||
@@ -227,9 +231,7 @@ async function handleResource(
|
|||||||
|
|
||||||
let health = "healthy";
|
let health = "healthy";
|
||||||
const allUnknown = monitoredTargets.length === 0;
|
const allUnknown = monitoredTargets.length === 0;
|
||||||
const allHealthy = monitoredTargets.every(
|
const allHealthy = monitoredTargets.every((t) => t.hcHealth === "healthy");
|
||||||
(t) => t.hcHealth === "healthy"
|
|
||||||
);
|
|
||||||
const allUnhealthy = monitoredTargets.every(
|
const allUnhealthy = monitoredTargets.every(
|
||||||
(t) => t.hcHealth === "unhealthy"
|
(t) => t.hcHealth === "unhealthy"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export enum TierFeature {
|
|||||||
ActionLogs = "actionLogs", // set the retention period to none on downgrade
|
ActionLogs = "actionLogs", // set the retention period to none on downgrade
|
||||||
ConnectionLogs = "connectionLogs",
|
ConnectionLogs = "connectionLogs",
|
||||||
RotateCredentials = "rotateCredentials",
|
RotateCredentials = "rotateCredentials",
|
||||||
MaintencePage = "maintencePage", // handle downgrade
|
MaintenancePage = "maintenancePage", // handle downgrade
|
||||||
DevicePosture = "devicePosture",
|
DevicePosture = "devicePosture",
|
||||||
TwoFactorEnforcement = "twoFactorEnforcement", // handle downgrade by setting to optional
|
TwoFactorEnforcement = "twoFactorEnforcement", // handle downgrade by setting to optional
|
||||||
SessionDurationPolicies = "sessionDurationPolicies", // handle downgrade by setting to default duration
|
SessionDurationPolicies = "sessionDurationPolicies", // handle downgrade by setting to default duration
|
||||||
@@ -25,8 +25,7 @@ export enum TierFeature {
|
|||||||
WildcardSubdomain = "wildcardSubdomain",
|
WildcardSubdomain = "wildcardSubdomain",
|
||||||
NewtAutoUpdate = "newtAutoUpdate",
|
NewtAutoUpdate = "newtAutoUpdate",
|
||||||
ResourcePolicies = "resourcePolicies",
|
ResourcePolicies = "resourcePolicies",
|
||||||
AdvancedPublicResources = "advancedPublicResources",
|
RoleBasedSSHControls = "roleBasedSSHControls"
|
||||||
AdvancedPrivateResources = "advancedPrivateResources"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const tierMatrix: Record<TierFeature, Tier[]> = {
|
export const tierMatrix: Record<TierFeature, Tier[]> = {
|
||||||
@@ -39,7 +38,7 @@ export const tierMatrix: Record<TierFeature, Tier[]> = {
|
|||||||
[TierFeature.ActionLogs]: ["tier2", "tier3", "enterprise"],
|
[TierFeature.ActionLogs]: ["tier2", "tier3", "enterprise"],
|
||||||
[TierFeature.ConnectionLogs]: ["tier2", "tier3", "enterprise"],
|
[TierFeature.ConnectionLogs]: ["tier2", "tier3", "enterprise"],
|
||||||
[TierFeature.RotateCredentials]: ["tier1", "tier2", "tier3", "enterprise"],
|
[TierFeature.RotateCredentials]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||||
[TierFeature.MaintencePage]: ["tier1", "tier2", "tier3", "enterprise"],
|
[TierFeature.MaintenancePage]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||||
[TierFeature.DevicePosture]: ["tier2", "tier3", "enterprise"],
|
[TierFeature.DevicePosture]: ["tier2", "tier3", "enterprise"],
|
||||||
[TierFeature.TwoFactorEnforcement]: [
|
[TierFeature.TwoFactorEnforcement]: [
|
||||||
"tier1",
|
"tier1",
|
||||||
@@ -69,6 +68,5 @@ export const tierMatrix: Record<TierFeature, Tier[]> = {
|
|||||||
[TierFeature.WildcardSubdomain]: ["tier1", "tier2", "tier3", "enterprise"],
|
[TierFeature.WildcardSubdomain]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||||
[TierFeature.NewtAutoUpdate]: ["tier1", "tier2", "tier3", "enterprise"],
|
[TierFeature.NewtAutoUpdate]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||||
[TierFeature.ResourcePolicies]: ["tier3", "enterprise"],
|
[TierFeature.ResourcePolicies]: ["tier3", "enterprise"],
|
||||||
[TierFeature.AdvancedPublicResources]: ["tier3", "enterprise"],
|
[TierFeature.RoleBasedSSHControls]: ["tier3", "enterprise"]
|
||||||
[TierFeature.AdvancedPrivateResources]: ["tier3", "enterprise"]
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { aiBudgets, Transaction } from "@server/db";
|
||||||
|
|
||||||
|
export type BlueprintAiBudgetInput = {
|
||||||
|
amount: number;
|
||||||
|
unit: "usd" | "tokens";
|
||||||
|
period:
|
||||||
|
| "monthly"
|
||||||
|
| "yearly"
|
||||||
|
| "lifetime"
|
||||||
|
| "daily"
|
||||||
|
| "hourly"
|
||||||
|
| "weekly";
|
||||||
|
enforcement: "hard" | "soft";
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SyncAiBudgetsInput = {
|
||||||
|
orgId: string;
|
||||||
|
trx: Transaction;
|
||||||
|
budgets: BlueprintAiBudgetInput[];
|
||||||
|
} & (
|
||||||
|
| { scope: "public"; resourceId: number }
|
||||||
|
| { scope: "site"; siteResourceId: number }
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fully declarative: makes the resource's/site resource's AI budgets match
|
||||||
|
* exactly what the blueprint declares (omitted unit/period budgets are removed).
|
||||||
|
*/
|
||||||
|
export async function syncAiBudgets(input: SyncAiBudgetsInput): Promise<void> {
|
||||||
|
const { orgId, trx, budgets } = input;
|
||||||
|
|
||||||
|
const existing = await trx
|
||||||
|
.select()
|
||||||
|
.from(aiBudgets)
|
||||||
|
.where(
|
||||||
|
input.scope === "public"
|
||||||
|
? eq(aiBudgets.resourceId, input.resourceId)
|
||||||
|
: eq(aiBudgets.siteResourceId, input.siteResourceId)
|
||||||
|
);
|
||||||
|
|
||||||
|
const existingByKey = new Map(
|
||||||
|
existing.map((b) => [`${b.unit}::${b.period}`, b])
|
||||||
|
);
|
||||||
|
|
||||||
|
const seenKeys = new Set<string>();
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
for (const budget of budgets) {
|
||||||
|
const key = `${budget.unit}::${budget.period}`;
|
||||||
|
seenKeys.add(key);
|
||||||
|
const existingBudget = existingByKey.get(key);
|
||||||
|
|
||||||
|
if (existingBudget) {
|
||||||
|
await trx
|
||||||
|
.update(aiBudgets)
|
||||||
|
.set({
|
||||||
|
amount: budget.amount,
|
||||||
|
enforcement: budget.enforcement,
|
||||||
|
enabled: budget.enabled,
|
||||||
|
updatedAt: now
|
||||||
|
})
|
||||||
|
.where(eq(aiBudgets.budgetId, existingBudget.budgetId));
|
||||||
|
} else {
|
||||||
|
await trx.insert(aiBudgets).values({
|
||||||
|
orgId,
|
||||||
|
resourceId: input.scope === "public" ? input.resourceId : null,
|
||||||
|
siteResourceId:
|
||||||
|
input.scope === "site" ? input.siteResourceId : null,
|
||||||
|
amount: budget.amount,
|
||||||
|
unit: budget.unit,
|
||||||
|
period: budget.period,
|
||||||
|
enforcement: budget.enforcement,
|
||||||
|
enabled: budget.enabled,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, existingBudget] of existingByKey) {
|
||||||
|
if (!seenKeys.has(key)) {
|
||||||
|
await trx
|
||||||
|
.delete(aiBudgets)
|
||||||
|
.where(eq(aiBudgets.budgetId, existingBudget.budgetId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
import { and, eq, inArray } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
aiModels,
|
||||||
|
aiProviders,
|
||||||
|
resourceAiModels,
|
||||||
|
siteResourceAiModels,
|
||||||
|
Transaction
|
||||||
|
} from "@server/db";
|
||||||
|
import {
|
||||||
|
AccessMode,
|
||||||
|
ModelListType,
|
||||||
|
clearPublicResourceAiConfig,
|
||||||
|
clearSiteResourceAiConfig,
|
||||||
|
isInferenceFieldsError,
|
||||||
|
resolveProviderAttachments,
|
||||||
|
setPublicResourceAiProviders,
|
||||||
|
setSiteResourceAiProviders
|
||||||
|
} from "@server/lib/aiInferenceResource";
|
||||||
|
|
||||||
|
export type BlueprintAiModelInput = {
|
||||||
|
model: string;
|
||||||
|
listType: ModelListType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BlueprintAiProviderInput = {
|
||||||
|
provider: string;
|
||||||
|
accessMode: AccessMode;
|
||||||
|
enabled: boolean;
|
||||||
|
models: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
async function resolveProviderNiceIds(
|
||||||
|
orgId: string,
|
||||||
|
niceIds: string[],
|
||||||
|
trx: Transaction
|
||||||
|
): Promise<Map<string, number>> {
|
||||||
|
const unique = [...new Set(niceIds)];
|
||||||
|
if (unique.length === 0) {
|
||||||
|
return new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = await trx
|
||||||
|
.select({
|
||||||
|
providerId: aiProviders.providerId,
|
||||||
|
niceId: aiProviders.niceId
|
||||||
|
})
|
||||||
|
.from(aiProviders)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(aiProviders.orgId, orgId),
|
||||||
|
inArray(aiProviders.niceId, unique)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const byNiceId = new Map(rows.map((r) => [r.niceId, r.providerId]));
|
||||||
|
const missing = unique.filter((id) => !byNiceId.has(id));
|
||||||
|
if (missing.length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
`AI provider(s) not found in this org: ${missing.join(", ")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return byNiceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveModelKeys(
|
||||||
|
providers: BlueprintAiProviderInput[],
|
||||||
|
providerIdByNiceId: Map<string, number>,
|
||||||
|
trx: Transaction
|
||||||
|
): Promise<Map<string, number>> {
|
||||||
|
const providerIds = [
|
||||||
|
...new Set(
|
||||||
|
providers
|
||||||
|
.filter((p) => p.models.length > 0)
|
||||||
|
.map((p) => providerIdByNiceId.get(p.provider)!)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
if (providerIds.length === 0) {
|
||||||
|
return new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = await trx
|
||||||
|
.select({
|
||||||
|
modelId: aiModels.modelId,
|
||||||
|
modelKey: aiModels.modelKey,
|
||||||
|
providerId: aiModels.providerId
|
||||||
|
})
|
||||||
|
.from(aiModels)
|
||||||
|
.where(inArray(aiModels.providerId, providerIds));
|
||||||
|
|
||||||
|
const byProviderAndKey = new Map<string, number>();
|
||||||
|
for (const row of rows) {
|
||||||
|
byProviderAndKey.set(`${row.providerId}::${row.modelKey}`, row.modelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelIdByEntryKey = new Map<string, number>();
|
||||||
|
const missing: string[] = [];
|
||||||
|
for (const provider of providers) {
|
||||||
|
const providerId = providerIdByNiceId.get(provider.provider)!;
|
||||||
|
for (const m of provider.models) {
|
||||||
|
const modelId = byProviderAndKey.get(`${providerId}::${m}`);
|
||||||
|
if (modelId === undefined) {
|
||||||
|
missing.push(`${provider.provider}/${m}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
modelIdByEntryKey.set(`${provider.provider}::${m}`, modelId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missing.length > 0) {
|
||||||
|
throw new Error(`AI model(s) not found: ${missing.join(", ")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return modelIdByEntryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validateModelEntries(input: {
|
||||||
|
orgId: string;
|
||||||
|
entries: { modelId: number }[];
|
||||||
|
selectProviderIds: number[];
|
||||||
|
trx: Transaction;
|
||||||
|
}): Promise<void> {
|
||||||
|
if (input.entries.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.selectProviderIds.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
"Set at least one attached AI provider to access-mode 'select' before declaring models"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelIds = input.entries.map((e) => e.modelId);
|
||||||
|
const catalogRows = await input.trx
|
||||||
|
.select({
|
||||||
|
modelId: aiModels.modelId,
|
||||||
|
listType: aiModels.listType,
|
||||||
|
providerId: aiModels.providerId,
|
||||||
|
enabled: aiModels.enabled
|
||||||
|
})
|
||||||
|
.from(aiModels)
|
||||||
|
.innerJoin(aiProviders, eq(aiModels.providerId, aiProviders.providerId))
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
inArray(aiModels.modelId, modelIds),
|
||||||
|
inArray(aiModels.providerId, input.selectProviderIds),
|
||||||
|
eq(aiProviders.orgId, input.orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const catalogById = new Map(catalogRows.map((row) => [row.modelId, row]));
|
||||||
|
for (const entry of input.entries) {
|
||||||
|
const catalog = catalogById.get(entry.modelId);
|
||||||
|
if (!catalog) {
|
||||||
|
throw new Error(
|
||||||
|
`Model ${entry.modelId} does not exist or does not belong to a select-mode attached provider`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!catalog.enabled) {
|
||||||
|
throw new Error(
|
||||||
|
`Model ${entry.modelId} is disabled on its provider`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SyncInferenceAiConfigInput = {
|
||||||
|
orgId: string;
|
||||||
|
trx: Transaction;
|
||||||
|
mode: string;
|
||||||
|
providers: BlueprintAiProviderInput[];
|
||||||
|
} & (
|
||||||
|
| { scope: "public"; resourceId: number }
|
||||||
|
| { scope: "site"; siteResourceId: number }
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fully declarative: makes the resource's attached AI providers/models match
|
||||||
|
* exactly what the blueprint declares (omitted providers/models are removed).
|
||||||
|
* Non-inference resources have any leftover AI config cleared.
|
||||||
|
*/
|
||||||
|
export async function syncInferenceAiConfig(
|
||||||
|
input: SyncInferenceAiConfigInput
|
||||||
|
): Promise<void> {
|
||||||
|
const { orgId, trx, mode } = input;
|
||||||
|
|
||||||
|
if (mode !== "inference") {
|
||||||
|
if (input.scope === "public") {
|
||||||
|
await clearPublicResourceAiConfig(input.resourceId, trx);
|
||||||
|
} else {
|
||||||
|
await clearSiteResourceAiConfig(input.siteResourceId, trx);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerIdByNiceId = await resolveProviderNiceIds(
|
||||||
|
orgId,
|
||||||
|
input.providers.map((p) => p.provider),
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
|
||||||
|
const resolvedAttachments = await resolveProviderAttachments({
|
||||||
|
orgId,
|
||||||
|
attachments: input.providers.map((p) => ({
|
||||||
|
providerId: providerIdByNiceId.get(p.provider)!,
|
||||||
|
accessMode: p.accessMode,
|
||||||
|
enabled: p.enabled
|
||||||
|
})),
|
||||||
|
requireAtLeastOne: false
|
||||||
|
});
|
||||||
|
if (isInferenceFieldsError(resolvedAttachments)) {
|
||||||
|
throw new Error(resolvedAttachments.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.scope === "public") {
|
||||||
|
await setPublicResourceAiProviders(
|
||||||
|
input.resourceId,
|
||||||
|
resolvedAttachments,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await setSiteResourceAiProviders(
|
||||||
|
input.siteResourceId,
|
||||||
|
resolvedAttachments,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelIdByEntryKey = await resolveModelKeys(
|
||||||
|
input.providers,
|
||||||
|
providerIdByNiceId,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
|
||||||
|
const modelEntries = input.providers.flatMap((p) =>
|
||||||
|
p.models.map((m) => ({
|
||||||
|
modelId: modelIdByEntryKey.get(`${p.provider}::${m}`)!
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectProviderIds = resolvedAttachments
|
||||||
|
.filter((a) => a.accessMode === "select")
|
||||||
|
.map((a) => a.providerId);
|
||||||
|
|
||||||
|
await validateModelEntries({
|
||||||
|
orgId,
|
||||||
|
entries: modelEntries,
|
||||||
|
selectProviderIds,
|
||||||
|
trx
|
||||||
|
});
|
||||||
|
|
||||||
|
if (input.scope === "public") {
|
||||||
|
await trx
|
||||||
|
.delete(resourceAiModels)
|
||||||
|
.where(eq(resourceAiModels.resourceId, input.resourceId));
|
||||||
|
if (modelEntries.length > 0) {
|
||||||
|
await trx.insert(resourceAiModels).values(
|
||||||
|
modelEntries.map((m) => ({
|
||||||
|
resourceId: input.resourceId,
|
||||||
|
modelId: m.modelId
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await trx
|
||||||
|
.delete(siteResourceAiModels)
|
||||||
|
.where(
|
||||||
|
eq(siteResourceAiModels.siteResourceId, input.siteResourceId)
|
||||||
|
);
|
||||||
|
if (modelEntries.length > 0) {
|
||||||
|
await trx.insert(siteResourceAiModels).values(
|
||||||
|
modelEntries.map((m) => ({
|
||||||
|
siteResourceId: input.siteResourceId,
|
||||||
|
modelId: m.modelId
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,12 +34,6 @@ import {
|
|||||||
rebuildClientAssociationsFromSiteResource,
|
rebuildClientAssociationsFromSiteResource,
|
||||||
waitForSiteResourceRebuildIdle
|
waitForSiteResourceRebuildIdle
|
||||||
} from "../rebuildClientAssociations";
|
} from "../rebuildClientAssociations";
|
||||||
import { build } from "@server/build";
|
|
||||||
import HttpCode from "@server/types/HttpCode";
|
|
||||||
import createHttpError from "http-errors";
|
|
||||||
import next from "next";
|
|
||||||
import { LimitId } from "../billing";
|
|
||||||
import { usageService } from "../billing/usageService";
|
|
||||||
|
|
||||||
type ApplyBlueprintArgs = {
|
type ApplyBlueprintArgs = {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import {
|
||||||
|
labels,
|
||||||
|
resourceLabels,
|
||||||
|
siteResourceLabels,
|
||||||
|
Transaction
|
||||||
|
} from "@server/db";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import { and, eq, sql } from "drizzle-orm";
|
||||||
|
|
||||||
|
// Matches the "gray" swatch in the label color palette used by the UI
|
||||||
|
// (src/components/labels-selector.tsx), used as the default for labels
|
||||||
|
// auto-created from a blueprint where no color is specified.
|
||||||
|
const DEFAULT_LABEL_COLOR = "#b4b4b4";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks up labels by name (case-insensitive) within an org, auto-creating
|
||||||
|
* any that don't already exist. Returns the resolved, de-duplicated labelIds.
|
||||||
|
*/
|
||||||
|
export async function getOrCreateLabelIds(
|
||||||
|
orgId: string,
|
||||||
|
labelNames: string[],
|
||||||
|
trx: Transaction
|
||||||
|
): Promise<number[]> {
|
||||||
|
const labelIds = new Set<number>();
|
||||||
|
|
||||||
|
for (const name of labelNames) {
|
||||||
|
let [label] = await trx
|
||||||
|
.select({ labelId: labels.labelId })
|
||||||
|
.from(labels)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(labels.orgId, orgId),
|
||||||
|
sql`LOWER(${labels.name}) = ${name.toLowerCase()}`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!label) {
|
||||||
|
[label] = await trx
|
||||||
|
.insert(labels)
|
||||||
|
.values({ name, color: DEFAULT_LABEL_COLOR, orgId })
|
||||||
|
.returning({ labelId: labels.labelId });
|
||||||
|
logger.info(
|
||||||
|
`Auto-created label "${name}" in org ${orgId} from blueprint`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
labelIds.add(label.labelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(labelIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function syncResourceLabels(
|
||||||
|
resourceId: number,
|
||||||
|
labelIds: number[],
|
||||||
|
trx: Transaction
|
||||||
|
) {
|
||||||
|
await trx
|
||||||
|
.delete(resourceLabels)
|
||||||
|
.where(eq(resourceLabels.resourceId, resourceId));
|
||||||
|
|
||||||
|
if (labelIds.length > 0) {
|
||||||
|
await trx
|
||||||
|
.insert(resourceLabels)
|
||||||
|
.values(labelIds.map((labelId) => ({ resourceId, labelId })));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function syncSiteResourceLabels(
|
||||||
|
siteResourceId: number,
|
||||||
|
labelIds: number[],
|
||||||
|
trx: Transaction
|
||||||
|
) {
|
||||||
|
await trx
|
||||||
|
.delete(siteResourceLabels)
|
||||||
|
.where(eq(siteResourceLabels.siteResourceId, siteResourceId));
|
||||||
|
|
||||||
|
if (labelIds.length > 0) {
|
||||||
|
await trx
|
||||||
|
.insert(siteResourceLabels)
|
||||||
|
.values(
|
||||||
|
labelIds.map((labelId) => ({ siteResourceId, labelId }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,23 +19,22 @@ import {
|
|||||||
import { sites } from "@server/db";
|
import { sites } from "@server/db";
|
||||||
import { eq, and, ne, inArray, or, isNotNull } from "drizzle-orm";
|
import { eq, and, ne, inArray, or, isNotNull } from "drizzle-orm";
|
||||||
import { Config } from "./types";
|
import { Config } from "./types";
|
||||||
|
import { getOrCreateLabelIds, syncSiteResourceLabels } from "./labels";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { defaultRoleAllowedActions } from "@server/routers/role/createRole";
|
import { defaultRoleAllowedActions } from "@server/routers/role/createRole";
|
||||||
import { getNextAvailableAliasAddress } from "../ip";
|
import { getNextAvailableAliasAddress } from "../ip";
|
||||||
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
import { createCertificate } from "@server/routers/certificates/createCertificate";
|
||||||
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
|
||||||
import { tierMatrix } from "../billing/tierMatrix";
|
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
|
||||||
import createHttpError from "http-errors";
|
|
||||||
import next from "next";
|
|
||||||
import { LimitId } from "../billing";
|
import { LimitId } from "../billing";
|
||||||
import { usageService } from "../billing/usageService";
|
import { usageService } from "../billing/usageService";
|
||||||
|
import { syncInferenceAiConfig } from "./aiProviders";
|
||||||
|
import { syncAiBudgets } from "./aiBudgets";
|
||||||
|
|
||||||
async function getDomainForSiteResource(
|
async function getDomainForSiteResource(
|
||||||
siteResourceId: number | undefined,
|
siteResourceId: number | undefined,
|
||||||
fullDomain: string,
|
fullDomain: string,
|
||||||
orgId: string,
|
orgId: string,
|
||||||
|
isInference: boolean,
|
||||||
trx: Transaction
|
trx: Transaction
|
||||||
): Promise<{ subdomain: string | null; domainId: string }> {
|
): Promise<{ subdomain: string | null; domainId: string }> {
|
||||||
const [fullDomainExists] = await trx
|
const [fullDomainExists] = await trx
|
||||||
@@ -45,6 +44,11 @@ async function getDomainForSiteResource(
|
|||||||
and(
|
and(
|
||||||
eq(siteResources.fullDomain, fullDomain),
|
eq(siteResources.fullDomain, fullDomain),
|
||||||
eq(siteResources.orgId, orgId),
|
eq(siteResources.orgId, orgId),
|
||||||
|
// exclude looking at the ones on exit nodes if this is an inference resource,
|
||||||
|
// and vice versa, so inference and non-inference resources can share a full-domain
|
||||||
|
isInference
|
||||||
|
? ne(siteResources.mode, "inference")
|
||||||
|
: eq(siteResources.mode, "inference"),
|
||||||
siteResourceId
|
siteResourceId
|
||||||
? ne(siteResources.siteResourceId, siteResourceId)
|
? ne(siteResources.siteResourceId, siteResourceId)
|
||||||
: isNotNull(siteResources.siteResourceId)
|
: isNotNull(siteResources.siteResourceId)
|
||||||
@@ -122,30 +126,6 @@ export async function updatePrivateResources(
|
|||||||
for (const [resourceNiceId, resourceData] of Object.entries(
|
for (const [resourceNiceId, resourceData] of Object.entries(
|
||||||
config["client-resources"]
|
config["client-resources"]
|
||||||
)) {
|
)) {
|
||||||
if (resourceData.mode === "http") {
|
|
||||||
const hasHttpFeature = await isLicensedOrSubscribed(
|
|
||||||
orgId,
|
|
||||||
tierMatrix.advancedPrivateResources
|
|
||||||
);
|
|
||||||
if (!hasHttpFeature) {
|
|
||||||
throw new Error(
|
|
||||||
"HTTP private resources are not included in your current plan. Please upgrade."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resourceData.mode === "ssh") {
|
|
||||||
const hasSshFeature = await isLicensedOrSubscribed(
|
|
||||||
orgId,
|
|
||||||
tierMatrix.advancedPrivateResources
|
|
||||||
);
|
|
||||||
if (!hasSshFeature) {
|
|
||||||
throw new Error(
|
|
||||||
"SSH private resources are not included in your current plan. Please upgrade."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const [existingResource] = await trx
|
const [existingResource] = await trx
|
||||||
.select()
|
.select()
|
||||||
.from(siteResources)
|
.from(siteResources)
|
||||||
@@ -201,60 +181,109 @@ export async function updatePrivateResources(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let resourceStatusFromSite: "approved" | "pending" = "approved";
|
||||||
if (siteId && allSites.length === 0) {
|
if (siteId && allSites.length === 0) {
|
||||||
// only add if there are not provided sites
|
// only add if there are not provided sites
|
||||||
// Use the provided siteId directly, but verify it belongs to the org
|
// Use the provided siteId directly, but verify it belongs to the org
|
||||||
const [siteSingle] = await trx
|
const [siteSingle] = await trx
|
||||||
.select({ siteId: sites.siteId })
|
.select({ siteId: sites.siteId, status: sites.status })
|
||||||
.from(sites)
|
.from(sites)
|
||||||
.where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId)))
|
.where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId)))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
if (siteSingle) {
|
if (siteSingle) {
|
||||||
allSites.push(siteSingle);
|
allSites.push(siteSingle);
|
||||||
}
|
}
|
||||||
|
resourceStatusFromSite = siteSingle.status ?? "approved";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allSites.length === 0) {
|
if (resourceData.mode !== "inference" && allSites.length === 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`No valid sites found for private private resource ${resourceNiceId} in org ${orgId}`
|
`No valid sites found for private private resource ${resourceNiceId} in org ${orgId}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resourceEnabled =
|
||||||
|
resourceData.enabled == undefined || resourceData.enabled == null
|
||||||
|
? true
|
||||||
|
: resourceStatusFromSite === "pending"
|
||||||
|
? false
|
||||||
|
: resourceData.enabled;
|
||||||
|
|
||||||
|
const resourceSsl =
|
||||||
|
resourceData.mode === "inference" || resourceData.mode === "http"
|
||||||
|
? resourceData.ssl == undefined || resourceData.ssl == null
|
||||||
|
? true
|
||||||
|
: resourceData.ssl
|
||||||
|
: resourceData.ssl;
|
||||||
|
|
||||||
if (existingResource) {
|
if (existingResource) {
|
||||||
let domainInfo:
|
let domainInfo:
|
||||||
| { subdomain: string | null; domainId: string }
|
| { subdomain: string | null; domainId: string }
|
||||||
| undefined;
|
| undefined;
|
||||||
if (resourceData["full-domain"] && resourceData.mode === "http") {
|
if (
|
||||||
|
resourceData["full-domain"] &&
|
||||||
|
(resourceData.mode === "http" ||
|
||||||
|
resourceData.mode === "inference")
|
||||||
|
) {
|
||||||
domainInfo = await getDomainForSiteResource(
|
domainInfo = await getDomainForSiteResource(
|
||||||
existingResource.siteResourceId,
|
existingResource.siteResourceId,
|
||||||
resourceData["full-domain"],
|
resourceData["full-domain"],
|
||||||
orgId,
|
orgId,
|
||||||
|
resourceData.mode === "inference",
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resourceData.alias) {
|
||||||
|
const [aliasConflict] = await trx
|
||||||
|
.select({
|
||||||
|
siteResourceId: siteResources.siteResourceId
|
||||||
|
})
|
||||||
|
.from(siteResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(siteResources.orgId, orgId),
|
||||||
|
eq(siteResources.alias, resourceData.alias),
|
||||||
|
ne(
|
||||||
|
siteResources.siteResourceId,
|
||||||
|
existingResource.siteResourceId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (aliasConflict) {
|
||||||
|
throw new Error(
|
||||||
|
`Alias ${resourceData.alias} already in use by another site resource in org ${orgId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInference = resourceData.mode === "inference";
|
||||||
|
|
||||||
// Update existing resource
|
// Update existing resource
|
||||||
const [updatedResource] = await trx
|
const [updatedResource] = await trx
|
||||||
.update(siteResources)
|
.update(siteResources)
|
||||||
.set({
|
.set({
|
||||||
name: resourceData.name || resourceNiceId,
|
name: resourceData.name || resourceNiceId,
|
||||||
mode: resourceData.mode,
|
mode: resourceData.mode,
|
||||||
ssl: resourceData.ssl,
|
ssl: resourceSsl,
|
||||||
scheme: resourceData.scheme,
|
scheme: resourceData.scheme,
|
||||||
destination: resourceData.destination,
|
destination: resourceData.destination,
|
||||||
destinationPort: resourceData["destination-port"],
|
destinationPort: resourceData["destination-port"],
|
||||||
enabled: true, // hardcoded for now
|
enabled: resourceEnabled,
|
||||||
// enabled: resourceData.enabled ?? true,
|
|
||||||
alias: resourceData.alias || null,
|
alias: resourceData.alias || null,
|
||||||
disableIcmp:
|
disableIcmp:
|
||||||
resourceData["disable-icmp"] ||
|
resourceData["disable-icmp"] ||
|
||||||
(resourceData.mode == "http" ? true : false), // default to true for http resources, otherwise false
|
(resourceData.mode == "http" || isInference
|
||||||
|
? true
|
||||||
|
: false), // default to true for http/inference resources, otherwise false
|
||||||
tcpPortRangeString:
|
tcpPortRangeString:
|
||||||
resourceData.mode == "http"
|
resourceData.mode == "http" || isInference
|
||||||
? "443,80"
|
? "443,80"
|
||||||
: resourceData["tcp-ports"],
|
: resourceData["tcp-ports"],
|
||||||
udpPortRangeString:
|
udpPortRangeString:
|
||||||
resourceData.mode == "http"
|
resourceData.mode == "http" || isInference
|
||||||
? ""
|
? ""
|
||||||
: resourceData["udp-ports"],
|
: resourceData["udp-ports"],
|
||||||
fullDomain: resourceData["full-domain"] || null,
|
fullDomain: resourceData["full-domain"] || null,
|
||||||
@@ -263,7 +292,10 @@ export async function updatePrivateResources(
|
|||||||
pamMode: resourceData["auth-daemon"]?.pam || "passthrough",
|
pamMode: resourceData["auth-daemon"]?.pam || "passthrough",
|
||||||
authDaemonMode:
|
authDaemonMode:
|
||||||
resourceData["auth-daemon"]?.mode || "native",
|
resourceData["auth-daemon"]?.mode || "native",
|
||||||
authDaemonPort: resourceData["auth-daemon"]?.port || 22123
|
authDaemonPort: resourceData["auth-daemon"]?.port || 22123,
|
||||||
|
status: resourceStatusFromSite,
|
||||||
|
networkId: isInference ? null : undefined,
|
||||||
|
requiresExitNodeConnection: isInference
|
||||||
})
|
})
|
||||||
.where(
|
.where(
|
||||||
eq(
|
eq(
|
||||||
@@ -275,7 +307,19 @@ export async function updatePrivateResources(
|
|||||||
|
|
||||||
const siteResourceId = existingResource.siteResourceId;
|
const siteResourceId = existingResource.siteResourceId;
|
||||||
|
|
||||||
if (updatedResource.networkId) {
|
if (isInference) {
|
||||||
|
// inference resources are not attached to any site network
|
||||||
|
if (existingResource.networkId) {
|
||||||
|
await trx
|
||||||
|
.delete(siteNetworks)
|
||||||
|
.where(
|
||||||
|
eq(
|
||||||
|
siteNetworks.networkId,
|
||||||
|
existingResource.networkId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (updatedResource.networkId) {
|
||||||
await trx
|
await trx
|
||||||
.delete(siteNetworks)
|
.delete(siteNetworks)
|
||||||
.where(
|
.where(
|
||||||
@@ -290,6 +334,28 @@ export async function updatePrivateResources(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await syncInferenceAiConfig({
|
||||||
|
orgId,
|
||||||
|
trx,
|
||||||
|
mode: resourceData.mode,
|
||||||
|
scope: "site",
|
||||||
|
siteResourceId,
|
||||||
|
providers: resourceData["ai-providers"].map((p) => ({
|
||||||
|
provider: p.provider,
|
||||||
|
accessMode: p["access-mode"],
|
||||||
|
enabled: p.enabled,
|
||||||
|
models: p.models
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
await syncAiBudgets({
|
||||||
|
orgId,
|
||||||
|
trx,
|
||||||
|
scope: "site",
|
||||||
|
siteResourceId,
|
||||||
|
budgets: resourceData["ai-budget"]
|
||||||
|
});
|
||||||
|
|
||||||
await trx
|
await trx
|
||||||
.delete(clientSiteResources)
|
.delete(clientSiteResources)
|
||||||
.where(eq(clientSiteResources.siteResourceId, siteResourceId));
|
.where(eq(clientSiteResources.siteResourceId, siteResourceId));
|
||||||
@@ -412,6 +478,13 @@ export async function updatePrivateResources(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const labelIds = await getOrCreateLabelIds(
|
||||||
|
orgId,
|
||||||
|
resourceData.labels,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
await syncSiteResourceLabels(siteResourceId, labelIds, trx);
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
newSiteResource: updatedResource,
|
newSiteResource: updatedResource,
|
||||||
oldSiteResource: existingResource,
|
oldSiteResource: existingResource,
|
||||||
@@ -462,25 +535,55 @@ export async function updatePrivateResources(
|
|||||||
releaseAliasLock = release;
|
releaseAliasLock = release;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isInference = resourceData.mode === "inference";
|
||||||
|
|
||||||
let domainInfo:
|
let domainInfo:
|
||||||
| { subdomain: string | null; domainId: string }
|
| { subdomain: string | null; domainId: string }
|
||||||
| undefined;
|
| undefined;
|
||||||
if (resourceData["full-domain"] && resourceData.mode === "http") {
|
if (
|
||||||
|
resourceData["full-domain"] &&
|
||||||
|
(resourceData.mode === "http" || isInference)
|
||||||
|
) {
|
||||||
domainInfo = await getDomainForSiteResource(
|
domainInfo = await getDomainForSiteResource(
|
||||||
undefined,
|
undefined,
|
||||||
resourceData["full-domain"],
|
resourceData["full-domain"],
|
||||||
orgId,
|
orgId,
|
||||||
|
isInference,
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [network] = await trx
|
if (resourceData.alias) {
|
||||||
.insert(networks)
|
const [aliasConflict] = await trx
|
||||||
.values({
|
.select({
|
||||||
scope: "resource",
|
siteResourceId: siteResources.siteResourceId
|
||||||
orgId: orgId
|
})
|
||||||
})
|
.from(siteResources)
|
||||||
.returning();
|
.where(
|
||||||
|
and(
|
||||||
|
eq(siteResources.orgId, orgId),
|
||||||
|
eq(siteResources.alias, resourceData.alias)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (aliasConflict) {
|
||||||
|
throw new Error(
|
||||||
|
`Alias ${resourceData.alias} already in use by another site resource in org ${orgId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let network: typeof networks.$inferSelect | undefined;
|
||||||
|
if (!isInference) {
|
||||||
|
[network] = await trx
|
||||||
|
.insert(networks)
|
||||||
|
.values({
|
||||||
|
scope: "resource",
|
||||||
|
orgId: orgId
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
}
|
||||||
|
|
||||||
// Create new resource
|
// Create new resource
|
||||||
const [newResource] = await trx
|
const [newResource] = await trx
|
||||||
@@ -488,27 +591,28 @@ export async function updatePrivateResources(
|
|||||||
.values({
|
.values({
|
||||||
orgId: orgId,
|
orgId: orgId,
|
||||||
niceId: resourceNiceId,
|
niceId: resourceNiceId,
|
||||||
networkId: network.networkId,
|
networkId: network ? network.networkId : null,
|
||||||
defaultNetworkId: network.networkId,
|
defaultNetworkId: network ? network.networkId : null,
|
||||||
name: resourceData.name || resourceNiceId,
|
name: resourceData.name || resourceNiceId,
|
||||||
mode: resourceData.mode,
|
mode: resourceData.mode,
|
||||||
ssl: resourceData.ssl,
|
ssl: resourceSsl,
|
||||||
scheme: resourceData.scheme,
|
scheme: resourceData.scheme,
|
||||||
destination: resourceData.destination,
|
destination: resourceData.destination,
|
||||||
destinationPort: resourceData["destination-port"],
|
destinationPort: resourceData["destination-port"],
|
||||||
enabled: true, // hardcoded for now
|
enabled: resourceEnabled,
|
||||||
// enabled: resourceData.enabled ?? true,
|
|
||||||
alias: resourceData.alias || null,
|
alias: resourceData.alias || null,
|
||||||
aliasAddress: aliasAddress,
|
aliasAddress: aliasAddress,
|
||||||
disableIcmp:
|
disableIcmp:
|
||||||
resourceData["disable-icmp"] ||
|
resourceData["disable-icmp"] ||
|
||||||
(resourceData.mode == "http" ? true : false), // default to true for http resources, otherwise false
|
(resourceData.mode == "http" || isInference
|
||||||
|
? true
|
||||||
|
: false), // default to true for http/inference resources, otherwise false
|
||||||
tcpPortRangeString:
|
tcpPortRangeString:
|
||||||
resourceData.mode == "http"
|
resourceData.mode == "http" || isInference
|
||||||
? "443,80"
|
? "443,80"
|
||||||
: resourceData["tcp-ports"],
|
: resourceData["tcp-ports"],
|
||||||
udpPortRangeString:
|
udpPortRangeString:
|
||||||
resourceData.mode == "http"
|
resourceData.mode == "http" || isInference
|
||||||
? ""
|
? ""
|
||||||
: resourceData["udp-ports"],
|
: resourceData["udp-ports"],
|
||||||
fullDomain: resourceData["full-domain"] || null,
|
fullDomain: resourceData["full-domain"] || null,
|
||||||
@@ -517,7 +621,9 @@ export async function updatePrivateResources(
|
|||||||
pamMode: resourceData["auth-daemon"]?.pam || "passthrough",
|
pamMode: resourceData["auth-daemon"]?.pam || "passthrough",
|
||||||
authDaemonMode:
|
authDaemonMode:
|
||||||
resourceData["auth-daemon"]?.mode || "native",
|
resourceData["auth-daemon"]?.mode || "native",
|
||||||
authDaemonPort: resourceData["auth-daemon"]?.port || 22123
|
authDaemonPort: resourceData["auth-daemon"]?.port || 22123,
|
||||||
|
status: resourceStatusFromSite,
|
||||||
|
requiresExitNodeConnection: isInference
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
@@ -525,13 +631,37 @@ export async function updatePrivateResources(
|
|||||||
|
|
||||||
const siteResourceId = newResource.siteResourceId;
|
const siteResourceId = newResource.siteResourceId;
|
||||||
|
|
||||||
for (const site of allSites) {
|
if (network) {
|
||||||
await trx.insert(siteNetworks).values({
|
for (const site of allSites) {
|
||||||
siteId: site.siteId,
|
await trx.insert(siteNetworks).values({
|
||||||
networkId: network.networkId
|
siteId: site.siteId,
|
||||||
});
|
networkId: network.networkId
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await syncInferenceAiConfig({
|
||||||
|
orgId,
|
||||||
|
trx,
|
||||||
|
mode: resourceData.mode,
|
||||||
|
scope: "site",
|
||||||
|
siteResourceId,
|
||||||
|
providers: resourceData["ai-providers"].map((p) => ({
|
||||||
|
provider: p.provider,
|
||||||
|
accessMode: p["access-mode"],
|
||||||
|
enabled: p.enabled,
|
||||||
|
models: p.models
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
await syncAiBudgets({
|
||||||
|
orgId,
|
||||||
|
trx,
|
||||||
|
scope: "site",
|
||||||
|
siteResourceId,
|
||||||
|
budgets: resourceData["ai-budget"]
|
||||||
|
});
|
||||||
|
|
||||||
const [adminRole] = await trx
|
const [adminRole] = await trx
|
||||||
.select()
|
.select()
|
||||||
.from(roles)
|
.from(roles)
|
||||||
@@ -645,6 +775,13 @@ export async function updatePrivateResources(
|
|||||||
|
|
||||||
await usageService.add(orgId, LimitId.PRIVATE_RESOURCES, 1, trx);
|
await usageService.add(orgId, LimitId.PRIVATE_RESOURCES, 1, trx);
|
||||||
|
|
||||||
|
const labelIds = await getOrCreateLabelIds(
|
||||||
|
orgId,
|
||||||
|
resourceData.labels,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
await syncSiteResourceLabels(siteResourceId, labelIds, trx);
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
newSiteResource: newResource,
|
newSiteResource: newResource,
|
||||||
newSites: allSites,
|
newSites: allSites,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
||||||
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
import { createCertificate } from "@server/routers/certificates/createCertificate";
|
||||||
import { hashPassword } from "@server/auth/password";
|
import { hashPassword } from "@server/auth/password";
|
||||||
import { generateId } from "@server/auth/sessions/app";
|
import { generateId } from "@server/auth/sessions/app";
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
rolePolicies,
|
rolePolicies,
|
||||||
roleResources,
|
roleResources,
|
||||||
roles,
|
roles,
|
||||||
|
Site,
|
||||||
sites,
|
sites,
|
||||||
Target,
|
Target,
|
||||||
TargetHealthCheck,
|
TargetHealthCheck,
|
||||||
@@ -49,11 +50,11 @@ import { and, asc, eq, isNotNull, ne, or } from "drizzle-orm";
|
|||||||
import { tierMatrix } from "../billing/tierMatrix";
|
import { tierMatrix } from "../billing/tierMatrix";
|
||||||
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
|
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
|
||||||
import { Config, isTargetsOnlyResource, TargetData } from "./types";
|
import { Config, isTargetsOnlyResource, TargetData } from "./types";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import { getOrCreateLabelIds, syncResourceLabels } from "./labels";
|
||||||
import createHttpError from "http-errors";
|
|
||||||
import next from "next";
|
|
||||||
import { LimitId } from "../billing";
|
import { LimitId } from "../billing";
|
||||||
import { usageService } from "../billing/usageService";
|
import { usageService } from "../billing/usageService";
|
||||||
|
import { syncInferenceAiConfig } from "./aiProviders";
|
||||||
|
import { syncAiBudgets } from "./aiBudgets";
|
||||||
|
|
||||||
export type PublicResourcesResults = {
|
export type PublicResourcesResults = {
|
||||||
proxyResource: Resource;
|
proxyResource: Resource;
|
||||||
@@ -74,19 +75,40 @@ export async function updatePublicResources(
|
|||||||
)) {
|
)) {
|
||||||
const targetsToUpdate: Target[] = [];
|
const targetsToUpdate: Target[] = [];
|
||||||
const healthchecksToUpdate: TargetHealthCheck[] = [];
|
const healthchecksToUpdate: TargetHealthCheck[] = [];
|
||||||
|
|
||||||
let resource: Resource;
|
let resource: Resource;
|
||||||
|
let resourceStatusFromSite: "approved" | "pending" = "approved";
|
||||||
|
let providedSite: Partial<Site> | undefined;
|
||||||
|
if (siteId) {
|
||||||
|
// Use the provided siteId directly, but verify it belongs to the org
|
||||||
|
[providedSite] = await trx
|
||||||
|
.select({
|
||||||
|
siteId: sites.siteId,
|
||||||
|
type: sites.type,
|
||||||
|
status: sites.status
|
||||||
|
})
|
||||||
|
.from(sites)
|
||||||
|
.where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId)))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
resourceStatusFromSite = providedSite?.status ?? "approved";
|
||||||
|
}
|
||||||
|
|
||||||
async function createTarget( // reusable function to create a target
|
async function createTarget( // reusable function to create a target
|
||||||
resourceId: number,
|
resourceId: number,
|
||||||
targetData: TargetData
|
targetData: TargetData
|
||||||
) {
|
) {
|
||||||
const targetSiteId = targetData.site;
|
const targetSiteId = targetData.site;
|
||||||
let site;
|
let site: Partial<Site> | undefined;
|
||||||
|
|
||||||
if (targetSiteId) {
|
if (targetSiteId) {
|
||||||
// Look up site by niceId
|
// Look up site by niceId
|
||||||
[site] = await trx
|
[site] = await trx
|
||||||
.select({ siteId: sites.siteId, type: sites.type })
|
.select({
|
||||||
|
siteId: sites.siteId,
|
||||||
|
type: sites.type,
|
||||||
|
status: sites.status
|
||||||
|
})
|
||||||
.from(sites)
|
.from(sites)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
@@ -95,15 +117,9 @@ export async function updatePublicResources(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
} else if (siteId) {
|
} else if (siteId && providedSite) {
|
||||||
// Use the provided siteId directly, but verify it belongs to the org
|
// Use the provided siteId directly, but verify it belongs to the org
|
||||||
[site] = await trx
|
site = providedSite;
|
||||||
.select({ siteId: sites.siteId, type: sites.type })
|
|
||||||
.from(sites)
|
|
||||||
.where(
|
|
||||||
and(eq(sites.siteId, siteId), eq(sites.orgId, orgId))
|
|
||||||
)
|
|
||||||
.limit(1);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Target site is required`);
|
throw new Error(`Target site is required`);
|
||||||
}
|
}
|
||||||
@@ -139,7 +155,7 @@ export async function updatePublicResources(
|
|||||||
.insert(targets)
|
.insert(targets)
|
||||||
.values({
|
.values({
|
||||||
resourceId: resourceId,
|
resourceId: resourceId,
|
||||||
siteId: site.siteId,
|
siteId: site.siteId!,
|
||||||
ip: targetData.hostname,
|
ip: targetData.hostname,
|
||||||
mode: resourceData.mode as Target["mode"],
|
mode: resourceData.mode as Target["mode"],
|
||||||
method: targetData.method,
|
method: targetData.method,
|
||||||
@@ -172,7 +188,7 @@ export async function updatePublicResources(
|
|||||||
.insert(targetHealthCheck)
|
.insert(targetHealthCheck)
|
||||||
.values({
|
.values({
|
||||||
name: `${targetData.hostname}:${targetData.port}`,
|
name: `${targetData.hostname}:${targetData.port}`,
|
||||||
siteId: site.siteId,
|
siteId: site.siteId!,
|
||||||
targetId: newTarget.targetId,
|
targetId: newTarget.targetId,
|
||||||
orgId: orgId,
|
orgId: orgId,
|
||||||
hcEnabled: healthcheckData?.enabled || false,
|
hcEnabled: healthcheckData?.enabled || false,
|
||||||
@@ -230,7 +246,10 @@ export async function updatePublicResources(
|
|||||||
const resourceEnabled =
|
const resourceEnabled =
|
||||||
resourceData.enabled == undefined || resourceData.enabled == null
|
resourceData.enabled == undefined || resourceData.enabled == null
|
||||||
? true
|
? true
|
||||||
: resourceData.enabled;
|
: resourceStatusFromSite === "pending"
|
||||||
|
? false
|
||||||
|
: resourceData.enabled;
|
||||||
|
|
||||||
const resourceSsl =
|
const resourceSsl =
|
||||||
resourceData.ssl == undefined || resourceData.ssl == null
|
resourceData.ssl == undefined || resourceData.ssl == null
|
||||||
? true
|
? true
|
||||||
@@ -240,18 +259,6 @@ export async function updatePublicResources(
|
|||||||
headers = JSON.stringify(resourceData.headers);
|
headers = JSON.stringify(resourceData.headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (["ssh", "rdp", "vnc"].includes(resourceData.mode || "")) {
|
|
||||||
const isLicensed = await isLicensedOrSubscribed(
|
|
||||||
orgId,
|
|
||||||
tierMatrix.advancedPublicResources
|
|
||||||
);
|
|
||||||
if (!isLicensed) {
|
|
||||||
throw new Error(
|
|
||||||
"Your current subscription does not support browser gateway resources. Please upgrade to access this feature."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resourceData.policy) {
|
if (resourceData.policy) {
|
||||||
const isLicensed = await isLicensedOrSubscribed(
|
const isLicensed = await isLicensedOrSubscribed(
|
||||||
orgId,
|
orgId,
|
||||||
@@ -267,7 +274,9 @@ export async function updatePublicResources(
|
|||||||
if (existingResource) {
|
if (existingResource) {
|
||||||
let domain;
|
let domain;
|
||||||
if (
|
if (
|
||||||
["http", "ssh", "rdp", "vnc"].includes(resourceData.mode || "")
|
["http", "ssh", "rdp", "vnc", "inference"].includes(
|
||||||
|
resourceData.mode || ""
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
if (resourceData["full-domain"]?.startsWith("*.")) {
|
if (resourceData["full-domain"]?.startsWith("*.")) {
|
||||||
const isLicensed = await isLicensedOrSubscribed(
|
const isLicensed = await isLicensedOrSubscribed(
|
||||||
@@ -285,6 +294,7 @@ export async function updatePublicResources(
|
|||||||
existingResource.resourceId,
|
existingResource.resourceId,
|
||||||
resourceData["full-domain"]!,
|
resourceData["full-domain"]!,
|
||||||
orgId,
|
orgId,
|
||||||
|
resourceData.mode === "inference",
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -306,7 +316,7 @@ export async function updatePublicResources(
|
|||||||
|
|
||||||
const isLicensed = await isLicensedOrSubscribed(
|
const isLicensed = await isLicensedOrSubscribed(
|
||||||
orgId,
|
orgId,
|
||||||
tierMatrix.maintencePage
|
tierMatrix.maintenancePage
|
||||||
);
|
);
|
||||||
if (!isLicensed) {
|
if (!isLicensed) {
|
||||||
resourceData.maintenance = undefined;
|
resourceData.maintenance = undefined;
|
||||||
@@ -351,14 +361,22 @@ export async function updatePublicResources(
|
|||||||
name: resourceData.name || "Unnamed Resource",
|
name: resourceData.name || "Unnamed Resource",
|
||||||
|
|
||||||
mode: resourceData.mode,
|
mode: resourceData.mode,
|
||||||
proxyPort: ["http", "ssh", "rdp", "vnc"].includes(
|
proxyPort: [
|
||||||
resourceData.mode || ""
|
"http",
|
||||||
)
|
"ssh",
|
||||||
|
"rdp",
|
||||||
|
"vnc",
|
||||||
|
"inference"
|
||||||
|
].includes(resourceData.mode || "")
|
||||||
? null
|
? null
|
||||||
: resourceData["proxy-port"],
|
: resourceData["proxy-port"],
|
||||||
fullDomain: ["http", "ssh", "rdp", "vnc"].includes(
|
fullDomain: [
|
||||||
resourceData.mode || ""
|
"http",
|
||||||
)
|
"ssh",
|
||||||
|
"rdp",
|
||||||
|
"vnc",
|
||||||
|
"inference"
|
||||||
|
].includes(resourceData.mode || "")
|
||||||
? resourceData["full-domain"]
|
? resourceData["full-domain"]
|
||||||
: null,
|
: null,
|
||||||
subdomain: domain ? domain.subdomain : null,
|
subdomain: domain ? domain.subdomain : null,
|
||||||
@@ -406,7 +424,8 @@ export async function updatePublicResources(
|
|||||||
? (resourceData["proxy-protocol-version"] ??
|
? (resourceData["proxy-protocol-version"] ??
|
||||||
1)
|
1)
|
||||||
: 1,
|
: 1,
|
||||||
resourcePolicyId: sharedPolicy.resourcePolicyId
|
resourcePolicyId: sharedPolicy.resourcePolicyId,
|
||||||
|
status: resourceStatusFromSite
|
||||||
})
|
})
|
||||||
.where(
|
.where(
|
||||||
eq(
|
eq(
|
||||||
@@ -546,14 +565,23 @@ export async function updatePublicResources(
|
|||||||
.update(resources)
|
.update(resources)
|
||||||
.set({
|
.set({
|
||||||
name: resourceData.name || "Unnamed Resource",
|
name: resourceData.name || "Unnamed Resource",
|
||||||
proxyPort: ["http", "ssh", "rdp", "vnc"].includes(
|
mode: resourceData.mode,
|
||||||
resourceData.mode || ""
|
proxyPort: [
|
||||||
)
|
"http",
|
||||||
|
"ssh",
|
||||||
|
"rdp",
|
||||||
|
"vnc",
|
||||||
|
"inference"
|
||||||
|
].includes(resourceData.mode || "")
|
||||||
? null
|
? null
|
||||||
: resourceData["proxy-port"],
|
: resourceData["proxy-port"],
|
||||||
fullDomain: ["http", "ssh", "rdp", "vnc"].includes(
|
fullDomain: [
|
||||||
resourceData.mode || ""
|
"http",
|
||||||
)
|
"ssh",
|
||||||
|
"rdp",
|
||||||
|
"vnc",
|
||||||
|
"inference"
|
||||||
|
].includes(resourceData.mode || "")
|
||||||
? resourceData["full-domain"]
|
? resourceData["full-domain"]
|
||||||
: null,
|
: null,
|
||||||
subdomain: domain ? domain.subdomain : null,
|
subdomain: domain ? domain.subdomain : null,
|
||||||
@@ -590,7 +618,8 @@ export async function updatePublicResources(
|
|||||||
authDaemonPort:
|
authDaemonPort:
|
||||||
resourceData["auth-daemon"]?.port || 22123,
|
resourceData["auth-daemon"]?.port || 22123,
|
||||||
resourcePolicyId: null,
|
resourcePolicyId: null,
|
||||||
defaultResourcePolicyId: inlinePolicyId
|
defaultResourcePolicyId: inlinePolicyId,
|
||||||
|
status: resourceStatusFromSite
|
||||||
})
|
})
|
||||||
.where(
|
.where(
|
||||||
eq(
|
eq(
|
||||||
@@ -652,6 +681,30 @@ export async function updatePublicResources(
|
|||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await syncInferenceAiConfig({
|
||||||
|
orgId,
|
||||||
|
trx,
|
||||||
|
mode: resourceData.mode || "",
|
||||||
|
scope: "public",
|
||||||
|
resourceId: existingResource.resourceId,
|
||||||
|
providers: (resourceData["ai-providers"] || []).map(
|
||||||
|
(p) => ({
|
||||||
|
provider: p.provider,
|
||||||
|
accessMode: p["access-mode"],
|
||||||
|
enabled: p.enabled,
|
||||||
|
models: p.models
|
||||||
|
})
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
await syncAiBudgets({
|
||||||
|
orgId,
|
||||||
|
trx,
|
||||||
|
scope: "public",
|
||||||
|
resourceId: existingResource.resourceId,
|
||||||
|
budgets: resourceData["ai-budget"] || []
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingResourceTargets = await trx
|
const existingResourceTargets = await trx
|
||||||
@@ -732,7 +785,7 @@ export async function updatePublicResources(
|
|||||||
: undefined),
|
: undefined),
|
||||||
rewritePathType: targetData["rewrite-match"],
|
rewritePathType: targetData["rewrite-match"],
|
||||||
priority: targetData.priority,
|
priority: targetData.priority,
|
||||||
mode: resourceData.mode
|
mode: resourceData.mode as Target["mode"]
|
||||||
})
|
})
|
||||||
.where(eq(targets.targetId, existingTarget.targetId))
|
.where(eq(targets.targetId, existingTarget.targetId))
|
||||||
.returning();
|
.returning();
|
||||||
@@ -1037,7 +1090,9 @@ export async function updatePublicResources(
|
|||||||
|
|
||||||
let domain;
|
let domain;
|
||||||
if (
|
if (
|
||||||
["http", "ssh", "rdp", "vnc"].includes(resourceData.mode || "")
|
["http", "ssh", "rdp", "vnc", "inference"].includes(
|
||||||
|
resourceData.mode || ""
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
if (resourceData["full-domain"]?.startsWith("*.")) {
|
if (resourceData["full-domain"]?.startsWith("*.")) {
|
||||||
const isLicensed = await isLicensedOrSubscribed(
|
const isLicensed = await isLicensedOrSubscribed(
|
||||||
@@ -1055,6 +1110,7 @@ export async function updatePublicResources(
|
|||||||
undefined,
|
undefined,
|
||||||
resourceData["full-domain"]!,
|
resourceData["full-domain"]!,
|
||||||
orgId,
|
orgId,
|
||||||
|
resourceData.mode === "inference",
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1067,7 +1123,7 @@ export async function updatePublicResources(
|
|||||||
|
|
||||||
const isLicensed = await isLicensedOrSubscribed(
|
const isLicensed = await isLicensedOrSubscribed(
|
||||||
orgId,
|
orgId,
|
||||||
tierMatrix.maintencePage
|
tierMatrix.maintenancePage
|
||||||
);
|
);
|
||||||
if (!isLicensed) {
|
if (!isLicensed) {
|
||||||
resourceData.maintenance = undefined;
|
resourceData.maintenance = undefined;
|
||||||
@@ -1131,16 +1187,25 @@ export async function updatePublicResources(
|
|||||||
.values({
|
.values({
|
||||||
orgId,
|
orgId,
|
||||||
niceId: resourceNiceId,
|
niceId: resourceNiceId,
|
||||||
|
status: resourceStatusFromSite,
|
||||||
name: resourceData.name || "Unnamed Resource",
|
name: resourceData.name || "Unnamed Resource",
|
||||||
mode: resourceData.mode,
|
mode: resourceData.mode,
|
||||||
proxyPort: ["http", "ssh", "rdp", "vnc"].includes(
|
proxyPort: [
|
||||||
resourceData.mode || ""
|
"http",
|
||||||
)
|
"ssh",
|
||||||
|
"rdp",
|
||||||
|
"vnc",
|
||||||
|
"inference"
|
||||||
|
].includes(resourceData.mode || "")
|
||||||
? null
|
? null
|
||||||
: resourceData["proxy-port"],
|
: resourceData["proxy-port"],
|
||||||
fullDomain: ["http", "ssh", "rdp", "vnc"].includes(
|
fullDomain: [
|
||||||
resourceData.mode || ""
|
"http",
|
||||||
)
|
"ssh",
|
||||||
|
"rdp",
|
||||||
|
"vnc",
|
||||||
|
"inference"
|
||||||
|
].includes(resourceData.mode || "")
|
||||||
? resourceData["full-domain"]
|
? resourceData["full-domain"]
|
||||||
: null,
|
: null,
|
||||||
subdomain: domain ? domain.subdomain : null,
|
subdomain: domain ? domain.subdomain : null,
|
||||||
@@ -1195,6 +1260,28 @@ export async function updatePublicResources(
|
|||||||
|
|
||||||
resource = newResource;
|
resource = newResource;
|
||||||
|
|
||||||
|
await syncInferenceAiConfig({
|
||||||
|
orgId,
|
||||||
|
trx,
|
||||||
|
mode: resourceData.mode || "",
|
||||||
|
scope: "public",
|
||||||
|
resourceId: newResource.resourceId,
|
||||||
|
providers: (resourceData["ai-providers"] || []).map((p) => ({
|
||||||
|
provider: p.provider,
|
||||||
|
accessMode: p["access-mode"],
|
||||||
|
enabled: p.enabled,
|
||||||
|
models: p.models
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
await syncAiBudgets({
|
||||||
|
orgId,
|
||||||
|
trx,
|
||||||
|
scope: "public",
|
||||||
|
resourceId: newResource.resourceId,
|
||||||
|
budgets: resourceData["ai-budget"] || []
|
||||||
|
});
|
||||||
|
|
||||||
await trx.insert(roleResources).values({
|
await trx.insert(roleResources).values({
|
||||||
roleId: adminRole.roleId,
|
roleId: adminRole.roleId,
|
||||||
resourceId: newResource.resourceId
|
resourceId: newResource.resourceId
|
||||||
@@ -1329,6 +1416,15 @@ export async function updatePublicResources(
|
|||||||
logger.debug(`Created resource ${newResource.resourceId}`);
|
logger.debug(`Created resource ${newResource.resourceId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isTargetsOnlyResource(resourceData)) {
|
||||||
|
const labelIds = await getOrCreateLabelIds(
|
||||||
|
orgId,
|
||||||
|
resourceData.labels || [],
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
await syncResourceLabels(resource.resourceId, labelIds, trx);
|
||||||
|
}
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
proxyResource: resource,
|
proxyResource: resource,
|
||||||
targetsToUpdate,
|
targetsToUpdate,
|
||||||
@@ -2043,6 +2139,7 @@ export async function getDomain(
|
|||||||
resourceId: number | undefined,
|
resourceId: number | undefined,
|
||||||
fullDomain: string,
|
fullDomain: string,
|
||||||
orgId: string,
|
orgId: string,
|
||||||
|
isInference: boolean,
|
||||||
trx: Transaction
|
trx: Transaction
|
||||||
) {
|
) {
|
||||||
const [fullDomainExists] = await trx
|
const [fullDomainExists] = await trx
|
||||||
@@ -2052,6 +2149,14 @@ export async function getDomain(
|
|||||||
and(
|
and(
|
||||||
eq(resources.fullDomain, fullDomain),
|
eq(resources.fullDomain, fullDomain),
|
||||||
eq(resources.orgId, orgId),
|
eq(resources.orgId, orgId),
|
||||||
|
// Inference resources route through the central AI gateway
|
||||||
|
// rather than normal target-based proxying, so they're
|
||||||
|
// allowed to share a full-domain with a non-inference
|
||||||
|
// resource (and vice versa) - only conflicts within the
|
||||||
|
// same routing category are rejected.
|
||||||
|
isInference
|
||||||
|
? ne(resources.mode, "inference")
|
||||||
|
: eq(resources.mode, "inference"),
|
||||||
resourceId
|
resourceId
|
||||||
? ne(resources.resourceId, resourceId)
|
? ne(resources.resourceId, resourceId)
|
||||||
: isNotNull(resources.resourceId)
|
: isNotNull(resources.resourceId)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
idp,
|
|
||||||
idpOrg,
|
|
||||||
resourcePolicies,
|
resourcePolicies,
|
||||||
resourcePolicyHeaderAuth,
|
resourcePolicyHeaderAuth,
|
||||||
resourcePolicyPassword,
|
resourcePolicyPassword,
|
||||||
@@ -20,6 +18,7 @@ import { Config, ResourcePolicyData } from "./types";
|
|||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { getUniqueResourcePolicyName } from "@server/db/names";
|
import { getUniqueResourcePolicyName } from "@server/db/names";
|
||||||
import { hashPassword } from "@server/auth/password";
|
import { hashPassword } from "@server/auth/password";
|
||||||
|
import { idpExistsForOrg } from "@server/lib/idp/idpExistsForOrg";
|
||||||
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
|
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
|
||||||
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
||||||
import { tierMatrix } from "../billing/tierMatrix";
|
import { tierMatrix } from "../billing/tierMatrix";
|
||||||
@@ -71,19 +70,13 @@ export async function updateResourcePolicies(
|
|||||||
|
|
||||||
// Validate auto-login-idp if provided
|
// Validate auto-login-idp if provided
|
||||||
if (policyData["auto-login-idp"]) {
|
if (policyData["auto-login-idp"]) {
|
||||||
const [provider] = await trx
|
const providerExists = await idpExistsForOrg(
|
||||||
.select()
|
policyData["auto-login-idp"],
|
||||||
.from(idp)
|
orgId,
|
||||||
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
trx
|
||||||
.where(
|
);
|
||||||
and(
|
|
||||||
eq(idp.idpId, policyData["auto-login-idp"]),
|
|
||||||
eq(idpOrg.orgId, orgId)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (!provider) {
|
if (!providerExists) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Identity provider not found for policy '${policyNiceId}' in this organization`
|
`Identity provider not found for policy '${policyNiceId}' in this organization`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ import { MaintenanceSchema } from "#dynamic/lib/blueprints/MaintenanceSchema";
|
|||||||
import { isValidRegionId } from "@server/db/regions";
|
import { isValidRegionId } from "@server/db/regions";
|
||||||
import { wildcardSubdomainSchema } from "@server/lib/schemas";
|
import { wildcardSubdomainSchema } from "@server/lib/schemas";
|
||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
|
import {
|
||||||
|
aiBudgetEnforcementSchema,
|
||||||
|
aiBudgetPeriodSchema,
|
||||||
|
aiBudgetUnitSchema
|
||||||
|
} from "@server/routers/aiBudget/validation";
|
||||||
|
|
||||||
const maxmindDbPath = config.getRawConfig().server.maxmind_db_path;
|
const maxmindDbPath = config.getRawConfig().server.maxmind_db_path;
|
||||||
const maxmindAsnPath = config.getRawConfig().server.maxmind_asn_path;
|
const maxmindAsnPath = config.getRawConfig().server.maxmind_asn_path;
|
||||||
@@ -28,7 +33,7 @@ export const TargetHealthCheckSchema = z.object({
|
|||||||
hostname: z.string(),
|
hostname: z.string(),
|
||||||
port: z.int().min(1).max(65535),
|
port: z.int().min(1).max(65535),
|
||||||
enabled: z.boolean().optional().default(true),
|
enabled: z.boolean().optional().default(true),
|
||||||
path: z.string().optional(),
|
path: z.string().optional().default("/"),
|
||||||
scheme: z.string().optional(),
|
scheme: z.string().optional(),
|
||||||
mode: z.string().default("http"),
|
mode: z.string().default("http"),
|
||||||
interval: z.int().default(30),
|
interval: z.int().default(30),
|
||||||
@@ -183,6 +188,56 @@ export const HeaderSchema = z.object({
|
|||||||
value: z.string().min(1)
|
value: z.string().min(1)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const AiProviderAttachmentSchema = z
|
||||||
|
.object({
|
||||||
|
provider: z.string().min(1),
|
||||||
|
"access-mode": z
|
||||||
|
.enum(["inherit", "select"])
|
||||||
|
.optional()
|
||||||
|
.default("inherit"),
|
||||||
|
enabled: z.boolean().optional().default(true),
|
||||||
|
models: z.array(z.string()).optional().default([])
|
||||||
|
})
|
||||||
|
.refine(
|
||||||
|
(provider) => {
|
||||||
|
if (provider.models.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return provider["access-mode"] === "select";
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ["models"],
|
||||||
|
error: "'models' can only be set on a provider with access-mode 'select'"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const AiBudgetSchema = z.object({
|
||||||
|
amount: z.number().positive(),
|
||||||
|
unit: aiBudgetUnitSchema,
|
||||||
|
period: aiBudgetPeriodSchema.optional().default("monthly"),
|
||||||
|
enforcement: aiBudgetEnforcementSchema.optional().default("hard"),
|
||||||
|
enabled: z.boolean().optional().default(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
const aiBudgetArraySchema = z.array(AiBudgetSchema).refine(
|
||||||
|
(budgets) => {
|
||||||
|
const keys = budgets.map((b) => `${b.unit}::${b.period}`);
|
||||||
|
return keys.length === new Set(keys).size;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message:
|
||||||
|
"'ai-budget' entries must not overlap: only one budget per unit/period combination is allowed"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// No default here: an object with only 'targets' set must remain
|
||||||
|
// recognized as a targets-only resource by isTargetsOnlyResource().
|
||||||
|
export const AiBudgetListSchema = aiBudgetArraySchema.optional();
|
||||||
|
|
||||||
|
export const AiBudgetListSchemaWithDefault = aiBudgetArraySchema
|
||||||
|
.optional()
|
||||||
|
.default([]);
|
||||||
|
|
||||||
export const AuthDaemonSchema = z
|
export const AuthDaemonSchema = z
|
||||||
.object({
|
.object({
|
||||||
pam: z.enum(["passthrough", "push"]).optional().default("passthrough"),
|
pam: z.enum(["passthrough", "push"]).optional().default("passthrough"),
|
||||||
@@ -209,7 +264,9 @@ export const PublicResourceSchema = z
|
|||||||
protocol: z
|
protocol: z
|
||||||
.enum(["http", "tcp", "udp", "ssh", "rdp", "vnc"])
|
.enum(["http", "tcp", "udp", "ssh", "rdp", "vnc"])
|
||||||
.optional(), // this was the old one and is now DEPRECATED in favor of the mode
|
.optional(), // this was the old one and is now DEPRECATED in favor of the mode
|
||||||
mode: z.enum(["http", "tcp", "udp", "ssh", "rdp", "vnc"]).optional(),
|
mode: z
|
||||||
|
.enum(["http", "tcp", "udp", "ssh", "rdp", "vnc", "inference"])
|
||||||
|
.optional(),
|
||||||
policy: z.string().optional(),
|
policy: z.string().optional(),
|
||||||
ssl: z.boolean().optional(),
|
ssl: z.boolean().optional(),
|
||||||
scheme: z.enum(["http", "https"]).optional(),
|
scheme: z.enum(["http", "https"]).optional(),
|
||||||
@@ -225,7 +282,10 @@ export const PublicResourceSchema = z
|
|||||||
maintenance: MaintenanceSchema.optional(),
|
maintenance: MaintenanceSchema.optional(),
|
||||||
"auth-daemon": AuthDaemonSchema.optional(),
|
"auth-daemon": AuthDaemonSchema.optional(),
|
||||||
"proxy-protocol": z.boolean().optional(),
|
"proxy-protocol": z.boolean().optional(),
|
||||||
"proxy-protocol-version": z.int().min(1).optional()
|
"proxy-protocol-version": z.int().min(1).optional(),
|
||||||
|
labels: z.array(z.string().min(1)).optional(),
|
||||||
|
"ai-providers": z.array(AiProviderAttachmentSchema).optional(),
|
||||||
|
"ai-budget": AiBudgetListSchema
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(resource) => {
|
(resource) => {
|
||||||
@@ -314,11 +374,13 @@ export const PublicResourceSchema = z
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If protocol/mode is http, ssh, rdp, or vnc, it must have a full-domain
|
// If protocol/mode is http, ssh, rdp, vnc, or inference, it must have a full-domain
|
||||||
const effectiveProtocol = resource.mode ?? resource.protocol;
|
const effectiveProtocol = resource.mode ?? resource.protocol;
|
||||||
if (
|
if (
|
||||||
effectiveProtocol !== undefined &&
|
effectiveProtocol !== undefined &&
|
||||||
["http", "ssh", "rdp", "vnc"].includes(effectiveProtocol)
|
["http", "ssh", "rdp", "vnc", "inference"].includes(
|
||||||
|
effectiveProtocol
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
resource["full-domain"] !== undefined &&
|
resource["full-domain"] !== undefined &&
|
||||||
@@ -329,7 +391,43 @@ export const PublicResourceSchema = z
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ["full-domain"],
|
path: ["full-domain"],
|
||||||
error: "When protocol is 'http', 'ssh', 'rdp', or 'vnc', a 'full-domain' must be provided"
|
error: "When protocol is 'http', 'ssh', 'rdp', 'vnc', or 'inference', a 'full-domain' must be provided"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.refine(
|
||||||
|
(resource) => {
|
||||||
|
if (isTargetsOnlyResource(resource)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const effectiveMode = resource.mode ?? resource.protocol;
|
||||||
|
if (effectiveMode !== "inference") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource.targets.every((target) => target == null);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ["targets"],
|
||||||
|
error: "When mode is 'inference', 'targets' must not be provided"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.refine(
|
||||||
|
(resource) => {
|
||||||
|
if (isTargetsOnlyResource(resource)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const effectiveMode = resource.mode ?? resource.protocol;
|
||||||
|
if (effectiveMode === "inference") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (resource["ai-providers"]?.length ?? 0) === 0;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ["ai-providers"],
|
||||||
|
error: "'ai-providers' can only be set when mode is 'inference'"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.refine(
|
.refine(
|
||||||
@@ -463,14 +561,14 @@ export function isTargetsOnlyResource(resource: any): boolean {
|
|||||||
export const PrivateResourceSchema = z
|
export const PrivateResourceSchema = z
|
||||||
.object({
|
.object({
|
||||||
name: z.string().min(1).max(255),
|
name: z.string().min(1).max(255),
|
||||||
mode: z.enum(["host", "cidr", "http", "ssh"]),
|
mode: z.enum(["host", "cidr", "http", "ssh", "inference"]),
|
||||||
site: z.string().optional(), // DEPRECATED IN FAVOR OF sites
|
site: z.string().optional(), // DEPRECATED IN FAVOR OF sites
|
||||||
sites: z.array(z.string()).optional().default([]),
|
sites: z.array(z.string()).optional().default([]),
|
||||||
// protocol: z.enum(["tcp", "udp"]).optional(),
|
// protocol: z.enum(["tcp", "udp"]).optional(),
|
||||||
// proxyPort: z.int().positive().optional(),
|
// proxyPort: z.int().positive().optional(),
|
||||||
"destination-port": z.int().positive().optional(),
|
"destination-port": z.int().positive().optional(),
|
||||||
destination: z.string().min(1).optional(),
|
destination: z.string().min(1).optional(),
|
||||||
// enabled: z.boolean().default(true),
|
enabled: z.boolean().default(true),
|
||||||
"tcp-ports": portRangeStringSchema.optional().default("*"),
|
"tcp-ports": portRangeStringSchema.optional().default("*"),
|
||||||
"udp-ports": portRangeStringSchema.optional().default("*"),
|
"udp-ports": portRangeStringSchema.optional().default("*"),
|
||||||
"disable-icmp": z.boolean().optional().default(false),
|
"disable-icmp": z.boolean().optional().default(false),
|
||||||
@@ -493,16 +591,26 @@ export const PrivateResourceSchema = z
|
|||||||
}),
|
}),
|
||||||
users: z.array(z.string()).optional().default([]),
|
users: z.array(z.string()).optional().default([]),
|
||||||
machines: z.array(z.string()).optional().default([]),
|
machines: z.array(z.string()).optional().default([]),
|
||||||
"auth-daemon": AuthDaemonSchema.optional()
|
labels: z.array(z.string().min(1)).optional().default([]),
|
||||||
|
"auth-daemon": AuthDaemonSchema.optional(),
|
||||||
|
"ai-providers": z
|
||||||
|
.array(AiProviderAttachmentSchema)
|
||||||
|
.optional()
|
||||||
|
.default([]),
|
||||||
|
"ai-budget": AiBudgetListSchemaWithDefault
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
// destination is optional only for ssh+native; required for everything else
|
// destination is optional only for ssh+native or inference; required for everything else
|
||||||
const isNativeSSH =
|
const isNativeSSH =
|
||||||
data.mode === "ssh" &&
|
data.mode === "ssh" &&
|
||||||
(data["auth-daemon"] === undefined ||
|
(data["auth-daemon"] === undefined ||
|
||||||
data["auth-daemon"].mode === "native");
|
data["auth-daemon"].mode === "native");
|
||||||
if (!isNativeSSH && !data.destination) {
|
if (
|
||||||
|
data.mode !== "inference" &&
|
||||||
|
!isNativeSSH &&
|
||||||
|
!data.destination
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -510,7 +618,19 @@ export const PrivateResourceSchema = z
|
|||||||
{
|
{
|
||||||
path: ["destination"],
|
path: ["destination"],
|
||||||
message:
|
message:
|
||||||
"destination is required unless mode is 'ssh' with auth-daemon mode 'native'"
|
"destination is required unless mode is 'ssh' with auth-daemon mode 'native', or mode is 'inference'"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.refine(
|
||||||
|
(data) => {
|
||||||
|
if (data.mode === "inference") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (data["ai-providers"]?.length ?? 0) === 0;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ["ai-providers"],
|
||||||
|
error: "'ai-providers' can only be set when mode is 'inference'"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.refine(
|
.refine(
|
||||||
@@ -632,7 +752,6 @@ export const ResourcePolicySchema = z.object({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.max(50)
|
|
||||||
.transform((v) => v.map((e) => e.toLowerCase()))
|
.transform((v) => v.map((e) => e.toLowerCase()))
|
||||||
.optional()
|
.optional()
|
||||||
.default([]),
|
.default([]),
|
||||||
@@ -838,3 +957,4 @@ export type Target = z.infer<typeof TargetSchema>;
|
|||||||
export type Resource = z.infer<typeof PublicResourceSchema>;
|
export type Resource = z.infer<typeof PublicResourceSchema>;
|
||||||
export type Config = z.infer<typeof ConfigSchema>;
|
export type Config = z.infer<typeof ConfigSchema>;
|
||||||
export type BlueprintResourcePolicy = z.infer<typeof ResourcePolicySchema>;
|
export type BlueprintResourcePolicy = z.infer<typeof ResourcePolicySchema>;
|
||||||
|
export type BlueprintAiBudget = z.infer<typeof AiBudgetSchema>;
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ export const localCache = new NodeCache({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Log cache statistics periodically for monitoring
|
// Log cache statistics periodically for monitoring
|
||||||
setInterval(() => {
|
// setInterval(() => {
|
||||||
const stats = localCache.getStats();
|
// const stats = localCache.getStats();
|
||||||
logger.debug(
|
// logger.debug(
|
||||||
`Local cache stats - Keys: ${stats.keys}, Hits: ${stats.hits}, Misses: ${stats.misses}, Hit rate: ${stats.hits > 0 ? ((stats.hits / (stats.hits + stats.misses)) * 100).toFixed(2) : 0}%`
|
// `Local cache stats - Keys: ${stats.keys}, Hits: ${stats.hits}, Misses: ${stats.misses}, Hit rate: ${stats.hits > 0 ? ((stats.hits / (stats.hits + stats.misses)) * 100).toFixed(2) : 0}%`
|
||||||
);
|
// );
|
||||||
}, 300000); // Every 5 minutes
|
// }, 300000); // Every 5 minutes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adaptive cache that uses Redis when available in multi-node environments,
|
* Adaptive cache that uses Redis when available in multi-node environments,
|
||||||
@@ -34,9 +34,9 @@ class AdaptiveCache {
|
|||||||
|
|
||||||
// Use local cache as fallback or primary
|
// Use local cache as fallback or primary
|
||||||
const success = localCache.set(key, value, effectiveTtl || 0);
|
const success = localCache.set(key, value, effectiveTtl || 0);
|
||||||
if (success) {
|
// if (success) {
|
||||||
logger.debug(`Set key in local cache: ${key}`);
|
// logger.debug(`Set key in local cache: ${key}`);
|
||||||
}
|
// }
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,11 +48,11 @@ class AdaptiveCache {
|
|||||||
async get<T = any>(key: string): Promise<T | undefined> {
|
async get<T = any>(key: string): Promise<T | undefined> {
|
||||||
// Use local cache as fallback or primary
|
// Use local cache as fallback or primary
|
||||||
const value = localCache.get<T>(key);
|
const value = localCache.get<T>(key);
|
||||||
if (value !== undefined) {
|
// if (value !== undefined) {
|
||||||
logger.debug(`Cache hit in local cache: ${key}`);
|
// logger.debug(`Cache hit in local cache: ${key}`);
|
||||||
} else {
|
// } else {
|
||||||
logger.debug(`Cache miss in local cache: ${key}`);
|
// logger.debug(`Cache miss in local cache: ${key}`);
|
||||||
}
|
// }
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,5 +168,5 @@ class AdaptiveCache {
|
|||||||
|
|
||||||
// Export singleton instance
|
// Export singleton instance
|
||||||
export const cache = new AdaptiveCache();
|
export const cache = new AdaptiveCache();
|
||||||
export const regionalCache = cache; // Alias for compatability with the private version
|
export const regionalCache = cache; // Alias for compatibility with the private version
|
||||||
export default cache;
|
export default cache;
|
||||||
|
|||||||
@@ -339,19 +339,6 @@ export async function calculateUserClientsForOrgs(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get exit nodes for this org
|
|
||||||
const exitNodesList = await getExitNodes(orgId);
|
|
||||||
|
|
||||||
if (exitNodesList.length === 0) {
|
|
||||||
logger.warn(
|
|
||||||
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): no exit nodes found`
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const randomExitNode =
|
|
||||||
exitNodesList[Math.floor(Math.random() * exitNodesList.length)];
|
|
||||||
|
|
||||||
// Get next available subnet
|
// Get next available subnet
|
||||||
const { value: newSubnet, release: releaseSubnetLock } =
|
const { value: newSubnet, release: releaseSubnetLock } =
|
||||||
await getNextAvailableClientSubnet(orgId, trx);
|
await getNextAvailableClientSubnet(orgId, trx);
|
||||||
@@ -370,7 +357,6 @@ export async function calculateUserClientsForOrgs(
|
|||||||
const newClientData: InferInsertModel<typeof clients> = {
|
const newClientData: InferInsertModel<typeof clients> = {
|
||||||
userId,
|
userId,
|
||||||
orgId: userOrg.orgId,
|
orgId: userOrg.orgId,
|
||||||
exitNodeId: randomExitNode.exitNodeId,
|
|
||||||
name: olm.name || "User Client",
|
name: olm.name || "User Client",
|
||||||
subnet: updatedSubnet,
|
subnet: updatedSubnet,
|
||||||
olmId: olm.olmId,
|
olmId: olm.olmId,
|
||||||
|
|||||||
@@ -1,16 +1,226 @@
|
|||||||
|
import config from "@server/lib/config";
|
||||||
|
import { certificates, db } from "@server/db";
|
||||||
|
import { and, eq, isNotNull, or, inArray, sql } from "drizzle-orm";
|
||||||
|
import { decrypt } from "@server/lib/crypto";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import { regionalCache as cache } from "#dynamic/lib/cache";
|
||||||
|
import { build } from "@server/build";
|
||||||
|
|
||||||
|
// Define the return type for clarity and type safety
|
||||||
|
export type CertificateResult = {
|
||||||
|
id: number;
|
||||||
|
domain: string;
|
||||||
|
queriedDomain: string; // The domain that was originally requested (may differ for wildcards)
|
||||||
|
wildcard: boolean | null;
|
||||||
|
certFile: string | null;
|
||||||
|
keyFile: string | null;
|
||||||
|
expiresAt: number | null;
|
||||||
|
updatedAt?: number | null;
|
||||||
|
};
|
||||||
|
|
||||||
export async function getValidCertificatesForDomains(
|
export async function getValidCertificatesForDomains(
|
||||||
domains: Set<string>,
|
domains: Set<string>,
|
||||||
useCache: boolean = true
|
useCache: boolean = true
|
||||||
): Promise<
|
): Promise<Array<CertificateResult>> {
|
||||||
Array<{
|
const finalResults: CertificateResult[] = [];
|
||||||
id: number;
|
const domainsToQuery = new Set<string>();
|
||||||
domain: string;
|
|
||||||
wildcard: boolean | null;
|
// 1. Check cache first if enabled
|
||||||
certFile: string | null;
|
if (useCache) {
|
||||||
keyFile: string | null;
|
for (const domain of domains) {
|
||||||
expiresAt: number | null;
|
const cacheKey = `cert:${domain}`;
|
||||||
updatedAt?: number | null;
|
const cachedCert = await cache.get<CertificateResult>(cacheKey);
|
||||||
}>
|
if (cachedCert) {
|
||||||
> {
|
finalResults.push(cachedCert); // Valid cache hit
|
||||||
return []; // stub
|
} else {
|
||||||
|
// Also check for a wildcard cache entry covering this domain's parent
|
||||||
|
const parts = domain.split(".");
|
||||||
|
let wildcardHit = false;
|
||||||
|
if (parts.length > 1) {
|
||||||
|
const parentDomain = parts.slice(1).join(".");
|
||||||
|
const wildcardCacheKey = `cert:*.${parentDomain}`;
|
||||||
|
const cachedWildcard =
|
||||||
|
await cache.get<CertificateResult>(wildcardCacheKey);
|
||||||
|
if (cachedWildcard) {
|
||||||
|
// Re-stamp queriedDomain so callers see the originally requested domain
|
||||||
|
finalResults.push({
|
||||||
|
...cachedWildcard,
|
||||||
|
queriedDomain: domain
|
||||||
|
});
|
||||||
|
wildcardHit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!wildcardHit) {
|
||||||
|
domainsToQuery.add(domain); // Cache miss or expired
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If caching is disabled, add all domains to the query set
|
||||||
|
domains.forEach((d) => domainsToQuery.add(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. If all domains were resolved from the cache, return early
|
||||||
|
if (domainsToQuery.size === 0) {
|
||||||
|
const decryptedResults = decryptFinalResults(
|
||||||
|
finalResults,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
return decryptedResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Prepare domains for the database query
|
||||||
|
const domainsToQueryArray = Array.from(domainsToQuery);
|
||||||
|
const parentDomainsToQuery = new Set<string>();
|
||||||
|
|
||||||
|
domainsToQueryArray.forEach((domain) => {
|
||||||
|
const parts = domain.split(".");
|
||||||
|
// A wildcard can only match a domain with at least two parts (e.g., example.com)
|
||||||
|
if (parts.length > 1) {
|
||||||
|
parentDomainsToQuery.add(parts.slice(1).join("."));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const parentDomainsArray = Array.from(parentDomainsToQuery);
|
||||||
|
|
||||||
|
// Build wildcard variants: for each parent domain "example.com", also query "*.example.com"
|
||||||
|
const wildcardPrefixedArray =
|
||||||
|
build != "saas" ? parentDomainsArray.map((d) => `*.${d}`) : [];
|
||||||
|
|
||||||
|
// 4. Build and execute a single, efficient Drizzle query
|
||||||
|
// This query fetches all potential exact and wildcard matches in one database round-trip.
|
||||||
|
const potentialCerts = await db
|
||||||
|
.select()
|
||||||
|
.from(certificates)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(certificates.status, "valid"),
|
||||||
|
isNotNull(certificates.certFile),
|
||||||
|
isNotNull(certificates.keyFile),
|
||||||
|
or(
|
||||||
|
// Condition for exact matches on the requested domains
|
||||||
|
inArray(certificates.domain, domainsToQueryArray),
|
||||||
|
// Condition for wildcard matches on the parent domains (stored as "example.com" or "*.example.com")
|
||||||
|
parentDomainsArray.length > 0
|
||||||
|
? and(
|
||||||
|
inArray(certificates.domain, [
|
||||||
|
...parentDomainsArray,
|
||||||
|
...wildcardPrefixedArray
|
||||||
|
]),
|
||||||
|
eq(certificates.wildcard, true)
|
||||||
|
)
|
||||||
|
: // If there are no possible parent domains, this condition is false
|
||||||
|
sql`false`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Helper to normalize a wildcard cert's domain to its bare parent domain (strips leading "*.")
|
||||||
|
const normalizeWildcardDomain = (domain: string): string =>
|
||||||
|
domain.startsWith("*.") ? domain.slice(2) : domain;
|
||||||
|
|
||||||
|
// 5. Process the database results, prioritizing exact matches over wildcards
|
||||||
|
const exactMatches = new Map<string, (typeof potentialCerts)[0]>();
|
||||||
|
const wildcardMatches = new Map<string, (typeof potentialCerts)[0]>();
|
||||||
|
|
||||||
|
for (const cert of potentialCerts) {
|
||||||
|
if (cert.wildcard) {
|
||||||
|
// Normalize to bare parent domain so lookups are consistent regardless of storage format
|
||||||
|
wildcardMatches.set(normalizeWildcardDomain(cert.domain), cert);
|
||||||
|
} else {
|
||||||
|
exactMatches.set(cert.domain, cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const domain of domainsToQuery) {
|
||||||
|
let foundCert: (typeof potentialCerts)[0] | undefined = undefined;
|
||||||
|
|
||||||
|
// Priority 1: Check for an exact match (non-wildcard)
|
||||||
|
if (exactMatches.has(domain)) {
|
||||||
|
foundCert = exactMatches.get(domain);
|
||||||
|
}
|
||||||
|
// Priority 2: Check for a wildcard certificate whose normalized domain equals the queried domain
|
||||||
|
else {
|
||||||
|
const normalizedDomain = normalizeWildcardDomain(domain);
|
||||||
|
if (wildcardMatches.has(normalizedDomain)) {
|
||||||
|
foundCert = wildcardMatches.get(normalizedDomain);
|
||||||
|
}
|
||||||
|
// Priority 3: Check for a wildcard match on the parent domain
|
||||||
|
else {
|
||||||
|
const parts = normalizedDomain.split(".");
|
||||||
|
if (parts.length > 1) {
|
||||||
|
const parentDomain = parts.slice(1).join(".");
|
||||||
|
if (wildcardMatches.has(parentDomain)) {
|
||||||
|
foundCert = wildcardMatches.get(parentDomain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a certificate was found, format it, add to results, and cache it
|
||||||
|
if (foundCert) {
|
||||||
|
logger.debug(
|
||||||
|
`Creating result cert for ${domain} using cert from ${foundCert.domain}`
|
||||||
|
);
|
||||||
|
const resultCert: CertificateResult = {
|
||||||
|
id: foundCert.certId,
|
||||||
|
domain: foundCert.domain, // The actual domain of the cert record
|
||||||
|
queriedDomain: domain, // The domain that was originally requested
|
||||||
|
wildcard: foundCert.wildcard,
|
||||||
|
certFile: foundCert.certFile,
|
||||||
|
keyFile: foundCert.keyFile,
|
||||||
|
expiresAt: foundCert.expiresAt,
|
||||||
|
updatedAt: foundCert.updatedAt
|
||||||
|
};
|
||||||
|
|
||||||
|
finalResults.push(resultCert);
|
||||||
|
|
||||||
|
// Add to cache for future requests, using the *requested domain* as the key
|
||||||
|
if (useCache) {
|
||||||
|
const cacheKey = `cert:${domain}`;
|
||||||
|
await cache.set(cacheKey, resultCert, 180);
|
||||||
|
|
||||||
|
// Also cache wildcard certs under a pattern key so other subdomains
|
||||||
|
// can find them without a DB round-trip
|
||||||
|
if (resultCert.wildcard) {
|
||||||
|
const normalizedCertDomain = normalizeWildcardDomain(
|
||||||
|
resultCert.domain
|
||||||
|
);
|
||||||
|
const wildcardCacheKey = `cert:*.${normalizedCertDomain}`;
|
||||||
|
await cache.set(wildcardCacheKey, resultCert, 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const decryptedResults = decryptFinalResults(
|
||||||
|
finalResults,
|
||||||
|
config.getRawConfig().server.secret!
|
||||||
|
);
|
||||||
|
return decryptedResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decryptFinalResults(
|
||||||
|
finalResults: CertificateResult[],
|
||||||
|
secret: string
|
||||||
|
): CertificateResult[] {
|
||||||
|
const validCertsDecrypted = finalResults.map((cert) => {
|
||||||
|
// Decrypt and save certificate file
|
||||||
|
const decryptedCert = decrypt(
|
||||||
|
cert.certFile!, // is not null from query
|
||||||
|
secret
|
||||||
|
);
|
||||||
|
|
||||||
|
// Decrypt and save key file
|
||||||
|
const decryptedKey = decrypt(cert.keyFile!, secret);
|
||||||
|
|
||||||
|
// Return only the certificate data without org information
|
||||||
|
return {
|
||||||
|
...cert,
|
||||||
|
certFile: decryptedCert,
|
||||||
|
keyFile: decryptedKey
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return validCertsDecrypted;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ import { cleanUpOldLogs as cleanUpOldAccessLogs } from "#dynamic/lib/logAccessAu
|
|||||||
import { cleanUpOldLogs as cleanUpOldActionLogs } from "#dynamic/middlewares/logActionAudit";
|
import { cleanUpOldLogs as cleanUpOldActionLogs } from "#dynamic/middlewares/logActionAudit";
|
||||||
import { cleanUpOldLogs as cleanUpOldRequestLogs } from "@server/routers/badger/logRequestAudit";
|
import { cleanUpOldLogs as cleanUpOldRequestLogs } from "@server/routers/badger/logRequestAudit";
|
||||||
import { cleanUpOldLogs as cleanUpOldConnectionLogs } from "#dynamic/routers/newt";
|
import { cleanUpOldLogs as cleanUpOldConnectionLogs } from "#dynamic/routers/newt";
|
||||||
|
import { cleanUpOldLogs as cleanUpOldAiSessionLogs } from "@server/routers/aiGateway/logAiSession";
|
||||||
import { gt, or } from "drizzle-orm";
|
import { gt, or } from "drizzle-orm";
|
||||||
import { cleanUpOldFingerprintSnapshots } from "@server/routers/olm/fingerprintingUtils";
|
import { cleanUpOldFingerprintSnapshots } from "@server/routers/olm/fingerprintingUtils";
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
|
|
||||||
export function initLogCleanupInterval() {
|
export function initLogCleanupInterval() {
|
||||||
if (build == "saas") { // skip log cleanup for saas builds
|
if (build == "saas") {
|
||||||
|
// skip log cleanup for saas builds
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return setInterval(
|
return setInterval(
|
||||||
@@ -23,7 +25,9 @@ export function initLogCleanupInterval() {
|
|||||||
settingsLogRetentionDaysRequest:
|
settingsLogRetentionDaysRequest:
|
||||||
orgs.settingsLogRetentionDaysRequest,
|
orgs.settingsLogRetentionDaysRequest,
|
||||||
settingsLogRetentionDaysConnection:
|
settingsLogRetentionDaysConnection:
|
||||||
orgs.settingsLogRetentionDaysConnection
|
orgs.settingsLogRetentionDaysConnection,
|
||||||
|
settingsLogRetentionDaysAISessions:
|
||||||
|
orgs.settingsLogRetentionDaysAISessions
|
||||||
})
|
})
|
||||||
.from(orgs)
|
.from(orgs)
|
||||||
.where(
|
.where(
|
||||||
@@ -31,7 +35,8 @@ export function initLogCleanupInterval() {
|
|||||||
gt(orgs.settingsLogRetentionDaysAction, 0),
|
gt(orgs.settingsLogRetentionDaysAction, 0),
|
||||||
gt(orgs.settingsLogRetentionDaysAccess, 0),
|
gt(orgs.settingsLogRetentionDaysAccess, 0),
|
||||||
gt(orgs.settingsLogRetentionDaysRequest, 0),
|
gt(orgs.settingsLogRetentionDaysRequest, 0),
|
||||||
gt(orgs.settingsLogRetentionDaysConnection, 0)
|
gt(orgs.settingsLogRetentionDaysConnection, 0),
|
||||||
|
gt(orgs.settingsLogRetentionDaysAISessions, 0)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -42,7 +47,8 @@ export function initLogCleanupInterval() {
|
|||||||
settingsLogRetentionDaysAction,
|
settingsLogRetentionDaysAction,
|
||||||
settingsLogRetentionDaysAccess,
|
settingsLogRetentionDaysAccess,
|
||||||
settingsLogRetentionDaysRequest,
|
settingsLogRetentionDaysRequest,
|
||||||
settingsLogRetentionDaysConnection
|
settingsLogRetentionDaysConnection,
|
||||||
|
settingsLogRetentionDaysAISessions
|
||||||
} = org;
|
} = org;
|
||||||
|
|
||||||
if (settingsLogRetentionDaysAction > 0) {
|
if (settingsLogRetentionDaysAction > 0) {
|
||||||
@@ -72,6 +78,13 @@ export function initLogCleanupInterval() {
|
|||||||
settingsLogRetentionDaysConnection
|
settingsLogRetentionDaysConnection
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settingsLogRetentionDaysAISessions > 0) {
|
||||||
|
await cleanUpOldAiSessionLogs(
|
||||||
|
orgId,
|
||||||
|
settingsLogRetentionDaysAISessions
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await cleanUpOldFingerprintSnapshots(365);
|
await cleanUpOldFingerprintSnapshots(365);
|
||||||
|
|||||||
@@ -18,3 +18,19 @@ export function canCompress(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether this newt client understands `tlsCertId` references into the
|
||||||
|
// sync message's `certs` array, instead of requiring each target to carry
|
||||||
|
// its own inline `tlsCert`/`tlsKey` PEM data. Bump the version floor here to
|
||||||
|
// match whatever release first ships the newt-side support.
|
||||||
|
export function supportsCertReferences(
|
||||||
|
clientVersion: string | null | undefined
|
||||||
|
): boolean {
|
||||||
|
try {
|
||||||
|
if (!clientVersion) return false;
|
||||||
|
if (!semver.valid(clientVersion)) return false;
|
||||||
|
return semver.gte(clientVersion, "1.16.0");
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import path from "path";
|
|||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
// This is a placeholder value replaced by the build process
|
// This is a placeholder value replaced by the build process
|
||||||
export const APP_VERSION = "1.20.0";
|
export const APP_VERSION = "1.22.0";
|
||||||
|
|
||||||
export const __FILENAME = fileURLToPath(import.meta.url);
|
export const __FILENAME = fileURLToPath(import.meta.url);
|
||||||
export const __DIRNAME = path.dirname(__FILENAME);
|
export const __DIRNAME = path.dirname(__FILENAME);
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ export async function deleteOrgById(
|
|||||||
await trx.delete(sites).where(eq(sites.siteId, site.siteId));
|
await trx.delete(sites).where(eq(sites.siteId, site.siteId));
|
||||||
}
|
}
|
||||||
for (const client of orgClients) {
|
for (const client of orgClients) {
|
||||||
|
if (client.exitNodeId && client.pubKey) {
|
||||||
|
await deletePeer(client.exitNodeId, client.pubKey);
|
||||||
|
}
|
||||||
const [olm] = await trx
|
const [olm] = await trx
|
||||||
.select()
|
.select()
|
||||||
.from(olms)
|
.from(olms)
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import {
|
|||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { removeTargets } from "@server/routers/newt/targets";
|
import { removeTargets } from "@server/routers/newt/targets";
|
||||||
import createHttpError from "http-errors";
|
|
||||||
import HttpCode from "@server/types/HttpCode";
|
|
||||||
|
|
||||||
export type DeleteResourceResult = {
|
export type DeleteResourceResult = {
|
||||||
deletedResource: Resource;
|
deletedResource: Resource;
|
||||||
@@ -66,13 +64,20 @@ export async function performDeleteResources(
|
|||||||
|
|
||||||
const targetsByResourceId = new Map<number, Target[]>();
|
const targetsByResourceId = new Map<number, Target[]>();
|
||||||
for (const target of targetsToBeRemoved) {
|
for (const target of targetsToBeRemoved) {
|
||||||
|
if (target.resourceId == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const existing = targetsByResourceId.get(target.resourceId) ?? [];
|
const existing = targetsByResourceId.get(target.resourceId) ?? [];
|
||||||
existing.push(target);
|
existing.push(target);
|
||||||
targetsByResourceId.set(target.resourceId, existing);
|
targetsByResourceId.set(target.resourceId, existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetIdToResourceId = new Map(
|
const targetIdToResourceId = new Map(
|
||||||
targetsToBeRemoved.map((target) => [target.targetId, target.resourceId])
|
targetsToBeRemoved.flatMap((target) =>
|
||||||
|
target.resourceId == null
|
||||||
|
? []
|
||||||
|
: [[target.targetId, target.resourceId] as const]
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const healthChecksByResourceId = new Map<number, TargetHealthCheck[]>();
|
const healthChecksByResourceId = new Map<number, TargetHealthCheck[]>();
|
||||||
@@ -117,10 +122,10 @@ export async function runResourceDeleteSideEffects(
|
|||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (!site) {
|
if (!site) {
|
||||||
throw createHttpError(
|
logger.debug(
|
||||||
HttpCode.NOT_FOUND,
|
`Site with ID ${target.siteId} not found during resource delete side effects; skipping target removal`
|
||||||
`Site with ID ${target.siteId} not found`
|
|
||||||
);
|
);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (site.pubKey && site.type === "newt") {
|
if (site.pubKey && site.type === "newt") {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { and, eq, sql } from "drizzle-orm";
|
import { and, eq, inArray, isNotNull, sql } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
|
resources,
|
||||||
siteNetworks,
|
siteNetworks,
|
||||||
siteResources,
|
siteResources,
|
||||||
targets,
|
targets,
|
||||||
@@ -32,9 +33,11 @@ export async function getResourceIdsForSite(
|
|||||||
const rows = await trx
|
const rows = await trx
|
||||||
.selectDistinct({ resourceId: targets.resourceId })
|
.selectDistinct({ resourceId: targets.resourceId })
|
||||||
.from(targets)
|
.from(targets)
|
||||||
.where(eq(targets.siteId, siteId));
|
.where(and(eq(targets.siteId, siteId), isNotNull(targets.resourceId)));
|
||||||
|
|
||||||
return rows.map((row) => row.resourceId);
|
return rows
|
||||||
|
.map((row) => row.resourceId)
|
||||||
|
.filter((resourceId): resourceId is number => resourceId != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSiteResourceIdsForSite(
|
export async function getSiteResourceIdsForSite(
|
||||||
@@ -97,6 +100,64 @@ export function exceedsSiteAssociatedResourceDeleteLimit(
|
|||||||
return resourceCount > MAX_SITE_ASSOCIATED_RESOURCES_FOR_BULK_DELETE;
|
return resourceCount > MAX_SITE_ASSOCIATED_RESOURCES_FOR_BULK_DELETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getPendingResourceIdsForSite(
|
||||||
|
siteId: number,
|
||||||
|
trx: Transaction | typeof db = db
|
||||||
|
): Promise<number[]> {
|
||||||
|
const resourceIds = await getResourceIdsForSite(siteId, trx);
|
||||||
|
if (resourceIds.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = await trx
|
||||||
|
.select({ resourceId: resources.resourceId })
|
||||||
|
.from(resources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
inArray(resources.resourceId, resourceIds),
|
||||||
|
eq(resources.status, "pending")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return rows.map((row) => row.resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPendingSiteResourceIdsForSite(
|
||||||
|
siteId: number,
|
||||||
|
orgId: string,
|
||||||
|
trx: Transaction | typeof db = db
|
||||||
|
): Promise<number[]> {
|
||||||
|
const siteResourceIds = await getSiteResourceIdsForSite(siteId, orgId, trx);
|
||||||
|
if (siteResourceIds.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = await trx
|
||||||
|
.select({ siteResourceId: siteResources.siteResourceId })
|
||||||
|
.from(siteResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
inArray(siteResources.siteResourceId, siteResourceIds),
|
||||||
|
eq(siteResources.status, "pending")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return rows.map((row) => row.siteResourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPendingAssociatedResourceCountForSite(
|
||||||
|
siteId: number,
|
||||||
|
orgId: string,
|
||||||
|
trx: Transaction | typeof db = db
|
||||||
|
): Promise<number> {
|
||||||
|
const [resourceIds, siteResourceIds] = await Promise.all([
|
||||||
|
getPendingResourceIdsForSite(siteId, trx),
|
||||||
|
getPendingSiteResourceIdsForSite(siteId, orgId, trx)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return resourceIds.length + siteResourceIds.length;
|
||||||
|
}
|
||||||
|
|
||||||
export async function deleteAssociatedResourcesForSite(
|
export async function deleteAssociatedResourcesForSite(
|
||||||
siteId: number,
|
siteId: number,
|
||||||
orgId: string,
|
orgId: string,
|
||||||
@@ -105,12 +166,32 @@ export async function deleteAssociatedResourcesForSite(
|
|||||||
const resourceIds = await getResourceIdsForSite(siteId, trx);
|
const resourceIds = await getResourceIdsForSite(siteId, trx);
|
||||||
const siteResourceIds = await getSiteResourceIdsForSite(siteId, orgId, trx);
|
const siteResourceIds = await getSiteResourceIdsForSite(siteId, orgId, trx);
|
||||||
|
|
||||||
const [resources, siteResourcesDeleted] = await Promise.all([
|
const [deletedResources, siteResourcesDeleted] = await Promise.all([
|
||||||
performDeleteResources(resourceIds, trx),
|
performDeleteResources(resourceIds, trx),
|
||||||
performDeleteSiteResources(siteResourceIds, trx)
|
performDeleteSiteResources(siteResourceIds, trx)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return { resources, siteResources: siteResourcesDeleted };
|
return { resources: deletedResources, siteResources: siteResourcesDeleted };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deletePendingAssociatedResourcesForSite(
|
||||||
|
siteId: number,
|
||||||
|
orgId: string,
|
||||||
|
trx: Transaction | typeof db = db
|
||||||
|
): Promise<DeleteSiteAssociatedResourcesSideEffects> {
|
||||||
|
const resourceIds = await getPendingResourceIdsForSite(siteId, trx);
|
||||||
|
const siteResourceIds = await getPendingSiteResourceIdsForSite(
|
||||||
|
siteId,
|
||||||
|
orgId,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
|
||||||
|
const [deletedResources, siteResourcesDeleted] = await Promise.all([
|
||||||
|
performDeleteResources(resourceIds, trx),
|
||||||
|
performDeleteSiteResources(siteResourceIds, trx)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return { resources: deletedResources, siteResources: siteResourcesDeleted };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runDeleteSiteAssociatedResourcesSideEffects(
|
export async function runDeleteSiteAssociatedResourcesSideEffects(
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { db, sites, clients } from "@server/db";
|
||||||
|
import { and, eq, count } from "drizzle-orm";
|
||||||
|
|
||||||
|
// (MAX_CONNECTIONS - current_connections) / MAX_CONNECTIONS)
|
||||||
|
// higher = more desirable
|
||||||
|
// like saying, this node has x% of its capacity left
|
||||||
|
export async function calculateExitNodeWeight(
|
||||||
|
exitNodeId: number,
|
||||||
|
maxConnections: number | null | undefined
|
||||||
|
): Promise<number | null> {
|
||||||
|
if (maxConnections === null || maxConnections === undefined) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [[siteConnections], [clientConnections]] = await Promise.all([
|
||||||
|
db
|
||||||
|
.select({ count: count() })
|
||||||
|
.from(sites)
|
||||||
|
.where(
|
||||||
|
and(eq(sites.exitNodeId, exitNodeId), eq(sites.online, true))
|
||||||
|
),
|
||||||
|
db
|
||||||
|
.select({ count: count() })
|
||||||
|
.from(clients)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(clients.exitNodeId, exitNodeId),
|
||||||
|
eq(clients.online, true)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const currentConnections = siteConnections.count + clientConnections.count;
|
||||||
|
|
||||||
|
if (currentConnections >= maxConnections) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (maxConnections - currentConnections) / maxConnections;
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { db, exitNodes, Transaction } from "@server/db";
|
import { db, exitNodes, Transaction } from "@server/db";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { ExitNodePingResult } from "@server/routers/newt";
|
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
|
||||||
export async function verifyExitNodeOrgAccess(
|
export async function verifyExitNodeOrgAccess(
|
||||||
@@ -52,6 +51,16 @@ export async function listExitNodes(
|
|||||||
return allExitNodes;
|
return allExitNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ExitNodePingResult = {
|
||||||
|
exitNodeId: number;
|
||||||
|
latencyMs: number;
|
||||||
|
weight: number;
|
||||||
|
error?: string;
|
||||||
|
exitNodeName: string;
|
||||||
|
endpoint: string;
|
||||||
|
wasPreviouslyConnected: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export function selectBestExitNode(
|
export function selectBestExitNode(
|
||||||
pingResults: ExitNodePingResult[]
|
pingResults: ExitNodePingResult[]
|
||||||
): ExitNodePingResult | null {
|
): ExitNodePingResult | null {
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { db, ExitNode, Transaction, sites, clients } from "@server/db";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import config from "@server/lib/config";
|
||||||
|
import { findNextAvailableCidr } from "@server/lib/ip";
|
||||||
|
import { lockManager } from "#dynamic/lib/lock";
|
||||||
|
|
||||||
|
export async function getUniqueSubnetForExitNode(
|
||||||
|
exitNode: ExitNode,
|
||||||
|
trx: Transaction | typeof db = db
|
||||||
|
): Promise<string | null> {
|
||||||
|
const lockKey = `subnet-allocation:${exitNode.exitNodeId}`;
|
||||||
|
|
||||||
|
return await lockManager.withLock(
|
||||||
|
lockKey,
|
||||||
|
async () => {
|
||||||
|
const [sitesQuery, clientsQuery] = await Promise.all([
|
||||||
|
trx
|
||||||
|
.select({ subnet: sites.exitNodeSubnet })
|
||||||
|
.from(sites)
|
||||||
|
.where(eq(sites.exitNodeId, exitNode.exitNodeId)),
|
||||||
|
trx
|
||||||
|
.select({ subnet: clients.exitNodeSubnet })
|
||||||
|
.from(clients)
|
||||||
|
.where(eq(clients.exitNodeId, exitNode.exitNodeId))
|
||||||
|
]);
|
||||||
|
|
||||||
|
const blockSize = config.getRawConfig().gerbil.site_block_size;
|
||||||
|
const subnets = [...sitesQuery, ...clientsQuery]
|
||||||
|
.map((row) => row.subnet)
|
||||||
|
.filter(
|
||||||
|
(subnet): subnet is string =>
|
||||||
|
!!subnet &&
|
||||||
|
/^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/.test(subnet)
|
||||||
|
);
|
||||||
|
subnets.push(exitNode.address.replace(/\/\d+$/, `/${blockSize}`));
|
||||||
|
|
||||||
|
return findNextAvailableCidr(subnets, blockSize, exitNode.address);
|
||||||
|
},
|
||||||
|
5000 // 5 second lock TTL - subnet allocation should be quick
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,3 +2,5 @@ export * from "./exitNodes";
|
|||||||
export * from "./exitNodeComms";
|
export * from "./exitNodeComms";
|
||||||
export * from "./subnet";
|
export * from "./subnet";
|
||||||
export * from "./getCurrentExitNodeId";
|
export * from "./getCurrentExitNodeId";
|
||||||
|
export * from "./calculateExitNodeWeight";
|
||||||
|
export * from "./getUniqueSubnetForExitNode";
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { db, idp, idpOrg, Transaction } from "@server/db";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import { build } from "@server/build";
|
||||||
|
|
||||||
|
export function isOrgIdentityProviderMode(): boolean {
|
||||||
|
return build === "saas" || process.env.IDENTITY_PROVIDER_MODE === "org";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether an identity provider can be used for the given org.
|
||||||
|
* In org IdP mode, the provider must be linked via idpOrg.
|
||||||
|
* In global IdP mode, the provider only needs to exist.
|
||||||
|
*/
|
||||||
|
export async function idpExistsForOrg(
|
||||||
|
idpId: number,
|
||||||
|
orgId: string,
|
||||||
|
dbOrTrx: typeof db | Transaction = db
|
||||||
|
): Promise<boolean> {
|
||||||
|
if (isOrgIdentityProviderMode()) {
|
||||||
|
const [provider] = await dbOrTrx
|
||||||
|
.select({ idpId: idp.idpId })
|
||||||
|
.from(idp)
|
||||||
|
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
||||||
|
.where(and(eq(idp.idpId, idpId), eq(idpOrg.orgId, orgId)))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
return !!provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [provider] = await dbOrTrx
|
||||||
|
.select({ idpId: idp.idpId })
|
||||||
|
.from(idp)
|
||||||
|
.where(eq(idp.idpId, idpId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
return !!provider;
|
||||||
|
}
|
||||||