Compare commits

...

29 Commits

Author SHA1 Message Date
1bc8fa0a9d Merge branch 'main' into web/legibility/dual-select-events 2025-02-25 09:32:42 +01:00
3ec0d30965 web: restructure ak-dual-select to avoid using CustomEvent
# What

- Replace all `CustomEvent<T>` handlers with a child class Event.
- Use the standard `dispatchEvent()` and `addEventListener()` clauses.
- Move common methods of the two panes into an abstract parent class.

# Why

CustomEvent is a bit of a side-show in JavaScript; it's perfectly acceptable to inherit from Event,
and there's much better support for type management while using it, plus deconstructing the received
event object is cleaner with child Events than unpacking the `details` object.

This codebase is now more open to change, and is closer to our still-evolving style.

Doing it this way mean that, once you have an event defined, you don't have to remember if you're
sending a custom event or a normal event, and you don't need all that infrastructure for making your
Lit objects sensitive to custom event handling.  There's enough mixin clutter already.

And just like I hate clutter, I hate duplication.  The two panes had a lot in common with ARIA
handling and storing, clearing, and assigning selected items to the "pending move" table.  Moving
all that into a parent class exposed the differences: one is a source and the other a sink; one
reflects changes made, the other possible changes to be made.

# Testing

The Storybook tests have all been updated to match the codebase, and there are standalone tests for
the various components (pagination, pane control, search) that can be exercised before deployment.
2025-01-15 16:20:12 -08:00
50d2f69332 Merge branch 'main' into dev
* main:
  website: revise full development environment instructions (#12638)
  website: bump typescript from 5.7.2 to 5.7.3 in /website (#12620)
  website: bump aws-cdk from 2.174.1 to 2.175.0 in /website (#12621)
  ci: bump docker/setup-qemu-action from 3.2.0 to 3.3.0 (#12622)
  core: bump twilio from 9.4.1 to 9.4.2 (#12623)
  core: bump python-kadmin-rs from 0.5.2 to 0.5.3 (#12624)
  core: bump ruff from 0.8.6 to 0.9.0 (#12625)
  core: bump pydantic from 2.10.4 to 2.10.5 (#12626)
  core: bump google-api-python-client from 2.157.0 to 2.158.0 (#12628)
  core: bump goauthentik.io/api/v3 from 3.2024121.3 to 3.2024122.1 (#12629)
  web: bump API Client version (#12617)
  release: 2024.12.2 (#12615)
  website/docs: prepare 2024.12.2 release notes (#12614)
  providers/saml: fix invalid SAML Response when assertion and response are signed (#12611)
  core: fix error when creating new user with default path (#12609)
  rbac: permissions endpoint: allow authenticated users (#12608)
  website/docs: update customer portal (#12603)
  website/docs: policy for email whitelist: modernize (#12558)
2025-01-10 16:26:36 -08:00
7d972ec711 Merge branch 'main' into dev
* main:
  lib: add expression helper ak_create_jwt to create JWTs (#12599)
  api: cleanup owner permissions (#12598)
  website: bump aws-cdk from 2.174.0 to 2.174.1 in /website (#12593)
  core: bump aws-cdk-lib from 2.174.0 to 2.174.1 (#12594)
  website/integrations: portainer: group config steps (#12548)
  translate: Updates for file web/xliff/en.xlf in fi (#12586)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fi (#12584)
  website/docs: fix Nginx redirection example (#12561)
2025-01-08 10:13:59 -08:00
854427e463 Merge branch 'main' into dev
* main:
  core: bump golang.org/x/oauth2 from 0.24.0 to 0.25.0 (#12571)
  website: bump the docusaurus group in /website with 9 updates (#12569)
  core: bump github.com/coreos/go-oidc/v3 from 3.11.0 to 3.12.0 (#12572)
  core: bump ruff from 0.8.5 to 0.8.6 (#12573)
  ci: release: fix AWS cfn template permissions (#12576)
  translate: Updates for file web/xliff/en.xlf in fr (#12578)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#12577)
  sources/kerberos: authenticate with the user's username instead of the first username in authentik (#12497)
  website/integrations: Fix deprecated terraform ressource authentik_scope_mapping in docs (#12554)
  website/user-sources Fix Free IPA docs page (#12549)
  core: bump aws-cdk-lib from 2.173.4 to 2.174.0 (#12574)
  website/integrations: semaphore: fix formatting (#12567)
  website: bump aws-cdk from 2.173.4 to 2.174.0 in /website (#12570)
  website/integrations: Update Frappe Application index.md (#12527)
  website: add api reference docs to redirect file (#12551)
2025-01-06 08:32:50 -08:00
be349e2e14 Merge branch 'main' into dev
* main:
  core: bump github.com/getsentry/sentry-go from 0.30.0 to 0.31.1 (#12543)
  core: bump google-api-python-client from 2.156.0 to 2.157.0 (#12544)
  core: bump ruff from 0.8.4 to 0.8.5 (#12545)
  core: bump msgraph-sdk from 1.15.0 to 1.16.0 (#12546)
  Update index.mdx (#12542)
  web: fix source selection and outpost integration health (#12530)
  Ading a step to paperless guide (#12539)
  website/integrations: Semaphore (#12515)
  website/integrations: komga: document (#12476)
  website/integrations: fix missing quote in paperless-ngx (#12537)
  website/integrations: cloudflare access: upd placeholder for saas (#12536)
  website/integrations: veeam-enterprise-manager: don't hardcode helpcenter doc version (#12538)
2025-01-03 08:09:25 -08:00
bd0e81b8ad Merge branch 'main' into dev
* main:
  website/integrations: meshcentral: document (#12509)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12524)
  core: bump goauthentik.io/api/v3 from 3.2024121.2 to 3.2024121.3 (#12522)
  web: bump API Client version (#12520)
  website/integrations: chronograf: document (#12474)
  website/integrations: update preparation placeholder (#12507)
  providers/saml: fix handle Accept: application/xml for SAML Metadata endpoint (#12483) (#12518)
  core: bump aws-cdk-lib from 2.173.3 to 2.173.4 (#12513)
  website: bump aws-cdk from 2.173.3 to 2.173.4 in /website (#12514)
  core: bump coverage from 7.6.9 to 7.6.10 (#12499)
  core: bump aws-cdk-lib from 2.173.2 to 2.173.3 (#12500)
  website: bump aws-cdk from 2.173.2 to 2.173.3 in /website (#12501)
  core: bump github.com/go-ldap/ldap/v3 from 3.4.9 to 3.4.10 (#12502)
  website/docs: New "Whats Up Docker" URL (#12488)
2025-01-02 10:01:26 -08:00
f6afb59515 Revert "This (temporary) change is needed to prevent the unit tests from failing."
This reverts commit dddde09be5.
2024-12-26 13:59:53 -08:00
dddde09be5 This (temporary) change is needed to prevent the unit tests from failing.
\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes
2024-12-26 13:59:00 -08:00
6d7fc94698 Merge branch 'main' into dev
* main: (118 commits)
  outposts: fix version label (#12486)
  web: only load version context when authenticated (#12482)
  core: bump goauthentik.io/api/v3 from 3.2024120.2 to 3.2024121.2 (#12478)
  ci: bump helm/kind-action from 1.11.0 to 1.12.0 (#12479)
  web: fix build dev build (#12473)
  root: fix dev build version being invalid semver (#12472)
  internal: fix missing trailing slash in outpost websocket (#12470)
  web: bump API Client version (#12469)
  admin: monitor worker version (#12463)
  core: bump jinja2 from 3.1.4 to 3.1.5 (#12467)
  web: bump API Client version (#12468)
  release: 2024.12.1 (#12466)
  web: misc fixes for admin and flow inspector (#12461)
  website/docs: 2024.12.1 release notes (#12462)
  core: bump goauthentik.io/api/v3 from 3.2024120.1 to 3.2024120.2 (#12456)
  core: bump urllib3 from 2.2.3 to 2.3.0 (#12457)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12454)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12453)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12455)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12458)
  ...
2024-12-26 08:49:23 -08:00
1dcf9108ad Merge branch 'main' into dev
* main:
  flows: better test stage's challenge responses (#12316)
  enterprise/stages/authenticator_endpoint_gdtc: don't set frame options globally (#12311)
  stages/identification: fix invalid challenge warning when no captcha stage is set (#12312)
  website/docs: prepare 2024.10.5 release notes (#12309)
  website: bump nanoid from 3.3.7 to 3.3.8 in /website (#12307)
  flows: silent authz flow (#12213)
  root:  use healthcheck in depends_on for postgres and redis (#12301)
  ci: ensure mark jobs always run and reflect correct status (#12288)
  enterprise: allow deletion/modification of users when in read-only mode (#12289)
  web/flows: resize captcha iframes (#12260)
2024-12-10 09:07:45 -08:00
7bb6a3dfe6 Merge branch 'main' into dev
* main:
  website/docs: add page about the Cobalt pentest (#12249)
  core: bump aws-cdk-lib from 2.171.1 to 2.172.0 (#12296)
  website: bump aws-cdk from 2.171.1 to 2.172.0 in /website (#12295)
  core: bump sentry-sdk from 2.19.1 to 2.19.2 (#12297)
  core: bump coverage from 7.6.8 to 7.6.9 (#12299)
  core, web: update translations (#12290)
  root: fix override locale only if it is not empty (#12283)
  translate: Updates for file web/xliff/en.xlf in fr (#12276)
  core: bump twilio from 9.3.7 to 9.3.8 (#12282)
  website: bump path-to-regexp and express in /website (#12279)
  core: bump sentry-sdk from 2.19.0 to 2.19.1 (#12280)
  core: bump ruff from 0.8.1 to 0.8.2 (#12281)
  website/docs: fix lint (#12287)
  website/integrations: netbird: fix redirect URI regex (#12284)
2024-12-09 08:28:52 -08:00
9cc440eee1 Merge branch 'main' into dev
* main:
  web: simplify `?inline` handler for Storybook (#12246)
  website/docs: Update Traefik middleware example to reflect latest version of Traefik (#12267)
  website/docs: add . in https://netbird.company* (#12166)
  core: bump goauthentik.io/api/v3 from 3.2024104.1 to 3.2024104.2 (#12263)
  core: bump pydantic from 2.10.2 to 2.10.3 (#12262)
  core: bump github.com/getsentry/sentry-go from 0.29.1 to 0.30.0 (#12264)
  core, web: update translations (#12268)
  website: bump @types/react from 18.3.12 to 18.3.13 in /website (#12269)
  website: bump prettier from 3.4.1 to 3.4.2 in /website (#12270)
  ci: bump actions/attest-build-provenance from 1 to 2 (#12271)
  core: bump golang.org/x/sync from 0.9.0 to 0.10.0 (#12272)
  core: bump django from 5.0.9 to 5.0.10 (#12273)
  core: bump webauthn from 2.3.0 to 2.4.0 (#12274)
  website/integrations: add The Lounge (#11971)
  core: bump python-kadmin-rs from 0.3.0 to 0.4.0 (#12257)
  root: fix health status code (#12255)
  ci: fix should_push always being false (#12252)
  web: bump API Client version (#12251)
  providers/oauth2: Add provider federation between OAuth2 Providers (#12083)
  website/integrations: mastodon: set correct uid field (#11945)
2024-12-05 10:47:00 -08:00
fe9e4526ac Merge branch 'main' into dev
* main: (31 commits)
  web/admin: bugfix: dual select initialization revision (#12051)
  web: update tests for Chromedriver 131 (#12199)
  website/integrations: add Aruba Orchestrator (#12220)
  core: bump aws-cdk-lib from 2.167.1 to 2.171.1 (#12237)
  website: bump aws-cdk from 2.167.1 to 2.171.1 in /website (#12241)
  core, web: update translations (#12236)
  core: bump python-kadmin-rs from 0.2.0 to 0.3.0 (#12238)
  core: bump pytest from 8.3.3 to 8.3.4 (#12239)
  core: bump drf-spectacular from 0.27.2 to 0.28.0 (#12240)
  core, web: update translations (#12222)
  core: Bump ruff from 0.8.0 to 0.8.1 (#12224)
  core: Bump ua-parser from 0.18.0 to 1.0.0 (#12225)
  core: Bump msgraph-sdk from 1.13.0 to 1.14.0 (#12226)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12234)
  website/docs: install: add aws (#12082)
  core: Bump pyjwt from 2.10.0 to 2.10.1 (#12217)
  core: Bump fido2 from 1.1.3 to 1.2.0 (#12218)
  core: Bump cryptography from 43.0.3 to 44.0.0 (#12219)
  providers/oauth2: allow m2m for JWKS without alg in keys (#12196)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#12210)
  ...
2024-12-02 09:10:36 -08:00
20b66f850c Merge branch 'main' into dev
* main:
  website/docs: Add note about single group per role (#12169)
  website/docs: Fix documentation about attribute merging for indirect membership (#12168)
  root: support running authentik in subpath (#8675)
  docs: fix contribution link (#12189)
  core, web: update translations (#12190)
  core: Bump msgraph-sdk from 1.12.0 to 1.13.0 (#12191)
  core: Bump selenium from 4.26.1 to 4.27.0 (#12192)
2024-11-26 09:27:51 -08:00
67b327414b Merge branch 'main' into dev
* main:
  website/docs: Fix CSP syntax (#12124)
2024-11-25 13:11:45 -08:00
5b8d86b5a9 Merge branch 'main' into dev
* main:
  ci: only mirror if secret is available (#12181)
  root: fix database ssl options not set correctly (#12180)
  core, web: update translations (#12145)
  core: bump tornado from 6.4.1 to 6.4.2 (#12165)
  website: bump the docusaurus group in /website with 9 updates (#12172)
  website: bump typescript from 5.6.3 to 5.7.2 in /website (#12173)
  ci: bump actions/checkout from 3 to 4 (#12174)
  core: bump github.com/stretchr/testify from 1.9.0 to 1.10.0 (#12175)
  core: bump coverage from 7.6.7 to 7.6.8 (#12176)
  core: bump ruff from 0.7.4 to 0.8.0 (#12177)
2024-11-25 09:21:19 -08:00
67aed3e318 Merge branch 'main' into dev
* main: (33 commits)
  ci: mirror repo to internal repo (#12160)
  core: bump goauthentik.io/api/v3 from 3.2024102.2 to 3.2024104.1 (#12149)
  core: bump debugpy from 1.8.8 to 1.8.9 (#12150)
  core: bump webauthn from 2.2.0 to 2.3.0 (#12151)
  core: bump pydantic from 2.10.0 to 2.10.1 (#12152)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12156)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12157)
  core: bump sentry-sdk from 2.18.0 to 2.19.0 (#12153)
  web: bump API Client version (#12147)
  root: Backport version change (#12146)
  website/docs: update info about footer links to match new UI (#12120)
  website/docs: prepare release notes (#12142)
  providers/oauth2: fix migration (#12138)
  providers/oauth2: fix migration dependencies (#12123)
  web: bump API Client version (#12129)
  providers/oauth2: fix redirect uri input (#12122)
  providers/proxy: fix redirect_uri (#12121)
  website/docs: prepare release notes (#12119)
  web: bump API Client version (#12118)
  security: fix CVE 2024 52289 (#12113)
  ...
2024-11-22 13:56:13 -08:00
9809b94030 Merge branch 'main' into dev
* main: (28 commits)
  providers/scim: accept string and int for SCIM IDs (#12093)
  website: bump the docusaurus group in /website with 9 updates (#12086)
  core: fix source_flow_manager throwing error when authenticated user attempts to re-authenticate with existing link (#12080)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#12079)
  scripts: remove read_replicas from generated dev config (#12078)
  core: bump geoip2 from 4.8.0 to 4.8.1 (#12071)
  core: bump goauthentik.io/api/v3 from 3.2024100.2 to 3.2024102.2 (#12072)
  core: bump maxmind/geoipupdate from v7.0.1 to v7.1.0 (#12073)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12074)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12075)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12076)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12077)
  web/admin: auto-prefill user path for new users based on selected path (#12070)
  core: bump aiohttp from 3.10.2 to 3.10.11 (#12069)
  web/admin: fix brand title not respected in application list (#12068)
  core: bump pyjwt from 2.9.0 to 2.10.0 (#12063)
  web: add italian locale (#11958)
  web/admin: better footer links (#12004)
  core, web: update translations (#12052)
  core: bump twilio from 9.3.6 to 9.3.7 (#12061)
  ...
2024-11-20 10:23:54 -08:00
e7527c551b Merge branch 'main' into dev
* main:
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12045)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12047)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12044)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12046)
  web/flows: fix invisible captcha call (#12048)
  rbac: fix incorrect object_description for object-level permissions (#12029)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12036)
  core: bump coverage from 7.6.4 to 7.6.5 (#12037)
  ci: bump codecov/codecov-action from 4 to 5 (#12038)
  release: 2024.10.2 (#12031)
2024-11-15 12:47:17 -08:00
36b10b434a :wqge branch 'main' into dev
* main:
  providers/ldap: fix global search_full_directory permission not being sufficient (#12028)
  website/docs: 2024.10.2 release notes (#12025)
  lifecycle: fix ak exit status not being passed (#12024)
  core: use versioned_script for path only (#12003)
  core, web: update translations (#12020)
  core: bump google-api-python-client from 2.152.0 to 2.153.0 (#12021)
  providers/oauth2: fix manual device code entry (#12017)
  crypto: validate that generated certificate's name is unique (#12015)
  core, web: update translations (#12006)
  core: bump google-api-python-client from 2.151.0 to 2.152.0 (#12007)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12011)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12010)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12012)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12013)
  providers/proxy: fix Issuer when AUTHENTIK_HOST_BROWSER is set (#11968)
  website/docs: move S3 ad GeoIP to System Management/Operations (#11998)
  website/integrations: nextcloud: add SSE warning (#11976)
2024-11-14 11:29:13 -08:00
831797b871 Merge branch 'main' into dev
* main: (21 commits)
  web: bump API Client version (#11997)
  sources/kerberos: use new python-kadmin implementation (#11932)
  core: add ability to provide reason for impersonation (#11951)
  website/integrations:  update vcenter integration docs (#11768)
  core, web: update translations (#11995)
  website: bump postcss from 8.4.48 to 8.4.49 in /website (#11996)
  web: bump API Client version (#11992)
  blueprints: add default Password policy (#11793)
  stages/captcha: Run interactive captcha in Frame (#11857)
  core, web: update translations (#11979)
  core: bump packaging from 24.1 to 24.2 (#11985)
  core: bump ruff from 0.7.2 to 0.7.3 (#11986)
  core: bump msgraph-sdk from 1.11.0 to 1.12.0 (#11987)
  website: bump the docusaurus group in /website with 9 updates (#11988)
  website: bump postcss from 8.4.47 to 8.4.48 in /website (#11989)
  stages/password: use recovery flow from brand (#11953)
  core: bump golang.org/x/sync from 0.8.0 to 0.9.0 (#11962)
  web: bump cookie, swagger-client and express in /web (#11966)
  core, web: update translations (#11959)
  core: bump debugpy from 1.8.7 to 1.8.8 (#11961)
  ...
2024-11-12 10:08:48 -08:00
5cc2c0f45f Merge branch 'main' into dev
* main:
  ci: fix dockerfile warning (#11956)
2024-11-07 12:58:15 -08:00
32442766f4 Merge branch 'main' into dev
* main:
  website/docs: fix slug matching redirect URI causing broken refresh (#11950)
  website/integrations: jellyfin: update plugin catalog location (#11948)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#11942)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#11946)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#11947)
  website/docs: clarify traefik ingress setup (#11938)
  core: bump importlib-metadata from 8.4.0 to 8.5.0 (#11934)
  web: bump API Client version (#11930)
  root: backport version bump `2024.10.1` (#11929)
  website/docs: `2024.10.1` Release Notes (#11926)
  website: bump path-to-regexp from 1.8.0 to 1.9.0 in /website (#11924)
  core: bump sentry-sdk from 2.17.0 to 2.18.0 (#11918)
  website: bump the docusaurus group in /website with 9 updates (#11917)
  core: bump goauthentik.io/api/v3 from 3.2024100.1 to 3.2024100.2 (#11915)
  core, web: update translations (#11914)
2024-11-07 08:08:46 -08:00
75790909a8 Merge branch 'main' into dev
* main:
  web: bump API Client version (#11909)
  enterprise/rac: fix API Schema for invalidation_flow (#11907)
2024-11-04 13:20:15 -08:00
e0d5df89ca Merge branch 'main' into dev
* main:
  core: add `None` check to a device's `extra_description` (#11904)
  providers/oauth2: fix size limited index for tokens (#11879)
  web: fix missing status code on failed build (#11903)
  website: bump docusaurus-theme-openapi-docs from 4.1.0 to 4.2.0 in /website (#11897)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#11891)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#11884)
  translate: Updates for file web/xliff/en.xlf in tr (#11878)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in tr (#11866)
  core: bump google-api-python-client from 2.149.0 to 2.151.0 (#11885)
  core: bump selenium from 4.26.0 to 4.26.1 (#11886)
  core, web: update translations (#11896)
  website: bump docusaurus-plugin-openapi-docs from 4.1.0 to 4.2.0 in /website (#11898)
  core: bump watchdog from 5.0.3 to 6.0.0 (#11899)
  core: bump ruff from 0.7.1 to 0.7.2 (#11900)
  core: bump django-pglock from 1.6.2 to 1.7.0 (#11901)
  website/docs: fix release notes to say Federation (#11889)
2024-11-04 10:25:52 -08:00
f25a9c624e Merge branch 'main' into dev
* main:
  website: bump elliptic from 6.5.7 to 6.6.0 in /website (#11869)
  core: bump selenium from 4.25.0 to 4.26.0 (#11875)
  core: bump goauthentik.io/api/v3 from 3.2024083.14 to 3.2024100.1 (#11876)
  website/docs: add info about invalidation flow, default flows in general (#11800)
  website: fix docs redirect (#11873)
  website: remove RC disclaimer for version 2024.10 (#11871)
  website: update supported versions (#11841)
  web: bump API Client version (#11870)
  root: backport version bump 2024.10.0 (#11868)
  website/docs: 2024.8.4 release notes (#11862)
  web/admin: provide default invalidation flows for LDAP and Radius (#11861)
2024-11-04 10:25:45 -08:00
914993a788 Merge branch 'main' into dev
* main: (43 commits)
  core, web: update translations (#11858)
  web/admin: fix code-based MFA toggle not working in wizard (#11854)
  sources/kerberos: add kiprop to ignored system principals (#11852)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#11846)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it (#11845)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#11847)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#11848)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#11849)
  translate: Updates for file web/xliff/en.xlf in it (#11850)
  website: 2024.10 Release Notes (#11839)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#11814)
  core, web: update translations (#11821)
  core: bump goauthentik.io/api/v3 from 3.2024083.13 to 3.2024083.14 (#11830)
  core: bump service-identity from 24.1.0 to 24.2.0 (#11831)
  core: bump twilio from 9.3.5 to 9.3.6 (#11832)
  core: bump pytest-randomly from 3.15.0 to 3.16.0 (#11833)
  website/docs: Update social-logins github (#11822)
  website/docs: remove � (#11823)
  lifecycle: fix kdc5-config missing (#11826)
  website/docs: update preview status of different features (#11817)
  ...
2024-10-30 10:04:59 -07:00
89dad07a66 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.
2024-10-23 14:17:30 -07:00
15 changed files with 310 additions and 278 deletions

View File

@ -1,6 +1,5 @@
import { AkControlElement } from "@goauthentik/elements/AkControlElement.js";
import { debounce } from "@goauthentik/elements/utils/debounce";
import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter";
import { msg } from "@lit/localize";
import { PropertyValues, html } from "lit";
@ -12,6 +11,11 @@ import type { Pagination } from "@goauthentik/api";
import "./ak-dual-select";
import { AkDualSelect } from "./ak-dual-select";
import {
DualSelectChangeEvent,
DualSelectPaginatorNavEvent,
DualSelectSearchEvent,
} from "./events";
import type { DataProvider, DualSelectPair } from "./types";
/**
@ -26,7 +30,7 @@ import type { DataProvider, DualSelectPair } from "./types";
*/
@customElement("ak-dual-select-provider")
export class AkDualSelectProvider extends CustomListenerElement(AkControlElement) {
export class AkDualSelectProvider extends AkControlElement {
/** A function that takes a page and returns the DualSelectPair[] collection with which to update
* the "Available" pane.
*
@ -86,9 +90,9 @@ export class AkDualSelectProvider extends CustomListenerElement(AkControlElement
this.onNav = this.onNav.bind(this);
this.onChange = this.onChange.bind(this);
this.onSearch = this.onSearch.bind(this);
this.addCustomListener("ak-pagination-nav-to", this.onNav);
this.addCustomListener("ak-dual-select-change", this.onChange);
this.addCustomListener("ak-dual-select-search", this.onSearch);
this.addEventListener(DualSelectPaginatorNavEvent.eventName, this.onNav);
this.addEventListener(DualSelectSearchEvent.eventName, this.onSearch);
this.addEventListener(DualSelectChangeEvent.eventName, this.onChange);
}
willUpdate(changedProperties: PropertyValues<this>) {
@ -122,26 +126,16 @@ export class AkDualSelectProvider extends CustomListenerElement(AkControlElement
this.isLoading = false;
}
onNav(event: Event) {
if (!(event instanceof CustomEvent)) {
throw new Error(`Expecting a CustomEvent for navigation, received ${event} instead`);
}
this.fetch(event.detail);
onNav(event: DualSelectPaginatorNavEvent) {
this.fetch(event.page);
}
onChange(event: Event) {
if (!(event instanceof CustomEvent)) {
throw new Error(`Expecting a CustomEvent for change, received ${event} instead`);
}
this.internalSelected = event.detail.value;
this.selected = this.internalSelected;
onChange(event: DualSelectChangeEvent) {
this.selected = this.internalSelected = event.selected;
}
onSearch(event: Event) {
if (!(event instanceof CustomEvent)) {
throw new Error(`Expecting a CustomEvent for change, received ${event} instead`);
}
this.doSearch(event.detail);
onSearch(event: DualSelectSearchEvent) {
this.doSearch(event.search);
}
doSearch(search: string) {

View File

@ -1,8 +1,5 @@
import { AKElement } from "@goauthentik/elements/Base";
import {
CustomEmitterElement,
CustomListenerElement,
} from "@goauthentik/elements/utils/eventEmitter";
import { match } from "ts-pattern";
import { msg, str } from "@lit/localize";
import { PropertyValues, html, nothing } from "lit";
@ -23,15 +20,13 @@ import { AkDualSelectSelectedPane } from "./components/ak-dual-select-selected-p
import "./components/ak-pagination";
import "./components/ak-search-bar";
import {
EVENT_ADD_ALL,
EVENT_ADD_ONE,
EVENT_ADD_SELECTED,
EVENT_DELETE_ALL,
EVENT_REMOVE_ALL,
EVENT_REMOVE_ONE,
EVENT_REMOVE_SELECTED,
} from "./constants";
import type { BasePagination, DualSelectPair, SearchbarEvent } from "./types";
DualSelectChangeEvent,
DualSelectMoveRequestEvent,
DualSelectPanelSearchEvent,
DualSelectSearchEvent,
DualSelectUpdateEvent,
} from "./events";
import type { BasePagination, DualSelectPair } from "./types";
function alphaSort([_k1, v1, s1]: DualSelectPair, [_k2, v2, s2]: DualSelectPair) {
const [l, r] = [s1 !== undefined ? s1 : v1, s2 !== undefined ? s2 : v2];
@ -60,7 +55,7 @@ const keyfinder =
k === key;
@customElement("ak-dual-select")
export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKElement)) {
export class AkDualSelect extends AKElement {
static get styles() {
return styles;
}
@ -96,21 +91,9 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
super();
this.handleMove = this.handleMove.bind(this);
this.handleSearch = this.handleSearch.bind(this);
[
EVENT_ADD_ALL,
EVENT_ADD_SELECTED,
EVENT_DELETE_ALL,
EVENT_REMOVE_ALL,
EVENT_REMOVE_SELECTED,
EVENT_ADD_ONE,
EVENT_REMOVE_ONE,
].forEach((eventName: string) => {
this.addCustomListener(eventName, (event: Event) => this.handleMove(eventName, event));
});
this.addCustomListener("ak-dual-select-move", () => {
this.requestUpdate();
});
this.addCustomListener("ak-search", this.handleSearch);
this.addEventListener(DualSelectMoveRequestEvent.eventName, this.handleMove);
this.addEventListener(DualSelectUpdateEvent.eventName, () => this.requestUpdate());
this.addEventListener(DualSelectPanelSearchEvent.eventName, this.handleSearch);
}
willUpdate(changedProperties: PropertyValues<this>) {
@ -123,47 +106,17 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
}
}
handleMove(eventName: string, event: Event) {
if (!(event instanceof CustomEvent)) {
throw new Error(`Expected move event here, got ${eventName}`);
}
switch (eventName) {
case EVENT_ADD_SELECTED: {
this.addSelected();
break;
}
case EVENT_REMOVE_SELECTED: {
this.removeSelected();
break;
}
case EVENT_ADD_ALL: {
this.addAllVisible();
break;
}
case EVENT_REMOVE_ALL: {
this.removeAllVisible();
break;
}
case EVENT_DELETE_ALL: {
this.removeAll();
break;
}
case EVENT_ADD_ONE: {
this.addOne(event.detail);
break;
}
case EVENT_REMOVE_ONE: {
this.removeOne(event.detail);
break;
}
default:
throw new Error(
`AkDualSelect.handleMove received unknown event type: ${eventName}`,
);
}
this.dispatchCustomEvent("ak-dual-select-change", { value: this.value });
handleMove(event: DualSelectMoveRequestEvent) {
match(event.move)
.with("add-all", () => this.addAllVisible())
.with("add-one", () => this.addOne(event.key))
.with("add-selected", () => this.addSelected())
.with("delete-all", () => this.removeAll())
.with("remove-all", () => this.removeAllVisible())
.with("remove-one", () => this.removeOne(event.key))
.with("remove-selected", () => this.removeSelected())
.exhaustive();
this.dispatchEvent(new DualSelectChangeEvent(this.value));
event.stopPropagation();
}
@ -182,7 +135,10 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
this.availablePane.value!.clearMove();
}
addOne(key: string) {
addOne(key?: string) {
if (!key) {
return;
}
const requested = this.options.find(keyfinder(key));
if (requested && !this.selected.find(keyfinder(requested[0]))) {
this.selected = [...this.selected, requested];
@ -207,7 +163,10 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
this.selectedPane.value!.clearMove();
}
removeOne(key: string) {
removeOne(key?: string) {
if (!key) {
return;
}
this.selected = this.selected.filter(([k]) => k !== key);
}
@ -223,18 +182,18 @@ export class AkDualSelect extends CustomEmitterElement(CustomListenerElement(AKE
this.selectedPane.value!.clearMove();
}
handleSearch(event: SearchbarEvent) {
switch (event.detail.source) {
handleSearch(event: DualSelectPanelSearchEvent) {
switch (event.source) {
case "ak-dual-list-available-search":
return this.handleAvailableSearch(event.detail.value);
return this.handleAvailableSearch(event.filterOn);
case "ak-dual-list-selected-search":
return this.handleSelectedSearch(event.detail.value);
return this.handleSelectedSearch(event.filterOn);
}
event.stopPropagation();
}
handleAvailableSearch(value: string) {
this.dispatchCustomEvent("ak-dual-select-search", value);
this.dispatchEvent(new DualSelectSearchEvent(value));
}
handleSelectedSearch(value: string) {

View File

@ -1,26 +1,19 @@
import { AKElement } from "@goauthentik/elements/Base";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { bound } from "@goauthentik/elements/decorators/bound";
import { html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { customElement, property } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { map } from "lit/directives/map.js";
import { availablePaneStyles, listStyles } from "./styles.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFDualListSelector from "@patternfly/patternfly/components/DualListSelector/dual-list-selector.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { availablePaneStyles } from "./styles.css";
import { EVENT_ADD_ONE } from "../constants";
import {
DualSelectMoveAvailableEvent,
DualSelectMoveRequestEvent,
DualSelectUpdateEvent,
} from "../events";
import type { DualSelectPair } from "../types";
const styles = [PFBase, PFButton, PFDualListSelector, listStyles, availablePaneStyles];
const hostAttributes = [
["aria-labelledby", "dual-list-selector-available-pane-status"],
["aria-multiselectable", "true"],
["role", "listbox"],
];
import { AkDualSelectAbstractPane } from "./ak-dual-select-pane";
/**
* @element ak-dual-select-available-panel
@ -40,9 +33,9 @@ const hostAttributes = [
*
*/
@customElement("ak-dual-select-available-pane")
export class AkDualSelectAvailablePane extends CustomEmitterElement(AKElement) {
export class AkDualSelectAvailablePane extends AkDualSelectAbstractPane {
static get styles() {
return styles;
return [...AkDualSelectAbstractPane.styles, availablePaneStyles];
}
/* The array of key/value pairs this pane is currently showing */
@ -56,68 +49,31 @@ export class AkDualSelectAvailablePane extends CustomEmitterElement(AKElement) {
@property({ type: Object })
readonly selected: Set<string> = new Set();
/* This is the only mutator for this object. It collects the list of objects the user has
* clicked on *in this pane*. It is explicitly marked as "public" to emphasize that the parent
* orchestrator for the dual-select widget can and will access it to get the list of keys to be
* moved (removed) if the user so requests.
*
*/
@state()
public toMove: Set<string> = new Set();
constructor() {
super();
this.onClick = this.onClick.bind(this);
this.onMove = this.onMove.bind(this);
}
connectedCallback() {
super.connectedCallback();
hostAttributes.forEach(([attr, value]) => {
if (!this.hasAttribute(attr)) {
this.setAttribute(attr, value);
}
});
}
clearMove() {
this.toMove = new Set();
}
@bound
onClick(key: string) {
if (this.selected.has(key)) {
return;
}
if (this.toMove.has(key)) {
this.toMove.delete(key);
} else {
this.toMove.add(key);
}
this.dispatchCustomEvent(
"ak-dual-select-available-move-changed",
Array.from(this.toMove.values()).sort(),
);
this.dispatchCustomEvent("ak-dual-select-move");
this.move(key);
this.dispatchEvent(new DualSelectMoveAvailableEvent(this.moveable.sort()));
this.dispatchEvent(new DualSelectUpdateEvent());
// Necessary because updating a map won't trigger a state change
this.requestUpdate();
}
@bound
onMove(key: string) {
this.toMove.delete(key);
this.dispatchCustomEvent(EVENT_ADD_ONE, key);
this.dispatchEvent(new DualSelectMoveRequestEvent("add-one", key));
this.requestUpdate();
}
get moveable() {
return Array.from(this.toMove.values());
}
// DO NOT use `Array.map()` instead of Lit's `map()` function. Lit's `map()` is object-aware and
// will not re-arrange or reconstruct the list automatically if the actual sources do not
// change; this allows the available pane to illustrate selected items with the checkmark
// without causing the list to scroll back up to the top.
render() {
override render() {
return html`
<div class="pf-c-dual-list-selector__menu">
<ul class="pf-c-dual-list-selector__list">

View File

@ -1,5 +1,4 @@
import { AKElement } from "@goauthentik/elements/Base";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { msg } from "@lit/localize";
import { css, html, nothing } from "lit";
@ -8,13 +7,7 @@ import { customElement, property } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import {
EVENT_ADD_ALL,
EVENT_ADD_SELECTED,
EVENT_DELETE_ALL,
EVENT_REMOVE_ALL,
EVENT_REMOVE_SELECTED,
} from "../constants";
import { DualSelectMoveRequestEvent, type MoveEventType } from "../events";
const styles = [
PFBase,
@ -47,7 +40,7 @@ const styles = [
*/
@customElement("ak-dual-select-controls")
export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
export class AkDualSelectControls extends AKElement {
static get styles() {
return styles;
}
@ -96,11 +89,11 @@ export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
this.onClick = this.onClick.bind(this);
}
onClick(eventName: string) {
this.dispatchCustomEvent(eventName);
onClick(eventName: MoveEventType) {
this.dispatchEvent(new DualSelectMoveRequestEvent(eventName));
}
renderButton(label: string, event: string, active: boolean, direction: string) {
renderButton(label: string, event: MoveEventType, active: boolean, direction: string) {
return html`
<div class="pf-c-dual-list-selector__controls-item">
<button
@ -121,23 +114,18 @@ export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
render() {
return html`
<div class="ak-dual-list-selector__controls">
${this.renderButton(
msg("Add"),
EVENT_ADD_SELECTED,
this.addActive,
"fa-angle-right",
)}
${this.renderButton(msg("Add"), "add-selected", this.addActive, "fa-angle-right")}
${this.selectAll
? html`
${this.renderButton(
msg("Add All Available"),
EVENT_ADD_ALL,
"add-all",
this.addAllActive,
"fa-angle-double-right",
)}
${this.renderButton(
msg("Remove All Available"),
EVENT_REMOVE_ALL,
"remove-all",
this.removeAllActive,
"fa-angle-double-left",
)}
@ -145,14 +133,14 @@ export class AkDualSelectControls extends CustomEmitterElement(AKElement) {
: nothing}
${this.renderButton(
msg("Remove"),
EVENT_REMOVE_SELECTED,
"remove-selected",
this.removeActive,
"fa-angle-left",
)}
${this.deleteAll
? html`${this.renderButton(
msg("Remove All"),
EVENT_DELETE_ALL,
"delete-all",
this.enableDeleteAll,
"fa-times",
)}`

View File

@ -0,0 +1,75 @@
import { AKElement } from "@goauthentik/elements/Base";
import { TemplateResult } from "lit";
import { state } from "lit/decorators.js";
import { listStyles } from "./styles.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFDualListSelector from "@patternfly/patternfly/components/DualListSelector/dual-list-selector.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
const styles = [PFBase, PFButton, PFDualListSelector, listStyles];
const hostAttributes = [
["aria-labelledby", "dual-list-selector-selected-pane-status"],
["aria-multiselectable", "true"],
["role", "listbox"],
];
/**
* @element ak-dual-select-panel
*
* The "selected options" or "right" pane in a dual-list multi-select. It receives from its parent
* a list of the selected options, and maintains an internal list of objects selected to move.
*
* @fires ak-dual-select-selected-move-changed - When the list of "to move" entries changed.
* Includes the current `toMove` content.
*
* @fires ak-dual-select-remove-one - Double-click with the element clicked on.
*
* It is not expected that the `ak-dual-select-selected-move-changed` will be used; instead, the
* attribute will be read by the parent when a control is clicked.
*
*/
export abstract class AkDualSelectAbstractPane extends AKElement {
static get styles() {
return styles;
}
/*
* This is the only mutator for this object. It collects the list of objects the user has
* clicked on *in this pane*. It is explicitly marked as "public" to emphasize that the parent
* orchestrator for the dual-select widget can and will access it to get the list of keys to be
* moved (removed) if the user so requests.
*
*/
@state()
public toMove: Set<string> = new Set();
connectedCallback() {
super.connectedCallback();
hostAttributes.forEach(([attr, value]) => {
if (!this.hasAttribute(attr)) {
this.setAttribute(attr, value);
}
});
}
clearMove() {
this.toMove = new Set();
}
move(key: string) {
if (this.toMove.has(key)) {
this.toMove.delete(key);
} else {
this.toMove.add(key);
}
}
get moveable() {
return Array.from(this.toMove.values());
}
abstract render(): TemplateResult;
}

View File

@ -1,26 +1,19 @@
import { AKElement } from "@goauthentik/elements/Base";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { bound } from "@goauthentik/elements/decorators/bound";
import { html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { customElement, property } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { map } from "lit/directives/map.js";
import { listStyles, selectedPaneStyles } from "./styles.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFDualListSelector from "@patternfly/patternfly/components/DualListSelector/dual-list-selector.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { selectedPaneStyles } from "./styles.css";
import { EVENT_REMOVE_ONE } from "../constants";
import {
DualSelectMoveRequestEvent,
DualSelectMoveSelectedEvent,
DualSelectUpdateEvent,
} from "../events";
import type { DualSelectPair } from "../types";
const styles = [PFBase, PFButton, PFDualListSelector, listStyles, selectedPaneStyles];
const hostAttributes = [
["aria-labelledby", "dual-list-selector-selected-pane-status"],
["aria-multiselectable", "true"],
["role", "listbox"],
];
import { AkDualSelectAbstractPane } from "./ak-dual-select-pane";
/**
* @element ak-dual-select-available-panel
@ -38,70 +31,32 @@ const hostAttributes = [
*
*/
@customElement("ak-dual-select-selected-pane")
export class AkDualSelectSelectedPane extends CustomEmitterElement(AKElement) {
export class AkDualSelectSelectedPane extends AkDualSelectAbstractPane {
static get styles() {
return styles;
return [...AkDualSelectAbstractPane.styles, selectedPaneStyles];
}
/* The array of key/value pairs that are in the selected list. ALL of them. */
@property({ type: Array })
readonly selected: DualSelectPair[] = [];
/*
* This is the only mutator for this object. It collects the list of objects the user has
* clicked on *in this pane*. It is explicitly marked as "public" to emphasize that the parent
* orchestrator for the dual-select widget can and will access it to get the list of keys to be
* moved (removed) if the user so requests.
*
*/
@state()
public toMove: Set<string> = new Set();
constructor() {
super();
this.onClick = this.onClick.bind(this);
this.onMove = this.onMove.bind(this);
}
connectedCallback() {
super.connectedCallback();
hostAttributes.forEach(([attr, value]) => {
if (!this.hasAttribute(attr)) {
this.setAttribute(attr, value);
}
});
}
clearMove() {
this.toMove = new Set();
}
@bound
onClick(key: string) {
if (this.toMove.has(key)) {
this.toMove.delete(key);
} else {
this.toMove.add(key);
}
this.dispatchCustomEvent(
"ak-dual-select-selected-move-changed",
Array.from(this.toMove.values()).sort(),
);
this.dispatchCustomEvent("ak-dual-select-move");
this.move(key);
this.dispatchEvent(new DualSelectMoveSelectedEvent(this.moveable.sort()));
this.dispatchEvent(new DualSelectUpdateEvent());
// Necessary because updating a map won't trigger a state change
this.requestUpdate();
}
@bound
onMove(key: string) {
this.toMove.delete(key);
this.dispatchCustomEvent(EVENT_REMOVE_ONE, key);
this.dispatchEvent(new DualSelectMoveRequestEvent("remove-one", key));
this.requestUpdate();
}
get moveable() {
return Array.from(this.toMove.values());
}
render() {
override render() {
return html`
<div class="pf-c-dual-list-selector__menu">
<ul class="pf-c-dual-list-selector__list">

View File

@ -1,5 +1,4 @@
import { AKElement } from "@goauthentik/elements/Base";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { msg, str } from "@lit/localize";
import { css, html, nothing } from "lit";
@ -9,6 +8,7 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFPagination from "@patternfly/patternfly/components/Pagination/pagination.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { DualSelectPaginatorNavEvent } from "../events";
import type { BasePagination } from "../types";
const styles = [
@ -27,7 +27,7 @@ const styles = [
];
@customElement("ak-pagination")
export class AkPagination extends CustomEmitterElement(AKElement) {
export class AkPagination extends AKElement {
static get styles() {
return styles;
}
@ -41,7 +41,7 @@ export class AkPagination extends CustomEmitterElement(AKElement) {
}
onClick(nav: number | undefined) {
this.dispatchCustomEvent("ak-pagination-nav-to", nav ?? 0);
this.dispatchEvent(new DualSelectPaginatorNavEvent(nav ?? 0));
}
render() {

View File

@ -1,5 +1,4 @@
import { AKElement } from "@goauthentik/elements/Base";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { html } from "lit";
import { customElement, property } from "lit/decorators.js";
@ -9,12 +8,12 @@ import type { Ref } from "lit/directives/ref.js";
import { globalVariables, searchStyles } from "./search.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import type { SearchbarEvent } from "../types";
import { DualSelectPanelSearchEvent } from "../events";
const styles = [PFBase, globalVariables, searchStyles];
@customElement("ak-search-bar")
export class AkSearchbar extends CustomEmitterElement(AKElement) {
export class AkSearchbar extends AKElement {
static get styles() {
return styles;
}
@ -40,10 +39,7 @@ export class AkSearchbar extends CustomEmitterElement(AKElement) {
if (this.input.value) {
this.value = this.input.value.value;
}
this.dispatchCustomEvent<SearchbarEvent>("ak-search", {
source: this.name,
value: this.value,
});
this.dispatchEvent(new DualSelectPanelSearchEvent(this.name, this.value));
}
render() {

View File

@ -0,0 +1,112 @@
import { DualSelectPair } from "./types";
// Handled by the Server layer provider
// Request to provide a different page of the paginated results in the "available" panel.
export class DualSelectPaginatorNavEvent extends Event {
static readonly eventName = "ak-dual-select-paginator-nav";
constructor(public page: number = 0) {
super(DualSelectPaginatorNavEvent.eventName, { bubbles: true, composed: true });
}
}
// Request to provide a filtered collection for the "available" panel via a search string
export class DualSelectSearchEvent extends Event {
static readonly eventName = "ak-dual-select-search";
constructor(public search: string) {
super(DualSelectSearchEvent.eventName, { bubbles: true, composed: true });
}
}
// Request to update the "selected" list in the provider
export class DualSelectChangeEvent extends Event {
static readonly eventName = "ak-dual-select-change";
constructor(public selected: DualSelectPair[]) {
super(DualSelectChangeEvent.eventName, { bubbles: true, composed: true });
}
}
// Paginator and specific item events
export const moveEvents = [
"add-all",
"add-one",
"add-selected",
"delete-all",
"remove-all",
"remove-one",
"remove-selected",
] as const;
export type MoveEventType = (typeof moveEvents)[number];
// Request to add or remove all, some, or just one item from the "selected" panel
export class DualSelectMoveRequestEvent extends Event {
static readonly eventName = "ak-dual-select-request-move";
constructor(
public move: MoveEventType,
public key?: string,
) {
super(DualSelectMoveRequestEvent.eventName, { bubbles: true, composed: true });
}
}
// Update events
// Request to update the viewset
export class DualSelectUpdateEvent extends Event {
static readonly eventName = "ak-dual-select-update";
constructor() {
super(DualSelectUpdateEvent.eventName, { bubbles: true, composed: true });
}
}
interface DualSelectMoveChangedEvent {
keys: string[];
}
// Request to update the list of "marked for move" items in the "available" panel
export class DualSelectMoveAvailableEvent extends Event implements DualSelectMoveChangedEvent {
static readonly eventName = "ak-dual-select-move-available";
constructor(public keys: string[]) {
super(DualSelectMoveAvailableEvent.eventName, { bubbles: true, composed: true });
}
}
// Request to update the list of "marked for move" items in the "selected" panel
export class DualSelectMoveSelectedEvent extends Event implements DualSelectMoveChangedEvent {
static readonly eventName = "ak-dual-select-move-selected";
constructor(public keys: string[]) {
super(DualSelectMoveSelectedEvent.eventName, { bubbles: true, composed: true });
}
}
// Request to update either panel with a Filter
export class DualSelectPanelSearchEvent extends Event {
static readonly eventName = "ak-dual-select-panel-search";
constructor(
public source: string,
public filterOn: string,
) {
super(DualSelectPanelSearchEvent.eventName, { bubbles: true, composed: true });
}
}
declare global {
interface HTMLElementEventMap {
[DualSelectUpdateEvent.eventName]: DualSelectUpdateEvent;
[DualSelectMoveAvailableEvent.eventName]: DualSelectMoveAvailableEvent;
[DualSelectMoveSelectedEvent.eventName]: DualSelectMoveSelectedEvent;
[DualSelectMoveRequestEvent.eventName]: DualSelectMoveRequestEvent;
[DualSelectPaginatorNavEvent.eventName]: DualSelectPaginatorNavEvent;
[DualSelectSearchEvent.eventName]: DualSelectSearchEvent;
[DualSelectChangeEvent.eventName]: DualSelectChangeEvent;
[DualSelectPanelSearchEvent.eventName]: DualSelectPanelSearchEvent;
}
interface WindowEventMap {
[DualSelectMoveRequestEvent.eventName]: DualSelectMoveRequestEvent;
[DualSelectPaginatorNavEvent.eventName]: DualSelectPaginatorNavEvent;
[DualSelectMoveSelectedEvent.eventName]: DualSelectMoveSelectedEvent;
}
}

View File

@ -6,6 +6,7 @@ import { TemplateResult, html } from "lit";
import "../components/ak-dual-select-available-pane";
import { AkDualSelectAvailablePane } from "../components/ak-dual-select-available-pane";
import { DualSelectMoveSelectedEvent } from "../events";
import "./sb-host-provider";
const metadata: Meta<AkDualSelectAvailablePane> = {
@ -53,15 +54,15 @@ const container = (testItem: TemplateResult) =>
</div>`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const handleMoveChanged = (result: any) => {
const handleMoveChanged = (result: DualSelectMoveSelectedEvent) => {
const target = document.querySelector("#action-button-message-pad");
target!.innerHTML = "";
result.detail.forEach((key: string) => {
result.keys.forEach((key: string) => {
target!.append(new DOMParser().parseFromString(`<li>${key}</li>`, "text/xml").firstChild!);
});
};
window.addEventListener("ak-dual-select-available-move-changed", handleMoveChanged);
window.addEventListener(DualSelectMoveSelectedEvent.eventName, handleMoveChanged);
type Story = StoryObj;

View File

@ -5,6 +5,7 @@ import { TemplateResult, html } from "lit";
import "../components/ak-dual-select-controls";
import { AkDualSelectControls } from "../components/ak-dual-select-controls";
import { DualSelectMoveRequestEvent } from "../events";
const metadata: Meta<AkDualSelectControls> = {
title: "Elements / Dual Select / Control Panel",
@ -59,10 +60,9 @@ const displayMessage = (result: any) => {
target!.appendChild(doc.firstChild!);
};
window.addEventListener("ak-dual-select-add", () => displayMessage("add"));
window.addEventListener("ak-dual-select-remove", () => displayMessage("remove"));
window.addEventListener("ak-dual-select-add-all", () => displayMessage("add all"));
window.addEventListener("ak-dual-select-remove-all", () => displayMessage("remove all"));
window.addEventListener(DualSelectMoveRequestEvent.eventName, (ev: DualSelectMoveRequestEvent) =>
displayMessage(ev.move.toString()),
);
type Story = StoryObj;

View File

@ -9,6 +9,7 @@ import { Pagination } from "@goauthentik/api";
import "../ak-dual-select";
import { AkDualSelect } from "../ak-dual-select";
import { DualSelectPaginatorNavEvent } from "../events";
import type { DualSelectPair } from "../types";
const goodForYouRaw = `
@ -83,11 +84,11 @@ export class AkSbFruity extends LitElement {
totalPages: Math.ceil(this.options.length / this.pageLength),
};
this.onNavigation = this.onNavigation.bind(this);
this.addEventListener("ak-pagination-nav-to", this.onNavigation);
this.addEventListener(DualSelectPaginatorNavEvent.eventName, this.onNavigation);
}
onNavigation(evt: Event) {
const current: number = (evt as CustomEvent).detail;
onNavigation(evt: DualSelectPaginatorNavEvent) {
const current = evt.page;
const index = current - 1;
if (index * this.pageLength > this.options.length) {
console.warn(

View File

@ -6,6 +6,7 @@ import { TemplateResult, html } from "lit";
import "../components/ak-dual-select-selected-pane";
import { AkDualSelectSelectedPane } from "../components/ak-dual-select-selected-pane";
import { DualSelectMoveSelectedEvent } from "../events";
import "./sb-host-provider";
const metadata: Meta<AkDualSelectSelectedPane> = {
@ -50,15 +51,15 @@ const container = (testItem: TemplateResult) =>
</div>`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const handleMoveChanged = (result: any) => {
const handleMoveChanged = (result: DualSelectMoveSelectedEvent) => {
const target = document.querySelector("#action-button-message-pad");
target!.innerHTML = "";
result.detail.forEach((key: string) => {
result.keys.forEach((key: string) => {
target!.append(new DOMParser().parseFromString(`<li>${key}</li>`, "text/xml").firstChild!);
});
};
window.addEventListener("ak-dual-select-selected-move-changed", handleMoveChanged);
window.addEventListener(DualSelectMoveSelectedEvent.eventName, handleMoveChanged);
type Story = StoryObj;

View File

@ -5,6 +5,7 @@ import { TemplateResult, html } from "lit";
import "../components/ak-pagination";
import { AkPagination } from "../components/ak-pagination";
import { DualSelectPaginatorNavEvent } from "../events";
const metadata: Meta<AkPagination> = {
title: "Elements / Dual Select / Pagination Control",
@ -43,18 +44,18 @@ const container = (testItem: TemplateResult) =>
</div>`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const handleMoveChanged = (result: any) => {
const handleMoveChanged = (result: DualSelectPaginatorNavEvent) => {
console.debug(result);
const target = document.querySelector("#action-button-message-pad");
target!.append(
new DOMParser().parseFromString(
`<li>Request to move to page ${result.detail}</li>`,
`<li>Request to move to page ${result.page}</li>`,
"text/xml",
).firstChild!,
);
};
window.addEventListener("ak-pagination-nav-to", handleMoveChanged);
window.addEventListener(DualSelectPaginatorNavEvent.eventName, handleMoveChanged);
type Story = StoryObj;

View File

@ -29,10 +29,3 @@ export type DataProvision = {
};
export type DataProvider = (page: number, search?: string) => Promise<DataProvision>;
export interface SearchbarEvent extends CustomEvent {
detail: {
source: string;
value: string;
};
}