mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-30 09:15:19 +02:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c340423c0 | |||
| 146c287aba | |||
| 95ee56217c | |||
| 7625cc208d | |||
| f2dfd939bc | |||
| 699bc8ddb4 | |||
| e658e007e1 | |||
| 3103265450 | |||
| 97789d9e2e | |||
| a1aa3d96d4 | |||
| ae39bc0ecd | |||
| e4d81aa610 | |||
| f59b524266 | |||
| 58c499acae | |||
| f22301a1eb | |||
| d6264fb39a | |||
| 08b5a9b34b | |||
| 263976bf41 | |||
| 0e4cd3a5ba | |||
| aeed271f3e | |||
| d41e9bbe68 | |||
| 904a5520b8 | |||
| 0f43ae4871 | |||
| bd0cf98319 | |||
| fc7d6bbaf9 | |||
| 1b89c328de | |||
| e7f147d4ca | |||
| 41dbc7d5ed | |||
| 9f297317f2 | |||
| a69b310109 | |||
| 864a6a39cd | |||
| 1882d4df88 | |||
| bc267b7107 | |||
| 5cbb767e5f | |||
| ac79621cae | |||
| 10773432bb | |||
| d5a56fb71d | |||
| b5518d029e | |||
| 0da96b06ea | |||
| 6649f15498 | |||
| 49854f31a5 | |||
| 762c79511b | |||
| 6e29ebd649 | |||
| e128b8c282 | |||
| 832e382888 | |||
| 8a68b899f5 | |||
| b3880e5c02 | |||
| 58004a8ec9 | |||
| b0ff7d2707 | |||
| 262f7bd090 | |||
| b1558b09b1 | |||
| a33de8268b | |||
| c92d5096c4 | |||
| 9867d3c876 | |||
| 70bddba55b | |||
| 23181f4019 | |||
| 9cc3190e3a | |||
| 72f179578b | |||
| 4c873e7c48 | |||
| 0275f44056 | |||
| 1580b7abff |
@@ -62,7 +62,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Monitor storage space
|
||||
run: |
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Monitor storage space
|
||||
run: |
|
||||
@@ -149,7 +149,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
@@ -201,10 +201,10 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
@@ -256,7 +256,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Extract tag name
|
||||
id: get-tag
|
||||
@@ -264,7 +264,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: 1.25
|
||||
|
||||
@@ -407,7 +407,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Login to GitHub Container Registry (for cosign)
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
||||
@@ -21,10 +21,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '24'
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
|
||||
- uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10.4.0
|
||||
with:
|
||||
days-before-stale: 14
|
||||
days-before-close: 14
|
||||
|
||||
@@ -14,10 +14,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '24'
|
||||
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Build Docker image sqlite
|
||||
run: make dev-build-sqlite
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Build Docker image pg
|
||||
run: make dev-build-pg
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
# FROM node:24-slim AS base
|
||||
FROM public.ecr.aws/docker/library/node:24-slim AS base
|
||||
FROM public.ecr.aws/docker/library/node:26-slim AS base
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -33,7 +33,7 @@ FROM base AS builder
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
# FROM node:24-slim AS runner
|
||||
FROM public.ecr.aws/docker/library/node:24-slim AS runner
|
||||
FROM public.ecr.aws/docker/library/node:26-slim AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM node:24-alpine
|
||||
FROM node:26-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ go 1.25.0
|
||||
require (
|
||||
github.com/charmbracelet/huh v1.0.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
|
||||
)
|
||||
|
||||
@@ -33,6 +33,6 @@ require (
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // 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
|
||||
)
|
||||
|
||||
+4
-4
@@ -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/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.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
|
||||
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/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Потвърдете изтриването на споделима връзка",
|
||||
"shareQuestionRemove": "Сигурни ли сте, че искате да изтриете тази споделена връзка?",
|
||||
"shareMessageRemove": "След изтриване връзката вече няма да работи и всеки, който я използва, ще загуби достъп до ресурса.",
|
||||
"shareTokenDescription": "Достъпният токен може да бъде предаван по два начина: като параметър или в хедърите на заявките. Те трябва да бъдат предавани от клиента при всяка заявка за удостоверен достъп.",
|
||||
"shareTokenDescription": "Токен за достъп може да бъде предаден като параметър на заявка или в хедърите на заявката. По подразбиране трябва да се изпраща при всяка заявка. Ако е активирано задържане на сесията, първата заявка го заменя за сесийна бисквитка.",
|
||||
"accessToken": "Достъп Токен",
|
||||
"usageExamples": "Примери за използване",
|
||||
"tokenId": "Токен ID",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Заглавие (по избор)",
|
||||
"sharePathOptional": "Път (по избор)",
|
||||
"sharePathDescription": "След удостоверяване, линкът ще препрати потребителите на този път.",
|
||||
"shareAssociateUserOptional": "Асоцииране на потребител (по избор)",
|
||||
"shareAssociateUserDescription": "Когато е настроен, заявките използващи този линк се свързват с потребителя в достъпните логове и заглавия за идентичност. Линкът се премахва, ако потребителят напусне организацията.",
|
||||
"userSelect": "Изберете потребител",
|
||||
"usersNotFound": "Няма намерени потребители",
|
||||
"expireIn": "Изтече",
|
||||
"neverExpire": "Никога не изтича",
|
||||
"sharePersistSession": "Задръж сесия след първо използване",
|
||||
"sharePersistSessionDescription": "Когато е активирано, първата заявка с този токен чрез параметър на заявка или хедър създава сесийна бисквитка, така че следващите заявки не се нуждаят от токена. Оставете го изключено за клиенти на API, които трябва да изпращат токена при всяка заявка.",
|
||||
"shareExpireDescription": "Времето на изтичане е колко дълго връзката ще бъде използваема и ще предоставя достъп до ресурса. След това време, връзката няма да работи и потребителите, които са я използвали, ще загубят достъп до ресурса.",
|
||||
"shareSeeOnce": "Ще можете да видите този линк само веднъж. Уверете се, че го копирате.",
|
||||
"shareAccessHint": "Всеки с тази връзка може да има достъп до ресурса. Споделяйте я с внимание.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Версия",
|
||||
"architecture": "Архитектура",
|
||||
"sites": "Сайтове",
|
||||
"siteWgAnyClients": "Използвайте клиент на WireGuard, за да се свържете. Ще трябва да използвате вътрешните ресурси чрез IP адреса на връстника.",
|
||||
"siteWgAnyClients": "Използвайте всеки WireGuard клиент, за да се свържете. Ще трябва да адресирате частни ресурси, използвайки IP на връстника.",
|
||||
"siteWgCompatibleAllClients": "Съвместим с всички WireGuard клиенти",
|
||||
"siteWgManualConfigurationRequired": "Необходима е ръчна конфигурация",
|
||||
"userErrorNotAdminOrOwner": "Потребителят не е администратор или собственик",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Поддомейн: {subdomain}",
|
||||
"domainPickerNamespace": "Име на пространство: {namespace}",
|
||||
"domainPickerShowMore": "Покажи повече",
|
||||
"domainPickerNoDomainsAvailableTitle": "Няма налични домейни",
|
||||
"domainPickerNoDomainsAvailableDescription": "Все още нямате конфигурирани домейни. Създайте домейн, за да продължите.",
|
||||
"domainPickerNoDomainsAvailableAction": "Отидете на Домейни",
|
||||
"regionSelectorTitle": "Избор на регион",
|
||||
"domainPickerRemoteExitNodeWarning": "Предоставените домейни не се поддържат, когато сайтовете се свързват към отдалечени крайни възли. За да бъдат ресурсите налични на отдалечени възли, използвайте персонализиран домейн вместо това.",
|
||||
"regionSelectorInfo": "Изборът на регион ни помага да предоставим по-добра производителност за вашето местоположение. Не е необходимо да сте в същия регион като сървъра.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Публичен",
|
||||
"resourcesTableClientResources": "Частен",
|
||||
"resourcesTableNoProxyResourcesFound": "Не са намерени ресурсни проксита.",
|
||||
"resourcesTableNoInternalResourcesFound": "Не са намерени вътрешни ресурси.",
|
||||
"resourcesTableNoInternalResourcesFound": "Не са намерени частни ресурси.",
|
||||
"resourcesTableDestination": "Дестинация",
|
||||
"resourcesTableAlias": "Псевдоним",
|
||||
"resourcesTableAliasAddress": "Адрес на псевдоним.",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Отмяна",
|
||||
"editInternalResourceDialogSaveResource": "Запазване на ресурс",
|
||||
"editInternalResourceDialogSuccess": "Успех",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Вътрешният ресурс успешно актуализиран",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Частният ресурс е успешно обновен",
|
||||
"editInternalResourceDialogError": "Грешка",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Неуспешно актуализиране на вътрешен ресурс",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Неуспешен опит за обновяване на частен ресурс",
|
||||
"editInternalResourceDialogNameRequired": "Името е задължително",
|
||||
"editInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа",
|
||||
"editInternalResourceDialogProxyPortMin": "Прокси портът трябва да бъде поне 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Псевдоним",
|
||||
"editInternalResourceDialogAliasDescription": "По избор вътрешен DNS псевдоним за този ресурс.",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Няма достъпни сайтове",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Трябва да имате поне един сайт на Newt с конфигурирана мрежа, за да създадете вътрешни ресурси.",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Трябва да имате поне един Newt сайт с конфигуриран сабнет, за да създадете частни ресурси.",
|
||||
"createInternalResourceDialogClose": "Затвори",
|
||||
"createInternalResourceDialogCreateClientResource": "Създаване на частен ресурс",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Създайте нов ресурс, който ще бъде достъпен само за клиенти, свързани към организацията",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Отмяна",
|
||||
"createInternalResourceDialogCreateResource": "Създаване на ресурс",
|
||||
"createInternalResourceDialogSuccess": "Успех",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Вътрешният ресурс създаден успешно",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Частният ресурс е създаден успешно",
|
||||
"createInternalResourceDialogError": "Грешка",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Неуспешно създаване на вътрешен ресурс",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Неуспешен опит за създаване на частен ресурс",
|
||||
"createInternalResourceDialogNameRequired": "Името е задължително",
|
||||
"createInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Моля, изберете сайт",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Източен адрес",
|
||||
"destinationAddress": "Адрес на дестинация",
|
||||
"duration": "Продължителност",
|
||||
"licenseRequiredToUse": "Изисква се лиценз за <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> или <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> за използване на тази функция. <bookADemoLink>Резервирайте демонстрация или пробен POC</bookADemoLink>.",
|
||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> е необходим за използване на тази функция. Тази функция също е налична в <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Резервирайте демонстрация или пробен POC</bookADemoLink>.",
|
||||
"licenseRequiredToUse": "Изисква се лиценз за <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> или <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>, за да използвате тази функция. <bookADemoLink>Резервирайте безплатна демонстрация или пробен POC, за да научите повече.</bookADemoLink>",
|
||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> е необходим за използване на тази функция. Тази функция също е налична в <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Резервирайте безплатна демонстрация или пробен POC, за да научите повече.</bookADemoLink>",
|
||||
"certResolver": "Решавач на сертификати",
|
||||
"certResolverDescription": "Изберете решавач на сертификати за използване за този ресурс.",
|
||||
"selectCertResolver": "Изберете решавач на сертификати",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Potvrdit odstranění sdílného odkazu",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Příklady použití",
|
||||
"tokenId": "ID tokenu",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Název (volitelné)",
|
||||
"sharePathOptional": "Cesta (volitelně)",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Verze",
|
||||
"architecture": "Architektura",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Je vyžadována ruční konfigurace",
|
||||
"userErrorNotAdminOrOwner": "Uživatel není administrátor nebo vlastník",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Subdoména: {subdomain}",
|
||||
"domainPickerNamespace": "Jmenný prostor: {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Veřejnost",
|
||||
"resourcesTableClientResources": "Soukromé",
|
||||
"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í",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Adresa aliasu",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Zrušit",
|
||||
"editInternalResourceDialogSaveResource": "Uložit dokument",
|
||||
"editInternalResourceDialogSuccess": "Úspěšně",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interní zdroj byl úspěšně aktualizován",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Privátní zdroj byl úspěšně aktualizován",
|
||||
"editInternalResourceDialogError": "Chyba",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Aktualizace interního zdroje se nezdařila",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Nepodařilo se aktualizovat privátní zdroj",
|
||||
"editInternalResourceDialogNameRequired": "Název je povinný",
|
||||
"editInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků",
|
||||
"editInternalResourceDialogProxyPortMin": "Port proxy serveru musí být alespoň 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Volitelný interní DNS alias pro tento dokument.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Vytvořit soukromý zdroj",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Vytvořte nový zdroj, který bude přístupný pouze klientům připojeným k organizaci",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Zrušit",
|
||||
"createInternalResourceDialogCreateResource": "Vytvořit zdroj",
|
||||
"createInternalResourceDialogSuccess": "Úspěšně",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interní zdroj byl úspěšně vytvořen",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Privátní zdroj byl úspěšně vytvořen",
|
||||
"createInternalResourceDialogError": "Chyba",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Nepodařilo se vytvořit interní zdroj",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Nepodařilo se vytvořit privátní zdroj",
|
||||
"createInternalResourceDialogNameRequired": "Název je povinný",
|
||||
"createInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Vyberte prosím web",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Zdrojová adresa",
|
||||
"destinationAddress": "Cílová adresa",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"licenseRequiredToUse": "Pro použití této funkce je vyžadována licence <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> nebo <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Zarezervujte si bezplatné demo nebo POC zkušební verzi, abyste se dozvěděli více.</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 zdarma, abyste se dozvěděli více.</bookADemoLink>",
|
||||
"certResolver": "Oddělovač certifikátů",
|
||||
"certResolverDescription": "Vyberte řešitele certifikátů pro tento dokument.",
|
||||
"selectCertResolver": "Vyberte řešič certifikátů",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Bekræft sletning af delbar link",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Brukseksempler",
|
||||
"tokenId": "Token-ID",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Titel (valgfrit)",
|
||||
"sharePathOptional": "Sti (valgfrit)",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Version",
|
||||
"architecture": "Arkitektur",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Manuel konfiguration påkrævet",
|
||||
"userErrorNotAdminOrOwner": "Bruger er ikke administrator eller ejer",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Underdomæne: {subdomain}",
|
||||
"domainPickerNamespace": "Navnerom: {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Offentlig",
|
||||
"resourcesTableClientResources": "Privat",
|
||||
"resourcesTableNoProxyResourcesFound": "Ingen proxy-ressourcer fundet.",
|
||||
"resourcesTableNoInternalResourcesFound": "Ingen interne ressourcer fundet.",
|
||||
"resourcesTableNoInternalResourcesFound": "Ingen private ressourcer fundet.",
|
||||
"resourcesTableDestination": "Destination",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Alias adresse",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Annuller",
|
||||
"editInternalResourceDialogSaveResource": "Gem ressource",
|
||||
"editInternalResourceDialogSuccess": "Succes",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Intern ressource opdateret med succes",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Privat ressource opdateret succesfuldt",
|
||||
"editInternalResourceDialogError": "Fejl",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Mislykkedes at opdatere intern ressource",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Mislykkedes at opdatere privat ressource",
|
||||
"editInternalResourceDialogNameRequired": "Navn er påkrævet",
|
||||
"editInternalResourceDialogNameMaxLength": "Navn kan ikke være længere enn 255 tegn",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy-port skal være mindst 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Et valgfrit internt DNS-alias for denne ressource.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Opret privat ressource",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Opret en ny ressource som kun vil være tilgængelig for kunder som er forbundet til organisationen",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Annuller",
|
||||
"createInternalResourceDialogCreateResource": "Opret ressource",
|
||||
"createInternalResourceDialogSuccess": "Succes",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Intern ressource oprettet med succes",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Privat ressource oprettet succesfuldt",
|
||||
"createInternalResourceDialogError": "Fejl",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke oprette intern ressource",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke oprette privat ressource",
|
||||
"createInternalResourceDialogNameRequired": "Navn er påkrævet",
|
||||
"createInternalResourceDialogNameMaxLength": "Navn kan ikke være længere enn 255 tegn",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Vælg venligst et site",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Kildeadresse",
|
||||
"destinationAddress": "Måladresse ",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"licenseRequiredToUse": "En <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink>-licens eller <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> er påkrævet for at bruge denne funktion. <bookADemoLink>Book en gratis demo eller POC-prøveversion for at lære mere.</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 gratis demo eller POC-prøve for at lære mere.</bookADemoLink>",
|
||||
"certResolver": "Certifikatløser",
|
||||
"certResolverDescription": "Vælg certifikatløser som skal bruges for denne ressource.",
|
||||
"selectCertResolver": "Vælg certifikatløser",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Löschung des Freigabelinks bestätigen",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Nutzungsbeispiele",
|
||||
"tokenId": "Token-ID",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Titel (optional)",
|
||||
"sharePathOptional": "Pfad (optional)",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Version",
|
||||
"architecture": "Architektur",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Manuelle Konfiguration erforderlich",
|
||||
"userErrorNotAdminOrOwner": "Benutzer ist kein Administrator oder Eigentümer",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Subdomain: {subdomain}",
|
||||
"domainPickerNamespace": "Namespace: {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Öffentlich",
|
||||
"resourcesTableClientResources": "Privat",
|
||||
"resourcesTableNoProxyResourcesFound": "Keine Proxy-Ressourcen gefunden.",
|
||||
"resourcesTableNoInternalResourcesFound": "Keine internen Ressourcen gefunden.",
|
||||
"resourcesTableNoInternalResourcesFound": "Keine privaten Ressourcen gefunden.",
|
||||
"resourcesTableDestination": "Ziel",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Alias-Adresse",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Abbrechen",
|
||||
"editInternalResourceDialogSaveResource": "Ressource speichern",
|
||||
"editInternalResourceDialogSuccess": "Erfolg",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interne Ressource erfolgreich aktualisiert",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private Ressource erfolgreich aktualisiert",
|
||||
"editInternalResourceDialogError": "Fehler",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Interne Ressource konnte nicht aktualisiert werden",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Fehler beim Aktualisieren der privaten Ressource",
|
||||
"editInternalResourceDialogNameRequired": "Name ist erforderlich",
|
||||
"editInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy-Port muss mindestens 1 sein",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Ein optionaler interner DNS-Alias für diese Ressource.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Private Ressource erstellen",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Erstelle eine neue Ressource, die nur für Clients zugänglich ist, die mit der Organisation verbunden sind",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Abbrechen",
|
||||
"createInternalResourceDialogCreateResource": "Ressource erstellen",
|
||||
"createInternalResourceDialogSuccess": "Erfolg",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interne Ressource erfolgreich erstellt",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private Ressource erfolgreich erstellt",
|
||||
"createInternalResourceDialogError": "Fehler",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Interne Ressource konnte nicht erstellt werden",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Fehler beim Erstellen der privaten Ressource",
|
||||
"createInternalResourceDialogNameRequired": "Name ist erforderlich",
|
||||
"createInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Bitte wählen Sie einen Standort aus",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Quelladresse",
|
||||
"destinationAddress": "Zieladresse",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"licenseRequiredToUse": "Eine <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> Lizenz oder <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> wird benötigt, um diese Funktion zu nutzen. <bookADemoLink>Buchen Sie eine kostenlose Demo oder POC Testversion, um mehr zu erfahren.</bookADemoLink>",
|
||||
"ossEnterpriseEditionRequired": "Die <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> ist notwendig, um diese Funktion zu nutzen. Diese Funktion ist auch in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> verfügbar. <bookADemoLink>Buchen Sie eine kostenlose Demo oder POC Testversion, um mehr zu erfahren.</bookADemoLink>",
|
||||
"certResolver": "Zertifikatsauflöser",
|
||||
"certResolverDescription": "Wählen Sie den Zertifikatslöser aus, der für diese Ressource verwendet werden soll.",
|
||||
"selectCertResolver": "Zertifikatsauflöser auswählen",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Confirmar Eliminación de Enlace Compartible",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Ejemplos de uso",
|
||||
"tokenId": "ID de token",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Título (opcional)",
|
||||
"sharePathOptional": "Ruta (opcional)",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Versión",
|
||||
"architecture": "Arquitectura",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Configuración manual requerida",
|
||||
"userErrorNotAdminOrOwner": "El usuario no es un administrador o propietario",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Subdominio: {subdomain}",
|
||||
"domainPickerNamespace": "Espacio de nombres: {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Público",
|
||||
"resourcesTableClientResources": "Privado",
|
||||
"resourcesTableNoProxyResourcesFound": "No se encontraron recursos de proxy.",
|
||||
"resourcesTableNoInternalResourcesFound": "No se encontraron recursos internos.",
|
||||
"resourcesTableNoInternalResourcesFound": "No se encontraron recursos privados.",
|
||||
"resourcesTableDestination": "Destino",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Dirección del alias",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Cancelar",
|
||||
"editInternalResourceDialogSaveResource": "Guardar recurso",
|
||||
"editInternalResourceDialogSuccess": "Éxito",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso interno actualizado con éxito",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso privado actualizado con éxito",
|
||||
"editInternalResourceDialogError": "Error",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Error al actualizar el recurso interno",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Error al actualizar el recurso privado",
|
||||
"editInternalResourceDialogNameRequired": "El nombre es requerido",
|
||||
"editInternalResourceDialogNameMaxLength": "El nombre no debe tener más de 255 caracteres",
|
||||
"editInternalResourceDialogProxyPortMin": "El puerto del proxy debe ser al menos 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Un alias DNS interno opcional para este recurso.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Crear recurso privado",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Crear un nuevo recurso que sólo será accesible a los clientes conectados a la organización",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Cancelar",
|
||||
"createInternalResourceDialogCreateResource": "Crear recurso",
|
||||
"createInternalResourceDialogSuccess": "Éxito",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso interno creado con éxito",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso privado creado con éxito",
|
||||
"createInternalResourceDialogError": "Error",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Error al crear recurso interno",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Error al crear recurso privado",
|
||||
"createInternalResourceDialogNameRequired": "El nombre es requerido",
|
||||
"createInternalResourceDialogNameMaxLength": "El nombre debe ser menor de 255 caracteres",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Por favor seleccione un sitio",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Dirección de origen",
|
||||
"destinationAddress": "Dirección de destino",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"licenseRequiredToUse": "Se requiere una licencia <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> o <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> para usar esta función. <bookADemoLink>Reserve una demostración gratuita o una prueba POC para saber más.</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 gratuita o prueba POC para saber más.</bookADemoLink>",
|
||||
"certResolver": "Resolver certificado",
|
||||
"certResolverDescription": "Seleccione la resolución de certificados a utilizar para este recurso.",
|
||||
"selectCertResolver": "Seleccionar Resolver Certificado",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Confirmer la suppression du lien partageable",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Exemples d'utilisation",
|
||||
"tokenId": "ID du jeton",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Titre (facultatif)",
|
||||
"sharePathOptional": "Chemin (optionnel)",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Version",
|
||||
"architecture": "Architecture",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Configuration manuelle requise",
|
||||
"userErrorNotAdminOrOwner": "L'utilisateur n'est pas un administrateur ou un propriétaire",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Sous-domaine : {subdomain}",
|
||||
"domainPickerNamespace": "Espace de noms : {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Publique",
|
||||
"resourcesTableClientResources": "Privé",
|
||||
"resourcesTableNoProxyResourcesFound": "Aucune ressource proxy trouvée.",
|
||||
"resourcesTableNoInternalResourcesFound": "Aucune ressource interne trouvée.",
|
||||
"resourcesTableNoInternalResourcesFound": "Aucune ressource privée trouvée.",
|
||||
"resourcesTableDestination": "Destination",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Adresse de l'alias",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Abandonner",
|
||||
"editInternalResourceDialogSaveResource": "Enregistrer la ressource",
|
||||
"editInternalResourceDialogSuccess": "Succès",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Ressource interne mise à jour avec succès",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Ressource privée mise à jour avec succès",
|
||||
"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",
|
||||
"editInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
|
||||
"editInternalResourceDialogProxyPortMin": "Le port proxy doit être d'au moins 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Un alias DNS interne optionnel pour cette ressource.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Créer une ressource privée",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Créer une nouvelle ressource qui ne sera accessible qu'aux clients connectés à l'organisation",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Abandonner",
|
||||
"createInternalResourceDialogCreateResource": "Créer une ressource",
|
||||
"createInternalResourceDialogSuccess": "Succès",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Ressource interne créée avec succès",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Ressource privée créée avec succès",
|
||||
"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",
|
||||
"createInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Veuillez sélectionner un site",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Adresse source",
|
||||
"destinationAddress": "Adresse de destination",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"licenseRequiredToUse": "Une <enterpriseLicenseLink>licence Enterprise Edition</enterpriseLicenseLink> ou <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> est requise pour utiliser cette fonctionnalité. <bookADemoLink>Réservez une démo gratuite ou un essai POC pour en savoir plus.</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 gratuite ou un essai POC pour en savoir plus.</bookADemoLink>",
|
||||
"certResolver": "Résolveur de certificat",
|
||||
"certResolverDescription": "Sélectionnez le solveur de certificat à utiliser pour cette ressource.",
|
||||
"selectCertResolver": "Sélectionnez le résolveur de certificat",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Conferma Eliminazione Collegamento Condivisibile",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Esempi Di Utilizzo",
|
||||
"tokenId": "ID del Token",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Titolo (facoltativo)",
|
||||
"sharePathOptional": "Percorso (opzionale)",
|
||||
"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",
|
||||
"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.",
|
||||
"shareSeeOnce": "Potrai vedere questo link solo una volta. Assicurati di copiarlo.",
|
||||
"shareAccessHint": "Chiunque abbia questo link può accedere alla risorsa. Condividilo con cura.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Versione",
|
||||
"architecture": "Architettura",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Configurazione manuale richiesta",
|
||||
"userErrorNotAdminOrOwner": "L'utente non è un amministratore o proprietario",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Sottodominio: {subdomain}",
|
||||
"domainPickerNamespace": "Namespace: {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Pubblico",
|
||||
"resourcesTableClientResources": "Privato",
|
||||
"resourcesTableNoProxyResourcesFound": "Nessuna risorsa proxy trovata.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nessuna risorsa interna trovata.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nessuna risorsa privata trovata.",
|
||||
"resourcesTableDestination": "Destinazione",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Indirizzo Alias",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Annulla",
|
||||
"editInternalResourceDialogSaveResource": "Salva Risorsa",
|
||||
"editInternalResourceDialogSuccess": "Successo",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Risorsa interna aggiornata con successo",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Risorsa privata aggiornata con successo",
|
||||
"editInternalResourceDialogError": "Errore",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Impossibile aggiornare la risorsa interna",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Impossibile aggiornare la risorsa privata",
|
||||
"editInternalResourceDialogNameRequired": "Il nome è obbligatorio",
|
||||
"editInternalResourceDialogNameMaxLength": "Il nome deve essere inferiore a 255 caratteri",
|
||||
"editInternalResourceDialogProxyPortMin": "La porta proxy deve essere almeno 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Un alias DNS interno opzionale per questa risorsa.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Crea Risorsa Privata",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Crea una nuova risorsa che sarà accessibile solo ai client connessi all'organizzazione",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Annulla",
|
||||
"createInternalResourceDialogCreateResource": "Crea Risorsa",
|
||||
"createInternalResourceDialogSuccess": "Successo",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Risorsa interna creata con successo",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Risorsa privata creata con successo",
|
||||
"createInternalResourceDialogError": "Errore",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Impossibile creare la risorsa interna",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Impossibile creare la risorsa privata",
|
||||
"createInternalResourceDialogNameRequired": "Il nome è obbligatorio",
|
||||
"createInternalResourceDialogNameMaxLength": "Il nome non deve superare i 255 caratteri",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Si prega di selezionare un sito",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Indirizzo Di Origine",
|
||||
"destinationAddress": "Indirizzo Di Destinazione",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"licenseRequiredToUse": "Per utilizzare questa funzione è necessaria una licenza <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> o <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Prenota una demo gratuita o una prova POC per saperne di più.</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 gratuita o una prova POC per saperne di più.</bookADemoLink>",
|
||||
"certResolver": "Risolutore Di Certificato",
|
||||
"certResolverDescription": "Selezionare il risolutore di certificati da usare per questa risorsa.",
|
||||
"selectCertResolver": "Seleziona Risolutore Di Certificato",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "공유 가능한 링크 삭제 확인",
|
||||
"shareQuestionRemove": "이 공유 링크를 삭제하시겠습니까?",
|
||||
"shareMessageRemove": "삭제되면 링크가 더 이상 작동하지 않으며, 이를 사용하는 모든 사용자는 자원에 대한 접근을 잃게 됩니다.",
|
||||
"shareTokenDescription": "액세스 토큰은 쿼리 매개변수 또는 요청 헤더의 두 가지 방법으로 전달될 수 있습니다. 이는 인증된 액세스를 위해 클라이언트에서 모든 요청마다 전달되어야 합니다.",
|
||||
"shareTokenDescription": "액세스 토큰은 쿼리 매개변수로 또는 요청 헤더에 전달될 수 있습니다. 기본적으로 모든 요청에 포함되어야 합니다. 세션 지속이 활성화된 경우, 첫 번째 요청이 세션 쿠키로 교환됩니다.",
|
||||
"accessToken": "액세스 토큰",
|
||||
"usageExamples": "사용 예",
|
||||
"tokenId": "토큰 ID",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "제목 (선택 사항)",
|
||||
"sharePathOptional": "경로 (선택 사항)",
|
||||
"sharePathDescription": "링크는 인증 후 이 경로로 사용자를 리디렉션합니다.",
|
||||
"shareAssociateUserOptional": "사용자 연관 (선택 사항)",
|
||||
"shareAssociateUserDescription": "설정 시, 이 링크를 사용하는 요청은 액세스 로그와 ID 헤더에서 사용자로 기록됩니다. 사용자가 조직을 떠나면 링크가 제거됩니다.",
|
||||
"userSelect": "사용자 선택",
|
||||
"usersNotFound": "사용자를 찾을 수 없습니다",
|
||||
"expireIn": "만료됨",
|
||||
"neverExpire": "만료되지 않음",
|
||||
"sharePersistSession": "첫 사용 후 세션 지속",
|
||||
"sharePersistSessionDescription": "활성화된 경우, 쿼리 매개변수나 헤더를 통해 이 토큰으로 첫 요청 시 세션 쿠키가 설정되어 이후 요청에는 토큰이 필요하지 않습니다. 모든 요청에 토큰을 포함해야 하는 API 클라이언트의 경우, 이 옵션을 해제하세요.",
|
||||
"shareExpireDescription": "만료 시간은 링크가 사용 가능하고 리소스에 접근할 수 있는 기간입니다. 이 시간이 지나면 링크는 더 이상 작동하지 않으며, 이 링크를 사용한 사용자는 리소스에 대한 접근 권한을 잃게 됩니다.",
|
||||
"shareSeeOnce": "이 링크는 한 번만 볼 수 있습니다. 반드시 복사해 두세요.",
|
||||
"shareAccessHint": "이 링크가 있는 누구나 리소스에 접근할 수 있습니다. 주의해서 공유하세요.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "버전",
|
||||
"architecture": "아키텍처",
|
||||
"sites": "사이트",
|
||||
"siteWgAnyClients": "WireGuard 클라이언트를 사용하여 연결하십시오. 피어 IP를 사용하여 내부 리소스에 접근해야 합니다.",
|
||||
"siteWgAnyClients": "WireGuard 클라이언트를 사용하여 연결하십시오. 피어 IP를 사용하여 개인 리소스에 접근해야 합니다.",
|
||||
"siteWgCompatibleAllClients": "모든 WireGuard 클라이언트와 호환",
|
||||
"siteWgManualConfigurationRequired": "수동 구성이 필요합니다.",
|
||||
"userErrorNotAdminOrOwner": "사용자는 관리자 또는 소유자가 아닙니다.",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "서브도메인: {subdomain}",
|
||||
"domainPickerNamespace": "이름 공간: {namespace}",
|
||||
"domainPickerShowMore": "더보기",
|
||||
"domainPickerNoDomainsAvailableTitle": "사용 가능한 도메인이 없습니다",
|
||||
"domainPickerNoDomainsAvailableDescription": "설정된 도메인이 아직 없습니다. 계속하려면 도메인을 생성하세요.",
|
||||
"domainPickerNoDomainsAvailableAction": "도메인으로 이동",
|
||||
"regionSelectorTitle": "지역 선택",
|
||||
"domainPickerRemoteExitNodeWarning": "제공된 도메인은 원격 종료 노드에 연결된 사이트에서 지원되지 않습니다. 원격 노드에서 리소스를 사용하려면 사용자 지정 도메인을 사용하십시오.",
|
||||
"regionSelectorInfo": "지역을 선택하면 위치에 따라 더 나은 성능이 제공됩니다. 서버와 같은 지역에 있을 필요는 없습니다.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "공유",
|
||||
"resourcesTableClientResources": "비공개",
|
||||
"resourcesTableNoProxyResourcesFound": "프록시 리소스를 찾을 수 없습니다.",
|
||||
"resourcesTableNoInternalResourcesFound": "내부 리소스를 찾을 수 없습니다.",
|
||||
"resourcesTableNoInternalResourcesFound": "개인 리소스를 찾을 수 없습니다.",
|
||||
"resourcesTableDestination": "대상지",
|
||||
"resourcesTableAlias": "별칭",
|
||||
"resourcesTableAliasAddress": "별칭 주소",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "취소",
|
||||
"editInternalResourceDialogSaveResource": "리소스 저장",
|
||||
"editInternalResourceDialogSuccess": "성공",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "내부 리소스가 성공적으로 업데이트되었습니다",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "개인 리소스가 성공적으로 업데이트되었습니다",
|
||||
"editInternalResourceDialogError": "오류",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "내부 리소스 업데이트 실패",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "개인 리소스 업데이트 실패",
|
||||
"editInternalResourceDialogNameRequired": "이름은 필수입니다.",
|
||||
"editInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.",
|
||||
"editInternalResourceDialogProxyPortMin": "프록시 포트는 최소 1이어야 합니다.",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "별칭",
|
||||
"editInternalResourceDialogAliasDescription": "이 리소스에 대한 선택적 내부 DNS 별칭입니다.",
|
||||
"createInternalResourceDialogNoSitesAvailable": "사용 가능한 사이트가 없습니다.",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "내부 리소스를 생성하려면 서브넷이 구성된 최소 하나의 Newt 사이트가 필요합니다.",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "개인 리소스를 생성하려면 서브넷이 구성된 최소 하나의 Newt 사이트가 필요합니다.",
|
||||
"createInternalResourceDialogClose": "닫기",
|
||||
"createInternalResourceDialogCreateClientResource": "사이트 리소스 생성",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "선택한 사이트에 연결된 클라이언트에 접근할 새 리소스를 생성합니다",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "취소",
|
||||
"createInternalResourceDialogCreateResource": "리소스 생성",
|
||||
"createInternalResourceDialogSuccess": "성공",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "내부 리소스가 성공적으로 생성되었습니다.",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "개인 리소스가 성공적으로 생성되었습니다",
|
||||
"createInternalResourceDialogError": "오류",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "내부 리소스 생성 실패",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "개인 리소스 생성 실패",
|
||||
"createInternalResourceDialogNameRequired": "이름은 필수입니다.",
|
||||
"createInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.",
|
||||
"createInternalResourceDialogPleaseSelectSite": "사이트를 선택하세요",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "소스 주소",
|
||||
"destinationAddress": "대상 주소",
|
||||
"duration": "지속 시간",
|
||||
"licenseRequiredToUse": "이 기능을 사용하려면 <enterpriseLicenseLink>엔터프라이즈 에디션</enterpriseLicenseLink> 라이선스가 필요합니다. 이 기능은 <pangolinCloudLink>판골린 클라우드</pangolinCloudLink>에서도 사용할 수 있습니다. <bookADemoLink>데모 또는 POC 체험을 예약하세요</bookADemoLink>.",
|
||||
"ossEnterpriseEditionRequired": "이 기능을 사용하려면 <enterpriseEditionLink>엔터프라이즈 에디션</enterpriseEditionLink>이(가) 필요합니다. 이 기능은 <pangolinCloudLink>판골린 클라우드</pangolinCloudLink>에서도 사용할 수 있습니다. <bookADemoLink>데모 또는 POC 체험을 예약하세요</bookADemoLink>.",
|
||||
"licenseRequiredToUse": "이 기능을 사용하려면 <enterpriseLicenseLink>엔터프라이즈 에디션</enterpriseLicenseLink> 라이선스가 필요합니다. 이 기능은 <pangolinCloudLink>판골린 클라우드</pangolinCloudLink>에서도 사용할 수 있습니다. <bookADemoLink>데모 또는 POC 체험을 예약하세요</bookADemoLink>",
|
||||
"ossEnterpriseEditionRequired": "이 기능을 사용하려면 <enterpriseEditionLink>엔터프라이즈 에디션</enterpriseEditionLink>이 필요합니다. 이 기능은 <pangolinCloudLink>판골린 클라우드</pangolinCloudLink>에서도 사용할 수 있습니다. <bookADemoLink>데모 또는 POC 체험을 예약하세요</bookADemoLink>",
|
||||
"certResolver": "인증서 해결사",
|
||||
"certResolverDescription": "이 리소스에 사용할 인증서 해결사를 선택하세요.",
|
||||
"selectCertResolver": "인증서 해결사 선택",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Bekreft sletting av delbar lenke",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Brukseksempler",
|
||||
"tokenId": "Token-ID",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Tittel (valgfritt)",
|
||||
"sharePathOptional": "Bane (valgfritt)",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Versjon",
|
||||
"architecture": "Arkitektur",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Manuell konfigurasjon påkrevd",
|
||||
"userErrorNotAdminOrOwner": "Bruker er ikke administrator eller eier",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Underdomene: {subdomain}",
|
||||
"domainPickerNamespace": "Navnerom: {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Offentlig",
|
||||
"resourcesTableClientResources": "Privat",
|
||||
"resourcesTableNoProxyResourcesFound": "Ingen proxy-ressurser funnet.",
|
||||
"resourcesTableNoInternalResourcesFound": "Ingen interne ressurser funnet.",
|
||||
"resourcesTableNoInternalResourcesFound": "Ingen private ressurser funnet.",
|
||||
"resourcesTableDestination": "Destinasjon",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Alias adresse",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Avbryt",
|
||||
"editInternalResourceDialogSaveResource": "Lagre ressurs",
|
||||
"editInternalResourceDialogSuccess": "Suksess",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Intern ressurs oppdatert vellykket",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Privat ressurs oppdatert vellykket",
|
||||
"editInternalResourceDialogError": "Feil",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Mislyktes å oppdatere intern ressurs",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Feil ved oppdatering av privat ressurs",
|
||||
"editInternalResourceDialogNameRequired": "Navn er påkrevd",
|
||||
"editInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy-port må være minst 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Et valgfritt internt DNS-alias for denne ressursen.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Opprett privat ressurs",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Opprett en ny ressurs som bare vil være tilgjengelig for kunder som er koblet til organisasjonen",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Avbryt",
|
||||
"createInternalResourceDialogCreateResource": "Opprett ressurs",
|
||||
"createInternalResourceDialogSuccess": "Suksess",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Intern ressurs opprettet vellykket",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Privat ressurs opprettet vellykket",
|
||||
"createInternalResourceDialogError": "Feil",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke opprette intern ressurs",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke opprette privat ressurs",
|
||||
"createInternalResourceDialogNameRequired": "Navn er påkrevd",
|
||||
"createInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Vennligst velg et område",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Kilde adresse",
|
||||
"destinationAddress": "Måladresse (Automatic Translation)",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"licenseRequiredToUse": "En <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> lisens eller <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> er nødvendig for å bruke denne funksjonen. <bookADemoLink>Bestill en gratis demo eller POC prøve for å lære mer.</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 gratis demo eller POC prøve for å lære mer.</bookADemoLink>",
|
||||
"certResolver": "Sertifikat løser",
|
||||
"certResolverDescription": "Velg sertifikatløser som skal brukes for denne ressursen.",
|
||||
"selectCertResolver": "Velg sertifikatløser",
|
||||
|
||||
+61
-52
@@ -13,7 +13,7 @@
|
||||
"orgDisplayName": "Dit is de weergavenaam van de organisatie.",
|
||||
"orgId": "Organisatie ID",
|
||||
"setupIdentifierMessage": "Dit is de unieke identificatie voor de organisatie.",
|
||||
"setupErrorIdentifier": "Organisatie-ID is al in gebruik. Kies een andere.",
|
||||
"setupErrorIdentifier": "Organisatie ID is al in gebruik, verzin iets anders.",
|
||||
"componentsErrorNoMemberCreate": "U bent momenteel geen lid van een organisatie. Maak een organisatie aan om aan de slag te gaan.",
|
||||
"componentsErrorNoMember": "U bent momenteel geen lid van een organisatie.",
|
||||
"welcome": "Welkom bij Pangolin!",
|
||||
@@ -78,7 +78,7 @@
|
||||
"siteManageSites": "Sites beheren",
|
||||
"siteDescription": "Maak en beheer sites om verbinding met privénetwerken in te schakelen",
|
||||
"sitesBannerTitle": "Verbind elk netwerk",
|
||||
"sitesBannerDescription": "Een site is een verbinding met een extern netwerk waarmee Pangolin toegang biedt tot bronnen, zowel openbaar als privé, aan gebruikers overal. Installeer de sitedatacenterconnector (Newt) overal waar je een binaire of container kunt uitvoeren om de verbinding tot stand te brengen.",
|
||||
"sitesBannerDescription": "Een site is een verbinding met een extern netwerk waarmee Pangolin toegang biedt voor gebruikers voor bronnen, zowel openbaar als privé. Installeer de sitedatacenterconnector (Newt) overal waar je een binaire of container kunt uitvoeren om de verbinding tot stand te brengen.",
|
||||
"sitesBannerButtonText": "Site installeren",
|
||||
"approvalsBannerTitle": "Toegang tot het apparaat goedkeuren of weigeren",
|
||||
"approvalsBannerDescription": "Bekijk en keur toestelverzoeken goed of weiger toegang van gebruikers. Wanneer apparaatgoedkeuringen vereist zijn, moeten gebruikers de goedkeuring van beheerders krijgen voordat hun apparaten verbinding kunnen maken met de bronnen van uw organisatie.",
|
||||
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Bevestig Verwijdering Deelbare Link",
|
||||
"shareQuestionRemove": "Weet u zeker dat u deze deel link wilt verwijderen?",
|
||||
"shareMessageRemove": "Zodra verwijderd, zal de link niet meer werken en zal iedereen die het gebruikt de toegang tot de bron verliezen.",
|
||||
"shareTokenDescription": "De toegangstoken kan op twee manieren worden doorgegeven: als queryparameter of in de aanvraagheaders. Deze moeten worden doorgegeven van de client op elk verzoek voor geverifieerde toegang.",
|
||||
"shareTokenDescription": "Het toegangstoken kan als queryparameter of in aanvraagheaders worden meegegeven. Standaard moet het bij elke aanvraag worden verzonden. Als sessie-persistentie is ingeschakeld, ruilt de eerste aanvraag deze in voor een sessiecookie.",
|
||||
"accessToken": "Toegangs-token",
|
||||
"usageExamples": "Voorbeelden van gebruik",
|
||||
"tokenId": "Token ID",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Titel (optioneel)",
|
||||
"sharePathOptional": "Pad (optioneel)",
|
||||
"sharePathDescription": "De link zal gebruikers naar dit pad doorsturen na authenticatie.",
|
||||
"shareAssociateUserOptional": "Gebruiker koppelen (optioneel)",
|
||||
"shareAssociateUserDescription": "Wanneer ingesteld, worden aanvragen met deze link toegeschreven aan de gebruiker in toegangslogboeken en identiteitsheaders. De link wordt verwijderd als de gebruiker de organisatie verlaat.",
|
||||
"userSelect": "Selecteer gebruiker",
|
||||
"usersNotFound": "Geen gebruikers gevonden",
|
||||
"expireIn": "Vervalt in",
|
||||
"neverExpire": "Nooit verlopen",
|
||||
"sharePersistSession": "Sessie behouden na eerste gebruik",
|
||||
"sharePersistSessionDescription": "Wanneer ingeschakeld, zet de eerste aanvraag met dit token via een queryparameter of header een sessiecookie zodat latere aanvragen het token niet nodig hebben. Laat dit uit voor API-clients die het token bij elke aanvraag moeten verzenden.",
|
||||
"shareExpireDescription": "Vervaltijd is hoe lang de link bruikbaar is en geeft toegang tot de bron. Na deze tijd zal de link niet meer werken en zullen gebruikers die deze link hebben gebruikt de toegang tot de pagina verliezen.",
|
||||
"shareSeeOnce": "U kunt deze link slechts één keer zien. Zorg ervoor dat u deze kopieert.",
|
||||
"shareAccessHint": "Iedereen met deze link heeft toegang tot de bron. Deel deze met zorg.",
|
||||
@@ -219,12 +225,12 @@
|
||||
"shareErrorSelectResource": "Selecteer een bron",
|
||||
"proxyResourceTitle": "Openbare bronnen beheren",
|
||||
"proxyResourceDescription": "Creëer en beheer bronnen die openbaar toegankelijk zijn via een webbrowser",
|
||||
"publicResourcesBannerTitle": "Web-gebaseerde Openbare Toegang",
|
||||
"publicResourcesBannerDescription": "Openbare bronnen zijn HTTPS-proxies die toegankelijk zijn voor iedereen op het internet via een webbrowser. In tegenstelling tot privébronnen hoeven ze geen client-software te hebben en kunnen ze identiteit- en context bewuste toegangsmiddelen bevatten.",
|
||||
"publicResourcesBannerTitle": "Webgebaseerde openbare bronnen",
|
||||
"publicResourcesBannerDescription": "Openbare bronnen zijn HTTPS proxy's die te bereiken zijn voor iedereen op het internet via een webbrowser. Het is mogelijk om deze te beveiligen door identiteitscontrole of een toegangsbeleid. In tegenstelling tot privébronnen hoeven ze geen clientsoftware te installeren.",
|
||||
"clientResourceTitle": "Privébronnen beheren",
|
||||
"clientResourceDescription": "Creëer en beheer bronnen die alleen toegankelijk zijn via een verbonden client",
|
||||
"privateResourcesBannerTitle": "Zero-Trust Private Access",
|
||||
"privateResourcesBannerDescription": "Privé bronnen maken gebruik van zero-trust-beveiliging, wat ervoor zorgt dat gebruikers en machines alleen toegang kunnen krijgen tot middelen die jij specifiek toestaat. Verbind gebruikersapparaten of machineclients om deze middelen te benaderen via een veilig virtueel priv��netwerk.",
|
||||
"privateResourcesBannerTitle": "Privébronnen via Zero Trust",
|
||||
"privateResourcesBannerDescription": "Privébronnen maken gebruik van zero trust beveiliging, wat ervoor zorgt dat gebruikers en machines alleen toegang kunnen krijgen tot resources die je specifiek toestaat. Verbind gebruikersapparaten of machines om deze middelen te benaderen via een veilig, virtueel privénetwerk.",
|
||||
"resourcesSearch": "Zoek bronnen...",
|
||||
"resourceAdd": "Bron toevoegen",
|
||||
"resourceErrorDelte": "Fout bij verwijderen document",
|
||||
@@ -253,7 +259,7 @@
|
||||
"resourcePolicyUsersRolesDescription": "Bepaal welke gebruikers en rollen geassocieerde bronnen kunnen bezoeken",
|
||||
"rulesResourcePolicyDescription": "Stel regels in om toegang te regelen tot bronnen die zijn gekoppeld aan dit beleid",
|
||||
"authentication": "Authenticatie",
|
||||
"protected": "Beschermd",
|
||||
"protected": "Beveiligd",
|
||||
"notProtected": "Niet beveiligd",
|
||||
"resourceMessageRemove": "Eenmaal verwijderd, zal het bestand niet langer toegankelijk zijn. Alle doelen die gekoppeld zijn aan het hulpbron, zullen ook verwijderd worden.",
|
||||
"resourceQuestionRemove": "Weet u zeker dat u het document van de organisatie wilt verwijderen?",
|
||||
@@ -324,7 +330,7 @@
|
||||
"labelEdit": "Label bewerken",
|
||||
"editLabelDialogTitle": "Label bijwerken",
|
||||
"editLabelDialogDescription": "Bewerk een nieuw label dat aan deze organisatie kan worden gekoppeld",
|
||||
"labelDeleteConfirm": "Bevestigen Verwijderen Label",
|
||||
"labelDeleteConfirm": "Label verwijderen",
|
||||
"labelErrorDelete": "Kan label niet verwijderen",
|
||||
"labelMessageRemove": "Deze handeling is definitief. Alle sites, bronnen en klanten met dit label zullen worden onttakeld.",
|
||||
"labelQuestionRemove": "Weet u zeker dat u het label uit de organisatie wilt verwijderen?",
|
||||
@@ -409,40 +415,40 @@
|
||||
"years": "Jaar",
|
||||
"day": "{count, plural, one {# dag} other {# dagen}}",
|
||||
"apiKeysTitle": "API Key Informatie",
|
||||
"apiKeysConfirmCopy2": "Bevestig dat u de API-sleutel hebt gekopieerd.",
|
||||
"apiKeysErrorCreate": "Fout bij maken API-sleutel",
|
||||
"apiKeysConfirmCopy2": "Bevestig dat u de API sleutel hebt gekopieerd.",
|
||||
"apiKeysErrorCreate": "Fout bij maken API sleutel",
|
||||
"apiKeysErrorSetPermission": "Fout instellen permissies",
|
||||
"apiKeysCreate": "API-sleutel genereren",
|
||||
"apiKeysCreateDescription": "Een nieuwe API-sleutel voor de organisatie genereren",
|
||||
"apiKeysCreate": "API sleutel genereren",
|
||||
"apiKeysCreateDescription": "Een nieuwe API sleutel voor de organisatie genereren",
|
||||
"apiKeysGeneralSettings": "Machtigingen",
|
||||
"apiKeysGeneralSettingsDescription": "Bepaal wat deze API-sleutel kan doen",
|
||||
"apiKeysList": "Nieuwe API-sleutel",
|
||||
"apiKeysSave": "De API-sleutel opslaan",
|
||||
"apiKeysGeneralSettingsDescription": "Bepaal wat deze API sleutel kan doen",
|
||||
"apiKeysList": "Nieuwe API sleutel",
|
||||
"apiKeysSave": "De API sleutel opslaan",
|
||||
"apiKeysSaveDescription": "Je kunt dit slechts één keer zien. Kopieer het naar een veilige plek.",
|
||||
"apiKeysInfo": "De API-sleutel is:",
|
||||
"apiKeysConfirmCopy": "Ik heb de API-sleutel gekopieerd",
|
||||
"apiKeysInfo": "De API sleutel is:",
|
||||
"apiKeysConfirmCopy": "Ik heb de API sleutel gekopieerd",
|
||||
"generate": "Genereren",
|
||||
"done": "Voltooid",
|
||||
"apiKeysSeeAll": "Alle API-sleutels bekijken",
|
||||
"apiKeysSeeAll": "Alle API sleutels bekijken",
|
||||
"apiKeysPermissionsErrorLoadingActions": "Fout bij het laden van API key acties",
|
||||
"apiKeysPermissionsErrorUpdate": "Fout instellen permissies",
|
||||
"apiKeysPermissionsUpdated": "Permissies bijgewerkt",
|
||||
"apiKeysPermissionsUpdatedDescription": "De bevoegdheden zijn bijgewerkt.",
|
||||
"apiKeysPermissionsGeneralSettings": "Machtigingen",
|
||||
"apiKeysPermissionsGeneralSettingsDescription": "Bepaal wat deze API-sleutel kan doen",
|
||||
"apiKeysPermissionsGeneralSettingsDescription": "Bepaal wat deze API sleutel kan doen",
|
||||
"apiKeysPermissionsSave": "Rechten opslaan",
|
||||
"apiKeysPermissionsTitle": "Machtigingen",
|
||||
"apiKeys": "API sleutels",
|
||||
"searchApiKeys": "API-sleutels zoeken...",
|
||||
"apiKeysAdd": "API-sleutel genereren",
|
||||
"apiKeysErrorDelete": "Fout bij verwijderen API-sleutel",
|
||||
"apiKeysErrorDeleteMessage": "Fout bij verwijderen API-sleutel",
|
||||
"apiKeysQuestionRemove": "Weet u zeker dat u de API-sleutel van de organisatie wilt verwijderen?",
|
||||
"apiKeysMessageRemove": "Eenmaal verwijderd, kan de API-sleutel niet meer worden gebruikt.",
|
||||
"apiKeysDeleteConfirm": "Bevestig Verwijderen API-sleutel",
|
||||
"apiKeysDelete": "API-sleutel verwijderen",
|
||||
"apiKeysManage": "API-sleutels beheren",
|
||||
"apiKeysDescription": "API-sleutels worden gebruikt om te verifiëren met de integratie-API",
|
||||
"searchApiKeys": "API sleutels zoeken...",
|
||||
"apiKeysAdd": "API sleutel genereren",
|
||||
"apiKeysErrorDelete": "Fout bij verwijderen API sleutel",
|
||||
"apiKeysErrorDeleteMessage": "Fout bij verwijderen API sleutel",
|
||||
"apiKeysQuestionRemove": "Weet u zeker dat u de API sleutel van de organisatie wilt verwijderen?",
|
||||
"apiKeysMessageRemove": "Eenmaal verwijderd, kan de API sleutel niet meer worden gebruikt.",
|
||||
"apiKeysDeleteConfirm": "Bevestig Verwijderen API sleutel",
|
||||
"apiKeysDelete": "API sleutel verwijderen",
|
||||
"apiKeysManage": "API sleutels beheren",
|
||||
"apiKeysDescription": "API sleutels worden gebruikt om toegang te verifiëren met de integratie API ",
|
||||
"provisioningKeysTitle": "Vertrekkende sleutel",
|
||||
"provisioningKeysManage": "Beheren van Provisioning Sleutels",
|
||||
"provisioningKeysDescription": "Provisionerende sleutels worden gebruikt om geautomatiseerde sitebepaling voor uw organisatie te verifiëren.",
|
||||
@@ -906,7 +912,7 @@
|
||||
"resourcesUsersRolesAccess": "Gebruiker en rol-gebaseerde toegangsbeheer",
|
||||
"resourcesErrorUpdate": "Bron wisselen mislukt",
|
||||
"resourcesErrorUpdateDescription": "Er is een fout opgetreden tijdens het bijwerken van het document",
|
||||
"access": "Toegangsrechten",
|
||||
"access": "Link",
|
||||
"accessControl": "Toegangs controle",
|
||||
"shareLink": "{resource} Deelbare Link",
|
||||
"resourceSelect": "Selecteer resource",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Versie",
|
||||
"architecture": "Architectuur",
|
||||
"sites": "Sites",
|
||||
"siteWgAnyClients": "Gebruik een willekeurige WireGuard client om verbinding te maken. Je zult interne bronnen moeten aanspreken met behulp van de peer IP.",
|
||||
"siteWgAnyClients": "Gebruik een willekeurige WireGuard-client om verbinding te maken. U moet privébronnen benaderen met de peer IP.",
|
||||
"siteWgCompatibleAllClients": "Compatibel met alle WireGuard clients",
|
||||
"siteWgManualConfigurationRequired": "Handmatige configuratie vereist",
|
||||
"userErrorNotAdminOrOwner": "Gebruiker is geen beheerder of eigenaar",
|
||||
@@ -1480,11 +1486,11 @@
|
||||
"actionCheckOrgId": "ID controleren",
|
||||
"actionCreateOrg": "Nieuwe organisatie aanmaken",
|
||||
"actionDeleteOrg": "Verwijder organisatie",
|
||||
"actionListApiKeys": "API-sleutels weergeven",
|
||||
"actionListApiKeys": "API sleutels weergeven",
|
||||
"actionListApiKeyActions": "Lijst van API Key Acties",
|
||||
"actionSetApiKeyActions": "Stel API Key Toegestane Acties",
|
||||
"actionCreateApiKey": "API-sleutel aanmaken",
|
||||
"actionDeleteApiKey": "API-sleutel verwijderen",
|
||||
"actionCreateApiKey": "API sleutel aanmaken",
|
||||
"actionDeleteApiKey": "API sleutel verwijderen",
|
||||
"actionCreateIdp": "IDP aanmaken",
|
||||
"actionUpdateIdp": "IDP bijwerken",
|
||||
"actionDeleteIdp": "Verwijder IDP",
|
||||
@@ -1550,7 +1556,7 @@
|
||||
"commandPaletteCreateProxyResource": "Maak Openbare Bron",
|
||||
"commandPaletteCreatePrivateResource": "Maak Privébron",
|
||||
"commandPaletteCreateUser": "Gebruiker aanmaken",
|
||||
"commandPaletteCreateApiKey": "API-sleutel aanmaken",
|
||||
"commandPaletteCreateApiKey": "API sleutel aanmaken",
|
||||
"commandPaletteCreateMachineClient": "Machineclient aanmaken",
|
||||
"commandPaletteCreateAlertRule": "Alarmregel aanmaken",
|
||||
"commandPaletteCreateIdentityProvider": "Identiteitsprovider aanmaken",
|
||||
@@ -1598,10 +1604,10 @@
|
||||
"authErrorNoUpdate": "Geen authenticatie informatie om bij te werken",
|
||||
"orgErrorNoUpdate": "Geen org om bij te werken",
|
||||
"orgErrorNoProvided": "Geen org opgegeven",
|
||||
"apiKeysErrorNoUpdate": "Geen API-sleutel om bij te werken",
|
||||
"apiKeysErrorNoUpdate": "Geen API sleutel om bij te werken",
|
||||
"sidebarOverview": "Overzicht.",
|
||||
"sidebarHome": "Startpagina",
|
||||
"sidebarSites": "Werkruimtes",
|
||||
"sidebarSites": "Sites",
|
||||
"sidebarApprovals": "Goedkeuringsverzoeken",
|
||||
"sidebarResources": "Bronnen",
|
||||
"sidebarProxyResources": "Openbaar",
|
||||
@@ -1671,8 +1677,8 @@
|
||||
"commandBilling": "Facturering",
|
||||
"commandEnterpriseLicenses": "Licentie",
|
||||
"commandSettings": "Instellingen",
|
||||
"commandLauncher": "Startprogramma",
|
||||
"commandResourceLauncher": "Bron Startprogramma",
|
||||
"commandLauncher": "Startpagina",
|
||||
"commandResourceLauncher": "Bron startpagina",
|
||||
"commandSearchResults": "Zoekresultaten",
|
||||
"alertingTitle": "Waarschuwingen",
|
||||
"alertingDescription": "Definieer bronnen, triggers en acties voor meldingen",
|
||||
@@ -1830,7 +1836,7 @@
|
||||
"standaloneHcFilterSiteIdFallback": "Site {id}",
|
||||
"standaloneHcFilterResourceIdFallback": "Bron {id}",
|
||||
"blueprints": "Blauwdrukken",
|
||||
"blueprintsLog": "Log Blueprints",
|
||||
"blueprintsLog": "Log blauwafdrukken",
|
||||
"blueprintsDescription": "Bekijk eerdere blauwdruktoepassingen en hun resultaten of pas een nieuwe blauwdruk toe",
|
||||
"blueprintAdd": "Blauwdruk toevoegen",
|
||||
"blueprintGoBack": "Bekijk alle Blauwdrukken",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Subdomein: {subdomain}",
|
||||
"domainPickerNamespace": "Naamruimte: {namespace}",
|
||||
"domainPickerShowMore": "Meer weergeven",
|
||||
"domainPickerNoDomainsAvailableTitle": "Geen domeinen beschikbaar",
|
||||
"domainPickerNoDomainsAvailableDescription": "Je hebt nog geen domeinen ingesteld. Maak een domein aan om door te gaan.",
|
||||
"domainPickerNoDomainsAvailableAction": "Ga naar Domeinen",
|
||||
"regionSelectorTitle": "Selecteer Regio",
|
||||
"domainPickerRemoteExitNodeWarning": "Opgegeven domeinen worden niet ondersteund wanneer websites verbinding maken met externe sluitnodes. Gebruik in plaats daarvan een aangepast domein. Om bronnen beschikbaar te maken op externe nodes.",
|
||||
"regionSelectorInfo": "Het selecteren van een regio helpt ons om betere prestaties te leveren voor uw locatie. U hoeft niet in dezelfde regio als uw server te zijn.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Openbaar",
|
||||
"resourcesTableClientResources": "Privé",
|
||||
"resourcesTableNoProxyResourcesFound": "Geen proxybronnen gevonden.",
|
||||
"resourcesTableNoInternalResourcesFound": "Geen interne bronnen gevonden.",
|
||||
"resourcesTableNoInternalResourcesFound": "Geen privébronnen gevonden.",
|
||||
"resourcesTableDestination": "Bestemming",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Alias adres",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Annuleren",
|
||||
"editInternalResourceDialogSaveResource": "Sla bron op",
|
||||
"editInternalResourceDialogSuccess": "Succes",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interne bron succesvol bijgewerkt",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Privébron succesvol bijgewerkt",
|
||||
"editInternalResourceDialogError": "Fout",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Het bijwerken van de interne bron is mislukt",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Fout bij het bijwerken van de privébron",
|
||||
"editInternalResourceDialogNameRequired": "Naam is verplicht",
|
||||
"editInternalResourceDialogNameMaxLength": "Naam mag niet langer zijn dan 255 tekens",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy poort moet minstens 1 zijn",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Een optionele interne DNS-alias voor dit document.",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Geen sites beschikbaar",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "U moet ten minste één Newt-site hebben met een geconfigureerd subnet om interne bronnen aan te maken.",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "U moet ten minste één Newt-site hebben met een geconfigureerd subnet om privébronnen aan te maken.",
|
||||
"createInternalResourceDialogClose": "Sluiten",
|
||||
"createInternalResourceDialogCreateClientResource": "Privé bron maken",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Maak een nieuwe bron aan die alleen toegankelijk is voor klanten die verbonden zijn met de organisatie",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Annuleren",
|
||||
"createInternalResourceDialogCreateResource": "Bron aanmaken",
|
||||
"createInternalResourceDialogSuccess": "Succes",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interne bron succesvol aangemaakt",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Privébron succesvol aangemaakt",
|
||||
"createInternalResourceDialogError": "Fout",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Het aanmaken van de interne bron is mislukt",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Fout bij het aanmaken van de privébron",
|
||||
"createInternalResourceDialogNameRequired": "Naam is verplicht",
|
||||
"createInternalResourceDialogNameMaxLength": "Naam mag niet langer zijn dan 255 tekens",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Selecteer alstublieft een site",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Bron adres",
|
||||
"destinationAddress": "Adres bestemming",
|
||||
"duration": "Duur",
|
||||
"licenseRequiredToUse": "Een <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> licentie of <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is vereist om deze functie te gebruiken. <bookADemoLink>Boek een demo of POC trial</bookADemoLink>.",
|
||||
"ossEnterpriseEditionRequired": "De <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is vereist om deze functie te gebruiken. Deze functie is ook beschikbaar in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Boek een demo of POC trial</bookADemoLink>.",
|
||||
"licenseRequiredToUse": "Een <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> licentie of <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is vereist om deze functie te gebruiken. <bookADemoLink>Boek een gratis demo of POC trial om meer te leren.</bookADemoLink>",
|
||||
"ossEnterpriseEditionRequired": "De <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is vereist om deze functie te gebruiken. Deze functie is ook beschikbaar in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Boek een gratis demo of POC trial om meer te leren.</bookADemoLink>",
|
||||
"certResolver": "Certificaat Resolver",
|
||||
"certResolverDescription": "Selecteer de certificaat resolver die moet worden gebruikt voor deze resource.",
|
||||
"selectCertResolver": "Certificaat Resolver selecteren",
|
||||
@@ -3311,7 +3320,7 @@
|
||||
"internalResourceAuthDaemonPort": "Daemon poort (optioneel)",
|
||||
"orgAuthWhatsThis": "Waar kan ik mijn organisatie-ID vinden?",
|
||||
"learnMore": "Meer informatie",
|
||||
"backToHome": "Ga terug naar startpagina",
|
||||
"backToHome": "Ga terug naar de startpagina",
|
||||
"needToSignInToOrg": "Moet u de identiteit provider van uw organisatie gebruiken?",
|
||||
"maintenanceMode": "Onderhoudspagina",
|
||||
"maintenanceModeDescription": "Toon een onderhoudspagina aan bezoekers",
|
||||
@@ -3524,7 +3533,7 @@
|
||||
"httpDestAuthNoneDescription": "Stuurt verzoeken zonder toestemmingskop.",
|
||||
"httpDestAuthBearerTitle": "Betere Token",
|
||||
"httpDestAuthBearerDescription": "Voegt een Authorization: Bearer '<token>' header toe aan elk verzoek.",
|
||||
"httpDestAuthBearerPlaceholder": "Uw API-sleutel of -token",
|
||||
"httpDestAuthBearerPlaceholder": "Uw API sleutel of token",
|
||||
"httpDestAuthBasicTitle": "Basis authenticatie",
|
||||
"httpDestAuthBasicDescription": "Voegt een Authorization: Basic '<credentials>' header toe. Verstrek inloggegevens als gebruikersnaam:wachtwoord.",
|
||||
"httpDestAuthBasicPlaceholder": "Gebruikersnaam:wachtwoord",
|
||||
@@ -3678,7 +3687,7 @@
|
||||
"memberPortalResourceDisabled": "Bron Uitgeschakeld",
|
||||
"memberPortalShowingResources": "Toont {start}-{end} van {total} bronnen",
|
||||
"resourceLauncherTitle": "Bron Launcher",
|
||||
"resourceSidebarLauncherTitle": "Startprogramma",
|
||||
"resourceSidebarLauncherTitle": "Startpagina",
|
||||
"resourceLauncherDescription": "Bekijk alle beschikbare bronnen en start ze vanuit één centraal punt",
|
||||
"resourceLauncherSearchPlaceholder": "Zoek naar bronnen...",
|
||||
"resourceLauncherDefaultView": "Standaard",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Potwierdź usunięcie linku do udostępnienia",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Przykłady użycia",
|
||||
"tokenId": "Identyfikator tokena",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Tytuł (opcjonalnie)",
|
||||
"sharePathOptional": "Ścieżka (opcjonalnie)",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Wersja",
|
||||
"architecture": "Architektura",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Wymagana konfiguracja ręczna",
|
||||
"userErrorNotAdminOrOwner": "Użytkownik nie jest administratorem ani właścicielem",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Subdomena: {subdomain}",
|
||||
"domainPickerNamespace": "Przestrzeń nazw: {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Publiczne",
|
||||
"resourcesTableClientResources": "Prywatny",
|
||||
"resourcesTableNoProxyResourcesFound": "Nie znaleziono zasobów proxy.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nie znaleziono wewnętrznych zasobów.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nie znaleziono prywatnych zasobów.",
|
||||
"resourcesTableDestination": "Miejsce docelowe",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Adres aliasu",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Anuluj",
|
||||
"editInternalResourceDialogSaveResource": "Zapisz zasób",
|
||||
"editInternalResourceDialogSuccess": "Sukces",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Wewnętrzny zasób zaktualizowany pomyślnie",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Prywatny zasób został pomyślnie zaktualizowany",
|
||||
"editInternalResourceDialogError": "Błąd",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Nie udało się zaktualizować wewnętrznego zasobu",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Nie udało się zaktualizować prywatnego zasobu",
|
||||
"editInternalResourceDialogNameRequired": "Nazwa jest wymagana",
|
||||
"editInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
|
||||
"editInternalResourceDialogProxyPortMin": "Port proxy musi wynosić przynajmniej 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Opcjonalny wewnętrzny alias DNS dla tego zasobu.",
|
||||
"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",
|
||||
"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",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Anuluj",
|
||||
"createInternalResourceDialogCreateResource": "Utwórz zasób",
|
||||
"createInternalResourceDialogSuccess": "Sukces",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Wewnętrzny zasób utworzony pomyślnie",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Prywatny zasób został pomyślnie utworzony",
|
||||
"createInternalResourceDialogError": "Błąd",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Nie udało się utworzyć wewnętrznego zasobu",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Nie udało się utworzyć prywatnego zasobu",
|
||||
"createInternalResourceDialogNameRequired": "Nazwa jest wymagana",
|
||||
"createInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Proszę wybrać stronę",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Adres źródłowy",
|
||||
"destinationAddress": "Adres docelowy",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"licenseRequiredToUse": "Do korzystania z tej funkcji wymagana jest licencja <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> lub <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Zarezerwuj darmową wersję demo lub próbę POC, aby dowiedzieć się więcej.</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 darmową wersję demo lub próbę POC, aby dowiedzieć się więcej.</bookADemoLink>",
|
||||
"certResolver": "Rozwiązywanie certyfikatów",
|
||||
"certResolverDescription": "Wybierz resolver certyfikatów do użycia dla tego zasobu.",
|
||||
"selectCertResolver": "Wybierz Resolver certyfikatów",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Confirmar exclusão do Link Compartilhável",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Exemplos de uso",
|
||||
"tokenId": "ID do Token",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Título (opcional)",
|
||||
"sharePathOptional": "Caminho (opcional)",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Versão",
|
||||
"architecture": "Arquitetura",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Configuração manual necessária",
|
||||
"userErrorNotAdminOrOwner": "Usuário não é administrador ou proprietário",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Subdomínio: {subdomain}",
|
||||
"domainPickerNamespace": "Namespace: {namespace}",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Público",
|
||||
"resourcesTableClientResources": "Privado",
|
||||
"resourcesTableNoProxyResourcesFound": "Nenhum recurso de proxy encontrado.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nenhum recurso interno encontrado.",
|
||||
"resourcesTableNoInternalResourcesFound": "Nenhum recurso privado encontrado.",
|
||||
"resourcesTableDestination": "Destino",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Endereço do Pseudônimo",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Cancelar",
|
||||
"editInternalResourceDialogSaveResource": "Guardar Recurso",
|
||||
"editInternalResourceDialogSuccess": "Sucesso",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso interno atualizado com sucesso",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso privado atualizado com sucesso",
|
||||
"editInternalResourceDialogError": "Erro",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Falha ao atualizar recurso interno",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Falha ao atualizar recurso privado",
|
||||
"editInternalResourceDialogNameRequired": "Nome é obrigatório",
|
||||
"editInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
|
||||
"editInternalResourceDialogProxyPortMin": "Porta de proxy deve ser pelo menos 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Um alias de DNS interno opcional para este recurso.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Criar Recurso Privado",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Criar um novo recurso que só será acessível para clientes conectados à organização",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Cancelar",
|
||||
"createInternalResourceDialogCreateResource": "Criar Recurso",
|
||||
"createInternalResourceDialogSuccess": "Sucesso",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso interno criado com sucesso",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso privado criado com sucesso",
|
||||
"createInternalResourceDialogError": "Erro",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Falha ao criar recurso interno",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Falha ao criar recurso privado",
|
||||
"createInternalResourceDialogNameRequired": "Nome é obrigatório",
|
||||
"createInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Por favor, selecione um site",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Endereço de origem",
|
||||
"destinationAddress": "Endereço de destino",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"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 para saber mais.</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 para saber mais.</bookADemoLink>",
|
||||
"certResolver": "Resolvedor de Certificado",
|
||||
"certResolverDescription": "Selecione o resolvedor de certificados para este recurso.",
|
||||
"selectCertResolver": "Selecionar solucionador de certificado",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Подтвердить удаление общей ссылки",
|
||||
"shareQuestionRemove": "Вы уверены, что хотите удалить эту общую ссылку?",
|
||||
"shareMessageRemove": "После удаления ссылка перестанет работать, и все, кто ее использует, потеряют доступ к ресурсу.",
|
||||
"shareTokenDescription": "Токен доступа может быть передан двумя способами: как параметр запроса или в заголовках запроса. Они должны быть переданы от клиента по каждому запросу для аутентифицированного доступа.",
|
||||
"shareTokenDescription": "Токен доступа может быть передан в виде параметра запроса или в заголовках запроса. По умолчанию, он должен отправляться при каждом запросе. Если включена устойчивость сеанса, первый запрос обменяет его на сеансовый файл cookie.",
|
||||
"accessToken": "Токен доступа",
|
||||
"usageExamples": "Примеры использования",
|
||||
"tokenId": "ID токена",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Заголовок (необязательно)",
|
||||
"sharePathOptional": "Путь (необязательно)",
|
||||
"sharePathDescription": "Ссылка перенаправит пользователей на этот путь после аутентификации.",
|
||||
"shareAssociateUserOptional": "Связать пользователя (необязательно)",
|
||||
"shareAssociateUserDescription": "При установке, запросы с этой ссылкой записываются за пользователем в журналах доступа и заголовках идентификации. Ссылка удаляется, если пользователь покидает организацию.",
|
||||
"userSelect": "Выберите пользователя",
|
||||
"usersNotFound": "Пользователи не найдены",
|
||||
"expireIn": "Срок действия",
|
||||
"neverExpire": "Бессрочный доступ",
|
||||
"sharePersistSession": "Сохранять сеанс после первого использования",
|
||||
"sharePersistSessionDescription": "При включении, первый запрос с этим токеном через параметр запроса или заголовок устанавливает сеансовый файл cookie, так что последующие запросы не требуют токена. Оставьте для API-клиентов, которые должны отправлять токен при каждом запросе.",
|
||||
"shareExpireDescription": "Срок действия - это период, в течение которого ссылка будет работать и предоставлять доступ к ресурсу. После этого времени ссылка перестанет работать, и пользователи, использовавшие эту ссылку, потеряют доступ к ресурсу.",
|
||||
"shareSeeOnce": "Вы сможете увидеть эту ссылку только один раз. Обязательно скопируйте ее.",
|
||||
"shareAccessHint": "Любой, у кого есть эта ссылка, может получить доступ к ресурсу. Делитесь ею с осторожностью.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Версия",
|
||||
"architecture": "Архитектура",
|
||||
"sites": "Сайты",
|
||||
"siteWgAnyClients": "Для подключения используйте любой клиент WireGuard. Вы должны будете адресовать внутренние ресурсы, используя IP адрес пира.",
|
||||
"siteWgAnyClients": "Используйте любой клиент WireGuard для подключения. Вам придётся обращаться к частным ресурсам, используя IP узла.",
|
||||
"siteWgCompatibleAllClients": "Совместим со всеми клиентами WireGuard",
|
||||
"siteWgManualConfigurationRequired": "Требуется ручная настройка",
|
||||
"userErrorNotAdminOrOwner": "Пользователь не является администратором или владельцем",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Поддомен: {subdomain}",
|
||||
"domainPickerNamespace": "Пространство имен: {namespace}",
|
||||
"domainPickerShowMore": "Показать еще",
|
||||
"domainPickerNoDomainsAvailableTitle": "Нет доступных доменов",
|
||||
"domainPickerNoDomainsAvailableDescription": "У вас еще не настроены домены. Создайте домен, чтобы продолжить.",
|
||||
"domainPickerNoDomainsAvailableAction": "Перейти к доменам",
|
||||
"regionSelectorTitle": "Выберите регион",
|
||||
"domainPickerRemoteExitNodeWarning": "Предоставленные домены не поддерживаются при подключении сайтов к удаленным узлам. Для доступа к ресурсам на удаленных узлах используйте пользовательский домен.",
|
||||
"regionSelectorInfo": "Выбор региона помогает нам обеспечить лучшее качество обслуживания для вашего расположения. Вам необязательно находиться в том же регионе, что и ваш сервер.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Публичный",
|
||||
"resourcesTableClientResources": "Приватный",
|
||||
"resourcesTableNoProxyResourcesFound": "Проксированных ресурсов не найдено.",
|
||||
"resourcesTableNoInternalResourcesFound": "Внутренних ресурсов не найдено.",
|
||||
"resourcesTableNoInternalResourcesFound": "Частные ресурсы не найдены.",
|
||||
"resourcesTableDestination": "Пункт назначения",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "Псевдоним адреса",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "Отмена",
|
||||
"editInternalResourceDialogSaveResource": "Сохранить ресурс",
|
||||
"editInternalResourceDialogSuccess": "Успешно",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Внутренний ресурс успешно обновлен",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Частный ресурс успешно обновлен",
|
||||
"editInternalResourceDialogError": "Ошибка",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Не удалось обновить внутренний ресурс",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Не удалось обновить частный ресурс",
|
||||
"editInternalResourceDialogNameRequired": "Имя обязательно",
|
||||
"editInternalResourceDialogNameMaxLength": "Имя не должно быть длиннее 255 символов",
|
||||
"editInternalResourceDialogProxyPortMin": "Порт прокси должен быть не менее 1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "Дополнительный внутренний DNS псевдоним для этого ресурса.",
|
||||
"createInternalResourceDialogNoSitesAvailable": "Нет доступных сайтов",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Вам необходимо иметь хотя бы один сайт Newt с настроенной подсетью для создания внутреннего ресурса.",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "Вам необходимо иметь хотя бы один сайт Newt с настроенной подсетью для создания частных ресурсов.",
|
||||
"createInternalResourceDialogClose": "Закрыть",
|
||||
"createInternalResourceDialogCreateClientResource": "Создать приватный ресурс",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Создать новый ресурс, который будет доступен только клиентам, подключенным к организации",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "Отмена",
|
||||
"createInternalResourceDialogCreateResource": "Создать ресурс",
|
||||
"createInternalResourceDialogSuccess": "Успешно",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Внутренний ресурс успешно создан",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Частный ресурс успешно создан",
|
||||
"createInternalResourceDialogError": "Ошибка",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Не удалось создать внутренний ресурс",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Не удалось создать частный ресурс",
|
||||
"createInternalResourceDialogNameRequired": "Имя обязательно",
|
||||
"createInternalResourceDialogNameMaxLength": "Имя должно содержать менее 255 символов",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Пожалуйста, выберите сайт",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Адрес источника",
|
||||
"destinationAddress": "Адрес назначения",
|
||||
"duration": "Продолжительность",
|
||||
"licenseRequiredToUse": "Требуется лицензия на <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> или <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> для использования этой функции. <bookADemoLink>Забронируйте демонстрацию или пробный POC</bookADemoLink>.",
|
||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> требуется для использования этой функции. Эта функция также доступна в <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Забронируйте демонстрацию или пробный POC</bookADemoLink>.",
|
||||
"licenseRequiredToUse": "Требуется лицензия на <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> или <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> для использования этой функции. <bookADemoLink>Забронируйте демонстрацию или пробный POC, чтобы узнать больше.</bookADemoLink>",
|
||||
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> требуется для использования этой функции. Эта функция также доступна в <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Забронируйте демонстрацию или пробный POC, чтобы узнать больше.</bookADemoLink>",
|
||||
"certResolver": "Резольвер сертификата",
|
||||
"certResolverDescription": "Выберите резолвер сертификата, который будет использоваться для этого ресурса.",
|
||||
"selectCertResolver": "Выберите резолвер сертификата",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "Paylaşılabilir Bağlantıyı Silmeyi Onayla",
|
||||
"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.",
|
||||
"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",
|
||||
"usageExamples": "Kullanım Örnekleri",
|
||||
"tokenId": "Jeton ID",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "Başlık (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.",
|
||||
"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",
|
||||
"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.",
|
||||
"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.",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "Sürüm",
|
||||
"architecture": "Mimari",
|
||||
"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",
|
||||
"siteWgManualConfigurationRequired": "Manuel yapılandırma gerekli",
|
||||
"userErrorNotAdminOrOwner": "Kullanıcı yönetici veya sahibi değil",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "Alt Alan: {subdomain}",
|
||||
"domainPickerNamespace": "Ad Alanı: {namespace}",
|
||||
"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ç",
|
||||
"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.",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "Herkese Açık",
|
||||
"resourcesTableClientResources": "Özel",
|
||||
"resourcesTableNoProxyResourcesFound": "Hiçbir proxy kaynağı bulunamadı.",
|
||||
"resourcesTableNoInternalResourcesFound": "Hiçbir dahili kaynak bulunamadı.",
|
||||
"resourcesTableNoInternalResourcesFound": "Özel kaynak bulunamadı.",
|
||||
"resourcesTableDestination": "Hedef",
|
||||
"resourcesTableAlias": "Takma Ad",
|
||||
"resourcesTableAliasAddress": "Alias Adresi",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "İptal",
|
||||
"editInternalResourceDialogSaveResource": "Kaynağı Kaydet",
|
||||
"editInternalResourceDialogSuccess": "Başarı",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Dahili kaynak başarıyla güncellendi",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Özel kaynak başarıyla güncellendi",
|
||||
"editInternalResourceDialogError": "Hata",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Dahili kaynak güncellenemedi",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "Özel kaynak güncellenemedi",
|
||||
"editInternalResourceDialogNameRequired": "Ad gerekli",
|
||||
"editInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
|
||||
"editInternalResourceDialogProxyPortMin": "Proxy bağlantı noktası en az 1 olmalıdır",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Takma Ad",
|
||||
"editInternalResourceDialogAliasDescription": "Bu kaynak için isteğe bağlı dahili DNS takma adı.",
|
||||
"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",
|
||||
"createInternalResourceDialogCreateClientResource": "Özel Kaynak Oluştur",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "Seçilen siteye bağlı istemcilere erişilebilir olacak yeni bir kaynak oluşturun",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "İptal",
|
||||
"createInternalResourceDialogCreateResource": "Kaynak Oluştur",
|
||||
"createInternalResourceDialogSuccess": "Başarı",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Dahili kaynak başarıyla oluşturuldu",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Özel kaynak başarıyla oluşturuldu",
|
||||
"createInternalResourceDialogError": "Hata",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Dahili kaynak oluşturulamadı",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "Özel kaynak oluşturulamadı",
|
||||
"createInternalResourceDialogNameRequired": "Ad gerekli",
|
||||
"createInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
|
||||
"createInternalResourceDialogPleaseSelectSite": "Lütfen bir site seçin",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "Kaynak Adresi",
|
||||
"destinationAddress": "Hedef Adresi",
|
||||
"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>.",
|
||||
"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>.",
|
||||
"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>",
|
||||
"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>",
|
||||
"certResolver": "Sertifika Çözücü",
|
||||
"certResolverDescription": "Bu kaynak için kullanılacak sertifika çözücüsünü seçin.",
|
||||
"selectCertResolver": "Sertifika Çözücü Seçin",
|
||||
|
||||
+19
-10
@@ -178,7 +178,7 @@
|
||||
"shareDeleteConfirm": "确认删除共享链接",
|
||||
"shareQuestionRemove": "您确定要删除这个共享链接吗?",
|
||||
"shareMessageRemove": "删除后,该链接将不再可用,使用它的任何人将失去对资源的访问权限。",
|
||||
"shareTokenDescription": "访问令牌可以通过两种方式传递:作为查询参数或请求标题。 每次验证访问请求都必须从客户端传递。",
|
||||
"shareTokenDescription": "访问令牌可以作为查询参数或请求头传递。默认情况下,它必须在每次请求时发送。如果启用了会话持久性,则第一个请求会将其交换为会话cookie。",
|
||||
"accessToken": "访问令牌",
|
||||
"usageExamples": "用法示例",
|
||||
"tokenId": "令牌 ID",
|
||||
@@ -196,8 +196,14 @@
|
||||
"shareTitleOptional": "标题 (可选)",
|
||||
"sharePathOptional": "路径(可选)",
|
||||
"sharePathDescription": "认证后,链接将把用户重定向到此路径。",
|
||||
"shareAssociateUserOptional": "关联用户(可选)",
|
||||
"shareAssociateUserDescription": "设置后,使用此链接的请求将在访问日志和身份头中归属于用户。如果用户离开组织,则该链接将被删除。",
|
||||
"userSelect": "选择用户",
|
||||
"usersNotFound": "未找到用户",
|
||||
"expireIn": "过期时间",
|
||||
"neverExpire": "永不过期",
|
||||
"sharePersistSession": "首次使用后会话持久化",
|
||||
"sharePersistSessionDescription": "启用后,通过查询参数或头部携带此令牌的首次请求会设置会话cookie,因此后续请求不需要令牌。对于应在每次请求中发送令牌的API客户端,请保持关闭。",
|
||||
"shareExpireDescription": "过期时间是链接可以使用并提供对资源的访问时间。 此时间后,链接将不再工作,使用此链接的用户将失去对资源的访问。",
|
||||
"shareSeeOnce": "您只能看到一次此链接。请确保复制它。",
|
||||
"shareAccessHint": "任何具有此链接的人都可以访问该资源。小心地分享它。",
|
||||
@@ -928,7 +934,7 @@
|
||||
"newtVersion": "版本",
|
||||
"architecture": "架构",
|
||||
"sites": "站点",
|
||||
"siteWgAnyClients": "使用任何 WireGuard 客户端连接。您必须使用对等IP解决内部资源问题。",
|
||||
"siteWgAnyClients": "使用任何WireGuard客户端进行连接。您必须使用对等IP来处理私有资源。",
|
||||
"siteWgCompatibleAllClients": "与所有WireGuard客户端兼容",
|
||||
"siteWgManualConfigurationRequired": "需要手动配置",
|
||||
"userErrorNotAdminOrOwner": "用户不是管理员或所有者",
|
||||
@@ -1989,6 +1995,9 @@
|
||||
"domainPickerSubdomain": "子域:{subdomain}",
|
||||
"domainPickerNamespace": "命名空间:{namespace}",
|
||||
"domainPickerShowMore": "显示更多",
|
||||
"domainPickerNoDomainsAvailableTitle": "无可用域",
|
||||
"domainPickerNoDomainsAvailableDescription": "您还没有设置任何域。创建一个域以继续。",
|
||||
"domainPickerNoDomainsAvailableAction": "转到域",
|
||||
"regionSelectorTitle": "选择区域",
|
||||
"domainPickerRemoteExitNodeWarning": "当站点连接到远程退出节点时不支持所提供的域。为了资源可在远程节点上使用,请使用自定义域名。",
|
||||
"regionSelectorInfo": "选择区域以帮助提升您所在地的性能。您不必与服务器在相同的区域。",
|
||||
@@ -2352,7 +2361,7 @@
|
||||
"resourcesTableProxyResources": "",
|
||||
"resourcesTableClientResources": "私有资源",
|
||||
"resourcesTableNoProxyResourcesFound": "未找到代理资源。",
|
||||
"resourcesTableNoInternalResourcesFound": "未找到内部资源。",
|
||||
"resourcesTableNoInternalResourcesFound": "未找到私有资源。",
|
||||
"resourcesTableDestination": "目标",
|
||||
"resourcesTableAlias": "Alias",
|
||||
"resourcesTableAliasAddress": "别名地址",
|
||||
@@ -2375,9 +2384,9 @@
|
||||
"editInternalResourceDialogCancel": "取消",
|
||||
"editInternalResourceDialogSaveResource": "保存资源",
|
||||
"editInternalResourceDialogSuccess": "成功",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "内部资源更新成功",
|
||||
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "私有资源更新成功",
|
||||
"editInternalResourceDialogError": "错误",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "更新内部资源失败",
|
||||
"editInternalResourceDialogFailedToUpdateInternalResource": "更新私有资源失败",
|
||||
"editInternalResourceDialogNameRequired": "名称为必填项",
|
||||
"editInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
|
||||
"editInternalResourceDialogProxyPortMin": "代理端口必须至少为1",
|
||||
@@ -2403,7 +2412,7 @@
|
||||
"editInternalResourceDialogAlias": "Alias",
|
||||
"editInternalResourceDialogAliasDescription": "此资源可选的内部DNS别名。",
|
||||
"createInternalResourceDialogNoSitesAvailable": "暂无可用站点",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "您需要至少配置一个子网的Newt站点来创建内部资源。",
|
||||
"createInternalResourceDialogNoSitesAvailableDescription": "您需要至少配置一个子网的Newt站点来创建私有资源。",
|
||||
"createInternalResourceDialogClose": "关闭",
|
||||
"createInternalResourceDialogCreateClientResource": "创建私有资源",
|
||||
"createInternalResourceDialogCreateClientResourceDescription": "创建一个新资源只能为连接到组织的客户端访问",
|
||||
@@ -2432,9 +2441,9 @@
|
||||
"createInternalResourceDialogCancel": "取消",
|
||||
"createInternalResourceDialogCreateResource": "创建资源",
|
||||
"createInternalResourceDialogSuccess": "成功",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "内部资源创建成功",
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "私有资源创建成功",
|
||||
"createInternalResourceDialogError": "错误",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "创建内部资源失败",
|
||||
"createInternalResourceDialogFailedToCreateInternalResource": "创建私有资源失败",
|
||||
"createInternalResourceDialogNameRequired": "名称为必填项",
|
||||
"createInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
|
||||
"createInternalResourceDialogPleaseSelectSite": "请选择一个站点",
|
||||
@@ -3089,8 +3098,8 @@
|
||||
"sourceAddress": "源地址",
|
||||
"destinationAddress": "目的地址",
|
||||
"duration": "期限",
|
||||
"licenseRequiredToUse": "使用此功能需要<enterpriseLicenseLink>企业版</enterpriseLicenseLink>许可证或<pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>。<bookADemoLink>预约演示或POC试用</bookADemoLink>。",
|
||||
"ossEnterpriseEditionRequired": "需要 <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> 才能使用此功能。 此功能也可在 <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>上获取。 <bookADemoLink>预订演示或POC 试用</bookADemoLink>。",
|
||||
"licenseRequiredToUse": "使用此功能需要<enterpriseLicenseLink>企业版</enterpriseLicenseLink>许可证或<pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>。<bookADemoLink>预约演示或POC试用以了解更多。</bookADemoLink>",
|
||||
"ossEnterpriseEditionRequired": "需要<enterpriseEditionLink>企业版</enterpriseEditionLink>才能使用此功能。此功能也可在<pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>上获取。<bookADemoLink>预约演示或POC试用以了解更多。</bookADemoLink>",
|
||||
"certResolver": "证书解决器",
|
||||
"certResolverDescription": "选择用于此资源的证书解析器。",
|
||||
"selectCertResolver": "选择证书解析",
|
||||
|
||||
Generated
+304
-60
@@ -51,7 +51,7 @@
|
||||
"@xterm/addon-web-links": "^0.12.0",
|
||||
"@xterm/xterm": "^6.0.0",
|
||||
"arctic": "3.7.0",
|
||||
"axios": "1.16.1",
|
||||
"axios": "1.18.0",
|
||||
"better-sqlite3": "11.9.1",
|
||||
"canvas-confetti": "1.9.4",
|
||||
"class-variance-authority": "0.7.1",
|
||||
@@ -70,12 +70,12 @@
|
||||
"input-otp": "1.4.2",
|
||||
"ioredis": "5.11.0",
|
||||
"jmespath": "0.16.0",
|
||||
"js-yaml": "4.2.0",
|
||||
"js-yaml": "4.3.0",
|
||||
"jsonwebtoken": "9.0.3",
|
||||
"lucide-react": "1.17.0",
|
||||
"maxmind": "5.0.6",
|
||||
"moment": "2.30.1",
|
||||
"next": "16.2.6",
|
||||
"next": "16.2.11",
|
||||
"next-intl": "4.13.0",
|
||||
"next-themes": "0.4.6",
|
||||
"nextjs-toploader": "3.9.17",
|
||||
@@ -2574,9 +2574,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz",
|
||||
"integrity": "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.11.tgz",
|
||||
"integrity": "sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next": {
|
||||
@@ -2590,9 +2590,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.6.tgz",
|
||||
"integrity": "sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.11.tgz",
|
||||
"integrity": "sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2606,9 +2606,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.6.tgz",
|
||||
"integrity": "sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.11.tgz",
|
||||
"integrity": "sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2622,12 +2622,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.6.tgz",
|
||||
"integrity": "sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.11.tgz",
|
||||
"integrity": "sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2638,12 +2641,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.6.tgz",
|
||||
"integrity": "sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.11.tgz",
|
||||
"integrity": "sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2654,12 +2660,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.6.tgz",
|
||||
"integrity": "sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.11.tgz",
|
||||
"integrity": "sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2670,12 +2679,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.6.tgz",
|
||||
"integrity": "sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.11.tgz",
|
||||
"integrity": "sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2686,9 +2698,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.6.tgz",
|
||||
"integrity": "sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.11.tgz",
|
||||
"integrity": "sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2702,9 +2714,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.6.tgz",
|
||||
"integrity": "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.11.tgz",
|
||||
"integrity": "sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -6460,6 +6472,225 @@
|
||||
"next": "16.2.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/env": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz",
|
||||
"integrity": "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.6.tgz",
|
||||
"integrity": "sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.6.tgz",
|
||||
"integrity": "sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.6.tgz",
|
||||
"integrity": "sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.6.tgz",
|
||||
"integrity": "sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.6.tgz",
|
||||
"integrity": "sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.6.tgz",
|
||||
"integrity": "sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.6.tgz",
|
||||
"integrity": "sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.6.tgz",
|
||||
"integrity": "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-email/ui/node_modules/next": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz",
|
||||
"integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "16.2.6",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"baseline-browser-mapping": "^2.9.19",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
"postcss": "8.4.31",
|
||||
"styled-jsx": "5.1.6"
|
||||
},
|
||||
"bin": {
|
||||
"next": "dist/bin/next"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.2.6",
|
||||
"@next/swc-darwin-x64": "16.2.6",
|
||||
"@next/swc-linux-arm64-gnu": "16.2.6",
|
||||
"@next/swc-linux-arm64-musl": "16.2.6",
|
||||
"@next/swc-linux-x64-gnu": "16.2.6",
|
||||
"@next/swc-linux-x64-musl": "16.2.6",
|
||||
"@next/swc-win32-arm64-msvc": "16.2.6",
|
||||
"@next/swc-win32-x64-msvc": "16.2.6",
|
||||
"sharp": "^0.34.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.1.0",
|
||||
"@playwright/test": "^1.51.1",
|
||||
"babel-plugin-react-compiler": "*",
|
||||
"react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
|
||||
"react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
|
||||
"sass": "^1.3.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@opentelemetry/api": {
|
||||
"optional": true
|
||||
},
|
||||
"@playwright/test": {
|
||||
"optional": true
|
||||
},
|
||||
"babel-plugin-react-compiler": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@react-types/shared": {
|
||||
"version": "3.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.34.0.tgz",
|
||||
@@ -9078,9 +9309,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz",
|
||||
"integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==",
|
||||
"version": "1.18.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz",
|
||||
"integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.16.0",
|
||||
@@ -9214,20 +9445,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
|
||||
"integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz",
|
||||
"integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "^3.1.2",
|
||||
"content-type": "^1.0.5",
|
||||
"content-type": "^2.0.0",
|
||||
"debug": "^4.4.3",
|
||||
"http-errors": "^2.0.0",
|
||||
"iconv-lite": "^0.7.0",
|
||||
"http-errors": "^2.0.1",
|
||||
"iconv-lite": "^0.7.2",
|
||||
"on-finished": "^2.4.1",
|
||||
"qs": "^6.14.1",
|
||||
"raw-body": "^3.0.1",
|
||||
"type-is": "^2.0.1"
|
||||
"qs": "^6.15.2",
|
||||
"raw-body": "^3.0.2",
|
||||
"type-is": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -9237,6 +9468,19 @@
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/content-type": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
|
||||
"integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/iconv-lite": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
|
||||
@@ -11925,9 +12169,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz",
|
||||
"integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -13389,9 +13633,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
|
||||
"integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
|
||||
"integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -14349,12 +14593,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "16.2.6",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz",
|
||||
"integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==",
|
||||
"version": "16.2.11",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.2.11.tgz",
|
||||
"integrity": "sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "16.2.6",
|
||||
"@next/env": "16.2.11",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"baseline-browser-mapping": "^2.9.19",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
@@ -14368,14 +14612,14 @@
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.2.6",
|
||||
"@next/swc-darwin-x64": "16.2.6",
|
||||
"@next/swc-linux-arm64-gnu": "16.2.6",
|
||||
"@next/swc-linux-arm64-musl": "16.2.6",
|
||||
"@next/swc-linux-x64-gnu": "16.2.6",
|
||||
"@next/swc-linux-x64-musl": "16.2.6",
|
||||
"@next/swc-win32-arm64-msvc": "16.2.6",
|
||||
"@next/swc-win32-x64-msvc": "16.2.6",
|
||||
"@next/swc-darwin-arm64": "16.2.11",
|
||||
"@next/swc-darwin-x64": "16.2.11",
|
||||
"@next/swc-linux-arm64-gnu": "16.2.11",
|
||||
"@next/swc-linux-arm64-musl": "16.2.11",
|
||||
"@next/swc-linux-x64-gnu": "16.2.11",
|
||||
"@next/swc-linux-x64-musl": "16.2.11",
|
||||
"@next/swc-win32-arm64-msvc": "16.2.11",
|
||||
"@next/swc-win32-x64-msvc": "16.2.11",
|
||||
"sharp": "^0.34.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
+3
-3
@@ -74,7 +74,7 @@
|
||||
"@xterm/addon-web-links": "^0.12.0",
|
||||
"@xterm/xterm": "^6.0.0",
|
||||
"arctic": "3.7.0",
|
||||
"axios": "1.16.1",
|
||||
"axios": "1.18.0",
|
||||
"better-sqlite3": "11.9.1",
|
||||
"canvas-confetti": "1.9.4",
|
||||
"class-variance-authority": "0.7.1",
|
||||
@@ -93,12 +93,12 @@
|
||||
"input-otp": "1.4.2",
|
||||
"ioredis": "5.11.0",
|
||||
"jmespath": "0.16.0",
|
||||
"js-yaml": "4.2.0",
|
||||
"js-yaml": "4.3.0",
|
||||
"jsonwebtoken": "9.0.3",
|
||||
"lucide-react": "1.17.0",
|
||||
"maxmind": "5.0.6",
|
||||
"moment": "2.30.1",
|
||||
"next": "16.2.6",
|
||||
"next": "16.2.11",
|
||||
"next-intl": "4.13.0",
|
||||
"next-themes": "0.4.6",
|
||||
"nextjs-toploader": "3.9.17",
|
||||
|
||||
@@ -18,7 +18,7 @@ export const domains = pgTable("domains", {
|
||||
domainId: varchar("domainId").primaryKey(),
|
||||
baseDomain: varchar("baseDomain").notNull(),
|
||||
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),
|
||||
failed: boolean("failed").notNull().default(false),
|
||||
tries: integer("tries").notNull().default(0),
|
||||
|
||||
@@ -15,7 +15,7 @@ export const domains = sqliteTable("domains", {
|
||||
configManaged: integer("configManaged", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
type: text("type"), // "ns", "cname", "wildcard"
|
||||
type: text("type").$type<"ns" | "cname" | "wildcard">(),
|
||||
verified: integer("verified", { mode: "boolean" }).notNull().default(false),
|
||||
failed: integer("failed", { mode: "boolean" }).notNull().default(false),
|
||||
tries: integer("tries").notNull().default(0),
|
||||
|
||||
@@ -2,7 +2,7 @@ import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
// This is a placeholder value replaced by the build process
|
||||
export const APP_VERSION = "1.21.0";
|
||||
export const APP_VERSION = "1.21.1";
|
||||
|
||||
export const __FILENAME = fileURLToPath(import.meta.url);
|
||||
export const __DIRNAME = path.dirname(__FILENAME);
|
||||
|
||||
+120
-5
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { db, logsDb, statusHistory } from "@server/db";
|
||||
import { and, eq, gte, lt, asc, desc } from "drizzle-orm";
|
||||
import { and, eq, gte, lt, asc, desc, inArray, max, sql } from "drizzle-orm";
|
||||
import { regionalCache as cache } from "#dynamic/lib/cache";
|
||||
|
||||
const STATUS_HISTORY_CACHE_TTL = 60; // seconds
|
||||
@@ -264,9 +264,7 @@ export function computeBuckets(
|
||||
|
||||
// Shift by the client's offset before formatting so the label reflects
|
||||
// their local calendar date rather than the UTC date of dayStartSec
|
||||
const dateStr = new Date(
|
||||
(dayStartSec + tzOffsetMinutes * 60) * 1000
|
||||
)
|
||||
const dateStr = new Date((dayStartSec + tzOffsetMinutes * 60) * 1000)
|
||||
.toISOString()
|
||||
.slice(0, 10);
|
||||
|
||||
@@ -301,6 +299,123 @@ export function computeBuckets(
|
||||
status
|
||||
});
|
||||
}
|
||||
|
||||
return { buckets, totalDowntime };
|
||||
}
|
||||
|
||||
export type BatchedStatusHistoryResponse = Record<
|
||||
string,
|
||||
StatusHistoryResponse
|
||||
>;
|
||||
|
||||
export async function getBatchedStatusHistory(
|
||||
entityType: string,
|
||||
entityIds: number[],
|
||||
days: number,
|
||||
tzOffsetMinutes: number = 0
|
||||
): Promise<BatchedStatusHistoryResponse> {
|
||||
// Anchor to local midnight (UTC when tzOffsetMinutes is 0) so the query
|
||||
// window aligns with stable calendar days for the requesting client
|
||||
const todayMidnightSec = localMidnightSec(tzOffsetMinutes);
|
||||
const startSec = todayMidnightSec - days * 86400;
|
||||
|
||||
const events = await logsDb
|
||||
.select()
|
||||
.from(statusHistory)
|
||||
.where(
|
||||
and(
|
||||
eq(statusHistory.entityType, entityType),
|
||||
inArray(statusHistory.entityId, entityIds),
|
||||
gte(statusHistory.timestamp, startSec)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(statusHistory.timestamp));
|
||||
|
||||
// Fetch the last known state before the window so that entities that
|
||||
// haven't changed status recently still show the correct status rather
|
||||
// than appearing as "no_data".
|
||||
|
||||
/**
|
||||
* If we used only postgres, we would have used `SELECT DISTINCT ON` to get the
|
||||
* latest event for each `entityId`,
|
||||
* but it doesn't work on SQLite, so instead we use a subquery,
|
||||
* the `ROW_NUMBER() OVER PARTITION` allows to assign a number
|
||||
* to each row ordered by the timestamp, the number 1 is the first one appearing in
|
||||
* the specified order, then the next and more, we only want the highest timestamp,
|
||||
* so we get for `row_number=1`
|
||||
*/
|
||||
const lastKnowEventsSub = logsDb
|
||||
.select({
|
||||
entityId: statusHistory.entityId,
|
||||
status: statusHistory.status,
|
||||
timestamp: statusHistory.timestamp,
|
||||
row_number:
|
||||
sql<number>`ROW_NUMBER() OVER (PARTITION BY ${statusHistory.entityId} ORDER BY ${statusHistory.timestamp} DESC)`.as(
|
||||
"row_number"
|
||||
)
|
||||
})
|
||||
.from(statusHistory)
|
||||
.where(
|
||||
and(
|
||||
eq(statusHistory.entityType, entityType),
|
||||
inArray(statusHistory.entityId, entityIds),
|
||||
lt(statusHistory.timestamp, startSec)
|
||||
)
|
||||
)
|
||||
.as("sub");
|
||||
|
||||
const lastKnownEvents = await logsDb
|
||||
.select({
|
||||
entityId: lastKnowEventsSub.entityId,
|
||||
status: lastKnowEventsSub.status,
|
||||
timestamp: lastKnowEventsSub.timestamp
|
||||
})
|
||||
.from(lastKnowEventsSub)
|
||||
.where(eq(lastKnowEventsSub.row_number, 1));
|
||||
|
||||
const eventStatusMap: Record<
|
||||
number,
|
||||
{
|
||||
events: typeof events;
|
||||
lastKnownEvent: (typeof lastKnownEvents)[number] | null;
|
||||
}
|
||||
> = {};
|
||||
|
||||
for (const entityId of entityIds) {
|
||||
eventStatusMap[entityId] = {
|
||||
events: events.filter((ev) => ev.entityId === entityId),
|
||||
lastKnownEvent:
|
||||
lastKnownEvents.find((ev) => ev.entityId === entityId) ?? null
|
||||
};
|
||||
}
|
||||
|
||||
const result: BatchedStatusHistoryResponse = {};
|
||||
|
||||
for (const entityId in eventStatusMap) {
|
||||
const event = eventStatusMap[Number(entityId)];
|
||||
const priorStatus = event.lastKnownEvent?.status ?? null;
|
||||
|
||||
const { buckets, totalDowntime } = computeBuckets(
|
||||
event.events,
|
||||
days,
|
||||
priorStatus,
|
||||
tzOffsetMinutes
|
||||
);
|
||||
const totalWindow = days * 86400;
|
||||
const overallUptime =
|
||||
totalWindow > 0
|
||||
? Math.max(
|
||||
0,
|
||||
((totalWindow - totalDowntime) / totalWindow) * 100
|
||||
)
|
||||
: 100;
|
||||
|
||||
result[entityId] = {
|
||||
entityType,
|
||||
entityId: Number(entityId),
|
||||
days: buckets,
|
||||
overallUptimePercent: Math.round(overallUptime * 100) / 100,
|
||||
totalDowntimeSeconds: totalDowntime
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
import {
|
||||
getResourceRuleValueValidationError,
|
||||
isValidDomain,
|
||||
isValidUrlGlobPattern
|
||||
} from "./validators";
|
||||
import { assertEquals } from "@test/assert";
|
||||
|
||||
function runTests() {
|
||||
console.log("Running domain validation tests...");
|
||||
|
||||
assertEquals(
|
||||
isValidDomain("example.com"),
|
||||
true,
|
||||
"Standard ASCII domain should be valid"
|
||||
);
|
||||
assertEquals(
|
||||
isValidDomain("xn--e1afmkfd.xn--p1ai"),
|
||||
true,
|
||||
"Punycode IDN domain should be valid"
|
||||
);
|
||||
assertEquals(
|
||||
isValidDomain("example.invalid-tld"),
|
||||
false,
|
||||
"Domain with unknown TLD should be invalid"
|
||||
);
|
||||
|
||||
console.log("Running URL pattern validation tests...");
|
||||
|
||||
// Test valid patterns
|
||||
|
||||
@@ -171,9 +171,10 @@ export function isValidDomain(domain: string): boolean {
|
||||
if (!/^[a-zA-Z0-9-]+$/.test(label)) return false;
|
||||
}
|
||||
|
||||
// TLD should be at least 2 characters and contain only letters
|
||||
// TLD should be at least 2 characters. Punycode TLDs can contain digits
|
||||
// and hyphens, so validity is ultimately enforced by the TLD allowlist.
|
||||
const tld = labels[labels.length - 1];
|
||||
if (tld.length < 2 || !/^[a-zA-Z]+$/.test(tld)) return false;
|
||||
if (tld.length < 2) return false;
|
||||
|
||||
// Check if TLD is in the list of valid TLDs
|
||||
if (!validTlds.includes(tld.toUpperCase())) return false;
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* This file is part of a proprietary work.
|
||||
*
|
||||
* Copyright (c) 2025-2026 Fossorial, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is licensed under the Fossorial Commercial License.
|
||||
* You may not use this file except in compliance with the License.
|
||||
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
|
||||
*
|
||||
* This file is not licensed under the AGPLv3.
|
||||
*/
|
||||
import { certificates, db, domains, orgDomains } from "@server/db";
|
||||
import response from "@server/lib/response";
|
||||
import logger from "@server/logger";
|
||||
import { type GetBatchedCertificateResponse } from "@server/routers/certificates/types";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { and, eq, inArray, or } from "drizzle-orm";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const getCertificateParamSchema = z.strictObject({
|
||||
orgId: z.string()
|
||||
});
|
||||
|
||||
const getCertificateQuerySchema = z.object({
|
||||
domains: z.preprocess(
|
||||
(val) => {
|
||||
if (val === undefined || val === null || val === "") {
|
||||
return undefined;
|
||||
}
|
||||
if (Array.isArray(val)) {
|
||||
return val;
|
||||
}
|
||||
// the array is returned as this
|
||||
if (typeof val === "string") {
|
||||
return val.split(",");
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
z.array(z.string().min(1).max(255))
|
||||
)
|
||||
});
|
||||
|
||||
async function query(orgId: string, domainList: string[]) {
|
||||
// Try to get CNAME certificates first
|
||||
let existingCertificates = await db
|
||||
.select({
|
||||
certId: certificates.certId,
|
||||
domain: certificates.domain,
|
||||
wildcard: certificates.wildcard,
|
||||
status: certificates.status,
|
||||
expiresAt: certificates.expiresAt,
|
||||
lastRenewalAttempt: certificates.lastRenewalAttempt,
|
||||
createdAt: certificates.createdAt,
|
||||
updatedAt: certificates.updatedAt,
|
||||
errorMessage: certificates.errorMessage,
|
||||
renewalCount: certificates.renewalCount,
|
||||
domainId: domains.domainId,
|
||||
domainType: domains.type
|
||||
})
|
||||
.from(certificates)
|
||||
.innerJoin(domains, eq(certificates.domainId, domains.domainId))
|
||||
.innerJoin(
|
||||
orgDomains,
|
||||
and(
|
||||
eq(domains.domainId, orgDomains.domainId),
|
||||
eq(orgDomains.orgId, orgId)
|
||||
)
|
||||
)
|
||||
.where(and(inArray(certificates.domain, domainList)));
|
||||
|
||||
// All non resolved domain certificates might be `ns` or `wildcard`,
|
||||
// which means exact domain certificates do not
|
||||
const nonAvailableCertificates = existingCertificates
|
||||
.filter((cert) => !domainList.includes(cert.domain))
|
||||
.map((cert) => cert.domain);
|
||||
|
||||
if (nonAvailableCertificates.length > 0) {
|
||||
const domainLevelDownSet = new Set<string>();
|
||||
const wildcardDomainSet = new Set<string>();
|
||||
|
||||
for (const domain of nonAvailableCertificates) {
|
||||
const domainLevelDown = domain.split(".").slice(1).join(".");
|
||||
const wildcardPrefixed = `*.${domainLevelDown}`;
|
||||
domainLevelDownSet.add(domainLevelDown);
|
||||
wildcardDomainSet.add(wildcardPrefixed);
|
||||
}
|
||||
|
||||
// Need to map the certificates to each domain
|
||||
const wildcardCertificates = await db
|
||||
.select({
|
||||
certId: certificates.certId,
|
||||
domain: certificates.domain,
|
||||
wildcard: certificates.wildcard,
|
||||
status: certificates.status,
|
||||
expiresAt: certificates.expiresAt,
|
||||
lastRenewalAttempt: certificates.lastRenewalAttempt,
|
||||
createdAt: certificates.createdAt,
|
||||
updatedAt: certificates.updatedAt,
|
||||
errorMessage: certificates.errorMessage,
|
||||
renewalCount: certificates.renewalCount,
|
||||
domainId: domains.domainId,
|
||||
domainType: domains.type
|
||||
})
|
||||
.from(certificates)
|
||||
.innerJoin(domains, eq(certificates.domainId, domains.domainId))
|
||||
.innerJoin(
|
||||
orgDomains,
|
||||
and(
|
||||
eq(domains.domainId, orgDomains.domainId),
|
||||
eq(orgDomains.orgId, orgId)
|
||||
)
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
eq(certificates.wildcard, true),
|
||||
or(
|
||||
inArray(certificates.domain, [...domainLevelDownSet]),
|
||||
inArray(certificates.domain, [...wildcardDomainSet])
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
existingCertificates.push(...wildcardCertificates);
|
||||
}
|
||||
|
||||
const certificateMap: Record<string, any> = {};
|
||||
for (const domain of domainList) {
|
||||
const domainLevelDown = domain.split(".").slice(1).join(".");
|
||||
const wildcardPrefixed = `*.${domainLevelDown}`;
|
||||
certificateMap[domain] =
|
||||
existingCertificates.find(
|
||||
(cert) =>
|
||||
cert.domain === domain ||
|
||||
cert.domain === domainLevelDown ||
|
||||
cert.domain === wildcardPrefixed
|
||||
) ?? null;
|
||||
}
|
||||
|
||||
return certificateMap;
|
||||
}
|
||||
|
||||
export async function getBatchedCertificates(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedParams = getCertificateParamSchema.safeParse(req.params);
|
||||
if (!parsedParams.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedParams.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { orgId } = parsedParams.data;
|
||||
const parsedQuery = getCertificateQuerySchema.safeParse(req.query);
|
||||
if (!parsedQuery.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedQuery.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { domains } = parsedQuery.data;
|
||||
|
||||
const cert = await query(orgId, domains);
|
||||
|
||||
return response<GetBatchedCertificateResponse>(res, {
|
||||
data: cert,
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Certificates retrieved successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -14,3 +14,4 @@
|
||||
export * from "./getCertificate";
|
||||
export * from "./restartCertificate";
|
||||
export * from "./syncCertToNewts";
|
||||
export * from "./getBatchedCertificates";
|
||||
|
||||
@@ -11,18 +11,16 @@
|
||||
* This file is not licensed under the AGPLv3.
|
||||
*/
|
||||
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { certificates, db } from "@server/db";
|
||||
import { sites } from "@server/db";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import logger from "@server/logger";
|
||||
import stoi from "@server/lib/stoi";
|
||||
import { registry } from "@server/openApi";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
|
||||
const restartCertificateParamsSchema = z.strictObject({
|
||||
certId: z.coerce.number().int().positive(),
|
||||
|
||||
@@ -175,6 +175,13 @@ authenticated.get(
|
||||
certificates.getCertificate
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/batched-certificates",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.getCertificate),
|
||||
certificates.getBatchedCertificates
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/certificate/:certId/restart",
|
||||
verifyValidLicense,
|
||||
@@ -853,6 +860,14 @@ authenticated.get(
|
||||
healthChecks.getHealthCheckStatusHistory
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/health-check-status-histories",
|
||||
verifyValidLicense,
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.getTarget),
|
||||
healthChecks.getBatchedHealthCheckStatusHistory
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/client/:clientId/verify-associations-cache",
|
||||
verifyClientAccess,
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is part of a proprietary work.
|
||||
*
|
||||
* Copyright (c) 2025-2026 Fossorial, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is licensed under the Fossorial Commercial License.
|
||||
* You may not use this file except in compliance with the License.
|
||||
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
|
||||
*
|
||||
* This file is not licensed under the AGPLv3.
|
||||
*/
|
||||
|
||||
import response from "@server/lib/response";
|
||||
import {
|
||||
getBatchedStatusHistory,
|
||||
type BatchedStatusHistoryResponse
|
||||
} from "@server/lib/statusHistory";
|
||||
import logger from "@server/logger";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const healthCheckIdParamsSchema = z.object({
|
||||
days: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => (v ? parseInt(v, 10) : 90)),
|
||||
// Minutes to add to UTC to get the requesting client's local time
|
||||
// (e.g. Australia/Sydney standard time is 600). Optional and
|
||||
// defaults to 0 (UTC) so older clients keep the prior behavior.
|
||||
tzOffsetMinutes: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => (v ? parseInt(v, 10) : 0)),
|
||||
healthCheckIds: z
|
||||
.preprocess((val) => {
|
||||
if (val === undefined || val === null || val === "") {
|
||||
return undefined;
|
||||
}
|
||||
const raw = Array.isArray(val) ? val : [val];
|
||||
const nums = raw
|
||||
.map((v) =>
|
||||
typeof v === "string" ? parseInt(v, 10) : Number(v)
|
||||
)
|
||||
.filter((n) => Number.isInteger(n) && n > 0);
|
||||
const unique = [...new Set(nums)];
|
||||
return unique.length ? unique : undefined;
|
||||
}, z.array(z.number().int().positive()))
|
||||
.openapi({
|
||||
description: "Filter by healthCheckIds (repeat query param)"
|
||||
})
|
||||
});
|
||||
|
||||
export async function getBatchedHealthCheckStatusHistory(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedQuery = healthCheckIdParamsSchema.safeParse(req.query);
|
||||
if (!parsedQuery.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedQuery.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const entityType = "health_check";
|
||||
const { days, healthCheckIds, tzOffsetMinutes } = parsedQuery.data;
|
||||
|
||||
const data = await getBatchedStatusHistory(
|
||||
entityType,
|
||||
healthCheckIds,
|
||||
days,
|
||||
tzOffsetMinutes
|
||||
);
|
||||
|
||||
return response<BatchedStatusHistoryResponse>(res, {
|
||||
data,
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Status history retrieved successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -16,3 +16,4 @@ export * from "./createHealthCheck";
|
||||
export * from "./updateHealthCheck";
|
||||
export * from "./deleteHealthCheck";
|
||||
export * from "./getStatusHistory";
|
||||
export * from "./getBatchedStatusHistory";
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { Domain } from "@server/db";
|
||||
|
||||
export type GetCertificateResponse = {
|
||||
certId: number;
|
||||
domain: string;
|
||||
domainId: string;
|
||||
wildcard: boolean;
|
||||
domainType: string;
|
||||
domainType: Domain["type"];
|
||||
status: string; // pending, requested, valid, expired, failed
|
||||
expiresAt: string | null;
|
||||
lastRenewalAttempt: Date | null;
|
||||
@@ -11,4 +13,9 @@ export type GetCertificateResponse = {
|
||||
updatedAt: number;
|
||||
errorMessage?: string | null;
|
||||
renewalCount: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type GetBatchedCertificateResponse = Record<
|
||||
string,
|
||||
GetCertificateResponse | null
|
||||
>;
|
||||
|
||||
@@ -319,6 +319,13 @@ authenticated.get(
|
||||
site.getSiteStatusHistory
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/site-status-histories",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.listSites),
|
||||
site.getBatchedSiteStatusHistory
|
||||
);
|
||||
|
||||
// Site Resource endpoints
|
||||
authenticated.put(
|
||||
"/org/:orgId/site-resource",
|
||||
@@ -469,6 +476,13 @@ authenticated.get(
|
||||
resource.getResourceStatusHistory
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/resource-status-histories",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.listResources),
|
||||
resource.getBatchedResourceStatusHistory
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/resources",
|
||||
verifyOrgAccess,
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import response from "@server/lib/response";
|
||||
import {
|
||||
getBatchedStatusHistory,
|
||||
type BatchedStatusHistoryResponse
|
||||
} from "@server/lib/statusHistory";
|
||||
import logger from "@server/logger";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const resourceIdParamsSchema = z.object({
|
||||
days: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => (v ? parseInt(v, 10) : 90)),
|
||||
// Minutes to add to UTC to get the requesting client's local time
|
||||
// (e.g. Australia/Sydney standard time is 600). Optional and
|
||||
// defaults to 0 (UTC) so older clients keep the prior behavior.
|
||||
tzOffsetMinutes: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => (v ? parseInt(v, 10) : 0)),
|
||||
resourceIds: z
|
||||
.preprocess((val) => {
|
||||
if (val === undefined || val === null || val === "") {
|
||||
return undefined;
|
||||
}
|
||||
const raw = Array.isArray(val) ? val : [val];
|
||||
const nums = raw
|
||||
.map((v) =>
|
||||
typeof v === "string" ? parseInt(v, 10) : Number(v)
|
||||
)
|
||||
.filter((n) => Number.isInteger(n) && n > 0);
|
||||
const unique = [...new Set(nums)];
|
||||
return unique.length ? unique : undefined;
|
||||
}, z.array(z.number().int().positive()))
|
||||
.openapi({
|
||||
description: "Filter by resourceIds (repeat query param)"
|
||||
})
|
||||
});
|
||||
|
||||
export async function getBatchedResourceStatusHistory(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedQuery = resourceIdParamsSchema.safeParse(req.query);
|
||||
if (!parsedQuery.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedQuery.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const entityType = "resource";
|
||||
const { days, resourceIds, tzOffsetMinutes } = parsedQuery.data;
|
||||
|
||||
const data = await getBatchedStatusHistory(
|
||||
entityType,
|
||||
resourceIds,
|
||||
days,
|
||||
tzOffsetMinutes
|
||||
);
|
||||
|
||||
return response<BatchedStatusHistoryResponse>(res, {
|
||||
data,
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Status history retrieved successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -33,4 +33,5 @@ export * from "./removeUserFromResource";
|
||||
export * from "./listAllResourceNames";
|
||||
export * from "./removeEmailFromResourceWhitelist";
|
||||
export * from "./getStatusHistory";
|
||||
export * from "./getBatchedStatusHistory";
|
||||
export * from "./getResourcePolicies";
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import response from "@server/lib/response";
|
||||
import {
|
||||
getBatchedStatusHistory,
|
||||
type BatchedStatusHistoryResponse
|
||||
} from "@server/lib/statusHistory";
|
||||
import logger from "@server/logger";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const siteIdParamsSchema = z.object({
|
||||
days: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => (v ? parseInt(v, 10) : 90)),
|
||||
// Minutes to add to UTC to get the requesting client's local time
|
||||
// (e.g. Australia/Sydney standard time is 600). Optional and
|
||||
// defaults to 0 (UTC) so older clients keep the prior behavior.
|
||||
tzOffsetMinutes: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((v) => (v ? parseInt(v, 10) : 0)),
|
||||
siteIds: z
|
||||
.preprocess((val) => {
|
||||
if (val === undefined || val === null || val === "") {
|
||||
return undefined;
|
||||
}
|
||||
const raw = Array.isArray(val) ? val : [val];
|
||||
const nums = raw
|
||||
.map((v) =>
|
||||
typeof v === "string" ? parseInt(v, 10) : Number(v)
|
||||
)
|
||||
.filter((n) => Number.isInteger(n) && n > 0);
|
||||
const unique = [...new Set(nums)];
|
||||
return unique.length ? unique : undefined;
|
||||
}, z.array(z.number().int().positive()))
|
||||
.openapi({
|
||||
description: "Filter by siteIds (repeat query param)"
|
||||
})
|
||||
});
|
||||
|
||||
export async function getBatchedSiteStatusHistory(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedQuery = siteIdParamsSchema.safeParse(req.query);
|
||||
if (!parsedQuery.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedQuery.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const entityType = "site";
|
||||
const { days, siteIds, tzOffsetMinutes } = parsedQuery.data;
|
||||
|
||||
const data = await getBatchedStatusHistory(
|
||||
entityType,
|
||||
siteIds,
|
||||
days,
|
||||
tzOffsetMinutes
|
||||
);
|
||||
|
||||
return response<BatchedStatusHistoryResponse>(res, {
|
||||
data,
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Status history retrieved successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from "./getSite";
|
||||
export * from "./getStatusHistory";
|
||||
export * from "./getBatchedStatusHistory";
|
||||
export * from "./createSite";
|
||||
export * from "./deleteSite";
|
||||
export * from "./updateSite";
|
||||
|
||||
@@ -6,6 +6,8 @@ import { internal } from "@app/lib/api";
|
||||
import { authCookieHeader } from "@app/lib/api/cookies";
|
||||
import { getCachedOrg } from "@app/lib/api/getCachedOrg";
|
||||
import OrgProvider from "@app/providers/OrgProvider";
|
||||
import { build } from "@server/build";
|
||||
import type { GetBatchedCertificateResponse } from "@server/routers/certificates/types";
|
||||
import type { ListAllSiteResourcesByOrgResponse } from "@server/routers/siteResource";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { Metadata } from "next";
|
||||
@@ -99,6 +101,42 @@ export default async function ClientResourcesPage(
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Prefetched in one batched call so the table doesn't fire a separate
|
||||
// certificate request per visible row once it mounts on the client.
|
||||
const certDomains = Array.from(
|
||||
new Set(
|
||||
internalResourceRows
|
||||
.filter(
|
||||
(r) =>
|
||||
r.mode === "http" &&
|
||||
!r.alias &&
|
||||
r.ssl &&
|
||||
r.domainId &&
|
||||
r.fullDomain
|
||||
)
|
||||
.map((r) => r.fullDomain as string)
|
||||
)
|
||||
);
|
||||
|
||||
let initialCertificates: GetBatchedCertificateResponse | undefined;
|
||||
if (build !== "oss" && certDomains.length > 0) {
|
||||
try {
|
||||
const certSearchParams = new URLSearchParams(
|
||||
certDomains.map((domain) => ["domains", domain])
|
||||
);
|
||||
const certRes = await internal.get<
|
||||
AxiosResponse<GetBatchedCertificateResponse>
|
||||
>(
|
||||
`/org/${params.orgId}/batched-certificates?${certSearchParams.toString()}`,
|
||||
await authCookieHeader()
|
||||
);
|
||||
initialCertificates = certRes.data.data;
|
||||
} catch {
|
||||
// leave undefined so each row falls back to fetching its own
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
@@ -117,6 +155,7 @@ export default async function ClientResourcesPage(
|
||||
pageIndex: pagination.page - 1,
|
||||
pageSize: pagination.pageSize
|
||||
}}
|
||||
initialCertificates={initialCertificates}
|
||||
/>
|
||||
</OrgProvider>
|
||||
</>
|
||||
|
||||
@@ -5,6 +5,8 @@ import PublicResourcesBanner from "@app/components/PublicResourcesBanner";
|
||||
import { internal } from "@app/lib/api";
|
||||
import { authCookieHeader } from "@app/lib/api/cookies";
|
||||
import OrgProvider from "@app/providers/OrgProvider";
|
||||
import { build } from "@server/build";
|
||||
import type { GetBatchedCertificateResponse } from "@server/routers/certificates/types";
|
||||
import type { GetOrgResponse } from "@server/routers/org";
|
||||
import type { ListResourcesResponse } from "@server/routers/resource";
|
||||
import { GetSiteResponse } from "@server/routers/site/getSite";
|
||||
@@ -60,29 +62,7 @@ export default async function ProxyResourcesPage(
|
||||
searchParams.get("siteId") ?? undefined
|
||||
);
|
||||
|
||||
let initialFilterSite: {
|
||||
siteId: number;
|
||||
name: string;
|
||||
type: string;
|
||||
} | null = null;
|
||||
if (siteIdParam) {
|
||||
try {
|
||||
const siteRes = await internal.get(
|
||||
`/site/${siteIdParam}`,
|
||||
await authCookieHeader()
|
||||
);
|
||||
const s = (siteRes.data as ResponseT<GetSiteResponse>).data;
|
||||
if (s && s.orgId === params.orgId) {
|
||||
initialFilterSite = {
|
||||
siteId: s.siteId,
|
||||
name: s.name,
|
||||
type: s.type
|
||||
};
|
||||
}
|
||||
} catch {
|
||||
// leave null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let org = null;
|
||||
try {
|
||||
@@ -140,6 +120,34 @@ export default async function ProxyResourcesPage(
|
||||
health: (resource.health as ResourceRow["health"]) ?? undefined
|
||||
};
|
||||
});
|
||||
// Prefetched in one batched call so the table doesn't fire a separate
|
||||
// certificate request per visible row once it mounts on the client.
|
||||
const certDomains = Array.from(
|
||||
new Set(
|
||||
resourceRows
|
||||
.filter((r) => r.ssl && r.fullDomain)
|
||||
.map((r) => r.fullDomain as string)
|
||||
)
|
||||
);
|
||||
|
||||
let initialCertificates: GetBatchedCertificateResponse | undefined;
|
||||
if (build !== "oss" && certDomains.length > 0) {
|
||||
try {
|
||||
const certSearchParams = new URLSearchParams(
|
||||
certDomains.map((domain) => ["domains", domain])
|
||||
);
|
||||
const certRes = await internal.get<
|
||||
AxiosResponse<GetBatchedCertificateResponse>
|
||||
>(
|
||||
`/org/${params.orgId}/batched-certificates?${certSearchParams.toString()}`,
|
||||
await authCookieHeader()
|
||||
);
|
||||
initialCertificates = certRes.data.data;
|
||||
} catch {
|
||||
// leave undefined so each row falls back to fetching its own
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
@@ -158,7 +166,7 @@ export default async function ProxyResourcesPage(
|
||||
pageIndex: pagination.page - 1,
|
||||
pageSize: pagination.pageSize
|
||||
}}
|
||||
initialFilterSite={initialFilterSite}
|
||||
initialCertificates={initialCertificates}
|
||||
/>
|
||||
</OrgProvider>
|
||||
</>
|
||||
|
||||
@@ -412,7 +412,6 @@ function AuthPageSettings({
|
||||
fullDomain={
|
||||
loginPage.fullDomain
|
||||
}
|
||||
autoFetch={true}
|
||||
showLabel={true}
|
||||
polling={true}
|
||||
/>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { FileBadge, RotateCw } from "lucide-react";
|
||||
import { useCertificate } from "@app/hooks/useCertificate";
|
||||
import type { GetCertificateResponse } from "@server/routers/certificates/types";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { durationToMs } from "@app/lib/durationToMs";
|
||||
|
||||
export type CertificateStatusContentProps = {
|
||||
cert: GetCertificateResponse | null;
|
||||
@@ -32,8 +33,7 @@ export function CertificateStatusContent({
|
||||
|
||||
const labelClass =
|
||||
"inline-flex shrink-0 items-center self-center text-sm font-medium leading-normal";
|
||||
const valueClass =
|
||||
"inline-flex items-center gap-2 text-sm leading-normal";
|
||||
const valueClass = "inline-flex items-center gap-2 text-sm leading-normal";
|
||||
|
||||
const handleRefresh = async () => {
|
||||
await refreshCert();
|
||||
@@ -187,7 +187,6 @@ type CertificateStatusProps = {
|
||||
orgId: string;
|
||||
domainId: string;
|
||||
fullDomain: string;
|
||||
autoFetch?: boolean;
|
||||
showLabel?: boolean;
|
||||
className?: string;
|
||||
onRefresh?: () => void;
|
||||
@@ -199,18 +198,16 @@ export default function CertificateStatus({
|
||||
orgId,
|
||||
domainId,
|
||||
fullDomain,
|
||||
autoFetch = true,
|
||||
showLabel = true,
|
||||
className = "",
|
||||
onRefresh,
|
||||
polling = false,
|
||||
pollingInterval = 5000
|
||||
pollingInterval = durationToMs(5, "seconds")
|
||||
}: CertificateStatusProps) {
|
||||
const hook = useCertificate({
|
||||
orgId,
|
||||
domainId,
|
||||
fullDomain,
|
||||
autoFetch,
|
||||
polling,
|
||||
pollingInterval
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import UptimeMiniBar from "@app/components/UptimeMiniBar";
|
||||
import { UptimeMiniBar } from "@app/components/UptimeMiniBar";
|
||||
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import HealthCheckCredenza, {
|
||||
@@ -51,6 +51,8 @@ import { usePaidStatus } from "@app/hooks/usePaidStatus";
|
||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
import { cn } from "@app/lib/cn";
|
||||
import { dataTableFilterPopoverContentClassName } from "@app/lib/dataTableFilterPopover";
|
||||
import { orgQueries } from "@app/lib/queries";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
type StandaloneHealthChecksTableProps = {
|
||||
orgId: string;
|
||||
@@ -81,6 +83,8 @@ function formatTarget(row: HealthCheckRow): string {
|
||||
return `${scheme}://${host}${port}${path}`;
|
||||
}
|
||||
|
||||
const HEALTH_CHECK_STATUS_HISTORY_DAYS = 30;
|
||||
|
||||
export default function HealthChecksTable({
|
||||
orgId,
|
||||
healthChecks,
|
||||
@@ -157,6 +161,20 @@ export default function HealthChecksTable({
|
||||
|
||||
const rows = healthChecks;
|
||||
|
||||
const healthCheckIds = useMemo(
|
||||
() => rows.map((r) => r.targetHealthCheckId),
|
||||
[rows]
|
||||
);
|
||||
|
||||
const statusHistoryQuery = useQuery({
|
||||
...orgQueries.batchedHealthCheckStatusHistory({
|
||||
orgId,
|
||||
healthCheckIds,
|
||||
days: HEALTH_CHECK_STATUS_HISTORY_DAYS
|
||||
}),
|
||||
enabled: healthCheckIds.length > 0
|
||||
});
|
||||
|
||||
function refreshList() {
|
||||
startRefresh(() => {
|
||||
router.refresh();
|
||||
@@ -547,9 +565,13 @@ export default function HealthChecksTable({
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<UptimeMiniBar
|
||||
orgId={orgId}
|
||||
healthCheckId={row.original.targetHealthCheckId}
|
||||
days={30}
|
||||
isLoading={statusHistoryQuery.isLoading}
|
||||
data={
|
||||
statusHistoryQuery.data?.[
|
||||
row.original.targetHealthCheckId
|
||||
]
|
||||
}
|
||||
days={HEALTH_CHECK_STATUS_HISTORY_DAYS}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ export default function IdpTypeIcon({
|
||||
}: Props) {
|
||||
const effectiveType = (variant || type || "").toLowerCase();
|
||||
|
||||
console.log(`[IdpTypeIcon]`, { effectiveType, variant, type });
|
||||
|
||||
let src: string | null = null;
|
||||
let defaultAlt = "";
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import { getPrivateResourceSettingsHref } from "@app/lib/launcherResourceAdminHr
|
||||
import { getNextSortOrder, getSortDirection } from "@app/lib/sortColumn";
|
||||
import { build } from "@server/build";
|
||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
import type { GetBatchedCertificateResponse } from "@server/routers/certificates/types";
|
||||
import { UpdateSiteResourceResponse } from "@server/routers/siteResource";
|
||||
import type { PaginationState } from "@tanstack/react-table";
|
||||
import { AxiosResponse } from "axios";
|
||||
@@ -136,13 +137,16 @@ type ClientResourcesTableProps = {
|
||||
orgId: string;
|
||||
pagination: PaginationState;
|
||||
rowCount: number;
|
||||
/** Certificates prefetched on the server, keyed by full domain. */
|
||||
initialCertificates?: GetBatchedCertificateResponse;
|
||||
};
|
||||
|
||||
export default function PrivateResourcesTable({
|
||||
internalResources,
|
||||
orgId,
|
||||
pagination,
|
||||
rowCount
|
||||
rowCount,
|
||||
initialCertificates
|
||||
}: ClientResourcesTableProps) {
|
||||
const router = useRouter();
|
||||
const {
|
||||
@@ -432,6 +436,9 @@ export default function PrivateResourcesTable({
|
||||
orgId={resourceRow.orgId}
|
||||
domainId={domainId}
|
||||
fullDomain={fullDomain}
|
||||
initialCertValue={
|
||||
initialCertificates?.[fullDomain]
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
<div className="">
|
||||
@@ -585,7 +592,7 @@ export default function PrivateResourcesTable({
|
||||
];
|
||||
|
||||
return cols;
|
||||
}, [orgId, t, searchParams]);
|
||||
}, [orgId, t, searchParams, initialCertificates]);
|
||||
|
||||
function handleFilterChange(
|
||||
column: string,
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
ResourceSitesStatusCell,
|
||||
type ResourceSiteRow
|
||||
} from "@app/components/ResourceSitesStatusCell";
|
||||
import { Selectedsite, SitesSelector } from "@app/components/site-selector";
|
||||
import { Badge } from "@app/components/ui/badge";
|
||||
import { Selectedsite } from "@app/components/site-selector";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import { ExtendedColumnDef } from "@app/components/ui/data-table";
|
||||
import {
|
||||
@@ -18,23 +17,19 @@ import {
|
||||
DropdownMenuTrigger
|
||||
} from "@app/components/ui/dropdown-menu";
|
||||
import { InfoPopup } from "@app/components/ui/info-popup";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger
|
||||
} from "@app/components/ui/popover";
|
||||
import { Switch } from "@app/components/ui/switch";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { useNavigationContext } from "@app/hooks/useNavigationContext";
|
||||
import { useOptimisticLabels } from "@app/hooks/useOptimisticLabels";
|
||||
import { usePaidStatus } from "@app/hooks/usePaidStatus";
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||
import { cn } from "@app/lib/cn";
|
||||
import { dataTableFilterPopoverContentClassName } from "@app/lib/dataTableFilterPopover";
|
||||
import { orgQueries } from "@app/lib/queries";
|
||||
import { getNextSortOrder, getSortDirection } from "@app/lib/sortColumn";
|
||||
import { build } from "@server/build";
|
||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
import { UpdateResourceResponse } from "@server/routers/resource";
|
||||
import type { GetBatchedCertificateResponse } from "@server/routers/certificates/types";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { PaginationState } from "@tanstack/react-table";
|
||||
import { AxiosResponse } from "axios";
|
||||
import {
|
||||
@@ -45,9 +40,7 @@ import {
|
||||
ChevronDown,
|
||||
ChevronsUpDownIcon,
|
||||
Clock,
|
||||
Funnel,
|
||||
MoreHorizontal,
|
||||
PlusIcon,
|
||||
ShieldCheck,
|
||||
ShieldOff,
|
||||
XCircle
|
||||
@@ -57,7 +50,6 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import {
|
||||
startTransition,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useOptimistic,
|
||||
useRef,
|
||||
@@ -68,15 +60,11 @@ import {
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import z from "zod";
|
||||
import { ColumnFilterButton } from "./ColumnFilterButton";
|
||||
import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||
import UptimeMiniBar from "./UptimeMiniBar";
|
||||
import { type SelectedLabel } from "./labels-selector";
|
||||
import { LabelColumnFilterButton } from "./LabelColumnFilterButton";
|
||||
import { useLocalLabels } from "@app/hooks/useLocalLabels";
|
||||
import { LabelsTableCell } from "./LabelsTableCell";
|
||||
import { useOptimisticLabels } from "@app/hooks/useOptimisticLabels";
|
||||
import { refresh } from "next/cache";
|
||||
import { SitesColumnFilterButton } from "./SitesColumnFilterButton";
|
||||
import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||
import { UptimeMiniBar } from "./UptimeMiniBar";
|
||||
|
||||
export type TargetHealth = {
|
||||
targetId: number;
|
||||
@@ -120,6 +108,8 @@ type ProxyResourcesTableProps = {
|
||||
pagination: PaginationState;
|
||||
rowCount: number;
|
||||
initialFilterSite?: Selectedsite | null;
|
||||
/** Certificates prefetched on the server, keyed by full domain. */
|
||||
initialCertificates?: GetBatchedCertificateResponse;
|
||||
};
|
||||
|
||||
const booleanSearchFilterSchema = z
|
||||
@@ -127,12 +117,14 @@ const booleanSearchFilterSchema = z
|
||||
.optional()
|
||||
.catch(undefined);
|
||||
|
||||
const RESOURCE_STATUS_HISTORY_DAYS = 30;
|
||||
|
||||
export default function PublicResourcesTable({
|
||||
resources,
|
||||
orgId,
|
||||
pagination,
|
||||
rowCount,
|
||||
initialFilterSite = null
|
||||
initialCertificates
|
||||
}: ProxyResourcesTableProps) {
|
||||
const router = useRouter();
|
||||
const {
|
||||
@@ -150,11 +142,24 @@ export default function PublicResourcesTable({
|
||||
const [selectedResource, setSelectedResource] =
|
||||
useState<ResourceRow | null>();
|
||||
|
||||
const { isPaidUser } = usePaidStatus();
|
||||
|
||||
const [isRefreshing, startTransition] = useTransition();
|
||||
const [isNavigatingToAddPage, startNavigation] = useTransition();
|
||||
|
||||
// Only http resources show an uptime bar, so don't ask for the others
|
||||
const statusHistoryResourceIds = useMemo(
|
||||
() => resources.filter((r) => r.mode === "http").map((r) => r.id),
|
||||
[resources]
|
||||
);
|
||||
|
||||
const statusHistoryQuery = useQuery({
|
||||
...orgQueries.batchedResourceStatusHistory({
|
||||
orgId,
|
||||
resourceIds: statusHistoryResourceIds,
|
||||
days: RESOURCE_STATUS_HISTORY_DAYS
|
||||
}),
|
||||
enabled: statusHistoryResourceIds.length > 0
|
||||
});
|
||||
|
||||
const refreshData = () => {
|
||||
startTransition(() => {
|
||||
try {
|
||||
@@ -407,7 +412,11 @@ export default function PublicResourcesTable({
|
||||
return <span>-</span>;
|
||||
}
|
||||
return (
|
||||
<UptimeMiniBar resourceId={resourceRow.id} days={30} />
|
||||
<UptimeMiniBar
|
||||
isLoading={statusHistoryQuery.isLoading}
|
||||
data={statusHistoryQuery.data?.[resourceRow.id]}
|
||||
days={RESOURCE_STATUS_HISTORY_DAYS}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -461,6 +470,9 @@ export default function PublicResourcesTable({
|
||||
orgId={resourceRow.orgId}
|
||||
domainId={domainId}
|
||||
fullDomain={certHostname}
|
||||
initialCertValue={
|
||||
initialCertificates?.[certHostname]
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
<div className="">
|
||||
@@ -625,7 +637,14 @@ export default function PublicResourcesTable({
|
||||
];
|
||||
|
||||
return cols;
|
||||
}, [orgId, t, searchParams]);
|
||||
}, [
|
||||
orgId,
|
||||
t,
|
||||
searchParams,
|
||||
statusHistoryQuery.data,
|
||||
statusHistoryQuery.isLoading,
|
||||
initialCertificates
|
||||
]);
|
||||
|
||||
function handleFilterChange(
|
||||
column: string,
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
PopoverContent
|
||||
} from "@app/components/ui/popover";
|
||||
import { useCertificate } from "@app/hooks/useCertificate";
|
||||
import type { GetCertificateResponse } from "@server/routers/certificates/types";
|
||||
import { cn } from "@app/lib/cn";
|
||||
import { FileBadge } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
@@ -17,11 +18,13 @@ import {
|
||||
useState,
|
||||
type ReactNode
|
||||
} from "react";
|
||||
import { durationToMs } from "@app/lib/durationToMs";
|
||||
|
||||
type ResourceAccessCertIndicatorProps = {
|
||||
orgId: string;
|
||||
domainId: string;
|
||||
fullDomain: string;
|
||||
initialCertValue?: GetCertificateResponse | null;
|
||||
};
|
||||
|
||||
function getStatusColor(status: string) {
|
||||
@@ -43,7 +46,8 @@ function getStatusColor(status: string) {
|
||||
export function ResourceAccessCertIndicator({
|
||||
orgId,
|
||||
domainId,
|
||||
fullDomain
|
||||
fullDomain,
|
||||
initialCertValue
|
||||
}: ResourceAccessCertIndicatorProps) {
|
||||
const t = useTranslations();
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -53,16 +57,19 @@ export function ResourceAccessCertIndicator({
|
||||
orgId,
|
||||
domainId,
|
||||
fullDomain,
|
||||
autoFetch: true,
|
||||
initialCertValue,
|
||||
polling: open,
|
||||
pollingInterval: 5000
|
||||
pollingInterval: durationToMs(5, "seconds")
|
||||
});
|
||||
|
||||
const { cert, certLoading, certError, refreshing, fetchCert } = certificate;
|
||||
|
||||
// `polling` only schedules on predefined intervals (1 second),
|
||||
// so the first request would be a full interval away if open = true (which set polling = true).
|
||||
// So we fetch immediately so the popover opens with fresh data.
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
void fetchCert(false);
|
||||
void fetchCert();
|
||||
}, [open, fetchCert]);
|
||||
|
||||
const clearCloseTimer = useCallback(() => {
|
||||
|
||||
@@ -180,7 +180,6 @@ export default function ResourceInfoBox({}: ResourceInfoBoxType) {
|
||||
orgId={resource.orgId}
|
||||
domainId={resource.domainId!}
|
||||
fullDomain={resource.fullDomain!}
|
||||
autoFetch={true}
|
||||
showLabel={false}
|
||||
polling={true}
|
||||
/>
|
||||
|
||||
@@ -182,7 +182,6 @@ export function SiteResourceInfoSections({
|
||||
orgId={siteResource.orgId}
|
||||
domainId={siteResource.domainId!}
|
||||
fullDomain={siteResource.fullDomain!}
|
||||
autoFetch={true}
|
||||
showLabel={false}
|
||||
polling={true}
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import UptimeMiniBar from "@app/components/UptimeMiniBar";
|
||||
import { UptimeMiniBar } from "@app/components/UptimeMiniBar";
|
||||
|
||||
import {
|
||||
Credenza,
|
||||
@@ -52,12 +52,12 @@ import {
|
||||
} from "./ui/controlled-data-table";
|
||||
|
||||
import { useOptimisticLabels } from "@app/hooks/useOptimisticLabels";
|
||||
import { usePaidStatus } from "@app/hooks/usePaidStatus";
|
||||
import { durationToMs } from "@app/lib/durationToMs";
|
||||
import { orgQueries, productUpdatesQueries } from "@app/lib/queries";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import semver from "semver";
|
||||
import { LabelColumnFilterButton } from "./LabelColumnFilterButton";
|
||||
import { LabelsTableCell } from "./LabelsTableCell";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { productUpdatesQueries } from "@app/lib/queries";
|
||||
import semver from "semver";
|
||||
|
||||
export type SiteRow = {
|
||||
id: number;
|
||||
@@ -89,6 +89,8 @@ type SitesTableProps = {
|
||||
rowCount: number;
|
||||
};
|
||||
|
||||
const SITE_STATUS_HISTORY_DAYS = 30;
|
||||
|
||||
export default function SitesTable({
|
||||
sites,
|
||||
orgId,
|
||||
@@ -112,7 +114,16 @@ export default function SitesTable({
|
||||
const [isRefreshing, startTransition] = useTransition();
|
||||
const [isNavigatingToAddPage, startNavigation] = useTransition();
|
||||
|
||||
const { isPaidUser } = usePaidStatus();
|
||||
const siteIds = useMemo(() => sites.map((s) => s.id), [sites]);
|
||||
|
||||
const statusHistoryQuery = useQuery({
|
||||
...orgQueries.batchedSiteStatusHistory({
|
||||
orgId,
|
||||
siteIds,
|
||||
days: SITE_STATUS_HISTORY_DAYS
|
||||
}),
|
||||
enabled: siteIds.length > 0
|
||||
});
|
||||
|
||||
const api = createApiClient(useEnvContext());
|
||||
const t = useTranslations();
|
||||
@@ -296,7 +307,14 @@ export default function SitesTable({
|
||||
if (originalRow.type == "local") {
|
||||
return <span>-</span>;
|
||||
}
|
||||
return <UptimeMiniBar siteId={originalRow.id} days={30} />;
|
||||
const data = statusHistoryQuery.data?.[row.original.id];
|
||||
return (
|
||||
<UptimeMiniBar
|
||||
isLoading={statusHistoryQuery.isLoading}
|
||||
data={data}
|
||||
days={SITE_STATUS_HISTORY_DAYS}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -359,14 +377,11 @@ export default function SitesTable({
|
||||
cell: ({ row }) => {
|
||||
const originalRow = row.original;
|
||||
|
||||
let updateAvailable = Boolean(
|
||||
const updateAvailable = Boolean(
|
||||
latestNewtVersion &&
|
||||
originalRow.newtVersion &&
|
||||
semver.valid(originalRow.newtVersion) &&
|
||||
semver.lt(
|
||||
originalRow.newtVersion,
|
||||
latestNewtVersion
|
||||
)
|
||||
originalRow.newtVersion &&
|
||||
semver.valid(originalRow.newtVersion) &&
|
||||
semver.lt(originalRow.newtVersion, latestNewtVersion)
|
||||
);
|
||||
|
||||
if (originalRow.type === "newt") {
|
||||
@@ -623,7 +638,14 @@ export default function SitesTable({
|
||||
];
|
||||
|
||||
return cols;
|
||||
}, [orgId, t, searchParams, latestNewtVersion]);
|
||||
}, [
|
||||
orgId,
|
||||
t,
|
||||
searchParams,
|
||||
latestNewtVersion,
|
||||
statusHistoryQuery.data,
|
||||
statusHistoryQuery.isLoading
|
||||
]);
|
||||
|
||||
function toggleSort(column: string) {
|
||||
const newSearch = getNextSortOrder(column, searchParams);
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { orgQueries } from "@app/lib/queries";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger
|
||||
} from "@app/components/ui/tooltip";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { createApiClient } from "@app/lib/api";
|
||||
import { cn } from "@app/lib/cn";
|
||||
import { orgQueries } from "@app/lib/queries";
|
||||
import type { StatusHistoryResponse } from "@server/lib/statusHistory";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
function formatDuration(seconds: number): string {
|
||||
@@ -46,21 +45,16 @@ type UptimeMiniBarProps = {
|
||||
days?: number;
|
||||
};
|
||||
|
||||
export default function UptimeMiniBar({
|
||||
export default function UptimeMiniBarWrapper({
|
||||
orgId,
|
||||
siteId,
|
||||
resourceId,
|
||||
healthCheckId,
|
||||
days = 30
|
||||
}: UptimeMiniBarProps) {
|
||||
const t = useTranslations();
|
||||
const api = createApiClient(useEnvContext());
|
||||
|
||||
const siteQuery = useQuery({
|
||||
...orgQueries.siteStatusHistory({ siteId: siteId ?? 0, days }),
|
||||
enabled: siteId != null,
|
||||
meta: { api },
|
||||
staleTime: 5 * 60 * 1000
|
||||
enabled: siteId != null
|
||||
});
|
||||
|
||||
const hcQuery = useQuery({
|
||||
@@ -69,16 +63,12 @@ export default function UptimeMiniBar({
|
||||
healthCheckId: healthCheckId ?? 0,
|
||||
days
|
||||
}),
|
||||
enabled: healthCheckId != null && siteId == null && resourceId == null,
|
||||
meta: { api },
|
||||
staleTime: 5 * 60 * 1000
|
||||
enabled: healthCheckId != null && siteId == null && resourceId == null
|
||||
});
|
||||
|
||||
const resourceQuery = useQuery({
|
||||
...orgQueries.resourceStatusHistory({ resourceId, days }),
|
||||
enabled: resourceId != null && siteId == null && healthCheckId == null,
|
||||
meta: { api },
|
||||
staleTime: 5 * 60 * 1000
|
||||
enabled: resourceId != null && siteId == null && healthCheckId == null
|
||||
});
|
||||
|
||||
const { data, isLoading } =
|
||||
@@ -88,6 +78,22 @@ export default function UptimeMiniBar({
|
||||
? resourceQuery
|
||||
: hcQuery;
|
||||
|
||||
return <UptimeMiniBar data={data} isLoading={isLoading} days={days} />;
|
||||
}
|
||||
|
||||
type UptimeMiniBarUIProps = {
|
||||
data?: StatusHistoryResponse;
|
||||
isLoading?: boolean;
|
||||
days?: number;
|
||||
};
|
||||
|
||||
export function UptimeMiniBar({
|
||||
data,
|
||||
isLoading,
|
||||
days = 30
|
||||
}: UptimeMiniBarUIProps) {
|
||||
const t = useTranslations();
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -138,7 +144,8 @@ export default function UptimeMiniBar({
|
||||
{formatDate(day.date)}
|
||||
</div>
|
||||
<div className="text-xs text-primary-foreground/80">
|
||||
{day.status === "no_data" || day.status === "unknown"
|
||||
{day.status === "no_data" ||
|
||||
day.status === "unknown"
|
||||
? t("uptimeNoData")
|
||||
: `${day.uptimePercent.toFixed(1)}% ${t("uptimeSuffix")}`}
|
||||
</div>
|
||||
@@ -159,4 +166,4 @@ export default function UptimeMiniBar({
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+80
-96
@@ -1,18 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useCallback, useEffect } from "react";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useCallback } from "react";
|
||||
import { GetCertificateResponse } from "@server/routers/certificates/types";
|
||||
import { createApiClient } from "@app/lib/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { domainQueries } from "@app/lib/queries";
|
||||
import { durationToMs } from "@app/lib/durationToMs";
|
||||
|
||||
type UseCertificateProps = {
|
||||
orgId: string;
|
||||
domainId: string;
|
||||
fullDomain: string;
|
||||
autoFetch?: boolean;
|
||||
polling?: boolean;
|
||||
pollingInterval?: number;
|
||||
initialCertValue?: GetCertificateResponse | null;
|
||||
};
|
||||
|
||||
type UseCertificateReturn = {
|
||||
@@ -20,124 +22,106 @@ type UseCertificateReturn = {
|
||||
certLoading: boolean;
|
||||
certError: string | null;
|
||||
refreshing: boolean;
|
||||
fetchCert: (showLoading?: boolean) => Promise<void>;
|
||||
fetchCert: () => Promise<void>;
|
||||
refreshCert: () => Promise<void>;
|
||||
clearCert: () => void;
|
||||
// clearCert: () => void;
|
||||
};
|
||||
|
||||
const POLL_JITTER_MS = durationToMs(1, "seconds");
|
||||
/** A valid cert isn't going anywhere soon, so check on it far less often. */
|
||||
const VALID_POLL_INTERVAL_MS = durationToMs(30, "seconds");
|
||||
|
||||
export function useCertificate({
|
||||
orgId,
|
||||
domainId,
|
||||
fullDomain,
|
||||
autoFetch = true,
|
||||
initialCertValue,
|
||||
polling = false,
|
||||
pollingInterval = 5000
|
||||
pollingInterval = durationToMs(5, "seconds")
|
||||
}: UseCertificateProps): UseCertificateReturn {
|
||||
const api = createApiClient(useEnvContext());
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [cert, setCert] = useState<GetCertificateResponse | null>(null);
|
||||
const [certLoading, setCertLoading] = useState(false);
|
||||
const [certError, setCertError] = useState<string | null>(null);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const certQuery = domainQueries.getCertificate({
|
||||
orgId,
|
||||
domainId,
|
||||
domain: fullDomain
|
||||
});
|
||||
|
||||
const fetchCert = useCallback(
|
||||
async (showLoading = true) => {
|
||||
if (!orgId || !domainId || !fullDomain) return;
|
||||
|
||||
if (showLoading) {
|
||||
setCertLoading(true);
|
||||
}
|
||||
try {
|
||||
const res = await api.get<
|
||||
AxiosResponse<GetCertificateResponse>
|
||||
>(`/org/${orgId}/certificate/${domainId}/${fullDomain}`);
|
||||
const certData = res.data.data;
|
||||
if (certData) {
|
||||
setCertError(null);
|
||||
setCert(certData);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("Failed to fetch certificate:", error);
|
||||
setCertError("Failed");
|
||||
} finally {
|
||||
if (showLoading) {
|
||||
setCertLoading(false);
|
||||
}
|
||||
}
|
||||
const { data, isLoading, isError, refetch } = useQuery({
|
||||
...certQuery,
|
||||
enabled: Boolean(orgId && domainId && fullDomain),
|
||||
refetchInterval: (query) => {
|
||||
if (!polling) return false;
|
||||
const interval =
|
||||
query.state.data?.status === "valid"
|
||||
? VALID_POLL_INTERVAL_MS
|
||||
: pollingInterval;
|
||||
// Add a small random offset to each tick. Without it, every row in
|
||||
// a table would poll at the exact same instant, hitting the server
|
||||
// in bursts instead of spreading the requests out.
|
||||
// the requests will be jittered by less or more than 1s
|
||||
const jitter = (Math.random() * 2 - 1) * POLL_JITTER_MS;
|
||||
return Math.max(1000, interval + jitter);
|
||||
},
|
||||
[api, orgId, domainId, fullDomain]
|
||||
);
|
||||
// An explicit `null` is a real answer ("this domain has no certificate")
|
||||
// and is seeded like any other, so a server-prefetched row doesn't
|
||||
// refetch on mount. Only an omitted prop leaves the cache empty.
|
||||
...(initialCertValue !== undefined && { initialData: initialCertValue })
|
||||
});
|
||||
|
||||
const cert = data ?? null;
|
||||
|
||||
const restartCert = useMutation({
|
||||
mutationFn: async (certId: number) => {
|
||||
await api.post(`/org/${orgId}/certificate/${certId}/restart`, {});
|
||||
},
|
||||
onSuccess: () => {
|
||||
// the backend flips the status asynchronously; reflect it optimistically
|
||||
setTimeout(() => {
|
||||
queryClient.setQueryData(certQuery.queryKey, (prev) =>
|
||||
prev ? { ...prev, status: "pending" } : prev
|
||||
);
|
||||
}, 500);
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("Failed to restart certificate:", error);
|
||||
}
|
||||
});
|
||||
|
||||
const fetchCert = useCallback(async () => {
|
||||
await refetch();
|
||||
}, [refetch]);
|
||||
|
||||
const { mutateAsync: restartCertAsync } = restartCert;
|
||||
const refreshCert = useCallback(async () => {
|
||||
if (!cert) return;
|
||||
|
||||
setRefreshing(true);
|
||||
setCertError(null);
|
||||
try {
|
||||
await api.post(
|
||||
`/org/${orgId}/certificate/${cert.certId}/restart`,
|
||||
{}
|
||||
);
|
||||
// Update status to pending
|
||||
setTimeout(() => {
|
||||
setCert({ ...cert, status: "pending" });
|
||||
}, 500);
|
||||
} catch (error: any) {
|
||||
console.error("Failed to restart certificate:", error);
|
||||
setCertError("Failed to restart");
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
await restartCertAsync(cert.certId);
|
||||
} catch {
|
||||
// surfaced through certError
|
||||
}
|
||||
}, [api, orgId, cert]);
|
||||
}, [cert, restartCertAsync]);
|
||||
|
||||
const clearCert = useCallback(() => {
|
||||
setCert(null);
|
||||
setCertError(null);
|
||||
}, []);
|
||||
// const clearCert = useCallback(() => {
|
||||
// queryClient.removeQueries({ queryKey: certQuery.queryKey });
|
||||
// }, [queryClient, certQuery.queryKey]);
|
||||
|
||||
// Auto-fetch on mount if enabled
|
||||
useEffect(() => {
|
||||
if (autoFetch && orgId && domainId && fullDomain) {
|
||||
fetchCert();
|
||||
}
|
||||
}, [autoFetch, orgId, domainId, fullDomain, fetchCert]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!polling || !orgId || !domainId || !fullDomain) return;
|
||||
|
||||
const POLL_JITTER_MS = 1000;
|
||||
let cancelled = false;
|
||||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
|
||||
const scheduleNext = () => {
|
||||
const jitter = (Math.random() * 2 - 1) * POLL_JITTER_MS;
|
||||
const delayMs = Math.max(
|
||||
1000,
|
||||
Math.round(pollingInterval + jitter)
|
||||
);
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
if (cancelled) return;
|
||||
void fetchCert(false);
|
||||
scheduleNext();
|
||||
}, delayMs);
|
||||
};
|
||||
|
||||
scheduleNext();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
clearTimeout(timeoutId);
|
||||
};
|
||||
}, [polling, orgId, domainId, fullDomain, pollingInterval, fetchCert]);
|
||||
let certError: string | null = null;
|
||||
if (restartCert.isError) {
|
||||
certError = "Failed to restart";
|
||||
} else if (isError) {
|
||||
certError = "Failed";
|
||||
}
|
||||
|
||||
return {
|
||||
cert,
|
||||
certLoading,
|
||||
certLoading: isLoading,
|
||||
certError,
|
||||
refreshing,
|
||||
refreshing: restartCert.isPending,
|
||||
fetchCert,
|
||||
refreshCert,
|
||||
clearCert
|
||||
refreshCert
|
||||
// clearCert
|
||||
};
|
||||
}
|
||||
|
||||
+188
-2
@@ -41,13 +41,16 @@ import {
|
||||
keepPreviousData,
|
||||
queryOptions
|
||||
} from "@tanstack/react-query";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { isAxiosError, type AxiosResponse } from "axios";
|
||||
import z, { meta } from "zod";
|
||||
import { remote } from "./api";
|
||||
import { durationToMs } from "./durationToMs";
|
||||
import type { ListOrgLabelsResponse } from "@server/routers/labels/types";
|
||||
import { ListHealthChecksResponse } from "@server/routers/healthChecks/types";
|
||||
import { StatusHistoryResponse } from "@server/lib/statusHistory";
|
||||
import {
|
||||
StatusHistoryResponse,
|
||||
type BatchedStatusHistoryResponse
|
||||
} from "@server/lib/statusHistory";
|
||||
import type { ListResourcePoliciesResponse } from "@server/routers/resource/types";
|
||||
import type { GetResourcePolicyResponse } from "@server/routers/policy";
|
||||
import type {
|
||||
@@ -66,6 +69,7 @@ import type { GetResourceAuthInfoResponse } from "@server/routers/resource/getRe
|
||||
import type { GetSiteResourceResponse } from "@server/routers/siteResource/getSiteResource";
|
||||
import type { LauncherQueryFilters } from "@app/lib/launcherSearchParams";
|
||||
import { buildLauncherSearchParams } from "@app/lib/launcherSearchParams";
|
||||
import type { GetCertificateResponse } from "@server/routers/certificates/types";
|
||||
|
||||
export type { LauncherQueryFilters } from "@app/lib/launcherSearchParams";
|
||||
export { buildLauncherSearchParams } from "@app/lib/launcherSearchParams";
|
||||
@@ -640,6 +644,143 @@ export const orgQueries = {
|
||||
};
|
||||
}
|
||||
}),
|
||||
batchedSiteStatusHistory: ({
|
||||
siteIds,
|
||||
orgId,
|
||||
days = 90
|
||||
}: {
|
||||
orgId: string;
|
||||
siteIds: number[];
|
||||
days?: number;
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: [
|
||||
"ORG",
|
||||
orgId,
|
||||
"BATCHED_SITE_STATUS_HISTORY",
|
||||
siteIds,
|
||||
days
|
||||
] as const,
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
// Negated because getTimezoneOffset() returns UTC - local,
|
||||
// while the API expects minutes to add to UTC to get local
|
||||
const tzOffsetMinutes = -new Date().getTimezoneOffset();
|
||||
const sp = new URLSearchParams([
|
||||
["days", days.toString()],
|
||||
["tzOffsetMinutes", tzOffsetMinutes.toString()],
|
||||
...siteIds.map((id) => ["siteIds", id.toString()])
|
||||
]);
|
||||
|
||||
const res = await meta!.api.get<
|
||||
AxiosResponse<BatchedStatusHistoryResponse>
|
||||
>(`/org/${orgId}/site-status-histories?${sp.toString()}`, {
|
||||
signal
|
||||
});
|
||||
return res.data.data;
|
||||
},
|
||||
staleTime: durationToMs(5, "seconds")
|
||||
}),
|
||||
batchedHealthCheckStatusHistory: ({
|
||||
healthCheckIds,
|
||||
orgId,
|
||||
days = 90
|
||||
}: {
|
||||
orgId: string;
|
||||
healthCheckIds: number[];
|
||||
days?: number;
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: [
|
||||
"ORG",
|
||||
orgId,
|
||||
"BATCHED_HEALTH_CHECK_STATUS_HISTORY",
|
||||
healthCheckIds,
|
||||
days
|
||||
] as const,
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
// Negated because getTimezoneOffset() returns UTC - local,
|
||||
// while the API expects minutes to add to UTC to get local
|
||||
const tzOffsetMinutes = -new Date().getTimezoneOffset();
|
||||
const sp = new URLSearchParams([
|
||||
["days", days.toString()],
|
||||
["tzOffsetMinutes", tzOffsetMinutes.toString()],
|
||||
...healthCheckIds.map((id) => [
|
||||
"healthCheckIds",
|
||||
id.toString()
|
||||
])
|
||||
]);
|
||||
|
||||
const res = await meta!.api.get<
|
||||
AxiosResponse<BatchedStatusHistoryResponse>
|
||||
>(
|
||||
`/org/${orgId}/health-check-status-histories?${sp.toString()}`,
|
||||
{ signal }
|
||||
);
|
||||
return res.data.data;
|
||||
},
|
||||
staleTime: durationToMs(5, "seconds")
|
||||
}),
|
||||
batchedDomainCertificates: ({
|
||||
domains,
|
||||
orgId
|
||||
}: {
|
||||
orgId: string;
|
||||
domains: string[];
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: ["ORG", orgId, "BATCHED_CERTIFICATES", domains] as const,
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
// Negated because getTimezoneOffset() returns UTC - local,
|
||||
// while the API expects minutes to add to UTC to get local
|
||||
const sp = new URLSearchParams([
|
||||
...domains.map((domain) => ["domains", domain.toString()])
|
||||
]);
|
||||
|
||||
const res = await meta!.api.get<
|
||||
AxiosResponse<BatchedStatusHistoryResponse>
|
||||
>(`/org/${orgId}/batched-certificates?${sp.toString()}`, {
|
||||
signal
|
||||
});
|
||||
return res.data.data;
|
||||
},
|
||||
staleTime: durationToMs(5, "seconds")
|
||||
}),
|
||||
batchedResourceStatusHistory: ({
|
||||
resourceIds,
|
||||
orgId,
|
||||
days = 90
|
||||
}: {
|
||||
orgId: string;
|
||||
resourceIds: number[];
|
||||
days?: number;
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: [
|
||||
"ORG",
|
||||
orgId,
|
||||
"BATCHED_RESOURCE_STATUS_HISTORY",
|
||||
resourceIds,
|
||||
days
|
||||
] as const,
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
// Negated because getTimezoneOffset() returns UTC - local,
|
||||
// while the API expects minutes to add to UTC to get local
|
||||
const tzOffsetMinutes = -new Date().getTimezoneOffset();
|
||||
const sp = new URLSearchParams([
|
||||
["days", days.toString()],
|
||||
["tzOffsetMinutes", tzOffsetMinutes.toString()],
|
||||
...resourceIds.map((id) => ["resourceIds", id.toString()])
|
||||
]);
|
||||
|
||||
const res = await meta!.api.get<
|
||||
AxiosResponse<BatchedStatusHistoryResponse>
|
||||
>(`/org/${orgId}/resource-status-histories?${sp.toString()}`, {
|
||||
signal
|
||||
});
|
||||
return res.data.data;
|
||||
},
|
||||
staleTime: durationToMs(5, "seconds")
|
||||
}),
|
||||
siteStatusHistory: ({
|
||||
siteId,
|
||||
days = 90
|
||||
@@ -649,6 +790,7 @@ export const orgQueries = {
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: ["SITE_STATUS_HISTORY", siteId, days] as const,
|
||||
staleTime: durationToMs(5, "seconds"),
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
const tzOffsetMinutes = -new Date().getTimezoneOffset();
|
||||
const res = await meta!.api.get<
|
||||
@@ -670,6 +812,7 @@ export const orgQueries = {
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: ["RESOURCE_STATUS_HISTORY", resourceId, days] as const,
|
||||
staleTime: durationToMs(5, "seconds"),
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
const tzOffsetMinutes = -new Date().getTimezoneOffset();
|
||||
const res = await meta!.api.get<
|
||||
@@ -692,6 +835,7 @@ export const orgQueries = {
|
||||
days?: number;
|
||||
}) =>
|
||||
queryOptions({
|
||||
staleTime: durationToMs(5, "seconds"),
|
||||
queryKey: [
|
||||
"HC_STATUS_HISTORY",
|
||||
orgId,
|
||||
@@ -1237,6 +1381,48 @@ export const approvalQueries = {
|
||||
};
|
||||
|
||||
export const domainQueries = {
|
||||
getCertificate: ({
|
||||
orgId,
|
||||
domainId,
|
||||
domain
|
||||
}: {
|
||||
orgId: string;
|
||||
domainId: string;
|
||||
domain: string;
|
||||
}) =>
|
||||
queryOptions({
|
||||
queryKey: [
|
||||
"ORG",
|
||||
orgId,
|
||||
"DOMAIN",
|
||||
domainId,
|
||||
"CERTIFICATE",
|
||||
domain
|
||||
] as const,
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
try {
|
||||
const res = await meta!.api.get<
|
||||
AxiosResponse<GetCertificateResponse | null>
|
||||
>(`/org/${orgId}/certificate/${domainId}/${domain}`, {
|
||||
signal
|
||||
});
|
||||
return res.data.data;
|
||||
} catch (error) {
|
||||
// the endpoint 404s when the domain has no certificate yet
|
||||
if (isAxiosError(error) && error.response?.status === 404) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
retry: (failureCount, error) =>
|
||||
isAxiosError(error) &&
|
||||
error.response != null &&
|
||||
error.response.status < 500
|
||||
? false
|
||||
: failureCount < 2,
|
||||
staleTime: durationToMs(1, "minutes")
|
||||
}),
|
||||
getDomain: ({ orgId, domainId }: { orgId: string; domainId: string }) =>
|
||||
queryOptions({
|
||||
queryKey: ["ORG", orgId, "DOMAIN", domainId] as const,
|
||||
|
||||
Reference in New Issue
Block a user