Merge branch 'main' into web/add-htmltagmaps-to-activate-lit-analyzer
* main: core: bump setuptools from 69.5.1 to 70.0.0 (#10503) web: replace multi-select with dual-select for all propertyMapping invocations (#9359) web: enable custom-element-manifest and DOM/JS integration checking. (#10177)
This commit is contained in:
11
poetry.lock
generated
11
poetry.lock
generated
@ -4402,19 +4402,18 @@ test = ["pytest"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "setuptools"
|
name = "setuptools"
|
||||||
version = "69.5.1"
|
version = "70.0.0"
|
||||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"},
|
{file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"},
|
||||||
{file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"},
|
{file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||||
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||||
testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "six"
|
name = "six"
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
"quotes": ["error", "double", { "avoidEscape": true }],
|
"quotes": ["error", "double", { "avoidEscape": true }],
|
||||||
"semi": ["error", "always"],
|
"semi": ["error", "always"],
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
"sonarjs/cognitive-complexity": ["error", 9],
|
"sonarjs/cognitive-complexity": ["warn", 9],
|
||||||
"sonarjs/no-duplicate-string": "off",
|
"sonarjs/no-duplicate-string": "off",
|
||||||
"sonarjs/no-nested-template-literals": "off"
|
"sonarjs/no-nested-template-literals": "off"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ const eslintConfig = {
|
|||||||
"quotes": ["error", "double", { avoidEscape: true }],
|
"quotes": ["error", "double", { avoidEscape: true }],
|
||||||
"semi": ["error", "always"],
|
"semi": ["error", "always"],
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
"sonarjs/cognitive-complexity": ["error", 9],
|
"sonarjs/cognitive-complexity": ["warn", 9],
|
||||||
"sonarjs/no-duplicate-string": "off",
|
"sonarjs/no-duplicate-string": "off",
|
||||||
"sonarjs/no-nested-template-literals": "off",
|
"sonarjs/no-nested-template-literals": "off",
|
||||||
},
|
},
|
||||||
@ -72,5 +72,6 @@ const formatter = await eslint.loadFormatter("stylish");
|
|||||||
const resultText = formatter.format(results);
|
const resultText = formatter.format(results);
|
||||||
const errors = results.reduce((acc, result) => acc + result.errorCount, 0);
|
const errors = results.reduce((acc, result) => acc + result.errorCount, 0);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(resultText);
|
console.log(resultText);
|
||||||
process.exit(errors > 1 ? 1 : 0);
|
process.exit(errors > 1 ? 1 : 0);
|
||||||
|
|||||||
@ -3,11 +3,14 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search";
|
|||||||
import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search";
|
import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search";
|
||||||
import {
|
import {
|
||||||
clientTypeOptions,
|
clientTypeOptions,
|
||||||
defaultScopes,
|
|
||||||
issuerModeOptions,
|
issuerModeOptions,
|
||||||
redirectUriHelp,
|
redirectUriHelp,
|
||||||
subjectModeOptions,
|
subjectModeOptions,
|
||||||
} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm";
|
} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm";
|
||||||
|
import {
|
||||||
|
makeOAuth2PropertyMappingsSelector,
|
||||||
|
oauth2PropertyMappingsProvider,
|
||||||
|
} from "@goauthentik/admin/providers/oauth2/Oauth2PropertyMappings.js";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
|
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/components/ak-number-input";
|
import "@goauthentik/components/ak-number-input";
|
||||||
@ -15,6 +18,7 @@ import "@goauthentik/components/ak-radio-input";
|
|||||||
import "@goauthentik/components/ak-switch-input";
|
import "@goauthentik/components/ak-switch-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/components/ak-textarea-input";
|
import "@goauthentik/components/ak-textarea-input";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
@ -23,17 +27,8 @@ import { customElement, state } from "@lit/reactive-element/decorators.js";
|
|||||||
import { html, nothing } from "lit";
|
import { html, nothing } from "lit";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
import {
|
import { ClientTypeEnum, FlowsInstancesListDesignationEnum, SourcesApi } from "@goauthentik/api";
|
||||||
ClientTypeEnum,
|
import { type OAuth2Provider, type PaginatedOAuthSourceList } from "@goauthentik/api";
|
||||||
FlowsInstancesListDesignationEnum,
|
|
||||||
PropertymappingsApi,
|
|
||||||
SourcesApi,
|
|
||||||
} from "@goauthentik/api";
|
|
||||||
import {
|
|
||||||
type OAuth2Provider,
|
|
||||||
type PaginatedOAuthSourceList,
|
|
||||||
type PaginatedScopeMappingList,
|
|
||||||
} from "@goauthentik/api";
|
|
||||||
|
|
||||||
import BaseProviderPanel from "../BaseProviderPanel";
|
import BaseProviderPanel from "../BaseProviderPanel";
|
||||||
|
|
||||||
@ -42,22 +37,11 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel {
|
|||||||
@state()
|
@state()
|
||||||
showClientSecret = true;
|
showClientSecret = true;
|
||||||
|
|
||||||
@state()
|
|
||||||
propertyMappings?: PaginatedScopeMappingList;
|
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
oauthSources?: PaginatedOAuthSourceList;
|
oauthSources?: PaginatedOAuthSourceList;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
new PropertymappingsApi(DEFAULT_CONFIG)
|
|
||||||
.propertymappingsScopeList({
|
|
||||||
ordering: "scope_name",
|
|
||||||
})
|
|
||||||
.then((propertyMappings: PaginatedScopeMappingList) => {
|
|
||||||
this.propertyMappings = propertyMappings;
|
|
||||||
});
|
|
||||||
|
|
||||||
new SourcesApi(DEFAULT_CONFIG)
|
new SourcesApi(DEFAULT_CONFIG)
|
||||||
.sourcesOauthList({
|
.sourcesOauthList({
|
||||||
ordering: "name",
|
ordering: "name",
|
||||||
@ -222,36 +206,19 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel {
|
|||||||
name="propertyMappings"
|
name="propertyMappings"
|
||||||
.errorMessages=${errors?.propertyMappings ?? []}
|
.errorMessages=${errors?.propertyMappings ?? []}
|
||||||
>
|
>
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results.map((scope) => {
|
.provider=${oauth2PropertyMappingsProvider}
|
||||||
let selected = false;
|
.selector=${makeOAuth2PropertyMappingsSelector(
|
||||||
if (!provider?.propertyMappings) {
|
provider?.propertyMappings,
|
||||||
selected = scope.managed
|
)}
|
||||||
? defaultScopes.includes(scope.managed)
|
available-label=${msg("Available Scopes")}
|
||||||
: false;
|
selected-label=${msg("Selected Scopes")}
|
||||||
} else {
|
></ak-dual-select-dynamic-selected>
|
||||||
selected = Array.from(provider?.propertyMappings).some(
|
|
||||||
(su) => {
|
|
||||||
return su == scope.pk;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(scope.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${scope.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg(
|
${msg(
|
||||||
"Select which scopes can be used by the client. The client still has to specify the scope to access the data.",
|
"Select which scopes can be used by the client. The client still has to specify the scope to access the data.",
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-radio-input
|
<ak-radio-input
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
||||||
|
import {
|
||||||
|
makeProxyPropertyMappingsSelector,
|
||||||
|
proxyPropertyMappingsProvider,
|
||||||
|
} from "@goauthentik/admin/providers/proxy/ProxyProviderPropertyMappings.js";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/components/ak-switch-input";
|
import "@goauthentik/components/ak-switch-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/components/ak-textarea-input";
|
import "@goauthentik/components/ak-textarea-input";
|
||||||
import "@goauthentik/components/ak-toggle-group";
|
import "@goauthentik/components/ak-toggle-group";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
@ -16,7 +21,6 @@ import {
|
|||||||
FlowsInstancesListDesignationEnum,
|
FlowsInstancesListDesignationEnum,
|
||||||
PaginatedOAuthSourceList,
|
PaginatedOAuthSourceList,
|
||||||
PaginatedScopeMappingList,
|
PaginatedScopeMappingList,
|
||||||
PropertymappingsApi,
|
|
||||||
ProxyMode,
|
ProxyMode,
|
||||||
ProxyProvider,
|
ProxyProvider,
|
||||||
SourcesApi,
|
SourcesApi,
|
||||||
@ -29,12 +33,6 @@ type MaybeTemplateResult = TemplateResult | typeof nothing;
|
|||||||
export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
|
export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
new PropertymappingsApi(DEFAULT_CONFIG)
|
|
||||||
.propertymappingsScopeList({ ordering: "scope_name" })
|
|
||||||
.then((propertyMappings: PaginatedScopeMappingList) => {
|
|
||||||
this.propertyMappings = propertyMappings;
|
|
||||||
});
|
|
||||||
|
|
||||||
new SourcesApi(DEFAULT_CONFIG)
|
new SourcesApi(DEFAULT_CONFIG)
|
||||||
.sourcesOauthList({
|
.sourcesOauthList({
|
||||||
ordering: "name",
|
ordering: "name",
|
||||||
@ -88,29 +86,8 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
|
|||||||
</ak-text-input>`;
|
</ak-text-input>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
scopeMappingConfiguration(provider?: ProxyProvider) {
|
|
||||||
const propertyMappings = this.propertyMappings?.results ?? [];
|
|
||||||
|
|
||||||
const defaultScopes = () =>
|
|
||||||
propertyMappings
|
|
||||||
.filter((scope) => !(scope?.managed ?? "").startsWith("goauthentik.io/providers"))
|
|
||||||
.map((pm) => pm.pk);
|
|
||||||
|
|
||||||
const configuredScopes = (providerMappings: string[]) =>
|
|
||||||
propertyMappings.map((scope) => scope.pk).filter((pk) => providerMappings.includes(pk));
|
|
||||||
|
|
||||||
const scopeValues = provider?.propertyMappings
|
|
||||||
? configuredScopes(provider?.propertyMappings ?? [])
|
|
||||||
: defaultScopes();
|
|
||||||
|
|
||||||
const scopePairs = propertyMappings.map((scope) => [scope.pk, scope.name]);
|
|
||||||
|
|
||||||
return { scopePairs, scopeValues };
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const errors = this.wizard.errors.provider;
|
const errors = this.wizard.errors.provider;
|
||||||
const { scopePairs, scopeValues } = this.scopeMappingConfiguration(this.instance);
|
|
||||||
|
|
||||||
return html` <ak-wizard-title>${msg("Configure Proxy Provider")}</ak-wizard-title>
|
return html` <ak-wizard-title>${msg("Configure Proxy Provider")}</ak-wizard-title>
|
||||||
<form class="pf-c-form pf-m-horizontal" @input=${this.handleChange}>
|
<form class="pf-c-form pf-m-horizontal" @input=${this.handleChange}>
|
||||||
@ -179,24 +156,22 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
|
|||||||
certificate=${ifDefined(this.instance?.certificate ?? undefined)}
|
certificate=${ifDefined(this.instance?.certificate ?? undefined)}
|
||||||
></ak-crypto-certificate-search>
|
></ak-crypto-certificate-search>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
<ak-multi-select
|
label=${msg("Additional scopes")}
|
||||||
label=${msg("AdditionalScopes")}
|
|
||||||
name="propertyMappings"
|
name="propertyMappings"
|
||||||
.options=${scopePairs}
|
>
|
||||||
.values=${scopeValues}
|
<ak-dual-select-dynamic-selected
|
||||||
.errorMessages=${errors?.propertyMappings ?? []}
|
.provider=${proxyPropertyMappingsProvider}
|
||||||
.richhelp=${html`
|
.selector=${makeProxyPropertyMappingsSelector(
|
||||||
<p class="pf-c-form__helper-text">
|
this.instance?.propertyMappings,
|
||||||
${msg(
|
|
||||||
"Additional scope mappings, which are passed to the proxy.",
|
|
||||||
)}
|
)}
|
||||||
</p>
|
available-label="${msg("Available Scopes")}"
|
||||||
|
selected-label="${msg("Selected Scopes")}"
|
||||||
|
></ak-dual-select-dynamic-selected>
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg("Hold control/command to select multiple items.")}
|
${msg("Additional scope mappings, which are passed to the proxy.")}
|
||||||
</p>
|
</p>
|
||||||
`}
|
</ak-form-element-horizontal>
|
||||||
></ak-multi-select>
|
|
||||||
|
|
||||||
<ak-textarea-input
|
<ak-textarea-input
|
||||||
name="skipPathRegex"
|
name="skipPathRegex"
|
||||||
|
|||||||
@ -1,44 +1,28 @@
|
|||||||
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
||||||
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import {
|
||||||
|
makeRACPropertyMappingsSelector,
|
||||||
|
racPropertyMappingsProvider,
|
||||||
|
} from "@goauthentik/admin/providers/rac/RACPropertyMappings.js";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { html } from "lit";
|
import { html } from "lit";
|
||||||
import { customElement, state } from "lit/decorators.js";
|
import { customElement } from "lit/decorators.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
import {
|
import { FlowsInstancesListDesignationEnum, RACProvider } from "@goauthentik/api";
|
||||||
FlowsInstancesListDesignationEnum,
|
|
||||||
PaginatedRACPropertyMappingList,
|
|
||||||
PropertymappingsApi,
|
|
||||||
RACProvider,
|
|
||||||
} from "@goauthentik/api";
|
|
||||||
|
|
||||||
import BaseProviderPanel from "../BaseProviderPanel";
|
import BaseProviderPanel from "../BaseProviderPanel";
|
||||||
|
|
||||||
@customElement("ak-application-wizard-authentication-for-rac")
|
@customElement("ak-application-wizard-authentication-for-rac")
|
||||||
export class ApplicationWizardAuthenticationByRAC extends BaseProviderPanel {
|
export class ApplicationWizardAuthenticationByRAC extends BaseProviderPanel {
|
||||||
@state()
|
|
||||||
propertyMappings?: PaginatedRACPropertyMappingList;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
new PropertymappingsApi(DEFAULT_CONFIG)
|
|
||||||
.propertymappingsRacList({
|
|
||||||
ordering: "name",
|
|
||||||
})
|
|
||||||
.then((propertyMappings) => {
|
|
||||||
this.propertyMappings = propertyMappings;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const provider = this.wizard.provider as RACProvider | undefined;
|
const provider = this.wizard.provider as RACProvider | undefined;
|
||||||
const selected = new Set(Array.from(provider?.propertyMappings ?? []));
|
|
||||||
const errors = this.wizard.errors.provider;
|
const errors = this.wizard.errors.provider;
|
||||||
|
|
||||||
return html`<ak-wizard-title
|
return html`<ak-wizard-title
|
||||||
@ -85,17 +69,14 @@ export class ApplicationWizardAuthenticationByRAC extends BaseProviderPanel {
|
|||||||
label=${msg("Property mappings")}
|
label=${msg("Property mappings")}
|
||||||
name="propertyMappings"
|
name="propertyMappings"
|
||||||
>
|
>
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results.map(
|
.provider=${racPropertyMappingsProvider}
|
||||||
(mapping) =>
|
.selector=${makeRACPropertyMappingsSelector(
|
||||||
html`<option
|
provider?.propertyMappings,
|
||||||
value=${ifDefined(mapping.pk)}
|
|
||||||
?selected=${selected.has(mapping.pk)}
|
|
||||||
>
|
|
||||||
${mapping.name}
|
|
||||||
</option>`,
|
|
||||||
)}
|
)}
|
||||||
</select>
|
available-label="${msg("Available Property Mappings")}"
|
||||||
|
selected-label="${msg("Selected Property Mappings")}"
|
||||||
|
></ak-dual-select-dynamic-selected>
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg("Hold control/command to select multiple items.")}
|
${msg("Hold control/command to select multiple items.")}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { ascii_letters, digits, first, randomString } from "@goauthentik/common/
|
|||||||
import "@goauthentik/components/ak-radio-input";
|
import "@goauthentik/components/ak-radio-input";
|
||||||
import "@goauthentik/components/ak-text-input";
|
import "@goauthentik/components/ak-text-input";
|
||||||
import "@goauthentik/components/ak-textarea-input";
|
import "@goauthentik/components/ak-textarea-input";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/Radio";
|
import "@goauthentik/elements/forms/Radio";
|
||||||
@ -23,13 +24,16 @@ import {
|
|||||||
IssuerModeEnum,
|
IssuerModeEnum,
|
||||||
OAuth2Provider,
|
OAuth2Provider,
|
||||||
PaginatedOAuthSourceList,
|
PaginatedOAuthSourceList,
|
||||||
PaginatedScopeMappingList,
|
|
||||||
PropertymappingsApi,
|
|
||||||
ProvidersApi,
|
ProvidersApi,
|
||||||
SourcesApi,
|
SourcesApi,
|
||||||
SubModeEnum,
|
SubModeEnum,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
import {
|
||||||
|
makeOAuth2PropertyMappingsSelector,
|
||||||
|
oauth2PropertyMappingsProvider,
|
||||||
|
} from "./Oauth2PropertyMappings.js";
|
||||||
|
|
||||||
export const clientTypeOptions = [
|
export const clientTypeOptions = [
|
||||||
{
|
{
|
||||||
label: msg("Confidential"),
|
label: msg("Confidential"),
|
||||||
@ -123,7 +127,6 @@ export const redirectUriHelp = html`${redirectUriHelpMessages.map(
|
|||||||
|
|
||||||
@customElement("ak-provider-oauth2-form")
|
@customElement("ak-provider-oauth2-form")
|
||||||
export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
|
export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
|
||||||
propertyMappings?: PaginatedScopeMappingList;
|
|
||||||
oauthSources?: PaginatedOAuthSourceList;
|
oauthSources?: PaginatedOAuthSourceList;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
@ -138,11 +141,6 @@ export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async load(): Promise<void> {
|
async load(): Promise<void> {
|
||||||
this.propertyMappings = await new PropertymappingsApi(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
).propertymappingsScopeList({
|
|
||||||
ordering: "scope_name",
|
|
||||||
});
|
|
||||||
this.oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({
|
this.oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({
|
||||||
ordering: "name",
|
ordering: "name",
|
||||||
hasJwks: true,
|
hasJwks: true,
|
||||||
@ -291,34 +289,20 @@ export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
|
|||||||
>
|
>
|
||||||
</ak-text-input>
|
</ak-text-input>
|
||||||
<ak-form-element-horizontal label=${msg("Scopes")} name="propertyMappings">
|
<ak-form-element-horizontal label=${msg("Scopes")} name="propertyMappings">
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results.map((scope) => {
|
.provider=${oauth2PropertyMappingsProvider}
|
||||||
let selected = false;
|
.selector=${makeOAuth2PropertyMappingsSelector(
|
||||||
if (!provider?.propertyMappings) {
|
provider?.propertyMappings,
|
||||||
selected = scope.managed
|
)}
|
||||||
? defaultScopes.includes(scope.managed)
|
available-label=${msg("Available Scopes")}
|
||||||
: false;
|
selected-label=${msg("Selected Scopes")}
|
||||||
} else {
|
></ak-dual-select-dynamic-selected>
|
||||||
selected = Array.from(provider?.propertyMappings).some((su) => {
|
|
||||||
return su == scope.pk;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(scope.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${scope.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg(
|
${msg(
|
||||||
"Select which scopes can be used by the client. The client still has to specify the scope to access the data.",
|
"Select which scopes can be used by the client. The client still has to specify the scope to access the data.",
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-radio-input
|
<ak-radio-input
|
||||||
name="subMode"
|
name="subMode"
|
||||||
|
|||||||
28
web/src/admin/providers/oauth2/Oauth2PropertyMappings.ts
Normal file
28
web/src/admin/providers/oauth2/Oauth2PropertyMappings.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||||
|
|
||||||
|
import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api";
|
||||||
|
|
||||||
|
export async function oauth2PropertyMappingsProvider(page = 1, search = "") {
|
||||||
|
const propertyMappings = await new PropertymappingsApi(
|
||||||
|
DEFAULT_CONFIG,
|
||||||
|
).propertymappingsScopeList({
|
||||||
|
ordering: "scope_name",
|
||||||
|
pageSize: 20,
|
||||||
|
search: search.trim(),
|
||||||
|
page,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
pagination: propertyMappings.pagination,
|
||||||
|
options: propertyMappings.results.map((scope) => [scope.pk, scope.name, scope.name, scope]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeOAuth2PropertyMappingsSelector(instanceMappings: string[] | undefined) {
|
||||||
|
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||||
|
return localMappings
|
||||||
|
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||||
|
: ([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) =>
|
||||||
|
scope?.managed?.startsWith("goauthentik.io/providers/oauth2/scope-") &&
|
||||||
|
scope?.managed !== "goauthentik.io/providers/oauth2/scope-offline_access";
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/components/ak-toggle-group";
|
import "@goauthentik/components/ak-toggle-group";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
@ -21,14 +22,17 @@ import PFSpacing from "@patternfly/patternfly/utilities/Spacing/spacing.css";
|
|||||||
import {
|
import {
|
||||||
FlowsInstancesListDesignationEnum,
|
FlowsInstancesListDesignationEnum,
|
||||||
PaginatedOAuthSourceList,
|
PaginatedOAuthSourceList,
|
||||||
PaginatedScopeMappingList,
|
|
||||||
PropertymappingsApi,
|
|
||||||
ProvidersApi,
|
ProvidersApi,
|
||||||
ProxyMode,
|
ProxyMode,
|
||||||
ProxyProvider,
|
ProxyProvider,
|
||||||
SourcesApi,
|
SourcesApi,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
import {
|
||||||
|
makeProxyPropertyMappingsSelector,
|
||||||
|
proxyPropertyMappingsProvider,
|
||||||
|
} from "./ProxyProviderPropertyMappings.js";
|
||||||
|
|
||||||
@customElement("ak-provider-proxy-form")
|
@customElement("ak-provider-proxy-form")
|
||||||
export class ProxyProviderFormPage extends BaseProviderForm<ProxyProvider> {
|
export class ProxyProviderFormPage extends BaseProviderForm<ProxyProvider> {
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
@ -45,18 +49,12 @@ export class ProxyProviderFormPage extends BaseProviderForm<ProxyProvider> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async load(): Promise<void> {
|
async load(): Promise<void> {
|
||||||
this.propertyMappings = await new PropertymappingsApi(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
).propertymappingsScopeList({
|
|
||||||
ordering: "scope_name",
|
|
||||||
});
|
|
||||||
this.oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({
|
this.oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({
|
||||||
ordering: "name",
|
ordering: "name",
|
||||||
hasJwks: true,
|
hasJwks: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
propertyMappings?: PaginatedScopeMappingList;
|
|
||||||
oauthSources?: PaginatedOAuthSourceList;
|
oauthSources?: PaginatedOAuthSourceList;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
@ -323,31 +321,17 @@ export class ProxyProviderFormPage extends BaseProviderForm<ProxyProvider> {
|
|||||||
label=${msg("Additional scopes")}
|
label=${msg("Additional scopes")}
|
||||||
name="propertyMappings"
|
name="propertyMappings"
|
||||||
>
|
>
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results
|
.provider=${proxyPropertyMappingsProvider}
|
||||||
.filter((scope) => {
|
.selector=${makeProxyPropertyMappingsSelector(
|
||||||
return !scope.managed?.startsWith("goauthentik.io/providers");
|
this.instance?.propertyMappings,
|
||||||
})
|
)}
|
||||||
.map((scope) => {
|
available-label="${msg("Available Scopes")}"
|
||||||
const selected = (this.instance?.propertyMappings || []).some(
|
selected-label="${msg("Selected Scopes")}"
|
||||||
(su) => {
|
></ak-dual-select-dynamic-selected>
|
||||||
return su == scope.pk;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(scope.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${scope.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg("Additional scope mappings, which are passed to the proxy.")}
|
${msg("Additional scope mappings, which are passed to the proxy.")}
|
||||||
</p>
|
</p>
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
|
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||||
|
|
||||||
|
import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api";
|
||||||
|
|
||||||
|
export async function proxyPropertyMappingsProvider(page = 1, search = "") {
|
||||||
|
const propertyMappings = await new PropertymappingsApi(
|
||||||
|
DEFAULT_CONFIG,
|
||||||
|
).propertymappingsScopeList({
|
||||||
|
ordering: "scope_name",
|
||||||
|
pageSize: 20,
|
||||||
|
search: search.trim(),
|
||||||
|
page,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
pagination: propertyMappings.pagination,
|
||||||
|
options: propertyMappings.results.map((scope) => [scope.pk, scope.name, scope.name, scope]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeProxyPropertyMappingsSelector(mappings?: string[]) {
|
||||||
|
const localMappings = mappings ? new Set(mappings) : undefined;
|
||||||
|
return localMappings
|
||||||
|
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||||
|
: ([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) =>
|
||||||
|
!(scope?.managed ?? "").startsWith("goauthentik.io/providers");
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
|||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/components/ak-radio-input";
|
import "@goauthentik/components/ak-radio-input";
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
@ -12,30 +13,18 @@ import { TemplateResult, html } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators.js";
|
import { customElement, property } from "lit/decorators.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
|
import { AuthModeEnum, Endpoint, ProtocolEnum, RacApi } from "@goauthentik/api";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AuthModeEnum,
|
makeRACPropertyMappingsSelector,
|
||||||
Endpoint,
|
racPropertyMappingsProvider,
|
||||||
PaginatedRACPropertyMappingList,
|
} from "./RACPropertyMappings.js";
|
||||||
PropertymappingsApi,
|
|
||||||
ProtocolEnum,
|
|
||||||
RacApi,
|
|
||||||
} from "@goauthentik/api";
|
|
||||||
|
|
||||||
@customElement("ak-rac-endpoint-form")
|
@customElement("ak-rac-endpoint-form")
|
||||||
export class EndpointForm extends ModelForm<Endpoint, string> {
|
export class EndpointForm extends ModelForm<Endpoint, string> {
|
||||||
@property({ type: Number })
|
@property({ type: Number })
|
||||||
providerID?: number;
|
providerID?: number;
|
||||||
|
|
||||||
propertyMappings?: PaginatedRACPropertyMappingList;
|
|
||||||
|
|
||||||
async load(): Promise<void> {
|
|
||||||
this.propertyMappings = await new PropertymappingsApi(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
).propertymappingsRacList({
|
|
||||||
ordering: "name",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loadInstance(pk: string): Promise<Endpoint> {
|
loadInstance(pk: string): Promise<Endpoint> {
|
||||||
return new RacApi(DEFAULT_CONFIG).racEndpointsRetrieve({
|
return new RacApi(DEFAULT_CONFIG).racEndpointsRetrieve({
|
||||||
pbmUuid: pk,
|
pbmUuid: pk,
|
||||||
@ -124,22 +113,12 @@ export class EndpointForm extends ModelForm<Endpoint, string> {
|
|||||||
</p>
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Property mappings")} name="propertyMappings">
|
<ak-form-element-horizontal label=${msg("Property mappings")} name="propertyMappings">
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results.map((mapping) => {
|
.provider=${racPropertyMappingsProvider}
|
||||||
let selected = false;
|
.selector=${makeRACPropertyMappingsSelector(this.instance?.propertyMappings)}
|
||||||
if (this.instance?.propertyMappings) {
|
available-label="${msg("Available User Property Mappings")}"
|
||||||
selected = Array.from(this.instance?.propertyMappings).some((su) => {
|
selected-label="${msg("Selected User Property Mappings")}"
|
||||||
return su == mapping.pk;
|
></ak-dual-select-dynamic-selected>
|
||||||
});
|
|
||||||
}
|
|
||||||
return html`<option value=${ifDefined(mapping.pk)} ?selected=${selected}>
|
|
||||||
${mapping.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-group>
|
<ak-form-group>
|
||||||
<span slot="header"> ${msg("Advanced settings")} </span>
|
<span slot="header"> ${msg("Advanced settings")} </span>
|
||||||
|
|||||||
22
web/src/admin/providers/rac/RACPropertyMappings.ts
Normal file
22
web/src/admin/providers/rac/RACPropertyMappings.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||||
|
|
||||||
|
import { PropertymappingsApi } from "@goauthentik/api";
|
||||||
|
|
||||||
|
export async function racPropertyMappingsProvider(page = 1, search = "") {
|
||||||
|
const propertyMappings = await new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsRacList({
|
||||||
|
ordering: "name",
|
||||||
|
pageSize: 20,
|
||||||
|
search: search.trim(),
|
||||||
|
page,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
pagination: propertyMappings.pagination,
|
||||||
|
options: propertyMappings.results.map((mapping) => [mapping.pk, mapping.name]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeRACPropertyMappingsSelector(instanceMappings?: string[]) {
|
||||||
|
const localMappings = new Set(instanceMappings ?? []);
|
||||||
|
return ([pk, _]: DualSelectPair) => localMappings.has(pk);
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search";
|
|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
import "@goauthentik/elements/CodeMirror";
|
import "@goauthentik/elements/CodeMirror";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||||
@ -13,30 +14,18 @@ import YAML from "yaml";
|
|||||||
|
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { TemplateResult, html } from "lit";
|
import { TemplateResult, html } from "lit";
|
||||||
import { customElement, state } from "lit/decorators.js";
|
import { customElement } from "lit/decorators.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
|
|
||||||
|
import { FlowsInstancesListDesignationEnum, ProvidersApi, RACProvider } from "@goauthentik/api";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FlowsInstancesListDesignationEnum,
|
makeRACPropertyMappingsSelector,
|
||||||
PaginatedRACPropertyMappingList,
|
racPropertyMappingsProvider,
|
||||||
PropertymappingsApi,
|
} from "./RACPropertyMappings.js";
|
||||||
ProvidersApi,
|
|
||||||
RACProvider,
|
|
||||||
} from "@goauthentik/api";
|
|
||||||
|
|
||||||
@customElement("ak-provider-rac-form")
|
@customElement("ak-provider-rac-form")
|
||||||
export class RACProviderFormPage extends ModelForm<RACProvider, number> {
|
export class RACProviderFormPage extends ModelForm<RACProvider, number> {
|
||||||
@state()
|
|
||||||
propertyMappings?: PaginatedRACPropertyMappingList;
|
|
||||||
|
|
||||||
async load(): Promise<void> {
|
|
||||||
this.propertyMappings = await new PropertymappingsApi(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
).propertymappingsRacList({
|
|
||||||
ordering: "name",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadInstance(pk: number): Promise<RACProvider> {
|
async loadInstance(pk: number): Promise<RACProvider> {
|
||||||
return new ProvidersApi(DEFAULT_CONFIG).providersRacRetrieve({
|
return new ProvidersApi(DEFAULT_CONFIG).providersRacRetrieve({
|
||||||
id: pk,
|
id: pk,
|
||||||
@ -137,27 +126,14 @@ export class RACProviderFormPage extends ModelForm<RACProvider, number> {
|
|||||||
label=${msg("Property mappings")}
|
label=${msg("Property mappings")}
|
||||||
name="propertyMappings"
|
name="propertyMappings"
|
||||||
>
|
>
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results.map((mapping) => {
|
.provider=${racPropertyMappingsProvider}
|
||||||
let selected = false;
|
.selector=${makeRACPropertyMappingsSelector(
|
||||||
if (this.instance?.propertyMappings) {
|
this.instance?.propertyMappings,
|
||||||
selected = Array.from(this.instance?.propertyMappings).some(
|
)}
|
||||||
(su) => {
|
available-label="${msg("Available Property Mappings")}"
|
||||||
return su == mapping.pk;
|
selected-label="${msg("Selected Property Mappings")}"
|
||||||
},
|
></ak-dual-select-dynamic-selected>
|
||||||
);
|
|
||||||
}
|
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(mapping.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${mapping.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal label=${msg("Settings")} name="settings">
|
<ak-form-element-horizontal label=${msg("Settings")} name="settings">
|
||||||
<ak-codemirror
|
<ak-codemirror
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search";
|
|||||||
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
||||||
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
|
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/Radio";
|
import "@goauthentik/elements/forms/Radio";
|
||||||
@ -16,7 +18,6 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
|||||||
import {
|
import {
|
||||||
DigestAlgorithmEnum,
|
DigestAlgorithmEnum,
|
||||||
FlowsInstancesListDesignationEnum,
|
FlowsInstancesListDesignationEnum,
|
||||||
PaginatedSAMLPropertyMappingList,
|
|
||||||
PropertymappingsApi,
|
PropertymappingsApi,
|
||||||
PropertymappingsSamlListRequest,
|
PropertymappingsSamlListRequest,
|
||||||
ProvidersApi,
|
ProvidersApi,
|
||||||
@ -26,6 +27,29 @@ import {
|
|||||||
SpBindingEnum,
|
SpBindingEnum,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
export async function samlPropertyMappingsProvider(page = 1, search = "") {
|
||||||
|
const propertyMappings = await new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSamlList(
|
||||||
|
{
|
||||||
|
ordering: "saml_name",
|
||||||
|
pageSize: 20,
|
||||||
|
search: search.trim(),
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
pagination: propertyMappings.pagination,
|
||||||
|
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeSAMLPropertyMappingsSelector(instanceMappings?: string[]) {
|
||||||
|
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||||
|
return localMappings
|
||||||
|
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||||
|
: ([_0, _1, _2, mapping]: DualSelectPair<SAMLPropertyMapping>) =>
|
||||||
|
mapping?.managed?.startsWith("goauthentik.io/providers/saml");
|
||||||
|
}
|
||||||
|
|
||||||
@customElement("ak-provider-saml-form")
|
@customElement("ak-provider-saml-form")
|
||||||
export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
|
export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
|
||||||
loadInstance(pk: number): Promise<SAMLProvider> {
|
loadInstance(pk: number): Promise<SAMLProvider> {
|
||||||
@ -34,16 +58,6 @@ export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(): Promise<void> {
|
|
||||||
this.propertyMappings = await new PropertymappingsApi(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
).propertymappingsSamlList({
|
|
||||||
ordering: "saml_name",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
propertyMappings?: PaginatedSAMLPropertyMappingList;
|
|
||||||
|
|
||||||
async send(data: SAMLProvider): Promise<SAMLProvider> {
|
async send(data: SAMLProvider): Promise<SAMLProvider> {
|
||||||
if (this.instance) {
|
if (this.instance) {
|
||||||
return new ProvidersApi(DEFAULT_CONFIG).providersSamlUpdate({
|
return new ProvidersApi(DEFAULT_CONFIG).providersSamlUpdate({
|
||||||
@ -193,29 +207,14 @@ export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
|
|||||||
label=${msg("Property mappings")}
|
label=${msg("Property mappings")}
|
||||||
name="propertyMappings"
|
name="propertyMappings"
|
||||||
>
|
>
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results.map((mapping) => {
|
.provider=${samlPropertyMappingsProvider}
|
||||||
let selected = false;
|
.selector=${makeSAMLPropertyMappingsSelector(
|
||||||
if (!this.instance?.propertyMappings) {
|
this.instance?.propertyMappings,
|
||||||
selected =
|
)}
|
||||||
mapping.managed?.startsWith(
|
available-label=${msg("Available User Property Mappings")}
|
||||||
"goauthentik.io/providers/saml",
|
selected-label=${msg("Selected User Property Mappings")}
|
||||||
) || false;
|
></ak-dual-select-dynamic-selected>
|
||||||
} else {
|
|
||||||
selected = Array.from(this.instance?.propertyMappings).some(
|
|
||||||
(su) => {
|
|
||||||
return su == mapping.pk;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(mapping.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${mapping.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg("Hold control/command to select multiple items.")}
|
${msg("Hold control/command to select multiple items.")}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
|
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/Radio";
|
import "@goauthentik/elements/forms/Radio";
|
||||||
@ -15,12 +17,35 @@ import {
|
|||||||
CoreApi,
|
CoreApi,
|
||||||
CoreGroupsListRequest,
|
CoreGroupsListRequest,
|
||||||
Group,
|
Group,
|
||||||
PaginatedSCIMMappingList,
|
|
||||||
PropertymappingsApi,
|
PropertymappingsApi,
|
||||||
ProvidersApi,
|
ProvidersApi,
|
||||||
|
SCIMMapping,
|
||||||
SCIMProvider,
|
SCIMProvider,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
export async function scimPropertyMappingsProvider(page = 1, search = "") {
|
||||||
|
const propertyMappings = await new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsScimList(
|
||||||
|
{
|
||||||
|
ordering: "managed",
|
||||||
|
pageSize: 20,
|
||||||
|
search: search.trim(),
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
pagination: propertyMappings.pagination,
|
||||||
|
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeSCIMPropertyMappingsSelector(instanceMappings: string[] | undefined) {
|
||||||
|
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||||
|
return localMappings
|
||||||
|
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||||
|
: ([_0, _1, _2, mapping]: DualSelectPair<SCIMMapping>) =>
|
||||||
|
mapping?.managed === "goauthentik.io/providers/scim/user";
|
||||||
|
}
|
||||||
|
|
||||||
@customElement("ak-provider-scim-form")
|
@customElement("ak-provider-scim-form")
|
||||||
export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
||||||
loadInstance(pk: number): Promise<SCIMProvider> {
|
loadInstance(pk: number): Promise<SCIMProvider> {
|
||||||
@ -29,16 +54,6 @@ export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(): Promise<void> {
|
|
||||||
this.propertyMappings = await new PropertymappingsApi(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
).propertymappingsScimList({
|
|
||||||
ordering: "managed",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
propertyMappings?: PaginatedSCIMMappingList;
|
|
||||||
|
|
||||||
async send(data: SCIMProvider): Promise<SCIMProvider> {
|
async send(data: SCIMProvider): Promise<SCIMProvider> {
|
||||||
if (this.instance) {
|
if (this.instance) {
|
||||||
return new ProvidersApi(DEFAULT_CONFIG).providersScimUpdate({
|
return new ProvidersApi(DEFAULT_CONFIG).providersScimUpdate({
|
||||||
@ -152,68 +167,34 @@ export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
|||||||
<div slot="body" class="pf-c-form">
|
<div slot="body" class="pf-c-form">
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${msg("User Property Mappings")}
|
label=${msg("User Property Mappings")}
|
||||||
name="propertyMappings"
|
name="propertyMappings">
|
||||||
>
|
<ak-dual-select-dynamic-selected
|
||||||
<select class="pf-c-form-control" multiple>
|
.provider=${scimPropertyMappingsProvider}
|
||||||
${this.propertyMappings?.results.map((mapping) => {
|
.selector=${makeSCIMPropertyMappingsSelector(
|
||||||
let selected = false;
|
this.instance?.propertyMappings,
|
||||||
if (!this.instance?.propertyMappings) {
|
)}
|
||||||
selected =
|
available-label=${msg("Available User Property Mappings")}
|
||||||
mapping.managed === "goauthentik.io/providers/scim/user" ||
|
selected-label=${msg("Selected User Property Mappings")}
|
||||||
false;
|
></ak-dual-select-dynamic-selected>
|
||||||
} else {
|
|
||||||
selected = Array.from(this.instance?.propertyMappings).some(
|
|
||||||
(su) => {
|
|
||||||
return su == mapping.pk;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(mapping.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${mapping.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
</select>
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg("Property mappings used to user mapping.")}
|
${msg("Property mappings used to user mapping.")}
|
||||||
</p>
|
</p>
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${msg("Group Property Mappings")}
|
label=${msg("Group Property Mappings")}
|
||||||
name="propertyMappingsGroup"
|
name="propertyMappingsGroup">
|
||||||
>
|
<ak-dual-select-dynamic-selected
|
||||||
<select class="pf-c-form-control" multiple>
|
.provider=${scimPropertyMappingsProvider}
|
||||||
${this.propertyMappings?.results.map((mapping) => {
|
.selector=${makeSCIMPropertyMappingsSelector(
|
||||||
let selected = false;
|
|
||||||
if (!this.instance?.propertyMappingsGroup) {
|
|
||||||
selected =
|
|
||||||
mapping.managed === "goauthentik.io/providers/scim/group";
|
|
||||||
} else {
|
|
||||||
selected = Array.from(
|
|
||||||
this.instance?.propertyMappingsGroup,
|
this.instance?.propertyMappingsGroup,
|
||||||
).some((su) => {
|
)}
|
||||||
return su == mapping.pk;
|
available-label=${msg("Available Group Property Mappings")}
|
||||||
});
|
selected-label=${msg("Selected Group Property Mappings")}
|
||||||
}
|
></ak-dual-select-dynamic-selected>
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(mapping.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${mapping.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg("Property mappings used to group creation.")}
|
${msg("Property mappings used to group creation.")}
|
||||||
</p>
|
</p>
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-group>`;
|
</ak-form-group>`;
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { placeholderHelperText } from "@goauthentik/admin/helperText";
|
|||||||
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
|
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||||
|
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||||
import "@goauthentik/elements/forms/FormGroup";
|
import "@goauthentik/elements/forms/FormGroup";
|
||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||||
import "@goauthentik/elements/forms/SearchSelect";
|
import "@goauthentik/elements/forms/SearchSelect";
|
||||||
@ -16,13 +18,37 @@ import {
|
|||||||
CoreApi,
|
CoreApi,
|
||||||
CoreGroupsListRequest,
|
CoreGroupsListRequest,
|
||||||
Group,
|
Group,
|
||||||
|
LDAPPropertyMapping,
|
||||||
LDAPSource,
|
LDAPSource,
|
||||||
LDAPSourceRequest,
|
LDAPSourceRequest,
|
||||||
PaginatedLDAPPropertyMappingList,
|
|
||||||
PropertymappingsApi,
|
PropertymappingsApi,
|
||||||
SourcesApi,
|
SourcesApi,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
async function propertyMappingsProvider(page = 1, search = "") {
|
||||||
|
const propertyMappings = await new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsLdapList(
|
||||||
|
{
|
||||||
|
ordering: "managed,object_field",
|
||||||
|
pageSize: 20,
|
||||||
|
search: search.trim(),
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
pagination: propertyMappings.pagination,
|
||||||
|
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function makePropertyMappingsSelector(instanceMappings?: string[]) {
|
||||||
|
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||||
|
return localMappings
|
||||||
|
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||||
|
: ([_0, _1, _2, mapping]: DualSelectPair<LDAPPropertyMapping>) =>
|
||||||
|
mapping?.managed?.startsWith("goauthentik.io/sources/ldap/default") ||
|
||||||
|
mapping?.managed?.startsWith("goauthentik.io/sources/ldap/ms");
|
||||||
|
}
|
||||||
|
|
||||||
@customElement("ak-source-ldap-form")
|
@customElement("ak-source-ldap-form")
|
||||||
export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
||||||
loadInstance(pk: string): Promise<LDAPSource> {
|
loadInstance(pk: string): Promise<LDAPSource> {
|
||||||
@ -31,16 +57,6 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(): Promise<void> {
|
|
||||||
this.propertyMappings = await new PropertymappingsApi(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
).propertymappingsLdapList({
|
|
||||||
ordering: "managed,object_field",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
propertyMappings?: PaginatedLDAPPropertyMappingList;
|
|
||||||
|
|
||||||
async send(data: LDAPSource): Promise<LDAPSource> {
|
async send(data: LDAPSource): Promise<LDAPSource> {
|
||||||
if (this.instance) {
|
if (this.instance) {
|
||||||
return new SourcesApi(DEFAULT_CONFIG).sourcesLdapPartialUpdate({
|
return new SourcesApi(DEFAULT_CONFIG).sourcesLdapPartialUpdate({
|
||||||
@ -277,71 +293,32 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
|||||||
label=${msg("User Property Mappings")}
|
label=${msg("User Property Mappings")}
|
||||||
name="propertyMappings"
|
name="propertyMappings"
|
||||||
>
|
>
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results.map((mapping) => {
|
.provider=${propertyMappingsProvider}
|
||||||
let selected = false;
|
.selector=${makePropertyMappingsSelector(
|
||||||
if (!this.instance?.propertyMappings) {
|
this.instance?.propertyMappings,
|
||||||
selected =
|
)}
|
||||||
mapping.managed?.startsWith(
|
available-label="${msg("Available User Property Mappings")}"
|
||||||
"goauthentik.io/sources/ldap/default",
|
selected-label="${msg("Selected User Property Mappings")}"
|
||||||
) ||
|
></ak-dual-select-dynamic-selected>
|
||||||
mapping.managed?.startsWith(
|
|
||||||
"goauthentik.io/sources/ldap/ms",
|
|
||||||
) ||
|
|
||||||
false;
|
|
||||||
} else {
|
|
||||||
selected = Array.from(this.instance?.propertyMappings).some(
|
|
||||||
(su) => {
|
|
||||||
return su == mapping.pk;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(mapping.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${mapping.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg("Property mappings used to user creation.")}
|
${msg("Property mappings for user creation.")}
|
||||||
</p>
|
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal
|
<ak-form-element-horizontal
|
||||||
label=${msg("Group Property Mappings")}
|
label=${msg("Group Property Mappings")}
|
||||||
name="propertyMappingsGroup"
|
name="propertyMappingsGroup"
|
||||||
>
|
>
|
||||||
<select class="pf-c-form-control" multiple>
|
<ak-dual-select-dynamic-selected
|
||||||
${this.propertyMappings?.results.map((mapping) => {
|
.provider=${propertyMappingsProvider}
|
||||||
let selected = false;
|
.selector=${makePropertyMappingsSelector(
|
||||||
if (!this.instance?.propertyMappingsGroup) {
|
|
||||||
selected =
|
|
||||||
mapping.managed ===
|
|
||||||
"goauthentik.io/sources/ldap/default-name";
|
|
||||||
} else {
|
|
||||||
selected = Array.from(
|
|
||||||
this.instance?.propertyMappingsGroup,
|
this.instance?.propertyMappingsGroup,
|
||||||
).some((su) => {
|
)}
|
||||||
return su == mapping.pk;
|
available-label="${msg("Available Group Property Mappings")}"
|
||||||
});
|
selected-label="${msg("Selected Group Property Mappings")}"
|
||||||
}
|
></ak-dual-select-dynamic-selected>
|
||||||
return html`<option
|
|
||||||
value=${ifDefined(mapping.pk)}
|
|
||||||
?selected=${selected}
|
|
||||||
>
|
|
||||||
${mapping.name}
|
|
||||||
</option>`;
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${msg("Property mappings used to group creation.")}
|
${msg("Property mappings for group creation.")}
|
||||||
</p>
|
|
||||||
<p class="pf-c-form__helper-text">
|
|
||||||
${msg("Hold control/command to select multiple items.")}
|
|
||||||
</p>
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -0,0 +1,52 @@
|
|||||||
|
import { PropertyValues, html } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators.js";
|
||||||
|
import { ref } from "lit/directives/ref.js";
|
||||||
|
|
||||||
|
import { AkDualSelectProvider } from "./ak-dual-select-provider.js";
|
||||||
|
import "./ak-dual-select.js";
|
||||||
|
import type { DualSelectPair } from "./types.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @element ak-dual-select-dynamic-provider
|
||||||
|
*
|
||||||
|
* A top-level component for multi-select elements have dynamically generated "selected"
|
||||||
|
* lists.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@customElement("ak-dual-select-dynamic-selected")
|
||||||
|
export class AkDualSelectDynamic extends AkDualSelectProvider {
|
||||||
|
/**
|
||||||
|
* An extra source of "default" entries. A number of our collections have an alternative default
|
||||||
|
* source when initializing a new component instance of that collection's host object. Only run
|
||||||
|
* on start-up.
|
||||||
|
*
|
||||||
|
* @attr
|
||||||
|
*/
|
||||||
|
@property({ attribute: false })
|
||||||
|
selector: ([key, _]: DualSelectPair) => boolean = ([_key, _]) => false;
|
||||||
|
|
||||||
|
private firstUpdateHasRun = false;
|
||||||
|
|
||||||
|
willUpdate(changed: PropertyValues<this>) {
|
||||||
|
super.willUpdate(changed);
|
||||||
|
// On the first update *only*, even before rendering, when the options are handed up, update
|
||||||
|
// the selected list with the contents derived from the selector.
|
||||||
|
if (!this.firstUpdateHasRun && this.options.length > 0) {
|
||||||
|
this.firstUpdateHasRun = true;
|
||||||
|
this.selected = Array.from(
|
||||||
|
new Set([...this.selected, ...this.options.filter(this.selector)]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`<ak-dual-select
|
||||||
|
${ref(this.dualSelector)}
|
||||||
|
.options=${this.options}
|
||||||
|
.pages=${this.pagination}
|
||||||
|
.selected=${this.selected}
|
||||||
|
available-label=${this.availableLabel}
|
||||||
|
selected-label=${this.selectedLabel}
|
||||||
|
></ak-dual-select>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -27,36 +27,59 @@ import type { DataProvider, DualSelectPair } from "./types";
|
|||||||
|
|
||||||
@customElement("ak-dual-select-provider")
|
@customElement("ak-dual-select-provider")
|
||||||
export class AkDualSelectProvider extends CustomListenerElement(AKElement) {
|
export class AkDualSelectProvider extends CustomListenerElement(AKElement) {
|
||||||
/** A function that takes a page and returns the DualSelectPair[] collection with which to update
|
/**
|
||||||
|
* A function that takes a page and returns the DualSelectPair[] collection with which to update
|
||||||
* the "Available" pane.
|
* the "Available" pane.
|
||||||
|
*
|
||||||
|
* @attr
|
||||||
*/
|
*/
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
provider!: DataProvider;
|
provider!: DataProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of selected items. This is the *complete* list, not paginated, as presented by a
|
||||||
|
* component with a multi-select list of items to track.
|
||||||
|
*
|
||||||
|
* @attr
|
||||||
|
*/
|
||||||
@property({ type: Array })
|
@property({ type: Array })
|
||||||
selected: DualSelectPair[] = [];
|
selected: DualSelectPair[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The label for the left ("available") pane
|
||||||
|
*
|
||||||
|
* @attr
|
||||||
|
*/
|
||||||
@property({ attribute: "available-label" })
|
@property({ attribute: "available-label" })
|
||||||
availableLabel = msg("Available options");
|
availableLabel = msg("Available options");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The label for the right ("selected") pane
|
||||||
|
*
|
||||||
|
* @attr
|
||||||
|
*/
|
||||||
@property({ attribute: "selected-label" })
|
@property({ attribute: "selected-label" })
|
||||||
selectedLabel = msg("Selected options");
|
selectedLabel = msg("Selected options");
|
||||||
|
|
||||||
/** The remote lists are debounced by definition. This is the interval for the debounce. */
|
/**
|
||||||
|
* The debounce for the search as the user is typing in a request
|
||||||
|
*
|
||||||
|
* @attr
|
||||||
|
*/
|
||||||
@property({ attribute: "search-delay", type: Number })
|
@property({ attribute: "search-delay", type: Number })
|
||||||
searchDelay = 250;
|
searchDelay = 250;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private options: DualSelectPair[] = [];
|
options: DualSelectPair[] = [];
|
||||||
|
|
||||||
private dualSelector: Ref<AkDualSelect> = createRef();
|
protected dualSelector: Ref<AkDualSelect> = createRef();
|
||||||
|
|
||||||
private isLoading = false;
|
protected isLoading = false;
|
||||||
|
|
||||||
private doneFirstUpdate = false;
|
private doneFirstUpdate = false;
|
||||||
private internalSelected: DualSelectPair[] = [];
|
private internalSelected: DualSelectPair[] = [];
|
||||||
|
|
||||||
private pagination?: Pagination;
|
protected pagination?: Pagination;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { Pagination } from "@goauthentik/api";
|
|||||||
|
|
||||||
// Key, Label (string or TemplateResult), (optional) string to sort by. If the sort string is
|
// Key, Label (string or TemplateResult), (optional) string to sort by. If the sort string is
|
||||||
// missing, it will use the label, which doesn't always work for TemplateResults).
|
// missing, it will use the label, which doesn't always work for TemplateResults).
|
||||||
export type DualSelectPair = [string, string | TemplateResult, string?];
|
export type DualSelectPair<T = never> = [string, string | TemplateResult, string?, T?];
|
||||||
|
|
||||||
export type BasePagination = Pick<
|
export type BasePagination = Pick<
|
||||||
Pagination,
|
Pagination,
|
||||||
|
|||||||
Reference in New Issue
Block a user