You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Implement selecting specific organizations in FGAP permission - #51717
variant="typeahead" is used for single-resource evaluation/search, but this modal always renders checkboxes with Select All enabled. Users can choose several organizations and this branch stores every ID, so pass a radio/single-selection mode through to OrganizationModal as the other resource pickers do.
This required rule is not accompanied by any rendered form error, unlike GroupSelect.tsx:156. Submitting “Specific Organizations” without a selection is blocked with no explanation; render a FormErrorText for this field and add the corresponding message.
In permission evaluation this component is used with variant="typeahead", but the modal still renders checkboxes and “select all”; choosing multiple organizations stores all IDs while evaluation silently uses only the first. Pass the single-selection intent through to OrganizationModal and set its table to radio selection (as GroupSelect does for selectOne).
Permission evaluation requests the key selectOrganizations (PermissionsEvaluationTab.tsx:203), but only the singular key is defined, so the help text displays the raw key. Add the plural key while retaining this singular key for the modal title.
This required validator blocks submission when no organization is selected, but unlike GroupSelect and RoleSelect, this component never renders the form error. Selecting “Specific Organizations” and saving with an empty selection therefore fails without explaining why; render a FormErrorText for this field and add its message key.
This issue also appears on line 81 of the same file.
The reason will be displayed to describe this comment to others. Learn more.
Great stuff, @theohh0. Can you please check the following:
For specific organizations permissions, there is no validation message when clicking save without selection a organization
There is no message when the modal has no organizations in the list. IIRC, other similar components render a specific message when there are no results.
Great stuff, @theohh0. Can you please check the following:
For specific organizations permissions, there is no validation message when clicking save without selection a organization
There is no message when the modal has no organizations in the list. IIRC, other similar components render a specific message when there are no results.
Other than, LGTM.
In testing this I've noticed that the error message for the group select seems to be missing a translation key (it just says "requiredGroups"). Could fix this relatively easily but I assume would be more appropriate for a separate pull request.
The reason will be displayed to describe this comment to others. Learn more.
Nice work — the component follows GroupSelect closely and the round-trip of organization IDs matches what AdminPermissionsSchema expects on the server, so the core approach looks right.
+1 to @pedroigor's two points (missing validation message, missing empty state in the modal); the emptyOrganizations message key already exists, so the empty state should be a one-liner — and it fixes the user Organizations tab modal at the same time.
The main thing I'd like addressed before merge is a new crash path: the Organizations resource type is offered even in realms where organizations aren't enabled, and the new picker turns that from "nothing renders" into a full-page error boundary. Details inline, along with a couple of robustness/consistency items.
One more thing worth adding: test/permissions/main.ts already has pickGroup/removeGroup helpers and main.spec.ts covers the specificResources path for groups — an organizations equivalent should drop in with little effort and would cover the select/remove round-trip.
The fetch depends on values (and adminClient), but the dependency array is [], so it will only run once and won’t refresh the displayed organizations when the form value changes (e.g., after adding/removing). Consider using watch(name) from react-hook-form (instead of getValues) and include the watched value in the useFetch deps, or otherwise include a stable representation of values in the deps so the list stays in sync.
The fetch depends on values (and adminClient), but the dependency array is [], so it will only run once and won’t refresh the displayed organizations when the form value changes (e.g., after adding/removing). Consider using watch(name) from react-hook-form (instead of getValues) and include the watched value in the useFetch deps, or otherwise include a stable representation of values in the deps so the list stays in sync.
useFetch(
() => {
if (values.length > 0) {
return Promise.all(
(values as string[]).map((id) =>
adminClient.organizations.findOne({ id }),
),
);
}
return Promise.resolve([]);
},
(organizations) => {
setOrganizations(organizations as OrganizationRepresentation[]);
},
[],
);
This is an icon-only button without an accessible name. Add an aria-label (and optionally title) such as “Remove organization” so screen readers can announce the action.
<Button
variant="link"
className="keycloak__client-authorization__policy-row-remove"
icon={<MinusCircleIcon />}
=> {
setValue(name!, [
...convertOrganizations(
organizations.filter(
({ id }) => id !== organization.id,
),
),
]);
setOrganizations([
...organizations.filter(
({ id }) => id !== organization.id,
),
]);
}}
/>
For mode === "send", data-testid is still set to "join", which makes tests and intent ambiguous and can cause incorrect test targeting. Consider mapping each mode to its own stable test id (e.g., "send" for send mode) or using data-testid={mode} if that matches your test strategy.
When select-all is clicked from an indeterminate state, this appends rows that are already selected, so onSelect receives duplicate entries. In this modal that can submit the same organization twice; append only selectable rows not already present.
@theohh0 The build is failing now. Sorry this keeps dragging on but I swear we are getting close. See below:
The selectableRows fix looks right — keeping "disableSelection" in row inside the guard preserves the union narrowing, and UI Shared and Account UI are green again.
The build is still red, but it's now a different thing, and it's fallout from the merge with main rather than anything you changed:
These are the multi-IdP-for-organizations files that landed on main while this PR was open. They call organizations.findOne and dereference the result straight away, which was fine against the old non-nullable signature:
This is the breaking change we accepted showing up in practice — and behaving the way we expected it to: a compile error naming every affected line, rather than something silent. It's this PR's to fix, since the PR is what changes the signature.
Both are small. IdpDomainsTab.tsx is already inside a try/catch that returns [], so one early return covers all three errors:
DomainsTab.tsx is the same org.domains ?? [] shape in all three places (lines 65, 180, 191), so optional chaining is enough:
constdomains=org?.domains??[];
The other call sites are already fine and need nothing — IdpOrganizationsTab.tsx:53 handles the undefined case, DetailOrganization.tsx:67 already casts to | undefined and guards, and your OrganizationSelect.tsx:58 filters.
Worth flagging separately: this is good evidence for the release-note entry on the admin-client change. If code written in this repo last week needs updating, downstream consoles building on @keycloak/keycloak-admin-client will too.
The other call sites are already fine and need nothing — IdpOrganizationsTab.tsx:53 handles the undefined case, DetailOrganization.tsx:67 already casts to | undefined and guards, and your OrganizationSelect.tsx:58 filters.
@ssilvert I don't think IdpOrganizationsTab.tsx:53 in its current state does handle the undefined case correctly - it doesn't throw any errors as it doesnt try to access any properties of the undefined organization, but it will return {...org, ...link} which in practice is just {...link}, and this wont get filtered out on line 65 as thats still truthy,
10BC8
despite not being a correct OrgWithLink. I'll get this file updated as well as the others you suggested. (I think you're correct that DetailOrganization.tsx doesn't need a change tho).
* Handle undefined organization in findOne callers
organizations.findOne now returns OrganizationRepresentation | undefined
(catchNotFound), but the callers added on main in the multi-IdP work still
assumed it always returns an organization, which fails the type check.
Each caller now handles a missing organization the same way it did when
the 404 was thrown, so behaviour doesn't change.
Signed-off-by: Danny <117714228+UCNDanny@users.noreply.github.com>
* Undo change to DetailOrganization.tsx
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Use optional chaining for organization domains rather than throwing for undefined orgs
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
---------
Signed-off-by: Danny <117714228+UCNDanny@users.noreply.github.com>
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
Co-authored-by: theohh0 <theo.hinton-hallows@ibm.com>
useIsFeatureEnabled(Feature.Organizations) also requires manage-realm or query-organizations (useIsFeatureEnabled.ts:40-43). A delegated admin with manage-authorization can access this screen without either role, so this removes the entire Organizations resource type—including the all-organizations option—while Groups and other resource types remain available; use a feature-only check here and handle picker access separately.
Add an admin-client test asserting that findOne returns the not-found sentinel after an organization is deleted. This newly changes the public request behavior, while organizations.spec.ts currently exercises deletion only through find() and would not catch a regression in catchNotFound.
PR keycloak#51717 changed organizations.findOne to resolve to undefined for a
missing organization instead of rejecting with a 404, but merged without
an upgrading-guide entry. Opens the 26.9.0 changes file for it.
Fixeskeycloak#53371
Signed-off-by: Stan Silvert <ssilvert@redhat.com>
Assisted-by: Claude Opus 5.5
PadzerButch
pushed a commit
to PadzerButch/-50764_test_migration_keycloak
that referenced
this pull request
Oct 2, 2026
…ak#51717)
* Safely Adapted organization modal for use with fgap
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Create OrganizationSelect component
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Add organizations to resource types
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Added en translation keys
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* added orgs to permission eval
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Show error when no orgs selected
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* disable add/join button if no orgs selected
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* display error message when no organizations exist
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* filter out organization resource type if disabled
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Catch not found organizations
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* pass isRadio through to organization modal
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Clean up organization modal titles code
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* casing and placement
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Don't show empty orgs error when orgs loading.
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Disable existing orgs selected rather than removing them from modal
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Select all shouldnt select disabled rows in `KeycloakDataTable`
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* fix adminclient org typing and catch nulls
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* use translation keys for OrganizationModal.tsx titles
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Missing message keys
Signed-off-by: theohh0 <theo.hinton-h
10BC8
allows@ibm.com>
* Calculate orgsEnabled outside of memo
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Don't include subrows in select all
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* remove unnecessary properties from SubRow
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* disable select all if nothing selectable
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* don't need to pass existingOrgs length into loader params now that they aren't removed
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* added select/delete org permission test
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* enable organizations in test realm
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* reusable selectedRows var
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* hopefully more concrete org row selector
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* create policy with different name
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* just check for presence of data property - not truthiness
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* clean up perm tests once complete
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Safely Adapted organization modal for use with fgap
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Create OrganizationSelect component
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Add organizations to resource types
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Added en translation keys
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* added orgs to permission eval
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Show error when no orgs selected
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* disable add/join button if no orgs selected
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* display error message when no organizations exist
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* filter out organization resource type if disabled
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Catch not found organizations
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* pass isRadio through to organization modal
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Clean up organization modal titles code
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* casing and placement
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Don't show empty orgs error when orgs loading.
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Disable existing orgs selected rather than removing them from modal
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Select all shouldnt select disabled rows in `KeycloakDataTable`
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* fix adminclient org typing and catch nulls
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* use translation keys for OrganizationModal.tsx titles
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Missing message keys
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Calculate orgsEnabled outside of memo
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Don't include subrows in select all
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* remove unnecessary properties from SubRow
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* disable select all if nothing selectable
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* don't need to pass existingOrgs length into loader params now that they aren't removed
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* added select/delete org permission test
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* enable organizations in test realm
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* reusable selectedRows var
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* hopefully more concrete org row selector
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* create policy with different name
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* just check for presence of data property - not truthiness
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* clean up perm tests once complete
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Make sure delete completes
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* disable row selection only when var exists and true in KeycloakDataTable
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: theohh0 <theo.hintonhallows123@gmail.com>
* corrected copilots edit
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Handle undefined organization in findOne callers
* Handle undefined organization in findOne callers
organizations.findOne now returns OrganizationRepresentation | undefined
(catchNotFound), but the callers added on main in the multi-IdP work still
assumed it always returns an organization, which fails the type check.
Each caller now handles a missing organization the same way it did when
the 404 was thrown, so behaviour doesn't change.
Signed-off-by: Danny <117714228+UCNDanny@users.noreply.github.com>
* Undo change to DetailOrganization.tsx
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
* Use optional chaining for organization domains rather than throwing for undefined orgs
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
---------
Signed-off-by: Danny <117714228+UCNDanny@users.noreply.github.com>
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
Co-authored-by: theohh0 <theo.hinton-hallows@ibm.com>
* use isRadio to manage evaluation 'canSelectAll' so column headings don't incorrectly get shifted over by 1.
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
---------
Signed-off-by: theohh0 <theo.hinton-hallows@ibm.com>
Signed-off-by: theohh0 <theo.hintonhallows123@gmail.com>
Signed-off-by: Danny <117714228+UCNDanny@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Danny <117714228+UCNDanny@users.noreply.github.com>
ssilvert
added a commit
to ssilvert/keycloak
that referenced
this pull request
Oct 5, 2026
PR keycloak#51717 changed organizations.findOne to resolve to undefined for a
missing organization instead of rejecting with a 404, but merged without
an upgrading-guide entry. Opens the 27.0.0 changes file for it.
Fixeskeycloak#53371
Signed-off-by: Stan Silvert <ssilvert@redhat.com>
Assisted-by: Claude Opus 5.5
ahus1
pushed a commit
that referenced
this pull request
Oct 5, 2026
PR #51717 changed organizations.findOne to resolve to undefined for a
missing organization instead of rejecting with a 404, but merged without
an upgrading-guide entry. Opens the 27.0.0 changes file for it.
Fixes#53371
Assisted-by: Claude Opus 5.5
Signed-off-by: Stan Silvert <ssilvert@redhat.com>
PadzerButch
pushed a commit
to PadzerButch/-50764_test_migration_keycloak
that referenced
this pull request
Oct 22, 2026
PR keycloak#51717 changed organizations.findOne to resolve to undefined for a
missing organization instead of rejecting with a 404, but merged without
an upgrading-guide entry. Opens the 27.0.0 changes file for it.
Fixeskeycloak#53371
Assisted-by: Claude Opus 5.5
Signed-off-by: Stan Silvert <ssilvert@redhat.com>
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
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.
Closes #50830
Implements selecting which organizations to apply fine-grained admin permissions to, similar to implementation group resource selection for FGAP.
Mostly reuses
organizations/OrganizationModal.tsxcurrently used to add users to organizations.