Compare commits
15 Commits
version-20
...
root/remov
Author | SHA1 | Date | |
---|---|---|---|
c255ec7e71 | |||
b23a6d5359 | |||
212904537b | |||
c46cd5e7e5 | |||
480a765f5f | |||
65b6ea416c | |||
2f56c3cecf | |||
5c1432c670 | |||
c49e83a926 | |||
0dc2c46d49 | |||
245d8b7b5c | |||
5884af8af1 | |||
08d52be20d | |||
941f05e7fa | |||
493cefaa6e |
2
.github/workflows/ci-main.yml
vendored
2
.github/workflows/ci-main.yml
vendored
@ -172,7 +172,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
docker-compose -f tests/e2e/docker-compose.yml up -d
|
docker-compose -f tests/e2e/docker-compose.yml up -d
|
||||||
- id: cache-web
|
- id: cache-web
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: web/dist
|
path: web/dist
|
||||||
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**') }}
|
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**') }}
|
||||||
|
29
Dockerfile
29
Dockerfile
@ -1,24 +1,6 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
# Stage 1: Build website
|
# Stage 1: Build webui
|
||||||
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as website-builder
|
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
|
|
||||||
WORKDIR /work/website
|
|
||||||
|
|
||||||
RUN --mount=type=bind,target=/work/website/package.json,src=./website/package.json \
|
|
||||||
--mount=type=bind,target=/work/website/package-lock.json,src=./website/package-lock.json \
|
|
||||||
--mount=type=cache,id=npm-website,sharing=shared,target=/root/.npm \
|
|
||||||
npm ci --include=dev
|
|
||||||
|
|
||||||
COPY ./website /work/website/
|
|
||||||
COPY ./blueprints /work/blueprints/
|
|
||||||
COPY ./SECURITY.md /work/
|
|
||||||
|
|
||||||
RUN npm run build-docs-only
|
|
||||||
|
|
||||||
# Stage 2: Build webui
|
|
||||||
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as web-builder
|
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as web-builder
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
@ -36,7 +18,7 @@ COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
|
|||||||
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Stage 3: Build go proxy
|
# Stage 2: Build go proxy
|
||||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.6-bookworm AS go-builder
|
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.6-bookworm AS go-builder
|
||||||
|
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
@ -68,7 +50,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
|
|||||||
--mount=type=cache,id=go-build-$TARGETARCH$TARGETVARIANT,sharing=locked,target=/root/.cache/go-build \
|
--mount=type=cache,id=go-build-$TARGETARCH$TARGETVARIANT,sharing=locked,target=/root/.cache/go-build \
|
||||||
GOARM="${TARGETVARIANT#v}" go build -o /go/authentik ./cmd/server
|
GOARM="${TARGETVARIANT#v}" go build -o /go/authentik ./cmd/server
|
||||||
|
|
||||||
# Stage 4: MaxMind GeoIP
|
# Stage 3: MaxMind GeoIP
|
||||||
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.1 as geoip
|
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.1 as geoip
|
||||||
|
|
||||||
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
|
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
|
||||||
@ -82,7 +64,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
|||||||
mkdir -p /usr/share/GeoIP && \
|
mkdir -p /usr/share/GeoIP && \
|
||||||
/bin/sh -c "/usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
|
/bin/sh -c "/usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
|
||||||
|
|
||||||
# Stage 5: Python dependencies
|
# Stage 4: Python dependencies
|
||||||
FROM docker.io/python:3.12.1-slim-bookworm AS python-deps
|
FROM docker.io/python:3.12.1-slim-bookworm AS python-deps
|
||||||
|
|
||||||
WORKDIR /ak-root/poetry
|
WORKDIR /ak-root/poetry
|
||||||
@ -107,7 +89,7 @@ RUN --mount=type=bind,target=./pyproject.toml,src=./pyproject.toml \
|
|||||||
pip3 install poetry && \
|
pip3 install poetry && \
|
||||||
poetry install --only=main --no-ansi --no-interaction
|
poetry install --only=main --no-ansi --no-interaction
|
||||||
|
|
||||||
# Stage 6: Run
|
# Stage 5: Run
|
||||||
FROM docker.io/python:3.12.1-slim-bookworm AS final-image
|
FROM docker.io/python:3.12.1-slim-bookworm AS final-image
|
||||||
|
|
||||||
ARG GIT_BUILD_HASH
|
ARG GIT_BUILD_HASH
|
||||||
@ -149,7 +131,6 @@ COPY --from=go-builder /go/authentik /bin/authentik
|
|||||||
COPY --from=python-deps /ak-root/venv /ak-root/venv
|
COPY --from=python-deps /ak-root/venv /ak-root/venv
|
||||||
COPY --from=web-builder /work/web/dist/ /web/dist/
|
COPY --from=web-builder /work/web/dist/ /web/dist/
|
||||||
COPY --from=web-builder /work/web/authentik/ /web/authentik/
|
COPY --from=web-builder /work/web/authentik/ /web/authentik/
|
||||||
COPY --from=website-builder /work/website/help/ /website/help/
|
|
||||||
COPY --from=geoip /usr/share/GeoIP /geoip
|
COPY --from=geoip /usr/share/GeoIP /geoip
|
||||||
|
|
||||||
USER 1000
|
USER 1000
|
||||||
|
@ -22,7 +22,6 @@ func (ws *WebServer) configureStatic() {
|
|||||||
distFs := http.FileServer(http.Dir("./web/dist"))
|
distFs := http.FileServer(http.Dir("./web/dist"))
|
||||||
distHandler := http.StripPrefix("/static/dist/", distFs)
|
distHandler := http.StripPrefix("/static/dist/", distFs)
|
||||||
authentikHandler := http.StripPrefix("/static/authentik/", http.FileServer(http.Dir("./web/authentik")))
|
authentikHandler := http.StripPrefix("/static/authentik/", http.FileServer(http.Dir("./web/authentik")))
|
||||||
helpHandler := http.FileServer(http.Dir("./website/help/"))
|
|
||||||
indexLessRouter.PathPrefix("/static/dist/").Handler(distHandler)
|
indexLessRouter.PathPrefix("/static/dist/").Handler(distHandler)
|
||||||
indexLessRouter.PathPrefix("/static/authentik/").Handler(authentikHandler)
|
indexLessRouter.PathPrefix("/static/authentik/").Handler(authentikHandler)
|
||||||
|
|
||||||
@ -42,9 +41,6 @@ func (ws *WebServer) configureStatic() {
|
|||||||
|
|
||||||
indexLessRouter.PathPrefix("/media/").Handler(http.StripPrefix("/media", fs))
|
indexLessRouter.PathPrefix("/media/").Handler(http.StripPrefix("/media", fs))
|
||||||
|
|
||||||
statRouter.PathPrefix("/if/help/").Handler(http.StripPrefix("/if/help/", helpHandler))
|
|
||||||
statRouter.PathPrefix("/help").Handler(http.RedirectHandler("/if/help/", http.StatusMovedPermanently))
|
|
||||||
|
|
||||||
ws.lh.Path("/robots.txt").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
ws.lh.Path("/robots.txt").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
rw.Header()["Content-Type"] = []string{"text/plain"}
|
rw.Header()["Content-Type"] = []string{"text/plain"}
|
||||||
rw.WriteHeader(200)
|
rw.WriteHeader(200)
|
||||||
|
6
poetry.lock
generated
6
poetry.lock
generated
@ -2543,13 +2543,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pdoc"
|
name = "pdoc"
|
||||||
version = "14.3.0"
|
version = "14.4.0"
|
||||||
description = "API Documentation for Python Projects"
|
description = "API Documentation for Python Projects"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pdoc-14.3.0-py3-none-any.whl", hash = "sha256:9a8f9a48bda5a99c249367c2b99779dbdd9f4a56f905068c9c2d6868dbae6882"},
|
{file = "pdoc-14.4.0-py3-none-any.whl", hash = "sha256:6ea4fe07620b1f7601e2708a307a257636ec206e20b5611640b30f2e3cab47d6"},
|
||||||
{file = "pdoc-14.3.0.tar.gz", hash = "sha256:40bf8f092fcd91560d5e6cebb7c21b65df699f90a468c8ea316235c3368d5449"},
|
{file = "pdoc-14.4.0.tar.gz", hash = "sha256:c92edc425429ccbe287ace2a027953c24f13de53eab484c1a6d31ca72dd2fda9"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
146
tests/wdio/package-lock.json
generated
146
tests/wdio/package-lock.json
generated
@ -9,15 +9,15 @@
|
|||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||||
"@typescript-eslint/parser": "^6.19.0",
|
"@typescript-eslint/parser": "^6.19.0",
|
||||||
"@wdio/cli": "^8.28.0",
|
"@wdio/cli": "^8.28.6",
|
||||||
"@wdio/local-runner": "^8.28.0",
|
"@wdio/local-runner": "^8.28.7",
|
||||||
"@wdio/mocha-framework": "^8.28.0",
|
"@wdio/mocha-framework": "^8.28.6",
|
||||||
"@wdio/spec-reporter": "^8.28.0",
|
"@wdio/spec-reporter": "^8.28.6",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-sonarjs": "^0.23.0",
|
"eslint-plugin-sonarjs": "^0.23.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^3.2.3",
|
"prettier": "^3.2.4",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"wdio-wait-for": "^3.0.10"
|
"wdio-wait-for": "^3.0.10"
|
||||||
@ -1166,18 +1166,18 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/cli": {
|
"node_modules/@wdio/cli": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.28.6.tgz",
|
||||||
"integrity": "sha512-pC15cIh1N14R6qidiymSmKtXEvvJBGrrWqKi8vlVVfby81TQEpfD2VqymzqDqv+YsLIp2J4XD8rwwcSvqtA9UA==",
|
"integrity": "sha512-cBgm/RA12tlKGqIywsqAJaACST2tbcBtbkNl16io88iiBKAWOMlK5tX75+5dNEeyKs7JlQqBJ+3toXcypf68tA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.1",
|
"@types/node": "^20.1.1",
|
||||||
"@wdio/config": "8.28.0",
|
"@wdio/config": "8.28.6",
|
||||||
"@wdio/globals": "8.28.0",
|
"@wdio/globals": "8.28.6",
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/protocols": "8.24.12",
|
"@wdio/protocols": "8.24.12",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"@wdio/utils": "8.28.0",
|
"@wdio/utils": "8.28.6",
|
||||||
"async-exit-hook": "^2.0.1",
|
"async-exit-hook": "^2.0.1",
|
||||||
"chalk": "^5.2.0",
|
"chalk": "^5.2.0",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
@ -1192,7 +1192,7 @@
|
|||||||
"lodash.union": "^4.6.0",
|
"lodash.union": "^4.6.0",
|
||||||
"read-pkg-up": "^10.0.0",
|
"read-pkg-up": "^10.0.0",
|
||||||
"recursive-readdir": "^2.2.3",
|
"recursive-readdir": "^2.2.3",
|
||||||
"webdriverio": "8.28.0",
|
"webdriverio": "8.28.6",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -1215,14 +1215,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/config": {
|
"node_modules/@wdio/config": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.28.6.tgz",
|
||||||
"integrity": "sha512-uXav11uUZSqbYyXGLzyggO8togdm6Bjdjkg8f0zZe4nQpqKpLAkcH7jRiekhuj7oIV5hZai6w5YFhFy5nsw/QA==",
|
"integrity": "sha512-rJ7GFnzg55MvG/CmN3rX79fFFBMcpoFZpILPTNaWJg43lBxidHue5pm7kXJT06D41sSJJPbtgoh6w4VPThIJrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"@wdio/utils": "8.28.0",
|
"@wdio/utils": "8.28.6",
|
||||||
"decamelize": "^6.0.0",
|
"decamelize": "^6.0.0",
|
||||||
"deepmerge-ts": "^5.0.0",
|
"deepmerge-ts": "^5.0.0",
|
||||||
"glob": "^10.2.2",
|
"glob": "^10.2.2",
|
||||||
@ -1233,29 +1233,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/globals": {
|
"node_modules/@wdio/globals": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.28.6.tgz",
|
||||||
"integrity": "sha512-wVgkHOsKskZYu6FPaJpT19tYul3hi7nkB/TayYIk1rQTRuf3hoP2vHVjibGsU9W3JdhrZA/MUNTm5yrID70KZA==",
|
"integrity": "sha512-6Wjk7iWnpK1ft/caTAhDXxlmwU+pARouzCssqUtdO/vlvP1VhUo3xArCA2dzzJgE+uD16KLR63DRpgkTdwWPkQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.13 || >=18"
|
"node": "^16.13 || >=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"expect-webdriverio": "^4.8.0",
|
"expect-webdriverio": "^4.8.0",
|
||||||
"webdriverio": "8.28.0"
|
"webdriverio": "8.28.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/local-runner": {
|
"node_modules/@wdio/local-runner": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.7",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.28.7.tgz",
|
||||||
"integrity": "sha512-zPev8IfItJtIWArTRyr9XjPu4Kp4kO0B/NAJmGQgDauLMBBzciwf35tPp1CFmggGtaO4czryAclyk2CsCkkAoA==",
|
"integrity": "sha512-QOeJluWEV3My+41f4kHe7Bo08UcSd3TvH4TbPMflOkl0VvGqxJuKfXlllkQhJ8w5e53fBRsf368vzHscbX86/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/repl": "8.24.12",
|
"@wdio/repl": "8.24.12",
|
||||||
"@wdio/runner": "8.28.0",
|
"@wdio/runner": "8.28.7",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"async-exit-hook": "^2.0.1",
|
"async-exit-hook": "^2.0.1",
|
||||||
"split2": "^4.1.0",
|
"split2": "^4.1.0",
|
||||||
"stream-buffers": "^3.0.2"
|
"stream-buffers": "^3.0.2"
|
||||||
@ -1292,16 +1292,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/mocha-framework": {
|
"node_modules/@wdio/mocha-framework": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.28.6.tgz",
|
||||||
"integrity": "sha512-ykXbJXu2sb7agTnLP6Tv2Ak+ee3ZG3Tag2bT30j30yiulnNpIIuHMuSgrxDs2NKzlF2Q4qla/SrjiMPSoZYhsw==",
|
"integrity": "sha512-3jTI1GilFGZROJi+UCywEt/ac0b8ETQkG9YlkTAVcxMqG+wUKY2Ks7ow/UDGAaYMHkrEPdopvUFGZmJmpNMKUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mocha": "^10.0.0",
|
"@types/mocha": "^10.0.0",
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"@wdio/utils": "8.28.0",
|
"@wdio/utils": "8.28.6",
|
||||||
"mocha": "^10.0.0"
|
"mocha": "^10.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -1327,14 +1327,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/reporter": {
|
"node_modules/@wdio/reporter": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.28.6.tgz",
|
||||||
"integrity": "sha512-O2MfFv1xIm95cBnTgZINpiejVlG8LpiXrvlmj9FPPiGzcWIsERtbTHDb6+8UagQZv9nBLmISLARUyR7XRYfwLQ==",
|
"integrity": "sha512-2KUSytk75fjT4XGEL43u1XLzZSvu1SUg3a7h8fRm2fU2q1dCC16TJk5eod4eSxHzjm2fL1vwFQIAZkwO3WyQZQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"diff": "^5.0.0",
|
"diff": "^5.0.0",
|
||||||
"object-inspect": "^1.12.0"
|
"object-inspect": "^1.12.0"
|
||||||
},
|
},
|
||||||
@ -1343,35 +1343,35 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/runner": {
|
"node_modules/@wdio/runner": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.7",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.28.7.tgz",
|
||||||
"integrity": "sha512-IPaYSSjN6DDn75gDfzGQtFAu5oE1ee90L2xzXCYXK7xR4xr4O0IgNtFTq5cuLZsPRzJsGoq3z+1GxGSogC3u1A==",
|
"integrity": "sha512-qk/3cMccCLXrIMN4a/vqmL0UeKaGXDclL/8buWC61IeZZ3SpDUgOoCJH47ULrkIeuoXXrnttZvo12fGjb8zmOg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/config": "8.28.0",
|
"@wdio/config": "8.28.6",
|
||||||
"@wdio/globals": "8.28.0",
|
"@wdio/globals": "8.28.6",
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"@wdio/utils": "8.28.0",
|
"@wdio/utils": "8.28.6",
|
||||||
"deepmerge-ts": "^5.0.0",
|
"deepmerge-ts": "^5.0.0",
|
||||||
"expect-webdriverio": "^4.8.0",
|
"expect-webdriverio": "^4.8.0",
|
||||||
"gaze": "^1.1.2",
|
"gaze": "^1.1.2",
|
||||||
"webdriver": "8.28.0",
|
"webdriver": "8.28.6",
|
||||||
"webdriverio": "8.28.0"
|
"webdriverio": "8.28.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.13 || >=18"
|
"node": "^16.13 || >=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/spec-reporter": {
|
"node_modules/@wdio/spec-reporter": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.28.6.tgz",
|
||||||
"integrity": "sha512-ukyViS7KbeL7Q0+8gHqx1C4YZJT5ne1/6fi0dbgnGNPe+R7c76vSmf0lIGGiqEcDV1W27E1OoL17NwRKBIt0Pw==",
|
"integrity": "sha512-ZMwbM7hxcV0DumGaK0Y9jzPgTjwYHN539FFcEgbYZV1eNKUyIi9cdEP2xIWZiYQHmq2eKBMlUEPA87mwVZ1V6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wdio/reporter": "8.28.0",
|
"@wdio/reporter": "8.28.6",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"chalk": "^5.1.2",
|
"chalk": "^5.1.2",
|
||||||
"easy-table": "^1.2.0",
|
"easy-table": "^1.2.0",
|
||||||
"pretty-ms": "^7.0.0"
|
"pretty-ms": "^7.0.0"
|
||||||
@ -1393,9 +1393,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/types": {
|
"node_modules/@wdio/types": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.28.6.tgz",
|
||||||
"integrity": "sha512-4/mUn3IGNa1GTiV0PMOtl1sRqStpbHOQldxz4Vheh0lYNc15W12jXRm84CwGsV6UW93GO9W2K9EprFJsUjc9sg==",
|
"integrity": "sha512-FU3mMRqULpc2XYh6DrSo/KgNoaS6EO9GFJQX5q7+EiOAqVeo1TCLggvAWIPayKyjfD1/ctd9q+uW9vmNicaOjw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0"
|
"@types/node": "^20.1.0"
|
||||||
@ -1405,14 +1405,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/utils": {
|
"node_modules/@wdio/utils": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.28.6.tgz",
|
||||||
"integrity": "sha512-v3xDJuQShLSfHW/Ee0y3z9ZtiV/UrILlucgKBCwCpLwHnO5HhfAH4Ehirt0yzQvYz+Pn9BuOXJImD/wsSbJtLw==",
|
"integrity": "sha512-EYQmGvejMiTMB18lW3CDc6cR+jXXjxDebP6ci53oK20QPx9VBuMQZdCbuoftKrKVLA+e9Fk0XfXq8xWYbjAvBQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@puppeteer/browsers": "^1.6.0",
|
"@puppeteer/browsers": "^1.6.0",
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"decamelize": "^6.0.0",
|
"decamelize": "^6.0.0",
|
||||||
"deepmerge-ts": "^5.1.0",
|
"deepmerge-ts": "^5.1.0",
|
||||||
"edgedriver": "^5.3.5",
|
"edgedriver": "^5.3.5",
|
||||||
@ -6508,9 +6508,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.3",
|
"version": "3.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz",
|
||||||
"integrity": "sha512-QNhUTBq+mqt1oH1dTfY3phOKNhcDdJkfttHI6u0kj7M2+c+7fmNKlgh2GhnHiqMcbxJ+a0j2igz/2jfl9QKLuw==",
|
"integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
@ -8520,18 +8520,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webdriver": {
|
"node_modules/webdriver": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.28.6.tgz",
|
||||||
"integrity": "sha512-1ASMK+sNfVh5rdaRRk+eFLIfae93ViXHJBpuJemeORwZkfOJNF2CNSZl5uK2e6+nzbkY2cjM6QsZwfhL3lCiRg==",
|
"integrity": "sha512-qKZuG2uqGhq2xjk14vSAvE3C6TTTYQyOqDHQOSWNzPNhdBI99g2h4EUbmO3bc/5YaWRsVWWp+RB7jfQZUcE/MA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@types/ws": "^8.5.3",
|
"@types/ws": "^8.5.3",
|
||||||
"@wdio/config": "8.28.0",
|
"@wdio/config": "8.28.6",
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/protocols": "8.24.12",
|
"@wdio/protocols": "8.24.12",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"@wdio/utils": "8.28.0",
|
"@wdio/utils": "8.28.6",
|
||||||
"deepmerge-ts": "^5.1.0",
|
"deepmerge-ts": "^5.1.0",
|
||||||
"got": "^12.6.1",
|
"got": "^12.6.1",
|
||||||
"ky": "^0.33.0",
|
"ky": "^0.33.0",
|
||||||
@ -8542,18 +8542,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webdriverio": {
|
"node_modules/webdriverio": {
|
||||||
"version": "8.28.0",
|
"version": "8.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.28.6.tgz",
|
||||||
"integrity": "sha512-rRVE8pvcxAEqnhhC70oMFkUZ82YWbpXYyzKgfl2LKBue13AHaiN5qWncsJv29rqREIim0dNj6q2JuuUTDFm1gg==",
|
"integrity": "sha512-vWo3Qx0bWubzUBBLaLYgeQkSN63KTfW5P3IbayhJ8Qx+NVVnclG0mu4mQj00gvj8+3a8opef6T54gdzitVSHSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/config": "8.28.0",
|
"@wdio/config": "8.28.6",
|
||||||
"@wdio/logger": "8.28.0",
|
"@wdio/logger": "8.28.0",
|
||||||
"@wdio/protocols": "8.24.12",
|
"@wdio/protocols": "8.24.12",
|
||||||
"@wdio/repl": "8.24.12",
|
"@wdio/repl": "8.24.12",
|
||||||
"@wdio/types": "8.28.0",
|
"@wdio/types": "8.28.6",
|
||||||
"@wdio/utils": "8.28.0",
|
"@wdio/utils": "8.28.6",
|
||||||
"archiver": "^6.0.0",
|
"archiver": "^6.0.0",
|
||||||
"aria-query": "^5.0.0",
|
"aria-query": "^5.0.0",
|
||||||
"css-shorthand-properties": "^1.1.1",
|
"css-shorthand-properties": "^1.1.1",
|
||||||
@ -8570,7 +8570,7 @@
|
|||||||
"resq": "^1.9.1",
|
"resq": "^1.9.1",
|
||||||
"rgb2hex": "0.2.5",
|
"rgb2hex": "0.2.5",
|
||||||
"serialize-error": "^11.0.1",
|
"serialize-error": "^11.0.1",
|
||||||
"webdriver": "8.28.0"
|
"webdriver": "8.28.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.13 || >=18"
|
"node": "^16.13 || >=18"
|
||||||
|
@ -6,15 +6,15 @@
|
|||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||||
"@typescript-eslint/parser": "^6.19.0",
|
"@typescript-eslint/parser": "^6.19.0",
|
||||||
"@wdio/cli": "^8.28.0",
|
"@wdio/cli": "^8.28.6",
|
||||||
"@wdio/local-runner": "^8.28.0",
|
"@wdio/local-runner": "^8.28.7",
|
||||||
"@wdio/mocha-framework": "^8.28.0",
|
"@wdio/mocha-framework": "^8.28.6",
|
||||||
"@wdio/spec-reporter": "^8.28.0",
|
"@wdio/spec-reporter": "^8.28.6",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-sonarjs": "^0.23.0",
|
"eslint-plugin-sonarjs": "^0.23.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^3.2.3",
|
"prettier": "^3.2.4",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"wdio-wait-for": "^3.0.10"
|
"wdio-wait-for": "^3.0.10"
|
||||||
|
668
web/package-lock.json
generated
668
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -87,14 +87,14 @@
|
|||||||
"@rollup/plugin-replace": "^5.0.5",
|
"@rollup/plugin-replace": "^5.0.5",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@rollup/plugin-typescript": "^11.1.6",
|
"@rollup/plugin-typescript": "^11.1.6",
|
||||||
"@spotlightjs/spotlight": "^1.2.6",
|
"@spotlightjs/spotlight": "^1.2.7",
|
||||||
"@storybook/addon-essentials": "^7.6.8",
|
"@storybook/addon-essentials": "^7.6.9",
|
||||||
"@storybook/addon-links": "^7.6.8",
|
"@storybook/addon-links": "^7.6.9",
|
||||||
"@storybook/api": "^7.6.8",
|
"@storybook/api": "^7.6.9",
|
||||||
"@storybook/blocks": "^7.6.4",
|
"@storybook/blocks": "^7.6.4",
|
||||||
"@storybook/manager-api": "^7.6.8",
|
"@storybook/manager-api": "^7.6.9",
|
||||||
"@storybook/web-components": "^7.6.8",
|
"@storybook/web-components": "^7.6.9",
|
||||||
"@storybook/web-components-vite": "^7.6.8",
|
"@storybook/web-components-vite": "^7.6.9",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"@types/chart.js": "^2.9.41",
|
"@types/chart.js": "^2.9.41",
|
||||||
"@types/codemirror": "5.60.15",
|
"@types/codemirror": "5.60.15",
|
||||||
@ -123,7 +123,7 @@
|
|||||||
"rollup-plugin-cssimport": "^1.0.3",
|
"rollup-plugin-cssimport": "^1.0.3",
|
||||||
"rollup-plugin-modify": "^3.0.0",
|
"rollup-plugin-modify": "^3.0.0",
|
||||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||||
"storybook": "^7.6.8",
|
"storybook": "^7.6.9",
|
||||||
"storybook-addon-mock": "^4.3.0",
|
"storybook-addon-mock": "^4.3.0",
|
||||||
"ts-lit-plugin": "^2.0.2",
|
"ts-lit-plugin": "^2.0.2",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 717 KiB After Width: | Height: | Size: 699 KiB |
@ -134,9 +134,11 @@ html > form > input {
|
|||||||
);
|
);
|
||||||
max-height: 9rem;
|
max-height: 9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ak-brand {
|
.ak-brand {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.ak-brand img {
|
.ak-brand img {
|
||||||
padding: 0 2rem;
|
padding: 0 2rem;
|
||||||
|
@ -1,324 +0,0 @@
|
|||||||
import { PreventFormSubmit } from "@goauthentik/app/elements/forms/helpers";
|
|
||||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
|
||||||
import { ascii_letters, digits, groupBy, randomString } from "@goauthentik/common/utils";
|
|
||||||
import { adaptCSS } from "@goauthentik/common/utils";
|
|
||||||
import { AKElement } from "@goauthentik/elements/Base";
|
|
||||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
|
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
|
||||||
import { CSSResult, TemplateResult, html, render } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators.js";
|
|
||||||
|
|
||||||
import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";
|
|
||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
|
||||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
|
||||||
import PFSelect from "@patternfly/patternfly/components/Select/select.css";
|
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
|
||||||
|
|
||||||
@customElement("ak-search-select")
|
|
||||||
export class SearchSelect<T> extends CustomEmitterElement(AKElement) {
|
|
||||||
@property()
|
|
||||||
query?: string;
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
objects?: T[];
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
selectedObject?: T;
|
|
||||||
|
|
||||||
@property()
|
|
||||||
name?: string;
|
|
||||||
|
|
||||||
@property({ type: Boolean })
|
|
||||||
open = false;
|
|
||||||
|
|
||||||
@property({ type: Boolean })
|
|
||||||
blankable = false;
|
|
||||||
|
|
||||||
@property()
|
|
||||||
placeholder: string = msg("Select an object.");
|
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
|
||||||
return [PFBase, PFForm, PFFormControl, PFSelect];
|
|
||||||
}
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
fetchObjects!: (query?: string) => Promise<T[]>;
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
renderElement!: (element: T) => string;
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
renderDescription?: (element: T) => TemplateResult;
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
value!: (element: T | undefined) => unknown;
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
selected?: (element: T, elements: T[]) => boolean;
|
|
||||||
|
|
||||||
@property()
|
|
||||||
emptyOption = "---------";
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
groupBy: (items: T[]) => [string, T[]][] = (items: T[]): [string, T[]][] => {
|
|
||||||
return groupBy(items, () => {
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
scrollHandler?: () => void;
|
|
||||||
observer: IntersectionObserver;
|
|
||||||
dropdownUID: string;
|
|
||||||
dropdownContainer: HTMLDivElement;
|
|
||||||
isFetchingData = false;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
if (!document.adoptedStyleSheets.includes(PFDropdown)) {
|
|
||||||
document.adoptedStyleSheets = adaptCSS([...document.adoptedStyleSheets, PFDropdown]);
|
|
||||||
}
|
|
||||||
this.dropdownContainer = document.createElement("div");
|
|
||||||
this.observer = new IntersectionObserver(() => {
|
|
||||||
this.open = false;
|
|
||||||
this.shadowRoot
|
|
||||||
?.querySelectorAll<HTMLInputElement>(
|
|
||||||
".pf-c-form-control.pf-c-select__toggle-typeahead",
|
|
||||||
)
|
|
||||||
.forEach((input) => {
|
|
||||||
input.blur();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.observer.observe(this);
|
|
||||||
this.dropdownUID = `dropdown-${randomString(10, ascii_letters + digits)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
shouldUpdate(changedProperties: Map<string, any>) {
|
|
||||||
if (changedProperties.has("selectedObject")) {
|
|
||||||
this.dispatchCustomEvent("ak-change", {
|
|
||||||
value: this.selectedObject,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
toForm(): unknown {
|
|
||||||
if (!this.objects) {
|
|
||||||
throw new PreventFormSubmit(msg("Loading options..."));
|
|
||||||
}
|
|
||||||
return this.value(this.selectedObject) || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated(): void {
|
|
||||||
this.updateData();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData(): void {
|
|
||||||
if (this.isFetchingData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.isFetchingData = true;
|
|
||||||
this.fetchObjects(this.query).then((objects) => {
|
|
||||||
objects.forEach((obj) => {
|
|
||||||
if (this.selected && this.selected(obj, objects || [])) {
|
|
||||||
this.selectedObject = obj;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.objects = objects;
|
|
||||||
this.isFetchingData = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback(): void {
|
|
||||||
super.connectedCallback();
|
|
||||||
this.dropdownContainer = document.createElement("div");
|
|
||||||
this.dropdownContainer.dataset["managedBy"] = "ak-search-select";
|
|
||||||
if (this.name) {
|
|
||||||
this.dropdownContainer.dataset["managedFor"] = this.name;
|
|
||||||
}
|
|
||||||
document.body.append(this.dropdownContainer);
|
|
||||||
this.updateData();
|
|
||||||
this.addEventListener(EVENT_REFRESH, this.updateData);
|
|
||||||
this.scrollHandler = () => {
|
|
||||||
this.requestUpdate();
|
|
||||||
};
|
|
||||||
window.addEventListener("scroll", this.scrollHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
|
||||||
super.disconnectedCallback();
|
|
||||||
this.removeEventListener(EVENT_REFRESH, this.updateData);
|
|
||||||
if (this.scrollHandler) {
|
|
||||||
window.removeEventListener("scroll", this.scrollHandler);
|
|
||||||
}
|
|
||||||
this.dropdownContainer.remove();
|
|
||||||
this.observer.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a little bit hacky. Because we mainly want to use this field in modal-based forms,
|
|
||||||
* rendering this menu inline makes the menu not overlay over top of the modal, and cause
|
|
||||||
* the modal to scroll.
|
|
||||||
* Hence, we render the menu into the document root, hide it when this menu isn't open
|
|
||||||
* and remove it on disconnect
|
|
||||||
* Also to move it to the correct position we're getting this elements's position and use that
|
|
||||||
* to position the menu
|
|
||||||
* The other downside this has is that, since we're rendering outside of a shadow root,
|
|
||||||
* the pf-c-dropdown CSS needs to be loaded on the body.
|
|
||||||
*/
|
|
||||||
renderMenu(): void {
|
|
||||||
if (!this.objects) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const pos = this.getBoundingClientRect();
|
|
||||||
let groupedItems = this.groupBy(this.objects);
|
|
||||||
let shouldRenderGroups = true;
|
|
||||||
if (groupedItems.length === 1) {
|
|
||||||
if (groupedItems[0].length < 1 || groupedItems[0][0] === "") {
|
|
||||||
shouldRenderGroups = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (groupedItems.length === 0) {
|
|
||||||
shouldRenderGroups = false;
|
|
||||||
groupedItems = [["", []]];
|
|
||||||
}
|
|
||||||
const renderGroup = (items: T[], tabIndexStart: number): TemplateResult => {
|
|
||||||
return html`${items.map((obj, index) => {
|
|
||||||
let desc = undefined;
|
|
||||||
if (this.renderDescription) {
|
|
||||||
desc = this.renderDescription(obj);
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
class="pf-c-dropdown__menu-item ${desc === undefined
|
|
||||||
? ""
|
|
||||||
: "pf-m-description"}"
|
|
||||||
role="option"
|
|
||||||
@click=${() => {
|
|
||||||
this.selectedObject = obj;
|
|
||||||
this.open = false;
|
|
||||||
}}
|
|
||||||
tabindex=${index + tabIndexStart}
|
|
||||||
>
|
|
||||||
${desc === undefined
|
|
||||||
? this.renderElement(obj)
|
|
||||||
: html`
|
|
||||||
<div class="pf-c-dropdown__menu-item-main">
|
|
||||||
${this.renderElement(obj)}
|
|
||||||
</div>
|
|
||||||
<div class="pf-c-dropdown__menu-item-description">
|
|
||||||
${desc}
|
|
||||||
</div>
|
|
||||||
`}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
`;
|
|
||||||
})}`;
|
|
||||||
};
|
|
||||||
render(
|
|
||||||
html`<div
|
|
||||||
class="pf-c-dropdown pf-m-expanded"
|
|
||||||
style="position: fixed; inset: 0px auto auto 0px; z-index: 9999; transform: translate(${pos.x}px, ${pos.y +
|
|
||||||
this.offsetHeight}px); width: ${pos.width}px; ${this.open
|
|
||||||
? ""
|
|
||||||
: "visibility: hidden;"}"
|
|
||||||
>
|
|
||||||
<ul
|
|
||||||
class="pf-c-dropdown__menu pf-m-static"
|
|
||||||
role="listbox"
|
|
||||||
style="max-height:50vh;overflow-y:auto;"
|
|
||||||
id=${this.dropdownUID}
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
${this.blankable
|
|
||||||
? html`
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
class="pf-c-dropdown__menu-item"
|
|
||||||
role="option"
|
|
||||||
@click=${() => {
|
|
||||||
this.selectedObject = undefined;
|
|
||||||
this.open = false;
|
|
||||||
}}
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
${this.emptyOption}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
`
|
|
||||||
: html``}
|
|
||||||
${shouldRenderGroups
|
|
||||||
? html`${groupedItems.map(([group, items], idx) => {
|
|
||||||
return html`
|
|
||||||
<section class="pf-c-dropdown__group">
|
|
||||||
<h1 class="pf-c-dropdown__group-title">${group}</h1>
|
|
||||||
<ul>
|
|
||||||
${renderGroup(items, idx)}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
`;
|
|
||||||
})}`
|
|
||||||
: html`${renderGroup(groupedItems[0][1], 0)}`}
|
|
||||||
</ul>
|
|
||||||
</div>`,
|
|
||||||
this.dropdownContainer,
|
|
||||||
{ host: this },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render(): TemplateResult {
|
|
||||||
this.renderMenu();
|
|
||||||
let value = "";
|
|
||||||
if (!this.objects) {
|
|
||||||
value = msg("Loading...");
|
|
||||||
} else if (this.selectedObject) {
|
|
||||||
value = this.renderElement(this.selectedObject);
|
|
||||||
} else if (this.blankable) {
|
|
||||||
value = this.emptyOption;
|
|
||||||
}
|
|
||||||
return html`<div class="pf-c-select">
|
|
||||||
<div class="pf-c-select__toggle pf-m-typeahead">
|
|
||||||
<div class="pf-c-select__toggle-wrapper">
|
|
||||||
<input
|
|
||||||
class="pf-c-form-control pf-c-select__toggle-typeahead"
|
|
||||||
type="text"
|
|
||||||
placeholder=${this.placeholder}
|
|
||||||
spellcheck="false"
|
|
||||||
@input=${(ev: InputEvent) => {
|
|
||||||
this.query = (ev.target as HTMLInputElement).value;
|
|
||||||
this.updateData();
|
|
||||||
}}
|
|
||||||
@focus=${() => {
|
|
||||||
this.open = true;
|
|
||||||
this.renderMenu();
|
|
||||||
}}
|
|
||||||
@blur=${(ev: FocusEvent) => {
|
|
||||||
// For Safari, we get the <ul> element itself here when clicking on one of
|
|
||||||
// it's buttons, as the container has tabindex set
|
|
||||||
if (
|
|
||||||
ev.relatedTarget &&
|
|
||||||
(ev.relatedTarget as HTMLElement).id === this.dropdownUID
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Check if we're losing focus to one of our dropdown items, and if such don't blur
|
|
||||||
if (ev.relatedTarget instanceof HTMLButtonElement) {
|
|
||||||
const parentMenu = ev.relatedTarget.closest(
|
|
||||||
"ul.pf-c-dropdown__menu.pf-m-static",
|
|
||||||
);
|
|
||||||
if (parentMenu && parentMenu.id === this.dropdownUID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.open = false;
|
|
||||||
this.renderMenu();
|
|
||||||
}}
|
|
||||||
.value=${value}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
}
|
|
370
web/src/elements/forms/SearchSelect/ak-search-select.ts
Normal file
370
web/src/elements/forms/SearchSelect/ak-search-select.ts
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
import { PreventFormSubmit } from "@goauthentik/app/elements/forms/helpers";
|
||||||
|
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||||
|
import { ascii_letters, digits, groupBy, randomString } from "@goauthentik/common/utils";
|
||||||
|
import { AKElement } from "@goauthentik/elements/Base";
|
||||||
|
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
|
||||||
|
|
||||||
|
import { msg } from "@lit/localize";
|
||||||
|
import { TemplateResult, html, render } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators.js";
|
||||||
|
import { styleMap } from "lit/directives/style-map.js";
|
||||||
|
|
||||||
|
import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";
|
||||||
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
import PFSelect from "@patternfly/patternfly/components/Select/select.css";
|
||||||
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
|
|
||||||
|
type Group<T> = [string, T[]];
|
||||||
|
|
||||||
|
@customElement("ak-search-select")
|
||||||
|
export class SearchSelect<T> extends CustomEmitterElement(AKElement) {
|
||||||
|
// A function which takes the query state object (accepting that it may be empty) and returns a
|
||||||
|
// new collection of objects.
|
||||||
|
@property({ attribute: false })
|
||||||
|
fetchObjects!: (query?: string) => Promise<T[]>;
|
||||||
|
|
||||||
|
// A function passed to this object that extracts a string representation of items of the
|
||||||
|
// collection under search.
|
||||||
|
@property({ attribute: false })
|
||||||
|
renderElement!: (element: T) => string;
|
||||||
|
|
||||||
|
// A function passed to this object that extracts an HTML representation of additional
|
||||||
|
// information for items of the collection under search.
|
||||||
|
@property({ attribute: false })
|
||||||
|
renderDescription?: (element: T) => TemplateResult;
|
||||||
|
|
||||||
|
// A function which returns the currently selected object's primary key, used for serialization
|
||||||
|
// into forms.
|
||||||
|
@property({ attribute: false })
|
||||||
|
value!: (element: T | undefined) => unknown;
|
||||||
|
|
||||||
|
// A function passed to this object that determines an object in the collection under search
|
||||||
|
// should be automatically selected. Only used when the search itself is responsible for
|
||||||
|
// fetching the data; sets an initial default value.
|
||||||
|
@property({ attribute: false })
|
||||||
|
selected?: (element: T, elements: T[]) => boolean;
|
||||||
|
|
||||||
|
// A function passed to this object (or using the default below) that groups objects in the
|
||||||
|
// collection under search into categories.
|
||||||
|
@property({ attribute: false })
|
||||||
|
groupBy: (items: T[]) => [string, T[]][] = (items: T[]): [string, T[]][] => {
|
||||||
|
return groupBy(items, () => {
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Whether or not the dropdown component can be left blank
|
||||||
|
@property({ type: Boolean })
|
||||||
|
blankable = false;
|
||||||
|
|
||||||
|
// An initial string to filter the search contents, and the value of the input which further
|
||||||
|
// serves to restrict the search
|
||||||
|
@property()
|
||||||
|
query?: string;
|
||||||
|
|
||||||
|
// The objects currently available under search
|
||||||
|
@property({ attribute: false })
|
||||||
|
objects?: T[];
|
||||||
|
|
||||||
|
// The currently selected object
|
||||||
|
@property({ attribute: false })
|
||||||
|
selectedObject?: T;
|
||||||
|
|
||||||
|
// Not used in this object. No known purpose.
|
||||||
|
@property()
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
// Whether or not the dropdown component is visible.
|
||||||
|
@property({ type: Boolean })
|
||||||
|
open = false;
|
||||||
|
|
||||||
|
// The textual placeholder for the search's <input> object, if currently empty. Used as the
|
||||||
|
// native <input> object's `placeholder` field.
|
||||||
|
@property()
|
||||||
|
placeholder: string = msg("Select an object.");
|
||||||
|
|
||||||
|
// A textual string representing "The user has affirmed they want to leave the selection blank."
|
||||||
|
// Only used if `blankable` above is true.
|
||||||
|
@property()
|
||||||
|
emptyOption = "---------";
|
||||||
|
|
||||||
|
// Handle the behavior of the drop-down when the :host scrolls off the page.
|
||||||
|
scrollHandler?: () => void;
|
||||||
|
observer: IntersectionObserver;
|
||||||
|
|
||||||
|
// Handle communication between the :host and the portal
|
||||||
|
dropdownUID: string;
|
||||||
|
dropdownContainer: HTMLDivElement;
|
||||||
|
|
||||||
|
isFetchingData = false;
|
||||||
|
|
||||||
|
static styles = [PFBase, PFForm, PFFormControl, PFSelect];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
if (!document.adoptedStyleSheets.includes(PFDropdown)) {
|
||||||
|
document.adoptedStyleSheets = [...document.adoptedStyleSheets, PFDropdown];
|
||||||
|
}
|
||||||
|
this.dropdownContainer = document.createElement("div");
|
||||||
|
this.observer = new IntersectionObserver(() => {
|
||||||
|
this.open = false;
|
||||||
|
this.shadowRoot
|
||||||
|
?.querySelectorAll<HTMLInputElement>(
|
||||||
|
".pf-c-form-control.pf-c-select__toggle-typeahead",
|
||||||
|
)
|
||||||
|
.forEach((input) => {
|
||||||
|
input.blur();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.observer.observe(this);
|
||||||
|
this.dropdownUID = `dropdown-${randomString(10, ascii_letters + digits)}`;
|
||||||
|
this.onMenuItemClick = this.onMenuItemClick.bind(this);
|
||||||
|
this.renderWithMenuGroupTitle = this.renderWithMenuGroupTitle.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
toForm(): unknown {
|
||||||
|
if (!this.objects) {
|
||||||
|
throw new PreventFormSubmit(msg("Loading options..."));
|
||||||
|
}
|
||||||
|
return this.value(this.selectedObject) || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated(): void {
|
||||||
|
this.updateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateData(): void {
|
||||||
|
if (this.isFetchingData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.isFetchingData = true;
|
||||||
|
this.fetchObjects(this.query).then((objects) => {
|
||||||
|
objects.forEach((obj) => {
|
||||||
|
if (this.selected && this.selected(obj, objects || [])) {
|
||||||
|
this.selectedObject = obj;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.objects = objects;
|
||||||
|
this.isFetchingData = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback(): void {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.dropdownContainer = document.createElement("div");
|
||||||
|
this.dropdownContainer.dataset["managedBy"] = "ak-search-select";
|
||||||
|
document.body.append(this.dropdownContainer);
|
||||||
|
this.updateData();
|
||||||
|
this.addEventListener(EVENT_REFRESH, this.updateData);
|
||||||
|
this.scrollHandler = () => {
|
||||||
|
this.requestUpdate();
|
||||||
|
};
|
||||||
|
window.addEventListener("scroll", this.scrollHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback(): void {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this.removeEventListener(EVENT_REFRESH, this.updateData);
|
||||||
|
if (this.scrollHandler) {
|
||||||
|
window.removeEventListener("scroll", this.scrollHandler);
|
||||||
|
}
|
||||||
|
this.dropdownContainer.remove();
|
||||||
|
this.observer.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderMenuItemWithDescription(obj: T, desc: TemplateResult, index: number) {
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="pf-c-dropdown__menu-item pf-m-description"
|
||||||
|
role="option"
|
||||||
|
@click=${this.onMenuItemClick(obj)}
|
||||||
|
tabindex=${index}
|
||||||
|
>
|
||||||
|
<div class="pf-c-dropdown__menu-item-main">${this.renderElement(obj)}</div>
|
||||||
|
<div class="pf-c-dropdown__menu-item-description">${desc}</div>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderMenuItemWithoutDescription(obj: T, index: number) {
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="pf-c-dropdown__menu-item"
|
||||||
|
role="option"
|
||||||
|
@click=${this.onMenuItemClick(obj)}
|
||||||
|
tabindex=${index}
|
||||||
|
>
|
||||||
|
${this.renderElement(obj)}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEmptyMenuItem() {
|
||||||
|
return html`<li>
|
||||||
|
<button
|
||||||
|
class="pf-c-dropdown__menu-item"
|
||||||
|
role="option"
|
||||||
|
@click=${this.onMenuItemClick(undefined)}
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
${this.emptyOption}
|
||||||
|
</button>
|
||||||
|
</li>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuItemClick(obj: T | undefined) {
|
||||||
|
return () => {
|
||||||
|
this.selectedObject = obj;
|
||||||
|
this.open = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
renderMenuGroup(items: T[], tabIndexStart: number) {
|
||||||
|
const renderedItems = items.map((obj, index) => {
|
||||||
|
const desc = this.renderDescription ? this.renderDescription(obj) : null;
|
||||||
|
const tabIndex = index + tabIndexStart;
|
||||||
|
return desc
|
||||||
|
? this.renderMenuItemWithDescription(obj, desc, tabIndex)
|
||||||
|
: this.renderMenuItemWithoutDescription(obj, tabIndex);
|
||||||
|
});
|
||||||
|
return html`${renderedItems}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderWithMenuGroupTitle([group, items]: Group<T>, idx: number) {
|
||||||
|
return html`
|
||||||
|
<section class="pf-c-dropdown__group">
|
||||||
|
<h1 class="pf-c-dropdown__group-title">${group}</h1>
|
||||||
|
<ul>
|
||||||
|
${this.renderMenuGroup(items, idx)}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get groupedItems(): [boolean, Group<T>[]] {
|
||||||
|
const items = this.groupBy(this.objects || []);
|
||||||
|
if (items.length === 0) {
|
||||||
|
return [false, [["", []]]];
|
||||||
|
}
|
||||||
|
if (items.length === 1 && (items[0].length < 1 || items[0][0] === "")) {
|
||||||
|
return [false, items];
|
||||||
|
}
|
||||||
|
return [true, items];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a little bit hacky. Because we mainly want to use this field in modal-based forms,
|
||||||
|
* rendering this menu inline makes the menu not overlay over top of the modal, and cause
|
||||||
|
* the modal to scroll.
|
||||||
|
* Hence, we render the menu into the document root, hide it when this menu isn't open
|
||||||
|
* and remove it on disconnect
|
||||||
|
* Also to move it to the correct position we're getting this elements's position and use that
|
||||||
|
* to position the menu
|
||||||
|
* The other downside this has is that, since we're rendering outside of a shadow root,
|
||||||
|
* the pf-c-dropdown CSS needs to be loaded on the body.
|
||||||
|
*/
|
||||||
|
|
||||||
|
renderMenu(): void {
|
||||||
|
if (!this.objects) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const [shouldRenderGroups, groupedItems] = this.groupedItems;
|
||||||
|
|
||||||
|
const pos = this.getBoundingClientRect();
|
||||||
|
const position = {
|
||||||
|
"position": "fixed",
|
||||||
|
"inset": "0px auto auto 0px",
|
||||||
|
"z-index": "9999",
|
||||||
|
"transform": `translate(${pos.x}px, ${pos.y + this.offsetHeight}px)`,
|
||||||
|
"width": `${pos.width}px`,
|
||||||
|
...(this.open ? {} : { visibility: "hidden" }),
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
html`<div style=${styleMap(position)} class="pf-c-dropdown pf-m-expanded">
|
||||||
|
<ul
|
||||||
|
class="pf-c-dropdown__menu pf-m-static"
|
||||||
|
role="listbox"
|
||||||
|
style="max-height:50vh;overflow-y:auto;"
|
||||||
|
id=${this.dropdownUID}
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
${this.blankable ? this.renderEmptyMenuItem() : html``}
|
||||||
|
${shouldRenderGroups
|
||||||
|
? html`${groupedItems.map(this.renderWithMenuGroupTitle)}`
|
||||||
|
: html`${this.renderMenuGroup(groupedItems[0][1], 0)}`}
|
||||||
|
</ul>
|
||||||
|
</div>`,
|
||||||
|
this.dropdownContainer,
|
||||||
|
{ host: this },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get renderedValue() {
|
||||||
|
// prettier-ignore
|
||||||
|
return (!this.objects) ? msg("Loading...")
|
||||||
|
: (this.selectedObject) ? this.renderElement(this.selectedObject)
|
||||||
|
: (this.blankable) ? this.emptyOption
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
this.renderMenu();
|
||||||
|
|
||||||
|
const onFocus = (ev: FocusEvent) => {
|
||||||
|
this.open = true;
|
||||||
|
this.renderMenu();
|
||||||
|
if (this.blankable && this.renderedValue === this.emptyOption) {
|
||||||
|
if (ev.target && ev.target instanceof HTMLInputElement) {
|
||||||
|
ev.target.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInput = (ev: InputEvent) => {
|
||||||
|
this.query = (ev.target as HTMLInputElement).value;
|
||||||
|
this.updateData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onBlur = (ev: FocusEvent) => {
|
||||||
|
// For Safari, we get the <ul> element itself here when clicking on one of
|
||||||
|
// it's buttons, as the container has tabindex set
|
||||||
|
if (ev.relatedTarget && (ev.relatedTarget as HTMLElement).id === this.dropdownUID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check if we're losing focus to one of our dropdown items, and if such don't blur
|
||||||
|
if (ev.relatedTarget instanceof HTMLButtonElement) {
|
||||||
|
const parentMenu = ev.relatedTarget.closest("ul.pf-c-dropdown__menu.pf-m-static");
|
||||||
|
if (parentMenu && parentMenu.id === this.dropdownUID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.open = false;
|
||||||
|
this.renderMenu();
|
||||||
|
};
|
||||||
|
|
||||||
|
return html`<div class="pf-c-select">
|
||||||
|
<div class="pf-c-select__toggle pf-m-typeahead">
|
||||||
|
<div class="pf-c-select__toggle-wrapper">
|
||||||
|
<input
|
||||||
|
class="pf-c-form-control pf-c-select__toggle-typeahead"
|
||||||
|
type="text"
|
||||||
|
placeholder=${this.placeholder}
|
||||||
|
spellcheck="false"
|
||||||
|
@input=${onInput}
|
||||||
|
@focus=${onFocus}
|
||||||
|
@blur=${onBlur}
|
||||||
|
.value=${this.renderedValue}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SearchSelect;
|
4
web/src/elements/forms/SearchSelect/index.ts
Normal file
4
web/src/elements/forms/SearchSelect/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { SearchSelect } from "./ak-search-select";
|
||||||
|
|
||||||
|
export { SearchSelect };
|
||||||
|
export default SearchSelect;
|
@ -43,7 +43,6 @@ export class SidebarBrand extends WithTenantConfig(AKElement) {
|
|||||||
min-height: 114px;
|
min-height: 114px;
|
||||||
}
|
}
|
||||||
.pf-c-brand img {
|
.pf-c-brand img {
|
||||||
width: 100%;
|
|
||||||
padding: 0 0.5rem;
|
padding: 0 0.5rem;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
}
|
}
|
||||||
|
@ -505,7 +505,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
? html`
|
? html`
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://unsplash.com/@federize"
|
href="https://unsplash.com/@theforestbirds"
|
||||||
>${msg("Background image")}</a
|
>${msg("Background image")}</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
|
@ -6249,6 +6249,12 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -6525,6 +6525,12 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -6165,6 +6165,12 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8217,6 +8217,14 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
|||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
<target>Nombre maximum de connections concurrentes à ce point de terminaison. Peut être défini à -1 pour désactiver la limite.</target>
|
<target>Nombre maximum de connections concurrentes à ce point de terminaison. Peut être défini à -1 pour désactiver la limite.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
<target>Coréen</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
|
<target>Néerlandais</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
182
web/xliff/ko.xlf
182
web/xliff/ko.xlf
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
<?xml version="1.0"?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||||
<file target-language="ko" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
<file target-language="ko" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
||||||
<body>
|
<body>
|
||||||
<trans-unit id="s4caed5b7a7e5d89b">
|
<trans-unit id="s4caed5b7a7e5d89b">
|
||||||
@ -612,8 +612,8 @@
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="saa0e2675da69651b">
|
<trans-unit id="saa0e2675da69651b">
|
||||||
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
<source>The URL "<x id="0" equiv-text="${this.url}"/>" was not found.</source>
|
||||||
<target>URL "<x id="0" equiv-text="${this.url}"/>" 을 찾을 수 없습니다.</target>
|
<target>URL "<x id="0" equiv-text="${this.url}"/>" 을 찾을 수 없습니다.</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s58cd9c2fe836d9c6">
|
<trans-unit id="s58cd9c2fe836d9c6">
|
||||||
@ -1054,8 +1054,8 @@
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sa8384c9c26731f83">
|
<trans-unit id="sa8384c9c26731f83">
|
||||||
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
<source>To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.</source>
|
||||||
<target>리디렉션 URI를 허용하려면 이 값을 ".*"로 설정합니다. 이로 인해 발생할 수 있는 보안상의 영향에 유의하세요.</target>
|
<target>리디렉션 URI를 허용하려면 이 값을 ".*"로 설정합니다. 이로 인해 발생할 수 있는 보안상의 영향에 유의하세요.</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s55787f4dfcdce52b">
|
<trans-unit id="s55787f4dfcdce52b">
|
||||||
@ -1792,8 +1792,8 @@
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sa90b7809586c35ce">
|
<trans-unit id="sa90b7809586c35ce">
|
||||||
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
<source>Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".</source>
|
||||||
<target>전체 URL, 상대 경로를 입력하거나, 또는 'fa://fa-test'를 사용하여 Font Awesome 아이콘 "fa-test"를 사용합니다.</target>
|
<target>전체 URL, 상대 경로를 입력하거나, 또는 'fa://fa-test'를 사용하여 Font Awesome 아이콘 "fa-test"를 사용합니다.</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s0410779cb47de312">
|
<trans-unit id="s0410779cb47de312">
|
||||||
@ -2972,7 +2972,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s76768bebabb7d543">
|
<trans-unit id="s76768bebabb7d543">
|
||||||
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'</source>
|
||||||
<target>그룹 구성원이 포함된 필드입니다. 'memberUid' 필드를 사용하는 경우 값에 상대적인 고유 이름이 포함된 것으로 가정합니다 (예:'memberUid=some-user' 대신 'memberUid=cn=some-user,ou=groups,...').</target>
|
<target>그룹 구성원이 포함된 필드입니다. 'memberUid' 필드를 사용하는 경우 값에 상대적인 고유 이름이 포함된 것으로 가정합니다 (예:'memberUid=some-user' 대신 'memberUid=cn=some-user,ou=groups,...').</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -3764,8 +3764,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s7b1fba26d245cb1c">
|
<trans-unit id="s7b1fba26d245cb1c">
|
||||||
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
<source>When using an external logging solution for archiving, this can be set to "minutes=5".</source>
|
||||||
<target>아카이브에 외부 로깅 솔루션을 사용하는 경우, 이 값을 "minutes=5"로 설정할 수 있습니다.</target>
|
<target>아카이브에 외부 로깅 솔루션을 사용하는 경우, 이 값을 "minutes=5"로 설정할 수 있습니다.</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s44536d20bb5c8257">
|
<trans-unit id="s44536d20bb5c8257">
|
||||||
@ -3774,8 +3774,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s3bb51cabb02b997e">
|
<trans-unit id="s3bb51cabb02b997e">
|
||||||
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
<source>Format: "weeks=3;days=2;hours=3,seconds=2".</source>
|
||||||
<target>서식: "weeks=3;days=2;hours=3,seconds=2".</target>
|
<target>서식: "weeks=3;days=2;hours=3,seconds=2".</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s04bfd02201db5ab8">
|
<trans-unit id="s04bfd02201db5ab8">
|
||||||
@ -3967,8 +3967,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sa95a538bfbb86111">
|
<trans-unit id="sa95a538bfbb86111">
|
||||||
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
<source>Are you sure you want to update <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>"?</source>
|
||||||
<target>정말 <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>" 을(를) 업데이트 하시겠습니까?</target>
|
<target>정말 <x id="0" equiv-text="${this.objectLabel}"/> "<x id="1" equiv-text="${this.obj?.name}"/>" 을(를) 업데이트 하시겠습니까?</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sc92d7cfb6ee1fec6">
|
<trans-unit id="sc92d7cfb6ee1fec6">
|
||||||
@ -5052,8 +5052,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sdf1d8edef27236f0">
|
<trans-unit id="sdf1d8edef27236f0">
|
||||||
<source>A "roaming" authenticator, like a YubiKey</source>
|
<source>A "roaming" authenticator, like a YubiKey</source>
|
||||||
<target>YubiKey 같은 "로밍" 인증기</target>
|
<target>YubiKey 같은 "로밍" 인증기</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sfffba7b23d8fb40c">
|
<trans-unit id="sfffba7b23d8fb40c">
|
||||||
@ -5387,8 +5387,8 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s2d5f69929bb7221d">
|
<trans-unit id="s2d5f69929bb7221d">
|
||||||
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
<source><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</source>
|
||||||
<target><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</target>
|
<target><x id="0" equiv-text="${prompt.name}"/> ("<x id="1" equiv-text="${prompt.fieldKey}"/>", of type <x id="2" equiv-text="${prompt.type}"/>)</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s3b7b519444181264">
|
<trans-unit id="s3b7b519444181264">
|
||||||
@ -5436,7 +5436,7 @@ doesn't pass when either or both of the selected options are equal or above the
|
|||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s1608b2f94fa0dbd4">
|
<trans-unit id="s1608b2f94fa0dbd4">
|
||||||
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
<source>If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here.</source>
|
||||||
<target>기간을 0 이상으로 설정하면, 사용자에게 '로그인 상태 유지'를 선택할 수 있는 옵션이 제공되며, 이 경우 세션이 여기에 지정된 시간만큼 연장됩니다.</target>
|
<target>기간을 0 이상으로 설정하면, 사용자에게 '로그인 상태 유지'를 선택할 수 있는 옵션이 제공되며, 이 경우 세션이 여기에 지정된 시간만큼 연장됩니다.</target>
|
||||||
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@ -7926,8 +7926,8 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<target>사용자 생성과 <x id="0" equiv-text="${this.group.name}"/> 그룹 추가에 성공했습니다.</target>
|
<target>사용자 생성과 <x id="0" equiv-text="${this.group.name}"/> 그룹 추가에 성공했습니다.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s824e0943a7104668">
|
<trans-unit id="s824e0943a7104668">
|
||||||
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
|
||||||
<target>이 사용자는 "<x id="0" equiv-text="${this.targetGroup.name}"/>" 그룹에 추가됩니다.</target>
|
<target>이 사용자는 "<x id="0" equiv-text="${this.targetGroup.name}"/>" 그룹에 추가됩니다.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62e7f6ed7d9cb3ca">
|
<trans-unit id="s62e7f6ed7d9cb3ca">
|
||||||
<source>Pretend user exists</source>
|
<source>Pretend user exists</source>
|
||||||
@ -8004,7 +8004,145 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s047a5f0211fedc72">
|
<trans-unit id="s047a5f0211fedc72">
|
||||||
<source>Require Outpost (flow can only be executed from an outpost).</source>
|
<source>Require Outpost (flow can only be executed from an outpost).</source>
|
||||||
<target>Outpost필요 (플로우는 Outpost에서만 실행할 수 있음).</target>
|
<target>Outpost필요 (플로우는 Outpost에서만 실행할 수 있음).</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="scc7f34824150bfb8">
|
||||||
|
<source>Provider require enterprise.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s31f1afc1bfe1cb3a">
|
||||||
|
<source>Learn more</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sa2ea0fcd3ffa80e0">
|
||||||
|
<source>Connection expiry</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s6dd297c217729828">
|
||||||
|
<source>Determines how long a session lasts before being disconnected and requiring re-authorization.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s3271da6c18c25b18">
|
||||||
|
<source>Connection settings.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s2f4ca2148183d692">
|
||||||
|
<source>Successfully updated endpoint.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s5adee855dbe191d9">
|
||||||
|
<source>Successfully created endpoint.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s61e136c0658e27d5">
|
||||||
|
<source>Protocol</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sa062b019ff0c8809">
|
||||||
|
<source>RDP</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s97f9bf19fa5b57d1">
|
||||||
|
<source>SSH</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7c100119e9ffcc32">
|
||||||
|
<source>VNC</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s6b05f9d8801fc14f">
|
||||||
|
<source>Host</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sb474f652a2c2fc76">
|
||||||
|
<source>Hostname/IP to connect to.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sc39f6abf0daedb0f">
|
||||||
|
<source>Maximum concurrent connections</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s8276649077e8715c">
|
||||||
|
<source>Endpoint(s)</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sf1dabfe0fe8a75ad">
|
||||||
|
<source>Update Endpoint</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s008496c7716b9812">
|
||||||
|
<source>These bindings control which users will have access to this endpoint. Users must also have access to the application.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s38e7cd1a24e70faa">
|
||||||
|
<source>Create Endpoint</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s4770c10e5b1c028c">
|
||||||
|
<source>RAC is in preview.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s168565f5ac74a89f">
|
||||||
|
<source>Update RAC Provider</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s8465a2caa2d9ea5d">
|
||||||
|
<source>Endpoints</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s9857d883d8eb98fc">
|
||||||
|
<source>General settings</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sd2066881798a1b96">
|
||||||
|
<source>RDP settings</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sb864dc36a463a155">
|
||||||
|
<source>Ignore server certificate</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s20366a8d1eaaca54">
|
||||||
|
<source>Enable wallpaper</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s1e44c5350ef7598c">
|
||||||
|
<source>Enable font-smoothing</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s04ff5d6ae711e6d6">
|
||||||
|
<source>Enable full window dragging</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s663ccbfdf27e8dd0">
|
||||||
|
<source>Network binding</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sb108a06693c67753">
|
||||||
|
<source>No binding</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s5aab90c74f1233b8">
|
||||||
|
<source>Bind ASN</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s488303b048afe83b">
|
||||||
|
<source>Bind ASN and Network</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s3268dcfe0c8234dc">
|
||||||
|
<source>Bind ASN, Network and IP</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s226381aca231644f">
|
||||||
|
<source>Configure if sessions created by this stage should be bound to the Networks they were created in.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s2555a1f20f3fd93e">
|
||||||
|
<source>GeoIP binding</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s3d63c78f93c9a92e">
|
||||||
|
<source>Bind Continent</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s395d5863b3a259b5">
|
||||||
|
<source>Bind Continent and Country</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s625ea0c32b4b136c">
|
||||||
|
<source>Bind Continent, Country and City</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s4bc7a1a88961be90">
|
||||||
|
<source>Configure if sessions created by this stage should be bound to their GeoIP-based location</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sa06cd519ff151b6d">
|
||||||
|
<source>RAC</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s28b99b59541f54ca">
|
||||||
|
<source>Connection failed after <x id="0" equiv-text="${this.connectionAttempt}"/> attempts.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7c7d956418e1c8c8">
|
||||||
|
<source>Re-connecting in <x id="0" equiv-text="${Math.max(1, delay / 1000)}"/> second(s).</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="sfc003381f593d943">
|
||||||
|
<source>Connecting...</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s31aa94a0b3c7edb2">
|
||||||
|
<source>Select endpoint to connect to</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
899
web/xliff/nl.xlf
899
web/xliff/nl.xlf
File diff suppressed because it is too large
Load Diff
@ -6373,6 +6373,12 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8111,4 +8111,10 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
|
</trans-unit>
|
||||||
</body></file></xliff>
|
</body></file></xliff>
|
||||||
|
@ -6158,6 +6158,12 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
5068
web/xliff/zh-CN.xlf
Normal file
5068
web/xliff/zh-CN.xlf
Normal file
File diff suppressed because it is too large
Load Diff
@ -8219,6 +8219,14 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
<target>允许到此端点的最大并发连接数。可以设置为 -1 以禁用限制。</target>
|
<target>允许到此端点的最大并发连接数。可以设置为 -1 以禁用限制。</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
<target>韩语</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
|
<target>荷兰语</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -6206,6 +6206,12 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8219,6 +8219,14 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
<target>允许到此端点的最大并发连接数。可以设置为 -1 以禁用限制。</target>
|
<target>允许到此端点的最大并发连接数。可以设置为 -1 以禁用限制。</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
<target>韩语</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
|
<target>荷兰语</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -8095,6 +8095,12 @@ Bindings to groups/users are checked against the user of the event.</source>
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="s62418cbcd2a25498">
|
<trans-unit id="s62418cbcd2a25498">
|
||||||
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
<source>Maximum concurrent allowed connections to this endpoint. Can be set to -1 to disable the limit.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s94d61907ee22a8c1">
|
||||||
|
<source>Korean</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s95d56e58f816d211">
|
||||||
|
<source>Dutch</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
@ -4,16 +4,16 @@ title: Docker Compose installation
|
|||||||
|
|
||||||
This installation method is for test-setups and small-scale production setups.
|
This installation method is for test-setups and small-scale production setups.
|
||||||
|
|
||||||
:::info
|
|
||||||
You can also [view a video walk-through](https://www.youtube.com/watch?v=O1qUbrk4Yc8) of the installation process on Docker (with bonus details about email configuration and other important options).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- A host with at least 2 CPU cores and 2 GB of RAM
|
- A host with at least 2 CPU cores and 2 GB of RAM
|
||||||
- Docker
|
- Docker
|
||||||
- Docker Compose
|
- Docker Compose
|
||||||
|
|
||||||
|
## Video
|
||||||
|
|
||||||
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/O1qUbrk4Yc8?si=HiSBjmJYhE_oJhB1&start=22" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||||
|
|
||||||
## Preparation
|
## Preparation
|
||||||
|
|
||||||
To download the latest `docker-compose.yml` open your terminal and navigate to the directory of your choice.
|
To download the latest `docker-compose.yml` open your terminal and navigate to the directory of your choice.
|
||||||
|
@ -4,6 +4,6 @@ title: Installation
|
|||||||
|
|
||||||
Everything you need to get authentik up and running! For information about upgrading to a new version, refer to the <b>Upgrade</b> section in the relevant [Release Notes](../releases).
|
Everything you need to get authentik up and running! For information about upgrading to a new version, refer to the <b>Upgrade</b> section in the relevant [Release Notes](../releases).
|
||||||
|
|
||||||
import DocCardList from '@theme/DocCardList';
|
import DocCardList from "@theme/DocCardList";
|
||||||
|
|
||||||
<DocCardList />
|
<DocCardList />
|
@ -13,6 +13,10 @@ You can also [view a video walk-through](https://www.youtube.com/watch?v=O1qUbrk
|
|||||||
- Kubernetes
|
- Kubernetes
|
||||||
- Helm
|
- Helm
|
||||||
|
|
||||||
|
## Video
|
||||||
|
|
||||||
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/O1qUbrk4Yc8?si=hs-ZhbVk4Y-TW_Vw&start=562" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||||
|
|
||||||
### Generate Passwords
|
### Generate Passwords
|
||||||
|
|
||||||
Start by generating passwords for the database and cache. You can use either of the following commands:
|
Start by generating passwords for the database and cache. You can use either of the following commands:
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
const config = require("./docusaurus.config");
|
|
||||||
import type { Config } from "@docusaurus/types";
|
|
||||||
|
|
||||||
module.exports = async function (): Promise<Config> {
|
|
||||||
const remarkGithub = (await import("remark-github")).default;
|
|
||||||
const defaultBuildUrl = (await import("remark-github")).defaultBuildUrl;
|
|
||||||
const mainConfig = await config();
|
|
||||||
return {
|
|
||||||
title: "authentik",
|
|
||||||
tagline: "Making authentication simple.",
|
|
||||||
url: "https://goauthentik.io",
|
|
||||||
baseUrl: "/if/help/",
|
|
||||||
onBrokenLinks: "throw",
|
|
||||||
favicon: "img/icon.png",
|
|
||||||
organizationName: "BeryJu",
|
|
||||||
projectName: "authentik",
|
|
||||||
themeConfig: {
|
|
||||||
navbar: {
|
|
||||||
logo: {
|
|
||||||
alt: "authentik logo",
|
|
||||||
src: "img/icon_left_brand.svg",
|
|
||||||
},
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
to: "docs/",
|
|
||||||
activeBasePath: "docs",
|
|
||||||
label: "Docs",
|
|
||||||
position: "left",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: "integrations/",
|
|
||||||
activeBasePath: "integrations",
|
|
||||||
label: "Integrations",
|
|
||||||
position: "left",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: "developer-docs/",
|
|
||||||
activeBasePath: "developer-docs",
|
|
||||||
label: "Developer Docs",
|
|
||||||
position: "left",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: "https://github.com/goauthentik/authentik",
|
|
||||||
label: "GitHub",
|
|
||||||
position: "right",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: "https://goauthentik.io/discord",
|
|
||||||
label: "Discord",
|
|
||||||
position: "right",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
links: [],
|
|
||||||
copyright: mainConfig.themeConfig.footer.copyright,
|
|
||||||
},
|
|
||||||
colorMode: mainConfig.themeConfig.colorMode,
|
|
||||||
tableOfContents: mainConfig.themeConfig.tableOfContents,
|
|
||||||
prims: mainConfig.themeConfig.prism,
|
|
||||||
},
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
"@docusaurus/preset-classic",
|
|
||||||
{
|
|
||||||
docs: {
|
|
||||||
id: "docs",
|
|
||||||
sidebarPath: require.resolve("./sidebars.js"),
|
|
||||||
editUrl:
|
|
||||||
"https://github.com/goauthentik/authentik/edit/main/website/",
|
|
||||||
remarkPlugins: [
|
|
||||||
[
|
|
||||||
remarkGithub,
|
|
||||||
{
|
|
||||||
repository: "goauthentik/authentik",
|
|
||||||
// Only replace issues and PR links
|
|
||||||
buildUrl: function (values) {
|
|
||||||
return values.type === "issue"
|
|
||||||
? defaultBuildUrl(values)
|
|
||||||
: false;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
pages: false,
|
|
||||||
theme: {
|
|
||||||
customCss: require.resolve("./src/css/custom.css"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
[
|
|
||||||
"@docusaurus/plugin-content-docs",
|
|
||||||
{
|
|
||||||
id: "docsIntegrations",
|
|
||||||
path: "integrations",
|
|
||||||
routeBasePath: "integrations",
|
|
||||||
sidebarPath: require.resolve("./sidebarsIntegrations.js"),
|
|
||||||
editUrl:
|
|
||||||
"https://github.com/goauthentik/authentik/edit/main/website/",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@docusaurus/plugin-content-docs",
|
|
||||||
{
|
|
||||||
id: "docsDevelopers",
|
|
||||||
path: "developer-docs",
|
|
||||||
routeBasePath: "developer-docs",
|
|
||||||
sidebarPath: require.resolve("./sidebarsDev.js"),
|
|
||||||
editUrl:
|
|
||||||
"https://github.com/goauthentik/authentik/edit/main/website/",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@docusaurus/plugin-client-redirects",
|
|
||||||
{
|
|
||||||
redirects: [
|
|
||||||
{
|
|
||||||
to: "/docs/",
|
|
||||||
from: ["/"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
};
|
|
||||||
};
|
|
@ -133,7 +133,7 @@ Add a new provider using the `+` button and set the following values:
|
|||||||
- Display name mapping: name
|
- Display name mapping: name
|
||||||
- Email mapping: email
|
- Email mapping: email
|
||||||
- Quota mapping: quota (leave empty if you have skipped the [custom profile scope](#custom-profile-scope) section)
|
- Quota mapping: quota (leave empty if you have skipped the [custom profile scope](#custom-profile-scope) section)
|
||||||
- Groups mapping: group (leave empty if you have skipped the [custom profile scope](#custom-profile-scope) section)
|
- Groups mapping: groups (leave empty if you have skipped the [custom profile scope](#custom-profile-scope) section)
|
||||||
:::tip
|
:::tip
|
||||||
You need to enable the "Use group provisioning" checkmark to be able to write to this field
|
You need to enable the "Use group provisioning" checkmark to be able to write to this field
|
||||||
:::
|
:::
|
||||||
|
8
website/package-lock.json
generated
8
website/package-lock.json
generated
@ -34,7 +34,7 @@
|
|||||||
"@docusaurus/tsconfig": "3.0.1",
|
"@docusaurus/tsconfig": "3.0.1",
|
||||||
"@docusaurus/types": "3.0.1",
|
"@docusaurus/types": "3.0.1",
|
||||||
"@types/react": "^18.2.48",
|
"@types/react": "^18.2.48",
|
||||||
"prettier": "3.2.3",
|
"prettier": "3.2.4",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.3.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -13754,9 +13754,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.3",
|
"version": "3.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz",
|
||||||
"integrity": "sha512-QNhUTBq+mqt1oH1dTfY3phOKNhcDdJkfttHI6u0kj7M2+c+7fmNKlgh2GhnHiqMcbxJ+a0j2igz/2jfl9QKLuw==",
|
"integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
"@docusaurus/tsconfig": "3.0.1",
|
"@docusaurus/tsconfig": "3.0.1",
|
||||||
"@docusaurus/types": "3.0.1",
|
"@docusaurus/types": "3.0.1",
|
||||||
"@types/react": "^18.2.48",
|
"@types/react": "^18.2.48",
|
||||||
"prettier": "3.2.3",
|
"prettier": "3.2.4",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.3.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
Reference in New Issue
Block a user