Repository navigation
added optional storage type for the declarative ui #47859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
edewit
wants to merge
26
commits into
keycloak:main
Choose a base branch
from
edewit:storage-type-declarative-ui
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
7483156
added optional storage type for the declarative ui
edewit a28c916
pr review comments
edewit 8c7f74b
PR review comments
edewit f6ca1fd
removed group as it's impossible to add custom tab on the group section
edewit b8165f5
split off custom and add dependencies
edewit 08a4267
remove group again
edewit 43606da
Address declarative UI storage review feedback
edewit b752853
Handle cleared fields and IdentityProviderMultiList storage
edewit 8a498f2
Fix TypeScript build for entity storage updates
edewit 69de334
Complete declarative UI extension phases 2-6
edewit 1062353
Address Copilot review feedback for declarative UI extensions
edewit 1fe31b9
Address second round of Copilot review feedback
edewit e5f85a8
Address third round of Copilot review feedback
edewit 68002b7
Add integration test for ComponentStorageFactory delegation
edewit 8c4001e
Fix Spotless import ordering violations
edewit 7b2f939
Address remaining Copilot review feedback for custom storage
edewit 6510d75
Fix component API auth ordering and custom storage edge cases
edewit 540b7c7
Fix stale component loading and tighten custom storage authorization
edewit b61b3ea
Fix duplicate components in type-wide custom storage queries
edewit 6d9179d
Deduplicate custom-storage components in admin component listing
edewit 2195d34
List custom-storage components without merging realm duplicates
edewit e5c6fbc
Exclude custom-storage provider IDs from realm component listing
edewit b361ea6
Stabilize custom-storage component listing integration test
edewit a51bf9b
Add missing cleanupUiPageComponents helper in storage test
edewit 7b9ba58
Reuse existing form utilities for declarative UI entity storage
edewit 708bda8
Map null component lookup to undefined in declarative UI Page
edewit File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| <#import "/templates/guide.adoc" as tmpl> | ||
| <#import "/templates/links.adoc" as links> | ||
|
|
||
| <@tmpl.guide | ||
| title="Extending the Admin Console declaratively" | ||
| priority=25 | ||
| summary="Add pages and tabs to the Admin Console with Java SPIs and automatic form rendering."> | ||
|
|
||
| The declarative UI SPI lets extension authors add Admin Console pages and tabs without writing React code. | ||
| Implement `UiPageProviderFactory` for new top-level pages or `UiTabProviderFactory` for tabs on existing routes. | ||
| The Admin Console renders forms from `ProviderConfigProperty` definitions returned by the provider factory. | ||
|
|
||
| == Enable the feature | ||
|
|
||
| The SPI is available as a preview feature: | ||
|
|
||
| [source,bash] | ||
| ---- | ||
| bin/kc.[sh|bat] start --features=declarative-ui | ||
| ---- | ||
|
|
||
| See link:{adminguide_link}#features[Enabling and disabling features] for other ways to enable preview features. | ||
|
|
||
| == Implement a page or tab | ||
|
8000
|
||
| . Create a JAR with a `META-INF/services/org.keycloak.services.ui.extend.UiPageProviderFactory` or | ||
| `META-INF/services/org.keycloak.services.ui.extend.UiTabProviderFactory` service file. | ||
| . Implement the factory and return configuration properties from `getConfigProperties()`. | ||
| . Deploy the provider JAR to the `providers` directory and restart {project_name}. | ||
|
|
||
| An example extension is available in the | ||
| https://github.com/keycloak/keycloak-quickstarts/tree/latest/extension/extend-admin-console-spi[keycloak-quickstarts repository]. | ||
|
|
||
| == Storage types for tabs | ||
|
|
||
| Tabs can store form data in different backends by overriding `getStorageType()`: | ||
|
|
||
| [cols="1,2", options="header"] | ||
| |=== | ||
| | Storage type | Description | ||
|
|
||
| | `COMPONENT` | ||
| | Default. Data is stored as a realm component through the components REST API. | ||
|
|
||
| | `CLIENT` | ||
| | Reads and writes `client.attributes` for the `clientId` in the current route. | ||
|
|
||
| | `USER` | ||
| | Reads and writes `user.attributes` for the `id` route parameter. | ||
|
|
||
| | `IDENTITY_PROVIDER` | ||
| | Reads and writes `identityProvider.config` for the `alias` route parameter. | ||
|
|
||
| | `CUSTOM` | ||
| | Uses a custom admin REST endpoint declared with `getEndpoint()`. | ||
| |=== | ||
|
|
||
| For `CUSTOM` storage, implement GET and PUT handlers relative to `/admin/realms/{realm}/`: | ||
|
|
||
| * `GET` returns JSON with a `config` object whose keys match property names. | ||
| * `PUT` receives submitted form data plus resolved route parameters as top-level fields. | ||
|
|
||
| Custom endpoints are served by a separate `AdminRealmResourceProvider` and are not protected by | ||
| `getRequiredViewRoles()` / `getRequiredManageRoles()`. Each handler must enforce admin permissions | ||
| explicitly, for example by using `AdminPermissionEvaluator` in the resource implementation. | ||
| The UI role metadata only controls Admin Console visibility; it is not a security boundary for | ||
| direct REST access. | ||
|
|
||
| == Runtime configuration | ||
|
|
||
| Static properties from server startup are still exposed through server info. | ||
| For context-aware fields (for example dropdowns populated from realm data), override: | ||
|
|
||
| [source,java] | ||
| ---- | ||
| List<ProviderConfigProperty> getConfigProperties(KeycloakSession session, Map<String, String> contextParams) | ||
| ---- | ||
|
|
||
| The Admin Console loads these properties at runtime from: | ||
|
|
||
| * `/admin/realms/{realm}/ui-extensions/tabs/{providerId}/config` | ||
| * `/admin/realms/{realm}/ui-extensions/pages/{providerId}/config` | ||
|
|
||
| Pass route parameters such as `clientId`, `id`, or `alias` as query parameters when opening a tab. | ||
|
|
||
| == Permissions and navigation | ||
|
|
||
| Override these methods to control access and placement: | ||
|
|
||
| * `getRequiredViewRoles()` and `getRequiredManageRoles()` — defaults to `view-realm` / `manage-realm` | ||
| * `getNavSection()` for pages — `manage`, `configure`, or `extensions` | ||
| * `getTabLabel()` for tabs — localized label key used instead of the provider id | ||
|
|
||
| Entity-backed tabs (`CLIENT`, `USER`, `IDENTITY_PROVIDER`) use the existing admin-client APIs, so fine-grained permissions for those resources apply automatically. | ||
|
|
||
| Component-backed pages and tabs can declare narrower roles in metadata. | ||
| When a factory also implements `ComponentStorageFactory`, component CRUD is delegated to the custom storage backend. | ||
|
|
||
| == Page detail tabs | ||
|
|
||
| Pages can expose additional declarative tabs on their detail view by overriding: | ||
|
|
||
| [source,java] | ||
| ---- | ||
| boolean supportsDetailTabs() | ||
| ---- | ||
|
|
||
| Child `UiTabProvider` entries whose path matches the page detail route are rendered automatically. | ||
|
|
||
| </@tmpl.guide> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.