b361dd3b59be672abe77e2b55407a652b8d34b1c
48 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| d97297e0ce |
web: (ESLint) Consistent use of triple-equals. (#14554)
web: Consistent use of triple-equals. |
|||
| 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> |
|||
| 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. |
|||
| 61a26c02b7 |
Revert-revert: Safari fixes (#14331)
* Reapply "web: Safari fixes merge branch (#14181)"
This reverts commit
|
|||
| 337956672f | Revert "web: Safari fixes merge branch (#14181)" (#14211) | |||
| cf160f800d |
web: Safari fixes merge branch (#14181)
* web/admin: Fix layout centering. Adjust theming. * web: Fix issue where references to Lit SSR break page styles. * web: Fix issues surrounding color scheme/theme mixup in UI. |
|||
| 0e83de2697 | web: Tidy temporal utilities. (#13755) | |||
| 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. |
|||
| e4a8c05d25 |
web/admin: fix diff showing previous false as "-" (#13580)
Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 46a968d1dd | web: Improve form input validation and visibility. (#12812) | |||
| 656beebd63 | web/components: ak-number-input: add support for min (#12703) | |||
| 2893a54ffb |
web/admin: more cleanup and consistency (#12657)
* web/admin: migrate user interface and stop impersonation to nav bar Signed-off-by: Jens Langhammer <jens@goauthentik.io> * move version diff to banner Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make click on backdrop close about modal just for you @rissson Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| d17f781d11 |
web: misc fixes for admin and flow inspector (#12461)
* fix flow inspector not closable on error Signed-off-by: Jens Langhammer <jens@goauthentik.io> # Conflicts: # authentik/enterprise/providers/ssf/views/configuration.py * unrelated: fix flow inspector for in memory stages Signed-off-by: Jens Langhammer <jens@goauthentik.io> * only open inspector when there's size Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix relative links Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| dc3559c7e9 |
web: housekeeping, optimizations and small fixes (#12450)
* web/user: fix incorrect font in RAC endpoint popup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix navbar button colour in light mode Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add about modal Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix sidebar overlapping page header Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix wizard hint alignment Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add loading state to about modal Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add version context Signed-off-by: Jens Langhammer <jens@goauthentik.io> * stub out init functions on loading interface saves 4 HTTP requests on each full page load 🎉 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix z-index for panels Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove redundant api request Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 02bd699917 |
web/admin: Refine navigation (#12441)
* fix spacing if there's no icon in page header Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add a very slight bar Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rework navigation to be similar between interfaces Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix subpath and rendering Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix display Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add version to sidebar Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make page header sticky? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * unrelated: hide session in system api Signed-off-by: Jens Langhammer <jens@goauthentik.io> * unrelated: add unidecode for policies Signed-off-by: Jens Langhammer <jens@goauthentik.io> #5859 --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 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> |
|||
| 0a1d283ac8 |
web: provide storybook demos and docs for existing tests (#11651)
* Added tests and refinements as tests indicate. * Building out the test suite. * web: test the simple things. Fix what the tests revealed. - Move `EmptyState.test.ts` into the `./tests` folder. - Provide unit tests for: - Alert - Divider - Expand - Label - LoadingOverlay - Give all tested items an Interface and a functional variant for rendering - Give Label an alternative syntax for declaring alert levels - Remove the slot name in LoadingOverlay - Change the slot call in `./enterprise/rac/index.ts` to not need the slot name as well - Change the attribute names `topMost`, `textOpen`, and `textClosed` to `topmost`, `text-open`, and `text-closed`, respectively. - Change locations in the code where those are used to correspond ** Why interfaces: ** Provides another check on the input/output boundaries of our elements, gives Storybook and WebdriverIO another validation to check, and guarantees any rendering functions cannot be passed invalid property names. ** Why functions for rendering: ** Providing functions for rendering gets us one step closer to dynamically defining our forms-in-code at runtime without losing any type safety. ** Why rename the attributes: ** A *very* subtle bug: [Element:setAttribute()](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute) automatically "converts an attribute name to all lower-case when called on an HTML element in an HTML document." The three attributes renamed are all treated *as* attributes, either classic boolean or stringly-typed attributes, and attempting to manipulate them with `setAttribute()` will fail. All of these attributes are presentational; none of them end up in a transaction with the back-end, so kebab-to-camel conversions are not a concern. Also, ["topmost" is one word](https://www.merriam-webster.com/dictionary/topmost). ** Why remove the slot name: ** Because there was only one slot. A name is not needed. * Fix minor spelling error. * First pass at a custom, styled input object. * . * web: Demo the simple things. Fix things the Demo says need fixing. - Move the Element's stories into a `./stories` folder - Provide stories for (these are the same ones "provided tests for" in the [previous PR](https://github.com/goauthentik/authentik/pull/11633)) - Alert - Divider - Expand - Label - LoadingOverlay - Provide Storybook documentation for: - AppIcon - ActionButton - AggregateCard - AggregatePromiseCard - QuickActionsCard - Alert - Divider - EmptyState - Expand - Label - LoadingOverlay - ApplicationEmptyState - Fix a bug in LoadingOverlay; naming error in nested slots caused any message attached to the overlay to not sow up correctly. - Revise AppIcon to be independent of authentik; it just cares if the data has a name or an icon reference, it does not need to know about `Application` objects. As such, it's an *element*, not a *component*, and I've moved it into the right location, and updated the few places it is used to match. * Prettier has opinions with which I sometimes diverge. * Found a bug! Although pf-m-xl was defined as a legal size, there was no code to handle drawing something XL! * Found a few typos and incorrect API descriptions. |
|||
| 9e2620a5b9 |
web: provide simple tables for API-less displays (#11028)
* 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 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: 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 * Some lint over-eagerness. * Updated after build. |
|||
| 5257370e4a |
web: small fixes for elements and forms (#11546)
* 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. * 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. * Removing SonarJS comments. * Reverting to log level for tests. |
|||
| c90ecf4ebe |
admin: refactor update check (#11272)
* admin: refactor update check Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 79c01ca473 |
web: update to ESLint 9 (#10812)
* web: update to ESLint 9 ESLint 9 has been out for awhile now, and all of the plug-ins that we use have caught up, so it is time to bite the bullet and upgrade. This commit: - upgrades to ESLint 9, and upgrades all associated plugins - Replaces the `.eslintrc` and `.eslintignore` files with the new, "flat" configuration file, "eslint.config.mjs". - Places the previous "precommit" and "nightmare" rules in `./scripts/eslint.precommit.mjs` and `./scripts/eslint.nightmare.mjs`, respectively - Replaces the scripted wrappers for eslint (`eslint`, `eslint-precommit`) with a single executable that takes the arguments `--precommit`, which applies a stricter set of rules, and `--nightmare`, which applies an even more terrifyingly strict set of rules. - Provides the scripted wrapper `./scripts/eslint.mjs` so that eslint can be run from `bun`, if one so chooses. - Fixes *all* of the lint `eslint.config.mjs` now finds, including removing all of the `eslint` styling rules and overrides because Eslint now proudly leaves that entirely up to Prettier. To shut Dependabot up about ESLint. * Added explanation for no-console removal. * web: did not need the old and unmaintained nightmare mode; it can be configured directly. |
|||
| d0a459076b |
web: enhance search select with portal, overflow, and keyboard controls (#9517)
* 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: enhance search select
Patternfly doesn't even *have* a setting for "selected but not hovered," so I had to invent one. I
borrowed a trick from MUI and used the light blue "info" color, making it darker on
"selected+hovered."
This commit starts the revision process for search select. The goal is to have it broken down into
four major components: The inline-DOM component, which just shows the current value (or placeholder,
if none) and creates the portal for the floating component, then have a higher-level component for
the SearchSelect behavior, and a sidecar to manage the keyboard interactivity.
This is the portaled component: the actual list.
* web: enhance search select. Break menu and Input items into separate handlers.
* web: search select: added keyboard controller.
* web: search select - the isolation continues
This commit brings us to the position of having an independently rendered menu that listens for
click events on its contents, records the value internally *and* sends it upstream as an event.
This commit also includes a KeyboardController reactor that listens for keyboard events on a list of
objects, moving the focus up and down and sending a both a "selected" event when the user presses
Enter or Space, and a "close" event when the user presses Escape.
A lot of this is just infrastructure. None of these *do* very much; they're just tools for making
SearchSelect better.
AkSearchSelectView is next: it's responsible for rendering the input and menu items, and then for
forwarding the `value` component up to whoever cares.
`ak-search-select` will ultimately be responsible for fetching the data and mapping the string
tokens from AkSearchSelectView back into the objects that Authentik cares about.
* web: search select - a functioning search select
So search select is now separated into the following components:
- SearchSelectView: Takes the renderables and the selected() Value and draws the Value in a
box, then forwards the Options to a portaled drop-down component.
- SearchSelectMenuPosition: A web component that renders the Menu into the <BODY> element and
positions it with respect to an anchor provided by SearchSelectView.
- SearchSelectMenu: Renders the Menu and listens for events indicating an Item has been selected.
Sends events through a reference to the View.
- SearchKeyboardController: A specialized listener that keeps an independent list of indices and
tabstops, and listens for keyboard events to move the index forward or backward, as well as for
Event or Space for "select" and Escape for "close". Doesn't actually _do_ these things; they're
just semantics implied by the event names, it just sends an event up to the host, which can do
what it wants with them.
What's not done:
- SearchSelect: The interface with the API. Maps to and from API values to renderable Options.
One thing of note: of the 35 uses of SearchSelect in our product, 28 of them have `renderElement`
annotations of a single field. Six of them use the same annotation (renderFlow), and only one (in
EventMatcherPolicyForm) is at all complex. The 28 are:
- 7: group.name;
- 1: item.label;
- 5: item.name;
- 1: policy.name;
- 1: role.name;
- 1: source.name;
- 3: stage.name;
- 9: user.username;
I propose to modify `.renderElement` to take a string of `keyof T`, where T is the type passed to the
SearchSelect; it will simply look that up in the object passed in and use that as the Label.
`.renderDescription` is more or less similar, except it has _no_ special cases:
- 6: html`${flow.name}`;
- 1: html`${source.verboseName}`;
- 9: html`${user.name}`;
- 2: html`${flow.slug}`;
Given that, it makes sense to modify this as well to take a field key as a look up and render it,
making all that function calling somewhat moot.
Selected has a similar issue; passing it a value that is _not_ a function would be a signal to find
this specific element in the corresponding 'pk'. Or we could pass a tuple of [keyof T] and value,
so we didn't have to hard-code 'pk' into the thing.
- 1 return item.pk === this.instance?.createUsersGroup;
- 1 return item.pk === this.instance?.filterGroup;
- 2 return item.pk === this.instance?.group;
- 1 return item.pk === this.instance?.parent;
- 1 return item.pk === this.instance?.searchGroup;
- 1 return item.pk === this.instance?.syncParentGroup;
- 1 return item.pk === this.instance?.policy;
- 1 return item.pk === this.instance?.source;
- 1 return item.pk === this.instance?.passwordStage;
- 1 return item.pk === this.instance?.stage;
- 1 return item.pk === this.instance?.user;
- 2 return item.pk === this.previewUser?.pk;
- 5 return item.pk === this.instance?.configureFlow;
- 1 return item.pk === this.instance?.mapping;
- 1 return item.pk === this.instance?.nameIdMapping;
- 1 return item.pk === this.instance?.user;
- 1 return item.pk === this.instance?.webhookMapping;
- 1 return item.component === this.instance?.action;
- 1 return item.path === this.instance?.path;
- 1 return item.name === this.instance?.model;
- 1 return item.name === this.instance?.app;
- 1 return user.pk.toString() === this.request?.toString();
- 2 return this.request?.user.toString() === user.pk.toString();
And of course, `.value` kinda sorta has the same thing going on:
- 6: flow?.pk;
- 3: group ? group.pk : undefined;
- 4: group?.pk;
- 1: item?.component;
- 2: item?.name;
- 1: item?.path;
- 4: item?.pk;
- 1: policy?.pk;
- 1: role?.pk;
- 1: source?.pk;
- 3: stage?.pk;
- 8: user?.pk;
- 1: user?.username;
All in all, the _protocol_ for SearchSelect could be streamlined. A _lot_. And still retain the
existing power.
* Old take; not keeping.
* Didn't need this either.
* web: search select - a functioning search select with API interface
So many edge cases!
Because the propagation here is sometimes KeyboardEvent -> MenuEvent -> SearchSelectEvent, I had to
rename some of the events to prevent them from creating infinite loops of event handling. This
resulted in having to define separate events for Input, Close, and Select.
I struggled like heck to get the `<input>` object to show the value after updating. Ultimately, I
had to special case the `updated()` method to make sure it was showing the currently chosen display
value. Looking through Stack Overflow, there's a lot of contention about the meaning of the `value`
field on HTMLInputElements.
The API layer distinguishes between a "search" event, which triggers the query to run, and the
"select" event, which triggers the component to pick an object as _the_ `.value`.
The API layer handles the conversion to GroupedItems and makes sure that the View receives either
FlatSelect or GroupedSelect options collections (see ./types, but in practice users should never
care too much about this.)
* web: completed the search select update
* web: search-select reveals a weakness in our plans
While testing SearchSelect, I realized that the protocol for our "custom input elements" was
neither specified nor documented. I have attempted to fix that, and am finding edge cases
and buggy implementations that required addressing.
I've described the protocol by creating a class that implements it: AkControlElement. It
extends the constructor to always provide the "this is an data-ak-control element," and
provides a `json()` method that throws an exception in the base class, so it must always
be overriden and never called as super().
I've also fixed ak-dual-select so it carries its name properly into the Forms parser.
* web: search select (and friends)
This commit finalizes the search select quest! Headline: Search Select is now keyboard-friendly
*and* CSS friendly; the styling needed for position is small enough to fit in a `styleMap`, and the
styling for the menu itself can be safely locked into a web component.
Primarily, I was forgetting to map the value to its displayValue whenever the value was changed from
an external source. It should have been an easy catch, but I missed it the first dozen times
through.
* Not using this yet. ESLint-9 experiment that was loosely left here for some reason.
* Added lots of comments.
* Added new comments, fixed error message.
* Removing a console.log
* Fixed an incorrect comment.
* Added comments about workaround.
* web: focus fixes.
Fixes several issues with the drop-down, including primarily how "loss of focus"
does not result in the pop-up being banished. Also, the type definition for the
attribute `hidden` is inconsistent between Typescript, the attribute, and the
related property; I've chosen to route around that problem by using a custom
attribute and setting `hidden` in the template, where `lit-analyze` has a workable
definition and allows it to pass. Finally, on `open` the focus is passed to the
current value, if any.
|
|||
| 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!
```
|
|||
| 453f7b8641 |
web: provide default endpoint api configuration (#10319)
* 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.
* Intermediate; prepping for remove that may fail.
* web: provide a default table endpoint configuration
This commit finds 19 places where the exact same configuration is
used to describe a table's API endpoint, and replaces that configuration
with a provided default from a parent class.
While examining the logs for our build, I noted that this particular
sequence is duplicated multiple times throughout our code base,
accounting for a bloat of 169 lines or so of the estimated 5552
lines of bloat. By providing a default endpoint configuration and
substituting it (mechanically) wherever the default is required,
we reduce our code duplication issue from 9.26% of the codesabe
to 8.99%.
... which is a start.
* Didn't need the duplication.
* remove page argument while we're at it
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* actually use it everywhere
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* web: fix inconsistent method signature for LogViewer
Removed the `_page` parameter from LogViewer's apiEndpoint() method.
The `page: number` parameter is no longer a part of this method's signature.
* web: restore reduced page size to Overview:Recent Events card
---------
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
|
|||
| 6c4c535d57 |
web/admin: rework initial wizard pages and add grid layout (#9668)
* remove @goauthentik/authentik as TS path Signed-off-by: Jens Langhammer <jens@goauthentik.io> * initial implementation Signed-off-by: Jens Langhammer <jens@goauthentik.io> * oh yeah Signed-off-by: Jens Langhammer <jens@goauthentik.io> * format earlier changes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * support plain alert Signed-off-by: Jens Langhammer <jens@goauthentik.io> * initial attempt at dedupe Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make it a base class Signed-off-by: Jens Langhammer <jens@goauthentik.io> * migrate all wizards Signed-off-by: Jens Langhammer <jens@goauthentik.io> * create type create mixin to dedupe more, add icon to source create Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add ldap icon Signed-off-by: Jens Langhammer <jens@goauthentik.io> * Optimised images with calibre/image-actions * match inverting we should probably replace all icons with coloured ones so we don't need to invert them...I guess Signed-off-by: Jens Langhammer <jens@goauthentik.io> * format Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make everything more explicit Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add icons to provider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add remaining provider icons Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rework to not use inheritance Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix unrelated typo Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make app wizard use grid layout Signed-off-by: Jens Langhammer <jens@goauthentik.io> * keep wizard height consistent Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> |
|||
| a60442fc2c | enterprise/audit: fix audit logging with m2m relations (#9571) | |||
| 5805ac83f7 |
web: clean up and remove redundant alias '@goauthentik/app' (#8889)
* 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: clean up and remove redundant alias '@goauthentik/app'
The path alias `@goauthentik/app` has been a thorn in our side for a long time, as it conflicts with
or is redundant with all the *other* aliases in `tsconfig.json`, such as `@goauthentik/elements` and
`@goauthentik/locales`.
This commit *replaces* `@goauthentik/app` with `@goauthentik/authentik` for a single use case: the
locale codes file in the project root. That also helps reserve the subproject name `authentik` in
case we ever do go the monorepo root.
Other than that, all the rest have been removed with the following mechanical refactor:
```
perl -pi.bak -e 's{\@goauthentik/app/}{\@goauthentik/}' $(rg -l '@goauthentik/app/' ./src/)
```
* web: separate the sizing enum from a specific component implementation (#8890)
The PFSizes enum is used by more than just the Spinner, but has been left inside the Spinner for all
this time, making refactoring the Spinner for Patternfly 5 a little harder (okay, an annoying amount
harder) than it should be.
This commit moves this UI-specific, widely-use enum into its own folder in `common`, and refactors
everything else to use it. As is often the case, the refactor is mechanical:
```
perl -pi.bak -e 's{import \{ PFSize \} from "\@goauthentik/elements/Spinner";}{import \{ PFSize \}
from "\@goauthentik/common/enums.js";}' \\
$(rg -l 'import.*PFSize')
```
**Note:** This commit is dependent upon the ["clean up and remove redundant alias `@goauthentik/app`" PR](https://github.com/goauthentik/authentik/pull/8889)
|
|||
| 2ba66f4f91 |
web: upgrade to lit 3 (#8781)
* Holding for a moment...
* web: replace rollup with esbuild
This commit replaces rollup with esbuild.
The biggest fix was to alter the way CSS is imported into our system;
esbuild delivers it to the browser as text, rather than as a bundle
with metadata that, frankly, we never use. ESBuild will bundle the
CSS for us just fine, and interpreting those strings *as* CSS turned
out to be a small hurdle. Code has been added to AKElement and
Interface to ensure that all CSS referenced by an element has been
converted to a Browser CSSStyleSheet before being presented to the
browser.
A similar fix has been provided for the markdown imports. The
biggest headache there was that the re-arrangement of our documentation
broke Jen's existing parser for fixing relative links. I've provided
a corresponding hack that provides the necessary detail, but since
the Markdown is being presented to the browser as text, we have to
provide a hint in the markdown component for where any relative
links should go, and we're importing and processing the markdown
at runtime. This doesn't seem to be a big performance hit.
The entire build process is driven by the new build script, `build.mjs`,
which starts the esbuild process as a service connected to the build
script and then runs the commands sent to it as fast as possible.
The biggest "hack" in it is actually the replacement for rollup's
`rollup-copy-plugin`, which is clever enough I'm surprised it doesn't
exist as a standalone file-copy package in its own right.
I've also used a filesystem watch library to encode a "watcher"
mechanism into the build script. `node build.mjs --watch` will
work on MacOS; I haven't tested it elsewhere, at least not yet.
`node build.mjs --proxy` does what the old rollup.proxy.js script
did.
The savings are substantial. It takes less than two seconds to build
the whole UI, a huge savings off the older ~45-50 seconds I routinely
saw on my old Mac. It's also about 9% smaller.
The trade-offs appear to be small: processing the CSS as StyleSheets,
and the Markdown as HTML, at run-time is a small performance hit,
but I didn't notice it in amongst everything else the UI does as
it starts up.
Manual chunking is gone; esbuild's support for that is quite difficult
to get right compared to Rollup's, although there's been a bit of
yelling at ESbuild over it. Codemirror is built into its own chunk;
it's just not _named_ distinctly anymore.
The one thing I haven't been able to test yet is whether or not the
polyfills and runtim shims work as expected on older browsers.
* web: continue with performance and build fixes
This commit introduces a couple of fixes enabled by esbuild and other
features.
1. build-locales
`build-locales` is a new NodeJS script in the `./scripts` folder
that does pretty much what it says in the name: it translates Xliff
files into `.ts` files. It has two DevExp advantages over the old
build system.
First, it will check the build times of the xlf files and
their ts equivalents, and will only run the actual build-locales
command if the XLF files are newer than their TS equivalents.
Second, it captures the stderr output from the build-locales command
and summarizes it. Instead of the thousands of lines of "this
string has no translation equivalent," now it just reports the
number of missed translations per locale.
2. check-spelling
This is a simple wrapper around the `codespell` command, mostly
just to reduce the visual clutter of `package.json`, but also to
permit it to run just about anywhere without needed hard-coded
paths to the dictionaries, using a fairly classic trick with git.
3. pseudolocalize and import-maps
These scripts were in TypeScript, but for our purposes I've
saved their constructed equivalents instead. This saves on
visual clutter in the `package.json` script, and reduced the
time they have to run during full builds. They're small enough
I feel confident they won't need too much looking over.
Also, two lint bugs in Markdown.ts have been fixed.
* Removed a few lines that weren't in use.
* build-locales was sufficiently complex it needed some comments.
* web: formalize that horrible unixy git status checker into a proper function.
* Added types for , the Markdown processor for in-line documentation.
* web: upgrade to Lit3
This commit replaces our Lit2 implementation with a Lit3 implementation.
This upgrade required two major shifts within our code, both of them consequential.
First, the restructuring of the way the get/set decorators for properties and states meant that a
lot of the code we were using needed to be refactored. More than that, a lot of those custom
accessors were implemented to trigger side-effects, such as when a providerID is set or changed
triggering the ProviderView to fetch the requsted Provider. The Lit2 and Lit3 documentation both say
[there is a better way to handle
this](https://lit.dev/docs/v2/components/properties/#:~:text=In%20most%20cases%2C%20you%20do%20not%20need%20to%20create%20custom%20property%20accessors)
by detecting the change in the `willUpdate()` point of an elements Lifecycle and triggering the side
effect there instead. I've done this in several places with a pattern of detecting the change, and
then naming the corresponding change as `fetchRequestedThing()`. The resulting code is cleaner and
uses fewer controversial features.
The other is that the type signature for `LitElement.createRenderRoot()` has changed to be either an
HTMLElement or a DocumentFragment. This required some serious refactoring of type changes through
Base and Interface codes. Noteably, the custom `AdoptedStyleSheetsElement` interface has been
superseded by the supplied and standardized
[DocumentOrShadowRoot](
|
|||
| 0c4dee8f9f |
providers: allow previewing mappings for other users (#8297)
* rework access check to do better validation
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* providers: allow previewing mappings for other users
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* fix ui
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* Revert "rework access check to do better validation"
This reverts commit
|
|||
| 11ca358242 |
web/admin: revamped rbac and user settings tabs (#8299)
* web/admin: fix duplicate RBAC preview banner on permission modal Signed-off-by: Jens Langhammer <jens@goauthentik.io> * switch non-embedded permission page to use vertical tabs Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix some leftover html? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * move stuff into vertical subtab Signed-off-by: Jens Langhammer <jens@goauthentik.io> * show all of users permission tabs on one main tab Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rework role page to match user page Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use separate tabs Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename role permission tables to match user tables Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename to credentials and tokens Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add country icon to session list Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add oauth access token list Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add helper to get relative time Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use pfdivider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * replace plain hr with pf-c-divider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use new logic for showing relative time in charts Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use consistent relative time for event display Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove more leftovers Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix some alignment issues on the admin dashboard Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update storybook map Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add sanity check to event app lookup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make api drawer header fixed Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix table padding for toggle Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix notification drawer for user interface Signed-off-by: Jens Langhammer <jens@goauthentik.io> * enable system task search Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix formatting, exclude generated script from formatting Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: minor fixes There's a renderer (it's not a component, not yet) for producing definition lists without the risk of missing a class or tag. Breaking conditionally rendered components out to make their use easier to identify. * fix prettier Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix outpost form Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix more flaky tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * re-create locale Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add some description for different permission views Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix system task search Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update docs Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Ken Sternberg <ken@goauthentik.io> |
|||
| 96b2a1a9ba |
events: migrate SystemTasks to DB (#8159)
* events: migrate system tasks to save in DB Signed-off-by: Jens Langhammer <jens@goauthentik.io> * prefill in app startup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * cleanup api Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update web Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use string for status Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix enum Signed-off-by: Jens Langhammer <jens@goauthentik.io> * save start and end directly in timestamp from default_timer() Signed-off-by: Jens Langhammer <jens@goauthentik.io> * improve metrics Signed-off-by: Jens Langhammer <jens@goauthentik.io> * lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename globally to system task Signed-off-by: Jens Langhammer <jens@goauthentik.io> * recreate migrations, better denote anonymous user Signed-off-by: Jens Langhammer <jens@goauthentik.io> * events: lookup actual django app instead of using module path, fallback to module path Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix logger call Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 4184f8a770 |
enterprise: add full audit log [AUTH-458] (#8177)
* enterprise: add full audit log Signed-off-by: Jens Langhammer <jens@goauthentik.io> * delegate enabled check to apps Signed-off-by: Jens Langhammer <jens@goauthentik.io> * move audit middleware to separate app Signed-off-by: Jens Langhammer <jens@goauthentik.io> * cleanse before diff Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make cleanse include a hash of the values Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix sentry error during lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * format Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * only use start of hash Signed-off-by: Jens Langhammer <jens@goauthentik.io> * don't use deepdiff Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add diff ui Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix info for dict Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update release notes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * enable audit logging for tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix startup with tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * include first 4 chars of raw value? Signed-off-by: Jens Langhammer <jens@goauthentik.io> * only log asterisks Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fixup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 830689f1cb |
web: bad default in select (#8258)
* web: fix event propogation in search-select wrappers Two different patches, an older one that extracted long search blocks that were cut-and-pasted into a standalone component, and a newer one that fixed displaying placeholder values properly, conflicted and broke a relationship that allowed for the values to be propagated through those standalone components correctly. This restores the event handling and updates the listener set-ups with more idiomatic hooks into Lit's event system. * Updated search-select to properly render with Storybook, and provided a foundation for testing the Search-Select component with Storybook. * Accidentally deleted this line while making Sonar accept my test data. * Fixing a small issue that's bugged me for awhile: there's no reason to manually duplicate what code can duplicate. * Provided a storybook for testing out the flow search. Discovered along the way that I'd mis-used a prop-drilling technique which caused the currentFlow to be "undefined" when pass forward, giving rise to Marc's bug. I *think* this shakes out the last of the bugs. Events are passed up correctly and the initial value is recorded correctly. * Added comments and prettier had opinions. * Restoring old variable names; they didn't have to change after all. * fix lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 240cf6dd94 |
enterprise/providers: Add RAC [AUTH-15] (#7291)
* add basic guacamole Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make everything mostly work Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add rac build to CI Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix resize, fix web lint, sendSize correctly Signed-off-by: Jens Langhammer <jens@goauthentik.io> * pre-send connection from client, format Signed-off-by: Jens Langhammer <jens@goauthentik.io> * improve throughput Signed-off-by: Jens Langhammer <jens@goauthentik.io> * cleanup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rework TokenOutpostConsumer into middleware Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix some layout issues Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add outpost controllers Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start testing audio things Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix a bunch of things Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add deps Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix to work with outpost group Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add simple loadbalancing Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add simple reconnect Signed-off-by: Jens Langhammer <jens@goauthentik.io> * show reconnecting text Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix error when checking ports Signed-off-by: Jens Langhammer <jens@goauthentik.io> * move to providers Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add flow check to interface Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix go lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix rac app label Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix audio Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add logging Signed-off-by: Jens Langhammer <jens@goauthentik.io> * cleanup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * allow overriding all settings Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix duplicate keyboard, debug high DPI Signed-off-by: Jens Langhammer <jens@goauthentik.io> * re-add deps Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix missing __init__.py breaking model loading I love python Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * bump successful ws connection to info Signed-off-by: Jens Langhammer <jens@goauthentik.io> * hide cursor since guac draws that Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add clipboard support (bidirectional) Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make codespell not want to break the code Signed-off-by: Jens Langhammer <jens@goauthentik.io> * run pr comment in separate task Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start endpoint and property mapping stuff Signed-off-by: Jens Langhammer <jens@goauthentik.io> * more endpoint things Signed-off-by: Jens Langhammer <jens@goauthentik.io> * unrelated: fix event model_pk filtering with ints Signed-off-by: Jens Langhammer <jens@goauthentik.io> * unrelated: improve event display for changelog Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rebuild endpoint stuff again Signed-off-by: Jens Langhammer <jens@goauthentik.io> * idk special url Signed-off-by: Jens Langhammer <jens@goauthentik.io> * more stuff, connect token with session Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add disconnect Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rework disconnect cleanly disconnect from guacd instead of just letting the connection timeout Signed-off-by: Jens Langhammer <jens@goauthentik.io> * clear cache when creating outpost Signed-off-by: Jens Langhammer <jens@goauthentik.io> * support host:port and fix protocol Signed-off-by: Jens Langhammer <jens@goauthentik.io> * center smaller viewport Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rework connection to wait more and stop after some time Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add policy control to endpoints Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove provider protocol Signed-off-by: Jens Langhammer <jens@goauthentik.io> * don't switch to different outpost connection when already chosen Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start using property mappings, add static settings Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add some RAC mapping settings Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start adding tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add tests for event changes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add tests and fix issues found by said tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add preview banner, move endpoints to main page Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add locale Signed-off-by: Jens Langhammer <jens@goauthentik.io> * auto-select endpoint if only one is available Signed-off-by: Jens Langhammer <jens@goauthentik.io> * backport https://github.com/goauthentik/authentik/pull/7831 to rac Signed-off-by: Jens Langhammer <jens@goauthentik.io> * dont select property mappings on endpoints Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make table modal only load when opened Signed-off-by: Jens Langhammer <jens@goauthentik.io> * only auto-redirect when open Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix web deps Signed-off-by: Jens Langhammer <jens@goauthentik.io> * check for token expiry and terminate session Signed-off-by: Jens Langhammer <jens@goauthentik.io> * re-add endpoint name to title Signed-off-by: Jens Langhammer <jens@goauthentik.io> * disconnect connection when token is manually deleted Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add initial RAC docs Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add connection expiry setting to provider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix flaky tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| ec8f2d4bf9 |
stages/email: prevent authentik emails from being marked as spam (also add text template support) (#7949)
* use <> style email address with name Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add support for text templates Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix icon display in event log Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add text email templates Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update docs, update email screenshot Signed-off-by: Jens Langhammer <jens@goauthentik.io> * prevent prettier from breaking example template Signed-off-by: Jens Langhammer <jens@goauthentik.io> * Optimised images with calibre/image-actions * Apply suggestions from code review Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> Signed-off-by: Jens L. <jens@beryju.org> * reword docs 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: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> |
|||
| 026e80bd10 |
web: replace 'description-list' with list of descriptions (#7392)
* web: break circular dependency between AKElement & Interface. This commit changes the way the root node of the web application shell is discovered by child components, such that the base class shared by both no longer results in a circular dependency between the two models. I've run this in isolation and have seen no failures of discovery; the identity token exists as soon as the Interface is constructed and is found by every item on the page. * web: fix broken typescript references This built... and then it didn't? Anyway, the current fix is to provide type information the AkInterface for the data that consumers require. * web: description lists as functions One thing I hate is clutter. Just tell me what you're going to do. "Description Lists" in our code are renderings of Patternfly's DescriptionList; we use only four of their idioms: horizontal, compact, 2col, and 3col. With that in mind, I've stripped out the DescriptionList rendering code from UserViewPage and replaced it with a list of "Here's what to render" and a function call to render them. The calling code is still responsible for having the right styles available, as this is not a component or an attempt at isolation; it is *just* a function (at this point). * web: fix issue that prevented the classMap from being rendered properly * web: added comments to the description list. * web: analyze & prettier had opinions * web: Fix description-list demo This commit re-instals the demo for the "description list" of user fields. * web: prettier had opinions. * any -> unknown Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io> |
|||
| afdc7d241f |
web/admin: revise wizard form handling (#7331)
* web: break circular dependency between AKElement & Interface. This commit changes the way the root node of the web application shell is discovered by child components, such that the base class shared by both no longer results in a circular dependency between the two models. I've run this in isolation and have seen no failures of discovery; the identity token exists as soon as the Interface is constructed and is found by every item on the page. * web: fix broken typescript references This built... and then it didn't? Anyway, the current fix is to provide type information the AkInterface for the data that consumers require. * web: extract the form processing from the form submission process Our forms have a lot of customized value handling, and the function `serializeForm` takes our input structures and creates a JSON object ready for submission across the wire for the various models provided by the API. That function was embedded in the `ak-form` object, but it has no actual dependencies on the state of that object; aside from identifying the input elements, which is done at the very start of processing, this large block of code stands alone. Separating out the "processing the form" from "identifying the form" allows us to customize our form handling and preserve form information on the client for transactional purposes such as our wizard. w * web: multi-select, but there's a styling issue. * web: provide a closed control for multi-select This commit creates a new control, using the ak-form-element-horizontal as a *CLOSED* object, for our multi-select. This control right now is limited to what we expect to be using in the wizard, but that doesn't mean it can't be smarter in the future. * web: hung up by a silly spelling error * web: update the form-handling method With the `serializeForm` method extracted, it's much easier to examine and parse every *form* with every keystroke, preserving them against the changes that happen as the customer navigates the Wizard. With that in place, it became straightforward to retrofit the "handle changes to the application, to the provider, and to the providerType" into the three pages of the wizard, and to provide *all* of the form elements in a base class such that no specialized handling needs to happen to any of the child pages. Fixed an ugly typo in the oauth2 provider, as well. * web: wizard should work with multi-select and should reflect default values (Note: This commit is predicated on both the "Extract serializeForm function from Form.ts" and "Provide a controlled multi-select input control" PRs.) The initial attempt at the wizard was woefully naive in its implementation, missing some critical details along the way. This revision starts off with one stronger assumption: trust that Jens knows what he's doing, and knew what he was building when he wrote the initial `Form` handler. The problem with the `Form` handler, and the reason I avoided it, was simply that it does too many things, especially in its ModelForm variant: it receives a model from the back-end, renders a (hand-written) form for that model, allows the user to interact with that model, and facilitates saving it to the back-end again, complete with on-page notifications of success or failure. The Wizard could not use all of that. It needs to gather the information for *two* models (an Application and a Provider, plus the ProviderType) and has a new and specialized end-point for a transaction that allows the committing or roll back of both models to happen simultaneously, predicated on success or failure respectively. With "Extract `serializeForm` completed, it was possible to repurpose the forms that already existed, stripping them down to just their input components, and eventing the entire thing in a single event loop of "events flow up, data flows down." In this case, the *entire form* is serialized on a per-event basis and pushed up the to the orchestration layer, which saves them off. Writing a parent `BasePanel` class that has accessors for `formValues` and `valid` means that the state of every page is accessible with a simple query. This simplified the `BaseProviderPanel` class to just specialize the `dispatchUpdate` method to send the wizard update with the new provider information filled out. Because the *form* is being treated as the source of truth about the state of a `Partial<Application>` or `Partial<*Provider>` object, the defaults are now being captured as expected. Likewise, this simplified the `providerCache` layer which preserves customer input in the event that the customer starts filling out the wrong provider to a simple conditional clause in the orchestrator. The Wizard has much fewer smarts because it doesn't (and probably never did) need them. Along with the above changes, the following has also been done: For SAML and SCIM, the providerMappings now works. They weren't being managed as `state` objects, so they weren't receiving updates when the update event retrieved the information from the back-end. In order to make clear what's happening, I have extracted the loops from the original definition and built them as named objects: `propertyMappings`, `pmUserValues`, `pmGroupValues` and so on, which I then pass into the new multi-select component. I fixed a really embarrassing typo in Oauth2's "advanced settings" block. I have extracted the CoreGroup search-select into a custom component. I deleted the `merge` function. That was a faulty experiment with non-deterministic outcomes, and I was never happy with it. I'm glad its gone. I've added a title header to each of the providers, so the user can be sure that they're looking at the right provider type when they start filling out the form. I've created a new token, `data-ak-control`, with which we can mark all objects that we can treat as Authentik value-producing components, the form value of which is available through a `json()` method. I've added this bit of intelligence to the `serializeForm` function, short-circuiting the complex processing and putting the "this is the shape of the value we expect from this input" *onto the input itself*. Which is where it belongs. * web: add error handling to wizard. * web: improve error handling in light components Rather than reproduce the error handling across all of the LightComponents, I've made a parent class that takes the common fields to distribute between the ak-form-element-horizontal and the input object itself. This made it much easier to properly display errors in freeform input fields in the wizard, as well as working with the routine error handling in Form.ts * Added the radio control to the list of LightComponents. * Fix bug where event was recorded twice. * Fixed merge bug (?) that somehow deleted the Authorization Select block in OAuth2. * web: prettier had opinions * web: added error handling and display * web: bump @lit-labs/context from 0.4.1 to 0.5.1 in /web Bumps [@lit-labs/context](https://github.com/lit/lit/tree/HEAD/packages/labs/context) from 0.4.1 to 0.5.1. - [Release notes](https://github.com/lit/lit/releases) - [Changelog](https://github.com/lit/lit/blob/main/packages/labs/context/CHANGELOG.md) - [Commits](https://github.com/lit/lit/commits/@lit-labs/context@0.5.1/packages/labs/context) --- updated-dependencies: - dependency-name: "@lit-labs/context" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * web: updated wizard to run with latest package.json configuration Apparently, there were stale dependencies in package-lock.json that were conflicting with the requests in our package.json. By running `npm update`, I was able to resolve the conflict. I have also removed the default names from the context names collection; they weren't doing any good, and they permit frictionless renaming of dependencies, which is never a good idea. * web: schlepping on the errors messages During testing, I realized I was unhappy with the error messages. They're not very helpful. By adding links to navigate back to the place where the error occurred, and providing better context for what the error could have been, I hope to help the use correct their errors. * make package the same as main 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> |
|||
| 73751e5cd9 |
web: refactor status label to separate component (#7407)
* web: break circular dependency between AKElement & Interface.
This commit changes the way the root node of the web application shell is
discovered by child components, such that the base class shared by both
no longer results in a circular dependency between the two models.
I've run this in isolation and have seen no failures of discovery; the identity
token exists as soon as the Interface is constructed and is found by every item
on the page.
* web: fix broken typescript references
This built... and then it didn't? Anyway, the current fix is to
provide type information the AkInterface for the data that consumers
require.
* A quality of life thing: `<ak-status-label good>`
There's an idiom throughout the UI:
``` HTML
<ak-label color=${item.enabled ? PFColor.Green : PFColor.Red}>
${item.enabled ? msg("Yes") : msg("No")}
</ak-label>
```
There are two problems with this.
- Repeating the conditional multiple times is error-prone
- The color scheme doesn't communicate much.
There are uses for ak-label that aren't like this, but I'm focusing on this particular use case,
which occurs about 20 times throughout the UI.
Since it's so common, let's isolate the most common case: `<ak-status-label good />` gives you the
"good" status, and `<ak-status-label/>` gives you the "bad" status, which is the default (no
arguments to the function).
There wasn't much clarity in the system for when to use orange vs red vs grey, but looking through
the use cases, it became clear that Red meant fail/inaccessible, Orange meant "Warning, but not
blocking," and Grey just means "info: this thing is off".
So let's define that with meaning: there are three types, error, warning, and info. Which
corresponds to debugging levels, but whatever, nerds grok that stuff.
So that example at the top becomes
```<ak-status-label ?good=${item.enabled}></ak-status-label>```
... and we can now more clearly understand what that conveys.
There is some heavy tension in this case: this is an easier and quicker-to-write solution to
informing the user of a binary status in an iconic way, but the developer has to remember that it
exists.
Story provided, and changes to the existing uses of the existing idiom provided.
* Added the 'compact label' story to storybook.
|
|||
| f728bbb14b |
sources/ldap: add check command to verify ldap connectivity (#7263)
* sources/ldap: add check command to verify ldap connectivity Signed-off-by: Jens Langhammer <jens@goauthentik.io> * default to checking all sources Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start adding an API for ldap connectivity Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add webui for ldap source connection status Signed-off-by: Jens Langhammer <jens@goauthentik.io> * better show sync status, clear previous tasks Signed-off-by: Jens Langhammer <jens@goauthentik.io> * set timeout on redis lock for ldap sync Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix py lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix web lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> |
|||
| 20e003656a |
web: fix bad comment that was confusing lit-analyze (#7234)
The old comment was left over from a previous revision of the wizard, and blocked lit-analyze's ability to understand the Modal's `slot="trigger"` declaration. |
|||
| 3a7283c670 |
web: Application wizard v2 with tests (#7004)
* A lot of comments about forms. * Adding comments to the wizard. * Broke out the text input into a single renderer. Still works as required. * web: Legibility in the ApplicationForm. This is a pretty good result. By using the LightDOM setting, this provides the existing Authentik form manager with access to the ak-form-horizontal-element components without having to do any cross-border magic. It's not ideal, and it shows up just how badly we've got patternfly splattered everywhere, but the actual results are remarkable. The patterns for text, switch, radio, textarea, file, and even select are smaller and easier here. I'm still noodling on what an unspread search-select element would look like. It's just dependency injection, so it ought to be as straightforward as that. * web: Marking down the start of the 'components' library. * web: Baby steps I become frustrated with my inability to make any progress on this project, so I decided to reach for a tool that I consider highly reliable but also incredibly time-consuming and boring: test driven development. In this case, I wrote a story about how I wanted to see the first page rendered: just put the HTML tag, completely unadorned, that will handle the first page of the wizard. Then, add an event handler that will send the updated content to some parent object, since what we really want is to orchestrate the state of the user's input with a centralized location. Then, rather than fiddling with the attributes and properties of the various pages, I wanted them to be able to "look up" the values they want, much as we'd expect a standalone form to be able to pull its values from the server, so I added a context object that receives the update event and incorporates the new knowledge about the state of the process into itself. The result is surprisingly satisfying: the first page renders cleanly, displays the content that we want, and as we fiddle with, we can *watch in real time* as the results of the context are updated and retransmitted to all receiving objects. And the sending object gets the results so it re-renders, but it ends up looking the same as it was before the render. * Now, it's starting to look like a complete package. The LDAP method is working, but there is a bug: the radio is sending the wrong value !?!?!?. Track that down, dammit. The search wrappers now resend their events as standard `input` events, and that actually seems to work well; the browser is decorating it with the right target, with the right `name` attribute, and since we have good definitions of the `value` as a string (the real value of any search object is its UUID4), that works quite well. Added search wrappers for CoreGroup and CryptoCertificate (CertificateKeyPairs), and the latter has flags for "use the first one if it's the only one" and "allow the display of keyless certificates." Not sure why `state()` is blocking the transmission of typing information from the typed element to the context handler, but it's a bug in the typechecker, and it's not a problem so far. * Now, it's starting to look like a complete package. The LDAP method is working, but there is a bug: the radio is sending the wrong value !?!?!?. Track that down, dammit. The search wrappers now resend their events as standard `input` events, and that actually seems to work well; the browser is decorating it with the right target, with the right `name` attribute, and since we have good definitions of the `value` as a string (the real value of any search object is its UUID4), that works quite well. Added search wrappers for CoreGroup and CryptoCertificate (CertificateKeyPairs), and the latter has flags for "use the first one if it's the only one" and "allow the display of keyless certificates." Not sure why `state()` is blocking the transmission of typing information from the typed element to the context handler, but it's a bug in the typechecker, and it's not a problem so far. * web: tracked down that weirld bug with the radio. Because radio inputs are actually multiples, the events handling for radio is... wonky. If we want our `<ak-radio>` component to be a unitary event dispatcher, saying "This is the element selected," we needed to do more than what was currently being handled. I've intercepted the events that we care about and have placed them into a controller that dictates both the setting and the re-render of the component. This makes it "controlled" (to use the Angular/React/Vue) language and depends on Lit's reactiveElement lifecycle to work, rather than trust the browser, but the browser's experience with respect to the `<input type=radio` is pretty bad: both input elements fire events, one for "losing selection" and one for "gaining selection". That can be very confusing to handle, so we funnel them down in our aggregate radio element to a single event, "selection changed". As a quality-of-life measure, I've also set the label to be unselectable; this means that a click on the label will trigger the selection event, and a long click will not disable selection or confuse the selection event generator. * web: now passing the precommit phase * web: a HACK for Storybook to inject the "use light theme" flag into the body. This isn't really a very good hack; what it does is say that every story is responsible for hacking its theme into the parent. This is very annoying, but it does mean that we can at least show our components in the best light. * web: ak-application-wizard-authentication-by-oauth, and many fixes! 1. Fixed `eventEmitter` so that if the detail object is a scalar, it will not attempt to "objectify" it. This was causing a bug where retrofitting the eventEmitter to some older components resulted in a detail of "some" being translated into ['s', 'o', 'm', 'e']. Not what is wanted. 2. Removed the "transitional form" from the existing components; they had a two-step where the web component class was just a wrapper around an independent rendering function. While this worked, it was only to make the case that they *were* independent rendering objects and could be supported with the right web component framework. We're halfway there now; the last step will be to transform the horizontal-element and various input CSS into componentized CSS, the way Patternfly-Elements is currently doing. 3. Fixed the `help` field so that it could take a string or a TemplateResult, and if the latter, don't bother wrapping it in the helper text functionality; just let it be its own thing. This supports the multi-line help of redirectURI as well as the `ak-utils-time-delta` capability. 4. Transform Oauth2ProviderForm to use the new components, to the best of our ability. Also used the `provider = this.wizard.provider` and `provider = this.instance` syntax to make the render function *completely portable*; it's the exact same text that is dropped into... 5. The complete `ak-application-wizard-authentication-by-oauth` component. They're so similar part of me wonders if I could push them both out to a common reference, or a collection of common references. Both components use the PropertyMapping and Sources, and both use the same collection of searches (Crypto, Flow). 6. A Storybook for `ak-application-wizard-authentication-by-oauth`, showing the works working. 7. New mocks for `authorizationFlow`, `propertyMappings`, and `hasJWKs`. This sequence has revealed a bug in the radio control. (It's always the radio control.) If the default doesn't match the current setting, the radio control doesn't behave as expected; it won't change when you fully expect that it should. I'll investigate how to harmonize those tomorrow. * web: Converted our toggle groups to a more streamlined implementation. * web: one more toggle group. * initial api and schema Signed-off-by: Jens Langhammer <jens@goauthentik.io> * separate blueprint importer from yaml parsing Signed-off-by: Jens Langhammer <jens@goauthentik.io> * cleanup Signed-off-by: Jens Langhammer <jens@goauthentik.io> * 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. * add new "must_created" state to blueprints to prevent overwriting objects Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: adding a storybook for the ak-toggle-group component * Bugs found by CI/CD. * 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. * Fixed behavioral problem with the radio; the `if` there was preventing the radio from reflecting the default correctly. The observed behavior was that the radio wouldn't "activate" until the item selected during the render pass was clicked on first. * Proxy Provider done. * web: Tactical change. Put all the variants on the second page; it's a longer list, but it's also easier to manage than all those required sub-options. * Rounding out the catalog. * web: SAML Manual Configuration Added a 'design document' that just kinda describes what I'm trying to do, in case I don't get this done by Friday Aug 11, 2023. I had two tables doing the same thing, so I merged them and then wrote a few map/filters to specialize them for those two use cases. Along the way I had to fiddle with the ESLint settings so that underscore-prefixed unused variables would be ignored. I cleaned up the visual appeal of the forms in the LDAP application. I was copy/pasting the "handleProviderEvent" function, so I pulled it out into ApplicationWizardProviderPageBase. Not so much a matter of abstraction as just disliking that kind of duplication; it served no purpose. * Added SAML Story to Storybook. * Web: This is coming together amazingly well. Like, almost too well. * web: 80% of the way there This commit includes the first three pages of the wizard, the completion of the wizard framework with evented handling, and control over progression. Some shortcomings of this design have become evident: it isn't possible to communicate between the steps' wrappers, as they are POJOs without access to the context. An imperative decision-making process has to be inserted in the orchestration layer, which is kinda annoying. But it looks good and it behaves correctly, to the extent that I've given it behavior. It's an excellent foundation. * Linting. * web: application wizard Found where the hook for form validity should go. Excellent! Now I just need to incorporate that basic validation into the business logic and we're good to go. * Turns out that was one layer too many; the topmost component was fine for maintaining the context. * It looks like my brilliant strategy has hit a snag. The idea is simple. Let's start with this picture: ``` <application-wizard .steps=${[... a collection of step objects ...]}> <wizard-main .steps=${(steps from above)}> <application-current-panel> <current-form> ``` - ApplicationWizard has a Context for the ApplicationProviderPair (or whatever it's going to be). This context does not know about the steps; it just knows about: the "application" object, the "provider" object, and a discriminator to know *which* provider the user has selected. - ApplicationWizard has Steps that, among other things, provides Panels for: - Application - Pick Provider - Configure Provider - Submit ApplicationProviderPair to the back-end - The WizardFrame renders the CurrentPanel for the CurrentStep The CurrentPanel gets its data from the ApplicationWizard in the form of a Context. It then sends messages (events) to ApplicationWizard about the contents of each field as the user is filling out the form, so that the ApplicationWizard can record those in the ApplicationProviderPair for later submission. When a CurrentForm is valid, the ApplicationWizard updates the Steps object to show that the "Next button" on the Wizard is now available. In this way, the user can progress through the system. When they get to the last page, we can provide in the ApplicationWizard with the means to submit the form and/or send the user back to the page with the validation failure. Problem: The context is being updated in real-time, which is triggering re-renders of the form. This leads to focus problems as the fields that are not yet valid are triggering "focus grab" behavior. This is a classic problem with "controlled" inputs. What we really want is for the CurrentPanel to not re-render at all, but to behave like a normal, uncontrolled form, and let the browser do most of the work. We still want the [Next] button to enable when the form is valid enough to permit that. --- Other details: I've ripped out a lot of Jen's work, which is probably a mistake. It's still preserved elsewhere. I've also cleaned up the various wizardly things to try and look organized. It *looks* like it should work, it just... doesn't. Not yet. * Late addition: I had an inspiration about how to reduce the way reactivity broke focus by, basically, removing the reactivity and managing the first-time-through lifecycle to prevent the update from causing refocus. It works well! Now I just need to test it. * This application fixes the bug with respect to the wizard-level context being updated incorrectly. Understandings: - To use uncontrolled inputs, which I prefer, the context object should not be a state or property at the level of consumers; it should not automatically re-render with every keystroke, i.e. "The React Way." We're using Web Components, [client-side validation](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation) exists on the platform already, and live-validation is problematic for any number of reasons. - The trade-off is that it is now necessary to re-render the target page of the wizard de-novo, but that's not really as big a deal as it sounds. Lit is ready to do that... and then nothing else until we request a change-of-page. Excellent. - The top level context *must* be a state, but it's better if it's a state never actually used by the top-level context container. The debate about whether or not to make that container a dumb one (`<slot></slot>`) or to merge it with the top-level object continues; here, I've merged it with the top-level wizard object, but that object does not refer to the state variable being managed in its render pass, so changes to it do not cause a re-render of the whole wizard. The purpose of the top-level page is to manage the *steps*, not the *content of any step*. A step may change dynamically based on the content of a step, but that's the same thing as *which step*. Lesson: always know what your state is *about*. - Deep merging is a complex subject, but here it's appropriate to our needs. * web: Application Wizard This commit combines a working (but very unpolished) version of the Application Wizard with Jen's code for the CoreTransactionApplicationRequest, resulting in a successful round trip. It fixes a number of bugs with the way ContextProducer decorators were being processed, such that they just weren't working with our current configuration (although they did work fine in Storybook); consumers didn't need to be fixed. It also *removes* the steps-aware context from the Wizard. That *may* be a mistake. To re-iterate, the `WizardFrame` provides the chrome for a Wizard: the button bar div, the breadcrumbs div, the header div, and it takes the steps object as its source of truth for all of the content. The `WizardContent` part of the application has two parts: The `WizardMain`, which wraps the frame and supplies the context for all the `WizardPanels`, and the `WizardPanels` themselves, which are dependent on a context from `WizardMain` for the data that populates each panel. YAGNI right now that the panels need to know anything about the steps, and the `WizardMain` can just pass a fresh `.steps` object to the `WizardFrame` when they need updating. Using props drilling may make more sense here. It certainy does *not* make sense for the panels. They need to be renderable on-demand, and they need to make sense of what they're rendering on-demand, so the function is ``` (panel code) => (context) => (rendered panel) ``` (Yes, that's curried notation. Deal.) * This commit includes the first WDIO test for the ApplicationWizard. It doesn't do much right now, but it does log in and navigate to the wizard successfully. * web: completed test for single application, provided new programming language to make it easier to write tests. * Almost there. Missing: The validation is currently not working as expected, and I cannot get the backend to give me meaningful data helping us "go back" to the field that wasn't valid. I really don't want to put all the meaningful validation on the front-end; that's the road to - perdition, the back-end must be usable by people less assiduous than we are. Also: Need to make the button bar work better; maybe each panel can provide a custom button bar if one is needed? * web: Test harness We have an end-to-end test harness that includes a trivially correct DSL for "This is what a user would do, do this": ``` const deleteProvider = (theSlug) => ([ ["button", '>>>ak-sidebar-item a[href="#/core/providers"]'], ["deletebox", `>>>a[href="#/core/applications/${theSlug}"]`], ["button", '>>>ak-forms-delete-bulk button[slot="trigger"]'], ["button", '>>>ak-forms-delete-bulk div[role="dialog"] ak-spinner-button'], ]); ``` It's now possible to target individual sequences of events this way. With a little creativity, we could have standalone functions that take parameters for our calls and just do them, without too much struggle. * web: Revised navigation After working with the navigation for awhile, I realized that it's a poor map; what I really wanted was a controller/view pair, where events flow up to the controller and then messages on "what to draw" flow down to the view. It work quite well, and the wizard frame is smaller and smarter for it. I've also moved the WDIO-driven tests into the 'tests' folder, because it (a) makes more sense to put them there, and (b) it prevents any confusion about who's in charge of node_modules. * web: Simplify, simplify, simplify Sort-of. This commit changes the way the "wizard step coordinator" layer works, giving the wizard writer much more power over button bar. It still assumes there are only three actions the wizard frame wants to commit: next, back, and close. This empowers the steps themselves to re-arrange their buttons and describe the rules through which transitions occur. * web: resetting the form is not working yet... I vehemently dislike the object-oriented "reset" command; every wizard should start with an absolutely fresh copy of the data upon entry. Refactoring the wizard to re-build its content from the inside is the correct way to go, but I don't have a good mental image of how to make the ModalButton and the component it invokes interact cleanly, which frustrates the hell out of me. * web: reset As I said, I greatly dislike having to be dependent upon "resets"; I prefer my data to be de novo going into a "new" transaction. That said, we work with what we've got; I've created an event generated by the wizard that says the modal just closed; anything wrapping and implementing the wizard can then capture that event and reset the data. I've also added a pair of functions that create the two states (what step, what form data) anew, so that resetting is as trivial as initializing (and is exactly the same, code-wise). * web: Without error handling, this is complete, but I still need @BeryJu (Jens) for help with the SAML Upload (it doesn't appear to be correctly handled?) and the error handling. * web: revise tests for wizard This commit replaces the previous WDIO instance with a more formal and straightforward process using the [pageobjects](https://martinfowler.com/bliki/PageObject.html). In this form, every major component has its own test suite, and a test is a sequence of exercises of those components. A test then becomes something as straightforward as: ``` await LoginPage.open(); await LoginPage.login("ken@goauthentik.io", "eat10bugs"); expect(await UserLibraryPage.pageHeader).toHaveText("My Applications"); await UserLibraryPage.goToAdmin(); expect(await AdminOverviewPage.pageHeader).toHaveText("Welcome, "); await AdminOverviewPage.openApplicationsListPage(); expect(await ApplicationsListPage.pageHeader).toHaveText("Applications"); ApplicationsListPage.startCreateApplicationWizard(); await ApplicationWizard.app.name.setValue(`Test application ${newId}`); await ApplicationWizard.nextButton.click(); await (await ApplicationWizard.getProviderType("ldapprovider")).click(); await ApplicationWizard.nextButton.click(); await ApplicationWizard.ldap.setBindFlow("default-authentication-flow"); await ApplicationWizard.nextButton.click(); await expect(await ApplicationWizard.commitMessage).toHaveText( "Your application has been saved" ); ``` Whether or not there's another layer of DSL in there or not, this is a pretty nice idiom for maintaining tests. * web: updating with forms and fixes for eslint complaints. * web/add webdriverIO testing layer This commit adds WebdriverIO as an end-to-end solution to unit testing. WebdriverIO can be run both locally and remotely, supports strong integration with web components, and is generally robust for use in pipelines. I'll confess to working through a tutorial on how to do this for web components, and this is just chapter 2 (I think there are 5 or so chapters...). There's a makefile, with help! If you just run `make` it tells you: ``` Specify a command. The choices are: help Show this help node_modules Runs `npm install` to prepare this feature precommit Run the precommit: spell check all comments, eslint with sonarJS, prettier-write test-good-login Test that we can log into the server. Requires a running instance of the server. test-bad-login Test that bad usernames and passwords create appropriate error messages ``` ... because Makefiles are documentation, and documentation belongs in Makefiles. I've chosen to go with a PageObject-oriented low-level DSL; what that means is that for each major components (a page, a form, a wizard), there's a class that provides human-readable names for human-interactable and human-viewable objects on the page. The LoginPage object, for example, has selectors for the username, password, submit button, and the failure alert; accessing those allows us to test for items as expected., and to write a DSL for "a good login" that's as straightforward as: ``` await LoginPage.open(); await LoginPage.login("ken@goauthentik.io", "eat10bugs"); await expect(UserLibraryPage.pageHeader).toHaveText("My applications"); ``` There was a *lot* of messing around with the LoginPage to get the username and password into the system. For example, I had to do this with all the `waitForClickable` and `waitForEnable` because we both keep the buttons inaccessible until the form has something and we "black out" the page (put a darkening filter over it) while accessing the flow, meaning there was a race condition such that the test would attempt to interact with the username or password field before it was accessible. But this works now, which is very nice. ``` JavaScript get inputUsername() { return $('>>>input[name="uidField"]'); } get btnSubmit() { return $('>>>button[type="submit"]'); } async username(username: string) { await this.inputUsername.waitForClickable(); await this.inputUsername.setValue(username); await this.btnSubmit.waitForEnabled(); await this.btnSubmit.click(); } ``` The bells & whistles of *Prettier*, *Eslint*, and *Codespell* have also been enabled. I do like my guardrails. * web/adding tests: added comments and cleaned up some administrative features. * web/test: changed the name of one test to reflect it's 'good' status * core/allow alternative postgres credentials This commit allows the `dev-reset` command in the Makefile to pick up and use credentials from the `.env` file if they are present, or fallback to the defaults provided if they are not. This is the only place in the Makefile where the database credentials are used directly against postgresql binaries. The syntax was tested with bash, zsh, and csh, and did not fail under those. The `$${:-}` syntax is a combination of a Makefile idiom for "Pass a single `$` to the environment where this command will be executed," and the shell expresion `${VARIABLE:-default}` means "dereference the environment variable; if it is undefined, used the default value provided." * Re-arrange sequence to avoid recursive make. Nothing wrong with recursive make; it just wasn't essential here. `migrate` is just a build target, not a task. * Cleanup according to the Usage: checkmake [options] <makefile>... checkmake -h | --help checkmake --version checkmake --list-rules Makefile linting tool. * core: added 'help' to the Makefile * get postgres config from authentik config loader Signed-off-by: Jens Langhammer <jens@goauthentik.io> * don't set -x by default Signed-off-by: Jens Langhammer <jens@goauthentik.io> * sort help Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update help strings Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: test LDAP wizard sequence * web: improve testing by adding test admin user via blueprint * This commit continues the application wizard buildout. In this commit are the following changes: - Added SCIM to the list of available providers - Fixed ForwardProxy so that its mode is set correctly. (This is a special case in the committer; I'm unhappy with that.) - Fixed the commit messages so that: - icons are set correctly (Success, Danger, Working) - icons are colored correctly according to state - commit message includes a `data-commit-state` field so tests can find it! - Merged the application wizard tests into a single test pass - Isolated common parts of the application wizard tests to reduce unnecessary repetition. All application tests are the same until you reach the provider section anyway. - Fixed the unit tests so they're finding the right error messages and are enabled to display them correctly. - Moved the test Form handlers into their own folder so they're not cluttering up the Pages folder. * web: add radius to application wizard This commit continues the application wizard buildout. In this commit are the following changes: - Fixed a width-setting bug in the Makefile `make help` feature (i.e "automate that stuff!") - Added Radius to the list of providers we can offer via the wizard - Added `launchUrl` and `UI Settings` to features of the application page the wizard can find - Changed 'SAML Manual Configuration' to just say "SAML Configuration" - Modified `ak-form-group` to take and honor the `aria-label` property (which in turn makes it easier to target specific forms with unit testing) - Reduced the log level for wdio to 'warn'; 'info' was super-spammy and not helpful. It can be put back with `--logLevel info` from the command line. * fix blueprints Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update package name Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add dependabot Signed-off-by: Jens Langhammer <jens@goauthentik.io> * prettier run Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add basic CI Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove hooks Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: application wizard refactor & completion This commit refactors the various components of the Wizard and ApplicationWizard, creating a much more maintainable and satisfying Wizard experience for both developers (i.e, *me* and *Jens* so far), and for the customer. The Wizard base has been refactored into three components: **AkWizardController** The `AkWizardController` provides the event listenters for the wizard; it hooks them up, recevies the events, and forwards them to the wizard. It unwraps the event objects and forwards the relevant messages contained in the events. It knows of three event categories: - Navigation requests (move to a different step) - Update requests (the current step has updated the business content) - Close requests (close or cancel the wizard). **ak-wizard-frame** The `ak-wizard-frame` is the ModalButton interface. It provides the Header, Breadcrumbs (nee` "navigation block"), Buttons, and a DIV into which the main content is rendered. **AkWizard** `AkWizard` is an *incomplete* implementation of the wizard. It's meant to be inherited by a child class, which will implement the rest. It extends `AKElement`. It provides the basic content needed, such as steps, currentStep (as an index), an accessor for the step itself, an accessor for the frame, and the interface to the `AkWizardController`. **ApplicationWizard** The `ApplicationWizard` itself has been refactored to accommodate these changes. It inherits from `AkWizard` and provides the business logic for what to do when a form updates, some custom logic for preventing moving through the wizard when the forms are incomplete, and a persistence layer for filling out different providers in the same session. It's simplified a *lot*. The types specified for `AkWizard` are pretty nifty, I think. I could wish the types being passed via the custom events were more robust, but [strongly typed custom events](https://github.com/lit/lit-element/issues/808) turn out to be quite the pain in the, er, neck. As it is, the `precommit` pass did very good at preventing the worst disasters. The steps themselves were re-written as objects so that they could take advantage of their `valid` and `disabled` states and provide more meaningful buttons and labels. I think it's a solid compromise, and it moved a lot of display logic out of the core `handleUpdate()` business method. The tests, such as they are, are passing. * Added comment describing new test. * web: ensuring copy from `main` is canon * web: fixes after merge * web: laying the groundwork for future expansion This commit is a hodge-podge of updates and changes to the web. Functional changes: - Makefile: Fixed a bug in the `help` section that prevented the WIDTH from being accurately calculated if `help` was included rather than in-lined. - ESLint: Modified the "unused vars" rule so that variables starting with an underline are not considered by the rule. This allows for elided variables in event handlers. It's not a perfect solution-- a better one would be to use Typescript's function-specialization typing, but there are too many places where we elide or ignore some variables in a function's usage that switching over to specialization would be a huge lift. - locale: It turns out, lit-locale does its own context management. We don't need to have a context at all in this space, and that's one less listener we need to attach t othe DOM. - ModalButton: A small thing, but using `nothing` instead of "html``" allows lit better control over rendering and reduces the number of actual renders of the page. - FormGroup: Provided a means to modify the aria-label, rather than stick with the just the word "Details." Specializing this field will both help users of screen readers in the future, and will allow test suites to find specific form groups now. - RadioButton: provide a more consistent interface to the RadioButton. First, we dispatch the events to the outside world, and we set the value locally so that the current `Form.ts` continues to behave as expected. We also prevent the "button lost value" event from propagating; this presents a unified select-like interface to users of the RadioButtonGroup. The current value semantics are preserved; other clients of the RadioButton do not see a change in behavior. - EventEmitter: If the custom event detail is *not* an object, do not use the object-like semantics for forwarding it; just send it as-is. - Comments: In the course of laying the groundwork for the application wizard, I throw a LOT of comments into the code, describing APIs, interfaces, class and function signatures, to better document the behavior inside and as signposts for future work. * web: permit arrays to be sent in custom events without interpolation. * actually use assignValue or rather serializeFieldRecursive Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: eslint & prettier fixes, plus small aesthetic differences. * Restoring this file. Not sure where it disappears to. * fix label in dark mode Signed-off-by: Jens Langhammer <jens@goauthentik.io> * SCIM Manuel -> SCIM Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix lint errors Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: better converter configuration, CSS repair, and forward-domain-proxy 1. Forward Domain Proxy. I wasn't sure if this method was appropriate for the wizard, but Jens says it is. I've added it. 2. In the process of doing so, I decided that the Provider.converter field was overly complexified; I tried too hard to reduce the number of functions I needed to define, but in the process outsourced some of the logic of converting the Wizard's dataset into a property typed request to the `commit` phase, which was inappropriate. All of the logic about a provider, aside from its display, should be here with the code that distinguishes between providers. This commit makes it so. 3. Small CSS fix: the fields inherited from the Proxy provider forms had some unexpected CSS which was causing a bit of a weird indent. That has been rectified. * web: running pre-commit after merge. * web: ensure the applications wizard tests finish after current changes * prettier has opinions. * web: application wizard spit & polish The "ApplicationWizardHint" now correctly uses the localstorage and allows the user to navigate back and see the message after it's been hidden, so that it will always be available during the test phase. The ApplicationList's old "Create Application Form" button has been restored for the purposes of the test phase. The ApplicationWizard is now available on both the ApplicationList and ProviderList pages. Tana and I discussed the microcopy, putting a stronger second-person "You can do..." twist onto the language, to give the user the sense of empowerment. The ShowHintController now has both "hide" and "show" operations, to support the hint restoration. * web: updated storybook stories for the wizard, illustration how "a simple wizard" is configured in source code and tested with storybook. * web: I hate getting spanked by prettier. * web: sometimes I wish I had lower standards Anyway, this was a very stupid bug, because by definition function definition arguments don't have uses, they're being defined, not implemented. Fixed, conf fixed to compensate, and consequences conquered. * move context from labs to main Signed-off-by: Jens Langhammer <jens@goauthentik.io> * Revert "move context from labs to main" This reverts commit |
|||
| 21e5441f92 |
web: patternfly hints as ak-web-component (#7120)
* web: patternfly hints as ak-web-component Patternfly 5's "Hints" React Component, but ported to web components. The discovery that CSS Custom Properties are still available in child components, even if they're within independent ShadowDOMs, made this fairly easy to port from Handlebars to Lit-HTML. Moving the definitions into `:host` and the applications into the root DIV of the component made duplicating the Patternfly 5 structure straightforward. Despite the [Patternfly Elements]documentation](https://patternflyelements.org/docs/develop/create/), there's a lot to Patternfly Elements that isn't well documented, such as their slot controller, which near as I can tell just makes it easy to determine if a slot with the given name is actually being used by the client code, but it's hard to tell why, other than that it provides an easy way to determine if some CSS should be included. * Pre-commit fixes. * web: fix some issues with styling found while testing. * web: separated the "with Title" and "without Title" stories. * Added footer story, fixed some CSS. * web: hint controller Add the `ShowHintController`. This ReactiveController takes a token in its constructor, and looks in LocalStorage for that token and an associated value. If that value is not `undefined`, it sets the field `this.host.showHint` to the value found. It also provides a `render()` method that provides an `ak-hint-footer` with a checkbox and the "Don't show this message again," and responds to clicks on the checkbox by setting the `this.hint.showHint` and LocalStorage values to "false". An example web component using it has been supplied. * web: support dark mode for hints. This was nifty. Still not entirely sure about the `theme="dark"` rippling through the product, but in this case it works quite well. All it took was defining the alternative dark mode values in a CSS entry, `:host([theme="dark"]) { ... }` and exploiting Patternfly's already intensely atomized CSS Custom Properties properly. * web: revise colors to use more of the Authentik dark-mode style. * Update web/src/components/ak-hint/ak-hint.ts Signed-off-by: Jens L. <jens@beryju.org> * remove any Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens L. <jens@beryju.org> Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens L <jens@goauthentik.io> |
|||
| 6792bf8876 |
web: package up horizontal elements into their own components (#7053)
* web: laying the groundwork for future expansion This commit is a hodge-podge of updates and changes to the web. Functional changes: - Makefile: Fixed a bug in the `help` section that prevented the WIDTH from being accurately calculated if `help` was included rather than in-lined. - ESLint: Modified the "unused vars" rule so that variables starting with an underline are not considered by the rule. This allows for elided variables in event handlers. It's not a perfect solution-- a better one would be to use Typescript's function-specialization typing, but there are too many places where we elide or ignore some variables in a function's usage that switching over to specialization would be a huge lift. - locale: It turns out, lit-locale does its own context management. We don't need to have a context at all in this space, and that's one less listener we need to attach t othe DOM. - ModalButton: A small thing, but using `nothing` instead of "html``" allows lit better control over rendering and reduces the number of actual renders of the page. - FormGroup: Provided a means to modify the aria-label, rather than stick with the just the word "Details." Specializing this field will both help users of screen readers in the future, and will allow test suites to find specific form groups now. - RadioButton: provide a more consistent interface to the RadioButton. First, we dispatch the events to the outside world, and we set the value locally so that the current `Form.ts` continues to behave as expected. We also prevent the "button lost value" event from propagating; this presents a unified select-like interface to users of the RadioButtonGroup. The current value semantics are preserved; other clients of the RadioButton do not see a change in behavior. - EventEmitter: If the custom event detail is *not* an object, do not use the object-like semantics for forwarding it; just send it as-is. - Comments: In the course of laying the groundwork for the application wizard, I throw a LOT of comments into the code, describing APIs, interfaces, class and function signatures, to better document the behavior inside and as signposts for future work. * web: permit arrays to be sent in custom events without interpolation. * actually use assignValue or rather serializeFieldRecursive Signed-off-by: Jens Langhammer <jens@goauthentik.io> * web: package up horizontal elements into their own components. This commit introduces a number of "components." Jens has this idiom: ``` <ak-form-element-horizontal label=${msg("Name")} name="name" ?required=${true}> <input type="text" value="${ifDefined(this.instance?.name)}" class="pf-c-form-control" required /> </ak-form-element-horizontal> ``` It's a very web-oriented idiom in that it's built out of two building blocks, the "element-horizontal" descriptor, and the input object itself. This idiom is repeated a lot throughout the code. As an alternative, let's wrap everything into an inheritable interface: ``` <ak-text-input name="name" label=${msg("Name")} value="${ifDefined(this.instance?.name)} required > </ak-text-input> ``` This preserves all the information of the above, makes it much clearer what kind of interaction we're having (sometimes the `type=` information in an input is lost or easily missed), and while it does require you know that there are provided components rather than the pair of layout-behavior as in the original it also gives the developer more precision over the look and feel of the components. *Right now* these components are placed into the LightDOM, as they are in the existing source code, because the Form handler has a need to be able to "peer into" the "element-horizontal" component to find the values of the input objects. In a future revision I hope to place the burden of type/value processing onto the input objects themselves such that the form handler will need only look for the `.value` of the associated input control. Other fixes: - update the FlowSearch() such that it actually emits an input event when its value changes. - Disable the storybook shortcuts; on Chrome, at least, they get confused with simple inputs - Fix an issue with precommit to not scan any Python with ESLint! :-) * web: provide storybook stories for the components This commit provides storybook stories for the ak-horizontal-element wrappers. A few bugs were found along the way, including one rather nasty one from Radio where we were still getting the "set/unset" pair in the wrong order, so I had to knuckle down and fix the event handler properly. * web: test oauth2 provider "guinea pig" for new components I used the Oauth2 provider page as my experiment in seeing if the horizontal-element wrappers could be used instead of the raw wrappers themselves, and I wanted to make sure a test existed that asserts that filling out THAT form in the ProvidersList and ProvidersForm didn't break anything. This commit updates the WDIO tests to do just that; the test is simple, but it does exercise the `name` field of the Provider, something not needed in the Wizard because it's set automatically based on the Application name, and it even asserts that the new Provider exists in the list of available Providers when it's done. * web: making sure ESlint and Prettier are happy * "fix" lint Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io> |
|||
| a0d2aca61c |
web: detangle components from applications (#6891)
* Web: Detangling some circular dependencies in Admin and User Admin, User, and Flow should not dependend upon each other, at least not in a circular way. If Admin and User depend on Flow, that's fine, but Flow should not correspondingly depend upon elements of either; if they have something in common, let's put them in `@goauthentik/common` or find some other smart place to store them. This commit refactors the intentToLabel and actionToLabel functions into `@goauthentik/common/labels` and converts them to static tables for maintenance purposes. * web: "Consistency is the hobgoblin of small minds" - Ralph Waldo Emerson * web: I found these confusing to look at, so I added comments. * web: remove admin-to-user component reference(s) There was only one: AppIcon. This has been moved to `components`. Touching the LibraryApplications page triggered a cyclomatic complexity check. Extracting the expansion block and streamlining the class and style declarations with lit directives helped. * web: remove admin from elements This commit removes the two references from `elements` to `admin`: the list of UserEvents and a reference to the FlowSearch type, used by the Forms manager to decide how to extract a value. For FlowSearch, a different convention for detecting the type was implemented (instances of the object have a unique fieldname for the value holder). UserEvents and ObjectChangelog have been moved to `components` as they're clearly dependent upon the API. This defers work on removing Admin from Components, as that is (again) references going the wrong way, but that can happen later. * web: remove admin-to-user component reference(s) (#6856) There was only one: AppIcon. This has been moved to `components`. Touching the LibraryApplications page triggered a cyclomatic complexity check. Extracting the expansion block and streamlining the class and style declarations with lit directives helped. * This was supposed to be merged. * web: remove `./element`⇢`./user` references The offender here is UserDevicesList, which despite being in `elements` is only used by the admin/user/UserViewPage. The problem is that UserDevicesList, despite being in `admin`, inherits from `user`, so moving it would have created a new admin⇢user reference, and the whole point of this exercise is to get rid of references that point "up" from the foundational pieces to the views, or that refer to components in sibling applications. After examining UserDevicesList, I realized that *every feature* of MFADevicesList had been overridden: the rows, the columns, the toolbar, and the endpoint all had custom overrides. Nothing was left of MFADevicesList after that. Even the property that the web component used had been completely changed. The only thing they had in common was that they both inherited from `Table<Device>`. Refactoring UserDevicesList so that it inherited directly from `Table<Device>` and then moving it into `./admin/users` was the obvious and correct step. Both used the same label table, so that went into the `common/labels` folder. Along the way, I cleaned up a few minor details. Just little things, like the repeated invocation of: ``` new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorAdminMETHODDestroy({ id: device.pk }); ``` This is repeated five times, once for each Method. By creating these: ``` const api = new AuthenticatorsApi(DEFAULT_CONFIG); const id = { id: device.pk }; ``` The method invocation could be just `api.authenticatorsMETHODDestroy(id)`, which is easier on the eyes. See the MFADevicesPage for the full example. Similarly, ``` return [ new TableColumn(msg("Name"), ""), new TableColumn(msg("Type"), ""), new TableColumn("") ]; ``` is more straightforward as: ``` const headers = [msg("Name"), msg("Type"), ""]; return headers.map((th) => new TableColumn(th, "")); ``` We've labeled what we're working with, and web developers ought to know that `th` is the HTML code for `table header`. I've had to alter what files are scanned in pre-commit mode; it doesn't handle renamed files very well, and at the moment a file that is renamed is not scanned, as its "new" name is not straightforwardly displayed, not even by `git porcelain`. * web: make the table of column headers look like a table * web: detangle `common` from `elements`. And just like that, `common` no longer has a reference to `elements`. I don't mind this little bit of code duplication if it removes a cycle. What it does point out is that there are bits of `common` that are predicated on the presence of the browser, and that there are bits of `elements` that, if they rely on `common`, can't be disentangled from the application as a whole. Which seems to me that we have two different things going on in common: things about an application, and things about elements that are independent of the application. I'll think about those later. ``` $ rg 'import.*@goauthentik' ./common/ | perl -ne 'm{"(@goauthentik[^"]*)"} && print "$1\n"' | sort | cut -d '/' -f1-2 | uniq | sort @goauthentik/api @goauthentik/common $ ``` * web: odd bug; merge-related? Gonna investigate. * web: build failure thanks to local cache; fixed * web: detangle `components` from `admin`. This was the last inappropriate reference: something from `./components` referencing something in `./admin`, in this case the `ak-event-info` component. Used by both Users and Admin, moving it into `./components` was the obvious correct step. `ak-event-info` is a lookup table relating specific events in the event log to rich, textual representations; in the special case of model changes and email info, even more rich content is available in a dl/dt format. I've tableized the model changes and email info renderer, and I've extracted every event's textual representation into its own method, converting the `switch/case` rendering statement into a `switch/case` dispatch switch. This has the virtue of isolating each unique case and making the dispatch switch short and coherent. The conversion was done mechanistically; I gave the refactorer (Tide, in this case) instructions to duplicate the switch block and then convert every case into a method with a name patterned on the `case`. Going back to the original switch block, it was easy to duplicate the pattern matching and convert it into a dispatch switch. And with this, there are zero cycles in the references between the different "packageable" sections of the UI. The only thing left to do is figure out how to redistribute `./elements` and `./components` in a way that makes sense for each. * Changed function name from 'emailMessageBody' to 'githubIssueMessageBody' to better reflect its usage. * web: added comments about length and purpose of githubIssueMessageBody. * Update web/src/common/labels.ts Co-authored-by: Jens L. <jens@goauthentik.io> Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com> * Unwanted change. --------- Signed-off-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com> Co-authored-by: Jens L. <jens@goauthentik.io> |
|||
| d35c7df789 |
web: detangle element to admin references (#6864)
* Web: Detangling some circular dependencies in Admin and User Admin, User, and Flow should not dependend upon each other, at least not in a circular way. If Admin and User depend on Flow, that's fine, but Flow should not correspondingly depend upon elements of either; if they have something in common, let's put them in `@goauthentik/common` or find some other smart place to store them. This commit refactors the intentToLabel and actionToLabel functions into `@goauthentik/common/labels` and converts them to static tables for maintenance purposes. * web: "Consistency is the hobgoblin of small minds" - Ralph Waldo Emerson * web: I found these confusing to look at, so I added comments. * web: remove admin-to-user component reference(s) There was only one: AppIcon. This has been moved to `components`. Touching the LibraryApplications page triggered a cyclomatic complexity check. Extracting the expansion block and streamlining the class and style declarations with lit directives helped. * web: remove admin from elements This commit removes the two references from `elements` to `admin`: the list of UserEvents and a reference to the FlowSearch type, used by the Forms manager to decide how to extract a value. For FlowSearch, a different convention for detecting the type was implemented (instances of the object have a unique fieldname for the value holder). UserEvents and ObjectChangelog have been moved to `components` as they're clearly dependent upon the API. This defers work on removing Admin from Components, as that is (again) references going the wrong way, but that can happen later. * web: remove admin-to-user component reference(s) (#6856) There was only one: AppIcon. This has been moved to `components`. Touching the LibraryApplications page triggered a cyclomatic complexity check. Extracting the expansion block and streamlining the class and style declarations with lit directives helped. * This was supposed to be merged. |
|||
| 28702b3a25 |
web: Detangling some circular dependencies in Admin and User (#6852)
* Web: Detangling some circular dependencies in Admin and User Admin, User, and Flow should not dependend upon each other, at least not in a circular way. If Admin and User depend on Flow, that's fine, but Flow should not correspondingly depend upon elements of either; if they have something in common, let's put them in `@goauthentik/common` or find some other smart place to store them. This commit refactors the intentToLabel and actionToLabel functions into `@goauthentik/common/labels` and converts them to static tables for maintenance purposes. * web: "Consistency is the hobgoblin of small minds" - Ralph Waldo Emerson * web: I found these confusing to look at, so I added comments. * web: remove admin-to-user component reference(s) (#6856) There was only one: AppIcon. This has been moved to `components`. Touching the LibraryApplications page triggered a cyclomatic complexity check. Extracting the expansion block and streamlining the class and style declarations with lit directives helped. |
|||
| bfd0fb66b3 |
web/admin: fix ak-toggle-group for policy and blueprint uses (#6687)
* web/admin: fix ak-toggle-group for policy and blueprint uses Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix and re-enable lit-analyse 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.
|