Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web: fix save & reset behavior on System ➲ Settings page. #8528

Merged
merged 2 commits into from
Feb 15, 2024

Conversation

kensternberg-authentik
Copy link
Contributor

@kensternberg-authentik kensternberg-authentik commented Feb 15, 2024

Details

This page is different from our other pages in that the form is always visible and present and not removed from the DOM at any time during its interaction. Part of the problem was a misapplication of the Lit event cycle, but part of it was just Lit being excessively aggressive with the relationship between values and what is displayed.

Primer: An HTML INPUT tag of any kind is either controlled or uncontrolled. An "uncontrolled" INPUT is managed by the browser; a "controlled" tag is managed by the framework, and changes to some state value in the current view dictates both what is shown and when to re-render. For a controlled text input, for example, every change to the input is captured, stored in the state variable, and the input re-rendered to reflect what the state variable says.

The confusion here is simple. Our form is usually uncontrolled. When you changed a toggle, the state variable (this.settings) did not change, so when you hit [Reset] Lit saw no reason to re-render the form; the control state hadn't changed at all! A reset form showed the wrong value(s). A call to forcibly resetForm() was needed.

The other bug, the problem with [Save], was just a race condition. The value was sent to the back-end, then read back, this.settings updated, and the form re-rendered. The gap between the re-read and the render created a race condition, and the render usually won, reflecting the earlier value. This problem was exacerbated by the implementation of this.setting's getter/setter pair following Lit 3's pattern, when we're currently using Lit 2.

Eventing the "update needed," putting an await() on the event handler after a save, and implementing the getter/setters correctly, created a better sequences of events:

  1. The Form submits and sends a notification that the settings were changed.
  2. When the Page receives a notification that the settings have changed, it retrieves the newly-stored settings and stores them locally.
  3. When the local settings change, Lit schedules a re-render of the Page.
  4. When the Page is re-rendered, the new settings are passed to the Form.
  5. When the Form receives new settings, it re-renders the displayed HTML form.

You'll note that these are five separate, independent events. This isn't a sequence. Each of these is a mini-routine that does its job and quits. (2 is most explicit about this: "... a notification...", not "...the notification...")

Cleanups, comments, etc, added as needed.

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)

If applicable

  • The documentation has been updated
  • The documentation has been formatted (make website)

This page is different from our other pages in that the form is always visible and present and
not removed from the DOM at any time during its interaction.  Part of the problem was a
misapplication of the Lit event cycle, but part of it was just Lit being excessively aggressive
with the relationship between values and what is displayed.

Primer: An HTML INPUT tag of any kind is either controlled or uncontrolled. An "uncontrolled" INPUT
is managed by the browser; a "controlled" tag is managed by the framework, and changes to some state
value in the current view dictates both what is shown and when to re-render. For a controlled text
input, for example, every change to the input is captured, stored in the state variable, and
the input re-rendered to reflect what the state variable says.

The confusion here is simple. Our form is usually uncontrolled. When you changed a toggle, the state
variable (`this.settings`) *did not change*, so when you hit `[Reset]` Lit saw no reason to
re-render the form; the control state hadn't changed at all! A reset form showed the wrong value(s).
A call to forcibly `resetForm()` was needed.

The other bug, the problem with `[Save]`, was just a race condition. The value was sent to the
back-end, then read back, `this.settings` updated, and the form re-rendered. The gap between the
re-read and the render created a race condition, and the render usually won, reflecting the
*earlier* value. This problem was exacerbated by the implementation of `this.setting`'s
getter/setter pair following Lit 3's pattern, when we're currently using Lit 2.

Eventing the "update needed," putting an `await()` on the event handler after a save, and
implementing the getter/setters correctly, created a better sequences of events:

1. The Form submits and sends a notification that the settings were changed.
2. When the Page receives a notification that the settings have changed, it retrieves the
   newly-stored settings and stores them locally.
3. When the local settings change, Lit schedules a re-render of the Page.
4. When the Page is re-rendered, the new settings are passed to the Form.
5. When the Form receives new settings, it re-renders the displayed HTML form.

You'll note that these are five *separate*, *independent* events. This isn't a sequence. Each of
these is a mini-routine that does its job and quits. (2 is most explicit about this: "... a
notification...", not "...the notification...")

Cleanups, comments, etc, added as needed.
Copy link

netlify bot commented Feb 15, 2024

Deploy Preview for authentik-storybook ready!

Name Link
🔨 Latest commit 3ebfd7e
🔍 Latest deploy log https://app.netlify.com/sites/authentik-storybook/deploys/65ce3ae4ff407600089cab5c
😎 Deploy Preview https://deploy-preview-8528--authentik-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@kensternberg-authentik kensternberg-authentik marked this pull request as ready for review February 15, 2024 16:27
@kensternberg-authentik kensternberg-authentik requested a review from a team as a code owner February 15, 2024 16:27
Copy link

netlify bot commented Feb 15, 2024

Deploy Preview for authentik ready!

Name Link
🔨 Latest commit 3ebfd7e
🔍 Latest deploy log https://app.netlify.com/sites/authentik/deploys/65ce3ae4eefb9b0008800c50
😎 Deploy Preview https://deploy-preview-8528--authentik.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@rissson rissson merged commit 07b6356 into main Feb 15, 2024
66 of 68 checks passed
@rissson rissson deleted the web/bug/settings-savings branch February 15, 2024 17:08
@rissson
Copy link
Member

rissson commented Feb 15, 2024

/cherry-pick version-2024.2

BeryJu pushed a commit that referenced this pull request Feb 15, 2024
…#8528) (#8534)

web: fix save & reset behavior on System ➲ Settings page. (#8528)

Co-authored-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants