diff --git a/web/.storybook/main.js b/web/.storybook/main.js index ac6c5eb8407c..dbfce93a9834 100644 --- a/web/.storybook/main.js +++ b/web/.storybook/main.js @@ -3,13 +3,10 @@ * @import { StorybookConfig } from "@storybook/web-components-vite"; * @import { InlineConfig, Plugin } from "vite"; */ -import { cwd } from "process"; import postcssLit from "rollup-plugin-postcss-lit"; import tsconfigPaths from "vite-tsconfig-paths"; -const NODE_ENV = process.env.NODE_ENV || "development"; - -const CSSImportPattern = /import [\w\$]+ from .+\.(css)/g; +const CSSImportPattern = /import [\w$]+ from .+\.(css)/g; const JavaScriptFilePattern = /\.m?(js|ts|tsx)$/; /** @@ -30,6 +27,11 @@ const inlineCSSPlugin = { }, }; +/** + * @satisfies {InlineConfig} + */ +// const viteFinal = ; + /** * @satisfies {StorybookConfig} */ @@ -48,22 +50,21 @@ const config = { docs: { autodocs: "tag", }, - viteFinal({ plugins = [], ...config }) { + async viteFinal(config) { + const [{ mergeConfig }, { createBundleDefinitions }] = await Promise.all([ + import("vite"), + import("@goauthentik/web/bundler/utils/node"), + ]); + /** * @satisfies {InlineConfig} */ - const mergedConfig = { - ...config, - define: { - "process.env.NODE_ENV": JSON.stringify(NODE_ENV), - "process.env.CWD": JSON.stringify(cwd()), - "process.env.AK_API_BASE_PATH": JSON.stringify(process.env.AK_API_BASE_PATH || ""), - }, - plugins: [inlineCSSPlugin, ...plugins, postcssLit(), tsconfigPaths()], + const overrides = { + define: createBundleDefinitions(), + plugins: [inlineCSSPlugin, postcssLit(), tsconfigPaths()], }; - return mergedConfig; + return mergeConfig(config, overrides); }, }; - export default config; diff --git a/web/scripts/esbuild/build-mdx-plugin.mjs b/web/bundler/mdx-plugin/node.js similarity index 93% rename from web/scripts/esbuild/build-mdx-plugin.mjs rename to web/bundler/mdx-plugin/node.js index c6f55339150f..1e899298f868 100644 --- a/web/scripts/esbuild/build-mdx-plugin.mjs +++ b/web/bundler/mdx-plugin/node.js @@ -1,10 +1,12 @@ /** + * @file MDX plugin for ESBuild. + * * @import { - OnLoadArgs, - OnLoadResult, - Plugin, - PluginBuild - * } from 'esbuild' + * OnLoadArgs, + * OnLoadResult, + * Plugin, + * PluginBuild + * } from "esbuild" */ import * as fs from "node:fs/promises"; import * as path from "node:path"; diff --git a/web/bundler/utils/node.js b/web/bundler/utils/node.js new file mode 100644 index 000000000000..827fd4098364 --- /dev/null +++ b/web/bundler/utils/node.js @@ -0,0 +1,29 @@ +/** + * @file Bundler utilities. + */ +import { NodeEnvironment, serializeEnvironmentVars } from "@goauthentik/core/environment/node"; +import { AuthentikVersion } from "@goauthentik/core/version/node"; + +/** + * Creates a mapping of environment variables to their respective runtime constants. + */ +export function createBundleDefinitions() { + const SerializedNodeEnvironment = /** @type {`"development"` | `"production"`} */ ( + JSON.stringify(NodeEnvironment) + ); + + /** + * @satisfies {Record} + */ + const envRecord = { + AK_VERSION: AuthentikVersion, + AK_API_BASE_PATH: process.env.AK_API_BASE_PATH ?? "", + }; + + return { + ...serializeEnvironmentVars(envRecord), + // We need to explicitly set this for NPM packages that use `process` + // to determine their environment. + "process.env.NODE_ENV": SerializedNodeEnvironment, + }; +} diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index 1d3fd5911daf..fc2777eb72ad 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -12,6 +12,7 @@ export default [ { ignores: [ "dist/", + "out/", // don't lint the cache ".wireit/", // let packages have their own configurations @@ -71,7 +72,7 @@ export default [ ...globals.node, }, }, - files: ["scripts/**/*.mjs", "*.ts", "*.mjs"], + files: ["scripts/**/*.mjs", "*.ts", "*.mjs", "**/node.js"], rules: { "no-unused-vars": "off", // We WANT our scripts to output to the console! diff --git a/web/package-lock.json b/web/package-lock.json index 81837c51e2f0..6b04513dac4d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.0", "license": "MIT", "workspaces": [ - ".", "./packages/*" ], "dependencies": { @@ -72,21 +71,21 @@ }, "devDependencies": { "@eslint/js": "^9.11.1", + "@goauthentik/core": "^1.0.0", "@goauthentik/esbuild-plugin-live-reload": "^1.0.4", - "@goauthentik/monorepo": "^1.0.0", "@goauthentik/prettier-config": "^1.0.4", "@goauthentik/tsconfig": "^1.0.4", "@hcaptcha/types": "^1.0.4", "@lit/localize-tools": "^0.8.0", "@rollup/plugin-replace": "^6.0.1", - "@storybook/addon-essentials": "^8.6.12", + "@storybook/addon-essentials": "^8.6.14", "@storybook/addon-links": "^8.6.12", "@storybook/blocks": "^8.6.12", - "@storybook/experimental-addon-test": "^8.6.12", - "@storybook/manager-api": "^8.6.12", - "@storybook/test": "^8.6.12", - "@storybook/web-components": "^8.6.12", - "@storybook/web-components-vite": "^8.6.12", + "@storybook/experimental-addon-test": "^8.6.14", + "@storybook/manager-api": "^8.6.14", + "@storybook/test": "^8.6.14", + "@storybook/web-components": "^8.6.14", + "@storybook/web-components-vite": "^8.6.14", "@trivago/prettier-plugin-sort-imports": "^5.2.2", "@types/chart.js": "^2.9.41", "@types/codemirror": "^5.60.15", @@ -119,10 +118,10 @@ "prettier": "^3.3.3", "pseudolocale": "^2.1.0", "rollup-plugin-postcss-lit": "^2.1.0", - "storybook": "^8.6.12", + "storybook": "^8.6.14", "storybook-addon-mock": "^5.0.0", "turnstile-types": "^1.2.3", - "typescript": "^5.6.2", + "typescript": "^5.8.3", "typescript-eslint": "^8.8.0", "vite-plugin-lit-css": "^2.0.0", "vite-tsconfig-paths": "^5.0.1", @@ -140,6 +139,22 @@ "@rollup/rollup-linux-x64-gnu": "4.23.0" } }, + "../packages/core": { + "name": "@goauthentik/core", + "version": "1.0.0", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "@goauthentik/prettier-config": "^1.0.4", + "@goauthentik/tsconfig": "^1.0.4", + "@types/node": "^22.14.1", + "prettier": "^3.3.3", + "typescript": "^5.6.2" + }, + "engines": { + "node": ">=20.11" + } + }, "../packages/monorepo": { "name": "@goauthentik/monorepo", "version": "1.0.4", @@ -157,9 +172,9 @@ } }, "node_modules/@adobe/css-tools": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", - "integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", + "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==", "dev": true, "license": "MIT" }, @@ -1587,12 +1602,12 @@ "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2025.4.1-1747687715.tgz", "integrity": "sha512-YN1iN+OYrBociCVT55AF4QsxFo4g7tk72QFHPXEkPGhBJC+x50h6lLW30S7FtfbEVRqYmvtBUsIW+iqHFhGvtA==" }, - "node_modules/@goauthentik/esbuild-plugin-live-reload": { - "resolved": "packages/esbuild-plugin-live-reload", + "node_modules/@goauthentik/core": { + "resolved": "packages/core", "link": true }, - "node_modules/@goauthentik/monorepo": { - "resolved": "packages/monorepo", + "node_modules/@goauthentik/esbuild-plugin-live-reload": { + "resolved": "packages/esbuild-plugin-live-reload", "link": true }, "node_modules/@goauthentik/prettier-config": { @@ -1621,10 +1636,6 @@ "node": ">=20.11" } }, - "node_modules/@goauthentik/web": { - "resolved": "", - "link": true - }, "node_modules/@goauthentik/web-sfe": { "resolved": "packages/sfe", "link": true @@ -3610,9 +3621,9 @@ } }, "node_modules/@storybook/addon-actions": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.6.12.tgz", - "integrity": "sha512-B5kfiRvi35oJ0NIo53CGH66H471A3XTzrfaa6SxXEJsgxxSeKScG5YeXcCvLiZfvANRQ7QDsmzPUgg0o3hdMXw==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.6.14.tgz", + "integrity": "sha512-mDQxylxGGCQSK7tJPkD144J8jWh9IU9ziJMHfB84PKpI/V5ZgqMDnpr2bssTrUaGDqU5e1/z8KcRF+Melhs9pQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3627,13 +3638,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-backgrounds": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.6.12.tgz", - "integrity": "sha512-lmIAma9BiiCTbJ8YfdZkXjpnAIrOUcgboLkt1f6XJ78vNEMnLNzD9gnh7Tssz1qrqvm34v9daDjIb+ggdiKp3Q==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.6.14.tgz", + "integrity": "sha512-l9xS8qWe5n4tvMwth09QxH2PmJbCctEvBAc1tjjRasAfrd69f7/uFK4WhwJAstzBTNgTc8VXI4w8ZR97i1sFbg==", "dev": true, "license": "MIT", "dependencies": { @@ -3646,13 +3657,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-controls": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.6.12.tgz", - "integrity": "sha512-9VSRPJWQVb9wLp21uvpxDGNctYptyUX0gbvxIWOHMH3R2DslSoq41lsC/oQ4l4zSHVdL+nq8sCTkhBxIsjKqdQ==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.6.14.tgz", + "integrity": "sha512-IiQpkNJdiRyA4Mq9mzjZlvQugL/aE7hNgVxBBGPiIZG6wb6Ht9hNnBYpap5ZXXFKV9p2qVI0FZK445ONmAa+Cw==", "dev": true, "license": "MIT", "dependencies": { @@ -3665,20 +3676,20 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-docs": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.6.12.tgz", - "integrity": "sha512-kEezQjAf/p3SpDzLABgg4fbT48B6dkT2LiZCKTRmCrJVtuReaAr4R9MMM6Jsph6XjbIj/SvOWf3CMeOPXOs9sg==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.6.14.tgz", + "integrity": "sha512-Obpd0OhAF99JyU5pp5ci17YmpcQtMNgqW2pTXV8jAiiipWpwO++hNDeQmLmlSXB399XjtRDOcDVkoc7rc6JzdQ==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/blocks": "8.6.12", - "@storybook/csf-plugin": "8.6.12", - "@storybook/react-dom-shim": "8.6.12", + "@storybook/blocks": "8.6.14", + "@storybook/csf-plugin": "8.6.14", + "@storybook/react-dom-shim": "8.6.14", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" @@ -3688,25 +3699,25 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-essentials": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.6.12.tgz", - "integrity": "sha512-Y/7e8KFlttaNfv7q2zoHMPdX6hPXHdsuQMAjYl5NG9HOAJREu4XBy4KZpbcozRe4ApZ78rYsN/MO1EuA+bNMIA==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.6.14.tgz", + "integrity": "sha512-5ZZSHNaW9mXMOFkoPyc3QkoNGdJHETZydI62/OASR0lmPlJ1065TNigEo5dJddmZNn0/3bkE8eKMAzLnO5eIdA==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/addon-actions": "8.6.12", - "@storybook/addon-backgrounds": "8.6.12", - "@storybook/addon-controls": "8.6.12", - "@storybook/addon-docs": "8.6.12", - "@storybook/addon-highlight": "8.6.12", - "@storybook/addon-measure": "8.6.12", - "@storybook/addon-outline": "8.6.12", - "@storybook/addon-toolbars": "8.6.12", - "@storybook/addon-viewport": "8.6.12", + "@storybook/addon-actions": "8.6.14", + "@storybook/addon-backgrounds": "8.6.14", + "@storybook/addon-controls": "8.6.14", + "@storybook/addon-docs": "8.6.14", + "@storybook/addon-highlight": "8.6.14", + "@storybook/addon-measure": "8.6.14", + "@storybook/addon-outline": "8.6.14", + "@storybook/addon-toolbars": "8.6.14", + "@storybook/addon-viewport": "8.6.14", "ts-dedent": "^2.0.0" }, "funding": { @@ -3714,13 +3725,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-highlight": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.6.12.tgz", - "integrity": "sha512-9FITVxdoycZ+eXuAZL9ElWyML/0fPPn9UgnnAkrU7zkMi+Segq/Tx7y+WWanC5zfWZrXAuG6WTOYEXeWQdm//w==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.6.14.tgz", + "integrity": "sha512-4H19OJlapkofiE9tM6K/vsepf4ir9jMm9T+zw5L85blJZxhKZIbJ6FO0TCG9PDc4iPt3L6+aq5B0X29s9zicNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3731,7 +3742,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-links": { @@ -3759,9 +3770,9 @@ } }, "node_modules/@storybook/addon-measure": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.6.12.tgz", - "integrity": "sha512-tACmwqqOvutaQSduw8SMb62wICaT1rWaHtMN3vtWXuxgDPSdJQxLP+wdVyRYMAgpxhLyIO7YRf++Hfha9RHgFg==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.6.14.tgz", + "integrity": "sha512-1Tlyb72NX8aAqm6I6OICsUuGOP6hgnXcuFlXucyhKomPa6j3Eu2vKu561t/f0oGtAK2nO93Z70kVaEh5X+vaGw==", "dev": true, "license": "MIT", "dependencies": { @@ -3773,13 +3784,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-outline": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.6.12.tgz", - "integrity": "sha512-1ylwm+n1s40S91No0v9T4tCjZORu3GbnjINlyjYTDLLhQHyBQd3nWR1Y1eewU4xH4cW9SnSLcMQFS/82xHqU6A==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.6.14.tgz", + "integrity": "sha512-CW857JvN6OxGWElqjlzJO2S69DHf+xO3WsEfT5mT3ZtIjmsvRDukdWfDU9bIYUFyA2lFvYjncBGjbK+I91XR7w==", "dev": true, "license": "MIT", "dependencies": { @@ -3791,13 +3802,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-toolbars": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.6.12.tgz", - "integrity": "sha512-HEcSzo1DyFtIu5/ikVOmh5h85C1IvK9iFKSzBR6ice33zBOaehVJK+Z5f487MOXxPsZ63uvWUytwPyViGInj+g==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.6.14.tgz", + "integrity": "sha512-W/wEXT8h3VyZTVfWK/84BAcjAxTdtRiAkT2KAN0nbSHxxB5KEM1MjKpKu2upyzzMa3EywITqbfy4dP6lpkVTwQ==", "dev": true, "license": "MIT", "funding": { @@ -3805,13 +3816,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/addon-viewport": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.6.12.tgz", - "integrity": "sha512-EXK2LArAnABsPP0leJKy78L/lbMWow+EIJfytEP5fHaW4EhMR6h7Hzaqzre6U0IMMr/jVFa1ci+m0PJ0eQc2bw==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.6.14.tgz", + "integrity": "sha512-gNzVQbMqRC+/4uQTPI2ZrWuRHGquTMZpdgB9DrD88VTEjNudP+J6r8myLfr2VvGksBbUMHkGHMXHuIhrBEnXYA==", "dev": true, "license": "MIT", "dependencies": { @@ -3822,13 +3833,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/blocks": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.6.12.tgz", - "integrity": "sha512-DohlTq6HM1jDbHYiXL4ZvZ00VkhpUp5uftzj/CZDLY1fYHRjqtaTwWm2/OpceivMA8zDitLcq5atEZN+f+siTg==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.6.14.tgz", + "integrity": "sha512-rBMHAfA39AGHgkrDze4RmsnQTMw1ND5fGWobr9pDcJdnDKWQWNRD7Nrlxj0gFlN3n4D9lEZhWGdFrCbku7FVAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3842,7 +3853,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "storybook": "^8.6.12" + "storybook": "^8.6.14" }, "peerDependenciesMeta": { "react": { @@ -3854,13 +3865,13 @@ } }, "node_modules/@storybook/builder-vite": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-8.6.12.tgz", - "integrity": "sha512-Gju21ud/3Qw4v2vLNaa5SuJECsI9ICNRr2G0UyCCzRvCHg8jpA9lDReu2NqhLDyFIuDG+ZYT38gcaHEUoNQ8KQ==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-8.6.14.tgz", + "integrity": "sha512-ajWYhy32ksBWxwWHrjwZzyC0Ii5ZTeu5lsqA95Q/EQBB0P5qWlHWGM3AVyv82Mz/ND03ebGy123uVwgf6olnYQ==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "8.6.12", + "@storybook/csf-plugin": "8.6.14", "browser-assert": "^1.2.1", "ts-dedent": "^2.0.0" }, @@ -3869,7 +3880,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12", + "storybook": "^8.6.14", "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" } }, @@ -3887,9 +3898,9 @@ } }, "node_modules/@storybook/components": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.6.12.tgz", - "integrity": "sha512-FiaE8xvCdvKC2arYusgtlDNZ77b8ysr8njAYQZwwaIHjy27TbR2tEpLDCmUwSbANNmivtc/xGEiDDwcNppMWlQ==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.6.14.tgz", + "integrity": "sha512-HNR2mC5I4Z5ek8kTrVZlIY/B8gJGs5b3XdZPBPBopTIN6U/YHXiDyOjY3JlaS4fSG1fVhp/Qp1TpMn1w/9m1pw==", "dev": true, "license": "MIT", "funding": { @@ -3901,13 +3912,13 @@ } }, "node_modules/@storybook/core": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.6.12.tgz", - "integrity": "sha512-t+ZuDzAlsXKa6tLxNZT81gEAt4GNwsKP/Id2wluhmUWD/lwYW0uum1JiPUuanw8xD6TdakCW/7ULZc7aQUBLCQ==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.6.14.tgz", + "integrity": "sha512-1P/w4FSNRqP8j3JQBOi3yGt8PVOgSRbP66Ok520T78eJBeqx9ukCfl912PQZ7SPbW3TIunBwLXMZOjZwBB/JmA==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/theming": "8.6.12", + "@storybook/theming": "8.6.14", "better-opn": "^3.0.2", "browser-assert": "^1.2.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", @@ -3946,9 +3957,9 @@ } }, "node_modules/@storybook/csf-plugin": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.6.12.tgz", - "integrity": "sha512-6s8CnP1aoKPb3XtC0jRLUp8M5vTA8RhGAwQDKUsFpCC7g89JR9CaKs9FY2ZSzsNbjR15uASi7b3K8BzeYumYQg==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.6.14.tgz", + "integrity": "sha512-dErtc9teAuN+eelN8FojzFE635xlq9cNGGGEu0WEmMUQ4iJ8pingvBO1N8X3scz4Ry7KnxX++NNf3J3gpxS8qQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3959,20 +3970,20 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/experimental-addon-test": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/experimental-addon-test/-/experimental-addon-test-8.6.12.tgz", - "integrity": "sha512-auc8Ql0buH0WeaKVuSSuabxIiBWvqvAyxtXCm1sVMkL68GwrX3cmpNMwviz3mvKvM//F8zKi/31HMl1PZ5UnIA==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/experimental-addon-test/-/experimental-addon-test-8.6.14.tgz", + "integrity": "sha512-Ey1WFTRXSx6Tcv2vpxW16fhk03xQKUmsdg0yWKz9llkNVTGqmL5CNMWZ7j1ZnBGneeRJOvxNsz83SwBRrr588A==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^1.2.12", - "@storybook/instrumenter": "8.6.12", - "@storybook/test": "8.6.12", + "@storybook/instrumenter": "8.6.14", + "@storybook/test": "8.6.14", "polished": "^4.2.2", "prompts": "^2.4.0", "ts-dedent": "^2.2.0" @@ -3984,7 +3995,7 @@ "peerDependencies": { "@vitest/browser": "^2.1.1 || ^3.0.0", "@vitest/runner": "^2.1.1 || ^3.0.0", - "storybook": "^8.6.12", + "storybook": "^8.6.14", "vitest": "^2.1.1 || ^3.0.0" }, "peerDependenciesMeta": { @@ -4019,9 +4030,9 @@ } }, "node_modules/@storybook/instrumenter": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.6.12.tgz", - "integrity": "sha512-VK5fYAF8jMwWP/u3YsmSwKGh+FeSY8WZn78flzRUwirp2Eg1WWjsqPRubAk7yTpcqcC/km9YMF3KbqfzRv2s/A==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.6.14.tgz", + "integrity": "sha512-iG4MlWCcz1L7Yu8AwgsnfVAmMbvyRSk700Mfy2g4c8y5O+Cv1ejshE1LBBsCwHgkuqU0H4R0qu4g23+6UnUemQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4033,13 +4044,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/manager-api": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.6.12.tgz", - "integrity": "sha512-O0SpISeJLNTQvhSBOsWzzkCgs8vCjOq1578rwqHlC6jWWm4QmtfdyXqnv7rR1Hk08kQ+Dzqh0uhwHx0nfwy4nQ==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.6.14.tgz", + "integrity": "sha512-ez0Zihuy17udLbfHZQXkGqwtep0mSGgHcNzGN7iZrMP1m+VmNo+7aGCJJdvXi7+iU3yq8weXSQFWg5DqWgLS7g==", "dev": true, "license": "MIT", "funding": { @@ -4051,9 +4062,9 @@ } }, "node_modules/@storybook/preview-api": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.6.12.tgz", - "integrity": "sha512-84FE3Hrs0AYKHqpDZOwx1S/ffOfxBdL65lhCoeI8GoWwCkzwa9zEP3kvXBo/BnEDO7nAfxvMhjASTZXbKRJh5Q==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.6.14.tgz", + "integrity": "sha512-2GhcCd4dNMrnD7eooEfvbfL4I83qAqEyO0CO7JQAmIO6Rxb9BsOLLI/GD5HkvQB73ArTJ+PT50rfaO820IExOQ==", "dev": true, "license": "MIT", "funding": { @@ -4065,9 +4076,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.6.12.tgz", - "integrity": "sha512-51QvoimkBzYs8s3rCYnY5h0cFqLz/Mh0vRcughwYaXckWzDBV8l67WBO5Xf5nBsukCbWyqBVPpEQLww8s7mrLA==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.6.14.tgz", + "integrity": "sha512-0hixr3dOy3f3M+HBofp3jtMQMS+sqzjKNgl7Arfuj3fvjmyXOks/yGjDImySR4imPtEllvPZfhiQNlejheaInw==", "dev": true, "license": "MIT", "funding": { @@ -4077,18 +4088,18 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/test": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.6.12.tgz", - "integrity": "sha512-0BK1Eg+VD0lNMB1BtxqHE3tP9FdkUmohtvWG7cq6lWvMrbCmAmh3VWai3RMCCDOukPFpjabOr8BBRLVvhNpv2w==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.6.14.tgz", + "integrity": "sha512-GkPNBbbZmz+XRdrhMtkxPotCLOQ1BaGNp/gFZYdGDk2KmUWBKmvc5JxxOhtoXM2703IzNFlQHSSNnhrDZYuLlw==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/instrumenter": "8.6.12", + "@storybook/instrumenter": "8.6.14", "@testing-library/dom": "10.4.0", "@testing-library/jest-dom": "6.5.0", "@testing-library/user-event": "14.5.2", @@ -4100,7 +4111,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/test/node_modules/@vitest/spy": { @@ -4117,9 +4128,9 @@ } }, "node_modules/@storybook/theming": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.12.tgz", - "integrity": "sha512-6VjZg8HJ2Op7+KV7ihJpYrDnFtd9D1jrQnUS8LckcpuBXrIEbaut5+34ObY8ssQnSqkk2GwIZBBBQYQBCVvkOw==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.14.tgz", + "integrity": "sha512-r4y+LsiB37V5hzpQo+BM10PaCsp7YlZ0YcZzQP1OCkPlYXmUAFy2VvDKaFRpD8IeNPKug2u4iFm/laDEbs03dg==", "dev": true, "license": "MIT", "funding": { @@ -4131,17 +4142,17 @@ } }, "node_modules/@storybook/web-components": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-8.6.12.tgz", - "integrity": "sha512-j+609VT8abBlpV+tB/vqSRO/fKA1QpnKWlbE0JpolzmEbgla//pAZomPysoOnvTLL3lSX3conjiAAaTpwbjyLg==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-8.6.14.tgz", + "integrity": "sha512-Jczq7EbIR3EJXX/n+0bKLW8mZS2g5Q57Y67fkw2hNr2E81OBL/4XSU9Dv4pZJXCstE1Ta+ELHj/fqbBbTj7QZA==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/components": "8.6.12", + "@storybook/components": "8.6.14", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "8.6.12", - "@storybook/preview-api": "8.6.12", - "@storybook/theming": "8.6.12", + "@storybook/manager-api": "8.6.14", + "@storybook/preview-api": "8.6.14", + "@storybook/theming": "8.6.14", "tiny-invariant": "^1.3.1", "ts-dedent": "^2.0.0" }, @@ -4154,18 +4165,18 @@ }, "peerDependencies": { "lit": "^2.0.0 || ^3.0.0", - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@storybook/web-components-vite": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-8.6.12.tgz", - "integrity": "sha512-1YVnkk7O9zPF5xTeWD5AxpmfCx9M7C9Du8pIwcypjHQLnb34PwiyjMRztYm/JKh5kCl4BZg187r2j3Q258ytHQ==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-8.6.14.tgz", + "integrity": "sha512-7lxz/hFMTSlhl1gkjqmEp9SchSHcoDCMJTu7LuM6fJWKLHydYB6zwIyL+qYvKDa+E+kgmUKc54yW5SqAWHkjoA==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/builder-vite": "8.6.12", - "@storybook/web-components": "8.6.12", + "@storybook/builder-vite": "8.6.14", + "@storybook/web-components": "8.6.14", "magic-string": "^0.30.0" }, "engines": { @@ -4176,7 +4187,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.6.12" + "storybook": "^8.6.14" } }, "node_modules/@swagger-api/apidom-ast": { @@ -16090,7 +16101,8 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-extensions": { "version": "2.0.0", @@ -16498,6 +16510,7 @@ "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", "dev": true, + "license": "MIT", "dependencies": { "map-or-similar": "^1.5.0" } @@ -21294,13 +21307,13 @@ "optional": true }, "node_modules/storybook": { - "version": "8.6.12", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.6.12.tgz", - "integrity": "sha512-Z/nWYEHBTLK1ZBtAWdhxC0l5zf7ioJ7G4+zYqtTdYeb67gTnxNj80gehf8o8QY9L2zA2+eyMRGLC2V5fI7Z3Tw==", + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.6.14.tgz", + "integrity": "sha512-sVKbCj/OTx67jhmauhxc2dcr1P+yOgz/x3h0krwjyMgdc5Oubvxyg4NYDZmzAw+ym36g/lzH8N0Ccp4dwtdfxw==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/core": "8.6.12" + "@storybook/core": "8.6.14" }, "bin": { "getstorybook": "bin/index.cjs", @@ -22771,10 +22784,11 @@ } }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -24867,6 +24881,38 @@ "url": "https://github.com/sponsors/wooorm" } }, + "packages/core": { + "name": "@goauthentik/core", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@goauthentik/prettier-config": "^1.0.4", + "@goauthentik/tsconfig": "^1.0.4", + "@types/node": "^22.14.1", + "prettier": "^3.3.3", + "typescript": "^5.6.2" + }, + "engines": { + "node": ">=20.11" + } + }, + "packages/core/node_modules/@types/node": { + "version": "22.15.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.19.tgz", + "integrity": "sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "packages/core/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, "packages/esbuild-plugin-live-reload": { "name": "@goauthentik/esbuild-plugin-live-reload", "version": "1.0.4", @@ -24910,6 +24956,7 @@ "packages/monorepo": { "name": "@goauthentik/monorepo", "version": "1.0.0", + "extraneous": true, "license": "MIT", "devDependencies": { "@goauthentik/prettier-config": "^1.0.4", @@ -24922,23 +24969,6 @@ "node": ">=20.11" } }, - "packages/monorepo/node_modules/@types/node": { - "version": "22.15.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", - "integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "packages/monorepo/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, "packages/sfe": { "name": "@goauthentik/web-sfe", "version": "0.0.0", diff --git a/web/package.json b/web/package.json index 78b2e8935477..a320315a3938 100644 --- a/web/package.json +++ b/web/package.json @@ -35,15 +35,52 @@ "type": "module", "exports": { "./package.json": "./package.json", - "./paths": "./paths.js", - "./scripts/*": "./scripts/*.mjs", "./elements/*": "./src/elements/*", "./common/*": "./src/common/*", "./components/*": "./src/components/*", "./flow/*": "./src/flow/*", "./locales/*": "./src/locales/*", "./user/*": "./src/user/*", - "./admin/*": "./src/admin/*" + "./admin/*": "./src/admin/*", + "./*/browser": { + "types": "./out/*/browser.d.ts", + "import": "./*/browser.js" + }, + "./*/node": { + "types": "./out/*/node.d.ts", + "import": "./*/node.js" + }, + "./*": { + "types": "./out/*/index.d.ts", + "import": "./*/index.js" + } + }, + "imports": { + "#common/*.css": "./src/common/*.css", + "#common/*": "./src/common/*.js", + "#elements/*.css": "./src/elements/*.css", + "#elements/*": "./src/elements/*.js", + "#components/*.css": "./src/components/*.css", + "#components/*": "./src/components/*.js", + "#user/*.css": "./src/user/*.css", + "#user/*": "./src/user/*.js", + "#admin/*.css": "./src/admin/*.css", + "#admin/*": "./src/admin/*.js", + "#flow/*.css": "./src/flow/*.css", + "#flow/*": "./src/flow/*.js", + "#stories/*": "./src/stories/*.js", + "#*/browser": { + "types": "./out/*/browser.d.ts", + "import": "./*/browser.js" + }, + "#*/node": { + "types": "./out/*/node.d.ts", + "import": "./*/node.js" + }, + "#*": { + "types": "./out/*/index.d.ts", + "import": "./*/index.js" + } }, "dependencies": { "@codemirror/lang-css": "^6.3.1", @@ -105,21 +142,21 @@ }, "devDependencies": { "@eslint/js": "^9.11.1", + "@goauthentik/core": "^1.0.0", "@goauthentik/esbuild-plugin-live-reload": "^1.0.4", - "@goauthentik/monorepo": "^1.0.0", "@goauthentik/prettier-config": "^1.0.4", "@goauthentik/tsconfig": "^1.0.4", "@hcaptcha/types": "^1.0.4", "@lit/localize-tools": "^0.8.0", "@rollup/plugin-replace": "^6.0.1", - "@storybook/addon-essentials": "^8.6.12", + "@storybook/addon-essentials": "^8.6.14", "@storybook/addon-links": "^8.6.12", "@storybook/blocks": "^8.6.12", - "@storybook/experimental-addon-test": "^8.6.12", - "@storybook/manager-api": "^8.6.12", - "@storybook/test": "^8.6.12", - "@storybook/web-components": "^8.6.12", - "@storybook/web-components-vite": "^8.6.12", + "@storybook/experimental-addon-test": "^8.6.14", + "@storybook/manager-api": "^8.6.14", + "@storybook/test": "^8.6.14", + "@storybook/web-components": "^8.6.14", + "@storybook/web-components-vite": "^8.6.14", "@trivago/prettier-plugin-sort-imports": "^5.2.2", "@types/chart.js": "^2.9.41", "@types/codemirror": "^5.60.15", @@ -152,10 +189,10 @@ "prettier": "^3.3.3", "pseudolocale": "^2.1.0", "rollup-plugin-postcss-lit": "^2.1.0", - "storybook": "^8.6.12", + "storybook": "^8.6.14", "storybook-addon-mock": "^5.0.0", "turnstile-types": "^1.2.3", - "typescript": "^5.6.2", + "typescript": "^5.8.3", "typescript-eslint": "^8.8.0", "vite-plugin-lit-css": "^2.0.0", "vite-tsconfig-paths": "^5.0.1", @@ -382,7 +419,6 @@ "node": ">=20" }, "workspaces": [ - ".", "./packages/*" ], "prettier": "@goauthentik/prettier-config", diff --git a/web/packages/monorepo/LICENSE.txt b/web/packages/core/LICENSE.txt similarity index 100% rename from web/packages/monorepo/LICENSE.txt rename to web/packages/core/LICENSE.txt diff --git a/web/packages/monorepo/README.md b/web/packages/core/README.md similarity index 82% rename from web/packages/monorepo/README.md rename to web/packages/core/README.md index a3930c1994ec..774455f595ab 100644 --- a/web/packages/monorepo/README.md +++ b/web/packages/core/README.md @@ -1,4 +1,4 @@ -# `@goauthentik/monorepo` +# `@goauthentik/core` This package contains utility scripts common to all TypeScript and JavaScript packages in the `@goauthentik` monorepo. diff --git a/web/packages/core/environment/node.js b/web/packages/core/environment/node.js new file mode 100644 index 000000000000..033374a1035a --- /dev/null +++ b/web/packages/core/environment/node.js @@ -0,0 +1,66 @@ +/** + * @file Utility functions for working with environment variables. + */ +/// + +//#region Constants + +/** + * 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. + * + * @category Environment + * @runtime node + */ +export const NodeEnvironment = process.env.NODE_ENV || "development"; + +/** + * A source environment variable, which can be a string, number, boolean, null, or undefined. + * @typedef {string | number | boolean | null | undefined} EnvironmentVariable + */ + +/** + * A type helper for serializing environment variables. + * + * @category Environment + * @template {EnvironmentVariable} T + * @typedef {T extends string ? `"${T}"` : T} JSONify + */ + +//#endregion + +//#region Utilities + +/** + * Given an object of environment variables, serializes them into a mapping of + * environment variable names to their respective runtime constants. + * + * This is useful for defining environment variables while bundling with ESBuild, Vite, etc. + * + * @category Environment + * @runtime node + * + * @template {Record} EnvRecord + * @template {string} [Prefix='import.meta.env.'] + * + * @param {EnvRecord} input + * @param {Prefix} [prefix='import.meta.env.'] + * + * @returns {{[K in keyof EnvRecord as `${Prefix}${K}`]: JSONify}} + */ +export function serializeEnvironmentVars( + input, + prefix = /** @type {Prefix} */ ("import.meta.env."), +) { + const env = Object.fromEntries( + Object.entries(input).map(([key, value]) => [prefix + key, JSON.stringify(value ?? "")]), + ); + + return /** @type {any} */ (env); +} + +//#endregion diff --git a/web/packages/core/index.js b/web/packages/core/index.js new file mode 100644 index 000000000000..6ec0988b5451 --- /dev/null +++ b/web/packages/core/index.js @@ -0,0 +1,12 @@ +/** + * @file Dummy entry point for the `core` package. + * + * This exists to make TypeScript's module resolution more predictable. + * + * @internal + * @ignore + */ + +export {}; + +export default {}; diff --git a/web/packages/core/package.json b/web/packages/core/package.json new file mode 100644 index 000000000000..eea5cfdba625 --- /dev/null +++ b/web/packages/core/package.json @@ -0,0 +1,59 @@ +{ + "name": "@goauthentik/core", + "version": "1.0.0", + "description": "Core functionality for the authentik monorepo", + "license": "MIT", + "private": true, + "scripts": { + "build": "tsc -p .", + "prettier": "prettier --write .", + "prettier-check": "prettier --check ." + }, + "main": "index.js", + "type": "module", + "exports": { + "./package.json": "./package.json", + "./*/browser": { + "types": "./out/*/browser.d.ts", + "import": "./*/browser.js" + }, + "./*/node": { + "types": "./out/*/node.d.ts", + "import": "./*/node.js" + }, + "./*": { + "types": "./out/*/index.d.ts", + "import": "./*/index.js" + }, + ".": { + "import": "./index.js", + "types": "./out/index.d.ts" + } + }, + "imports": { + "#*/browser": { + "types": "./out/*/browser.d.ts", + "import": "./*/browser.js" + }, + "#*/node": { + "types": "./out/*/node.d.ts", + "import": "./*/node.js" + }, + "#*": { + "types": "./out/*/index.d.ts", + "import": "./*/index.js" + } + }, + "devDependencies": { + "@goauthentik/prettier-config": "^1.0.4", + "@goauthentik/tsconfig": "^1.0.4", + "@types/node": "^22.14.1", + "prettier": "^3.3.3", + "typescript": "^5.6.2" + }, + "engines": { + "node": ">=20.11" + }, + "types": "./out/index.d.ts", + "prettier": "@goauthentik/prettier-config" +} diff --git a/web/packages/monorepo/paths.js b/web/packages/core/paths/node.js similarity index 72% rename from web/packages/monorepo/paths.js rename to web/packages/core/paths/node.js index ab923a26afb1..77ec9b1ca3d3 100644 --- a/web/packages/monorepo/paths.js +++ b/web/packages/core/paths/node.js @@ -10,22 +10,26 @@ const relativeDirname = dirname(fileURLToPath(import.meta.url)); /** * The root of the authentik monorepo. + * + * @runtime node */ -// TODO: Revise when this package is moved to the monorepo's `packages/monorepo` directory. export const MonoRepoRoot = /** @type {MonoRepoRoot} */ ( - resolve(relativeDirname, "..", "..", "..") + resolve(relativeDirname, "..", "..", "..", "..") ); -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 + * @param {ImportMeta} [meta] The `import.meta` object of the module. * + * @runtime node * @returns {string} The resolved path to the package. * @throws {Error} If the package cannot be resolved. */ -export function resolvePackage(packageName) { +export function resolvePackage(packageName, meta) { + const require = createRequire(meta ? meta.url : import.meta.url); + const relativePackageJSONPath = join(packageName, "package.json"); /** @type {string} */ @@ -34,7 +38,7 @@ export function resolvePackage(packageName) { try { absolutePackageJSONPath = require.resolve(relativePackageJSONPath); } catch (cause) { - const error = new Error(`Failed to resolve package "${packageName}"`); + const error = new Error(`🚫 Failed to resolve package "${packageName}"`); error.cause = cause; diff --git a/web/packages/monorepo/scripting.js b/web/packages/core/scripting/node.js similarity index 98% rename from web/packages/monorepo/scripting.js rename to web/packages/core/scripting/node.js index 6e260d528761..16513d3d0679 100644 --- a/web/packages/monorepo/scripting.js +++ b/web/packages/core/scripting/node.js @@ -9,6 +9,7 @@ import { fileURLToPath } from "node:url"; * @param {ImportMeta} meta The `import.meta` object of the module. * * @return {boolean} Whether the module was run directly. + * @runtime node */ export function isMain(meta) { // Are we not in a module context? diff --git a/web/packages/monorepo/tsconfig.json b/web/packages/core/tsconfig.json similarity index 72% rename from web/packages/monorepo/tsconfig.json rename to web/packages/core/tsconfig.json index 83e94d8cf27b..f5338b1c66ba 100644 --- a/web/packages/monorepo/tsconfig.json +++ b/web/packages/core/tsconfig.json @@ -1,9 +1,11 @@ { "extends": "@goauthentik/tsconfig", "compilerOptions": { + "lib": ["DOM", "DOM.Iterable", "ESNext"], "resolveJsonModule": true, "baseUrl": ".", "checkJs": true, + "allowJs": true, "emitDeclarationOnly": true } } diff --git a/web/packages/core/types/node.d.ts b/web/packages/core/types/node.d.ts new file mode 100644 index 000000000000..07d3b8119ae8 --- /dev/null +++ b/web/packages/core/types/node.d.ts @@ -0,0 +1,54 @@ +/** + * @file Global variables provided by Node.js + */ + +declare module "module" { + global { + /** + * @deprecated This is not present in ESM files. + * + * ```js + * import { dirname } from "node:path"; + * import { fileURLToPath } from "node:url"; + * + * const relativeDirname = dirname(fileURLToPath(import.meta.url)); + * ``` + */ + // eslint-disable-next-line no-var + var __dirname: string; + } +} + +declare module "process" { + global { + namespace NodeJS { + interface ProcessEnv { + /** + * The port used by the Docker Compose HTTP service. + */ + COMPOSE_PORT_HTTP?: string; + + /** + * The port used by the Docker Compose HTTPS service. + */ + COMPOSE_PORT_HTTPS?: string; + + /** + * An environment variable used to determine + * whether Node.js is running in production mode. + * + * @see {@link https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production | The difference between development and production} + * @runtime node + */ + readonly NODE_ENV?: "development" | "production"; + /** + * @todo Determine where this is used and if it is needed, + * give it a better name. + * @deprecated + * @runtime node + */ + readonly AK_API_BASE_PATH?: string; + } + } + } +} diff --git a/web/packages/core/version/index.js b/web/packages/core/version/index.js new file mode 100644 index 000000000000..3bb7c19ba7c7 --- /dev/null +++ b/web/packages/core/version/index.js @@ -0,0 +1,21 @@ +/** + * @file Utility functions for working with semantic versions. + * + * @runtime common + */ + +/** + * Creates a URL to the release notes for the given version. + * + * @param {string} semver + * @returns {URL} + * @runtime common + */ +export function createReleaseNotesURL(semver) { + const segments = semver.split("."); + const versionFamily = segments.slice(0, -1).join("."); + + const release = `${versionFamily}#fixed-in-${segments.join("")}`; + + return new URL(`/docs/releases/${release}`, "https://goauthentik.io"); +} diff --git a/web/packages/monorepo/version.js b/web/packages/core/version/node.js similarity index 80% rename from web/packages/monorepo/version.js rename to web/packages/core/version/node.js index e738968d7be0..7622a0097ee2 100644 --- a/web/packages/monorepo/version.js +++ b/web/packages/core/version/node.js @@ -1,16 +1,24 @@ +/** + * @file Utility functions for working with semantic versions. + * + * @runtime node + */ +import { MonoRepoRoot } from "#paths/node"; import { execSync } from "node:child_process"; -import PackageJSON from "../../../package.json" with { type: "json" }; -import { MonoRepoRoot } from "./paths.js"; +import PackageJSON from "../../../../package.json" with { type: "json" }; /** * The current version of authentik in SemVer format. * + * @runtime node */ export const AuthentikVersion = /**@type {`${number}.${number}.${number}`} */ (PackageJSON.version); /** * Reads the last commit hash from the current git repository. + * + * @runtime node */ export function readGitBuildHash() { try { @@ -34,6 +42,7 @@ export function readGitBuildHash() { * * This must match the behavior defined in authentik's server-side `get_full_version` function. * + * @runtime node * @see {@link "authentik\_\_init\_\_.py"} */ export function readBuildIdentifier() { diff --git a/web/packages/esbuild-plugin-live-reload/client/ESBuildObserver.js b/web/packages/esbuild-plugin-live-reload/client/ESBuildObserver.js index 2f8ebe3ce216..9207a89508e0 100644 --- a/web/packages/esbuild-plugin-live-reload/client/ESBuildObserver.js +++ b/web/packages/esbuild-plugin-live-reload/client/ESBuildObserver.js @@ -21,7 +21,7 @@ const log = console.debug.bind(console, logPrefix); * ESBuild may tree-shake it out of production builds. * * ```ts - * if (process.env.NODE_ENV === "development") { + * if (process.env.NODE_ENV=== "development") { * await import("@goauthentik/esbuild-plugin-live-reload/client") * .catch(() => console.warn("Failed to import watcher")) * } diff --git a/web/packages/esbuild-plugin-live-reload/client/types.d.ts b/web/packages/esbuild-plugin-live-reload/client/types.d.ts index c4461817165f..370d24a14873 100644 --- a/web/packages/esbuild-plugin-live-reload/client/types.d.ts +++ b/web/packages/esbuild-plugin-live-reload/client/types.d.ts @@ -4,15 +4,20 @@ export {}; declare global { + /** + * Environment variables injected by ESBuild. + */ + interface ImportMetaEnv { + /** + * The injected watcher URL for ESBuild. + * This is used for live reloading in development mode. + * + * @format url + */ + readonly ESBUILD_WATCHER_URL?: string; + } + interface ImportMeta { - readonly env: { - /** - * The injected watcher URL for ESBuild. - * This is used for live reloading in development mode. - * - * @format url - */ - ESBUILD_WATCHER_URL: string; - }; + readonly env: ImportMetaEnv; } } diff --git a/web/packages/monorepo/build.js b/web/packages/monorepo/build.js deleted file mode 100644 index 343d522cd673..000000000000 --- a/web/packages/monorepo/build.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file Utility functions for building and copying files. - */ - -/** - * A source environment variable, which can be a string, number, boolean, null, or undefined. - * @typedef {string | number | boolean | null | undefined} EnvironmentVariable - */ - -/** - * A type helper for serializing environment variables. - * - * @template {EnvironmentVariable} T - * @typedef {T extends string ? `"${T}"` : T} JSONify - */ - -/** - * Given an object of environment variables, returns a new object with the same keys and values, but - * with the values serialized as strings. - * - * @template {Record} EnvRecord - * @template {string} [Prefix='process.env.'] - * - * @param {EnvRecord} input - * @param {Prefix} [prefix='process.env.'] - * - * @returns {{[K in keyof EnvRecord as `${Prefix}${K}`]: JSONify}} - */ -export function serializeEnvironmentVars(input, prefix = /** @type {Prefix} */ ("process.env.")) { - /** - * @type {Record} - */ - const env = {}; - - for (const [key, value] of Object.entries(input)) { - const namespaceKey = prefix + key; - - env[namespaceKey] = JSON.stringify(value || ""); - } - - return /** @type {any} */ (env); -} diff --git a/web/packages/monorepo/constants.js b/web/packages/monorepo/constants.js deleted file mode 100644 index 6abf55e8a582..000000000000 --- a/web/packages/monorepo/constants.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @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 = process.env.NODE_ENV || "development"; diff --git a/web/packages/monorepo/index.js b/web/packages/monorepo/index.js deleted file mode 100644 index 284d2b5d2b5e..000000000000 --- a/web/packages/monorepo/index.js +++ /dev/null @@ -1,7 +0,0 @@ -/// - -export * from "./paths.js"; -export * from "./constants.js"; -export * from "./build.js"; -export * from "./version.js"; -export * from "./scripting.js"; diff --git a/web/packages/monorepo/package.json b/web/packages/monorepo/package.json deleted file mode 100644 index 86b0b3aa215c..000000000000 --- a/web/packages/monorepo/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "@goauthentik/monorepo", - "version": "1.0.0", - "description": "Utilities for the authentik monorepo.", - "license": "MIT", - "private": true, - "main": "index.js", - "type": "module", - "exports": { - "./package.json": "./package.json", - ".": { - "types": "./out/index.d.ts", - "import": "./index.js" - } - }, - "devDependencies": { - "@goauthentik/prettier-config": "^1.0.4", - "@goauthentik/tsconfig": "^1.0.4", - "@types/node": "^22.14.1", - "prettier": "^3.3.3", - "typescript": "^5.6.2" - }, - "engines": { - "node": ">=20.11" - }, - "types": "./out/index.d.ts", - "prettier": "@goauthentik/prettier-config" -} diff --git a/web/packages/monorepo/types/global.d.ts b/web/packages/monorepo/types/global.d.ts deleted file mode 100644 index 90ebfa5555e3..000000000000 --- a/web/packages/monorepo/types/global.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -declare module "process" { - global { - namespace NodeJS { - interface ProcessEnv { - /** - * An environment variable used to determine - * whether Node.js is running in production mode. - * - * @see {@link https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production | The difference between development and production} - */ - NODE_ENV?: "production" | "development"; - } - } - } -} diff --git a/web/paths.js b/web/paths/node.js similarity index 96% rename from web/paths.js rename to web/paths/node.js index 5d9dac17dedf..7570231833ac 100644 --- a/web/paths.js +++ b/web/paths/node.js @@ -12,7 +12,7 @@ const relativeDirname = dirname(fileURLToPath(import.meta.url)); /** * The root of the web package. */ -export const PackageRoot = /** @type {WebPackageIdentifier} */ (resolve(relativeDirname)); +export const PackageRoot = /** @type {WebPackageIdentifier} */ (resolve(relativeDirname, "..")); /** * The name of the distribution directory. @@ -25,7 +25,7 @@ export const DistDirectoryName = "dist"; * This is where the built files are located after running the build process. */ export const DistDirectory = /** @type {`${WebPackageIdentifier}/${DistDirectoryName}`} */ ( - resolve(relativeDirname, DistDirectoryName) + resolve(PackageRoot, DistDirectoryName) ); //#endregion diff --git a/web/scripts/build-locales.mjs b/web/scripts/build-locales.mjs index 991ac8306d63..375a7b55e7d5 100644 --- a/web/scripts/build-locales.mjs +++ b/web/scripts/build-locales.mjs @@ -1,17 +1,33 @@ -import { spawnSync } from "child_process"; -import fs from "fs"; -import path from "path"; -import process from "process"; - /** - * Determines if all the Xliff translation source files are present and if the Typescript source - * 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 + * @file Lit Localize build script. + * + * @remarks + * Determines if all the Xliff translation source files are present and + * if the Typescript source 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. + * + * @import { ConfigFile } from "@lit/localize-tools/lib/types/config" */ +import { PackageRoot } from "#paths/node"; +import { spawnSync } from "node:child_process"; +import { readFileSync, statSync } from "node:fs"; +import path from "node:path"; -const localizeRules = JSON.parse(fs.readFileSync("./lit-localize.json", "utf-8")); +/** + * @type {ConfigFile} + */ +const localizeRules = JSON.parse( + readFileSync(path.join(PackageRoot, "lit-localize.json"), "utf-8"), +); +/** + * + * @param {string} loc + * @returns {boolean} + */ function generatedFileIsUpToDateWithXliffSource(loc) { const xliff = path.join("./xliff", `${loc}.xlf`); const gened = path.join("./src/locales", `${loc}.ts`); @@ -22,7 +38,7 @@ function generatedFileIsUpToDateWithXliffSource(loc) { // generates a unique error message and halts the build. try { - var xlfStat = fs.statSync(xliff); + var xlfStat = statSync(xliff); } catch (_error) { console.error(`lit-localize expected '${loc}.xlf', but XLF file is not present`); process.exit(1); @@ -30,7 +46,7 @@ function generatedFileIsUpToDateWithXliffSource(loc) { // If the generated file doesn't exist, of course it's not up to date. try { - var genedStat = fs.statSync(gened); + var genedStat = statSync(gened); } catch (_error) { return false; } diff --git a/web/scripts/build-web.mjs b/web/scripts/build-web.mjs index 3b1f329e23b7..d757dd7752f8 100644 --- a/web/scripts/build-web.mjs +++ b/web/scripts/build-web.mjs @@ -1,17 +1,16 @@ +/// /** * @file ESBuild script for building the authentik web UI. * * @import { BuildOptions } from "esbuild"; */ +import { mdxPlugin } from "#bundler/mdx-plugin/node"; +import { createBundleDefinitions } from "#bundler/utils/node"; +import { DistDirectory, DistDirectoryName, EntryPoint, PackageRoot } from "#paths/node"; +import { NodeEnvironment } from "@goauthentik/core/environment/node"; +import { MonoRepoRoot, resolvePackage } from "@goauthentik/core/paths/node"; +import { readBuildIdentifier } from "@goauthentik/core/version/node"; import { liveReloadPlugin } from "@goauthentik/esbuild-plugin-live-reload/plugin"; -import { - MonoRepoRoot, - NodeEnvironment, - readBuildIdentifier, - resolvePackage, - serializeEnvironmentVars, -} from "@goauthentik/monorepo"; -import { DistDirectory, DistDirectoryName, EntryPoint, PackageRoot } from "@goauthentik/web/paths"; import { deepmerge } from "deepmerge-ts"; import esbuild from "esbuild"; import copy from "esbuild-plugin-copy"; @@ -19,17 +18,9 @@ import { polyfillNode } from "esbuild-plugin-polyfill-node"; import * as fs from "node:fs/promises"; import * as path from "node:path"; -import { mdxPlugin } from "./esbuild/build-mdx-plugin.mjs"; - const logPrefix = "[Build]"; -const definitions = serializeEnvironmentVars({ - NODE_ENV: NodeEnvironment, - CWD: process.cwd(), - AK_API_BASE_PATH: process.env.AK_API_BASE_PATH, -}); - -const patternflyPath = resolvePackage("@patternfly/patternfly"); +const patternflyPath = resolvePackage("@patternfly/patternfly", import.meta); /** * @type {Readonly} @@ -86,7 +77,7 @@ const BASE_ESBUILD_OPTIONS = { root: MonoRepoRoot, }), ], - define: definitions, + define: createBundleDefinitions(), format: "esm", logOverride: { /** @@ -168,6 +159,19 @@ async function doWatch() { await buildContext.rebuild(); await buildContext.watch(); + const httpURL = new URL("http://localhost"); + httpURL.port = process.env.COMPOSE_PORT_HTTP ?? "9000"; + + const httpsURL = new URL("http://localhost"); + httpsURL.port = process.env.COMPOSE_PORT_HTTPS ?? "9443"; + + console.log(`\n${logPrefix} 🚀 Server running\n\n`); + + console.log(` 🔓 ${httpURL.href}`); + console.log(` 🔒 ${httpsURL.href}`); + + console.log(`\n---`); + return /** @type {Promise} */ ( new Promise((resolve) => { process.on("SIGINT", () => { diff --git a/web/scripts/eslint.mjs b/web/scripts/eslint.mjs index 63ba74eebd0b..3b38f544d15f 100644 --- a/web/scripts/eslint.mjs +++ b/web/scripts/eslint.mjs @@ -35,6 +35,11 @@ const __dirname = fileURLToPath(new URL(".", import.meta.url)); const projectRoot = path.join(__dirname, ".."); process.chdir(projectRoot); +/** + * + * @param {string[]} flags + * @returns + */ const hasFlag = (flags) => process.argv.length > 1 && flags.includes(process.argv[2]); const [configFile, files] = hasFlag(["-n", "--nightmare"]) diff --git a/web/scripts/eslint.nightmare.mjs b/web/scripts/eslint.nightmare.mjs index 484621b01b45..346e29347084 100644 --- a/web/scripts/eslint.nightmare.mjs +++ b/web/scripts/eslint.nightmare.mjs @@ -152,6 +152,7 @@ export default [ { ignores: [ "dist/", + "out/", ".wireit/", "packages/", // don't ever lint node_modules diff --git a/web/scripts/pseudolocalize.mjs b/web/scripts/pseudolocalize.mjs index d0495f15c855..416fa9630f27 100644 --- a/web/scripts/pseudolocalize.mjs +++ b/web/scripts/pseudolocalize.mjs @@ -1,22 +1,36 @@ -import { readFileSync } from "fs"; -import path from "path"; +/** + * @file Pseudo-localization script. + * + * @import { ConfigFile } from "@lit/localize-tools/lib/types/config.js" + * @import { Config } from '@lit/localize-tools/lib/types/config.js'; + * @import { ProgramMessage } from "@lit/localize-tools/src/messages.js" + * @import { Locale } from "@lit/localize-tools/src/types/locale.js" + */ +import { PackageRoot } from "#paths/node"; +import { readFileSync } from "node:fs"; +import path from "node:path"; import pseudolocale from "pseudolocale"; -import { fileURLToPath } from "url"; import { makeFormatter } from "@lit/localize-tools/lib/formatters/index.js"; import { sortProgramMessages } from "@lit/localize-tools/lib/messages.js"; import { TransformLitLocalizer } from "@lit/localize-tools/lib/modes/transform.js"; -const __dirname = fileURLToPath(new URL(".", import.meta.url)); -const pseudoLocale = "pseudo-LOCALE"; +const pseudoLocale = /** @type {Locale} */ ("pseudo-LOCALE"); const targetLocales = [pseudoLocale]; -const baseConfig = JSON.parse(readFileSync(path.join(__dirname, "../lit-localize.json"), "utf-8")); + +/** + * @type {ConfigFile} + */ +const baseConfig = JSON.parse(readFileSync(path.join(PackageRoot, "lit-localize.json"), "utf-8")); // 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 // 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. +/** + * @satisfies {Config} + */ const config = { ...baseConfig, baseDir: path.join(__dirname, ".."), @@ -28,6 +42,11 @@ const config = { resolve: (path) => path, }; +/** + * + * @param {ProgramMessage} message + * @returns + */ const pseudoMessagify = (message) => ({ name: message.name, contents: message.contents.map((content) => @@ -36,7 +55,7 @@ const pseudoMessagify = (message) => ({ }); const localizer = new TransformLitLocalizer(config); -const messages = localizer.extractSourceMessages().messages; +const { messages } = localizer.extractSourceMessages(); const translations = messages.map(pseudoMessagify); const sorted = sortProgramMessages([...messages]); const formatter = makeFormatter(config); diff --git a/web/src/admin/AdminInterface/AboutModal.ts b/web/src/admin/AdminInterface/AboutModal.ts index d947ba43ace4..d5b7e7e71a10 100644 --- a/web/src/admin/AdminInterface/AboutModal.ts +++ b/web/src/admin/AdminInterface/AboutModal.ts @@ -1,5 +1,4 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { VERSION } from "@goauthentik/common/constants"; import { globalAK } from "@goauthentik/common/global"; import { DefaultBrand } from "@goauthentik/common/ui/config"; import "@goauthentik/elements/EmptyState"; @@ -45,7 +44,7 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton)) } return [ [msg("Version"), version.versionCurrent], - [msg("UI Version"), VERSION], + [msg("UI Version"), import.meta.env.AK_VERSION], [msg("Build"), build], [msg("Python version"), status.runtime.pythonVersion], [msg("Platform"), status.runtime.platform], diff --git a/web/src/admin/AdminInterface/index.entrypoint.ts b/web/src/admin/AdminInterface/index.entrypoint.ts index 9b6480078e5e..5a0290c71e17 100644 --- a/web/src/admin/AdminInterface/index.entrypoint.ts +++ b/web/src/admin/AdminInterface/index.entrypoint.ts @@ -1,29 +1,26 @@ +import { EVENT_API_DRAWER_TOGGLE, EVENT_NOTIFICATION_DRAWER_TOGGLE } from "#common/constants"; +import { configureSentry } from "#common/sentry/index"; +import { me } from "#common/users"; +import { WebsocketClient } from "#common/ws"; +import { AuthenticatedInterface } from "#elements/Interface/Interface"; +import { WithLicenseSummary } from "#elements/Interface/licenseSummaryProvider"; +import "#elements/ak-locale-context/ak-locale-context"; +import "#elements/banner/EnterpriseStatusBanner"; +import "#elements/banner/EnterpriseStatusBanner"; +import "#elements/banner/VersionBanner"; +import "#elements/banner/VersionBanner"; +import "#elements/messages/MessageContainer"; +import "#elements/messages/MessageContainer"; +import "#elements/notifications/APIDrawer"; +import "#elements/notifications/NotificationDrawer"; +import { getURLParam, updateURLParams } from "#elements/router/RouteMatch"; +import "#elements/router/RouterOutlet"; +import "#elements/sidebar/Sidebar"; +import "#elements/sidebar/SidebarItem"; import "@goauthentik/admin/AdminInterface/AboutModal"; import type { AboutModal } from "@goauthentik/admin/AdminInterface/AboutModal"; import { ROUTES } from "@goauthentik/admin/Routes"; -import { - EVENT_API_DRAWER_TOGGLE, - EVENT_NOTIFICATION_DRAWER_TOGGLE, -} from "@goauthentik/common/constants"; -import { configureSentry } from "@goauthentik/common/sentry"; -import { me } from "@goauthentik/common/users"; -import { WebsocketClient } from "@goauthentik/common/ws"; -import { AuthenticatedInterface } from "@goauthentik/elements/Interface"; -import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider.js"; -import { SidebarToggleEventDetail } from "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/ak-locale-context"; -import "@goauthentik/elements/banner/EnterpriseStatusBanner"; -import "@goauthentik/elements/banner/EnterpriseStatusBanner"; -import "@goauthentik/elements/banner/VersionBanner"; -import "@goauthentik/elements/banner/VersionBanner"; -import "@goauthentik/elements/messages/MessageContainer"; -import "@goauthentik/elements/messages/MessageContainer"; -import "@goauthentik/elements/notifications/APIDrawer"; -import "@goauthentik/elements/notifications/NotificationDrawer"; -import { getURLParam, updateURLParams } from "@goauthentik/elements/router/RouteMatch"; -import "@goauthentik/elements/router/RouterOutlet"; -import "@goauthentik/elements/sidebar/Sidebar"; -import "@goauthentik/elements/sidebar/SidebarItem"; +import { SidebarToggleEventDetail } from "@goauthentik/components/ak-page-header.js"; import { CSSResult, TemplateResult, css, html, nothing } from "lit"; import { customElement, eventOptions, property, query } from "lit/decorators.js"; diff --git a/web/src/admin/DebugPage.ts b/web/src/admin/DebugPage.ts index 050e242fecca..1e2b64c64112 100644 --- a/web/src/admin/DebugPage.ts +++ b/web/src/admin/DebugPage.ts @@ -1,9 +1,9 @@ -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { parseAPIResponseError, pluckErrorDetail } from "@goauthentik/common/errors/network"; -import { MessageLevel } from "@goauthentik/common/messages"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/PageHeader"; -import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import { parseAPIResponseError, pluckErrorDetail } from "#common/errors/network"; +import { MessageLevel } from "#common/messages"; +import "#components/ak-page-header"; +import { AKElement } from "#elements/Base"; +import { showMessage } from "#elements/messages/MessageContainer"; import * as Sentry from "@sentry/browser"; import { CSSResult, TemplateResult, html } from "lit"; diff --git a/web/src/admin/admin-overview/AdminOverviewPage.ts b/web/src/admin/admin-overview/AdminOverviewPage.ts index 8a750f15fccb..5ba4ce6b9bb1 100644 --- a/web/src/admin/admin-overview/AdminOverviewPage.ts +++ b/web/src/admin/admin-overview/AdminOverviewPage.ts @@ -1,29 +1,27 @@ -import "@goauthentik/admin/admin-overview/TopApplicationsTable"; -import "@goauthentik/admin/admin-overview/cards/AdminStatusCard"; -import "@goauthentik/admin/admin-overview/cards/FipsStatusCard"; -import "@goauthentik/admin/admin-overview/cards/RecentEventsCard"; -import "@goauthentik/admin/admin-overview/cards/SystemStatusCard"; -import "@goauthentik/admin/admin-overview/cards/VersionStatusCard"; -import "@goauthentik/admin/admin-overview/cards/WorkerStatusCard"; -import "@goauthentik/admin/admin-overview/charts/AdminLoginAuthorizeChart"; -import "@goauthentik/admin/admin-overview/charts/OutpostStatusChart"; -import "@goauthentik/admin/admin-overview/charts/SyncStatusChart"; -import { VERSION } from "@goauthentik/common/constants"; -import { me } from "@goauthentik/common/users"; -import { AKElement } from "@goauthentik/elements/Base"; -import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider.js"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/cards/AggregatePromiseCard"; -import "@goauthentik/elements/cards/QuickActionsCard.js"; -import type { QuickAction } from "@goauthentik/elements/cards/QuickActionsCard.js"; -import { paramURL } from "@goauthentik/elements/router/RouterOutlet"; +import "#admin/admin-overview/TopApplicationsTable"; +import "#admin/admin-overview/cards/AdminStatusCard"; +import "#admin/admin-overview/cards/FipsStatusCard"; +import "#admin/admin-overview/cards/RecentEventsCard"; +import "#admin/admin-overview/cards/SystemStatusCard"; +import "#admin/admin-overview/cards/VersionStatusCard"; +import "#admin/admin-overview/cards/WorkerStatusCard"; +import "#admin/admin-overview/charts/AdminLoginAuthorizeChart"; +import "#admin/admin-overview/charts/OutpostStatusChart"; +import "#admin/admin-overview/charts/SyncStatusChart"; +import { me } from "#common/users"; +import "#components/ak-page-header"; +import { AKElement } from "#elements/Base"; +import { WithLicenseSummary } from "#elements/Interface/licenseSummaryProvider"; +import "#elements/cards/AggregatePromiseCard"; +import type { QuickAction } from "#elements/cards/QuickActionsCard"; +import "#elements/cards/QuickActionsCard"; +import { paramURL } from "#elements/router/RouterOutlet"; +import { createReleaseNotesURL } from "@goauthentik/core/version"; import { msg, str } from "@lit/localize"; import { CSSResult, TemplateResult, css, html, nothing } from "lit"; import { customElement, state } from "lit/decorators.js"; import { classMap } from "lit/directives/class-map.js"; -import { map } from "lit/directives/map.js"; -import { when } from "lit/directives/when.js"; import PFContent from "@patternfly/patternfly/components/Content/content.css"; import PFDivider from "@patternfly/patternfly/components/Divider/divider.css"; @@ -33,21 +31,8 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { SessionUser } from "@goauthentik/api"; -export function versionFamily(): string { - const parts = VERSION.split("."); - parts.pop(); - return parts.join("."); -} - -const RELEASE = `${VERSION.split(".").slice(0, -1).join(".")}#fixed-in-${VERSION.replaceAll( - ".", - "", -)}`; - const AdminOverviewBase = WithLicenseSummary(AKElement); -type Renderer = () => TemplateResult | typeof nothing; - @customElement("ak-admin-overview") export class AdminOverviewPage extends AdminOverviewBase { static get styles(): CSSResult[] { @@ -83,7 +68,11 @@ export class AdminOverviewPage extends AdminOverviewBase { [msg("Check the logs"), paramURL("/events/log")], [msg("Explore integrations"), "https://goauthentik.io/integrations/", true], [msg("Manage users"), paramURL("/identity/users")], - [msg("Check the release notes"), `https://goauthentik.io/docs/releases/${RELEASE}`, true], + [ + msg("Check the release notes"), + createReleaseNotesURL(import.meta.env.AK_VERSION).href, + true, + ], ]; @state() @@ -193,45 +182,6 @@ export class AdminOverviewPage extends AdminOverviewBase { ` : nothing} `; } - - renderActions() { - const release = `${versionFamily()}#fixed-in-${VERSION.replaceAll(".", "")}`; - - const quickActions: [string, string][] = [ - [msg("Create a new application"), paramURL("/core/applications", { createForm: true })], - [msg("Check the logs"), paramURL("/events/log")], - [msg("Explore integrations"), "https://goauthentik.io/integrations/"], - [msg("Manage users"), paramURL("/identity/users")], - [msg("Check the release notes"), `https://goauthentik.io/docs/releases/${release}`], - ]; - - const action = ([label, url]: [string, string]) => { - const isExternal = url.startsWith("https://"); - const ex = (truecase: Renderer, falsecase: Renderer) => - when(isExternal, truecase, falsecase); - - const content = html`${label}${ex( - () => html``, - () => nothing, - )}`; - - return html`
  • - ${ex( - () => - html`${content}`, - () => html`${content}`, - )} -
  • `; - }; - - return html`${map(quickActions, action)}`; - } } declare global { diff --git a/web/src/admin/admin-overview/DashboardUserPage.ts b/web/src/admin/admin-overview/DashboardUserPage.ts index 3fd5483422e2..eb1b168bd042 100644 --- a/web/src/admin/admin-overview/DashboardUserPage.ts +++ b/web/src/admin/admin-overview/DashboardUserPage.ts @@ -1,7 +1,7 @@ -import "@goauthentik/admin/admin-overview/charts/AdminModelPerDay"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/cards/AggregatePromiseCard"; +import "#admin/admin-overview/charts/AdminModelPerDay"; +import "#components/ak-page-header"; +import { AKElement } from "#elements/Base"; +import "#elements/cards/AggregatePromiseCard"; import { msg } from "@lit/localize"; import { CSSResult, TemplateResult, css, html } from "lit"; diff --git a/web/src/admin/admin-settings/AdminSettingsPage.ts b/web/src/admin/admin-settings/AdminSettingsPage.ts index b1d1a34a42bd..9693750a0c2e 100644 --- a/web/src/admin/admin-settings/AdminSettingsPage.ts +++ b/web/src/admin/admin-settings/AdminSettingsPage.ts @@ -1,16 +1,15 @@ -import "@goauthentik/admin/admin-settings/AdminSettingsForm"; -import { AdminSettingsForm } from "@goauthentik/admin/admin-settings/AdminSettingsForm"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import "@goauthentik/components/events/ObjectChangelog"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/CodeMirror"; -import "@goauthentik/elements/EmptyState"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/Tabs"; -import "@goauthentik/elements/buttons/ModalButton"; -import "@goauthentik/elements/buttons/SpinnerButton"; -import "@goauthentik/elements/buttons/SpinnerButton"; -import "@goauthentik/elements/forms/ModalForm"; +import "#admin/admin-settings/AdminSettingsForm"; +import { AdminSettingsForm } from "#admin/admin-settings/AdminSettingsForm"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import "#components/ak-page-header"; +import "#components/events/ObjectChangelog"; +import { AKElement } from "#elements/Base"; +import "#elements/CodeMirror"; +import "#elements/EmptyState"; +import "#elements/Tabs"; +import "#elements/buttons/ModalButton"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; +import "#elements/forms/ModalForm"; import { msg } from "@lit/localize"; import { html, nothing } from "lit"; diff --git a/web/src/admin/applications/ApplicationViewPage.ts b/web/src/admin/applications/ApplicationViewPage.ts index 6cd06094f9a6..1de763df3574 100644 --- a/web/src/admin/applications/ApplicationViewPage.ts +++ b/web/src/admin/applications/ApplicationViewPage.ts @@ -1,18 +1,18 @@ -import "@goauthentik/admin/applications/ApplicationAuthorizeChart"; -import "@goauthentik/admin/applications/ApplicationCheckAccessForm"; -import "@goauthentik/admin/applications/ApplicationForm"; -import "@goauthentik/admin/applications/entitlements/ApplicationEntitlementPage"; -import "@goauthentik/admin/policies/BoundPoliciesList"; -import "@goauthentik/admin/rbac/ObjectPermissionsPage"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { PFSize } from "@goauthentik/common/enums.js"; -import "@goauthentik/components/events/ObjectChangelog"; -import "@goauthentik/elements/AppIcon"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/EmptyState"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/Tabs"; -import "@goauthentik/elements/buttons/SpinnerButton"; +import "#admin/applications/ApplicationAuthorizeChart"; +import "#admin/applications/ApplicationCheckAccessForm"; +import "#admin/applications/ApplicationForm"; +import "#admin/applications/entitlements/ApplicationEntitlementPage"; +import "#admin/policies/BoundPoliciesList"; +import "#admin/rbac/ObjectPermissionsPage"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import { PFSize } from "#common/enums"; +import "#components/ak-page-header"; +import "#components/events/ObjectChangelog"; +import "#elements/AppIcon"; +import { AKElement } from "#elements/Base"; +import "#elements/EmptyState"; +import "#elements/Tabs"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; import { msg } from "@lit/localize"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit"; diff --git a/web/src/admin/events/EventViewPage.ts b/web/src/admin/events/EventViewPage.ts index ca24b4cfc51b..45c5badd2381 100644 --- a/web/src/admin/events/EventViewPage.ts +++ b/web/src/admin/events/EventViewPage.ts @@ -1,11 +1,11 @@ -import { EventGeo, EventUser } from "@goauthentik/admin/events/utils"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { EventWithContext } from "@goauthentik/common/events"; -import { actionToLabel } from "@goauthentik/common/labels"; -import { formatElapsedTime } from "@goauthentik/common/temporal"; -import "@goauthentik/components/ak-event-info"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/PageHeader"; +import { EventGeo, EventUser } from "#admin/events/utils"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import { EventWithContext } from "#common/events"; +import { actionToLabel } from "#common/labels"; +import { formatElapsedTime } from "#common/temporal"; +import "#components/ak-event-info"; +import "#components/ak-page-header"; +import { AKElement } from "#elements/Base"; import { msg, str } from "@lit/localize"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit"; diff --git a/web/src/admin/flows/FlowViewPage.ts b/web/src/admin/flows/FlowViewPage.ts index 718235b397ce..6aee2ba9dd78 100644 --- a/web/src/admin/flows/FlowViewPage.ts +++ b/web/src/admin/flows/FlowViewPage.ts @@ -1,16 +1,16 @@ -import "@goauthentik/admin/flows/BoundStagesList"; -import "@goauthentik/admin/flows/FlowDiagram"; -import "@goauthentik/admin/flows/FlowForm"; -import { DesignationToLabel } from "@goauthentik/admin/flows/utils"; -import "@goauthentik/admin/policies/BoundPoliciesList"; -import "@goauthentik/admin/rbac/ObjectPermissionsPage"; -import { AndNext, DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { isResponseErrorLike } from "@goauthentik/common/errors/network"; -import "@goauthentik/components/events/ObjectChangelog"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/Tabs"; -import "@goauthentik/elements/buttons/SpinnerButton"; +import "#admin/flows/BoundStagesList"; +import "#admin/flows/FlowDiagram"; +import "#admin/flows/FlowForm"; +import { DesignationToLabel } from "#admin/flows/utils"; +import "#admin/policies/BoundPoliciesList"; +import "#admin/rbac/ObjectPermissionsPage"; +import { AndNext, DEFAULT_CONFIG } from "#common/api/config"; +import { isResponseErrorLike } from "#common/errors/network"; +import "#components/ak-page-header"; +import "#components/events/ObjectChangelog"; +import { AKElement } from "#elements/Base"; +import "#elements/Tabs"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; import { msg } from "@lit/localize"; import { CSSResult, PropertyValues, TemplateResult, css, html } from "lit"; diff --git a/web/src/admin/groups/GroupViewPage.ts b/web/src/admin/groups/GroupViewPage.ts index a9c023e7676f..7441c40740ad 100644 --- a/web/src/admin/groups/GroupViewPage.ts +++ b/web/src/admin/groups/GroupViewPage.ts @@ -3,11 +3,11 @@ import "@goauthentik/admin/groups/RelatedUserList"; import "@goauthentik/admin/rbac/ObjectPermissionsPage"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { EVENT_REFRESH } from "@goauthentik/common/constants"; +import "@goauthentik/components/ak-page-header"; import "@goauthentik/components/ak-status-label"; import "@goauthentik/components/events/ObjectChangelog"; import { AKElement } from "@goauthentik/elements/Base"; import "@goauthentik/elements/CodeMirror"; -import "@goauthentik/elements/PageHeader"; import "@goauthentik/elements/Tabs"; import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/buttons/SpinnerButton"; diff --git a/web/src/admin/providers/ProviderViewPage.ts b/web/src/admin/providers/ProviderViewPage.ts index 4afad2f86bd2..b40abc409ea6 100644 --- a/web/src/admin/providers/ProviderViewPage.ts +++ b/web/src/admin/providers/ProviderViewPage.ts @@ -1,18 +1,18 @@ -import "@goauthentik/admin/providers/google_workspace/GoogleWorkspaceProviderViewPage"; -import "@goauthentik/admin/providers/ldap/LDAPProviderViewPage"; -import "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderViewPage"; -import "@goauthentik/admin/providers/oauth2/OAuth2ProviderViewPage"; -import "@goauthentik/admin/providers/proxy/ProxyProviderViewPage"; -import "@goauthentik/admin/providers/rac/RACProviderViewPage"; -import "@goauthentik/admin/providers/radius/RadiusProviderViewPage"; -import "@goauthentik/admin/providers/saml/SAMLProviderViewPage"; -import "@goauthentik/admin/providers/scim/SCIMProviderViewPage"; -import "@goauthentik/admin/providers/ssf/SSFProviderViewPage"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/EmptyState"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/buttons/SpinnerButton"; +import "#admin/providers/google_workspace/GoogleWorkspaceProviderViewPage"; +import "#admin/providers/ldap/LDAPProviderViewPage"; +import "#admin/providers/microsoft_entra/MicrosoftEntraProviderViewPage"; +import "#admin/providers/oauth2/OAuth2ProviderViewPage"; +import "#admin/providers/proxy/ProxyProviderViewPage"; +import "#admin/providers/rac/RACProviderViewPage"; +import "#admin/providers/radius/RadiusProviderViewPage"; +import "#admin/providers/saml/SAMLProviderViewPage"; +import "#admin/providers/scim/SCIMProviderViewPage"; +import "#admin/providers/ssf/SSFProviderViewPage"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import "#components/ak-page-header"; +import { AKElement } from "#elements/Base"; +import "#elements/EmptyState"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; import { CSSResult, TemplateResult, html } from "lit"; import { customElement, property } from "lit/decorators.js"; diff --git a/web/src/admin/rbac/InitialPermissionsListPage.ts b/web/src/admin/rbac/InitialPermissionsListPage.ts index 15b8206444ad..fb1808ed083e 100644 --- a/web/src/admin/rbac/InitialPermissionsListPage.ts +++ b/web/src/admin/rbac/InitialPermissionsListPage.ts @@ -1,11 +1,11 @@ -import "@goauthentik/admin/rbac/InitialPermissionsForm"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import "@goauthentik/elements/buttons/SpinnerButton"; -import "@goauthentik/elements/forms/DeleteBulkForm"; -import "@goauthentik/elements/forms/ModalForm"; -import { PaginatedResponse } from "@goauthentik/elements/table/Table"; -import { TableColumn } from "@goauthentik/elements/table/Table"; -import { TablePage } from "@goauthentik/elements/table/TablePage"; +import "#admin/rbac/InitialPermissionsForm"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; +import "#elements/forms/DeleteBulkForm"; +import "#elements/forms/ModalForm"; +import { PaginatedResponse } from "#elements/table/Table"; +import { TableColumn } from "#elements/table/Table"; +import { TablePage } from "#elements/table/TablePage"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import { msg } from "@lit/localize"; diff --git a/web/src/admin/roles/RoleListPage.ts b/web/src/admin/roles/RoleListPage.ts index fd68f93c0def..4d086528fea4 100644 --- a/web/src/admin/roles/RoleListPage.ts +++ b/web/src/admin/roles/RoleListPage.ts @@ -1,11 +1,11 @@ -import "@goauthentik/admin/roles/RoleForm"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import "@goauthentik/elements/buttons/SpinnerButton"; -import "@goauthentik/elements/forms/DeleteBulkForm"; -import "@goauthentik/elements/forms/ModalForm"; -import { PaginatedResponse } from "@goauthentik/elements/table/Table"; -import { TableColumn } from "@goauthentik/elements/table/Table"; -import { TablePage } from "@goauthentik/elements/table/TablePage"; +import "#admin/roles/RoleForm"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; +import "#elements/forms/DeleteBulkForm"; +import "#elements/forms/ModalForm"; +import { PaginatedResponse } from "#elements/table/Table"; +import { TableColumn } from "#elements/table/Table"; +import { TablePage } from "#elements/table/TablePage"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import { msg } from "@lit/localize"; diff --git a/web/src/admin/roles/RoleViewPage.ts b/web/src/admin/roles/RoleViewPage.ts index b21e88acaa76..50c26d28f338 100644 --- a/web/src/admin/roles/RoleViewPage.ts +++ b/web/src/admin/roles/RoleViewPage.ts @@ -1,15 +1,15 @@ -import "@goauthentik/admin/groups/RelatedGroupList"; -import "@goauthentik/admin/rbac/ObjectPermissionsPage"; -import "@goauthentik/admin/roles/RoleForm"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { EVENT_REFRESH } from "@goauthentik/common/constants"; -import { renderDescriptionList } from "@goauthentik/components/DescriptionList"; -import "@goauthentik/components/events/ObjectChangelog"; -import "@goauthentik/components/events/UserEvents"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/Tabs"; -import "@goauthentik/elements/forms/ModalForm"; +import "#admin/groups/RelatedGroupList"; +import "#admin/rbac/ObjectPermissionsPage"; +import "#admin/roles/RoleForm"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import { EVENT_REFRESH } from "#common/constants"; +import { renderDescriptionList } from "#components/DescriptionList"; +import "#components/ak-page-header"; +import "#components/events/ObjectChangelog"; +import "#components/events/UserEvents"; +import { AKElement } from "#elements/Base"; +import "#elements/Tabs"; +import "#elements/forms/ModalForm"; import { msg, str } from "@lit/localize"; import { css, html, nothing } from "lit"; diff --git a/web/src/admin/sources/SourceViewPage.ts b/web/src/admin/sources/SourceViewPage.ts index 2badf3543b0a..e08c43882cc9 100644 --- a/web/src/admin/sources/SourceViewPage.ts +++ b/web/src/admin/sources/SourceViewPage.ts @@ -1,14 +1,14 @@ -import "@goauthentik/admin/sources/kerberos/KerberosSourceViewPage"; -import "@goauthentik/admin/sources/ldap/LDAPSourceViewPage"; -import "@goauthentik/admin/sources/oauth/OAuthSourceViewPage"; -import "@goauthentik/admin/sources/plex/PlexSourceViewPage"; -import "@goauthentik/admin/sources/saml/SAMLSourceViewPage"; -import "@goauthentik/admin/sources/scim/SCIMSourceViewPage"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/EmptyState"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/buttons/SpinnerButton"; +import "#admin/sources/kerberos/KerberosSourceViewPage"; +import "#admin/sources/ldap/LDAPSourceViewPage"; +import "#admin/sources/oauth/OAuthSourceViewPage"; +import "#admin/sources/plex/PlexSourceViewPage"; +import "#admin/sources/saml/SAMLSourceViewPage"; +import "#admin/sources/scim/SCIMSourceViewPage"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import "#components/ak-page-header"; +import { AKElement } from "#elements/Base"; +import "#elements/EmptyState"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; import { TemplateResult, html } from "lit"; import { customElement, property } from "lit/decorators.js"; diff --git a/web/src/admin/stages/invitation/InvitationListPage.ts b/web/src/admin/stages/invitation/InvitationListPage.ts index 08fd7695ebd1..eeb8dc72b483 100644 --- a/web/src/admin/stages/invitation/InvitationListPage.ts +++ b/web/src/admin/stages/invitation/InvitationListPage.ts @@ -1,15 +1,15 @@ -import "@goauthentik/admin/rbac/ObjectPermissionModal"; -import "@goauthentik/admin/stages/invitation/InvitationForm"; -import "@goauthentik/admin/stages/invitation/InvitationListLink"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { PFColor } from "@goauthentik/elements/Label"; -import "@goauthentik/elements/buttons/ModalButton"; -import "@goauthentik/elements/buttons/SpinnerButton"; -import "@goauthentik/elements/forms/DeleteBulkForm"; -import "@goauthentik/elements/forms/ModalForm"; -import { PaginatedResponse } from "@goauthentik/elements/table/Table"; -import { TableColumn } from "@goauthentik/elements/table/Table"; -import { TablePage } from "@goauthentik/elements/table/TablePage"; +import "#admin/rbac/ObjectPermissionModal"; +import "#admin/stages/invitation/InvitationForm"; +import "#admin/stages/invitation/InvitationListLink"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import { PFColor } from "#elements/Label"; +import "#elements/buttons/ModalButton"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; +import "#elements/forms/DeleteBulkForm"; +import "#elements/forms/ModalForm"; +import { PaginatedResponse } from "#elements/table/Table"; +import { TableColumn } from "#elements/table/Table"; +import { TablePage } from "#elements/table/TablePage"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import { msg } from "@lit/localize"; diff --git a/web/src/admin/users/UserViewPage.ts b/web/src/admin/users/UserViewPage.ts index eb11589dc77a..1629c34e1d3d 100644 --- a/web/src/admin/users/UserViewPage.ts +++ b/web/src/admin/users/UserViewPage.ts @@ -1,44 +1,38 @@ -import "@goauthentik/admin/groups/RelatedGroupList"; -import "@goauthentik/admin/providers/rac/ConnectionTokenList"; -import "@goauthentik/admin/rbac/ObjectPermissionsPage"; -import "@goauthentik/admin/users/UserActiveForm"; -import "@goauthentik/admin/users/UserApplicationTable"; -import "@goauthentik/admin/users/UserChart"; -import "@goauthentik/admin/users/UserForm"; -import "@goauthentik/admin/users/UserImpersonateForm"; -import { - renderRecoveryEmailRequest, - requestRecoveryLink, -} from "@goauthentik/admin/users/UserListPage"; -import "@goauthentik/admin/users/UserPasswordForm"; -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { EVENT_REFRESH } from "@goauthentik/common/constants"; -import { PFSize } from "@goauthentik/common/enums.js"; -import { userTypeToLabel } from "@goauthentik/common/labels"; -import { formatElapsedTime } from "@goauthentik/common/temporal"; -import { me } from "@goauthentik/common/users"; -import "@goauthentik/components/DescriptionList"; -import { - type DescriptionPair, - renderDescriptionList, -} from "@goauthentik/components/DescriptionList"; -import "@goauthentik/components/ak-status-label"; -import "@goauthentik/components/events/ObjectChangelog"; -import "@goauthentik/components/events/UserEvents"; -import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/CodeMirror"; -import { WithCapabilitiesConfig } from "@goauthentik/elements/Interface/capabilitiesProvider"; -import "@goauthentik/elements/PageHeader"; -import "@goauthentik/elements/Tabs"; -import "@goauthentik/elements/buttons/ActionButton"; -import "@goauthentik/elements/buttons/SpinnerButton"; -import "@goauthentik/elements/forms/ModalForm"; -import "@goauthentik/elements/oauth/UserAccessTokenList"; -import "@goauthentik/elements/oauth/UserRefreshTokenList"; -import "@goauthentik/elements/user/SessionList"; -import "@goauthentik/elements/user/UserConsentList"; -import "@goauthentik/elements/user/UserReputationList"; -import "@goauthentik/elements/user/sources/SourceSettings"; +import "#admin/groups/RelatedGroupList"; +import "#admin/providers/rac/ConnectionTokenList"; +import "#admin/rbac/ObjectPermissionsPage"; +import "#admin/users/UserActiveForm"; +import "#admin/users/UserApplicationTable"; +import "#admin/users/UserChart"; +import "#admin/users/UserForm"; +import "#admin/users/UserImpersonateForm"; +import { renderRecoveryEmailRequest, requestRecoveryLink } from "#admin/users/UserListPage"; +import "#admin/users/UserPasswordForm"; +import { DEFAULT_CONFIG } from "#common/api/config"; +import { EVENT_REFRESH } from "#common/constants"; +import { PFSize } from "#common/enums"; +import { userTypeToLabel } from "#common/labels"; +import { formatElapsedTime } from "#common/temporal"; +import { me } from "#common/users"; +import "#components/DescriptionList"; +import { type DescriptionPair, renderDescriptionList } from "#components/DescriptionList"; +import "#components/ak-page-header"; +import "#components/ak-status-label"; +import "#components/events/ObjectChangelog"; +import "#components/events/UserEvents"; +import { AKElement } from "#elements/Base"; +import "#elements/CodeMirror"; +import { WithCapabilitiesConfig } from "#elements/Interface/capabilitiesProvider"; +import "#elements/Tabs"; +import "#elements/buttons/ActionButton/ak-action-button"; +import "#elements/buttons/SpinnerButton/ak-spinner-button"; +import "#elements/forms/ModalForm"; +import "#elements/oauth/UserAccessTokenList"; +import "#elements/oauth/UserRefreshTokenList"; +import "#elements/user/SessionList"; +import "#elements/user/UserConsentList"; +import "#elements/user/UserReputationList"; +import "#elements/user/sources/SourceSettings"; import { msg, str } from "@lit/localize"; import { TemplateResult, css, html, nothing } from "lit"; diff --git a/web/src/common/api/config.ts b/web/src/common/api/config.ts index d003cb5029ef..a22a214aaca6 100644 --- a/web/src/common/api/config.ts +++ b/web/src/common/api/config.ts @@ -3,7 +3,7 @@ import { EventMiddleware, LoggingMiddleware, } from "@goauthentik/common/api/middleware.js"; -import { EVENT_LOCALE_REQUEST, VERSION } from "@goauthentik/common/constants.js"; +import { EVENT_LOCALE_REQUEST } from "@goauthentik/common/constants.js"; import { globalAK } from "@goauthentik/common/global.js"; import { SentryMiddleware } from "@goauthentik/common/sentry/middleware"; @@ -79,4 +79,6 @@ export function AndNext(url: string): string { return `?next=${encodeURIComponent(url)}`; } -console.debug(`authentik(early): version ${VERSION}, apiBase ${DEFAULT_CONFIG.basePath}`); +console.debug( + `authentik(early): version ${import.meta.env.AK_VERSION}, apiBase ${DEFAULT_CONFIG.basePath}`, +); diff --git a/web/src/common/constants.ts b/web/src/common/constants.ts index 917d4804577f..040105aca241 100644 --- a/web/src/common/constants.ts +++ b/web/src/common/constants.ts @@ -1,12 +1,35 @@ +/** + * @file Global constants used throughout the application. + * + * @todo Much of this content can be moved to a specific file, element, or component. + */ + +/// + +//#region Patternfly + export const SECONDARY_CLASS = "pf-m-secondary"; export const SUCCESS_CLASS = "pf-m-success"; export const ERROR_CLASS = "pf-m-danger"; export const PROGRESS_CLASS = "pf-m-in-progress"; export const CURRENT_CLASS = "pf-m-current"; -export const VERSION = "2025.4.1"; + +//#endregion + +//#region Application + export const TITLE_DEFAULT = "authentik"; +/** + * The delimiter used to parse the URL for the current route. + * + * @todo Move this to the ak-router. + */ export const ROUTE_SEPARATOR = ";"; +//#endregion + +//#region Events + export const EVENT_REFRESH = "ak-refresh"; export const EVENT_NOTIFICATION_DRAWER_TOGGLE = "ak-notification-toggle"; export const EVENT_API_DRAWER_TOGGLE = "ak-api-drawer-toggle"; @@ -20,7 +43,17 @@ export const EVENT_MESSAGE = "ak-message"; export const EVENT_THEME_CHANGE = "ak-theme-change"; export const EVENT_REFRESH_ENTERPRISE = "ak-refresh-enterprise"; +//#endregion + +//#region WebSocket + export const WS_MSG_TYPE_MESSAGE = "message"; export const WS_MSG_TYPE_REFRESH = "refresh"; +//#endregion + +//#region LocalStorage + export const LOCALSTORAGE_AUTHENTIK_KEY = "authentik-local-settings"; + +//#endregion diff --git a/web/src/common/helpers/plex.ts b/web/src/common/helpers/plex.ts index 228a505a07d8..4172d6672e6c 100644 --- a/web/src/common/helpers/plex.ts +++ b/web/src/common/helpers/plex.ts @@ -1,4 +1,3 @@ -import { VERSION } from "@goauthentik/common/constants"; import { SentryIgnoredError } from "@goauthentik/common/sentry"; export interface PlexPinResponse { @@ -19,7 +18,7 @@ export const DEFAULT_HEADERS = { "Accept": "application/json", "Content-Type": "application/json", "X-Plex-Product": "authentik", - "X-Plex-Version": VERSION, + "X-Plex-Version": import.meta.env.AK_VERSION, "X-Plex-Device-Vendor": "goauthentik.io", }; diff --git a/web/src/common/sentry/index.ts b/web/src/common/sentry/index.ts index 7aede31d7865..37150e5f24e5 100644 --- a/web/src/common/sentry/index.ts +++ b/web/src/common/sentry/index.ts @@ -1,4 +1,3 @@ -import { VERSION } from "@goauthentik/common/constants"; import { globalAK } from "@goauthentik/common/global"; import { me } from "@goauthentik/common/users"; import { readInterfaceRouteParam } from "@goauthentik/elements/router/utils"; @@ -41,7 +40,7 @@ export function configureSentry(canDoPpi = false) { /MutationObserver.observe/gi, /NS_ERROR_FAILURE/gi, ], - release: `authentik@${VERSION}`, + release: `authentik@${import.meta.env.AK_VERSION}`, integrations: [ browserTracingIntegration({ // https://docs.sentry.io/platforms/javascript/tracing/instrumentation/automatic-instrumentation/#custom-routing diff --git a/web/src/common/theme.ts b/web/src/common/theme.ts index 063fb8c0da98..bb105f5d16ca 100644 --- a/web/src/common/theme.ts +++ b/web/src/common/theme.ts @@ -1,15 +1,11 @@ /** * @file Theme utilities. */ -import { - type StyleRoot, - createStyleSheetUnsafe, - setAdoptedStyleSheets, -} from "@goauthentik/web/common/stylesheets.js"; -import { UIConfig } from "@goauthentik/web/common/ui/config.js"; - -import AKBase from "@goauthentik/web/common/styles/authentik.css"; -import AKBaseDark from "@goauthentik/web/common/styles/theme-dark.css"; +import { type StyleRoot, createStyleSheetUnsafe, setAdoptedStyleSheets } from "#common/stylesheets"; +import { UIConfig } from "#common/ui/config"; + +import AKBase from "#common/styles/authentik.css"; +import AKBaseDark from "#common/styles/theme-dark.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { Config, CurrentBrand, UiThemeEnum } from "@goauthentik/api"; diff --git a/web/src/components/ak-event-info.ts b/web/src/components/ak-event-info.ts index 2b2af8f28465..23847ba8bceb 100644 --- a/web/src/components/ak-event-info.ts +++ b/web/src/components/ak-event-info.ts @@ -1,5 +1,4 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; -import { VERSION } from "@goauthentik/common/constants"; import { PFSize } from "@goauthentik/common/enums.js"; import { EventContext, @@ -76,7 +75,7 @@ ${context.message as string} **Version and Deployment (please complete the following information):** -- authentik version: ${VERSION} +- authentik version: ${import.meta.env.AK_VERSION} - Deployment: [e.g. docker-compose, helm] **Additional context** diff --git a/web/src/components/ak-page-header.ts b/web/src/components/ak-page-header.ts new file mode 100644 index 000000000000..be178b15b8e6 --- /dev/null +++ b/web/src/components/ak-page-header.ts @@ -0,0 +1,84 @@ +import "#components/ak-nav-buttons"; +import { AKPageNavbar } from "#components/ak-page-navbar"; +import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; + +import { CSSResult, LitElement, css } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +export interface PageHeaderInit { + header?: string; + description?: string; + icon?: string; + iconImage?: boolean; +} + +//#region Events + +export interface SidebarToggleEventDetail { + open?: boolean; +} + +//#endregion + +//#region Page Header + +/** + * A page header component, used to display the page title and description. + * + * Internally, this component dispatches the `ak-page-header` event, which is + * listened to by the `ak-page-navbar` component. + * + * @singleton + */ +@customElement("ak-page-header") +export class AKPageHeader extends LitElement implements PageHeaderInit { + @property({ type: String }) + header?: string; + + @property({ type: String }) + description?: string; + + @property({ type: String }) + icon?: string; + + @property({ type: Boolean }) + iconImage = false; + + static get styles(): CSSResult[] { + return [ + css` + :host { + display: none; + } + `, + ]; + } + + connectedCallback(): void { + super.connectedCallback(); + + AKPageNavbar.setNavbarDetails({ + header: this.header, + description: this.description, + icon: this.icon, + iconImage: this.iconImage, + }); + } + + updated(): void { + AKPageNavbar.setNavbarDetails({ + header: this.header, + description: this.description, + icon: this.icon, + iconImage: this.iconImage, + }); + } +} + +//#endregion + +declare global { + interface HTMLElementTagNameMap { + "ak-page-header": AKPageHeader; + } +} diff --git a/web/src/elements/PageHeader.ts b/web/src/components/ak-page-navbar.ts similarity index 81% rename from web/src/elements/PageHeader.ts rename to web/src/components/ak-page-navbar.ts index 909fd8599c22..63856fcfc373 100644 --- a/web/src/elements/PageHeader.ts +++ b/web/src/components/ak-page-navbar.ts @@ -1,17 +1,18 @@ -import { EVENT_WS_MESSAGE, TITLE_DEFAULT } from "@goauthentik/common/constants"; -import { globalAK } from "@goauthentik/common/global"; -import { UIConfig, UserDisplay, getConfigForUser } from "@goauthentik/common/ui/config"; -import { DefaultBrand } from "@goauthentik/common/ui/config"; -import { me } from "@goauthentik/common/users"; -import "@goauthentik/components/ak-nav-buttons"; -import { AKElement } from "@goauthentik/elements/Base"; -import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; -import { isAdminRoute } from "@goauthentik/elements/router/utils"; -import { themeImage } from "@goauthentik/elements/utils/images"; +import { EVENT_WS_MESSAGE, TITLE_DEFAULT } from "#common/constants"; +import { globalAK } from "#common/global"; +import { UIConfig, UserDisplay, getConfigForUser } from "#common/ui/config"; +import { DefaultBrand } from "#common/ui/config"; +import { me } from "#common/users"; +import "#components/ak-nav-buttons"; +import type { PageHeaderInit, SidebarToggleEventDetail } from "#components/ak-page-header"; +import { AKElement } from "#elements/Base"; +import { WithBrandConfig } from "#elements/Interface/brandProvider"; +import { isAdminRoute } from "#elements/router/utils"; +import { themeImage } from "#elements/utils/images"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import { msg } from "@lit/localize"; -import { CSSResult, LitElement, TemplateResult, css, html, nothing } from "lit"; +import { CSSResult, TemplateResult, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css"; @@ -25,23 +26,6 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { SessionUser } from "@goauthentik/api"; -//#region Events - -export interface SidebarToggleEventDetail { - open?: boolean; -} - -//#endregion - -//#region Page Navbar - -export interface PageNavbarDetails { - header?: string; - description?: string; - icon?: string; - iconImage?: boolean; -} - /** * A global navbar component at the top of the page. * @@ -51,13 +35,13 @@ export interface PageNavbarDetails { @customElement("ak-page-navbar") export class AKPageNavbar extends WithBrandConfig(AKElement) - implements PageNavbarDetails, SidebarToggleEventDetail + implements PageHeaderInit, SidebarToggleEventDetail { //#region Static Properties private static elementRef: AKPageNavbar | null = null; - static readonly setNavbarDetails = (detail: Partial): void => { + static readonly setNavbarDetails = (detail: Partial): void => { const { elementRef } = AKPageNavbar; if (!elementRef) { console.debug( @@ -115,7 +99,6 @@ export class AKPageNavbar flex-direction: row; display: grid; - row-gap: var(--pf-global--spacer--sm); column-gap: var(--pf-global--spacer--sm); grid-template-columns: [brand] auto [toggle] auto [primary] 1fr [secondary] auto; grid-template-rows: auto auto; @@ -123,7 +106,7 @@ export class AKPageNavbar "brand toggle primary secondary" "brand toggle description secondary"; - @media (min-width: 426px) { + @media (min-width: 769px) { height: var(--host-navbar-height); } @@ -146,9 +129,17 @@ export class AKPageNavbar grid-column: primary; grid-row: primary / description; - align-content: center; + align-self: center; padding-block: var(--pf-global--spacer--md); + @media (max-width: 768px) { + padding-block: var(--pf-global--spacer--sm); + } + + &.block-sibling { + align-self: end; + } + @media (min-width: 426px) { &.block-sibling { padding-block-end: 0; @@ -156,10 +147,6 @@ export class AKPageNavbar } } - @media (max-width: 768px) { - padding-block: var(--pf-global--spacer--sm); - } - .accent-icon { height: 1em; width: 1em; @@ -249,9 +236,14 @@ export class AKPageNavbar color: var(--pf-global--active-color--100); } - .page-title { - display: flex; - gap: var(--pf-global--spacer--xs); + .pf-c-content .page-title { + display: box; + display: -webkit-box; + line-clamp: 2; + -webkit-line-clamp: 2; + box-orient: vertical; + -webkit-box-orient: vertical; + overflow: hidden; } h1 { @@ -370,7 +362,8 @@ export class AKPageNavbar } render(): TemplateResult { - return html` + return html` +