web/maintenance: remove writeOnly hacks from Form and HorizontalFormElement (#14649)

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

* web/maintenance: remove `writeOnly` hacks from Form and HorizontalFormElement

## What

The `writeOnly` hack substituted an obscuring, read-only field for secret keys and passwords that an
admin should never be able to see/read, only *write*, but allowed the user to click on and replace
the key or password. The hack performed this substitution within `HorizontalFormElement` and
dispersed a flag throughout the code to enforce it. Another hack within `Form` directed the API to
not update / write changes to that field if the field had never been activated.

This commit replaces the `writeOnly` hack with a pair of purpose-built components,
`ak-private-text-input` and `ak-private-textarea-input`, that perform the exact same functionality
but without having to involve the HorizontalFormElement, which really should just be layout and
generic functionality.  It also replaces all the `writeOnly` hackery in Form with a simple
`doNotProcess` flag, which extends and genericizes this capability to any and all input fields.

The only major protocol change is that `?writeOnly` was a *positive* flag; you controlled it by
saying `this.instance !== undefined`; `?revealed` is a *positive* flog; you reveal the working input
field when `this.instance === undefined`.

It is not necessary to specify the monospace, autocomplete, and spell-check features; those are
enabled or disabled automatically when the `input-hint="code"` flag is passed.

## Why

Removing special cases from processing code is an important step toward the Authentik Elements NPM
package, as well as the Schema-Driven Forms update.

## Note

This is actually a very significant change; this is important functionality that I have hand-tested
quite a bit, but could wish for automated testing that also checks the database back-end to ensure
the fixes made write the keys and passwords as required. Checking the back-end directly is important
since these fields are never re-sent to the front-end after being saved!

Things like `placeholder`, `required`, and getting the `name`, `label` or `help` are all issues very
subject to Last-Line Effect, so give this the hairiest eyeball you've got, please.

* Found a few small things, like a missing import that might have broken something.

* web/admin: Update `private-text` field to pass new linting requirement.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes
This commit is contained in:
Ken Sternberg
2025-06-06 15:11:49 -07:00
committed by GitHub
parent 6b530ff764
commit 9a03bdeaf1
16 changed files with 223 additions and 181 deletions

View File

@ -29,11 +29,6 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
* 3. Updated() pushes the `name` field down to the children, as if that were necessary; why isn't
* it being written on-demand when the child is written? Because it's slotted... despite there
* being very few unique uses.
* 4. There is some very specific use-case around the `writeOnly` boolean; this seems to be a case
* where the field isn't available for the user to view unless they explicitly request to be able
* to see the content; otherwise, a dead password field is shown. There are 10 uses of this
* feature.
*
*/
const isAkControl = (el: unknown): boolean =>
@ -79,12 +74,6 @@ export class HorizontalFormElement extends AKElement {
@property({ type: Boolean })
required = false;
@property({ type: Boolean })
writeOnly = false;
@property({ type: Boolean })
writeOnlyActivated = false;
@property({ attribute: false })
errorMessages: string[] | string[][] = [];
@ -130,7 +119,6 @@ export class HorizontalFormElement extends AKElement {
this.querySelectorAll("*").forEach((input) => {
if (isAkControl(input) && !input.getAttribute("name")) {
input.setAttribute("name", this.name);
// This is fine; writeOnly won't apply to anything built this way.
return;
}
@ -139,17 +127,6 @@ export class HorizontalFormElement extends AKElement {
} else {
return;
}
if (this.writeOnly && !this.writeOnlyActivated) {
const i = input as HTMLInputElement;
i.setAttribute("hidden", "true");
const handler = () => {
i.removeAttribute("hidden");
this.writeOnlyActivated = true;
i.parentElement?.removeEventListener("click", handler);
};
i.parentElement?.addEventListener("click", handler);
}
});
}
@ -165,23 +142,8 @@ export class HorizontalFormElement extends AKElement {
</label>
</div>
<div class="pf-c-form__group-control">
${this.writeOnly && !this.writeOnlyActivated
? html`<div class="pf-c-form__horizontal-group">
<input
class="pf-c-form-control"
type="password"
disabled
value="**************"
/>
</div>`
: html``}
<slot class="pf-c-form__horizontal-group"></slot>
<div class="pf-c-form__horizontal-group">
${this.writeOnly
? html`<p class="pf-c-form__helper-text" aria-live="polite">
${msg("Click to change value")}
</p>`
: html``}
${this.errorMessages.map((message) => {
if (message instanceof Object) {
return html`${Object.entries(message).map(([field, errMsg]) => {