3f33519ec050e9a9b75cba689620dcbcaaf1dfd7
36 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| a01bb551d0 |
web/standards: fix boolean attribute abuse (#14662)
* web: Add InvalidationFlow to Radius Provider dialogues
## What
- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
- Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`
## Note
Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.
* This (temporary) change is needed to prevent the unit tests from failing.
\# What
\# Why
\# How
\# Designs
\# Test Steps
\# Other Notes
* Revert "This (temporary) change is needed to prevent the unit tests from failing."
This reverts commit
|
|||
| c28b65a3f2 |
Web: Controllers cleanup (#14616)
* web: Fix issues surrounding availability of controllers during init. web: Fix edgecase where flow does not have brand. * web: Fix import path. * web: Clean up mixin/controller paths. * web: Prepare for consistent import styling. - Prep for Storybook fixes. * web: Update MDX types. * web: Fix issues surrounding async imports, MDX typing, relative paths. * web: Format. Clarify. * web: Group module types. |
|||
| b72d0e84c9 | web: (ESLint) Use dot notation. (#14557) | |||
| f70635c295 |
web: Clean up browser-only module imports that crash WebDriverIO. (#14330)
* web: Clean up browser-only module imports that crash WebDriverIO. * web: Clarify slug format output. |
|||
| 3253de73ec |
web: update gen-client-ts to OpenAPI 7.11.0 (#12756)
* web: Add InvalidationFlow to Radius Provider dialogues
## What
- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
- Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`
## Note
Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.
* This (temporary) change is needed to prevent the unit tests from failing.
\# What
\# Why
\# How
\# Designs
\# Test Steps
\# Other Notes
* Revert "This (temporary) change is needed to prevent the unit tests from failing."
This reverts commit
|
|||
| e077a5c18f |
web/admin: bugfix: dual select initialization revision (#12051)
* web: Add InvalidationFlow to Radius Provider dialogues
## What
- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
- Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`
## Note
Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.
* Start of dual select revision process.
* Progress.
* Made the RuleFormHelper's dualselect conform.
* Providers and Selectors harmonized for sources.
* web/bugfix/dual-select-full-options
# What
- Replaces the dual-select "selected" list mechanism with a more comprehensive (if computationally
expensive) version that is correct.
# How
In the previous iteration, each dual select controller gets a *provider* and a *selector*; the
latter keeps the keys of all the objects a specific instance may have, and marks those objects as
"selected" when they appear in the dual-selects "selected" panel.
In order to distinguish between "selected on the existing instance" and "selected by the user," the
*selector* only runs at construction time, creating a unified "selected" list; this is standard and
allows for a uniform experience of adding and deleting items. Unfortunately, this means that the
"selected" items, because their displays are crafted bespoke, are only chosen from those available
at construction. If there are selected items later in the paginated collection, they will not be
marked as selected.
This defeats the purpose of having a paginated multi-select!
The correct way to do this is to retrieve every item pased to the *selector* and use the same
algorithm to craft the views in both windows.
For every instance of Dual Select with dynamic selection, the *provider* and *selector* have been
put in a separate file (usually suffixed as a `*FormHelper.ts` file); the algorithm by which an item is
crafted for use by DualSelect has been broken out into a small function (usually named
`*toSelect()`). The *provider* works as before. The *selector* takes every instance key passed to it
and runs a `Promise.allSettled(...*Retrieve({ uuid: instanceId }))` on them, mapping them onto the
`selected` collection using the same `*toSelect()`, so they resemble the possibilities in every way.
# Lessons
This exercise emphasizes just how much sheer *repetition* the Django REST API creates on the client
side. Every Helper file is a copy-pasta of a sibling, with only a few minor changes:
- How the objects are turned into displays for DualSelect
- The type and calls being used;
- The field on which retrival is defined
- The defaulting rule.
There are 19 `*FormHelper` files, and each one is 50 lines long. That's 950 lines of code.
Of those 950 lines of code, 874 of those lines are *complete duplicates* of those in the other
FormHelper files. Only 76 lines are unique.
This language really needs macros. That, or I need to seriously level up my Typescript and figure
out how to make this whole thing a lot smarter.
* order fields by field_key and order
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
---------
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
|
|||
| 77c595a0fd |
sources/saml: fix NameIDFormat descriptor in metadata generation (#11614)
* source/saml - Changed namespace of X509SSubjectName NameIDFormat Under the SAML2 Core spec (http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf) 8.3.3 the URI of the 5.509 Subject Name contains SAML:1.1 and not SAML:2.0 * source/saml - Change NameIDFormat descriptor build logic to only append chosen format for the source. * Merge diff |
|||
| 8f81237fc5 |
web/admin: fix authentication/enrollment flow in sources being marked as required (#10911)
Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 19c3f7dd80 |
sources/saml: Basic support for EncryptedAssertion element. (#10099)
* source/saml: Updated backend for encrypted assertion support * source/saml: all lint-fix checks passed * source/saml: Used Optional type instead of union, on enc_key_descriptor type hint * source/saml: request_encrypted_assertion model field migration * source/saml: Added 'noqa' comment to type hint on encryption key descriptor * small fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add to UI Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add some error handling Signed-off-by: Jens Langhammer <jens@goauthentik.io> * sources/saml: Pivot to encryption_kp model field, instead of request_encryption bool * sources/saml: Typo fix * re-create migrations Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update web Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add to release notes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * unrelated fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add improve error handling, add tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * test metadata with encryption and remove WantAssertionsEncrypted since it's not in the schema Signed-off-by: Jens Langhammer <jens@goauthentik.io> * unrelated fix to radius path Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix unrelated fix...sigh Signed-off-by: Jens Langhammer <jens@goauthentik.io> * re-migrate Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 83b02a17d5 |
sources: add property mappings for all oauth and saml sources (#8771)
Co-authored-by: Jens L. <jens@goauthentik.io> |
|||
| ee58cf0c1c |
web: add HTMLTagNameElementMaps to everything to activate lit analyzer (#10217)
* web: fix esbuild issue with style sheets
Getting ESBuild, Lit, and Storybook to all agree on how to read and parse stylesheets is a serious
pain. This fix better identifies the value types (instances) being passed from various sources in
the repo to the three *different* kinds of style processors we're using (the native one, the
polyfill one, and whatever the heck Storybook does internally).
Falling back to using older CSS instantiating techniques one era at a time seems to do the trick.
It's ugly, but in the face of the aggressive styling we use to avoid Flashes of Unstyled Content
(FLoUC), it's the logic with which we're left.
In standard mode, the following warning appears on the console when running a Flow:
```
Autofocus processing was blocked because a document already has a focused element.
```
In compatibility mode, the following **error** appears on the console when running a Flow:
```
crawler-inject.js:1106 Uncaught TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.
at initDomMutationObservers (crawler-inject.js:1106:18)
at crawler-inject.js:1114:24
at Array.forEach (<anonymous>)
at initDomMutationObservers (crawler-inject.js:1114:10)
at crawler-inject.js:1549:1
initDomMutationObservers @ crawler-inject.js:1106
(anonymous) @ crawler-inject.js:1114
initDomMutationObservers @ crawler-inject.js:1114
(anonymous) @ crawler-inject.js:1549
```
Despite this error, nothing seems to be broken and flows work as anticipated.
* web: add more linting
* A reliable test for the extra code needed in analyzer, passing shellcheck
* web: re-enable custom-element-manifest and enable component checking in Typescript
This commit includes a monkeypatch to allow custom-element-manifest (CEM) to work correctly again
despite our rich collection of mixins, reactive controllers, symbol-oriented event handlers, and the
like. With that monkeypatch in place, we can now create the CEM manifest file and then exploit it so
that IDEs and the Typescript compilation pass can tell when a component is being used incorrectly;
when the wrong types are being passed to it, or when a required attribute is not initialized.
* Added building the manifest to the build process, rather than storing it. It is not appreciably slow.
* web: the most boring PR in the universe: Add HTMLTagNameElementMap to everyhing
This commit adds HTMLTagNameElementMap entries to every web component in the front end. Activating
and associating the HTMLTagNamElementMap with its class has enabled
[LitAnalyzer](https://github.com/runem/lit-analyzer/tree/master/packages/lit-analyzer) to reveal a
*lot* of basic problems within the UI, the most popular of which is "missing import." We usually get
away with it because the object being imported was already registered with the browser elsewhere,
but it still surprises me that we haven't gotten any complaints over things like:
```
./src/flow/stages/base.ts
Missing import for <ak-form-static>
96: <ak-form-static
no-missing-import
```
Given how early and fundamental that seems to be in our code, I'd have expected to hear _something_
about it.
I have not enabled most of the possible checks because, well, there are just a ton of warnings when
I do. I'd like to get in and fix those.
Aside from this, I have also _removed_ `customElement` declarations from anything declared as an
`abstract class`. It makes no sense to try and instantiate something that cannot, by definition, be
instantiated. If the class is capable of running on its own, it's not abstract, it just needs to be
overridden in child classes. Before removing the declaration I did check to make sure no other
piece of code was even *trying* to instantiate it, and so far I have detected no failures. Those
elements were:
- elements/forms/Form.ts
- element-/wizard/WizardFormPage.ts
The one that blows my mind, though, is this:
```
src/elements/forms/ProxyForm.ts
6-@customElement("ak-proxy-form")
7:export abstract class ProxyForm extends Form<unknown> {
```
Which, despite being `abstract`, is somehow instantiable?
```
src/admin/outposts/ServiceConnectionListPage.ts: <ak-proxy-form
src/admin/providers/ProviderListPage.ts: <ak-proxy-form
src/admin/sources/SourceWizard.ts: <ak-proxy-form
src/admin/sources/SourceListPage.ts: <ak-proxy-form
src/admin/providers/ProviderWizard.ts: <ak-proxy-form type=${type.component}></ak-proxy-form>
src/admin/stages/StageListPage.ts: <ak-proxy-form
```
I've made a note to investigate.
I've started a new folder where all of my one-off tools for *how* a certain PR was run. It has a
README describing what it's for, and the first tool, `add-htmlelementtagnamemaps-to-everything`, is
its first entry. That tool is also documented internally.
``` Gilbert & Sullivan
I've got a little list,
I've got a little list,
Of all the code that would never be missed,
The duplicate code of cute-and-paste,
The weak abstractions that lead to waste,
The embedded templates-- you get the gist,
There ain't none of 'em that will ever be missed,
And that's why I've got them on my list!
```
|
|||
| d555c0db41 |
web: abstract rootInterface()?.config?.capabilities.includes() into .can() (#7737)
* This commit abstracts access to the object `rootInterface()?.config?` into a single accessor,
`authentikConfig`, that can be mixed into any AKElement object that requires access to it.
Since access to `rootInterface()?.config?` is _universally_ used for a single (and repetitive)
boolean check, a separate accessor has been provided that converts all calls of the form:
``` javascript
rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate)
```
into:
``` javascript
this.can(CapabilitiesEnum.CanImpersonate)
```
It does this via a Mixin, `WithCapabilitiesConfig`, which understands that these calls only make
sense in the context of a running, fully configured authentik instance, and that their purpose is to
inform authentik components of a user’s capabilities. The latter is why I don’t feel uncomfortable
turning a function call into a method; we should make it explicit that this is a relationship
between components.
The mixin has a single single field, `[WCC.capabilitiesConfig]`, where its association with the
upper-level configuration is made. If that syntax looks peculiar to you, good! I’ve used an explict
unique symbol as the field name; it is inaccessable an innumerable in the object list. The debugger
shows it only as:
Symbol(): {
cacheTimeout: 300
cacheTimeoutFlows: 300
cacheTimeoutPolicies: 300
cacheTimeoutReputation: 300
capabilities: (5) ['can_save_media', 'can_geo_ip', 'can_impersonate', 'can_debug', 'is_enterprise']
}
Since you can’t reference it by identity, you can’t write to it. Until every browser supports actual
private fields, this is the best we can do; it does guarantee that field name collisions are
impossible, which is a win.
The mixin takes a second optional boolean; setting this to true will cause any web component using
the mixin to automatically schedule a re-render if the capabilities list changes.
The mixin is also generic; despite the "...into a Lit-Context" in the title, the internals of the
Mixin can be replaced with anything so long as the signature of `.can()` is preserved.
Because this work builds off the work I did to give the Sidebar access to the configuration without
ad-hoc retrieval or prop-drilling, it wasn’t necessary to create a new context for it. That will be
necessary for the following:
TODO:
``` javascript
rootInterface()?.uiConfig;
rootInterface()?.tenant;
me();
```
* web: Added a README with a description of the applications' "mental model," essentially an architectural description.
* web: prettier had opinions about the README
* web: Jens requested that subscription be by default, and it's the right call.
* This commit abstracts access to the object `rootInterface()?.config?` into a single accessor,
`authentikConfig`, that can be mixed into any AKElement object that requires access to it.
Since access to `rootInterface()?.config?` is _universally_ used for a single (and repetitive)
boolean check, a separate accessor has been provided that converts all calls of the form:
``` javascript
rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanImpersonate)
```
into:
``` javascript
this.can(CapabilitiesEnum.CanImpersonate)
```
It does this via a Mixin, `WithCapabilitiesConfig`, which understands that these calls only make
sense in the context of a running, fully configured authentik instance, and that their purpose is to
inform authentik components of a user’s capabilities. The latter is why I don’t feel uncomfortable
turning a function call into a method; we should make it explicit that this is a relationship
between components.
The mixin has a single single field, `[WCC.capabilitiesConfig]`, where its association with the
upper-level configuration is made. If that syntax looks peculiar to you, good! I’ve used an explict
unique symbol as the field name; it is inaccessable an innumerable in the object list. The debugger
shows it only as:
Symbol(): {
cacheTimeout: 300
cacheTimeoutFlows: 300
cacheTimeoutPolicies: 300
cacheTimeoutReputation: 300
capabilities: (5) ['can_save_media', 'can_geo_ip', 'can_impersonate', 'can_debug', 'is_enterprise']
}
Since you can’t reference it by identity, you can’t write to it. Until every browser supports actual
private fields, this is the best we can do; it does guarantee that field name collisions are
impossible, which is a win.
The mixin takes a second optional boolean; setting this to true will cause any web component using
the mixin to automatically schedule a re-render if the capabilities list changes.
The mixin is also generic; despite the "...into a Lit-Context" in the title, the internals of the
Mixin can be replaced with anything so long as the signature of `.can()` is preserved.
Because this work builds off the work I did to give the Sidebar access to the configuration without
ad-hoc retrieval or prop-drilling, it wasn’t necessary to create a new context for it. That will be
necessary for the following:
TODO:
``` javascript
rootInterface()?.uiConfig;
rootInterface()?.tenant;
me();
```
* web: Added a README with a description of the applications' "mental model," essentially an architectural description.
* web: prettier had opinions about the README
* web: Jens requested that subscription be by default, and it's the right call.
* web: adjust RAC to point to the (now independent) Interface.
- Also, removed redundant check.
|
|||
| b181c551a5 |
web: expressing success (#7830)
* web: expressing success Ever see an idiom that just, I dunno, *annoyed* you? Automated tools for the win. * web: repetition, repetition, repetition! [throws chair] * web: giving the de-duplication treatment to policy mappings. * Created a BaseStageForm with success message and canonical primary key type for for Providers, Sources, and Stages. |
|||
| c6c6646fd5 |
web: bump lit-analyzer from 2.0.1 to 2.0.2 in /web (#7858)
* web: bump lit-analyzer from 2.0.1 to 2.0.2 in /web Bumps [lit-analyzer](https://github.com/runem/lit-analyzer) from 2.0.1 to 2.0.2. - [Release notes](https://github.com/runem/lit-analyzer/releases) - [Changelog](https://github.com/runem/lit-analyzer/blob/master/CHANGELOG.md) - [Commits](https://github.com/runem/lit-analyzer/commits) --- updated-dependencies: - dependency-name: lit-analyzer dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jens Langhammer <jens@goauthentik.io> |
|||
| b503379319 |
web: fix form default submit handler (#7122)
* web/elements: rename renderInlineForm to renderForm set submit handler to empty function Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix all kinds of forms not using the form inheritance correctly Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| f5394da9f7 |
web: Replace ad-hoc toggle control with ak-toggle-group (#6470)
* web: Replace ad-hoc toggle control with ak-toggle-group
This commit replaces various ad-hoc implementations of the Patternfly Toggle Group HTML with a web
component that encapsulates all of the needed behavior and exposes a single API with a single event
handler, return the value of the option clicked.
The results are: Lots of visual clutter is eliminated. A single link of:
```
<div class="pf-c-toggle-group__item">
<button
class="pf-c-toggle-group__button ${this.mode === ProxyMode.Proxy
? "pf-m-selected"
: ""}"
type="button"
@click=${() => {
this.mode = ProxyMode.Proxy;
}}>
<span class="pf-c-toggle-group__text">${msg("Proxy")}</span>
</button>
</div>
<div class="pf-c-divider pf-m-vertical" role="separator"></div>
```
Now looks like:
```
<option value=${ProxyMode.Proxy}>${msg("Proxy")}</option>
```
This also means that the three pages that used the Patternfly Toggle Group could eliminate all of
their Patternfly PFToggleGroup needs, as well as the `justify-content: center` extension, which also
eliminated the `css` import.
The savings aren't as spectacular as I'd hoped: removed 178 lines, but added 123; total savings 55
lines of code. I still count this a win: we need never write another toggle component again, and
any bugs, extensions or features we may want to add can be centralized or forked without risking the
whole edifice.
* web: minor code formatting issue.
* web: adding a storybook for the ak-toggle-group component
* Bugs found by CI/CD.
* web: Replace ad-hoc search for CryptoCertificateKeyPairs with crypto-certificate-search (#6475)
* web: Replace ad-hoc search for CryptoCertificateKeyPairs with ak-crypto-certeficate-search
This commit replaces various ad-hoc implementations of `search-select` for CryptoCertificateKeyPairs
with a web component that encapsulates all of the needed behavior and exposes a single API.
The results are: Lots of visual clutter is eliminated. A single search of:
```HTML
<ak-search-select
.fetchObjects=${async (query?: string): Promise<CertificateKeyPair[]> => {
const args: CryptoCertificatekeypairsListRequest = {
ordering: "name",
hasKey: true,
includeDetails: false,
};
if (query !== undefined) {
args.search = query;
}
const certificates = await new CryptoApi(
DEFAULT_CONFIG,
).cryptoCertificatekeypairsList(args);
return certificates.results;
}}
.renderElement=${(item: CertificateKeyPair): string => {
return item.name;
}}
.value=${(item: CertificateKeyPair | undefined): string | undefined => {
return item?.pk;
}}
.selected=${(item: CertificateKeyPair): boolean => {
return this.instance?.tlsVerification === item.pk;
}}
?blankable=${true}
>
</ak-search-select>
```
Now looks like:
```HTML
<ak-crypto-certificate-search certificate=${this.instance?.tlsVerification}>
</ak-crypto-certificate-search>
```
There are three searches that do not require there to be a valid key with the certificate; these are
supported with the boolean property `nokey`; likewise, there is one search (in SAMLProviderForm)
that states that if there is no current certificate in the SAMLProvider and only one certificate can
be found in the Authentik database, use that one; this is supported with the boolean property
`singleton`.
These changes replace 382 lines of object-oriented invocations with 36 lines of declarative
configuration, and 98 lines for the class. Overall, the code for "find a crypto certificate" has
been reduced by 46%.
Suggestions for a better word than `singleton` are welcome!
* web: display tests for CryptoCertificateKeypair search
This adds a Storybook for the CryptoCertificateKeypair search, including
a mock fetch of the data. In the course of running the tests, we discovered
that including the SearchSelect _class_ won't include the customElement declaration
unless you include the whole file! Other bugs found: including the CSS from
Storybook is different from that of LitElement native, so much so that the
adapter needed to be included. FlowSearch had a similar bug. The problem
only manifests when building via Webpack (which Storybook uses) and not
Rollup, but we should support both in distribution.
|
|||
| 3f02534eb1 |
web: weightloss program, part 1: FlowSearch (#6332)
* web: weightloss program, part 1: FlowSearch
This commit extracts the multiple uses of SearchSelect for Flow lookups in the `providers`
collection and replaces them with a slightly more legible format, from:
```HTML
<ak-search-select
.fetchObjects=${async (query?: string): Promise<Flow[]> => {
const args: FlowsInstancesListRequest = {
ordering: "slug",
designation: FlowsInstancesListDesignationEnum.Authentication,
};
if (query !== undefined) {
args.search = query;
}
const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList(args);
return flows.results;
}}
.renderElement=${(flow: Flow): string => {
return RenderFlowOption(flow);
}}
.renderDescription=${(flow: Flow): TemplateResult => {
return html`${flow.name}`;
}}
.value=${(flow: Flow | undefined): string | undefined => {
return flow?.pk;
}}
.selected=${(flow: Flow): boolean => {
return flow.pk === this.instance?.authenticationFlow;
}}
>
</ak-search-select>
```
... to:
```HTML
<ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authentication}
.currentFlow=${this.instance?.authenticationFlow}
required
></ak-flow-search>
```
All of those middle methods, like `renderElement`, `renderDescription`, etc, are *completely the
same* for *all* of the searches, and there are something like 25 of them; this commit only covers
the 8 in `providers`, but the next commit should carry all of them.
The topmost example has been extracted into its own Web Component, `ak-flow-search`, that takes only
two arguments: the type of `FlowInstanceListDesignation` and the current instance of the flow.
The static methods for `renderElement`, `renderDescription` and `value` (which are all the same in
all 25 instances of `FlowInstancesListRequest`) have been made into standalone functions.
`fetchObjects` has been made into a method that takes the parameter from the `designation` property,
and `selected` has been turned into a method that takes the comparator instance from the
`currentFlow` property. That's it. That's the whole of it.
`SearchSelect` now emits an event whenever the user changes the field, and `ak-flow-search`
intercepts that event to mirror the value locally.
`Form` has been adapted to recognize the `ak-flow-search` element and extract the current value.
There are a number of legibility issues remaining, even with this fix. The Authentik Form manager
is dependent upon a component named `ak-form-element-horizontal`, which is a container for a single
displayed element in a form:
```HTML
<ak-form-element-horizontal
label=${msg("Authorization flow")}
?required=${true}
name="authorizationFlow"
>
<ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authorization}
.currentFlow=${this.instance?.authorizationFlow}
required
></ak-flow-search>
<p class="pf-c-form__helper-text">
${msg("Flow used when authorizing this provider.")}
</p>
</ak-form-element-horizontal>
```
Imagine, instead, if we could write:
```HTML
<ak-form-element-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authorization}
.currentFlow=${this.instance?.authorizationFlow}
required
name="authorizationFlow">
<label slot="label">${msg("Authorization flow")}</label>
<span slot="help">${msg("Flow used when authorizing this provider.")}</span>
<ak-form-element-flow-search>
```
Starting with a superclass that understands the need for `label` and `help` slots, it would
automatically configure the input object that would be used. We've already specified multiple
identical copies of this thing in multiple different places; centralizing their definition and then
re-using them would be classic code re-use.
Even better, since the Authorization flow is used 10 times in the whole of our code base, and the
Authentication flow 8 times, and they are *all identical*, it would be fitting if we just created
wrappers:
```HTML
<ak-form-element-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authorization}>
<ak-form-element-flow-search>
```
That's really all that's needed. There are *hundreds* (about 470 total) cases where nine or more
lines of repetitious HTML could be replaced with a one-liner like the above.
A "narrow waist" design is one that allows for a system to communicate between two different
components through a small but consistent collection of calls. The Form manager needs to be narrowed
hard. The `ak-form-element-horizontal` is a wrapper around an input object, and it has this at its
core for extracting that information. This forwards the name component to the containing input
object so that when the input object generates an event, we can identify the field it's associated
with.
```Javascript
this.querySelectorAll("*").forEach((input) => {
switch (input.tagName.toLowerCase()) {
case "input":
case "textarea":
case "select":
case "ak-codemirror":
case "ak-chip-group":
case "ak-search-select":
case "ak-radio":
input.setAttribute("name", this.name);
break;
default:
return;
}
```
A *temporary* variant of this is in the `ak-flow-search` component, to support this API without
having to modify `ak-form-element-horizontal`.
And then `ak-form` itself has this:
```Javascript
if (
inputElement.tagName.toLowerCase() === "select" &&
"multiple" in inputElement.attributes
) {
const selectElement = inputElement as unknown as HTMLSelectElement;
json[element.name] = Array.from(selectElement.selectedOptions).map((v) => v.value);
} else if (
inputElement.tagName.toLowerCase() === "input" &&
inputElement.type === "date"
) {
json[element.name] = inputElement.valueAsDate;
} else if (
inputElement.tagName.toLowerCase() === "input" &&
inputElement.type === "datetime-local"
) {
json[element.name] = new Date(inputElement.valueAsNumber);
}
// ... another 20 lines removed
```
This ought to read:
```Javascript
const json = elements.filter((element => element instanceof AkFormComponent)
.reduce((acc, element) => ({ ...acc, [element.name]: element.value] });
```
Where, instead of hand-writing all the different input objects for date and datetime and checkbox
into our forms, and then having to craft custom value extractors for each and every one of them,
just write *one* version of each with all the wrappers and bells and whistles already attached, and
have each one of them have a `value` getter descriptor that returns the value expected by our form
handler.
A back-of-the-envelope estimation is that there's about four *thousand* lines that could disappear
if we did this right.
More importantly, it would be possible to create new `AkFormComponent`s without having to register
them or define them for `ak-form`; as long as they conformed to the AkFormComponent's expectations
for "what is a source of values for a Form", `ak-form` would understand how to handle it.
Ultimately, what I want is to be able to do this:
``` HTML
<ak-input-form
itemtype="ak-search"
itemid="ak-authentication"
itemprop=${this.instance}></ak-inputform>
```
And it will (1) go out and find the right kind of search to put there, (2) conduct the right kind of
fetch to fill that search, (3) pre-configure it with the user's current choice in that locale.
I don't think this is possible-- for one thing, it would be very expensive in terms of development,
and it may break the "narrow waist" ideal by require that the `ak-input-form` object know all the
different kinds of searches that are available. The old Midgardian dream was that the object would
have *just* the identity triple (A table, a row of that table, a field of that row), and the
Javascript would go out and, using the identity, *find* the right object for CRUD (Creating,
Retrieving, Updating, and Deleting) it.
But that inspiration, as unreachable as it is, is where I'm headed. Where our objects are both
*smart* and *standalone*. Where they're polite citizens in an ordered universe, capable of
independence sufficient to be tested and validated and trusted, but working in concert to achieve
our aims.
* web: unravel the search-select for flows completely.
This commit removes *all* instances of the search-select
for flows, classifying them into four different categories:
- a search with no default
- a search with a default
- a search with a default and a fallback to a static default if non specified
- a search with a default and a fallback to the tenant's preferred default if this is a new instance
and no flow specified.
It's not humanly possible to test all the instances where this has been committed, but the linters
are very happy with the results, and I'm going to eyeball every one of them in the github
presentation before I move this out of draft.
* web: several were declared 'required' that were not.
* web: I can't believe this was rejected because of a misspelling in a code comment. Well done\!
* web: another codespell fix for a comment.
* web: adding 'codespell' to the pre-commit command. Fixed spelling error in eventEmitter.
|
|||
| 44a057ed9c |
web: Replace lingui.js with lit-localize (#5761)
* \#\# Details
web: replace lingui with lit/localize
\#\# Changes
This rather massive shift replaces the lingui and `t()` syntax with lit-localize, XLIFF, and the `msg()`
syntax used by lit-localize. 90% of this work was mechanized; simple perl scripts found and replaced
all uses of `t()` with the appropriate corresponding syntax for `msg()` and `msg(str())`.
The XLIFF files were auto-generated from the PO files. They have not been audited, and they should be
checked over by professional translators. The actual _strings_ have not been changed, but as this was
a mechanized change there is always the possibility of mis-translation-- not by the translator, but by
the script.
* web: revise lit/localize: fix two installation issues.
* web: revise localization
TL;DR:
- Replaced all of Lingui's `t()` syntax with `msg()` syntax.
- Mechanically (i.e with a script) converted all of the PO files to XLIFF files
- Refactored the localization code to be a bit smarter:
- the function `getBestMatchLocale` takes the locale lists and a requested locale, and returns the
first match of:
- The locale's code exactly matches the requested locale
- The locale code exactly matches the prefix of the requested locale (i.e the "en" part of "en-US")
- the locale code's prefix exactly matches the prefix of the requested locale
This function is passed to lit-locate's `loadLocale()`.
- `activateLocale()` just calls `loadLocale()` now.
- `autodetectLanguage` searches the following, and picks the first that returns a valid locale
object, before passing it to `loadLocale()`:
- The User's settings
- A `?locale=` component found in `window.location.search`
- The `window.navigator.language` field
- English
The `msg()` only runs when it's run. This seems obvious, but it means that you cannot cache
strings at load time; they must be kept inside functions that are re-run so that the `msg()` engine
can look up the strings in the preferred language of the user at that moment.
You can use thunks-of-strings if you really need them that way.
* Including the 'xliff-converter' in case anyone wants to review it.
* The xliff-converter is tagged as 'xliff-converter', but has been
deleted.
\#\# Details
- Resolves #5171
\#\# Changes
\#\#\# New Features
- Adds a "Add an Application" to the LibraryView if there are no applications and the user is an administrator.
\#\#\# Breaking Changes
- Adds breaking change which causes \<issue\>.
\#\# Checklist
- [ ] Local tests pass (`ak test authentik/`)
- [ ] The code has been formatted (`make lint-fix`)
If an API change has been made
- [ ] The API schema has been updated (`make gen-build`)
If changes to the frontend have been made
- [ ] The code has been formatted (`make web`)
- [ ] The translation files have been updated (`make i18n-extract`)
If applicable
- [ ] The documentation has been updated
- [ ] The documentation has been formatted (`make website`)
* web: fix redundant locales for zh suite.
* web: prettier pass for locale update
* web: localization moderization
Changed the names of the lit-localize commands to make it clear they're
part of the localization effort, and not just "build" and "extract".
* update transifex config
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* fix package lock?
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* use build not compile
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* web: conversion to lit-localize
The CI produced a list of problems that I hadn't caught earlier,
due to a typo ("localize build" is correct, "localize compile" is
not) I had left in package.json. They were minor and linty, but
it was still wise to fix them.
* web: replace lingui with lit/locale
This commit fixes some minor linting issues that were hidden by a typo in package.json. The
issues were not apparently problematic from a Javascript point of view, but they pointed
to sloppy thinking in the progression of types through the system, so I cleaned them
up and formalized the types from LocaleModule to AkLocale.
* web: replace lingui with lit/localize
One problem that has repeatedly come up is that localize's templates do not produce
JavaScript that conforms with our shop style. I've replaced `build-locale` with
a two-step that builds the locale *and* ensures that it conforms to the shop style
via `prettier` every time.
* web: replace lingui with lit-locale
This commit applies the most recent bundle of translations to the
new lit-locale aspect component. It also revises the algorithm
for *finding* the correct locale, replacing the complex fall-back
with some rather straightforward regular expressions.
In the case of Chinese, the fallback comes at the end of the
selection list, which may not be, er, politically valuable
(since Taiwan and Hong Kong come before, being exceptions that
need to be tested). If we need a different order for presentation,
that'll be a future feature.
* web: replace lingui with lit/locale
Well, that was embarassing.
---------
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
|
|||
| 5d5938c412 |
sources/saml: separate verification cert (#5699)
* sources/saml: allow separate verification certificate to be specified Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add migration to keep current behaviour Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update strings Signed-off-by: Jens Langhammer <jens@goauthentik.io> * keep testing verification Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| fef841a458 |
web/admin: always override send method instead of assigning (#5426)
Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| cc8f52b502 |
web/admin: fix state issue after clearIcon/Background is used and for… (#5423)
web/admin: fix state issue after clearIcon/Background is used and form is re-used Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 948b83a2b2 |
web: fix build (#5327)
Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 14f0034a0a |
web/elements: only render form once instance is loaded (#5049)
* web/elements: only render form once instance is loaded Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use radio for transport Signed-off-by: Jens Langhammer <jens@goauthentik.io> * only wait for instance to be loaded if set Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add hook to load additional data in form Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make send an abstract function instead of attribute Signed-off-by: Jens Langhammer <jens@goauthentik.io> * ensure form is updated after data is loaded Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove until for select and multi-selects in forms Signed-off-by: Jens Langhammer <jens@goauthentik.io> * don't use until for file uploads Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove last until from form Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove deprecated import Signed-off-by: Jens Langhammer <jens@goauthentik.io> * prevent form double load, add error handling for PreventFormSubmit Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix double creation of inner element in proxy form Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make PreventFormSubmit work correctly Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 397b9845ec |
web/admin: fix inconsistent display of flows in selections (#4977)
Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| ddbd8153e2 |
web: migrate checkbox to switch (#4409)
* start migrating to switch Signed-off-by: Jens Langhammer <jens@goauthentik.io> * general cleanup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove broken Create provider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * migrate all Signed-off-by: Jens Langhammer <jens@goauthentik.io> * migrate table selectors, fix dark theme Signed-off-by: Jens Langhammer <jens@goauthentik.io> Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| ba5cd6e719 |
web/admin: add Radio control, search-select fixes (#4333)
* move search select to forms folder Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add radio, migrate smaller lists Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * move dropdown when scrolling, hide when container out of frame Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| 6a44695c48 |
web/admin: use flow slug as main name for flow dropdown
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| c46b2d5573 |
web/admin: finish migration to search-select
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| 5fba08c911 |
web/admin: replace more selects with search select
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| 1149a61986 |
web/admin: replace certificate selection with ak-search-select
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| 9f5fb692ba |
sources: add custom icon support (#4022)
* add source icon Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add to oauth form Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add to other browser sources Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add migration, return icon in UI challenges Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * deduplicate file upload Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| 363872715d |
sources/saml: revamp SAML Source (#3785)
* update saml source to use user connections, add all attributes to flow context Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * check for SAML Status in response, add tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * package apple icon Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add webui for connections Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| 44e4f2e561 | crypto: make certificate parsing optional for crypto api (#3711) | |||
| c0270cc3b3 |
web: fix linting
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| 0c48b40848 |
web/admin: allow web-based sources to have empty enrollment/authentication flow
closes #3683 Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |
|||
| 4a91a7d2e2 |
web: re-organise frontend and cleanup common code (#3572)
* fix repo in api client Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web: re-organise files to match their interface Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * core: include version in script tags Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * cleanup maybe broken Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * revert rename Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web: get rid of Client.ts Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * move more to common Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * more moving Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * format Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * unfuck files that vscode fucked, thanks Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * move more Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * finish moving (maybe) Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * ok more moving Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more stuff that vs code destroyed Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * get rid "web" prefix for virtual package Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix locales Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * use custom base element Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix css file Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * don't run autoDetectLanguage when importing locale Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix circular dependencies Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web: fix build Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> |