Commit Graph

16 Commits

Author SHA1 Message Date
e85d2d0096 Web/cleanup/empty state better slot handling (#14289)
* 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 dddde09be5.

* web: remove Lit syntax from always true attributes

## What

Replaces instances of `?loading=${true}` and `?loading="${true}"` with `loading`

## Why

The Lit syntax is completely unnecessary when the attribute's state is constant, and it's a few
(just a few) extra CPU cycles for Lit to process that.

More to the point, it annoys me.

## How

```
$ perl -pi.bak -e 's/\?loading=\$\{true\}/loading/' $(rg -l '\?loading=\$\{true\}')
$ find . -name '*.bak' -exec rm {} \;
$ perl -pi.bak -e 's/\?loading="\$\{true\}"/loading/' $(rg -l '\?loading="\$\{true\}"')
$ find . -name '*.bak' -exec rm {} \;
```

* Prettier had opinions

* web: move optional textual information out of attributes and into slots

## What

Replaces instances of:

```
<ak-empty-state header=${msg(...)}></ak-empty-state>
```

with

```
<ak-empty-state><span slot="header">${msg(...)}</span></ak-empty-state>
```

## Why

1. It's correct.
2. It lets us elide the decorations for any slots we aren't using.
3. It's preparation for moving to Patternfly 5
4. It annoyed me.

## How

Since we already have Patternfly Elements installed, we have access to the PFE-Core, which has the
unbelievable useful `SlotsController`.  Using it, I created a conditional render template that will
only put in the header, body, and primary slots if there is something in the lightDOM requesting
those slots.  The conditional template will still put the spinner in if the header is not provided
but the loading state is true.

I then had to edit all the places where this is used. For about 30 of them, this script sufficed:

```
perl -pi.bak -e 's/header="?(\$\{msg\([^)]+\)\})"?>/><span slot="header">\1<\/span>/' \
     $(rg -l `<ak-empty-state[^>]header')

```

The other six had to be done by hand.  I have tested a handful of the automatic ones, and all of the
ones that were edited manually.  I'm pleasantly surprised that the textual rules [are inherited by
the slots as expected](https://htmlwithsuperpowers.netlify.app/styling/inheritable.htm).
2025-06-16 08:17:11 -07:00
0ce017b77e web/admin: show selected policy engine mode on bindings pages, allow setting it on sources (#12963)
* web/admin: show select policy engine mode on bindings pages, allow setting it in sources

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* slight cleanup

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-06-10 16:17:31 +02:00
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 dddde09be5.

* web/maintenance: correct the usage of boolean (false) attributes

## What

Just cleaning up a bad habit; we have a lot of `?attribute=${true|false}` (or, more alarmingly,
`.attribute=${true|false}`.  These should just be `attribute` or be missing; anything else is
unnecessary.

Where the attribute is `true` by default, no changes have been made; there are only a few of them,
and they require re-working of the logic to assist with the changes. Booleans should never be `true` by
default, and if you absolutely cannot find an alternative phrasing that makes having them be `false`
by default a valid choice, they should be `reflect: true` to make their presence visible to screen
readers and debuggers.

## Why

Removing non-standard HTML uses from web components matches our programming standards and is an
important step toward the Authentik Elements NPM package, as well as the Schema-Driven Forms update.

## Boring excessive detail.

Because there are literally hundreds of changes, I've documented the boring ones here.

Changes that do *not* meet the basic criteria of "made the component comply with the standards" are
commented in the PR.

Here are all the Boolean property declarations in the system, delta the ones that declare `= true`;
those are documented at the bottom of this commit, and are not addressed in this PR.  This
information is included to guide your decision making.  The second block, below, documents the
actual changes made to component declarations throughout our code.  The third block, at the bottom,
documents changes not made due to logic and effort constraints.

```
components/ak-switch-input.ts:
    @property({ type: Boolean })
    checked: boolean = false;
--
components/ak-switch-input.ts:
    @property({ type: Boolean })
    required = false;
--
components/ak-file-input.ts:
    @property({ type: Boolean })
    required = false;
--
components/HorizontalLightComponent.ts:
    @property({ type: Boolean })
    required = false;
--
components/ak-multi-select.ts:
    @property({ type: Boolean })
    required = false;
--
elements/TreeView.ts:
    @property({ type: Boolean })
    open = false;
--
components/ak-status-label.ts:
    @property({ type: Boolean })
    good = false;
--
components/ak-status-label.ts:
    @property({ type: Boolean })
    compact = false;
--
elements/CodeMirror.ts:
    @property({ type: Boolean })
    readOnly = false;
--
elements/buttons/ModalButton.ts:
    @property({ type: Boolean })
    open = false;
--
elements/EmptyState.ts:
    @property({ type: Boolean })
    fullHeight = false;
--
elements/Tabs.ts:
    @property({ type: Boolean })
    vertical = false;
--
elements/ak-checkbox-group/ak-checkbox-group.ts:
    @property({ type: Boolean })
    required = false;
--
elements/Label.ts:
    @property({ type: Boolean })
    compact = false;
--
elements/forms/FormGroup.ts:
    @property({ type: Boolean, reflect: true })
    expanded = false;
--
elements/Expand.ts:
    @property({ type: Boolean })
    expanded = false;
--
elements/forms/HorizontalFormElement.ts:
    @property({ type: Boolean })
    required = false;
--
elements/forms/HorizontalFormElement.ts:
    @property({ type: Boolean })
    slugMode = false;
--
elements/forms/SearchSelect/ak-portal.ts:
    @property({ type: Boolean, reflect: true })
    open = false;
--
elements/Alert.ts:
    @property({ type: Boolean })
    inline = false;
--
elements/forms/SearchSelect/ak-search-select-view.ts:
    @property({ type: Boolean, reflect: true })
    open = false;
--
elements/forms/SearchSelect/ak-search-select-view.ts:
    @property({ type: Boolean })
    blankable = false;
--
elements/sidebar/SidebarItem.ts:
    @property({ type: Boolean })
    expanded = false;
--
admin/stages/StageWizard.ts:
    @property({ type: Boolean })
    showBindingPage = false;
--
elements/forms/FormElement.ts:
    @property({ type: Boolean })
    required = false;
--
admin/common/ak-flow-search/FlowSearch.ts:
    @property({ type: Boolean })
    required?: boolean = false;
--
admin/applications/ProviderSelectModal.ts:
    @property({ type: Boolean })
    backchannel = false;
--
elements/forms/SearchSelect/SearchSelect.ts:
    @property({ type: Boolean })
    blankable = false;
--
admin/applications/components/ak-provider-search-input.ts:
    @property({ type: Boolean })
    required = false;
--
admin/applications/components/ak-provider-search-input.ts:
    @property({ type: Boolean })
    blankable = false;
--
admin/applications/components/ak-backchannel-input.ts:
    @property({ type: Boolean })
    required = false;
--
admin/policies/PolicyWizard.ts:
    @property({ type: Boolean })
    showBindingPage = false;
```

The attribute 'required' is an HTML native, and is false by default.

Here are all the change pairs around HTML attrbutes:

```
$ git diff | rg -A 1 '\?(backchannel|blankable|checked|compact|expanded|fullHeight|good|inline|open|readOnly|required|showBindingPage|slugMode|vertical)\b'

-                ?required=${true}
+                required

-                    <ak-provider-select-table ?backchannel=${true} .confirm=${this.confirm}>
+                    <ak-provider-select-table backchannel .confirm=${this.confirm}>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${false}

-                    ?required=${true}
+                    required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                                  ?blankable=${true}
+                                  blankable

-                        ?required=${true}
+                        required

-                ?blankable=${true}
+                blankable

-                ?blankable=${true}
+                blankable

-            ?required=${true}
+            required

-            ?required=${true}
+            required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} name="name" ?required=${true}>
+        return html` <ak-form-element-horizontal label=${msg("Name")} name="name" required>

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                    ?blankable=${true}
+                    blankable

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Severity")} ?required=${true} name="severity">
+            <ak-form-element-horizontal label=${msg("Severity")} required name="severity">

-                        ?showBindingPage=${true}
+                        showBindingPage

-                ?showBindingPage=${true}
+                showBindingPage

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Title")} ?required=${true} name="title">
+            <ak-form-element-horizontal label=${msg("Title")} required name="title">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            ?required=${true}
+            required

-            <ak-form-element-horizontal label=${msg("Stage")} ?required=${true} name="stage">
+            <ak-form-element-horizontal label=${msg("Stage")} required name="stage">

-            <ak-form-element-horizontal label=${msg("Order")} ?required=${true} name="order">
+            <ak-form-element-horizontal label=${msg("Order")} required name="order">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                    ?blankable=${true}
+                    blankable

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Type")} ?required=${true} name="type">
+            <ak-form-element-horizontal label=${msg("Type")} required name="type">

-                    ?blankable=${true}
+                    blankable

-                        <ak-label color=${PFColor.Green} ?compact=${true}>
+                        <ak-label color=${PFColor.Green} compact>

-                            ? html`<ak-label color=${PFColor.Red} ?compact=${true}
+                            ? html`<ak-label color=${PFColor.Red} compact

-                            : html`<ak-label color=${PFColor.Green} ?compact=${true}
+                            : html`<ak-label color=${PFColor.Green} compact

-                    ? html`<ak-label color=${PFColor.Orange} ?compact=${true}>
+                    ? html`<ak-label color=${PFColor.Orange} compact>

-                    : html`<ak-label color=${PFColor.Green} ?compact=${true}>
+                    : html`<ak-label color=${PFColor.Green} compact>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Docker URL")} ?required=${true} name="url">
+            <ak-form-element-horizontal label=${msg("Docker URL")} required name="url">

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?showBindingPage=${true}
+                        showBindingPage

-                      ?showBindingPage=${true}
+                      showBindingPage

-                            ?blankable=${true}
+                            blankable

-                            ?blankable=${true}
+                            blankable

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Order")} ?required=${true} name="order">
+            <ak-form-element-horizontal label=${msg("Order")} required name="order">

-            <ak-form-element-horizontal label=${msg("Timeout")} ?required=${true} name="timeout">
+            <ak-form-element-horizontal label=${msg("Timeout")} required name="timeout">

-                    ? html`<ak-label color=${PFColor.Green} ?compact=${true}>
+                    ? html`<ak-label color=${PFColor.Green} compact>

-                    : html`<ak-label color=${PFColor.Orange} ?compact=${true}>
+                    : html`<ak-label color=${PFColor.Orange} compact>

-        return html`<ak-form-element-horizontal label=${msg("User")} ?required=${true} name="user">
+        return html`<ak-form-element-horizontal label=${msg("User")} required name="user">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                            ?blankable=${true}
+                            blankable

-                            ?blankable=${true}
+                            blankable

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                      ?readOnly=${true}
+                      readOnly

-            return html`<ak-empty-state loading ?fullHeight=${true}></ak-empty-state>`;
+            return html`<ak-empty-state loading fullHeight></ak-empty-state>`;

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                            ?blankable=${true}
+                            blankable

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                    ?required=${true}
+                    required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                            ?blankable=${true}
+                            blankable

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-            ?required=${true}
+            required

-                    ?required=${true}
+                    required

-                                        ?blankable=${true}
+                                        blankable

-            <ak-form-element-horizontal label=${msg("Name")} name="name" ?required=${true}>
+            <ak-form-element-horizontal label=${msg("Name")} name="name" required>

-            <ak-form-element-horizontal label=${msg("Protocol")} ?required=${true} name="protocol">
+            <ak-form-element-horizontal label=${msg("Protocol")} required name="protocol">

-            <ak-form-element-horizontal label=${msg("Host")} name="host" ?required=${true}>
+            <ak-form-element-horizontal label=${msg("Host")} name="host" required>

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                    ?required=${false}

-                        ?blankable=${true}
+                        blankable

-                        ?blankable=${true}
+                        blankable

-        return html`<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html`<ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                                      ?readOnly=${true}
+                                      readOnly

-                                    ?blankable=${true}
+                                    blankable

-        return html`<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html`<ak-form-element-horizontal label=${msg("Name")} required name="name">

-                    : html`<ak-label color=${PFColor.Orange} ?compact=${true}>
+                    : html`<ak-label color=${PFColor.Orange} compact>

-                <ak-label color=${PFColor.Grey} ?compact=${true}> ${msg("Built-in")}</ak-label>
+                <ak-label color=${PFColor.Grey} compact> ${msg("Built-in")}</ak-label>

-            return html`<ak-empty-state loading ?fullHeight=${true}></ak-empty-state>`;
+            return html`<ak-empty-state loading fullHeight></ak-empty-state>`;

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${false}>
+            <ak-form-group>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                            ?blankable=${true}
+                            blankable

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                        ?required=${true}
+                        required

-                                ?readOnly=${true}
+                                readOnly

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                <ak-form-element-horizontal label=${msg("SMTP Host")} ?required=${true} name="host">
+                <ak-form-element-horizontal label=${msg("SMTP Host")} required name="host">

-                <ak-form-element-horizontal label=${msg("SMTP Port")} ?required=${true} name="port">
+                <ak-form-element-horizontal label=${msg("SMTP Port")} required name="port">

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                    ?blankable=${true}
+                    blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        <ak-alert ?inline=${true}>
+                        <ak-alert inline>

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                    <ak-form-element-horizontal label=${msg("Mode")} ?required=${true} name="mode">
+                    <ak-form-element-horizontal label=${msg("Mode")} required name="mode">

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                <ak-form-element-horizontal label=${msg("SMTP Host")} ?required=${true} name="host">
+                <ak-form-element-horizontal label=${msg("SMTP Host")} required name="host">

-                <ak-form-element-horizontal label=${msg("SMTP Port")} ?required=${true} name="port">
+                <ak-form-element-horizontal label=${msg("SMTP Port")} required name="port">

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                ?slugMode=${true}
+                slugMode

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Expires")} ?required=${true} name="expires">
+            <ak-form-element-horizontal label=${msg("Expires")} required name="expires">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-                        ?required=${true}
+                        required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Field Key")} ?required=${true} name="fieldKey">
+            <ak-form-element-horizontal label=${msg("Field Key")} required name="fieldKey">

-            <ak-form-element-horizontal label=${msg("Label")} ?required=${true} name="label">
+            <ak-form-element-horizontal label=${msg("Label")} required name="label">

-            <ak-form-element-horizontal label=${msg("Type")} ?required=${true} name="type">
+            <ak-form-element-horizontal label=${msg("Type")} required name="type">

-            <ak-form-element-horizontal label=${msg("Order")} ?required=${true} name="order">
+            <ak-form-element-horizontal label=${msg("Order")} required name="order">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Source")} ?required=${true} name="source">
+            <ak-form-element-horizontal label=${msg("Source")} required name="source">

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        <ak-alert ?inline=${true}>
+                        <ak-alert inline>

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                            ?blankable=${true}
+                            blankable

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("User")} ?required=${true} name="user">
+            <ak-form-element-horizontal label=${msg("User")} required name="user">

-            <ak-form-element-horizontal label=${msg("Intent")} ?required=${true} name="intent">
+            <ak-form-element-horizontal label=${msg("Intent")} required name="intent">

-                ?required=${true}
+                required

-                    <input class="pf-c-switch__input" type="checkbox" ?checked=${true} />
+                    <input class="pf-c-switch__input" type="checkbox" checked />

-                    <input class="pf-c-switch__input" type="checkbox" ?checked=${true} />
+                    <input class="pf-c-switch__input" type="checkbox" checked />

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("User type")} ?required=${true} name="type">
+            <ak-form-element-horizontal label=${msg("User type")} required name="type">

-            <ak-form-element-horizontal label=${msg("Path")} ?required=${true} name="path">
+            <ak-form-element-horizontal label=${msg("Path")} required name="path">

-            ?required=${true}
+            required

-            ?required=${true}
+            required

-            <ak-tabs pageIdentifier="userCredentialsTokens" ?vertical=${true}>
+            <ak-tabs pageIdentifier="userCredentialsTokens" vertical>

-                <ak-status-label ?good=${true}></ak-status-label>
+                <ak-status-label good></ak-status-label>

-                    ?open=${true}
+                    open

-                ?blankable=${true}
+                blankable

-                <ak-tabs ?vertical="${true}">
+                <ak-tabs vertical>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

```

The following issues are the `true` by default Booleans.  As mentioned, these are **not addressed** by this PR.

```
elements/table/Table.ts::
    @property({ type: Boolean })
    paginated = true;

elements/forms/ModalForm.ts::
    @property({ type: Boolean })
    closeAfterSuccessfulSubmit = true;

elements/forms/ModalForm.ts::
    @property({ type: Boolean })
    showSubmitButton = true;

elements/CodeMirror.ts::
    @property({ type: Boolean })
    parseValue = true;

elements/LoadingOverlay.ts::
    @property({ type: Boolean })
    loading = true;

admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts::
    @property({ type: Boolean })
    showConfigurationStages = true;

elements/user/sources/SourceSettings.ts::
    @property({ type: Boolean })
    canConnect = true;

admin/outposts/OutpostHealthSimple.ts::
    @property({ attribute: false })
    showVersion = true;

elements/wizard/Wizard.ts::
    @property({ type: Boolean })
    canCancel = true;

elements/wizard/Wizard.ts::
    @property({ type: Boolean })
    canBack = true;
```

* Prettier had opinions.

* Caught during code review.

* Merged incorrectly; not sure what went wrong, but this re-applies the removal of the  syntax from the current LDAPSourceForm.ts from  to this branch.
2025-06-06 23:06:25 +00:00
6b530ff764 web/admin: use attribute naming scheme for attributes (#14644)
web/standards: use attribute naming scheme for attributes

## What

Renamed the 'inputHint' attribute to 'input-hint', because it is an attribute, not a property.
Properties are camelCased, but attributes are kebab-cased.

Updated all instances where this appears with the usual magic:

```
$ perl -pi.bak -e 's/inputHint="code"/input-hint="code"/' $(rg -l 'inputHint="code"')
```

This fix is in preparation for both the Patternfly 5 project and the Schema-Driven Forms project.

* Revision: You almost certainly do NOT want every field to be reflected.  Booleans are okay, especially for fields that may be changed internally but need to be read by screen-readers, sunch as 'hidden' or 'invalid'.  But if a field is a string or a number and has a default value, you do not want it to be reflected.
2025-06-06 14:49:47 -07:00
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.
2025-05-26 07:06:14 -04:00
b72d0e84c9 web: (ESLint) Use dot notation. (#14557) 2025-05-19 19:33:52 +02:00
0cf6bff93c tests/e2e: add test for authentication flow in compatibility mode (#14392)
* tests/e2e: add test for authentication flow in compatibility mode

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* web: Add prefix class to CSS for easier debugging of constructed stylesheets.

- Use CSS variables for highlighter.

* web: Fix issue where MDX components apply styles out of order.

* web: Fix hover color.

* web: Fix CSS module types. Clean up globals.

* web: Fix issues surrounding availability of shadow root in compatibility mode.

* web: Fix typo.

* web: Partial fixes for storybook dark theme.

* web: Fix overflow.

* web: Fix issues surrounding competing interfaces attempting to apply styles.

* fix padding in ak-alert in. markdown

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* web: Minimize use of sub-module exports.

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Teffen Ellis <teffen@sister.software>
2025-05-15 16:51:11 +02:00
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.
2025-05-02 20:04:05 -04:00
ad733033d7 web: Packagify live reload plugin. (#14134)
* web: Packagify live reload plugin.

* web: Use shared formatter.

* web: Format.

* web: Use project mode typecheck.

* web: Fix type errors.
2025-04-21 19:07:45 +02:00
363d655378 web: Normalize client-side error handling (#13595)
web: Clean up error handling. Prep for permission checks.

- Add clearer reporting for API and network errors.
- Tidy error checking.
- Partial type safety for events.
2025-04-07 19:50:41 +02:00
985d491073 web/admin: fix display bug for assigned users in application bindings in the wizard (#13435)
* 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 dddde09be5.

* web/admin: fix display bug for assigned users in application bindings in the wizard

## What

Modifies the type-of-binding detection algorithm to check if there's a user field and
that it's a number.

## Why

The original type-of-binding detector checked if the field was set and asserted that it was a string
of at least one character. Unfortunately, this doesn't work for `user`, where the primary key is an
integer. Changing the algorithm to "It's really a string with something in it, *or* it's a number,"
works.

## Testing

- Ensure you have at least one user you can use, and that user has a username.
- Navigate through the Application Wizard until you reach the binding page.
- Create a user binding
- See that the user shows up in the table.
2025-03-10 08:34:28 -07:00
cf58c5617a core: Tidy contributor onboarding, fix typos. (#12700)
core: Tidy contributor onboarding.

- Fixes typos.
- Fixes stale links.
- Tidies Makefile so that Poetry env is optional for hygiene commands.
- Remove mismatched YAML naming.
- Uses shebang on Python scripts.
- Document semver usage.
- Redirect OpenAPI schema.

Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
2025-03-06 18:34:54 +00:00
46a968d1dd web: Improve form input validation and visibility. (#12812) 2025-02-14 02:11:35 +01:00
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 dddde09be5.

* web: Update to OpenAPI 7.11.

This commit updates our Makefile to generate the Typescript api using OpenAPI 7.11, and updates
names (mostly of enum targets) in our product to correspond to the changes in how OpenAPI generates
enum source names.

1. Replaced `ProviderModelEnum.` (note terminal period) with `ProviderModelEnum.AuthentikProvider`.
   For example:

```
-    ProviderModelEnum.SamlSamlprovider
+    ProviderModelEnum.AuthentikProvidersSamlSamlprovider
```

2. Replaced `RbacPermissionsAssignedByUsersListModelEnum.` (note terminal period) with
   `RbacPermissionsAssignedByUsersListModelEnum.Authentik`. For example:

```
-    RbacPermissionsAssignedByUsersListModelEnum.ProvidersLdapLdapprovider.toString(),
+    RbacPermissionsAssignedByUsersListModelEnum.AuthentikProvidersLdapLdapprovider.toString(),
```

3. Replaced `SyncObjectModelEnum.` (note terminal period) with
   `SyncObjectModelEnum.AuthentikCoreModels`. For example:

```
-    model=${SyncObjectModelEnum.Group}
+    model=${SyncObjectModelEnum.AuthentikCoreModelsGroup}
```

4. Replaced `SignatureAlgorithmEnum._` (note terminal symbols) with
   `SignatureAlgorithmEnum.HttpWwwW3Org`. For example:

```
-    ["ECDSA-SHA256", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha256],
+    ["ECDSA-SHA256", SignatureAlgorithmEnum.HttpWwwW3Org200104XmldsigMoreecdsaSha256],
```

5. Replaced `DigestAlgorithmEnum._` (note terminal symbols) with `DigestAlgorithmEnum.HttpWwwW3Org`.
   For example:

```
-    ["SHA256", DigestAlgorithmEnum._200104Xmlencsha256, true],
+    ["SHA256", DigestAlgorithmEnum.HttpWwwW3Org200104Xmlencsha256, true],
```

6. Replaced `NameIdPolicyEnum._` (note terminal symbols) with
   `NameIdPolicyEnum.UrnOasisNamesTcSaml`. This one is trickier than the others: If you look
   closely, you'll see that how OpenAPI generates the names has changed, with `nameid` now being
   `Nameid`, and `FormatemailAddress` now being `FormatEmailAddress`.

```
-    value=${NameIdPolicyEnum._11nameidFormatemailAddress}
+    value=${NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
```

# How

After determining how the enum prefixes had changed, I just ran six of these, testing after each
step to ensure that `npm run lint:types` had fewer errors than the previous run, until the product
built without type errors.

``` sh
$ perl -pi.bak -e 's/DigestAlgorithmEnum\._/DigestAlgorithmEnum.HttpWwwW3Org/' $(rg -l 'DigestAlgorithmEnum\.' src/)
```

# Testing

You can validate that these items have changed by finding the prefixes in the source code and
assuring yourself that every option, checkbox, or radio associated with them is populated correctly.

# User documentation changes required.

None.

# Developer documentation changes required.

None.
2025-01-22 08:15:22 -08:00
0befc26507 web: fix error handling bug in ApplicationWizard.RACProviderForm (#12640)
* 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 dddde09be5.

* web: fix error handling bug in ui

# What

When I converted all of the Provider forms over to a unified structure, the RAC form
stood out as one that couldn't be directly converted, so two copies were retained.
The error handling was updated to a new format, but this one bit of older handling
was missed.

For now, we're going back to using `Record<string, string>` for errors, to stay as
close to the `./admin/providers/` style of handling.

# Testing

This error prevented the RAC Provider form from loading in the wizard. Seeing that it works in the
wizard should be sufficient.
2025-01-13 19:56:37 +01:00
c528a6c336 web/admin: add application bindings to the application wizard (#11462)
* web: fix Flash of Unstructured Content while SearchSelect is loading from the backend

Provide an alternative, readonly, disabled, unindexed input object with the text "Loading...", to be
replaced with the _real_ input element after the content is loaded.

This provides the correct appearance and spacing so the content doesn't jiggle about between the
start of loading and the SearchSelect element being finalized.  It was visually distracting and
unappealing.

* web: comment on state management in API layer, move file to point to correct component under test.

* web: test for flash of unstructured content

- Add a unit test to ensure the "Loading..." element is displayed correctly before data arrives
- Demo how to mock a `fetchObjects()` call in testing. Very cool.
- Make distinguishing rule sets for code, tests, and scripts in nightmare mode
- In SearchSelect, Move the `styles()` declaration to the top of the class for consistency.

- To test for the FLOUC issue in SearchSelect.

This is both an exercise in mocking @beryju's `fetchObjects()` protocol, and shows how we can unit
test generic components that render API objects.

* web: interim commit of the basic sortable & selectable table.

* web: added basic unit testing to API-free tables

Mostly these tests assert that the table renders and that the content we give it
is where we expect it to be after sorting. For select tables, it also asserts that
the overall value of the table is what we expect it to be when we click on a
single row, or on the "select all" button.

* web: finalize testing for tables

Includes documentation updates and better tests for select-table.

* Provide unit test accessibility to Firefox and Safari; wrap calls to manipulate test DOMs directly in a browser.exec call so they run in the proper context and be await()ed properly

* web: repeat is needed to make sure sub-elements move around correctly. Map does not do full tracking.

* web: Update HorizontalLightComponent to accurately convey its value "upwards."

* interim commit, gods, the CSS is finally working.

* web: update

Got the binding editor in.  The tests complete.  Removed sonarjs.

* web: fixed tests to complete.

* web: fixed round-trip between binding list and binding editor. Fixed 'delete'.  TODO: Fix error reporting on home page, the edit button is ugly, and the height is off somehow, but I'm not yet sure how. I just know it bugs my eyes.

* core: add support to set policy bindings in transactional endpoint

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* improve permission checks

especially since we'll be using the wizard as default in the future, it shouldn't be superuser only

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* web: update api-less tables

- Replace `th` with `td` in `thead` components. Because Patternfly.
- Add @beryju's styling to the tables, which make it much better looking

* web: wizard for applications, now with bindings!

- Add policy bindings to the application wizard

- Restructures the Wizard base code.
  - ak-wizard-steps holds the steps and listens for NavigationRequest events to move
    from one step to the next.
  - WizardStep is a base class (no component registration provided) that provides the *whole frame*,
    not just the form.  It receives the navigation content for the sidebar from ak-wizard-steps,
    and provides the styling for the header, footer, sidebar, and main form.  It has abstractions
    for `buttons`, `renderMain()`, `handleButton()`, `handleEnable()`, in a section well-marked as
    "Public API".  Steps inherit from this class.

Conceptually:

- A wizard is a series of pages ("steps") with a distinct beginning and end, linked in a series,
  to complete a task.
- Later steps in the series are inaccessible until an earlier steps has granted access to it.
- Access is predicated on the earlier step being complete and valid. The developer is responsible
  for determining what "complete and valid" means.
- The series is visible, giving the customer a sense of how much effort is needed to complete the
  task.
- A parent object maintains (and can modify as needed) the list of steps. It *can* maintain the
  information being collected from the user. Alternatively, that information can be kept in each
  step.

Details:

- Keeping with the Lit paradigm, "requests to change the system flow up, information changed by
  valid requests flows down."
- The information flows up using events: WizardNavigation, WizardUpdate, WizardClose.
- The information flows down using properties.

- ak-application-wizard-main holds the list of steps, providing a unique slot name for each.
  - It maintains the ApplicationWizardState object.
- ApplicationWizardStep inherits from WizardStep and provides:
  - A means of extraction information from forms
  - A convenience method for updating the ApplicationWizardState object, enabling future steps, and
    navigating to a future step, in the correct order.
  - A method for cleaning error from the error reporting mechanism as the user navigates from an
    error-handling state.
  - The title, description, and cancelability of the wizard.
- Steps:
  - step: Handles the application. A good starting point for understanding the point of
    the Wizard.  Check the `handleButton()` method to understand how we enable or disable access to
    future steps.
  - provider-choice: Just a list. Shows validation without the form.
  - provider: Uses a *very* esoteric Lit feature, `unsafeStaticTag`, which enables
    the display to show anything that conforms to the expectations of ApplicationWizardProviderForm.
    - ApplicationWizardProviderForm repeats some of the base of ApplicationWizardStep, but allows us
      to provide multiple variants on a single form without having to create separate steps for each
      form.
    - The forms (`provider-for-ldap`, `provider-for-radius`) are therefore *just* the form and any
      fetchers needed to populate it.
  - bindings: Shows the table of bindings.  Has a custom display for "This table is empty."
  - edit-binding: Showcase for the `SearchSelectEZ` configuration format. Has an override on the
    `handleButton` feature to figure out which binding is about to be overridden. Is also a
    `.hidden` page; it doesn't show up on the navigation sidebar, as is only navigable-to by buttons
    not associated with the button bar at the bottom.
  - submit: Has a lot of machinery of state: Reviewing with errors, reviewing without errors,
    running submission, and success. Uses `ts-pattern` a lot to make sure the state/request pairs
    make sense.

The key insight is that, even though a wizard is a series in order, that order can't be simply
maintained in a list. The parent needs various strategies for swapping pages in and out of the
sequence, while still maintaining a coherent idea of "flow" and providing the visual cues the user
needs to feel confident that the work can be completed and completed quickly. The entire mechanism
for using an array and index to navigate, with index numbering, blocked the implementation of the
bindings pages.

One thing led to another.  *Sigh*  Really wish this hadn't been as much of a mess as it turned out.
The end result is pretty good, though.  Definitely re-usable.

One important feature to note is that the wizard is *not* tied to the ModalButton object; it's
simply embedded in a modal as-needed.  This allows us to use wizards in other places, such as just
being in a DIV, or just a page on its own.

* web: rollback dependabot "upgrade" that broke testing

Dependabot rolled us into WebdriverIO 9.  While that's probably the
right thing to do, right now it breaks out end-to-end tests badly.
Dependabot's mucking with infrastructure should not be taken lightly,
especially in cases when the infrastructure is for DX, not UX, and
doesn't create a bigger attack surface on the running product.

* web: small fixes for wdio and lint

- Roll back another dependabot breaking change, this time to WebdriverIO
- Remove the redundant scripts wrapping ESLint for Precommit mode. Access to those modes is
  available through the flags to the `./web/scripts/eslint.mjs` script.
- Remove SonarJS checks until SonarJS is ESLint 9 compatible.
- Minor nitpicking.

* web: not sure where all these getElement() additions come from; did I add them?  Anyway, they were breaking the tests, they're a Wdio9-ism.

* package-lock.json update

* web: small fixes for wdio and lint

**PLEASE** Stop trying to upgrade WebdriverIO following Dependabot's instructions. The changes
between wdio8 and wdio9 are extensive enough to require a lot more manual intervention. The unit
tests fail in wdio 9, with the testbed driver Wdio uses to compile content to push to the browser
([vite](https://vitejs.dev) complaining:

```
2024-09-27T15:30:03.672Z WARN @wdio/browser-runner:vite: warning: Unrecognized default export in file /Users/ken/projects/dev/web/node_modules/@patternfly/patternfly/components/Dropdown/dropdown.css
  Plugin: postcss-lit
  File: /Users/ken/projects/dev/web/node_modules/@patternfly/patternfly/components/Dropdown/dropdown.css
[0-6] 2024-09-27T15:30:04.083Z INFO webdriver: BIDI COMMAND script.callFunction {"functionDeclaration":"<Function[976 bytes]>","awaitPromise":true,"arguments":[],"target":{"context":"8E608E6D13E355DFFC28112C236B73AF"}}
[0-6]  Error:  Test failed due to following error(s):
  - ak-search-select.test.ts: The requested module '/src/common/styles/authentik.css' does not provide an export named 'default': SyntaxError: The requested module '/src/common/styles/authentik.css' does not provide an export named 'default'

```

So until we can figure out why the Vite installation isn't liking our CSS import scheme, we'll
have to soldier on with what we have.  At least with Wdio 8, we get:

```
Spec Files:      7 passed, 7 total (100% completed) in 00:00:19
```

* Forgot to run prettier.

* web: small fixes for elements and forms

- provides a new utility, `_isSlug_`, used to verify a user input
- extends the ak-horizontal-component wrapper to have a stronger identity and available value
- updates the types that use the wrapper to be typed more strongly
  - (Why) The above are used in the wizard to get and store values
- fixes a bug in SearchSelectEZ that broke the display if the user didn't supply a `groupBy` field.
- Adds `@wdio/types` to the package file so eslint is satisfied wdio builds correctly
- updates the end-to-end test to understand the revised button identities on the login page
  - Running the end-to-end tests verifies that changes to the components listed above did not break
    the semantics of those components.

* Prettier had opinions

* Fix the oauth2 provider test.

* web: fix oauth2 provider.  Fix resolutions in package-lock.json

* Provide an error field for the form errors on the OAuth2 form.  Unfortunately, this does not solve the general problem that we have a UX issue with which stage bindings to show where now that we've introduced the Invalidation Stage.

* 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.

* web/admin: provide default invalidation flows for LDAP provider.

* admin/web: the default invalidation flows for LDAP and Radius are different from the others.

* Updating the SAML Wizard page to correspond to the provider page.  *This is an intermediate fix to get the tests passing. It will probably be mooted with the next revision.*

* Making progress...

* web/admin: provider formectomy complete

* fix minor issues

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* custom ordering for provider types

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix css

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix missing PFBase causing wrong font

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix missing card for type select

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix padding on last page

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add card to bindings

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* web/element/wizard: fix the CSS cascade so the modifications to the title display don't affect the wiard header.

* web/elements/wizard: fix logic on unavailable / available / current indicators in nav bar.

* Debugging code is not needed.

* web: small visual fixes

As requested by reviewers:

- Fixed the height to 75% of the viewport
- Put 1rem of whitespace between the hint label and the Wizard startup button.

* web: disable lint check for cAsEfUnNy AtTrIbUtE nAmEs.

* Apply suggestions from code review

Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Jens L. <jens@beryju.org>

* rework title

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2024-12-18 18:44:27 +01:00