core: Format. Fix. WIP.
This commit is contained in:
@ -10,6 +10,9 @@ insert_final_newline = true
|
|||||||
[*.html]
|
[*.html]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
|
[schemas/*.json]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
[*.{yaml,yml}]
|
[*.{yaml,yml}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,14 @@
|
|||||||
## Static Files
|
## Static Files
|
||||||
**/LICENSE
|
**/LICENSE
|
||||||
|
|
||||||
|
authentik/stages/**/*
|
||||||
|
|
||||||
## Build asset directories
|
## Build asset directories
|
||||||
/build
|
|
||||||
coverage
|
coverage
|
||||||
dist
|
dist
|
||||||
out
|
out
|
||||||
|
.docusaurus
|
||||||
|
website/docs/developer-docs/api/**/*
|
||||||
|
|
||||||
## Environment
|
## Environment
|
||||||
*.env
|
*.env
|
||||||
@ -20,9 +23,25 @@ out
|
|||||||
|
|
||||||
## Node
|
## Node
|
||||||
node_modules
|
node_modules
|
||||||
|
coverage
|
||||||
|
|
||||||
## Configs
|
## Configs
|
||||||
*.log
|
*.log
|
||||||
*.yaml
|
*.yaml
|
||||||
*.yml
|
*.yml
|
||||||
|
|
||||||
|
# Templates
|
||||||
|
# TODO: Rename affected files to *.template.* or similar.
|
||||||
|
*.html
|
||||||
|
*.mdx
|
||||||
|
*.md
|
||||||
|
|
||||||
|
## Import order matters
|
||||||
|
poly.ts
|
||||||
|
src/locale-codes.ts
|
||||||
|
src/locales/
|
||||||
|
|
||||||
|
# Storybook
|
||||||
|
storybook-static/
|
||||||
|
.storybook/css-import-maps*
|
||||||
|
|
||||||
|
|||||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@ -17,6 +17,6 @@
|
|||||||
"ms-python.vscode-pylance",
|
"ms-python.vscode-pylance",
|
||||||
"redhat.vscode-yaml",
|
"redhat.vscode-yaml",
|
||||||
"Tobermory.es6-string-html",
|
"Tobermory.es6-string-html",
|
||||||
"unifiedjs.vscode-mdx",
|
"unifiedjs.vscode-mdx"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
57
.vscode/settings.json
vendored
57
.vscode/settings.json
vendored
@ -16,7 +16,7 @@
|
|||||||
],
|
],
|
||||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||||
"typescript.preferences.importModuleSpecifierEnding": "index",
|
"typescript.preferences.importModuleSpecifierEnding": "index",
|
||||||
"typescript.tsdk": "./web/node_modules/typescript/lib",
|
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
"yaml.schemas": {
|
"yaml.schemas": {
|
||||||
"./blueprints/schema.json": "blueprints/**/*.yaml"
|
"./blueprints/schema.json": "blueprints/**/*.yaml"
|
||||||
@ -30,7 +30,56 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"go.testFlags": ["-count=1"],
|
"go.testFlags": ["-count=1"],
|
||||||
"github-actions.workflows.pinned.workflows": [
|
"github-actions.workflows.pinned.workflows": [".github/workflows/ci-main.yml"],
|
||||||
".github/workflows/ci-main.yml"
|
|
||||||
]
|
"eslint.useFlatConfig": true,
|
||||||
|
|
||||||
|
"explorer.fileNesting.enabled": true,
|
||||||
|
"explorer.fileNesting.patterns": {
|
||||||
|
"*.cjs": "*.d.cts",
|
||||||
|
"package.json": "package-lock.json, yarn.lock, .yarnrc, .yarnrc.yml, .yarn, .nvmrc, .node-version",
|
||||||
|
"tsconfig.json": "tsconfig.*.json, jsconfig.json"
|
||||||
|
},
|
||||||
|
|
||||||
|
"search.exclude": {
|
||||||
|
"**/node_modules": true,
|
||||||
|
"**/*.code-search": true,
|
||||||
|
"**/dist": true,
|
||||||
|
"**/out": true,
|
||||||
|
"**/package-lock.json": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"[css]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[javascriptreact]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[markdown]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[shellscript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[typescriptreact]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.removeUnusedImports": "explicit"
|
||||||
|
},
|
||||||
|
// We use Prettier for formatting, but specifying these settings
|
||||||
|
// will ensure that VS Code's IntelliSense doesn't autocomplete unformatted code.
|
||||||
|
"javascript.format.semicolons": "insert",
|
||||||
|
"typescript.format.semicolons": "insert",
|
||||||
|
"javascript.preferences.quoteStyle": "double",
|
||||||
|
"typescript.preferences.quoteStyle": "double"
|
||||||
}
|
}
|
||||||
|
|||||||
40
.vscode/tasks.json
vendored
40
.vscode/tasks.json
vendored
@ -4,12 +4,7 @@
|
|||||||
{
|
{
|
||||||
"label": "authentik/core: make",
|
"label": "authentik/core: make",
|
||||||
"command": "uv",
|
"command": "uv",
|
||||||
"args": [
|
"args": ["run", "make", "lint-fix", "lint"],
|
||||||
"run",
|
|
||||||
"make",
|
|
||||||
"lint-fix",
|
|
||||||
"lint"
|
|
||||||
],
|
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"panel": "new"
|
"panel": "new"
|
||||||
},
|
},
|
||||||
@ -18,11 +13,7 @@
|
|||||||
{
|
{
|
||||||
"label": "authentik/core: run",
|
"label": "authentik/core: run",
|
||||||
"command": "uv",
|
"command": "uv",
|
||||||
"args": [
|
"args": ["run", "ak", "server"],
|
||||||
"run",
|
|
||||||
"ak",
|
|
||||||
"server"
|
|
||||||
],
|
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"panel": "dedicated",
|
"panel": "dedicated",
|
||||||
@ -32,17 +23,13 @@
|
|||||||
{
|
{
|
||||||
"label": "authentik/web: make",
|
"label": "authentik/web: make",
|
||||||
"command": "make",
|
"command": "make",
|
||||||
"args": [
|
"args": ["web"],
|
||||||
"web"
|
|
||||||
],
|
|
||||||
"group": "build"
|
"group": "build"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "authentik/web: watch",
|
"label": "authentik/web: watch",
|
||||||
"command": "make",
|
"command": "make",
|
||||||
"args": [
|
"args": ["web-watch"],
|
||||||
"web-watch"
|
|
||||||
],
|
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"panel": "dedicated",
|
"panel": "dedicated",
|
||||||
@ -52,26 +39,19 @@
|
|||||||
{
|
{
|
||||||
"label": "authentik: install",
|
"label": "authentik: install",
|
||||||
"command": "make",
|
"command": "make",
|
||||||
"args": [
|
"args": ["install", "-j4"],
|
||||||
"install",
|
|
||||||
"-j4"
|
|
||||||
],
|
|
||||||
"group": "build"
|
"group": "build"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "authentik/website: make",
|
"label": "authentik/website: make",
|
||||||
"command": "make",
|
"command": "make",
|
||||||
"args": [
|
"args": ["website"],
|
||||||
"website"
|
|
||||||
],
|
|
||||||
"group": "build"
|
"group": "build"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "authentik/website: watch",
|
"label": "authentik/website: watch",
|
||||||
"command": "make",
|
"command": "make",
|
||||||
"args": [
|
"args": ["website-watch"],
|
||||||
"website-watch"
|
|
||||||
],
|
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"panel": "dedicated",
|
"panel": "dedicated",
|
||||||
@ -81,11 +61,7 @@
|
|||||||
{
|
{
|
||||||
"label": "authentik/api: generate",
|
"label": "authentik/api: generate",
|
||||||
"command": "uv",
|
"command": "uv",
|
||||||
"args": [
|
"args": ["run", "make", "gen"],
|
||||||
"run",
|
|
||||||
"make",
|
|
||||||
"gen"
|
|
||||||
],
|
|
||||||
"group": "build"
|
"group": "build"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
12
Makefile
12
Makefile
@ -133,16 +133,14 @@ gen-client-ts: gen-clean-ts ## Build and install the authentik API for Typescri
|
|||||||
--rm -v ${PWD}:/local \
|
--rm -v ${PWD}:/local \
|
||||||
--user ${UID}:${GID} \
|
--user ${UID}:${GID} \
|
||||||
docker.io/openapitools/openapi-generator-cli:v7.11.0 generate \
|
docker.io/openapitools/openapi-generator-cli:v7.11.0 generate \
|
||||||
-i /local/schema.yml \
|
--input-spec /local/schema.yml \
|
||||||
-g typescript-fetch \
|
--generator-name typescript-fetch \
|
||||||
-o /local/${GEN_API_TS} \
|
--output /local/${GEN_API_TS} \
|
||||||
-c /local/scripts/api-ts-config.yaml \
|
--config /local/scripts/api-ts-config.yaml \
|
||||||
--additional-properties=npmVersion=${NPM_VERSION} \
|
--additional-properties=npmVersion=${NPM_VERSION} \
|
||||||
--git-repo-id authentik \
|
--git-repo-id authentik \
|
||||||
--git-user-id goauthentik
|
--git-user-id goauthentik
|
||||||
mkdir -p web/node_modules/@goauthentik/api
|
npm install
|
||||||
cd ./${GEN_API_TS} && npm i
|
|
||||||
\cp -rf ./${GEN_API_TS}/* web/node_modules/@goauthentik/api
|
|
||||||
|
|
||||||
gen-client-py: gen-clean-py ## Build and install the authentik API for Python
|
gen-client-py: gen-clean-py ## Build and install the authentik API for Python
|
||||||
docker run \
|
docker run \
|
||||||
|
|||||||
@ -323,12 +323,7 @@
|
|||||||
"multiValued": false,
|
"multiValued": false,
|
||||||
"description": "Indicates whether or not an attribute is modifiable.",
|
"description": "Indicates whether or not an attribute is modifiable.",
|
||||||
"required": false,
|
"required": false,
|
||||||
"canonicalValues": [
|
"canonicalValues": ["readOnly", "readWrite", "immutable", "writeOnly"],
|
||||||
"readOnly",
|
|
||||||
"readWrite",
|
|
||||||
"immutable",
|
|
||||||
"writeOnly"
|
|
||||||
],
|
|
||||||
"caseExact": false,
|
"caseExact": false,
|
||||||
"mutability": "readOnly",
|
"mutability": "readOnly",
|
||||||
"returned": "default",
|
"returned": "default",
|
||||||
@ -340,12 +335,7 @@
|
|||||||
"multiValued": false,
|
"multiValued": false,
|
||||||
"description": "Indicates when an attribute is returned in a response (e.g., to a query).",
|
"description": "Indicates when an attribute is returned in a response (e.g., to a query).",
|
||||||
"required": false,
|
"required": false,
|
||||||
"canonicalValues": [
|
"canonicalValues": ["always", "never", "default", "request"],
|
||||||
"always",
|
|
||||||
"never",
|
|
||||||
"default",
|
|
||||||
"request"
|
|
||||||
],
|
|
||||||
"caseExact": false,
|
"caseExact": false,
|
||||||
"mutability": "readOnly",
|
"mutability": "readOnly",
|
||||||
"returned": "default",
|
"returned": "default",
|
||||||
@ -369,12 +359,7 @@
|
|||||||
"multiValued": true,
|
"multiValued": true,
|
||||||
"description": "Used only with an attribute of type 'reference'. Specifies a SCIM resourceType that a reference attribute MAY refer to, e.g., 'User'.",
|
"description": "Used only with an attribute of type 'reference'. Specifies a SCIM resourceType that a reference attribute MAY refer to, e.g., 'User'.",
|
||||||
"required": false,
|
"required": false,
|
||||||
"canonicalValues": [
|
"canonicalValues": ["resource", "external", "uri", "url"],
|
||||||
"resource",
|
|
||||||
"external",
|
|
||||||
"uri",
|
|
||||||
"url"
|
|
||||||
],
|
|
||||||
"caseExact": false,
|
"caseExact": false,
|
||||||
"mutability": "readOnly",
|
"mutability": "readOnly",
|
||||||
"returned": "default",
|
"returned": "default",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
10
eslint.config.mjs
Normal file
10
eslint.config.mjs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { createESLintPackageConfig } from "@goauthentik/eslint-config";
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ESLint configuration for authentik's monorepo.
|
||||||
|
*/
|
||||||
|
const ESLintConfig = createESLintPackageConfig();
|
||||||
|
|
||||||
|
export default ESLintConfig;
|
||||||
@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/lifecycle-aws",
|
"name": "@goauthentik/lifecycle-aws",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"aws-cfn": "cross-env CI=false cdk synth --version-reporting=false > template.yaml"
|
"aws-cfn": "cross-env CI=false cdk synth --version-reporting=false > template.yaml"
|
||||||
},
|
},
|
||||||
"engines": {
|
|
||||||
"node": ">=20"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aws-cdk": "^2.1005.0",
|
"aws-cdk": "^2.1005.0",
|
||||||
"cross-env": "^7.0.3"
|
"cross-env": "^7.0.3"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43195
package-lock.json
generated
43195
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
37
package.json
37
package.json
@ -1,5 +1,38 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/authentik",
|
"name": "@goauthentik/universe",
|
||||||
"version": "2025.2.2",
|
"version": "2025.2.2",
|
||||||
"private": true
|
"description": "Monorepo for authentik.",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"compile": "NODE_OPTIONS=\"--max-old-space-size=3000\" tsc -b",
|
||||||
|
"compile:clean": "node ./sdk/out/scripts/clean.js",
|
||||||
|
"lint": "run-s lint:prettier:check lint:eslint:check",
|
||||||
|
"lint:eslint:check": "eslint .",
|
||||||
|
"lint:eslint:fix": "eslint --fix .",
|
||||||
|
"lint:fix": "run-s lint:prettier:fix lint:eslint:fix",
|
||||||
|
"lint:prettier": "eslint .",
|
||||||
|
"lint:prettier:check": "prettier --cache --check -u .",
|
||||||
|
"lint:prettier:fix": "prettier --cache --write -u ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@eslint/js": "^9.11.1",
|
||||||
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
||||||
|
"@typescript-eslint/parser": "^8.28.0",
|
||||||
|
"eslint": "^9.23.0",
|
||||||
|
"eslint-plugin-lit": "^2.0.0",
|
||||||
|
"eslint-plugin-wc": "^3.0.0",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"prettier": "^3.5.3",
|
||||||
|
"typescript": "^5.8.2",
|
||||||
|
"typescript-eslint": "^8.29.0",
|
||||||
|
"zx": "^8.4.1"
|
||||||
|
},
|
||||||
|
"workspaces": [
|
||||||
|
"gen-ts-api",
|
||||||
|
"web",
|
||||||
|
"website",
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"prettier": "@goauthentik/prettier-config"
|
||||||
}
|
}
|
||||||
|
|||||||
11
packages/eslint-config/@types/eslint-plugin-react-hooks.d.ts
vendored
Normal file
11
packages/eslint-config/@types/eslint-plugin-react-hooks.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* @file TypeScript type definitions for eslint-plugin-react-hooks
|
||||||
|
*/
|
||||||
|
declare module "eslint-plugin-react-hooks" {
|
||||||
|
import { ESLint } from "eslint";
|
||||||
|
// We have to do this because ESLint aliases the namespace and class simultaneously.
|
||||||
|
type PluginInstance = ESLint.Plugin;
|
||||||
|
const Plugin: PluginInstance;
|
||||||
|
|
||||||
|
export default Plugin;
|
||||||
|
}
|
||||||
11
packages/eslint-config/@types/eslint-plugin-react.d.ts
vendored
Normal file
11
packages/eslint-config/@types/eslint-plugin-react.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* @file TypeScript type definitions for eslint-plugin-react
|
||||||
|
*/
|
||||||
|
declare module "eslint-plugin-react" {
|
||||||
|
import { ESLint } from "eslint";
|
||||||
|
// We have to do this because ESLint aliases the namespace and class simultaneously.
|
||||||
|
type PluginInstance = ESLint.Plugin;
|
||||||
|
const Plugin: PluginInstance;
|
||||||
|
|
||||||
|
export default Plugin;
|
||||||
|
}
|
||||||
@ -1,8 +1,9 @@
|
|||||||
import eslint from "@eslint/js";
|
import eslint from "@eslint/js";
|
||||||
|
import { javaScriptConfig } from "@goauthentik/eslint-config/javascript-config";
|
||||||
import { reactConfig } from "@goauthentik/eslint-config/react-config";
|
import { reactConfig } from "@goauthentik/eslint-config/react-config";
|
||||||
import { typescriptConfig } from "@goauthentik/eslint-config/typescript-config";
|
import { typescriptConfig } from "@goauthentik/eslint-config/typescript-config";
|
||||||
import litconf from "eslint-plugin-lit";
|
import * as litconf from "eslint-plugin-lit";
|
||||||
import wcconf from "eslint-plugin-wc";
|
import * as wcconf from "eslint-plugin-wc";
|
||||||
import tseslint from "typescript-eslint";
|
import tseslint from "typescript-eslint";
|
||||||
|
|
||||||
// @ts-check
|
// @ts-check
|
||||||
@ -10,7 +11,6 @@ import tseslint from "typescript-eslint";
|
|||||||
/**
|
/**
|
||||||
* @typedef ESLintPackageConfigOptions Options for creating package ESLint configuration.
|
* @typedef ESLintPackageConfigOptions Options for creating package ESLint configuration.
|
||||||
* @property {string[]} [ignorePatterns] Override ignore patterns for ESLint.
|
* @property {string[]} [ignorePatterns] Override ignore patterns for ESLint.
|
||||||
* @property {import("typescript-eslint").ConfigWithExtends} [overrides] Additional ESLint rules
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,9 +19,17 @@ import tseslint from "typescript-eslint";
|
|||||||
export const DefaultIgnorePatterns = [
|
export const DefaultIgnorePatterns = [
|
||||||
// ---
|
// ---
|
||||||
"**/*.md",
|
"**/*.md",
|
||||||
"**/.yarn",
|
|
||||||
"**/out",
|
"**/out",
|
||||||
"**/dist",
|
"**/dist",
|
||||||
|
"**/.wireit",
|
||||||
|
"website/build/**",
|
||||||
|
"website/.docusaurus/**",
|
||||||
|
"**/node_modules",
|
||||||
|
"**/coverage",
|
||||||
|
"**/storybook-static",
|
||||||
|
"**/locale-codes.ts",
|
||||||
|
"**/src/locales",
|
||||||
|
"**/gen-ts-api",
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,24 +39,34 @@ export const DefaultIgnorePatterns = [
|
|||||||
*
|
*
|
||||||
* @returns The ESLint configuration object.
|
* @returns The ESLint configuration object.
|
||||||
*/
|
*/
|
||||||
export function createESLintPackageConfig({
|
export function createESLintPackageConfig({ ignorePatterns = DefaultIgnorePatterns } = {}) {
|
||||||
ignorePatterns = DefaultIgnorePatterns,
|
|
||||||
overrides = {},
|
|
||||||
} = {}) {
|
|
||||||
return tseslint.config(
|
return tseslint.config(
|
||||||
{
|
{
|
||||||
ignores: ignorePatterns,
|
ignores: ignorePatterns,
|
||||||
},
|
},
|
||||||
|
|
||||||
eslint.configs.recommended,
|
eslint.configs.recommended,
|
||||||
...tseslint.configs.recommended,
|
javaScriptConfig,
|
||||||
eslint.configs.recommended,
|
|
||||||
wcconf.configs["flat/recommended"],
|
wcconf.configs["flat/recommended"],
|
||||||
litconf.configs["flat/recommended"],
|
litconf.configs["flat/recommended"],
|
||||||
|
|
||||||
...reactConfig,
|
...tseslint.configs.recommended,
|
||||||
|
|
||||||
...typescriptConfig,
|
...typescriptConfig,
|
||||||
|
|
||||||
overrides,
|
...reactConfig,
|
||||||
|
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
"no-console": "off",
|
||||||
|
},
|
||||||
|
files: [
|
||||||
|
// ---
|
||||||
|
"**/scripts/**/*",
|
||||||
|
"**/test/**/*",
|
||||||
|
"**/tests/**/*",
|
||||||
|
],
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
143
packages/eslint-config/javascript-config.js
Normal file
143
packages/eslint-config/javascript-config.js
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
// @ts-check
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
|
|
||||||
|
const MAX_DEPTH = 4;
|
||||||
|
const MAX_NESTED_CALLBACKS = 4;
|
||||||
|
const MAX_PARAMS = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ESLint configuration for JavaScript authentik projects.
|
||||||
|
*/
|
||||||
|
export const javaScriptConfig = tseslint.config({
|
||||||
|
rules: {
|
||||||
|
// TODO: Clean up before enabling.
|
||||||
|
"accessor-pairs": "off",
|
||||||
|
"array-callback-return": "error",
|
||||||
|
"block-scoped-var": "error",
|
||||||
|
"consistent-return": ["error", { treatUndefinedAsUnspecified: false }],
|
||||||
|
"consistent-this": ["error", "that"],
|
||||||
|
"curly": "off",
|
||||||
|
"dot-notation": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
allowKeywords: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"eqeqeq": "error",
|
||||||
|
"func-names": ["error", "as-needed"],
|
||||||
|
"guard-for-in": "error",
|
||||||
|
"max-depth": ["error", MAX_DEPTH],
|
||||||
|
"max-nested-callbacks": ["error", MAX_NESTED_CALLBACKS],
|
||||||
|
"max-params": ["error", MAX_PARAMS],
|
||||||
|
// TODO: Clean up before enabling.
|
||||||
|
// "new-cap": "error",
|
||||||
|
"no-alert": "error",
|
||||||
|
"no-array-constructor": "error",
|
||||||
|
"no-bitwise": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
allow: ["~"],
|
||||||
|
int32Hint: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"no-caller": "error",
|
||||||
|
"no-case-declarations": "error",
|
||||||
|
"no-class-assign": "error",
|
||||||
|
"no-cond-assign": "error",
|
||||||
|
"no-const-assign": "error",
|
||||||
|
"no-constant-condition": "error",
|
||||||
|
"no-control-regex": "error",
|
||||||
|
"no-debugger": "error",
|
||||||
|
"no-delete-var": "error",
|
||||||
|
"no-div-regex": "error",
|
||||||
|
"no-dupe-args": "error",
|
||||||
|
"no-dupe-keys": "error",
|
||||||
|
"no-duplicate-case": "error",
|
||||||
|
"no-else-return": "error",
|
||||||
|
"no-empty": "error",
|
||||||
|
"no-empty-character-class": "error",
|
||||||
|
"no-empty-function": ["error", { allow: ["constructors"] }],
|
||||||
|
"no-labels": "error",
|
||||||
|
"no-eq-null": "error",
|
||||||
|
"no-eval": "error",
|
||||||
|
"no-ex-assign": "error",
|
||||||
|
"no-extend-native": "error",
|
||||||
|
"no-extra-bind": "error",
|
||||||
|
"no-extra-boolean-cast": "error",
|
||||||
|
"no-extra-label": "error",
|
||||||
|
"no-fallthrough": "error",
|
||||||
|
"no-func-assign": "error",
|
||||||
|
"no-implied-eval": "error",
|
||||||
|
"no-implicit-coercion": "error",
|
||||||
|
"no-implicit-globals": "error",
|
||||||
|
"no-inner-declarations": ["error", "functions"],
|
||||||
|
"no-invalid-regexp": "error",
|
||||||
|
"no-irregular-whitespace": "error",
|
||||||
|
"no-iterator": "error",
|
||||||
|
"no-label-var": "error",
|
||||||
|
"no-lone-blocks": "error",
|
||||||
|
"no-lonely-if": "error",
|
||||||
|
"no-loop-func": "error",
|
||||||
|
"no-multi-str": "error",
|
||||||
|
// TODO: Clean up before enabling.
|
||||||
|
"no-negated-condition": "off",
|
||||||
|
"no-new": "error",
|
||||||
|
"no-new-func": "error",
|
||||||
|
"no-new-wrappers": "error",
|
||||||
|
"no-obj-calls": "error",
|
||||||
|
"no-octal": "error",
|
||||||
|
"no-octal-escape": "error",
|
||||||
|
"no-param-reassign": ["error", { props: false }],
|
||||||
|
"no-proto": "error",
|
||||||
|
"no-redeclare": "error",
|
||||||
|
"no-regex-spaces": "error",
|
||||||
|
"no-restricted-syntax": ["error", "WithStatement"],
|
||||||
|
"no-script-url": "error",
|
||||||
|
"no-self-assign": "error",
|
||||||
|
"no-self-compare": "error",
|
||||||
|
"no-sequences": "error",
|
||||||
|
// TODO: Clean up before enabling.
|
||||||
|
// "no-shadow": "error",
|
||||||
|
"no-shadow-restricted-names": "error",
|
||||||
|
"no-sparse-arrays": "error",
|
||||||
|
"no-this-before-super": "error",
|
||||||
|
"no-throw-literal": "error",
|
||||||
|
"no-trailing-spaces": "off", // Handled by Prettier.
|
||||||
|
"no-undef": "off",
|
||||||
|
"no-undef-init": "off",
|
||||||
|
"no-unexpected-multiline": "error",
|
||||||
|
"no-useless-constructor": "error",
|
||||||
|
"no-unmodified-loop-condition": "error",
|
||||||
|
"no-unneeded-ternary": "error",
|
||||||
|
"no-unreachable": "error",
|
||||||
|
"no-unused-expressions": "error",
|
||||||
|
"no-unused-labels": "error",
|
||||||
|
"no-use-before-define": "error",
|
||||||
|
"no-useless-call": "error",
|
||||||
|
"no-dupe-class-members": "error",
|
||||||
|
"no-var": "error",
|
||||||
|
"no-void": "error",
|
||||||
|
"no-with": "error",
|
||||||
|
"prefer-arrow-callback": "error",
|
||||||
|
"prefer-const": "error",
|
||||||
|
"prefer-rest-params": "error",
|
||||||
|
"prefer-spread": "error",
|
||||||
|
"prefer-template": "error",
|
||||||
|
"radix": "error",
|
||||||
|
"require-yield": "error",
|
||||||
|
"strict": ["error", "global"],
|
||||||
|
"use-isnan": "error",
|
||||||
|
"valid-typeof": "error",
|
||||||
|
"vars-on-top": "error",
|
||||||
|
"yoda": ["error", "never"],
|
||||||
|
|
||||||
|
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
|
||||||
|
// SonarJS is not yet compatible with ESLint 9. Commenting these out
|
||||||
|
// until it is.
|
||||||
|
// "sonarjs/cognitive-complexity": ["off", MAX_COGNITIVE_COMPLEXITY],
|
||||||
|
// "sonarjs/no-duplicate-string": "off",
|
||||||
|
// "sonarjs/no-nested-template-literals": "off",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default javaScriptConfig;
|
||||||
@ -14,13 +14,15 @@
|
|||||||
"import": "./react-config.js",
|
"import": "./react-config.js",
|
||||||
"types": "./out/react-config.d.ts"
|
"types": "./out/react-config.d.ts"
|
||||||
},
|
},
|
||||||
|
"./javascript-config": {
|
||||||
|
"import": "./javascript-config.js",
|
||||||
|
"types": "./out/javascript-config.d.ts"
|
||||||
|
},
|
||||||
"./typescript-config": {
|
"./typescript-config": {
|
||||||
"import": "./typescript-config.js",
|
"import": "./typescript-config.js",
|
||||||
"types": "./out/typescript-config.d.ts"
|
"types": "./out/typescript-config.d.ts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"types": "./out/index.d.ts",
|
|
||||||
"prettier": "@goauthentik/prettier-config",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eslint": "^9.23.0",
|
"eslint": "^9.23.0",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.31.0",
|
||||||
@ -30,13 +32,12 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@goauthentik/tsconfig": "1.0.0",
|
"@goauthentik/tsconfig": "1.0.0",
|
||||||
"@types/eslint": "^9.6.1",
|
"@types/eslint": "^9.6.1",
|
||||||
"@types/eslint__js": "^9.14.0",
|
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"typescript-eslint": "^8.27.0"
|
"typescript-eslint": "^8.29.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"typescript-eslint": "^8.27.0"
|
"typescript-eslint": "^8.29.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"react": "^18.3.1"
|
"react": "^18.3.1"
|
||||||
@ -44,6 +45,8 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.11"
|
"node": ">=20.11"
|
||||||
},
|
},
|
||||||
|
"types": "./out/index.d.ts",
|
||||||
|
"prettier": "@goauthentik/prettier-config",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
}
|
}
|
||||||
|
|||||||
54
packages/eslint-config/react-config.js
vendored
54
packages/eslint-config/react-config.js
vendored
@ -1,38 +1,34 @@
|
|||||||
import reactPlugin from "eslint-plugin-react"
|
import reactPlugin from "eslint-plugin-react";
|
||||||
import hooksPlugin from "eslint-plugin-react-hooks"
|
import hooksPlugin from "eslint-plugin-react-hooks";
|
||||||
import tseslint from "typescript-eslint"
|
import tseslint from "typescript-eslint";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ESLint configuration for React authentik projects.
|
* ESLint configuration for React authentik projects.
|
||||||
*/
|
*/
|
||||||
export const reactConfig = tseslint.config(
|
export const reactConfig = tseslint.config({
|
||||||
{
|
settings: {
|
||||||
settings: {
|
react: {
|
||||||
react: {
|
version: "detect",
|
||||||
version: "detect",
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
plugins: {
|
plugins: {
|
||||||
// @ts-ignore Fixup plugin rules.
|
"react": reactPlugin,
|
||||||
react: reactPlugin,
|
"react-hooks": hooksPlugin,
|
||||||
// @ts-ignore Fixup plugin
|
},
|
||||||
"react-hooks": hooksPlugin,
|
|
||||||
},
|
|
||||||
|
|
||||||
rules: {
|
rules: {
|
||||||
"react-hooks/rules-of-hooks": "error",
|
"react-hooks/rules-of-hooks": "error",
|
||||||
"react-hooks/exhaustive-deps": "warn",
|
"react-hooks/exhaustive-deps": "warn",
|
||||||
|
|
||||||
"react/jsx-uses-react": 0,
|
"react/jsx-uses-react": 0,
|
||||||
|
|
||||||
"react/display-name": "off",
|
"react/display-name": "off",
|
||||||
"react/jsx-curly-brace-presence": "error",
|
"react/jsx-curly-brace-presence": "error",
|
||||||
"react/jsx-no-leaked-render": "error",
|
"react/jsx-no-leaked-render": "error",
|
||||||
"react/prop-types": "off",
|
"react/prop-types": "off",
|
||||||
"react/react-in-jsx-scope": "off",
|
"react/react-in-jsx-scope": "off",
|
||||||
},
|
},
|
||||||
}
|
});
|
||||||
)
|
|
||||||
|
|
||||||
export default reactConfig
|
export default reactConfig;
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"extends": "@goauthentik/tsconfig",
|
"extends": "@goauthentik/tsconfig",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"checkJs": true,
|
"baseUrl": ".",
|
||||||
"emitDeclarationOnly": true
|
"checkJs": true,
|
||||||
}
|
"emitDeclarationOnly": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,54 +7,28 @@ import tseslint from "typescript-eslint";
|
|||||||
export const typescriptConfig = tseslint.config({
|
export const typescriptConfig = tseslint.config({
|
||||||
rules: {
|
rules: {
|
||||||
"@typescript-eslint/ban-ts-comment": [
|
"@typescript-eslint/ban-ts-comment": [
|
||||||
"warn",
|
"error",
|
||||||
{
|
{
|
||||||
"ts-ignore": "allow-with-description",
|
"ts-expect-error": "allow-with-description",
|
||||||
},
|
"ts-ignore": true,
|
||||||
],
|
"ts-nocheck": "allow-with-description",
|
||||||
"@typescript-eslint/ban-types": "off",
|
"ts-check": false,
|
||||||
"@typescript-eslint/no-empty-interface": "off",
|
"minimumDescriptionLength": 5,
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"@typescript-eslint/no-extra-semi": "off",
|
|
||||||
"@typescript-eslint/no-misused-new": "off",
|
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
|
||||||
"@typescript-eslint/no-shadow": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
ignoreFunctionTypeParameterNameValueShadow: true,
|
|
||||||
ignoreTypeValueShadow: true,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
"no-use-before-define": "off",
|
||||||
|
"@typescript-eslint/no-use-before-define": "error",
|
||||||
|
"no-invalid-this": "off",
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/no-namespace": "off",
|
||||||
"@typescript-eslint/no-unused-vars": [
|
"@typescript-eslint/no-unused-vars": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
args: "all",
|
|
||||||
argsIgnorePattern: "^_",
|
argsIgnorePattern: "^_",
|
||||||
caughtErrors: "all",
|
varsIgnorePattern: "^_",
|
||||||
caughtErrorsIgnorePattern: "^_",
|
caughtErrorsIgnorePattern: "^_",
|
||||||
destructuredArrayIgnorePattern: "^_",
|
|
||||||
// Ignore all variables, since Prettier takes care of this.
|
|
||||||
varsIgnorePattern: "^\\w",
|
|
||||||
ignoreRestSiblings: true,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"@typescript-eslint/no-var-requires": "off",
|
|
||||||
|
|
||||||
"eqeqeq": ["error", "always", { null: "ignore" }],
|
|
||||||
"no-shadow": "off",
|
|
||||||
"no-extra-semi": "off",
|
|
||||||
"no-undef": "off",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"object-shorthand": [
|
|
||||||
"warn",
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
avoidQuotes: true,
|
|
||||||
ignoreConstructors: true,
|
|
||||||
avoidExplicitReturnArrows: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"prefer-const": "warn",
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2024 Authentik Security, Inc.
|
Copyright (c) 2025 Authentik Security, Inc.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
5
packages/monorepo/README.md
Normal file
5
packages/monorepo/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# `@goauthentik/monorepo`
|
||||||
|
|
||||||
|
This package contains utility scripts common to all TypeScript and JavaScript packages in the
|
||||||
|
`@goauthentik` monorepo.
|
||||||
|
|
||||||
17
packages/monorepo/constants.js
Normal file
17
packages/monorepo/constants.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* @file Constants for JavaScript and TypeScript files.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current Node.js environment, defaulting to "development" when not set.
|
||||||
|
*
|
||||||
|
* Note, this should only be used during the build process.
|
||||||
|
*
|
||||||
|
* If you need to check the environment at runtime, use `process.env.NODE_ENV` to
|
||||||
|
* ensure that module tree-shaking works correctly.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const NodeEnvironment = /** @type {'development' | 'production'} */ (
|
||||||
|
process.env.NODE_ENV || "development"
|
||||||
|
);
|
||||||
4
packages/monorepo/index.js
Normal file
4
packages/monorepo/index.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from "./paths.js";
|
||||||
|
export * from "./constants.js";
|
||||||
|
export * from "./version.js";
|
||||||
|
export * from "./scripting.js";
|
||||||
19
packages/monorepo/package.json
Normal file
19
packages/monorepo/package.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@goauthentik/monorepo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Utilities for the authentik monorepo.",
|
||||||
|
"private": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"import": "./index.js",
|
||||||
|
"types": "./out/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types": "./out/index.d.ts",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.11"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
packages/monorepo/paths.js
Normal file
30
packages/monorepo/paths.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { createRequire } from "node:module";
|
||||||
|
import { dirname, join, resolve } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {'~authentik'} MonoRepoRoot
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root of the authentik monorepo.
|
||||||
|
*/
|
||||||
|
export const MonoRepoRoot = /** @type {MonoRepoRoot} */ (resolve(__dirname, "..", ".."));
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a package name to its location in the monorepo to the single node_modules directory.
|
||||||
|
* @param {string} packageName
|
||||||
|
* @returns {string} The resolved path to the package.
|
||||||
|
* @throws {Error} If the package cannot be resolved.
|
||||||
|
*/
|
||||||
|
export function resolvePackage(packageName) {
|
||||||
|
const packageJSONPath = require.resolve(join(packageName, "package.json"), {
|
||||||
|
paths: [MonoRepoRoot],
|
||||||
|
});
|
||||||
|
|
||||||
|
return dirname(packageJSONPath);
|
||||||
|
}
|
||||||
40
packages/monorepo/scripting.js
Normal file
40
packages/monorepo/scripting.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { createRequire } from "module";
|
||||||
|
import * as path from "path";
|
||||||
|
import * as process from "process";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predicate to determine if a module was run directly, i.e. not imported.
|
||||||
|
*
|
||||||
|
* @param {ImportMeta} meta The `import.meta` object of the module.
|
||||||
|
*
|
||||||
|
* @return {boolean} Whether the module was run directly.
|
||||||
|
*/
|
||||||
|
export function isMain(meta) {
|
||||||
|
// Are we not in a module context?
|
||||||
|
if (!meta) return false;
|
||||||
|
|
||||||
|
const relativeScriptPath = process.argv[1];
|
||||||
|
|
||||||
|
if (!relativeScriptPath) return false;
|
||||||
|
|
||||||
|
const require = createRequire(meta.url);
|
||||||
|
const absoluteScriptPath = require.resolve(relativeScriptPath);
|
||||||
|
|
||||||
|
const modulePath = fileURLToPath(meta.url);
|
||||||
|
|
||||||
|
const scriptExtension = path.extname(absoluteScriptPath);
|
||||||
|
|
||||||
|
if (scriptExtension) {
|
||||||
|
return modulePath === absoluteScriptPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleExtension = path.extname(modulePath);
|
||||||
|
|
||||||
|
if (moduleExtension) {
|
||||||
|
return absoluteScriptPath === modulePath.slice(0, -moduleExtension.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both are without extension, compare them directly.
|
||||||
|
return modulePath === absoluteScriptPath;
|
||||||
|
}
|
||||||
0
packages/monorepo/scripts.js
Normal file
0
packages/monorepo/scripts.js
Normal file
9
packages/monorepo/tsconfig.json
Normal file
9
packages/monorepo/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "@goauthentik/tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"checkJs": true,
|
||||||
|
"emitDeclarationOnly": true
|
||||||
|
}
|
||||||
|
}
|
||||||
45
packages/monorepo/version.js
Normal file
45
packages/monorepo/version.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { execSync } from "node:child_process";
|
||||||
|
|
||||||
|
import PackageJSON from "../../package.json" with { type: "json" };
|
||||||
|
import { MonoRepoRoot } from "./paths.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current version of authentik in SemVer format.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const AuthentikVersion = /**@type {`${number}.${number}.${number}`} */ (PackageJSON.version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the last commit hash from the current git repository.
|
||||||
|
*/
|
||||||
|
export function readGitBuildHash() {
|
||||||
|
try {
|
||||||
|
const commit = execSync("git rev-parse HEAD", {
|
||||||
|
encoding: "utf8",
|
||||||
|
cwd: MonoRepoRoot,
|
||||||
|
})
|
||||||
|
.toString()
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
return commit;
|
||||||
|
} catch (_error) {
|
||||||
|
console.debug("Git commit could not be read.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.env.GIT_BUILD_HASH || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the build identifier for the current environment.
|
||||||
|
*
|
||||||
|
* This must match the behavior defined in authentik's server-side `get_full_version` function.
|
||||||
|
*
|
||||||
|
* @see {@link "authentik\_\_init\_\_.py"}
|
||||||
|
*/
|
||||||
|
export function readBuildIdentifier() {
|
||||||
|
const { GIT_BUILD_HASH = "d72def036820985a909266e8167ccb8087c7ce32" } = process.env;
|
||||||
|
|
||||||
|
if (!GIT_BUILD_HASH) return AuthentikVersion;
|
||||||
|
|
||||||
|
return [AuthentikVersion, GIT_BUILD_HASH].join("+");
|
||||||
|
}
|
||||||
@ -1,7 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* @file Prettier configuration for authentik.
|
||||||
|
*
|
||||||
|
* @import { Config as PrettierConfig } from "prettier";
|
||||||
|
* @import { PluginConfig as SortPluginConfig } from "@trivago/prettier-plugin-sort-imports";
|
||||||
|
*
|
||||||
|
* @typedef {object} PackageJSONPluginConfig
|
||||||
|
* @property {string[]} [packageSortOrder] Custom ordering array.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* authentik Prettier configuration.
|
* authentik Prettier configuration.
|
||||||
*
|
*
|
||||||
* @type {import("prettier").Config}
|
* @type {PrettierConfig & SortPluginConfig & PackageJSONPluginConfig}
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export const AuthentikPrettierConfig = {
|
export const AuthentikPrettierConfig = {
|
||||||
@ -27,6 +37,12 @@ export const AuthentikPrettierConfig = {
|
|||||||
importOrderSortSpecifiers: true,
|
importOrderSortSpecifiers: true,
|
||||||
importOrderParserPlugins: ["typescript", "jsx", "classProperties", "decorators-legacy"],
|
importOrderParserPlugins: ["typescript", "jsx", "classProperties", "decorators-legacy"],
|
||||||
overrides: [
|
overrides: [
|
||||||
|
{
|
||||||
|
files: "schemas/**/*.json",
|
||||||
|
options: {
|
||||||
|
tabWidth: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
files: "tsconfig.json",
|
files: "tsconfig.json",
|
||||||
options: {
|
options: {
|
||||||
@ -41,9 +57,22 @@ export const AuthentikPrettierConfig = {
|
|||||||
"name",
|
"name",
|
||||||
"version",
|
"version",
|
||||||
"description",
|
"description",
|
||||||
|
"license",
|
||||||
|
"private",
|
||||||
|
"author",
|
||||||
|
"authors",
|
||||||
"scripts",
|
"scripts",
|
||||||
"devDependencies",
|
"main",
|
||||||
|
"type",
|
||||||
|
"exports",
|
||||||
|
"imports",
|
||||||
"dependencies",
|
"dependencies",
|
||||||
|
"devDependencies",
|
||||||
|
"peerDependencies",
|
||||||
|
"optionalDependencies",
|
||||||
|
"wireit",
|
||||||
|
"resolutions",
|
||||||
|
"engines",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { format } from "prettier";
|
import { format } from "prettier";
|
||||||
|
|
||||||
import { AuthentikPrettierConfig } from "./config.js";
|
import { AuthentikPrettierConfig } from "./config.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
"name": "@goauthentik/prettier-config",
|
"name": "@goauthentik/prettier-config",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "authentik's Prettier config",
|
"description": "authentik's Prettier config",
|
||||||
"type": "module",
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
".": {
|
".": {
|
||||||
@ -13,9 +13,9 @@
|
|||||||
},
|
},
|
||||||
"types": "./out/index.d.ts",
|
"types": "./out/index.d.ts",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||||
"prettier-plugin-organize-imports": "^4.1.0",
|
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
|
"prettier-plugin-organize-imports": "^4.1.0",
|
||||||
"prettier-plugin-packagejson": "^2.5.10"
|
"prettier-plugin-packagejson": "^2.5.10"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "@goauthentik/tsconfig",
|
"extends": "@goauthentik/tsconfig",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
"emitDeclarationOnly": true
|
"emitDeclarationOnly": true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,66 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@goauthentik/web-sfe",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
|
||||||
"build": "wireit",
|
|
||||||
"lint:lockfile": "wireit",
|
|
||||||
"prettier": "prettier --write ./src ./tsconfig.json ./rollup.config.js ./package.json",
|
|
||||||
"watch": "rollup -w -c rollup.config.js --bundleConfigAsCjs"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@goauthentik/api": "^2024.6.0-1719577139",
|
|
||||||
"base64-js": "^1.5.1",
|
|
||||||
"bootstrap": "^4.6.1",
|
|
||||||
"formdata-polyfill": "^4.0.10",
|
|
||||||
"jquery": "^3.7.1",
|
|
||||||
"weakmap-polyfill": "^2.0.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@rollup/plugin-commonjs": "^28.0.0",
|
|
||||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
|
||||||
"@rollup/plugin-swc": "^0.4.0",
|
|
||||||
"@swc/cli": "^0.4.0",
|
|
||||||
"@swc/core": "^1.7.28",
|
|
||||||
"@types/jquery": "^3.5.31",
|
|
||||||
"lockfile-lint": "^4.14.0",
|
|
||||||
"rollup": "^4.23.0",
|
|
||||||
"rollup-plugin-copy": "^3.5.0",
|
|
||||||
"wireit": "^0.14.9"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@swc/core": "^1.7.28",
|
|
||||||
"@swc/core-darwin-arm64": "^1.6.13",
|
|
||||||
"@swc/core-darwin-x64": "^1.6.13",
|
|
||||||
"@swc/core-linux-arm-gnueabihf": "^1.6.13",
|
|
||||||
"@swc/core-linux-arm64-gnu": "^1.6.13",
|
|
||||||
"@swc/core-linux-arm64-musl": "^1.6.13",
|
|
||||||
"@swc/core-linux-x64-gnu": "^1.6.13",
|
|
||||||
"@swc/core-linux-x64-musl": "^1.6.13",
|
|
||||||
"@swc/core-win32-arm64-msvc": "^1.6.13",
|
|
||||||
"@swc/core-win32-ia32-msvc": "^1.6.13",
|
|
||||||
"@swc/core-win32-x64-msvc": "^1.6.13"
|
|
||||||
},
|
|
||||||
"wireit": {
|
|
||||||
"build:sfe": {
|
|
||||||
"command": "rollup -c rollup.config.js --bundleConfigAsCjs",
|
|
||||||
"files": [
|
|
||||||
"../../node_modules/bootstrap/dist/css/bootstrap.min.css",
|
|
||||||
"src/index.ts"
|
|
||||||
],
|
|
||||||
"output": [
|
|
||||||
"./dist/sfe/*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"build": {
|
|
||||||
"command": "mkdir -p ../../dist/sfe && cp -r dist/sfe/* ../../dist/sfe",
|
|
||||||
"dependencies": [
|
|
||||||
"build:sfe"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lint:lockfile": {
|
|
||||||
"command": "lockfile-lint --path package.json --type npm --allowed-hosts npm --validate-https"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
import commonjs from "@rollup/plugin-commonjs";
|
|
||||||
import resolve from "@rollup/plugin-node-resolve";
|
|
||||||
import swc from "@rollup/plugin-swc";
|
|
||||||
import copy from "rollup-plugin-copy";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
input: "src/index.ts",
|
|
||||||
output: {
|
|
||||||
dir: "./dist/sfe",
|
|
||||||
format: "cjs",
|
|
||||||
},
|
|
||||||
context: "window",
|
|
||||||
plugins: [
|
|
||||||
copy({
|
|
||||||
targets: [
|
|
||||||
{
|
|
||||||
src: "../../node_modules/bootstrap/dist/css/bootstrap.min.css",
|
|
||||||
dest: "./dist/sfe",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
resolve({ browser: true }),
|
|
||||||
commonjs(),
|
|
||||||
swc({
|
|
||||||
swc: {
|
|
||||||
jsc: {
|
|
||||||
loose: false,
|
|
||||||
externalHelpers: false,
|
|
||||||
// Requires v1.2.50 or upper and requires target to be es2016 or upper.
|
|
||||||
keepClassNames: false,
|
|
||||||
},
|
|
||||||
minify: false,
|
|
||||||
env: {
|
|
||||||
targets: {
|
|
||||||
edge: "17",
|
|
||||||
ie: "11",
|
|
||||||
},
|
|
||||||
mode: "entry",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@ -28,10 +28,7 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"description": "A label indicating the type of resource, e.g., 'User' or 'Group'.",
|
"description": "A label indicating the type of resource, e.g., 'User' or 'Group'.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["User", "Group"],
|
||||||
"User",
|
|
||||||
"Group"
|
|
||||||
],
|
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -39,7 +36,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["displayName"]
|
||||||
"displayName"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,10 +51,7 @@
|
|||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["schema", "required"],
|
||||||
"schema",
|
|
||||||
"required"
|
|
||||||
],
|
|
||||||
"additionalProperties": true
|
"additionalProperties": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -62,11 +59,6 @@
|
|||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["name", "endpoint", "schema", "schemaExtensions"],
|
||||||
"name",
|
|
||||||
"endpoint",
|
|
||||||
"schema",
|
|
||||||
"schemaExtensions"
|
|
||||||
],
|
|
||||||
"additionalProperties": true
|
"additionalProperties": true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,9 +21,7 @@
|
|||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["supported"],
|
||||||
"supported"
|
|
||||||
],
|
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
"bulk": {
|
"bulk": {
|
||||||
@ -36,9 +34,7 @@
|
|||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["supported"],
|
||||||
"supported"
|
|
||||||
],
|
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
@ -56,9 +52,7 @@
|
|||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["supported"],
|
||||||
"supported"
|
|
||||||
],
|
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
"changePassword": {
|
"changePassword": {
|
||||||
@ -71,9 +65,7 @@
|
|||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["supported"],
|
||||||
"supported"
|
|
||||||
],
|
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
"sort": {
|
"sort": {
|
||||||
@ -86,9 +78,7 @@
|
|||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["supported"],
|
||||||
"supported"
|
|
||||||
],
|
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
"authenticationSchemes": {
|
"authenticationSchemes": {
|
||||||
@ -119,21 +109,11 @@
|
|||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["name", "description"],
|
||||||
"name",
|
|
||||||
"description"
|
|
||||||
],
|
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["patch", "bulk", "filter", "changePassword", "sort", "authenticationSchemes"]
|
||||||
"patch",
|
|
||||||
"bulk",
|
|
||||||
"filter",
|
|
||||||
"changePassword",
|
|
||||||
"sort",
|
|
||||||
"authenticationSchemes"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,11 +99,7 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"description": "A label indicating the attribute's function, e.g., 'work' or 'home'.",
|
"description": "A label indicating the attribute's function, e.g., 'work' or 'home'.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["work", "home", "other"]
|
||||||
"work",
|
|
||||||
"home",
|
|
||||||
"other"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"primary": {
|
"primary": {
|
||||||
"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred mailing address or primary email address. The primary attribute value 'true' MUST appear no more than once.",
|
"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred mailing address or primary email address. The primary attribute value 'true' MUST appear no more than once.",
|
||||||
@ -129,14 +125,7 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"description": "A label indicating the attribute's function, e.g., 'work', 'home', 'mobile'.",
|
"description": "A label indicating the attribute's function, e.g., 'work', 'home', 'mobile'.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["work", "home", "mobile", "fax", "pager", "other"]
|
||||||
"work",
|
|
||||||
"home",
|
|
||||||
"mobile",
|
|
||||||
"fax",
|
|
||||||
"pager",
|
|
||||||
"other"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"primary": {
|
"primary": {
|
||||||
"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred phone number or primary phone number. The primary attribute value 'true' MUST appear no more than once.",
|
"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred phone number or primary phone number. The primary attribute value 'true' MUST appear no more than once.",
|
||||||
@ -162,16 +151,7 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"description": "A label indicating the attribute's function, e.g., 'aim', 'gtalk', 'xmpp'.",
|
"description": "A label indicating the attribute's function, e.g., 'aim', 'gtalk', 'xmpp'.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["aim", "gtalk", "icq", "xmpp", "msn", "skype", "qq", "yahoo"]
|
||||||
"aim",
|
|
||||||
"gtalk",
|
|
||||||
"icq",
|
|
||||||
"xmpp",
|
|
||||||
"msn",
|
|
||||||
"skype",
|
|
||||||
"qq",
|
|
||||||
"yahoo"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"primary": {
|
"primary": {
|
||||||
"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred messenger or primary messenger. The primary attribute value 'true' MUST appear no more than once.",
|
"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred messenger or primary messenger. The primary attribute value 'true' MUST appear no more than once.",
|
||||||
@ -198,10 +178,7 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"description": "A label indicating the attribute's function, i.e., 'photo' or 'thumbnail'.",
|
"description": "A label indicating the attribute's function, i.e., 'photo' or 'thumbnail'.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["photo", "thumbnail"]
|
||||||
"photo",
|
|
||||||
"thumbnail"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"primary": {
|
"primary": {
|
||||||
"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred photo or thumbnail. The primary attribute value 'true' MUST appear no more than once.",
|
"description": "A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred photo or thumbnail. The primary attribute value 'true' MUST appear no more than once.",
|
||||||
@ -243,11 +220,7 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"description": "A label indicating the attribute's function, e.g., 'work' or 'home'.",
|
"description": "A label indicating the attribute's function, e.g., 'work' or 'home'.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["work", "home", "other"]
|
||||||
"work",
|
|
||||||
"home",
|
|
||||||
"other"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,10 +250,7 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"description": "A label indicating the attribute's function, e.g., 'direct' or 'indirect'.",
|
"description": "A label indicating the attribute's function, e.g., 'direct' or 'indirect'.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["direct", "indirect"],
|
||||||
"direct",
|
|
||||||
"indirect"
|
|
||||||
],
|
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -366,7 +336,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["userName"]
|
||||||
"userName"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,9 +19,8 @@
|
|||||||
"files": [],
|
"files": [],
|
||||||
"references": [
|
"references": [
|
||||||
// Note that references are in the order we want them to be built.
|
// Note that references are in the order we want them to be built.
|
||||||
{ "path": "./packages/tsconfig" },
|
|
||||||
{ "path": "./packages/prettier-config" },
|
{ "path": "./packages/prettier-config" },
|
||||||
{ "path": "./packages/eslint-config" },
|
{ "path": "./packages/eslint-config" },
|
||||||
{ "path": "./packages/sfe" }
|
{ "path": "./web" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
# don't ever lint node_modules
|
|
||||||
node_modules
|
|
||||||
# don't lint build output (make sure it's set to your correct build folder name)
|
|
||||||
dist
|
|
||||||
# don't lint nyc coverage output
|
|
||||||
coverage
|
|
||||||
# Import order matters
|
|
||||||
poly.ts
|
|
||||||
src/locale-codes.ts
|
|
||||||
src/locales/
|
|
||||||
storybook-static/
|
|
||||||
# Prettier breaks the tsconfig file
|
|
||||||
tsconfig.json
|
|
||||||
.storybook/css-import-maps*
|
|
||||||
package.json
|
|
||||||
packages/**/package.json
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"arrowParens": "always",
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"embeddedLanguageFormatting": "auto",
|
|
||||||
"htmlWhitespaceSensitivity": "css",
|
|
||||||
"insertPragma": false,
|
|
||||||
"jsxSingleQuote": false,
|
|
||||||
"printWidth": 100,
|
|
||||||
"proseWrap": "preserve",
|
|
||||||
"quoteProps": "consistent",
|
|
||||||
"requirePragma": false,
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": false,
|
|
||||||
"tabWidth": 4,
|
|
||||||
"trailingComma": "all",
|
|
||||||
"useTabs": false,
|
|
||||||
"vueIndentScriptAndStyle": false,
|
|
||||||
"plugins": ["@trivago/prettier-plugin-sort-imports"],
|
|
||||||
"importOrder": ["^(@?)lit(.*)$", "\\.css$", "^@goauthentik/api$", "^[./]"],
|
|
||||||
"importOrderSeparation": true,
|
|
||||||
"importOrderSortSpecifiers": true,
|
|
||||||
"importOrderParserPlugins": ["typescript", "jsx", "classProperties", "decorators-legacy"]
|
|
||||||
}
|
|
||||||
@ -1,13 +1,16 @@
|
|||||||
import replace from "@rollup/plugin-replace";
|
|
||||||
import type { StorybookConfig } from "@storybook/web-components-vite";
|
import type { StorybookConfig } from "@storybook/web-components-vite";
|
||||||
import { cwd } from "process";
|
import { cwd } from "node:process";
|
||||||
import modify from "rollup-plugin-modify";
|
import modify from "rollup-plugin-modify";
|
||||||
import postcssLit from "rollup-plugin-postcss-lit";
|
import postcssLit from "rollup-plugin-postcss-lit";
|
||||||
|
import { mergeConfig } from "vite";
|
||||||
import tsconfigPaths from "vite-tsconfig-paths";
|
import tsconfigPaths from "vite-tsconfig-paths";
|
||||||
|
|
||||||
export const isProdBuild = process.env.NODE_ENV === "production";
|
export const isProdBuild = process.env.NODE_ENV === "production";
|
||||||
export const apiBasePath = process.env.AK_API_BASE_PATH || "";
|
export const apiBasePath = process.env.AK_API_BASE_PATH || "";
|
||||||
|
|
||||||
|
const NODE_ENV = process.env.NODE_ENV || "development";
|
||||||
|
const AK_API_BASE_PATH = process.env.AK_API_BASE_PATH || "";
|
||||||
|
|
||||||
const importInlinePatterns = [
|
const importInlinePatterns = [
|
||||||
'import AKGlobal from "(\\.\\./)*common/styles/authentik\\.css',
|
'import AKGlobal from "(\\.\\./)*common/styles/authentik\\.css',
|
||||||
'import AKGlobal from "@goauthentik/common/styles/authentik\\.css',
|
'import AKGlobal from "@goauthentik/common/styles/authentik\\.css',
|
||||||
@ -53,8 +56,14 @@ const config: StorybookConfig = {
|
|||||||
autodocs: "tag",
|
autodocs: "tag",
|
||||||
},
|
},
|
||||||
async viteFinal(config) {
|
async viteFinal(config) {
|
||||||
return {
|
return mergeConfig(config, {
|
||||||
...config,
|
define: {
|
||||||
|
"process.env.NODE_ENV": JSON.stringify(NODE_ENV),
|
||||||
|
"process.env.CWD": JSON.stringify(cwd()),
|
||||||
|
"process.env.AK_API_BASE_PATH": JSON.stringify(AK_API_BASE_PATH),
|
||||||
|
"process.env.WATCHER_URL": "",
|
||||||
|
},
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
modify({
|
modify({
|
||||||
find: importInlineRegexp,
|
find: importInlineRegexp,
|
||||||
@ -62,19 +71,10 @@ const config: StorybookConfig = {
|
|||||||
return `${match}?inline`;
|
return `${match}?inline`;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
replace({
|
|
||||||
"process.env.NODE_ENV": JSON.stringify(
|
|
||||||
isProdBuild ? "production" : "development",
|
|
||||||
),
|
|
||||||
"process.env.CWD": JSON.stringify(cwd()),
|
|
||||||
"process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath),
|
|
||||||
"preventAssignment": true,
|
|
||||||
}),
|
|
||||||
...config.plugins,
|
|
||||||
postcssLit(),
|
postcssLit(),
|
||||||
tsconfigPaths(),
|
tsconfigPaths(),
|
||||||
],
|
],
|
||||||
};
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,90 +0,0 @@
|
|||||||
import eslint from "@eslint/js";
|
|
||||||
import tsparser from "@typescript-eslint/parser";
|
|
||||||
import litconf from "eslint-plugin-lit";
|
|
||||||
import wcconf from "eslint-plugin-wc";
|
|
||||||
import globals from "globals";
|
|
||||||
import tseslint from "typescript-eslint";
|
|
||||||
|
|
||||||
export default [
|
|
||||||
// You would not believe how much this change has frustrated users: ["if an ignores key is used
|
|
||||||
// without any other keys in the configuration object, then the patterns act as global
|
|
||||||
// ignores"](https://eslint.org/docs/latest/use/configure/ignore)
|
|
||||||
{
|
|
||||||
ignores: [
|
|
||||||
"dist/",
|
|
||||||
// don't lint the cache
|
|
||||||
".wireit/",
|
|
||||||
// let packages have their own configurations
|
|
||||||
"packages/",
|
|
||||||
// don't ever lint node_modules
|
|
||||||
"node_modules/",
|
|
||||||
".storybook/*",
|
|
||||||
// don't lint build output (make sure it's set to your correct build folder name)
|
|
||||||
// don't lint nyc coverage output
|
|
||||||
"coverage/",
|
|
||||||
"src/locale-codes.ts",
|
|
||||||
"storybook-static/",
|
|
||||||
"src/locales/",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
eslint.configs.recommended,
|
|
||||||
wcconf.configs["flat/recommended"],
|
|
||||||
litconf.configs["flat/recommended"],
|
|
||||||
...tseslint.configs.recommended,
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsparser,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 12,
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
files: ["src/**"],
|
|
||||||
rules: {
|
|
||||||
"lit/attribute-names": "off",
|
|
||||||
// "lit/attribute-names": "error",
|
|
||||||
"lit/no-private-properties": "error",
|
|
||||||
// "lit/prefer-nothing": "warn",
|
|
||||||
"lit/no-template-bind": "error",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
|
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
argsIgnorePattern: "^_",
|
|
||||||
varsIgnorePattern: "^_",
|
|
||||||
caughtErrorsIgnorePattern: "^_",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsparser,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 12,
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
...globals.nodeBuiltin,
|
|
||||||
...globals.node,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
files: ["scripts/**/*.mjs", "*.ts", "*.mjs"],
|
|
||||||
rules: {
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
// We WANT our scripts to output to the console!
|
|
||||||
"no-console": "off",
|
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
argsIgnorePattern: "^_",
|
|
||||||
varsIgnorePattern: "^_",
|
|
||||||
caughtErrorsIgnorePattern: "^_",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
272
web/package.json
272
web/package.json
@ -1,138 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/web",
|
"name": "@goauthentik/web",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
|
||||||
"@codemirror/lang-html": "^6.4.9",
|
|
||||||
"@codemirror/lang-javascript": "^6.2.2",
|
|
||||||
"@codemirror/lang-python": "^6.1.6",
|
|
||||||
"@codemirror/lang-xml": "^6.1.0",
|
|
||||||
"@codemirror/legacy-modes": "^6.4.1",
|
|
||||||
"@codemirror/theme-one-dark": "^6.1.2",
|
|
||||||
"@floating-ui/dom": "^1.6.11",
|
|
||||||
"@formatjs/intl-listformat": "^7.5.7",
|
|
||||||
"@fortawesome/fontawesome-free": "^6.6.0",
|
|
||||||
"@goauthentik/api": "^2025.2.2-1742585853",
|
|
||||||
"@lit-labs/ssr": "^3.2.2",
|
|
||||||
"@lit/context": "^1.1.2",
|
|
||||||
"@lit/localize": "^0.12.2",
|
|
||||||
"@lit/reactive-element": "^2.0.4",
|
|
||||||
"@lit/task": "^1.0.1",
|
|
||||||
"@mdx-js/mdx": "^3.1.0",
|
|
||||||
"@open-wc/lit-helpers": "^0.7.0",
|
|
||||||
"@patternfly/elements": "^4.0.2",
|
|
||||||
"@patternfly/patternfly": "^4.224.2",
|
|
||||||
"@sentry/browser": "^8.32.0",
|
|
||||||
"@spotlightjs/spotlight": "^2.4.2",
|
|
||||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
|
||||||
"base64-js": "^1.5.1",
|
|
||||||
"change-case": "^5.4.4",
|
|
||||||
"chart.js": "^4.4.4",
|
|
||||||
"chartjs-adapter-date-fns": "^3.0.0",
|
|
||||||
"codemirror": "^6.0.1",
|
|
||||||
"construct-style-sheets-polyfill": "^3.1.0",
|
|
||||||
"core-js": "^3.38.1",
|
|
||||||
"country-flag-icons": "^1.5.13",
|
|
||||||
"date-fns": "^4.1.0",
|
|
||||||
"deepmerge-ts": "^7.1.5",
|
|
||||||
"dompurify": "^3.2.4",
|
|
||||||
"fuse.js": "^7.0.0",
|
|
||||||
"guacamole-common-js": "^1.5.0",
|
|
||||||
"hastscript": "^9.0.1",
|
|
||||||
"lit": "^3.2.0",
|
|
||||||
"md-front-matter": "^1.0.4",
|
|
||||||
"mermaid": "^11.4.1",
|
|
||||||
"rapidoc": "^9.3.7",
|
|
||||||
"react": "^18.3.1",
|
|
||||||
"react-dom": "^18.3.1",
|
|
||||||
"rehype-highlight": "^7.0.2",
|
|
||||||
"rehype-mermaid": "^3.0.0",
|
|
||||||
"rehype-parse": "^9.0.1",
|
|
||||||
"rehype-stringify": "^10.0.1",
|
|
||||||
"remark-directive": "^4.0.0",
|
|
||||||
"remark-frontmatter": "^5.0.0",
|
|
||||||
"remark-gfm": "^4.0.1",
|
|
||||||
"remark-mdx-frontmatter": "^5.0.0",
|
|
||||||
"style-mod": "^4.1.2",
|
|
||||||
"ts-pattern": "^5.4.0",
|
|
||||||
"unist-util-visit": "^5.0.0",
|
|
||||||
"webcomponent-qr-code": "^1.2.0",
|
|
||||||
"yaml": "^2.5.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@eslint/js": "^9.11.1",
|
|
||||||
"@hcaptcha/types": "^1.0.4",
|
|
||||||
"@lit/localize-tools": "^0.8.0",
|
|
||||||
"@rollup/plugin-replace": "^6.0.1",
|
|
||||||
"@storybook/addon-essentials": "^8.3.4",
|
|
||||||
"@storybook/addon-links": "^8.3.4",
|
|
||||||
"@storybook/api": "^7.6.17",
|
|
||||||
"@storybook/blocks": "^8.3.4",
|
|
||||||
"@storybook/builder-vite": "^8.3.4",
|
|
||||||
"@storybook/manager-api": "^8.3.4",
|
|
||||||
"@storybook/web-components": "^8.3.4",
|
|
||||||
"@storybook/web-components-vite": "^8.3.4",
|
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
|
||||||
"@types/chart.js": "^2.9.41",
|
|
||||||
"@types/codemirror": "^5.60.15",
|
|
||||||
"@types/dompurify": "^3.0.5",
|
|
||||||
"@types/eslint__js": "^8.42.3",
|
|
||||||
"@types/grecaptcha": "^3.0.9",
|
|
||||||
"@types/guacamole-common-js": "^1.5.2",
|
|
||||||
"@types/mocha": "^10.0.8",
|
|
||||||
"@types/node": "^22.7.4",
|
|
||||||
"@types/react": "^18.3.13",
|
|
||||||
"@types/react-dom": "^18.3.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
|
||||||
"@typescript-eslint/parser": "^8.8.0",
|
|
||||||
"@wdio/browser-runner": "9.4",
|
|
||||||
"@wdio/cli": "9.4",
|
|
||||||
"@wdio/spec-reporter": "^9.1.2",
|
|
||||||
"chromedriver": "^131.0.1",
|
|
||||||
"esbuild": "^0.25.0",
|
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
|
||||||
"esbuild-plugins-node-modules-polyfill": "^1.7.0",
|
|
||||||
"eslint": "^9.11.1",
|
|
||||||
"eslint-plugin-lit": "^1.15.0",
|
|
||||||
"eslint-plugin-wc": "^2.1.1",
|
|
||||||
"find-free-ports": "^3.1.1",
|
|
||||||
"github-slugger": "^2.0.0",
|
|
||||||
"glob": "^11.0.0",
|
|
||||||
"globals": "^15.10.0",
|
|
||||||
"knip": "^5.30.6",
|
|
||||||
"lit-analyzer": "^2.0.3",
|
|
||||||
"npm-run-all": "^4.1.5",
|
|
||||||
"prettier": "^3.3.3",
|
|
||||||
"pseudolocale": "^2.1.0",
|
|
||||||
"rollup-plugin-modify": "^3.0.0",
|
|
||||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
|
||||||
"storybook": "^8.3.4",
|
|
||||||
"storybook-addon-mock": "^5.0.0",
|
|
||||||
"syncpack": "^13.0.0",
|
|
||||||
"turnstile-types": "^1.2.3",
|
|
||||||
"typescript": "^5.6.2",
|
|
||||||
"typescript-eslint": "^8.8.0",
|
|
||||||
"vite-plugin-lit-css": "^2.0.0",
|
|
||||||
"vite-tsconfig-paths": "^5.0.1",
|
|
||||||
"wireit": "^0.14.9"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@esbuild/darwin-arm64": "^0.24.0",
|
|
||||||
"@esbuild/linux-amd64": "^0.18.11",
|
|
||||||
"@esbuild/linux-arm64": "^0.24.0",
|
|
||||||
"@rollup/rollup-darwin-arm64": "4.23.0",
|
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.23.0",
|
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.23.0"
|
|
||||||
},
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "wireit",
|
"build": "wireit",
|
||||||
"build-locales": "wireit",
|
"build-locales": "wireit",
|
||||||
"build-locales:build": "wireit",
|
|
||||||
"build-proxy": "wireit",
|
"build-proxy": "wireit",
|
||||||
"build:sfe": "wireit",
|
"build:sfe": "wireit",
|
||||||
"esbuild:watch": "node scripts/build-web.mjs --watch",
|
"esbuild:watch": "node scripts/build-web.mjs --watch",
|
||||||
@ -160,7 +31,138 @@
|
|||||||
"tsc": "wireit",
|
"tsc": "wireit",
|
||||||
"watch": "run-s build-locales esbuild:watch"
|
"watch": "run-s build-locales esbuild:watch"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@goauthentik/monorepo": "1.0.0",
|
||||||
|
"@hcaptcha/types": "^1.0.4",
|
||||||
|
"@lit/localize-tools": "^0.8.0",
|
||||||
|
"@rollup/plugin-replace": "^6.0.1",
|
||||||
|
"@storybook/addon-essentials": "^8.3.4",
|
||||||
|
"@storybook/addon-links": "^8.3.4",
|
||||||
|
"@storybook/api": "^7.6.17",
|
||||||
|
"@storybook/blocks": "^8.3.4",
|
||||||
|
"@storybook/builder-vite": "^8.3.4",
|
||||||
|
"@storybook/manager-api": "^8.3.4",
|
||||||
|
"@storybook/web-components": "^8.3.4",
|
||||||
|
"@storybook/web-components-vite": "^8.3.4",
|
||||||
|
"@swc/helpers": "^0.5.15",
|
||||||
|
"@types/chart.js": "^2.9.41",
|
||||||
|
"@types/codemirror": "^5.60.15",
|
||||||
|
"@types/dompurify": "^3.0.5",
|
||||||
|
"@types/grecaptcha": "^3.0.9",
|
||||||
|
"@types/guacamole-common-js": "^1.5.2",
|
||||||
|
"@types/mocha": "^10.0.8",
|
||||||
|
"@types/node": "^22.7.4",
|
||||||
|
"@types/react": "^18.3.13",
|
||||||
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"@wdio/browser-runner": "9.12.1",
|
||||||
|
"@wdio/cli": "9.12.1",
|
||||||
|
"@wdio/spec-reporter": "^9.11.0",
|
||||||
|
"chromedriver": "^134.0.5",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
|
"esbuild-plugin-copy": "^2.1.1",
|
||||||
|
"esbuild-plugin-es5": "^2.1.1",
|
||||||
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
|
"esbuild-plugins-node-modules-polyfill": "^1.7.0",
|
||||||
|
"find-free-ports": "^3.1.1",
|
||||||
|
"github-slugger": "^2.0.0",
|
||||||
|
"glob": "^11.0.0",
|
||||||
|
"globals": "^15.10.0",
|
||||||
|
"knip": "^5.30.6",
|
||||||
|
"lit-analyzer": "^2.0.3",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"pseudolocale": "^2.1.0",
|
||||||
|
"rollup-plugin-modify": "^3.0.0",
|
||||||
|
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||||
|
"storybook": "^8.3.4",
|
||||||
|
"storybook-addon-mock": "^5.0.0",
|
||||||
|
"syncpack": "^13.0.0",
|
||||||
|
"turnstile-types": "^1.2.3",
|
||||||
|
"vite-plugin-lit-css": "^2.0.0",
|
||||||
|
"vite-tsconfig-paths": "^5.0.1",
|
||||||
|
"wireit": "^0.14.9",
|
||||||
|
"zx": "^8.4.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
|
"@codemirror/lang-html": "^6.4.9",
|
||||||
|
"@codemirror/lang-javascript": "^6.2.2",
|
||||||
|
"@codemirror/lang-python": "^6.1.6",
|
||||||
|
"@codemirror/lang-xml": "^6.1.0",
|
||||||
|
"@codemirror/legacy-modes": "^6.4.1",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
|
"@floating-ui/dom": "^1.6.11",
|
||||||
|
"@formatjs/intl-listformat": "^7.5.7",
|
||||||
|
"@fortawesome/fontawesome-free": "^6.6.0",
|
||||||
|
"@goauthentik/api": "^2025.2.2-1742585853",
|
||||||
|
"@lit-labs/ssr": "^3.2.2",
|
||||||
|
"@lit/context": "^1.1.2",
|
||||||
|
"@lit/localize": "^0.12.2",
|
||||||
|
"@lit/reactive-element": "^2.0.4",
|
||||||
|
"@lit/task": "^1.0.1",
|
||||||
|
"@mdx-js/mdx": "^3.1.0",
|
||||||
|
"@open-wc/lit-helpers": "^0.7.0",
|
||||||
|
"@patternfly/elements": "^4.0.2",
|
||||||
|
"@patternfly/patternfly": "^4.224.2",
|
||||||
|
"@sentry/browser": "^8.32.0",
|
||||||
|
"@spotlightjs/spotlight": "^2.4.2",
|
||||||
|
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||||
|
"base64-js": "^1.5.1",
|
||||||
|
"bootstrap": "^4.6.1",
|
||||||
|
"change-case": "^5.4.4",
|
||||||
|
"chart.js": "^4.4.4",
|
||||||
|
"chartjs-adapter-date-fns": "^3.0.0",
|
||||||
|
"codemirror": "^6.0.1",
|
||||||
|
"construct-style-sheets-polyfill": "^3.1.0",
|
||||||
|
"core-js": "^3.38.1",
|
||||||
|
"country-flag-icons": "^1.5.13",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
|
"deepmerge-ts": "^7.1.5",
|
||||||
|
"dompurify": "^3.2.4",
|
||||||
|
"formdata-polyfill": "^4.0.10",
|
||||||
|
"fuse.js": "^7.0.0",
|
||||||
|
"guacamole-common-js": "^1.5.0",
|
||||||
|
"hastscript": "^9.0.1",
|
||||||
|
"jquery": "^3.7.1",
|
||||||
|
"lit": "^3.2.0",
|
||||||
|
"md-front-matter": "^1.0.4",
|
||||||
|
"mermaid": "^11.4.1",
|
||||||
|
"rapidoc": "^9.3.7",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"rehype-highlight": "^7.0.2",
|
||||||
|
"rehype-mermaid": "^3.0.0",
|
||||||
|
"rehype-parse": "^9.0.1",
|
||||||
|
"rehype-stringify": "^10.0.1",
|
||||||
|
"remark-directive": "^4.0.0",
|
||||||
|
"remark-frontmatter": "^5.0.0",
|
||||||
|
"remark-gfm": "^4.0.1",
|
||||||
|
"remark-mdx-frontmatter": "^5.0.0",
|
||||||
|
"style-mod": "^4.1.2",
|
||||||
|
"ts-pattern": "^5.4.0",
|
||||||
|
"unist-util-visit": "^5.0.0",
|
||||||
|
"weakmap-polyfill": "^2.0.4",
|
||||||
|
"webcomponent-qr-code": "^1.2.0",
|
||||||
|
"yaml": "^2.5.1"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
"./paths": "./paths.js",
|
||||||
|
"./scripts/*": "./scripts/*.mjs"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/darwin-arm64": "^0.24.0",
|
||||||
|
"@esbuild/linux-amd64": "^0.18.11",
|
||||||
|
"@esbuild/linux-arm64": "^0.24.0",
|
||||||
|
"@rollup/rollup-darwin-arm64": "4.23.0",
|
||||||
|
"@rollup/rollup-linux-arm64-gnu": "4.23.0",
|
||||||
|
"@rollup/rollup-linux-x64-gnu": "4.23.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
"wireit": {
|
"wireit": {
|
||||||
"build": {
|
"build": {
|
||||||
"#comment": [
|
"#comment": [
|
||||||
@ -217,12 +219,6 @@
|
|||||||
"build-locales"
|
"build-locales"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"build-locales:build": {
|
|
||||||
"command": "lit-localize build"
|
|
||||||
},
|
|
||||||
"build-locales:repair": {
|
|
||||||
"command": "prettier --write ./src/locale-codes.ts"
|
|
||||||
},
|
|
||||||
"build-locales": {
|
"build-locales": {
|
||||||
"command": "node scripts/build-locales.mjs",
|
"command": "node scripts/build-locales.mjs",
|
||||||
"files": [
|
"files": [
|
||||||
@ -376,9 +372,5 @@
|
|||||||
"lint:types"
|
"lint:types"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"workspaces": [
|
|
||||||
".",
|
|
||||||
"./packages/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* @file Simple Flow Executor entry point.
|
||||||
|
*/
|
||||||
import { fromByteArray } from "base64-js";
|
import { fromByteArray } from "base64-js";
|
||||||
import "formdata-polyfill";
|
import "formdata-polyfill";
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
@ -33,82 +36,6 @@ function ak(): GlobalAuthentik {
|
|||||||
).authentik;
|
).authentik;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimpleFlowExecutor {
|
|
||||||
challenge?: ChallengeTypes;
|
|
||||||
flowSlug: string;
|
|
||||||
container: HTMLDivElement;
|
|
||||||
|
|
||||||
constructor(container: HTMLDivElement) {
|
|
||||||
this.flowSlug = window.location.pathname.split("/")[3];
|
|
||||||
this.container = container;
|
|
||||||
}
|
|
||||||
|
|
||||||
get apiURL() {
|
|
||||||
return `${ak().api.base}api/v3/flows/executor/${this.flowSlug}/?query=${encodeURIComponent(window.location.search.substring(1))}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
$.ajax({
|
|
||||||
type: "GET",
|
|
||||||
url: this.apiURL,
|
|
||||||
success: (data) => {
|
|
||||||
this.challenge = ChallengeTypesFromJSON(data);
|
|
||||||
this.renderChallenge();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submit(data: { [key: string]: unknown } | FormData) {
|
|
||||||
$("button[type=submit]").addClass("disabled")
|
|
||||||
.html(`<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
|
|
||||||
<span role="status">Loading...</span>`);
|
|
||||||
let finalData: { [key: string]: unknown } = {};
|
|
||||||
if (data instanceof FormData) {
|
|
||||||
finalData = {};
|
|
||||||
data.forEach((value, key) => {
|
|
||||||
finalData[key] = value;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
finalData = data;
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: this.apiURL,
|
|
||||||
data: JSON.stringify(finalData),
|
|
||||||
success: (data) => {
|
|
||||||
this.challenge = ChallengeTypesFromJSON(data);
|
|
||||||
this.renderChallenge();
|
|
||||||
},
|
|
||||||
contentType: "application/json",
|
|
||||||
dataType: "json",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
renderChallenge() {
|
|
||||||
switch (this.challenge?.component) {
|
|
||||||
case "ak-stage-identification":
|
|
||||||
new IdentificationStage(this, this.challenge).render();
|
|
||||||
return;
|
|
||||||
case "ak-stage-password":
|
|
||||||
new PasswordStage(this, this.challenge).render();
|
|
||||||
return;
|
|
||||||
case "xak-flow-redirect":
|
|
||||||
new RedirectStage(this, this.challenge).render();
|
|
||||||
return;
|
|
||||||
case "ak-stage-autosubmit":
|
|
||||||
new AutosubmitStage(this, this.challenge).render();
|
|
||||||
return;
|
|
||||||
case "ak-stage-authenticator-validate":
|
|
||||||
new AuthenticatorValidateStage(this, this.challenge).render();
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
this.container.innerText =
|
|
||||||
"Unsupported stage: " + this.challenge?.component;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlowInfoChallenge {
|
export interface FlowInfoChallenge {
|
||||||
flowInfo?: ContextualFlowInfo;
|
flowInfo?: ContextualFlowInfo;
|
||||||
responseErrors?: {
|
responseErrors?: {
|
||||||
@ -271,13 +198,10 @@ export interface AuthAssertion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge> {
|
class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge> {
|
||||||
deviceChallenge?: DeviceChallenge;
|
declare deviceChallenge?: DeviceChallenge;
|
||||||
|
|
||||||
b64enc(buf: Uint8Array): string {
|
b64enc(buf: Uint8Array): string {
|
||||||
return fromByteArray(buf)
|
return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]/g, "");
|
||||||
.replace(/\+/g, "-")
|
|
||||||
.replace(/\//g, "_")
|
|
||||||
.replace(/=/g, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b64RawEnc(buf: Uint8Array): string {
|
b64RawEnc(buf: Uint8Array): string {
|
||||||
@ -285,9 +209,8 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
}
|
}
|
||||||
|
|
||||||
u8arr(input: string): Uint8Array {
|
u8arr(input: string): Uint8Array {
|
||||||
return Uint8Array.from(
|
return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
|
||||||
atob(input.replace(/_/g, "/").replace(/-/g, "+")),
|
c.charCodeAt(0),
|
||||||
(c) => c.charCodeAt(0),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,13 +218,8 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
if ("credentials" in navigator) {
|
if ("credentials" in navigator) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (
|
if (window.location.protocol === "http:" && window.location.hostname !== "localhost") {
|
||||||
window.location.protocol === "http:" &&
|
console.warn("WebAuthn requires this page to be accessed via HTTPS.");
|
||||||
window.location.hostname !== "localhost"
|
|
||||||
) {
|
|
||||||
console.warn(
|
|
||||||
"WebAuthn requires this page to be accessed via HTTPS.",
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
console.warn("WebAuthn not supported by browser.");
|
console.warn("WebAuthn not supported by browser.");
|
||||||
@ -322,9 +240,7 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
// string, then a byte array, re-encode it and wrap that in an array.
|
// string, then a byte array, re-encode it and wrap that in an array.
|
||||||
const stringId = decodeURIComponent(window.atob(userId));
|
const stringId = decodeURIComponent(window.atob(userId));
|
||||||
user.id = this.u8arr(this.b64enc(this.u8arr(stringId)));
|
user.id = this.u8arr(this.b64enc(this.u8arr(stringId)));
|
||||||
const challenge = this.u8arr(
|
const challenge = this.u8arr(credentialCreateOptions.challenge.toString());
|
||||||
credentialCreateOptions.challenge.toString(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Object.assign({}, credentialCreateOptions, {
|
return Object.assign({}, credentialCreateOptions, {
|
||||||
challenge,
|
challenge,
|
||||||
@ -337,28 +253,19 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
* for posting to the server.
|
* for posting to the server.
|
||||||
* @param {PublicKeyCredential} newAssertion
|
* @param {PublicKeyCredential} newAssertion
|
||||||
*/
|
*/
|
||||||
transformNewAssertionForServer(
|
transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion {
|
||||||
newAssertion: PublicKeyCredential,
|
|
||||||
): Assertion {
|
|
||||||
const attObj = new Uint8Array(
|
const attObj = new Uint8Array(
|
||||||
(
|
(newAssertion.response as AuthenticatorAttestationResponse).attestationObject,
|
||||||
newAssertion.response as AuthenticatorAttestationResponse
|
|
||||||
).attestationObject,
|
|
||||||
);
|
|
||||||
const clientDataJSON = new Uint8Array(
|
|
||||||
newAssertion.response.clientDataJSON,
|
|
||||||
);
|
);
|
||||||
|
const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON);
|
||||||
const rawId = new Uint8Array(newAssertion.rawId);
|
const rawId = new Uint8Array(newAssertion.rawId);
|
||||||
|
|
||||||
const registrationClientExtensions =
|
const registrationClientExtensions = newAssertion.getClientExtensionResults();
|
||||||
newAssertion.getClientExtensionResults();
|
|
||||||
return {
|
return {
|
||||||
id: newAssertion.id,
|
id: newAssertion.id,
|
||||||
rawId: this.b64enc(rawId),
|
rawId: this.b64enc(rawId),
|
||||||
type: newAssertion.type,
|
type: newAssertion.type,
|
||||||
registrationClientExtensions: JSON.stringify(
|
registrationClientExtensions: JSON.stringify(registrationClientExtensions),
|
||||||
registrationClientExtensions,
|
|
||||||
),
|
|
||||||
response: {
|
response: {
|
||||||
clientDataJSON: this.b64enc(clientDataJSON),
|
clientDataJSON: this.b64enc(clientDataJSON),
|
||||||
attestationObject: this.b64enc(attObj),
|
attestationObject: this.b64enc(attObj),
|
||||||
@ -369,16 +276,14 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
transformCredentialRequestOptions(
|
transformCredentialRequestOptions(
|
||||||
credentialRequestOptions: PublicKeyCredentialRequestOptions,
|
credentialRequestOptions: PublicKeyCredentialRequestOptions,
|
||||||
): PublicKeyCredentialRequestOptions {
|
): PublicKeyCredentialRequestOptions {
|
||||||
const challenge = this.u8arr(
|
const challenge = this.u8arr(credentialRequestOptions.challenge.toString());
|
||||||
credentialRequestOptions.challenge.toString(),
|
|
||||||
);
|
|
||||||
|
|
||||||
const allowCredentials = (
|
const allowCredentials = (credentialRequestOptions.allowCredentials || []).map(
|
||||||
credentialRequestOptions.allowCredentials || []
|
(credentialDescriptor) => {
|
||||||
).map((credentialDescriptor) => {
|
const id = this.u8arr(credentialDescriptor.id.toString());
|
||||||
const id = this.u8arr(credentialDescriptor.id.toString());
|
return Object.assign({}, credentialDescriptor, { id });
|
||||||
return Object.assign({}, credentialDescriptor, { id });
|
},
|
||||||
});
|
);
|
||||||
|
|
||||||
return Object.assign({}, credentialRequestOptions, {
|
return Object.assign({}, credentialRequestOptions, {
|
||||||
challenge,
|
challenge,
|
||||||
@ -390,25 +295,19 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
* Encodes the binary data in the assertion into strings for posting to the server.
|
* Encodes the binary data in the assertion into strings for posting to the server.
|
||||||
* @param {PublicKeyCredential} newAssertion
|
* @param {PublicKeyCredential} newAssertion
|
||||||
*/
|
*/
|
||||||
transformAssertionForServer(
|
transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion {
|
||||||
newAssertion: PublicKeyCredential,
|
const response = newAssertion.response as AuthenticatorAssertionResponse;
|
||||||
): AuthAssertion {
|
|
||||||
const response =
|
|
||||||
newAssertion.response as AuthenticatorAssertionResponse;
|
|
||||||
const authData = new Uint8Array(response.authenticatorData);
|
const authData = new Uint8Array(response.authenticatorData);
|
||||||
const clientDataJSON = new Uint8Array(response.clientDataJSON);
|
const clientDataJSON = new Uint8Array(response.clientDataJSON);
|
||||||
const rawId = new Uint8Array(newAssertion.rawId);
|
const rawId = new Uint8Array(newAssertion.rawId);
|
||||||
const sig = new Uint8Array(response.signature);
|
const sig = new Uint8Array(response.signature);
|
||||||
const assertionClientExtensions =
|
const assertionClientExtensions = newAssertion.getClientExtensionResults();
|
||||||
newAssertion.getClientExtensionResults();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: newAssertion.id,
|
id: newAssertion.id,
|
||||||
rawId: this.b64enc(rawId),
|
rawId: this.b64enc(rawId),
|
||||||
type: newAssertion.type,
|
type: newAssertion.type,
|
||||||
assertionClientExtensions: JSON.stringify(
|
assertionClientExtensions: JSON.stringify(assertionClientExtensions),
|
||||||
assertionClientExtensions,
|
|
||||||
),
|
|
||||||
|
|
||||||
response: {
|
response: {
|
||||||
clientDataJSON: this.b64RawEnc(clientDataJSON),
|
clientDataJSON: this.b64RawEnc(clientDataJSON),
|
||||||
@ -421,8 +320,10 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.deviceChallenge) {
|
if (!this.deviceChallenge) {
|
||||||
return this.renderChallengePicker();
|
this.renderChallengePicker();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (this.deviceChallenge.deviceClass) {
|
switch (this.deviceChallenge.deviceClass) {
|
||||||
case "static":
|
case "static":
|
||||||
case "totp":
|
case "totp":
|
||||||
@ -437,12 +338,10 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderChallengePicker() {
|
renderChallengePicker() {
|
||||||
const challenges = this.challenge.deviceChallenges.filter(
|
const challenges = this.challenge.deviceChallenges.filter((challenge) =>
|
||||||
(challenge) =>
|
challenge.deviceClass === "webauthn" && !this.checkWebAuthnSupport()
|
||||||
challenge.deviceClass === "webauthn" &&
|
? undefined
|
||||||
!this.checkWebAuthnSupport()
|
: challenge,
|
||||||
? undefined
|
|
||||||
: challenge,
|
|
||||||
);
|
);
|
||||||
this.html(`<form id="picker-form">
|
this.html(`<form id="picker-form">
|
||||||
<img class="mb-4 brand-icon" src="${ak().brand.branding_logo}" alt="">
|
<img class="mb-4 brand-icon" src="${ak().brand.branding_logo}" alt="">
|
||||||
@ -480,12 +379,13 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
.join("")}
|
.join("")}
|
||||||
</form>`);
|
</form>`);
|
||||||
this.challenge.deviceChallenges.forEach((challenge) => {
|
this.challenge.deviceChallenges.forEach((challenge) => {
|
||||||
$(
|
$(`#picker-form button#${challenge.deviceClass}-${challenge.deviceUid}`).on(
|
||||||
`#picker-form button#${challenge.deviceClass}-${challenge.deviceUid}`,
|
"click",
|
||||||
).on("click", () => {
|
() => {
|
||||||
this.deviceChallenge = challenge;
|
this.deviceChallenge = challenge;
|
||||||
this.render();
|
this.render();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,8 +423,7 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
navigator.credentials
|
navigator.credentials
|
||||||
.get({
|
.get({
|
||||||
publicKey: this.transformCredentialRequestOptions(
|
publicKey: this.transformCredentialRequestOptions(
|
||||||
this.deviceChallenge
|
this.deviceChallenge?.challenge as PublicKeyCredentialRequestOptions,
|
||||||
?.challenge as PublicKeyCredentialRequestOptions,
|
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.then((assertion) => {
|
.then((assertion) => {
|
||||||
@ -534,19 +433,16 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
try {
|
try {
|
||||||
// we now have an authentication assertion! encode the byte arrays contained
|
// we now have an authentication assertion! encode the byte arrays contained
|
||||||
// in the assertion data as strings for posting to the server
|
// in the assertion data as strings for posting to the server
|
||||||
const transformedAssertionForServer =
|
const transformedAssertionForServer = this.transformAssertionForServer(
|
||||||
this.transformAssertionForServer(
|
assertion as PublicKeyCredential,
|
||||||
assertion as PublicKeyCredential,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
// post the assertion to the server for verification.
|
// post the assertion to the server for verification.
|
||||||
this.executor.submit({
|
this.executor.submit({
|
||||||
webauthn: transformedAssertionForServer,
|
webauthn: transformedAssertionForServer,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(
|
throw new Error(`Error when validating assertion on server: ${err}`);
|
||||||
`Error when validating assertion on server: ${err}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -557,7 +453,87 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sfe = new SimpleFlowExecutor(
|
class SimpleFlowExecutor {
|
||||||
$("#flow-sfe-container")[0] as HTMLDivElement,
|
challenge?: ChallengeTypes;
|
||||||
);
|
flowSlug: string;
|
||||||
|
container: HTMLDivElement;
|
||||||
|
|
||||||
|
constructor(container: HTMLDivElement) {
|
||||||
|
this.flowSlug = window.location.pathname.split("/")[3] || "";
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
get apiURL() {
|
||||||
|
return `${ak().api.base}api/v3/flows/executor/${this.flowSlug}/?query=${encodeURIComponent(window.location.search.substring(1))}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: this.apiURL,
|
||||||
|
success: (data) => {
|
||||||
|
this.challenge = ChallengeTypesFromJSON(data);
|
||||||
|
this.renderChallenge();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
submit(payload: { [key: string]: unknown } | FormData) {
|
||||||
|
$("button[type=submit]").addClass("disabled")
|
||||||
|
.html(`<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
|
||||||
|
<span role="status">Loading...</span>`);
|
||||||
|
let finalData: { [key: string]: unknown } = {};
|
||||||
|
if (payload instanceof FormData) {
|
||||||
|
finalData = {};
|
||||||
|
payload.forEach((value, key) => {
|
||||||
|
finalData[key] = value;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
finalData = payload;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: this.apiURL,
|
||||||
|
data: JSON.stringify(finalData),
|
||||||
|
success: (data) => {
|
||||||
|
this.challenge = ChallengeTypesFromJSON(data);
|
||||||
|
this.renderChallenge();
|
||||||
|
},
|
||||||
|
contentType: "application/json",
|
||||||
|
dataType: "json",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderChallenge() {
|
||||||
|
switch (this.challenge?.component) {
|
||||||
|
case "ak-stage-identification":
|
||||||
|
new IdentificationStage(this, this.challenge).render();
|
||||||
|
return;
|
||||||
|
case "ak-stage-password":
|
||||||
|
new PasswordStage(this, this.challenge).render();
|
||||||
|
return;
|
||||||
|
case "xak-flow-redirect":
|
||||||
|
new RedirectStage(this, this.challenge).render();
|
||||||
|
return;
|
||||||
|
case "ak-stage-autosubmit":
|
||||||
|
new AutosubmitStage(this, this.challenge).render();
|
||||||
|
return;
|
||||||
|
case "ak-stage-authenticator-validate":
|
||||||
|
new AuthenticatorValidateStage(this, this.challenge).render();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
this.container.innerText = `Unsupported stage: ${this.challenge?.component}`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [flowContainer] = $<HTMLDivElement>("#flow-sfe-container");
|
||||||
|
|
||||||
|
if (!flowContainer) {
|
||||||
|
throw new Error("No flow container element found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const sfe = new SimpleFlowExecutor(flowContainer);
|
||||||
|
|
||||||
sfe.start();
|
sfe.start();
|
||||||
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
"extends": "@goauthentik/tsconfig",
|
"extends": "@goauthentik/tsconfig",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"types": ["jquery"],
|
"emitDeclarationOnly": true,
|
||||||
|
"baseUrl": ".",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"lib": ["DOM", "ES2015", "ES2017"]
|
"lib": ["DOM", "ES2015", "ES2017"]
|
||||||
}
|
}
|
||||||
22
web/paths.js
Normal file
22
web/paths.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { dirname, resolve } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {'@goauthentik/web'} WebPackageIdentifier
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root of the web package.
|
||||||
|
*/
|
||||||
|
export const PackageRoot = /** @type {WebPackageIdentifier} */ (resolve(__dirname));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to the web package's distribution directory.
|
||||||
|
*
|
||||||
|
* This is where the built files are located after running the build process.
|
||||||
|
*/
|
||||||
|
export const DistDirectory = /** @type {`${WebPackageIdentifier}/dist`} */ (
|
||||||
|
resolve(__dirname, "dist")
|
||||||
|
);
|
||||||
@ -1,72 +1,103 @@
|
|||||||
import { spawnSync } from "child_process";
|
/**
|
||||||
import fs from "fs";
|
* @file Lit Localize build script.
|
||||||
import path from "path";
|
*
|
||||||
import process from "process";
|
* @import { Config } from "@lit/localize-tools/lib/types/config.js"
|
||||||
|
*/
|
||||||
|
import * as fs from "node:fs/promises";
|
||||||
|
import * as path from "node:path";
|
||||||
|
import process from "node:process";
|
||||||
|
import { $ } from "zx";
|
||||||
|
|
||||||
|
const localizeRules = await import("../lit-localize.json", {
|
||||||
|
with: {
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((module) => {
|
||||||
|
return /** @type {Config} */ (module.default);
|
||||||
|
})
|
||||||
|
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed to load lit-localize.json", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if all the Xliff translation source files are present and if the Typescript source
|
* Attempt to stat a file, returning null if it doesn't exist.
|
||||||
* files generated from those sources are up-to-date. If they are not, it runs the locale building
|
|
||||||
* script, intercepting the long spew of "this string is not translated" and replacing it with a
|
|
||||||
* summary of how many strings are missing with respect to the source locale.
|
|
||||||
*/
|
*/
|
||||||
|
function tryStat(filePath) {
|
||||||
|
return fs.stat(filePath).catch(() => null);
|
||||||
|
}
|
||||||
|
|
||||||
const localizeRules = JSON.parse(fs.readFileSync("./lit-localize.json", "utf-8"));
|
/**
|
||||||
|
* Check if a generated file is up-to-date with its XLIFF source.
|
||||||
|
*
|
||||||
|
* @param {string} languageCode The locale to check.
|
||||||
|
*/
|
||||||
|
async function generatedFileIsUpToDateWithXliffSource(languageCode) {
|
||||||
|
const xlfFilePath = path.join("./xliff", `${languageCode}.xlf`);
|
||||||
|
const xlfStat = await tryStat(xlfFilePath);
|
||||||
|
|
||||||
function generatedFileIsUpToDateWithXliffSource(loc) {
|
if (!xlfStat) {
|
||||||
const xliff = path.join("./xliff", `${loc}.xlf`);
|
console.error(`lit-localize expected '${languageCode}.xlf', but XLF file is not present`);
|
||||||
const gened = path.join("./src/locales", `${loc}.ts`);
|
|
||||||
|
|
||||||
// Returns false if: the expected XLF file doesn't exist, The expected
|
|
||||||
// generated file doesn't exist, or the XLF file is newer (has a higher date)
|
|
||||||
// than the generated file. The missing XLF file is important enough it
|
|
||||||
// generates a unique error message and halts the build.
|
|
||||||
|
|
||||||
try {
|
|
||||||
var xlfStat = fs.statSync(xliff);
|
|
||||||
} catch (_error) {
|
|
||||||
console.error(`lit-localize expected '${loc}.xlf', but XLF file is not present`);
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the generated file doesn't exist, of course it's not up to date.
|
const generatedTSFilePath = path.join("./src/locales", `${languageCode}.ts`);
|
||||||
try {
|
|
||||||
var genedStat = fs.statSync(gened);
|
const generatedTSFilePathStat = await tryStat(generatedTSFilePath);
|
||||||
} catch (_error) {
|
|
||||||
return false;
|
// Does the generated file exist?
|
||||||
|
if (!generatedTSFilePathStat) {
|
||||||
|
return {
|
||||||
|
languageCode,
|
||||||
|
exists: false,
|
||||||
|
expired: null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the generated file is the same age or newer (date is greater) than the xliff file, it's
|
return {
|
||||||
// presumed to have been generated by that file and is up-to-date.
|
languageCode,
|
||||||
return genedStat.mtimeMs >= xlfStat.mtimeMs;
|
exists: true,
|
||||||
|
// Is the generated file older than the XLIFF file?
|
||||||
|
expired: generatedTSFilePathStat.mtimeMs < xlfStat.mtimeMs,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all the expected files, find out if any aren't up-to-date.
|
const results = await Promise.all(
|
||||||
const upToDate = localizeRules.targetLocales.reduce(
|
localizeRules.targetLocales.map(generatedFileIsUpToDateWithXliffSource),
|
||||||
(acc, loc) => acc && generatedFileIsUpToDateWithXliffSource(loc),
|
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!upToDate) {
|
const pendingBuild = results.some((result) => !result.exists || result.expired);
|
||||||
const status = spawnSync("npm", ["run", "build-locales:build"], { encoding: "utf8" });
|
|
||||||
|
|
||||||
// Count all the missing message warnings
|
if (!pendingBuild) {
|
||||||
const counts = status.stderr.split("\n").reduce((acc, line) => {
|
console.log("Local is up-to-date!");
|
||||||
const match = /^([\w-]+) message/.exec(line);
|
process.exit(0);
|
||||||
if (!match) {
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
acc.set(match[1], (acc.get(match[1]) || 0) + 1);
|
|
||||||
return acc;
|
|
||||||
}, new Map());
|
|
||||||
|
|
||||||
const locales = Array.from(counts.keys());
|
|
||||||
locales.sort();
|
|
||||||
|
|
||||||
const report = locales
|
|
||||||
.map((locale) => `Locale '${locale}' has ${counts.get(locale)} missing translations`)
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
console.log(`Translation tables rebuilt.\n${report}\n`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Locale ./src is up-to-date");
|
const status = await $({ stdio: ["ignore", "pipe", "pipe"] })`npx lit-localize build`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Map<string, number>}
|
||||||
|
*/
|
||||||
|
const counts = new Map();
|
||||||
|
|
||||||
|
// Count all the missing message warnings
|
||||||
|
for (const line of status.stderr.split("\n")) {
|
||||||
|
const match = /^([\w-]+) message/.exec(line);
|
||||||
|
if (!match) continue;
|
||||||
|
|
||||||
|
const count = counts.get(match[1]) || 0;
|
||||||
|
counts.set(match[1], count + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const locales = Array.from(counts.keys()).sort();
|
||||||
|
|
||||||
|
for (const locale of locales) {
|
||||||
|
console.log(`Locale '${locale}' has ${counts.get(locale)} missing translations`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await $`npx prettier --write src/locale-codes.ts`;
|
||||||
|
|
||||||
|
console.log("\nTranslation tables rebuilt.\n");
|
||||||
|
|||||||
79
web/scripts/build-sfe.mjs
Normal file
79
web/scripts/build-sfe.mjs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* @file Build script for the simplified flow executor (SFE).
|
||||||
|
*/
|
||||||
|
import { DistDirectory, PackageRoot } from "@goauthentik/web/paths";
|
||||||
|
import esbuild from "esbuild";
|
||||||
|
import copy from "esbuild-plugin-copy";
|
||||||
|
import { es5Plugin } from "esbuild-plugin-es5";
|
||||||
|
import { createRequire } from "node:module";
|
||||||
|
import * as path from "node:path";
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
|
async function buildSFE() {
|
||||||
|
const sourceDirectory = path.join(PackageRoot, "packages", "sfe");
|
||||||
|
const outDirectory = path.join(DistDirectory, "sfe");
|
||||||
|
|
||||||
|
const bootstrapCSSPath = require.resolve(
|
||||||
|
path.join("bootstrap", "dist", "css", "bootstrap.min.css"),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {esbuild.BuildOptions}
|
||||||
|
*/
|
||||||
|
const config = {
|
||||||
|
tsconfig: path.join(sourceDirectory, "tsconfig.json"),
|
||||||
|
entryPoints: [path.join(sourceDirectory, "index.ts")],
|
||||||
|
minify: false,
|
||||||
|
bundle: true,
|
||||||
|
sourcemap: true,
|
||||||
|
|
||||||
|
legalComments: "external",
|
||||||
|
platform: "browser",
|
||||||
|
format: "iife",
|
||||||
|
alias: {
|
||||||
|
"@swc/helpers": path.dirname(require.resolve("@swc/helpers/package.json")),
|
||||||
|
},
|
||||||
|
banner: {
|
||||||
|
js: [
|
||||||
|
// ---
|
||||||
|
"// Simplified Flow Executor (SFE)",
|
||||||
|
"// @ts-nocheck",
|
||||||
|
"",
|
||||||
|
].join("\n"),
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
copy({
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
from: bootstrapCSSPath,
|
||||||
|
to: outDirectory,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
es5Plugin({
|
||||||
|
swc: {
|
||||||
|
jsc: {
|
||||||
|
loose: false,
|
||||||
|
externalHelpers: false,
|
||||||
|
keepClassNames: false,
|
||||||
|
},
|
||||||
|
minify: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
target: ["es5"],
|
||||||
|
outdir: outDirectory,
|
||||||
|
};
|
||||||
|
|
||||||
|
esbuild.build(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildSFE()
|
||||||
|
.then(() => {
|
||||||
|
console.log("Build complete");
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Build failed", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@ -1,14 +1,14 @@
|
|||||||
import { execFileSync } from "child_process";
|
|
||||||
import { deepmerge } from "deepmerge-ts";
|
import { deepmerge } from "deepmerge-ts";
|
||||||
import esbuild from "esbuild";
|
import esbuild from "esbuild";
|
||||||
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
||||||
import findFreePorts from "find-free-ports";
|
import findFreePorts from "find-free-ports";
|
||||||
import { copyFileSync, mkdirSync, readFileSync, statSync } from "fs";
|
import { copyFileSync, mkdirSync, readFileSync, statSync } from "fs";
|
||||||
import { globSync } from "glob";
|
import { globSync } from "glob";
|
||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
import { cwd } from "node:process";
|
||||||
|
import process from "node:process";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { cwd } from "process";
|
|
||||||
import process from "process";
|
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
|
|
||||||
import { mdxPlugin } from "./esbuild/build-mdx-plugin.mjs";
|
import { mdxPlugin } from "./esbuild/build-mdx-plugin.mjs";
|
||||||
import { buildObserverPlugin } from "./esbuild/build-observer-plugin.mjs";
|
import { buildObserverPlugin } from "./esbuild/build-observer-plugin.mjs";
|
||||||
@ -117,6 +117,7 @@ const BASE_ESBUILD_OPTIONS = {
|
|||||||
write: true,
|
write: true,
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
minify: NODE_ENV === "production",
|
minify: NODE_ENV === "production",
|
||||||
|
legalComments: "external",
|
||||||
splitting: true,
|
splitting: true,
|
||||||
treeShaking: true,
|
treeShaking: true,
|
||||||
external: ["*.woff", "*.woff2"],
|
external: ["*.woff", "*.woff2"],
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { execSync } from "child_process";
|
import { execSync } from "node:child_process";
|
||||||
import path from "path";
|
import * as path from "node:path";
|
||||||
|
|
||||||
const projectRoot = execSync("git rev-parse --show-toplevel", { encoding: "utf8" }).replace(
|
const projectRoot = execSync("git rev-parse --show-toplevel", { encoding: "utf8" }).replace(
|
||||||
"\n",
|
"\n",
|
||||||
|
|||||||
@ -40,22 +40,13 @@ const name = "mdx-plugin";
|
|||||||
* @returns {Plugin} Plugin.
|
* @returns {Plugin} Plugin.
|
||||||
*/
|
*/
|
||||||
export function mdxPlugin({ root }) {
|
export function mdxPlugin({ root }) {
|
||||||
return { name, setup };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PluginBuild} build
|
* @param {PluginBuild} build
|
||||||
* Build.
|
|
||||||
* @returns {undefined}
|
|
||||||
* Nothing.
|
|
||||||
*/
|
*/
|
||||||
function setup(build) {
|
function setup(build) {
|
||||||
build.onLoad({ filter: /\.mdx?$/ }, onload);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {LoadData} data
|
* @param {LoadData} data Data.
|
||||||
* Data.
|
* @returns {Promise<OnLoadResult>} Result.
|
||||||
* @returns {Promise<OnLoadResult>}
|
|
||||||
* Result.
|
|
||||||
*/
|
*/
|
||||||
async function onload(data) {
|
async function onload(data) {
|
||||||
const content = String(
|
const content = String(
|
||||||
@ -77,5 +68,9 @@ export function mdxPlugin({ root }) {
|
|||||||
loader: "file",
|
loader: "file",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build.onLoad({ filter: /\.mdx?$/ }, onload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { name, setup };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import * as http from "http";
|
import * as http from "http";
|
||||||
import path from "path";
|
import * as path from "node:path";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes a custom event to a text stream.
|
* Serializes a custom event to a text stream.
|
||||||
@ -13,7 +13,7 @@ export function serializeCustomEventToStream(event) {
|
|||||||
|
|
||||||
const eventContent = [`event: ${event.type}`, `data: ${JSON.stringify(data)}`];
|
const eventContent = [`event: ${event.type}`, `data: ${JSON.stringify(data)}`];
|
||||||
|
|
||||||
return eventContent.join("\n") + "\n\n";
|
return `${eventContent.join("\n")}\n\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,6 +70,13 @@ export function buildObserverPlugin({ serverURL, logPrefix, relativeRoot }) {
|
|||||||
dispatcher.addEventListener("esbuild:error", listener);
|
dispatcher.addEventListener("esbuild:error", listener);
|
||||||
dispatcher.addEventListener("esbuild:end", listener);
|
dispatcher.addEventListener("esbuild:end", listener);
|
||||||
|
|
||||||
|
const keepAliveInterval = setInterval(() => {
|
||||||
|
console.timeStamp("🏓 Keep-alive");
|
||||||
|
|
||||||
|
res.write("event: keep-alive\n\n");
|
||||||
|
res.write(serializeCustomEventToStream(new CustomEvent("esbuild:keep-alive")));
|
||||||
|
}, 15_000);
|
||||||
|
|
||||||
req.on("close", () => {
|
req.on("close", () => {
|
||||||
console.log("🔌 Client disconnected");
|
console.log("🔌 Client disconnected");
|
||||||
|
|
||||||
@ -79,13 +86,6 @@ export function buildObserverPlugin({ serverURL, logPrefix, relativeRoot }) {
|
|||||||
dispatcher.removeEventListener("esbuild:error", listener);
|
dispatcher.removeEventListener("esbuild:error", listener);
|
||||||
dispatcher.removeEventListener("esbuild:end", listener);
|
dispatcher.removeEventListener("esbuild:end", listener);
|
||||||
});
|
});
|
||||||
|
|
||||||
const keepAliveInterval = setInterval(() => {
|
|
||||||
console.timeStamp("🏓 Keep-alive");
|
|
||||||
|
|
||||||
res.write("event: keep-alive\n\n");
|
|
||||||
res.write(serializeCustomEventToStream(new CustomEvent("esbuild:keep-alive")));
|
|
||||||
}, 15_000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
import { execFileSync } from "child_process";
|
|
||||||
import { ESLint } from "eslint";
|
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import process from "process";
|
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
|
|
||||||
function changedFiles() {
|
|
||||||
const gitStatus = execFileSync("git", ["diff", "--name-only", "HEAD"], { encoding: "utf8" });
|
|
||||||
const gitUntracked = execFileSync("git", ["ls-files", "--others", "--exclude-standard"], {
|
|
||||||
encoding: "utf8",
|
|
||||||
});
|
|
||||||
|
|
||||||
const changed = gitStatus
|
|
||||||
.split("\n")
|
|
||||||
.filter((line) => line.trim().substring(0, 4) === "web/")
|
|
||||||
.filter((line) => /\.(m|c)?(t|j)s$/.test(line))
|
|
||||||
.map((line) => line.substring(4))
|
|
||||||
.filter((line) => fs.existsSync(line));
|
|
||||||
|
|
||||||
const untracked = gitUntracked
|
|
||||||
.split("\n")
|
|
||||||
.filter((line) => /\.(m|c)?(t|j)s$/.test(line))
|
|
||||||
.filter((line) => fs.existsSync(line));
|
|
||||||
|
|
||||||
const sourceFiles = [...changed, ...untracked].filter((line) => /^src\//.test(line));
|
|
||||||
const scriptFiles = [...changed, ...untracked].filter(
|
|
||||||
(line) => /^scripts\//.test(line) || !/^src\//.test(line),
|
|
||||||
);
|
|
||||||
|
|
||||||
return [...sourceFiles, ...scriptFiles];
|
|
||||||
}
|
|
||||||
|
|
||||||
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
||||||
const projectRoot = path.join(__dirname, "..");
|
|
||||||
process.chdir(projectRoot);
|
|
||||||
|
|
||||||
const hasFlag = (flags) => process.argv.length > 1 && flags.includes(process.argv[2]);
|
|
||||||
|
|
||||||
const [configFile, files] = hasFlag(["-n", "--nightmare"])
|
|
||||||
? [path.join(__dirname, "eslint.nightmare.mjs"), changedFiles()]
|
|
||||||
: hasFlag(["-p", "--precommit"])
|
|
||||||
? [path.join(__dirname, "eslint.precommit.mjs"), changedFiles()]
|
|
||||||
: [path.join(projectRoot, "eslint.config.mjs"), ["."]];
|
|
||||||
|
|
||||||
const eslint = new ESLint({
|
|
||||||
overrideConfigFile: configFile,
|
|
||||||
warnIgnored: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const results = await eslint.lintFiles(files);
|
|
||||||
const formatter = await eslint.loadFormatter("stylish");
|
|
||||||
const resultText = formatter.format(results);
|
|
||||||
const errors = results.reduce((acc, result) => acc + result.errorCount, 0);
|
|
||||||
console.log(resultText);
|
|
||||||
process.exit(errors > 1 ? 1 : 0);
|
|
||||||
@ -1,217 +0,0 @@
|
|||||||
import eslint from "@eslint/js";
|
|
||||||
import tsparser from "@typescript-eslint/parser";
|
|
||||||
import litconf from "eslint-plugin-lit";
|
|
||||||
import wcconf from "eslint-plugin-wc";
|
|
||||||
import globals from "globals";
|
|
||||||
import tseslint from "typescript-eslint";
|
|
||||||
|
|
||||||
const MAX_DEPTH = 4;
|
|
||||||
const MAX_NESTED_CALLBACKS = 4;
|
|
||||||
const MAX_PARAMS = 5;
|
|
||||||
|
|
||||||
// Waiting for SonarJS to be compatible
|
|
||||||
// const MAX_COGNITIVE_COMPLEXITY = 9;
|
|
||||||
|
|
||||||
const rules = {
|
|
||||||
"accessor-pairs": "error",
|
|
||||||
"array-callback-return": "error",
|
|
||||||
"block-scoped-var": "error",
|
|
||||||
"consistent-return": "error",
|
|
||||||
"consistent-this": ["error", "that"],
|
|
||||||
"curly": ["error", "all"],
|
|
||||||
"dot-notation": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
allowKeywords: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"eqeqeq": "error",
|
|
||||||
"func-names": "error",
|
|
||||||
"guard-for-in": "error",
|
|
||||||
"max-depth": ["error", MAX_DEPTH],
|
|
||||||
"max-nested-callbacks": ["error", MAX_NESTED_CALLBACKS],
|
|
||||||
"max-params": ["error", MAX_PARAMS],
|
|
||||||
"new-cap": "error",
|
|
||||||
"no-alert": "error",
|
|
||||||
"no-array-constructor": "error",
|
|
||||||
"no-bitwise": "error",
|
|
||||||
"no-caller": "error",
|
|
||||||
"no-case-declarations": "error",
|
|
||||||
"no-class-assign": "error",
|
|
||||||
"no-cond-assign": "error",
|
|
||||||
"no-const-assign": "error",
|
|
||||||
"no-constant-condition": "error",
|
|
||||||
"no-control-regex": "error",
|
|
||||||
"no-debugger": "error",
|
|
||||||
"no-delete-var": "error",
|
|
||||||
"no-div-regex": "error",
|
|
||||||
"no-dupe-args": "error",
|
|
||||||
"no-dupe-keys": "error",
|
|
||||||
"no-duplicate-case": "error",
|
|
||||||
"no-else-return": "error",
|
|
||||||
"no-empty": "error",
|
|
||||||
"no-empty-character-class": "error",
|
|
||||||
"no-empty-function": "error",
|
|
||||||
"no-labels": "error",
|
|
||||||
"no-eq-null": "error",
|
|
||||||
"no-eval": "error",
|
|
||||||
"no-ex-assign": "error",
|
|
||||||
"no-extend-native": "error",
|
|
||||||
"no-extra-bind": "error",
|
|
||||||
"no-extra-boolean-cast": "error",
|
|
||||||
"no-extra-label": "error",
|
|
||||||
"no-fallthrough": "error",
|
|
||||||
"no-func-assign": "error",
|
|
||||||
"no-implied-eval": "error",
|
|
||||||
"no-implicit-coercion": "error",
|
|
||||||
"no-implicit-globals": "error",
|
|
||||||
"no-inner-declarations": ["error", "functions"],
|
|
||||||
"no-invalid-regexp": "error",
|
|
||||||
"no-irregular-whitespace": "error",
|
|
||||||
"no-iterator": "error",
|
|
||||||
"no-invalid-this": "error",
|
|
||||||
"no-label-var": "error",
|
|
||||||
"no-lone-blocks": "error",
|
|
||||||
"no-lonely-if": "error",
|
|
||||||
"no-loop-func": "error",
|
|
||||||
"no-magic-numbers": ["error", { ignore: [0, 1, -1] }],
|
|
||||||
"no-multi-str": "error",
|
|
||||||
"no-negated-condition": "error",
|
|
||||||
"no-nested-ternary": "error",
|
|
||||||
"no-new": "error",
|
|
||||||
"no-new-func": "error",
|
|
||||||
"no-new-wrappers": "error",
|
|
||||||
"no-obj-calls": "error",
|
|
||||||
"no-octal": "error",
|
|
||||||
"no-octal-escape": "error",
|
|
||||||
"no-param-reassign": "error",
|
|
||||||
"no-proto": "error",
|
|
||||||
"no-redeclare": "error",
|
|
||||||
"no-regex-spaces": "error",
|
|
||||||
"no-restricted-syntax": ["error", "WithStatement"],
|
|
||||||
"no-script-url": "error",
|
|
||||||
"no-self-assign": "error",
|
|
||||||
"no-self-compare": "error",
|
|
||||||
"no-sequences": "error",
|
|
||||||
"no-shadow": "error",
|
|
||||||
"no-shadow-restricted-names": "error",
|
|
||||||
"no-sparse-arrays": "error",
|
|
||||||
"no-this-before-super": "error",
|
|
||||||
"no-throw-literal": "error",
|
|
||||||
"no-trailing-spaces": "error",
|
|
||||||
"no-undef": "error",
|
|
||||||
"no-undef-init": "error",
|
|
||||||
"no-unexpected-multiline": "error",
|
|
||||||
"no-useless-constructor": "error",
|
|
||||||
"no-unmodified-loop-condition": "error",
|
|
||||||
"no-unneeded-ternary": "error",
|
|
||||||
"no-unreachable": "error",
|
|
||||||
"no-unused-expressions": "error",
|
|
||||||
"no-unused-labels": "error",
|
|
||||||
"no-use-before-define": "error",
|
|
||||||
"no-useless-call": "error",
|
|
||||||
"no-dupe-class-members": "error",
|
|
||||||
"no-var": "error",
|
|
||||||
"no-void": "error",
|
|
||||||
"no-with": "error",
|
|
||||||
"prefer-arrow-callback": "error",
|
|
||||||
"prefer-const": "error",
|
|
||||||
"prefer-rest-params": "error",
|
|
||||||
"prefer-spread": "error",
|
|
||||||
"prefer-template": "error",
|
|
||||||
"radix": "error",
|
|
||||||
"require-yield": "error",
|
|
||||||
"strict": ["error", "global"],
|
|
||||||
"use-isnan": "error",
|
|
||||||
"valid-typeof": "error",
|
|
||||||
"vars-on-top": "error",
|
|
||||||
"yoda": ["error", "never"],
|
|
||||||
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
|
|
||||||
// SonarJS is not yet compatible with ESLint 9. Commenting these out
|
|
||||||
// until it is.
|
|
||||||
// "sonarjs/cognitive-complexity": ["off", MAX_COGNITIVE_COMPLEXITY],
|
|
||||||
// "sonarjs/no-duplicate-string": "off",
|
|
||||||
// "sonarjs/no-nested-template-literals": "off",
|
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
argsIgnorePattern: "^_",
|
|
||||||
varsIgnorePattern: "^_",
|
|
||||||
caughtErrorsIgnorePattern: "^_",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export default [
|
|
||||||
// You would not believe how much this change has frustrated users: ["if an ignores key is used
|
|
||||||
// without any other keys in the configuration object, then the patterns act as global
|
|
||||||
// ignores"](https://eslint.org/docs/latest/use/configure/ignore)
|
|
||||||
{
|
|
||||||
ignores: [
|
|
||||||
"dist/",
|
|
||||||
".wireit/",
|
|
||||||
"packages/",
|
|
||||||
// don't ever lint node_modules
|
|
||||||
"node_modules/",
|
|
||||||
".storybook/*",
|
|
||||||
// don't lint build output (make sure it's set to your correct build folder name)
|
|
||||||
// don't lint nyc coverage output
|
|
||||||
"coverage/",
|
|
||||||
"src/locale-codes.ts",
|
|
||||||
"storybook-static/",
|
|
||||||
"src/locales/",
|
|
||||||
"src/**/*.test.ts",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
eslint.configs.recommended,
|
|
||||||
wcconf.configs["flat/recommended"],
|
|
||||||
litconf.configs["flat/recommended"],
|
|
||||||
...tseslint.configs.recommended,
|
|
||||||
// sonar.configs.recommended,
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsparser,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 12,
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
...globals.browser,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
files: ["src/**"],
|
|
||||||
rules,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsparser,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 12,
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
...globals.nodeBuiltin,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
files: ["scripts/*.mjs", "*.ts", "*.mjs"],
|
|
||||||
rules,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsparser,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 12,
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
...globals.nodeBuiltin,
|
|
||||||
...globals.jest,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
files: ["src/**/*.test.ts"],
|
|
||||||
rules,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
import eslint from "@eslint/js";
|
|
||||||
import tsparser from "@typescript-eslint/parser";
|
|
||||||
import litconf from "eslint-plugin-lit";
|
|
||||||
import wcconf from "eslint-plugin-wc";
|
|
||||||
import globals from "globals";
|
|
||||||
import tseslint from "typescript-eslint";
|
|
||||||
|
|
||||||
export default [
|
|
||||||
// You would not believe how much this change has frustrated users: ["if an ignores key is used
|
|
||||||
// without any other keys in the configuration object, then the patterns act as global
|
|
||||||
// ignores"](https://eslint.org/docs/latest/use/configure/ignore)
|
|
||||||
{
|
|
||||||
ignores: [
|
|
||||||
"dist/",
|
|
||||||
".wireit/",
|
|
||||||
"packages/",
|
|
||||||
// don't ever lint node_modules
|
|
||||||
"node_modules/",
|
|
||||||
".storybook/*",
|
|
||||||
// don't lint build output (make sure it's set to your correct build folder name)
|
|
||||||
// don't lint nyc coverage output
|
|
||||||
"coverage/",
|
|
||||||
"src/locale-codes.ts",
|
|
||||||
"storybook-static/",
|
|
||||||
"src/locales/",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
eslint.configs.recommended,
|
|
||||||
wcconf.configs["flat/recommended"],
|
|
||||||
litconf.configs["flat/recommended"],
|
|
||||||
...tseslint.configs.recommended,
|
|
||||||
// sonar.configs.recommended,
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsparser,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 12,
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
files: ["src/**"],
|
|
||||||
rules: {
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
|
|
||||||
// SonarJS is not yet compatible with ESLint 9. Commenting these out
|
|
||||||
// until it is.
|
|
||||||
// "sonarjs/cognitive-complexity": ["off", 9],
|
|
||||||
// "sonarjs/no-duplicate-string": "off",
|
|
||||||
// "sonarjs/no-nested-template-literals": "off",
|
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
argsIgnorePattern: "^_",
|
|
||||||
varsIgnorePattern: "^_",
|
|
||||||
caughtErrorsIgnorePattern: "^_",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsparser,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 12,
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
...globals.nodeBuiltin,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
files: ["scripts/*.mjs", "*.ts", "*.mjs"],
|
|
||||||
rules: {
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"no-console": "off",
|
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
argsIgnorePattern: "^_",
|
|
||||||
varsIgnorePattern: "^_",
|
|
||||||
caughtErrorsIgnorePattern: "^_",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@ -1,22 +1,47 @@
|
|||||||
import { readFileSync } from "fs";
|
/**
|
||||||
import path from "path";
|
* @import { Config } from "@lit/localize-tools/lib/types/config.js"
|
||||||
|
* @import { TransformOutputConfig } from "@lit/localize-tools/lib/types/modes.js"
|
||||||
|
* @import { Locale } from "@lit/localize-tools/lib/types/locale.js"
|
||||||
|
* @import { ProgramMessage } from "@lit/localize-tools/lib/messages.js"
|
||||||
|
* @import { Message } from "@lit/localize-tools/lib/messages.js"
|
||||||
|
*
|
||||||
|
* @typedef {Config & { output: TransformOutputConfig; }} TransformerConfig
|
||||||
|
*/
|
||||||
|
import * as path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
import pseudolocale from "pseudolocale";
|
import pseudolocale from "pseudolocale";
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
|
|
||||||
import { makeFormatter } from "@lit/localize-tools/lib/formatters/index.js";
|
import { makeFormatter } from "@lit/localize-tools/lib/formatters/index.js";
|
||||||
import { sortProgramMessages } from "@lit/localize-tools/lib/messages.js";
|
import { sortProgramMessages } from "@lit/localize-tools/lib/messages.js";
|
||||||
import { TransformLitLocalizer } from "@lit/localize-tools/lib/modes/transform.js";
|
import { TransformLitLocalizer } from "@lit/localize-tools/lib/modes/transform.js";
|
||||||
|
|
||||||
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||||
const pseudoLocale = "pseudo-LOCALE";
|
const pseudoLocale = /** @type {Locale} */ ("pseudo-LOCALE");
|
||||||
|
|
||||||
const targetLocales = [pseudoLocale];
|
const targetLocales = [pseudoLocale];
|
||||||
const baseConfig = JSON.parse(readFileSync(path.join(__dirname, "../lit-localize.json"), "utf-8"));
|
|
||||||
|
const baseConfig = await import("../lit-localize.json", {
|
||||||
|
with: {
|
||||||
|
type: "json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((module) => {
|
||||||
|
return /** @type {Config} */ (module.default);
|
||||||
|
})
|
||||||
|
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed to load lit-localize.json", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
// Need to make some internal specifications to satisfy the transformer. It doesn't actually matter
|
// Need to make some internal specifications to satisfy the transformer. It doesn't actually matter
|
||||||
// which Localizer we use (transformer or runtime), because all of the functionality we care about
|
// which Localizer we use (transformer or runtime), because all of the functionality we care about
|
||||||
// is in their common parent class, but I had to pick one. Everything else here is just pure
|
// is in their common parent class, but I had to pick one. Everything else here is just pure
|
||||||
// exploitation of the lit/localize-tools internals.
|
// exploitation of the lit/localize-tools internals.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {TransformerConfig}
|
||||||
|
*/
|
||||||
const config = {
|
const config = {
|
||||||
...baseConfig,
|
...baseConfig,
|
||||||
baseDir: path.join(__dirname, ".."),
|
baseDir: path.join(__dirname, ".."),
|
||||||
@ -25,18 +50,26 @@ const config = {
|
|||||||
...baseConfig.output,
|
...baseConfig.output,
|
||||||
mode: "transform",
|
mode: "transform",
|
||||||
},
|
},
|
||||||
resolve: (path) => path,
|
resolve: (filePath) => filePath,
|
||||||
};
|
};
|
||||||
|
|
||||||
const pseudoMessagify = (message) => ({
|
/**
|
||||||
name: message.name,
|
* @param {ProgramMessage} message
|
||||||
contents: message.contents.map((content) =>
|
* @returns {Message}
|
||||||
typeof content === "string" ? pseudolocale(content, { prepend: "", append: "" }) : content,
|
*/
|
||||||
),
|
function pseudoMessagify({ name, contents }) {
|
||||||
});
|
return {
|
||||||
|
name,
|
||||||
|
contents: contents.map((content) =>
|
||||||
|
typeof content === "string"
|
||||||
|
? pseudolocale(content, { prepend: "", append: "" })
|
||||||
|
: content,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const localizer = new TransformLitLocalizer(config);
|
const localizer = new TransformLitLocalizer(config);
|
||||||
const messages = localizer.extractSourceMessages().messages;
|
const { messages } = localizer.extractSourceMessages();
|
||||||
const translations = messages.map(pseudoMessagify);
|
const translations = messages.map(pseudoMessagify);
|
||||||
const sorted = sortProgramMessages([...messages]);
|
const sorted = sortProgramMessages([...messages]);
|
||||||
const formatter = makeFormatter(config);
|
const formatter = makeFormatter(config);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import { AdminApi, CapabilitiesEnum, LicenseSummaryStatusEnum } from "@goauthent
|
|||||||
@customElement("ak-about-modal")
|
@customElement("ak-about-modal")
|
||||||
export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton)) {
|
export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton)) {
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return super.styles.concat(
|
return ModalButton.styles.concat(
|
||||||
PFAbout,
|
PFAbout,
|
||||||
css`
|
css`
|
||||||
.pf-c-about-modal-box__hero {
|
.pf-c-about-modal-box__hero {
|
||||||
@ -59,7 +59,7 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton))
|
|||||||
|
|
||||||
renderModal() {
|
renderModal() {
|
||||||
let product = globalAK().brand.brandingTitle || DefaultBrand.brandingTitle;
|
let product = globalAK().brand.brandingTitle || DefaultBrand.brandingTitle;
|
||||||
if (this.licenseSummary.status != LicenseSummaryStatusEnum.Unlicensed) {
|
if (this.licenseSummary.status !== LicenseSummaryStatusEnum.Unlicensed) {
|
||||||
product += ` ${msg("Enterprise")}`;
|
product += ` ${msg("Enterprise")}`;
|
||||||
}
|
}
|
||||||
return html`<div
|
return html`<div
|
||||||
|
|||||||
@ -125,6 +125,7 @@ export class AdminInterface extends AuthenticatedInterface {
|
|||||||
if (process.env.NODE_ENV === "development" && process.env.WATCHER_URL) {
|
if (process.env.NODE_ENV === "development" && process.env.WATCHER_URL) {
|
||||||
const { ESBuildObserver } = await import("@goauthentik/common/client");
|
const { ESBuildObserver } = await import("@goauthentik/common/client");
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-new
|
||||||
new ESBuildObserver(process.env.WATCHER_URL);
|
new ESBuildObserver(process.env.WATCHER_URL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,7 +46,7 @@ export class SystemStatusCard extends AdminStatusCard<SystemInfo> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const outpost = outposts.results[0];
|
const outpost = outposts.results[0];
|
||||||
outpost.config["authentik_host"] = window.location.origin;
|
outpost.config.authentik_host = window.location.origin;
|
||||||
await new OutpostsApi(DEFAULT_CONFIG).outpostsInstancesUpdate({
|
await new OutpostsApi(DEFAULT_CONFIG).outpostsInstancesUpdate({
|
||||||
uuid: outpost.pk,
|
uuid: outpost.pk,
|
||||||
outpostRequest: outpost,
|
outpostRequest: outpost,
|
||||||
|
|||||||
@ -28,16 +28,18 @@ export class WorkersStatusCard extends AdminStatusCard<Worker[]> {
|
|||||||
icon: "fa fa-times-circle pf-m-danger",
|
icon: "fa fa-times-circle pf-m-danger",
|
||||||
message: html`${msg("No workers connected. Background tasks will not run.")}`,
|
message: html`${msg("No workers connected. Background tasks will not run.")}`,
|
||||||
});
|
});
|
||||||
} else if (value.filter((w) => !w.versionMatching).length > 0) {
|
}
|
||||||
|
|
||||||
|
if (value.filter((w) => !w.versionMatching).length > 0) {
|
||||||
return Promise.resolve<AdminStatus>({
|
return Promise.resolve<AdminStatus>({
|
||||||
icon: "fa fa-times-circle pf-m-danger",
|
icon: "fa fa-times-circle pf-m-danger",
|
||||||
message: html`${msg("Worker with incorrect version connected.")}`,
|
message: html`${msg("Worker with incorrect version connected.")}`,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return Promise.resolve<AdminStatus>({
|
|
||||||
icon: "fa fa-check-circle pf-m-success",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.resolve<AdminStatus>({
|
||||||
|
icon: "fa fa-check-circle pf-m-success",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderValue() {
|
renderValue() {
|
||||||
|
|||||||
@ -127,7 +127,7 @@ export class SyncStatusChart extends AKChart<SummarizedSyncStatus[]> {
|
|||||||
msg("LDAP Source"),
|
msg("LDAP Source"),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
this.centerText = statuses.reduce((total, el) => (total += el.total), 0).toString();
|
this.centerText = statuses.reduce((total, el) => total + el.total, 0).toString();
|
||||||
return statuses;
|
return statuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,26 +6,26 @@ import { html } from "lit";
|
|||||||
import "../AdminSettingsFooterLinks.js";
|
import "../AdminSettingsFooterLinks.js";
|
||||||
|
|
||||||
describe("ak-admin-settings-footer-link", () => {
|
describe("ak-admin-settings-footer-link", () => {
|
||||||
afterEach(async () => {
|
afterEach(() => {
|
||||||
await browser.execute(async () => {
|
return browser.execute(() => {
|
||||||
await document.body.querySelector("ak-admin-settings-footer-link")?.remove();
|
document.body.querySelector("ak-admin-settings-footer-link")?.remove();
|
||||||
if (document.body["_$litPart$"]) {
|
|
||||||
// @ts-expect-error expression of type '"_$litPart$"' is added by Lit
|
if ("_$litPart$" in document.body) {
|
||||||
await delete document.body["_$litPart$"];
|
delete document.body._$litPart$;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render an empty control", async () => {
|
it("should render an empty control", async () => {
|
||||||
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
||||||
const link = await $("ak-admin-settings-footer-link");
|
const link = $("ak-admin-settings-footer-link");
|
||||||
await expect(await link.getProperty("isValid")).toStrictEqual(false);
|
await expect(await link.getProperty("isValid")).toStrictEqual(false);
|
||||||
await expect(await link.getProperty("toJson")).toEqual({ name: "", href: "" });
|
await expect(await link.getProperty("toJson")).toEqual({ name: "", href: "" });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not be valid if just a name is filled in", async () => {
|
it("should not be valid if just a name is filled in", async () => {
|
||||||
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
||||||
const link = await $("ak-admin-settings-footer-link");
|
const link = $("ak-admin-settings-footer-link");
|
||||||
await link.$('input[name="name"]').setValue("foo");
|
await link.$('input[name="name"]').setValue("foo");
|
||||||
await expect(await link.getProperty("isValid")).toStrictEqual(false);
|
await expect(await link.getProperty("isValid")).toStrictEqual(false);
|
||||||
await expect(await link.getProperty("toJson")).toEqual({ name: "foo", href: "" });
|
await expect(await link.getProperty("toJson")).toEqual({ name: "foo", href: "" });
|
||||||
@ -33,7 +33,7 @@ describe("ak-admin-settings-footer-link", () => {
|
|||||||
|
|
||||||
it("should be valid if just a URL is filled in", async () => {
|
it("should be valid if just a URL is filled in", async () => {
|
||||||
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
||||||
const link = await $("ak-admin-settings-footer-link");
|
const link = $("ak-admin-settings-footer-link");
|
||||||
await link.$('input[name="href"]').setValue("https://foo.com");
|
await link.$('input[name="href"]').setValue("https://foo.com");
|
||||||
await expect(await link.getProperty("isValid")).toStrictEqual(true);
|
await expect(await link.getProperty("isValid")).toStrictEqual(true);
|
||||||
await expect(await link.getProperty("toJson")).toEqual({
|
await expect(await link.getProperty("toJson")).toEqual({
|
||||||
@ -44,7 +44,7 @@ describe("ak-admin-settings-footer-link", () => {
|
|||||||
|
|
||||||
it("should be valid if both are filled in", async () => {
|
it("should be valid if both are filled in", async () => {
|
||||||
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
||||||
const link = await $("ak-admin-settings-footer-link");
|
const link = $("ak-admin-settings-footer-link");
|
||||||
await link.$('input[name="name"]').setValue("foo");
|
await link.$('input[name="name"]').setValue("foo");
|
||||||
await link.$('input[name="href"]').setValue("https://foo.com");
|
await link.$('input[name="href"]').setValue("https://foo.com");
|
||||||
await expect(await link.getProperty("isValid")).toStrictEqual(true);
|
await expect(await link.getProperty("isValid")).toStrictEqual(true);
|
||||||
@ -56,7 +56,7 @@ describe("ak-admin-settings-footer-link", () => {
|
|||||||
|
|
||||||
it("should not be valid if the URL is not valid", async () => {
|
it("should not be valid if the URL is not valid", async () => {
|
||||||
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
render(html`<ak-admin-settings-footer-link name="link"></ak-admin-settings-footer-link>`);
|
||||||
const link = await $("ak-admin-settings-footer-link");
|
const link = $("ak-admin-settings-footer-link");
|
||||||
await link.$('input[name="name"]').setValue("foo");
|
await link.$('input[name="name"]').setValue("foo");
|
||||||
await link.$('input[name="href"]').setValue("never://foo.com");
|
await link.$('input[name="href"]').setValue("never://foo.com");
|
||||||
await expect(await link.getProperty("toJson")).toEqual({
|
await expect(await link.getProperty("toJson")).toEqual({
|
||||||
|
|||||||
@ -79,7 +79,7 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this.can(CapabilitiesEnum.CanSaveMedia)) {
|
if (this.can(CapabilitiesEnum.CanSaveMedia)) {
|
||||||
const icon = this.getFormFiles()["metaIcon"];
|
const icon = this.getFormFiles().metaIcon;
|
||||||
if (icon || this.clearIcon) {
|
if (icon || this.clearIcon) {
|
||||||
await new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({
|
await new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({
|
||||||
slug: app.slug,
|
slug: app.slug,
|
||||||
@ -117,7 +117,7 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
|
|||||||
if (!(ev instanceof InputEvent) || !ev.target) {
|
if (!(ev instanceof InputEvent) || !ev.target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.clearIcon = !!(ev.target as HTMLInputElement).checked;
|
this.clearIcon = Boolean((ev.target as HTMLInputElement).checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -71,7 +71,7 @@ export class ApplicationListPage extends WithBrandConfig(TablePage<Application>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return super.styles.concat(PFCard, applicationListStyle);
|
return TablePage.styles.concat(PFCard, applicationListStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
columns(): TableColumn[] {
|
columns(): TableColumn[] {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import "@goauthentik/elements/forms/HorizontalFormElement";
|
|||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
import "@goauthentik/elements/forms/Radio";
|
import "@goauthentik/elements/forms/Radio";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
import YAML from "yaml";
|
import * as YAML from "yaml";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { CSSResult } from "lit";
|
import { CSSResult } from "lit";
|
||||||
@ -31,9 +31,8 @@ export class ApplicationEntitlementForm extends ModelForm<ApplicationEntitlement
|
|||||||
getSuccessMessage(): string {
|
getSuccessMessage(): string {
|
||||||
if (this.instance?.pbmUuid) {
|
if (this.instance?.pbmUuid) {
|
||||||
return msg("Successfully updated entitlement.");
|
return msg("Successfully updated entitlement.");
|
||||||
} else {
|
|
||||||
return msg("Successfully created entitlement.");
|
|
||||||
}
|
}
|
||||||
|
return msg("Successfully created entitlement.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
@ -49,11 +48,10 @@ export class ApplicationEntitlementForm extends ModelForm<ApplicationEntitlement
|
|||||||
pbmUuid: this.instance.pbmUuid || "",
|
pbmUuid: this.instance.pbmUuid || "",
|
||||||
applicationEntitlementRequest: data,
|
applicationEntitlementRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsCreate({
|
|
||||||
applicationEntitlementRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new CoreApi(DEFAULT_CONFIG).coreApplicationEntitlementsCreate({
|
||||||
|
applicationEntitlementRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -52,7 +52,6 @@ function renderRadiusOverview(rawProvider: OneOfProvider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderRACOverview(rawProvider: OneOfProvider) {
|
function renderRACOverview(rawProvider: OneOfProvider) {
|
||||||
// @ts-expect-error TS6133
|
|
||||||
const _provider = rawProvider as RACProvider;
|
const _provider = rawProvider as RACProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ export class ApplicationWizardApplicationStep extends ApplicationWizardStep {
|
|||||||
errors = new Map<string, string>();
|
errors = new Map<string, string>();
|
||||||
|
|
||||||
@query("form#applicationform")
|
@query("form#applicationform")
|
||||||
form!: HTMLFormElement;
|
declare form: HTMLFormElement;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -61,18 +61,18 @@ export class ApplicationWizardApplicationStep extends ApplicationWizardStep {
|
|||||||
this.errors = new Map();
|
this.errors = new Map();
|
||||||
const values = trimMany(this.formValues ?? {}, ["metaLaunchUrl", "name", "slug"]);
|
const values = trimMany(this.formValues ?? {}, ["metaLaunchUrl", "name", "slug"]);
|
||||||
|
|
||||||
if (values["name"] === "") {
|
if (values.name === "") {
|
||||||
this.errors.set("name", msg("An application name is required"));
|
this.errors.set("name", msg("An application name is required"));
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
!(
|
!(
|
||||||
isStr(values["metaLaunchUrl"]) &&
|
isStr(values.metaLaunchUrl) &&
|
||||||
(values["metaLaunchUrl"] === "" || URL.canParse(values["metaLaunchUrl"]))
|
(values.metaLaunchUrl === "" || URL.canParse(values.metaLaunchUrl))
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.errors.set("metaLaunchUrl", msg("Not a valid URL"));
|
this.errors.set("metaLaunchUrl", msg("Not a valid URL"));
|
||||||
}
|
}
|
||||||
if (!(isStr(values["slug"]) && values["slug"] !== "" && isSlug(values["slug"]))) {
|
if (!(isStr(values.slug) && values.slug !== "" && isSlug(values.slug))) {
|
||||||
this.errors.set("slug", msg("Not a valid slug"));
|
this.errors.set("slug", msg("Not a valid slug"));
|
||||||
}
|
}
|
||||||
return this.errors.size === 0;
|
return this.errors.size === 0;
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export class ApplicationWizardEditBindingStep extends ApplicationWizardStep {
|
|||||||
hide = true;
|
hide = true;
|
||||||
|
|
||||||
@query("form#bindingform")
|
@query("form#bindingform")
|
||||||
form!: HTMLFormElement;
|
declare form: HTMLFormElement;
|
||||||
|
|
||||||
@query(".policy-search-select")
|
@query(".policy-search-select")
|
||||||
searchSelect!: SearchSelectBase<Policy> | SearchSelectBase<Group> | SearchSelectBase<User>;
|
searchSelect!: SearchSelectBase<Policy> | SearchSelectBase<Group> | SearchSelectBase<User>;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export class ApplicationWizardProviderSamlForm extends ApplicationWizardProvider
|
|||||||
const setHasSigningKp = (ev: InputEvent) => {
|
const setHasSigningKp = (ev: InputEvent) => {
|
||||||
const target = ev.target as AkCryptoCertificateSearch;
|
const target = ev.target as AkCryptoCertificateSearch;
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
this.hasSigningKp = !!target.selectedKeypair;
|
this.hasSigningKp = Boolean(target.selectedKeypair);
|
||||||
};
|
};
|
||||||
|
|
||||||
return html` <ak-wizard-title>${this.label}</ak-wizard-title>
|
return html` <ak-wizard-title>${this.label}</ak-wizard-title>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import "@goauthentik/elements/forms/FormGroup";
|
|||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
import YAML from "yaml";
|
import * as YAML from "yaml";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { CSSResult, TemplateResult, html } from "lit";
|
import { CSSResult, TemplateResult, html } from "lit";
|
||||||
@ -59,11 +59,10 @@ export class BlueprintForm extends ModelForm<BlueprintInstance, string> {
|
|||||||
instanceUuid: this.instance.pk,
|
instanceUuid: this.instance.pk,
|
||||||
blueprintInstanceRequest: data,
|
blueprintInstanceRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new ManagedApi(DEFAULT_CONFIG).managedBlueprintsCreate({
|
|
||||||
blueprintInstanceRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new ManagedApi(DEFAULT_CONFIG).managedBlueprintsCreate({
|
||||||
|
blueprintInstanceRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import "@goauthentik/elements/forms/HorizontalFormElement";
|
|||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand";
|
import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||||
import YAML from "yaml";
|
import * as YAML from "yaml";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { TemplateResult, html } from "lit";
|
import { TemplateResult, html } from "lit";
|
||||||
@ -43,11 +43,10 @@ export class BrandForm extends ModelForm<Brand, string> {
|
|||||||
brandUuid: this.instance.brandUuid,
|
brandUuid: this.instance.brandUuid,
|
||||||
brandRequest: data,
|
brandRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreBrandsCreate({
|
|
||||||
brandRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new CoreApi(DEFAULT_CONFIG).coreBrandsCreate({
|
||||||
|
brandRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -107,7 +107,7 @@ export class AkCryptoCertificateSearch extends CustomListenerElement(AKElement)
|
|||||||
selected(item: CertificateKeyPair, items: CertificateKeyPair[]) {
|
selected(item: CertificateKeyPair, items: CertificateKeyPair[]) {
|
||||||
return (
|
return (
|
||||||
(this.singleton && !this.certificate && items.length === 1) ||
|
(this.singleton && !this.certificate && items.length === 1) ||
|
||||||
(!!this.certificate && this.certificate === item.pk)
|
(Boolean(this.certificate) && this.certificate === item.pk)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,7 @@ const metadata: Meta<AkCryptoCertificateSearch> = {
|
|||||||
argTypes: {
|
argTypes: {
|
||||||
// Typescript is unaware that arguments for components are treated as properties, and
|
// Typescript is unaware that arguments for components are treated as properties, and
|
||||||
// properties are typically renamed to lower case, even if the variable is not.
|
// properties are typically renamed to lower case, even if the variable is not.
|
||||||
// @ts-expect-error
|
// @ts-expect-error TODO: Explain.
|
||||||
nokey: {
|
nokey: {
|
||||||
control: "boolean",
|
control: "boolean",
|
||||||
description:
|
description:
|
||||||
@ -75,7 +75,7 @@ export const CryptoCertificateSearch = () => {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const showMessage = (ev: CustomEvent<any>) => {
|
const showMessage = (ev: CustomEvent<any>) => {
|
||||||
const detail = ev.detail;
|
const detail = ev.detail;
|
||||||
delete detail["target"];
|
delete detail.target;
|
||||||
document.getElementById("message-pad")!.innerText = `Event: ${JSON.stringify(
|
document.getElementById("message-pad")!.innerText = `Event: ${JSON.stringify(
|
||||||
detail,
|
detail,
|
||||||
null,
|
null,
|
||||||
|
|||||||
@ -30,11 +30,10 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
|
|||||||
kpUuid: this.instance.pk || "",
|
kpUuid: this.instance.pk || "",
|
||||||
patchedCertificateKeyPairRequest: data,
|
patchedCertificateKeyPairRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsCreate({
|
|
||||||
certificateKeyPairRequest: data as unknown as CertificateKeyPairRequest,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsCreate({
|
||||||
|
certificateKeyPairRequest: data as unknown as CertificateKeyPairRequest,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -51,11 +51,10 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
|
|||||||
pbmUuid: this.instance.pk || "",
|
pbmUuid: this.instance.pk || "",
|
||||||
notificationRuleRequest: data,
|
notificationRuleRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new EventsApi(DEFAULT_CONFIG).eventsRulesCreate({
|
|
||||||
notificationRuleRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new EventsApi(DEFAULT_CONFIG).eventsRulesCreate({
|
||||||
|
notificationRuleRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -47,11 +47,10 @@ export class TransportForm extends ModelForm<NotificationTransport, string> {
|
|||||||
uuid: this.instance.pk || "",
|
uuid: this.instance.pk || "",
|
||||||
notificationTransportRequest: data,
|
notificationTransportRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new EventsApi(DEFAULT_CONFIG).eventsTransportsCreate({
|
|
||||||
notificationTransportRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new EventsApi(DEFAULT_CONFIG).eventsTransportsCreate({
|
||||||
|
notificationTransportRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onModeChange(mode: string | undefined): void {
|
onModeChange(mode: string | undefined): void {
|
||||||
|
|||||||
@ -58,7 +58,7 @@ export class FlowForm extends WithCapabilitiesConfig(ModelForm<Flow, string>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.can(CapabilitiesEnum.CanSaveMedia)) {
|
if (this.can(CapabilitiesEnum.CanSaveMedia)) {
|
||||||
const icon = this.getFormFiles()["background"];
|
const icon = this.getFormFiles().background;
|
||||||
if (icon || this.clearBackground) {
|
if (icon || this.clearBackground) {
|
||||||
await new FlowsApi(DEFAULT_CONFIG).flowsInstancesSetBackgroundCreate({
|
await new FlowsApi(DEFAULT_CONFIG).flowsInstancesSetBackgroundCreate({
|
||||||
slug: flow.slug,
|
slug: flow.slug,
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export class FlowImportForm extends Form<Flow> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async send(): Promise<FlowImportResult> {
|
async send(): Promise<FlowImportResult> {
|
||||||
const file = this.getFormFiles()["flow"];
|
const file = this.getFormFiles().flow;
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw new SentryIgnoredError("No form data");
|
throw new SentryIgnoredError("No form data");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,9 +39,8 @@ export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
|
|||||||
getSuccessMessage(): string {
|
getSuccessMessage(): string {
|
||||||
if (this.instance?.pk) {
|
if (this.instance?.pk) {
|
||||||
return msg("Successfully updated binding.");
|
return msg("Successfully updated binding.");
|
||||||
} else {
|
|
||||||
return msg("Successfully created binding.");
|
|
||||||
}
|
}
|
||||||
|
return msg("Successfully created binding.");
|
||||||
}
|
}
|
||||||
|
|
||||||
send(data: FlowStageBinding): Promise<unknown> {
|
send(data: FlowStageBinding): Promise<unknown> {
|
||||||
@ -50,14 +49,13 @@ export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
|
|||||||
fsbUuid: this.instance.pk,
|
fsbUuid: this.instance.pk,
|
||||||
patchedFlowStageBindingRequest: data,
|
patchedFlowStageBindingRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
if (this.targetPk) {
|
|
||||||
data.target = this.targetPk;
|
|
||||||
}
|
|
||||||
return new FlowsApi(DEFAULT_CONFIG).flowsBindingsCreate({
|
|
||||||
flowStageBindingRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (this.targetPk) {
|
||||||
|
data.target = this.targetPk;
|
||||||
|
}
|
||||||
|
return new FlowsApi(DEFAULT_CONFIG).flowsBindingsCreate({
|
||||||
|
flowStageBindingRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOrder(): Promise<number> {
|
async getOrder(): Promise<number> {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import "@goauthentik/elements/chips/ChipGroup";
|
|||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
import YAML from "yaml";
|
import * as YAML from "yaml";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
@ -55,12 +55,11 @@ export class GroupForm extends ModelForm<Group, string> {
|
|||||||
groupUuid: this.instance.pk,
|
groupUuid: this.instance.pk,
|
||||||
patchedGroupRequest: data,
|
patchedGroupRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
data.users = [];
|
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsCreate({
|
|
||||||
groupRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
data.users = [];
|
||||||
|
return new CoreApi(DEFAULT_CONFIG).coreGroupsCreate({
|
||||||
|
groupRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -125,7 +125,8 @@ export class RelatedGroupList extends Table<Group> {
|
|||||||
buttonLabel=${msg("Remove")}
|
buttonLabel=${msg("Remove")}
|
||||||
.objects=${this.selectedElements}
|
.objects=${this.selectedElements}
|
||||||
.delete=${(item: Group) => {
|
.delete=${(item: Group) => {
|
||||||
if (!this.targetUser) return;
|
if (!this.targetUser) return null;
|
||||||
|
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsRemoveUserCreate({
|
return new CoreApi(DEFAULT_CONFIG).coreGroupsRemoveUserCreate({
|
||||||
groupUuid: item.pk,
|
groupUuid: item.pk,
|
||||||
userAccountRequest: {
|
userAccountRequest: {
|
||||||
|
|||||||
@ -46,8 +46,12 @@ import {
|
|||||||
User,
|
User,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
interface AddUsersToGroupFormData {
|
||||||
|
users: number[];
|
||||||
|
}
|
||||||
|
|
||||||
@customElement("ak-user-related-add")
|
@customElement("ak-user-related-add")
|
||||||
export class RelatedUserAdd extends Form<{ users: number[] }> {
|
export class RelatedUserAdd extends Form<AddUsersToGroupFormData> {
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
group?: Group;
|
group?: Group;
|
||||||
|
|
||||||
@ -58,7 +62,7 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
|
|||||||
return msg("Successfully added user(s).");
|
return msg("Successfully added user(s).");
|
||||||
}
|
}
|
||||||
|
|
||||||
async send(data: { users: number[] }): Promise<{ users: number[] }> {
|
async send(data: AddUsersToGroupFormData): Promise<AddUsersToGroupFormData> {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
data.users.map((user) => {
|
data.users.map((user) => {
|
||||||
return new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
|
return new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
|
||||||
@ -69,6 +73,7 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +138,7 @@ export class RelatedUserList extends WithBrandConfig(WithCapabilitiesConfig(Tabl
|
|||||||
me?: SessionUser;
|
me?: SessionUser;
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return super.styles.concat(PFDescriptionList, PFAlert, PFBanner);
|
return Table.styles.concat(PFDescriptionList, PFAlert, PFBanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
async apiEndpoint(): Promise<PaginatedResponse<User>> {
|
async apiEndpoint(): Promise<PaginatedResponse<User>> {
|
||||||
|
|||||||
@ -65,7 +65,7 @@ export class OutpostDeploymentModal extends ModalButton {
|
|||||||
</label>
|
</label>
|
||||||
<input class="pf-c-form-control" readonly type="text" value="true" />
|
<input class="pf-c-form-control" readonly type="text" value="true" />
|
||||||
</div>
|
</div>
|
||||||
${this.outpost?.type == OutpostTypeEnum.Proxy
|
${this.outpost?.type === OutpostTypeEnum.Proxy
|
||||||
? html`
|
? html`
|
||||||
<h3>
|
<h3>
|
||||||
${msg(
|
${msg(
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import "@goauthentik/elements/forms/HorizontalFormElement";
|
|||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
|
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
|
||||||
import YAML from "yaml";
|
import * as YAML from "yaml";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { TemplateResult, html } from "lit";
|
import { TemplateResult, html } from "lit";
|
||||||
@ -129,11 +129,10 @@ export class OutpostForm extends ModelForm<Outpost, string> {
|
|||||||
uuid: this.instance.pk || "",
|
uuid: this.instance.pk || "",
|
||||||
outpostRequest: data,
|
outpostRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsInstancesCreate({
|
|
||||||
outpostRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new OutpostsApi(DEFAULT_CONFIG).outpostsInstancesCreate({
|
||||||
|
outpostRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -32,11 +32,10 @@ export class ServiceConnectionDockerForm extends ModelForm<DockerServiceConnecti
|
|||||||
uuid: this.instance.pk || "",
|
uuid: this.instance.pk || "",
|
||||||
dockerServiceConnectionRequest: data,
|
dockerServiceConnectionRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsDockerCreate({
|
|
||||||
dockerServiceConnectionRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsDockerCreate({
|
||||||
|
dockerServiceConnectionRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import "@goauthentik/elements/CodeMirror";
|
|||||||
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
import YAML from "yaml";
|
import * as YAML from "yaml";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { TemplateResult, html } from "lit";
|
import { TemplateResult, html } from "lit";
|
||||||
@ -36,11 +36,10 @@ export class ServiceConnectionKubernetesForm extends ModelForm<
|
|||||||
uuid: this.instance.pk || "",
|
uuid: this.instance.pk || "",
|
||||||
kubernetesServiceConnectionRequest: data,
|
kubernetesServiceConnectionRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsKubernetesCreate({
|
|
||||||
kubernetesServiceConnectionRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsKubernetesCreate({
|
||||||
|
kubernetesServiceConnectionRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -72,9 +72,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
|||||||
return msg(str`Group ${item.groupObj?.name}`);
|
return msg(str`Group ${item.groupObj?.name}`);
|
||||||
} else if (item.user) {
|
} else if (item.user) {
|
||||||
return msg(str`User ${item.userObj?.name}`);
|
return msg(str`User ${item.userObj?.name}`);
|
||||||
} else {
|
|
||||||
return msg("-");
|
|
||||||
}
|
}
|
||||||
|
return msg("-");
|
||||||
}
|
}
|
||||||
|
|
||||||
getPolicyUserGroupRow(item: PolicyBinding): TemplateResult {
|
getPolicyUserGroupRow(item: PolicyBinding): TemplateResult {
|
||||||
@ -123,9 +122,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
|||||||
${msg("Edit User")}
|
${msg("Edit User")}
|
||||||
</button>
|
</button>
|
||||||
</ak-forms-modal>`;
|
</ak-forms-modal>`;
|
||||||
} else {
|
|
||||||
return html``;
|
|
||||||
}
|
}
|
||||||
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderToolbarSelected(): TemplateResult {
|
renderToolbarSelected(): TemplateResult {
|
||||||
|
|||||||
@ -72,9 +72,8 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
|
|||||||
getSuccessMessage(): string {
|
getSuccessMessage(): string {
|
||||||
if (this.instance?.pk) {
|
if (this.instance?.pk) {
|
||||||
return msg("Successfully updated binding.");
|
return msg("Successfully updated binding.");
|
||||||
} else {
|
|
||||||
return msg("Successfully created binding.");
|
|
||||||
}
|
}
|
||||||
|
return msg("Successfully created binding.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
@ -111,11 +110,10 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
|
|||||||
policyBindingUuid: this.instance.pk,
|
policyBindingUuid: this.instance.pk,
|
||||||
policyBindingRequest: data,
|
policyBindingRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsCreate({
|
|
||||||
policyBindingRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsCreate({
|
||||||
|
policyBindingRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOrder(): Promise<number> {
|
async getOrder(): Promise<number> {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import "@goauthentik/elements/events/LogViewer";
|
|||||||
import { Form } from "@goauthentik/elements/forms/Form";
|
import { Form } from "@goauthentik/elements/forms/Form";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
import YAML from "yaml";
|
import * as YAML from "yaml";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { CSSResult, TemplateResult, html } from "lit";
|
import { CSSResult, TemplateResult, html } from "lit";
|
||||||
|
|||||||
@ -25,11 +25,11 @@ export class DummyPolicyForm extends BasePolicyForm<DummyPolicy> {
|
|||||||
policyUuid: this.instance.pk || "",
|
policyUuid: this.instance.pk || "",
|
||||||
dummyPolicyRequest: data,
|
dummyPolicyRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new PoliciesApi(DEFAULT_CONFIG).policiesDummyCreate({
|
|
||||||
dummyPolicyRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesDummyCreate({
|
||||||
|
dummyPolicyRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -37,11 +37,10 @@ export class EventMatcherPolicyForm extends BasePolicyForm<EventMatcherPolicy> {
|
|||||||
policyUuid: this.instance.pk || "",
|
policyUuid: this.instance.pk || "",
|
||||||
eventMatcherPolicyRequest: data,
|
eventMatcherPolicyRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new PoliciesApi(DEFAULT_CONFIG).policiesEventMatcherCreate({
|
|
||||||
eventMatcherPolicyRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesEventMatcherCreate({
|
||||||
|
eventMatcherPolicyRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -25,11 +25,10 @@ export class PasswordExpiryPolicyForm extends BasePolicyForm<PasswordExpiryPolic
|
|||||||
policyUuid: this.instance.pk || "",
|
policyUuid: this.instance.pk || "",
|
||||||
passwordExpiryPolicyRequest: data,
|
passwordExpiryPolicyRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new PoliciesApi(DEFAULT_CONFIG).policiesPasswordExpiryCreate({
|
|
||||||
passwordExpiryPolicyRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesPasswordExpiryCreate({
|
||||||
|
passwordExpiryPolicyRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -28,11 +28,10 @@ export class ExpressionPolicyForm extends BasePolicyForm<ExpressionPolicy> {
|
|||||||
policyUuid: this.instance.pk || "",
|
policyUuid: this.instance.pk || "",
|
||||||
expressionPolicyRequest: data,
|
expressionPolicyRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new PoliciesApi(DEFAULT_CONFIG).policiesExpressionCreate({
|
|
||||||
expressionPolicyRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesExpressionCreate({
|
||||||
|
expressionPolicyRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -39,11 +39,10 @@ export class GeoIPPolicyForm extends BasePolicyForm<GeoIPPolicy> {
|
|||||||
policyUuid: this.instance.pk || "",
|
policyUuid: this.instance.pk || "",
|
||||||
geoIPPolicyRequest: data,
|
geoIPPolicyRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new PoliciesApi(DEFAULT_CONFIG).policiesGeoipCreate({
|
|
||||||
geoIPPolicyRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesGeoipCreate({
|
||||||
|
geoIPPolicyRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
@ -38,11 +38,10 @@ export class PasswordPolicyForm extends BasePolicyForm<PasswordPolicy> {
|
|||||||
policyUuid: this.instance.pk || "",
|
policyUuid: this.instance.pk || "",
|
||||||
passwordPolicyRequest: data,
|
passwordPolicyRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new PoliciesApi(DEFAULT_CONFIG).policiesPasswordCreate({
|
|
||||||
passwordPolicyRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesPasswordCreate({
|
||||||
|
passwordPolicyRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderStaticRules(): TemplateResult {
|
renderStaticRules(): TemplateResult {
|
||||||
|
|||||||
@ -25,11 +25,10 @@ export class ReputationPolicyForm extends BasePolicyForm<ReputationPolicy> {
|
|||||||
policyUuid: this.instance.pk || "",
|
policyUuid: this.instance.pk || "",
|
||||||
reputationPolicyRequest: data,
|
reputationPolicyRequest: data,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return new PoliciesApi(DEFAULT_CONFIG).policiesReputationCreate({
|
|
||||||
reputationPolicyRequest: data,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesReputationCreate({
|
||||||
|
reputationPolicyRequest: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user