remove all use of deprecated Select and Dropdown (#29270)
* removed deprecated select Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * some more deprecation removal working towards fixing: #28197 Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * changed to use new api Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * more deprecation removal Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed merge error Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fix tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * small fix Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed merge error Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * no more default text for SelectOption Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * changed to use id Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed dropdown in keycloakCard and test fixes Signed-off-by: mfrances <mfrances@redhat.com> Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed lint error Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fix dropdown/select related test failures Signed-off-by: mfrances <mfrances@redhat.com> * fixed test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * i18n label Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fix test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed tests Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed test Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * removed Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> * fixed merge error Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> --------- Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com> Signed-off-by: mfrances <mfrances@redhat.com> Co-authored-by: mfrances <mfrances@redhat.com>
This commit is contained in:
parent
e0507eb762
commit
5949fd43d0
142 changed files with 2843 additions and 2432 deletions
|
@ -85,7 +85,7 @@ export const EditTheResource = ({
|
|||
id={`permissions-${p.id}`}
|
||||
name={`permissions.${index}.scopes`}
|
||||
label="permissions"
|
||||
variant="typeaheadmulti"
|
||||
variant="typeaheadMulti"
|
||||
controller={{ defaultValue: [] }}
|
||||
options={resource.scopes.map(({ name, displayName }) => ({
|
||||
key: name,
|
||||
|
|
|
@ -195,7 +195,7 @@ export const ShareTheResource = ({
|
|||
<FormGroup label="" fieldId="permissions-selected">
|
||||
<SelectControl
|
||||
name="permissions"
|
||||
variant="typeaheadmulti"
|
||||
variant="typeaheadMulti"
|
||||
controller={{ defaultValue: [] }}
|
||||
options={resource.scopes.map(({ name, displayName }) => ({
|
||||
key: name,
|
||||
|
|
|
@ -192,11 +192,9 @@ describe("Client Scopes test", () => {
|
|||
.checkDropdownItemIsDisabled("Delete")
|
||||
.clickItemCheckbox(itemName)
|
||||
.checkInSearchBarChangeTypeToButtonIsDisabled(false)
|
||||
.clickSearchBarActionButton()
|
||||
.checkDropdownItemIsDisabled("Delete", false)
|
||||
.clickItemCheckbox(itemName)
|
||||
.checkInSearchBarChangeTypeToButtonIsDisabled()
|
||||
.clickSearchBarActionButton()
|
||||
.checkDropdownItemIsDisabled("Delete");
|
||||
});
|
||||
|
||||
|
|
|
@ -321,8 +321,8 @@ describe("Clients test", () => {
|
|||
clientDetailsPage.goToClientScopesEvaluateGeneratedUserInfoTab();
|
||||
cy.get("div#generatedUserInfo").contains("No generated user info");
|
||||
|
||||
cy.get("input#user-select-typeahead").type("admin-a");
|
||||
cy.get("li[id*=select-option-] > button:first-child").click();
|
||||
cy.get("[data-testid='user'] input").type("admin-a");
|
||||
cy.get(".pf-v5-c-menu__item-text").click();
|
||||
|
||||
clientDetailsPage.goToClientScopesEvaluateGeneratedAccessTokenTab();
|
||||
cy.get("div#generatedAccessToken").contains(
|
||||
|
|
|
@ -412,7 +412,6 @@ describe("Realm settings events tab tests", () => {
|
|||
});
|
||||
|
||||
it("Should remove all events from event listener and re-save original", () => {
|
||||
realmSettingsPage.shouldSaveEventListener();
|
||||
realmSettingsPage.shouldRemoveAllEventListeners();
|
||||
realmSettingsPage.shouldReSaveEventListener();
|
||||
});
|
||||
|
|
|
@ -204,14 +204,14 @@ describe("Realm settings tabs tests", () => {
|
|||
realmSettingsPage.goToLocalizationTab();
|
||||
realmSettingsPage.goToLocalizationLocalesSubTab();
|
||||
|
||||
cy.findByTestId("internationalization-disabled").click({ force: true });
|
||||
cy.findByTestId("internationalizationEnabled").click({ force: true });
|
||||
|
||||
cy.get(realmSettingsPage.supportedLocalesTypeahead)
|
||||
.click()
|
||||
.get(".pf-v5-c-select__menu-item")
|
||||
.get(".pf-v5-c-menu__list-item")
|
||||
.contains("Danish")
|
||||
.click();
|
||||
cy.get("#kc-l-supported-locales").click();
|
||||
.click({ force: true });
|
||||
cy.findByTestId("internationalizationEnabled").click({ force: true });
|
||||
|
||||
cy.intercept("GET", `/admin/realms/${realmName}/localization/en*`).as(
|
||||
"load",
|
||||
|
@ -258,7 +258,7 @@ describe("Realm settings tabs tests", () => {
|
|||
.should("be.visible");
|
||||
|
||||
cy.findByTestId("selectAll").click();
|
||||
cy.get('[data-testid="toolbar-deleteBtn"] button').click();
|
||||
cy.get('[data-testid="toolbar-deleteBtn"]').click();
|
||||
cy.findByTestId("delete-selected-TranslationBtn").click();
|
||||
cy.findByTestId("confirm").click();
|
||||
masthead.checkNotificationMessage("Successfully removed translation(s).");
|
||||
|
|
|
@ -438,7 +438,7 @@ describe("User creation", () => {
|
|||
cy.get("table")
|
||||
.contains(itemCredential)
|
||||
.parentsUntil("tbody")
|
||||
.find(".pf-v5-c-dropdown__toggle")
|
||||
.find(".pf-v5-c-table__action .pf-v5-c-menu-toggle")
|
||||
.click();
|
||||
cy.get("table").contains("Delete").click();
|
||||
modalUtils.checkModalTitle("Delete credentials?").confirmModal();
|
||||
|
|
|
@ -15,6 +15,6 @@ export default class Select {
|
|||
}
|
||||
|
||||
static #getSelectMenu(chain: Cypress.Chainable<JQuery<HTMLElement>>) {
|
||||
return chain.parent().get(".pf-v5-c-select__menu");
|
||||
return chain.parent().get(".pf-v5-c-menu__list");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,16 +18,14 @@ export default class CommonElements {
|
|||
this.secondaryBtn = this.parentSelector + ".pf-v5-c-button.pf-m-secondary";
|
||||
this.secondaryBtnLink = this.parentSelector + ".pf-v5-c-button.pf-m-link";
|
||||
this.dropdownMenuItem =
|
||||
this.parentSelector +
|
||||
".pf-v5-c-dropdown__menu .pf-v5-c-dropdown__menu-item";
|
||||
this.parentSelector + ".pf-v5-c-menu__list .pf-v5-c-menu__item";
|
||||
this.selectMenuItem =
|
||||
this.parentSelector + ".pf-v5-c-select__menu .pf-v5-c-select__menu-item";
|
||||
this.dropdownToggleBtn = this.parentSelector + ".pf-v5-c-select__toggle";
|
||||
this.tableKebabBtn = this.parentSelector + ".pf-v5-c-dropdown__toggle";
|
||||
this.dropdownSelectToggleBtn =
|
||||
this.parentSelector + ".pf-v5-c-select__toggle";
|
||||
this.parentSelector + ".pf-v5-c-menu__list .pf-v5-c-menu__list-item";
|
||||
this.dropdownToggleBtn = this.parentSelector + ".pf-v5-c-menu-toggle";
|
||||
this.tableKebabBtn = this.parentSelector + ".pf-v5-c-menu-toggle";
|
||||
this.dropdownSelectToggleBtn = this.parentSelector + ".pf-v5-c-menu-toggle";
|
||||
this.dropdownSelectToggleItem =
|
||||
this.parentSelector + ".pf-v5-c-select__menu > li";
|
||||
this.parentSelector + ".pf-v5-c-menu__list > li";
|
||||
}
|
||||
|
||||
clickPrimaryBtn() {
|
||||
|
|
|
@ -28,14 +28,14 @@ export enum FilterSession {
|
|||
}
|
||||
|
||||
export default class ListingPage extends CommonElements {
|
||||
#tableToolbar = ".pf-v5-c-toolbar";
|
||||
#tableToolbar = "section .pf-v5-c-toolbar";
|
||||
#itemsRows = "table:visible";
|
||||
#deleteUserButton = "delete-user-btn";
|
||||
#emptyListImg = '[role="tabpanel"]:not([hidden]) [data-testid="empty-state"]';
|
||||
#emptyState = "empty-state";
|
||||
#itemRowDrpDwn = ".pf-v5-c-menu-toggle";
|
||||
#itemRowSelect = ".pf-v5-c-select__toggle:nth-child(1)";
|
||||
#itemRowSelectItem = ".pf-v5-c-select__menu-item";
|
||||
#itemRowDrpDwn = ".pf-v5-c-table__action button";
|
||||
#itemRowSelect = "[data-testid='cell-dropdown']";
|
||||
#itemRowSelectItem = ".pf-v5-c-menu__item";
|
||||
#itemCheckbox = ".pf-v5-c-table__check";
|
||||
public exportBtn = '[role="menuitem"]:nth-child(1)';
|
||||
public deleteBtn = '[role="menuitem"]:nth-child(2)';
|
||||
|
@ -52,10 +52,11 @@ export default class ListingPage extends CommonElements {
|
|||
public tableRowItem = "tbody tr[data-ouia-component-type]:visible";
|
||||
#table = "table[aria-label]";
|
||||
#filterSessionDropdownButton = ".pf-v5-c-select button:nth-child(1)";
|
||||
#filterDropdownButton = "[class*='searchtype'] button";
|
||||
#kebabMenu = ".pf-v5-c-dropdown__toggle";
|
||||
#dropdownItem = ".pf-v5-c-dropdown__menu-item";
|
||||
#changeTypeToButton = ".pf-v5-c-select__toggle";
|
||||
#searchTypeButton = "[data-testid='clientScopeSearch']";
|
||||
#filterDropdownButton = "[data-testid='clientScopeSearchType']";
|
||||
#protocolFilterDropdownButton = "[data-testid='clientScopeSearchProtocol']";
|
||||
#kebabMenu = "[data-testid='kebab']";
|
||||
#dropdownItem = ".pf-v5-c-menu__list-item";
|
||||
#toolbarChangeType = "#change-type-dropdown";
|
||||
#tableNameColumnPrefix = "name-column-";
|
||||
#rowGroup = "table:visible tbody[role='rowgroup']";
|
||||
|
@ -139,7 +140,7 @@ export default class ListingPage extends CommonElements {
|
|||
}
|
||||
|
||||
clickSearchBarActionButton() {
|
||||
cy.get(this.#tableToolbar).find(this.#kebabMenu).last().click();
|
||||
cy.get(this.#tableToolbar).find(this.#kebabMenu).click();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -320,14 +321,14 @@ export default class ListingPage extends CommonElements {
|
|||
}
|
||||
|
||||
selectFilter(filter: Filter) {
|
||||
cy.get(this.#filterDropdownButton).first().click();
|
||||
cy.get(this.#searchTypeButton).click();
|
||||
cy.get(this.#dropdownItem).contains(filter).click();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
selectSecondaryFilter(itemName: string) {
|
||||
cy.get(this.#filterDropdownButton).last().click();
|
||||
cy.get(this.#filterDropdownButton).click();
|
||||
cy.get(this.#itemRowSelectItem).contains(itemName).click();
|
||||
|
||||
return this;
|
||||
|
@ -340,7 +341,8 @@ export default class ListingPage extends CommonElements {
|
|||
}
|
||||
|
||||
selectSecondaryFilterProtocol(protocol: FilterProtocol) {
|
||||
this.selectSecondaryFilter(protocol);
|
||||
cy.get(this.#protocolFilterDropdownButton).click();
|
||||
cy.get(this.#itemRowSelectItem).contains(protocol).click();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -364,14 +366,14 @@ export default class ListingPage extends CommonElements {
|
|||
cy.get(this.#itemsRows)
|
||||
.contains(itemName)
|
||||
.parentsUntil("tbody")
|
||||
.find(this.#changeTypeToButton)
|
||||
.find(this.#toolbarChangeType)
|
||||
.first()
|
||||
.click();
|
||||
|
||||
cy.get(this.#itemsRows)
|
||||
.contains(itemName)
|
||||
.parentsUntil("tbody")
|
||||
.find(this.#changeTypeToButton)
|
||||
.find(this.#toolbarChangeType)
|
||||
.contains(assignedType)
|
||||
.click();
|
||||
|
||||
|
@ -383,7 +385,7 @@ export default class ListingPage extends CommonElements {
|
|||
if (!disabled) {
|
||||
condition = "be.enabled";
|
||||
}
|
||||
cy.get(this.#changeTypeToButton).first().should(condition);
|
||||
cy.get(this.#toolbarChangeType).first().should(condition);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -391,7 +393,7 @@ export default class ListingPage extends CommonElements {
|
|||
checkDropdownItemIsDisabled(itemName: string, disabled: boolean = true) {
|
||||
cy.get(this.#dropdownItem)
|
||||
.contains(itemName)
|
||||
.should("have.attr", "aria-disabled", String(disabled));
|
||||
.should((disabled ? "" : "not.") + "be.disabled");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export default class SidebarPage extends CommonElements {
|
|||
#identityProvidersBtn = "#nav-item-identity-providers";
|
||||
#userFederationBtn = "#nav-item-user-federation";
|
||||
|
||||
realmsElements = '[data-testid="realmSelector"] li';
|
||||
realmsElements = '[id="realm-select"] li';
|
||||
|
||||
showCurrentRealms(length: number) {
|
||||
cy.findByTestId(this.#realmsDrpDwn).click();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
export default class PageObject {
|
||||
#selectItemSelectedIcon = ".pf-v5-c-select__menu-item-icon";
|
||||
#drpDwnMenuList = ".pf-v5-c-dropdown__menu";
|
||||
#drpDwnMenuItem = ".pf-v5-c-dropdown__menu-item";
|
||||
#drpDwnMenuToggleBtn = ".pf-v5-c-select__toggle";
|
||||
#selectMenuList = ".pf-v5-c-select__menu";
|
||||
#selectMenuItem = ".pf-v5-c-select__menu-item";
|
||||
#selectMenuToggleBtn = ".pf-v5-c-select__toggle";
|
||||
#selectItemSelectedIcon = ".pf-v5-c-menu-toggle__toggle-icon";
|
||||
#drpDwnMenuList = ".pf-v5-c-menu__list";
|
||||
#drpDwnMenuItem = ".pf-v5-c-menu__item";
|
||||
#drpDwnMenuToggleBtn = ".pf-v5-c-menu-toggle";
|
||||
#selectMenuList = ".pf-v5-c-menu__list";
|
||||
#selectMenuItem = ".pf-v5-c-menu__list-item";
|
||||
#selectMenuToggleBtn = ".pf-v5-c-menu-toggle";
|
||||
#switchInput = ".pf-v5-c-switch__input";
|
||||
#formLabel = ".pf-v5-c-form__label";
|
||||
#chipGroup = ".pf-v5-c-chip-group";
|
||||
|
@ -103,7 +103,12 @@ export default class PageObject {
|
|||
) {
|
||||
element =
|
||||
element ??
|
||||
cy.get(this.#drpDwnMenuToggleBtn).contains(itemName).parent().parent();
|
||||
cy
|
||||
.get(this.#drpDwnMenuToggleBtn)
|
||||
.parent()
|
||||
.contains(itemName)
|
||||
.parent()
|
||||
.parent();
|
||||
element.click();
|
||||
return this;
|
||||
}
|
||||
|
@ -114,7 +119,12 @@ export default class PageObject {
|
|||
) {
|
||||
element =
|
||||
element ??
|
||||
cy.get(this.#drpDwnMenuToggleBtn).contains(itemName).parent().parent();
|
||||
cy
|
||||
.get(this.#drpDwnMenuToggleBtn)
|
||||
.parent()
|
||||
.contains(itemName)
|
||||
.parent()
|
||||
.parent();
|
||||
this.clickDropdownMenuToggleButton(itemName, element);
|
||||
this.assertDropdownMenuIsOpen(true);
|
||||
return this;
|
||||
|
@ -126,7 +136,12 @@ export default class PageObject {
|
|||
) {
|
||||
element =
|
||||
element ??
|
||||
cy.get(this.#drpDwnMenuToggleBtn).contains(itemName).parent().parent();
|
||||
cy
|
||||
.get(this.#drpDwnMenuToggleBtn)
|
||||
.parent()
|
||||
.contains(itemName)
|
||||
.parent()
|
||||
.parent();
|
||||
this.clickDropdownMenuToggleButton(itemName, element);
|
||||
this.assertDropdownMenuIsOpen(false);
|
||||
return this;
|
||||
|
|
|
@ -61,7 +61,7 @@ export default class TablePage extends CommonElements {
|
|||
)
|
||||
.contains(itemName)
|
||||
.parentsUntil("tbody")
|
||||
.find(".pf-v5-c-menu-toggle")
|
||||
.find(".pf-v5-c-table__action .pf-v5-c-menu-toggle")
|
||||
.click()
|
||||
.get(this.#tableKebabMenu)
|
||||
.contains(actionItemName);
|
||||
|
|
|
@ -8,7 +8,6 @@ export default class TableToolbar extends CommonElements {
|
|||
#nextPageBtn: string;
|
||||
#previousPageBtn: string;
|
||||
#searchTypeDropdownBtn: string;
|
||||
#searchTypeSelectToggleBtn: string;
|
||||
#actionToggleBtn: string;
|
||||
|
||||
constructor() {
|
||||
|
@ -21,12 +20,8 @@ export default class TableToolbar extends CommonElements {
|
|||
this.#nextPageBtn = this.parentSelector + "button[data-action=next]";
|
||||
this.#previousPageBtn =
|
||||
this.parentSelector + "button[data-action=previous]";
|
||||
this.#searchTypeDropdownBtn =
|
||||
this.parentSelector +
|
||||
".pf-v5-c-dropdown .keycloak__client-scopes__searchtype";
|
||||
this.#searchTypeSelectToggleBtn =
|
||||
this.parentSelector + "[class*='searchtype'] .pf-v5-c-select__toggle";
|
||||
this.#actionToggleBtn = this.tableKebabBtn + "[aria-label='Actions']";
|
||||
this.#searchTypeDropdownBtn = "[data-testid='clientScopeSearchType']";
|
||||
this.#actionToggleBtn = "[data-testid='kebab']";
|
||||
}
|
||||
|
||||
clickNextPageButton(isUpperButton = true) {
|
||||
|
@ -98,7 +93,7 @@ export default class TableToolbar extends CommonElements {
|
|||
}
|
||||
|
||||
selectSecondarySearchType(itemName: FilterAssignedType) {
|
||||
cy.get(this.#searchTypeSelectToggleBtn).click();
|
||||
cy.get(this.#searchTypeDropdownBtn).click();
|
||||
cy.get(this.dropdownSelectToggleItem).contains(itemName).click();
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import ModalUtils from "../../../../util/ModalUtils";
|
||||
|
||||
export default class BindFlowModal extends ModalUtils {
|
||||
#bindingType = "#bindingType";
|
||||
#dropdownSelectToggleItem = ".pf-v5-c-select__menu > li";
|
||||
#bindingType = "#chooseBindingType";
|
||||
#dropdownSelectToggleItem = ".pf-v5-c-menu__list > li";
|
||||
|
||||
fill(bindingType: string) {
|
||||
cy.get(this.#bindingType).click();
|
||||
|
|
|
@ -40,6 +40,7 @@ export default class FlowDetails {
|
|||
.parentsUntil(".keycloak__authentication__flow-row")
|
||||
.find(".keycloak__authentication__requirement-dropdown")
|
||||
.click()
|
||||
.parent()
|
||||
.contains(requirement)
|
||||
.click();
|
||||
return this;
|
||||
|
@ -53,6 +54,7 @@ export default class FlowDetails {
|
|||
#clickEditDropdownForFlow(subFlowName: string, option: string) {
|
||||
cy.findByTestId(`${subFlowName}-edit-dropdown`)
|
||||
.click()
|
||||
.parent()
|
||||
.contains(option)
|
||||
.click();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ export default class WebAuthnPolicies {
|
|||
isPasswordLess ? prop.replace("Policy", "PolicyPasswordless") : prop
|
||||
}`,
|
||||
).click();
|
||||
cy.get(".pf-v5-c-select__menu").contains(data[prop]).click();
|
||||
cy.get(".pf-v5-c-menu__list").contains(data[prop]).click();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ import CommonPage from "../../../../../CommonPage";
|
|||
export default class MappersTab extends CommonPage {
|
||||
#addMapperBtn = "#mapperAction";
|
||||
#fromPredefinedMappersBtn =
|
||||
'ul[aria-labelledby="mapperAction"] > li:nth-child(1) a';
|
||||
'ul[class="pf-v5-c-menu__list"] > li:nth-child(1) button';
|
||||
#byConfigurationBtn =
|
||||
'ul[aria-labelledby="mapperAction"] > li:nth-child(2) a';
|
||||
'ul[class="pf-v5-c-menu__list"] > li:nth-child(2) button';
|
||||
#mapperConfigurationList =
|
||||
'ul[aria-label="Add predefined mappers"] > li:not([id=header])';
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ export default class CreateClientPage extends CommonPage {
|
|||
#adminUrlInput = "adminUrl";
|
||||
|
||||
#loginThemeDrpDwn = "#login_theme";
|
||||
#loginThemeList = 'ul[class="pf-v5-c-select__menu"]';
|
||||
#loginThemeList = 'ul[class="pf-v5-c-menu__list"]';
|
||||
#consentRequiredSwitch = '[for="consentRequired"] .pf-v5-c-switch__toggle';
|
||||
#consentRequiredSwitchInput = "#consentRequired";
|
||||
#displayClientOnScreenSwitch =
|
||||
|
|
|
@ -85,9 +85,7 @@ export default class AdvancedTab extends PageObject {
|
|||
|
||||
selectAccessTokenSignatureAlgorithm(algorithm: string) {
|
||||
cy.get(this.#accessTokenSignatureAlgorithmInput).click();
|
||||
cy.get(this.#accessTokenSignatureAlgorithmInput + " + ul")
|
||||
.contains(algorithm)
|
||||
.click();
|
||||
cy.get(".pf-v5-c-menu__list").contains(algorithm).click();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -200,7 +198,9 @@ export default class AdvancedTab extends PageObject {
|
|||
|
||||
selectKeyForCodeExchangeInput(input: string) {
|
||||
cy.get(this.#keyForCodeExchangeInput).click();
|
||||
cy.get(this.#keyForCodeExchangeInput + " + ul")
|
||||
cy.get(this.#keyForCodeExchangeInput)
|
||||
.parent()
|
||||
.get("ul")
|
||||
.contains(input)
|
||||
.click();
|
||||
return this;
|
||||
|
@ -228,17 +228,13 @@ export default class AdvancedTab extends PageObject {
|
|||
|
||||
selectBrowserFlowInput(input: string) {
|
||||
cy.get(this.#browserFlowInput).click();
|
||||
cy.get(this.#browserFlowInput + " + ul")
|
||||
.contains(input)
|
||||
.click();
|
||||
cy.get(this.#browserFlowInput).parent().get("ul").contains(input).click();
|
||||
return this;
|
||||
}
|
||||
|
||||
selectDirectGrantInput(input: string) {
|
||||
cy.get(this.#directGrantInput).click();
|
||||
cy.get(this.#directGrantInput + " + ul")
|
||||
.contains(input)
|
||||
.click();
|
||||
cy.get(this.#directGrantInput).parent().get("ul").contains(input).click();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import Masthead from "../../Masthead";
|
|||
const masthead = new Masthead();
|
||||
|
||||
export enum LoginFlowOption {
|
||||
empty = "",
|
||||
empty = "First login flow override",
|
||||
none = "None",
|
||||
browser = "browser",
|
||||
directGrant = "direct grant",
|
||||
|
@ -171,7 +171,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
cy.get(this.#firstLoginFlowSelect).click();
|
||||
super.clickSelectMenuItem(
|
||||
loginFlowOption,
|
||||
cy.get(".pf-v5-c-select__menu-item").contains(loginFlowOption),
|
||||
cy.get(".pf-v5-c-menu__list-item").contains(loginFlowOption),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
cy.get(this.#postLoginFlowSelect).click();
|
||||
super.clickSelectMenuItem(
|
||||
loginFlowOption,
|
||||
cy.get(".pf-v5-c-select__menu-item").contains(loginFlowOption),
|
||||
cy.get(".pf-v5-c-menu__list-item").contains(loginFlowOption),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
cy.get(this.#clientAssertionSigningAlg).click();
|
||||
super.clickSelectMenuItem(
|
||||
clientAssertionSigningAlg,
|
||||
cy.get(".pf-v5-c-select__menu-item").contains(clientAssertionSigningAlg),
|
||||
cy.get(".pf-v5-c-menu__list-item").contains(clientAssertionSigningAlg),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
cy.get(this.#syncModeSelect).click();
|
||||
super.clickSelectMenuItem(
|
||||
syncModeOption,
|
||||
cy.get(".pf-v5-c-select__menu-item").contains(syncModeOption),
|
||||
cy.get(".pf-v5-c-menu__list-item").contains(syncModeOption),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
cy.get(this.#promptSelect).click();
|
||||
super.clickSelectMenuItem(
|
||||
promptOption,
|
||||
cy.get(".pf-v5-c-select__menu-item").contains(promptOption).parent(),
|
||||
cy.get(".pf-v5-c-menu__list-item").contains(promptOption).parent(),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
cy.findByTestId("jump-link-openid-connect-settings").click();
|
||||
cy.get(this.#clientAuth)
|
||||
.click()
|
||||
.get(".pf-v5-c-select__menu-item")
|
||||
.get(".pf-v5-c-menu__list-item")
|
||||
.contains(option)
|
||||
.click();
|
||||
return this;
|
||||
|
@ -403,7 +403,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
cy.findByTestId("jump-link-openid-connect-settings").click();
|
||||
cy.get(this.#clientAssertionSigningAlg)
|
||||
.click()
|
||||
.get(".pf-v5-c-select__menu-item")
|
||||
.get(".pf-v5-c-menu__list-item")
|
||||
.contains(alg)
|
||||
.click();
|
||||
return this;
|
||||
|
@ -413,25 +413,25 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
cy.findByTestId("jump-link-openid-connect-settings").click();
|
||||
cy.get(this.#clientAuth)
|
||||
.click()
|
||||
.get(".pf-v5-c-select__menu-item")
|
||||
.get(".pf-v5-c-menu__list-item")
|
||||
.contains(ClientAuthentication.post)
|
||||
.click();
|
||||
cy.get(this.#jwtX509HeadersSwitch).should("not.exist");
|
||||
cy.get(this.#clientAuth)
|
||||
.click()
|
||||
.get(".pf-v5-c-select__menu-item")
|
||||
.get(".pf-v5-c-menu__list-item")
|
||||
.contains(ClientAuthentication.basicAuth)
|
||||
.click();
|
||||
cy.get(this.#jwtX509HeadersSwitch).should("not.exist");
|
||||
cy.get(this.#clientAuth)
|
||||
.click()
|
||||
.get(".pf-v5-c-select__menu-item")
|
||||
.get(".pf-v5-c-menu__list-item")
|
||||
.contains(ClientAuthentication.jwt)
|
||||
.click();
|
||||
cy.get(this.#jwtX509HeadersSwitch).should("not.exist");
|
||||
cy.get(this.#clientAuth)
|
||||
.click()
|
||||
.get(".pf-v5-c-select__menu-item")
|
||||
.get(".pf-v5-c-menu__list-item")
|
||||
.contains(ClientAuthentication.jwtPrivKey)
|
||||
.click();
|
||||
cy.get(this.#jwtX509HeadersSwitch).should("exist");
|
||||
|
|
|
@ -8,25 +8,20 @@ export default class ProviderPage {
|
|||
// LdapSettingsGeneral input values
|
||||
#ldapNameInput = "name";
|
||||
#ldapVendorInput = "#kc-vendor";
|
||||
#ldapVendorList = "#kc-vendor + ul";
|
||||
|
||||
// LdapSettingsConnection input values
|
||||
connectionUrlInput = "config.connectionUrl.0";
|
||||
truststoreSpiInput = "#kc-use-truststore-spi";
|
||||
truststoreSpiList = "#kc-use-truststore-spi + ul";
|
||||
truststoreSpiInput = "#useTruststoreSpi";
|
||||
connectionTimeoutInput = "config.connectionTimeout.0";
|
||||
bindTypeInput = "#kc-bind-type";
|
||||
#bindTypeList = "#kc-bind-type + ul";
|
||||
bindDnInput = "config.bindDn.0";
|
||||
bindCredsInput = "config.bindCredential.0";
|
||||
#testConnectionBtn = "test-connection-button";
|
||||
#testAuthBtn = "test-auth-button";
|
||||
|
||||
// LdapSettingsSearching input values
|
||||
ldapEditModeInput = "#kc-edit-mode";
|
||||
#ldapEditModeList = "#kc-edit-mode + ul";
|
||||
ldapEditModeInput = "#editMode";
|
||||
ldapSearchScopeInput = "#kc-search-scope";
|
||||
#ldapSearchScopeInputList = "#kc-search-scope + ul";
|
||||
ldapPagination = "ui-pagination";
|
||||
ldapUsersDnInput = "config.usersDn.0";
|
||||
ldapUserLdapAttInput = "config.usernameLDAPAttribute.0";
|
||||
|
@ -54,13 +49,9 @@ export default class ProviderPage {
|
|||
|
||||
// SettingsCache input values
|
||||
#cacheDayInput = "#kc-eviction-day";
|
||||
#cacheDayList = "#kc-eviction-day + ul";
|
||||
#cacheHourInput = "#kc-eviction-hour";
|
||||
#cacheHourList = "#kc-eviction-hour + ul";
|
||||
#cacheMinuteInput = "#kc-eviction-minute";
|
||||
#cacheMinuteList = "#kc-eviction-minute + ul";
|
||||
#cachePolicyInput = "#kc-cache-policy";
|
||||
#cachePolicyList = "#kc-cache-policy + ul";
|
||||
|
||||
// Mapper input values
|
||||
#userModelAttInput = "config.user🍺model🍺attribute";
|
||||
|
@ -119,15 +110,19 @@ export default class ProviderPage {
|
|||
switch (unit) {
|
||||
case "day":
|
||||
cy.get(this.#cacheDayInput).click();
|
||||
cy.get(this.#cacheDayList).contains(time).click();
|
||||
cy.get(this.#cacheDayInput).parent().find("ul").contains(time).click();
|
||||
break;
|
||||
case "hour":
|
||||
cy.get(this.#cacheHourInput).click();
|
||||
cy.get(this.#cacheHourList).contains(time).click();
|
||||
cy.get(this.#cacheHourInput).parent().find("ul").contains(time).click();
|
||||
break;
|
||||
case "minute":
|
||||
cy.get(this.#cacheMinuteInput).click();
|
||||
cy.get(this.#cacheMinuteList).contains(time).click();
|
||||
cy.get(this.#cacheMinuteInput)
|
||||
.parent()
|
||||
.find("ul")
|
||||
.contains(time)
|
||||
.click();
|
||||
break;
|
||||
default:
|
||||
console.log("Invalid cache time, must be 'day', 'hour', or 'minute'.");
|
||||
|
@ -187,7 +182,7 @@ export default class ProviderPage {
|
|||
|
||||
fillSelect(selectField: string, value: string) {
|
||||
cy.get(selectField).click();
|
||||
cy.get(`${selectField} + ul`).contains(value).click();
|
||||
cy.get(selectField).parent().find("ul").contains(value).click();
|
||||
}
|
||||
|
||||
fillTextField(textField: string, value: string) {
|
||||
|
@ -218,7 +213,11 @@ export default class ProviderPage {
|
|||
cy.findByTestId(this.#ldapNameInput).clear().type(name);
|
||||
if (vendor) {
|
||||
cy.get(this.#ldapVendorInput).click();
|
||||
cy.get(this.#ldapVendorList).contains(vendor).click();
|
||||
cy.get(this.#ldapVendorInput)
|
||||
.parent()
|
||||
.find("ul")
|
||||
.contains(vendor)
|
||||
.click();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -234,11 +233,15 @@ export default class ProviderPage {
|
|||
cy.findByTestId(this.connectionUrlInput).clear().type(connectionUrl);
|
||||
|
||||
cy.get(this.bindTypeInput).click();
|
||||
cy.get(this.#bindTypeList).contains(bindType).click();
|
||||
cy.get(this.bindTypeInput).parent().find("ul").contains(bindType).click();
|
||||
|
||||
if (truststoreSpi) {
|
||||
cy.get(this.truststoreSpiInput).click();
|
||||
cy.get(this.truststoreSpiList).contains(truststoreSpi).click();
|
||||
cy.get(this.truststoreSpiInput)
|
||||
.parent()
|
||||
.find("ul")
|
||||
.contains(truststoreSpi)
|
||||
.click();
|
||||
}
|
||||
if (connectionTimeout) {
|
||||
cy.findByTestId(this.connectionTimeoutInput)
|
||||
|
@ -266,7 +269,11 @@ export default class ProviderPage {
|
|||
readTimeout?: string,
|
||||
) {
|
||||
cy.get(this.ldapEditModeInput).click();
|
||||
cy.get(this.#ldapEditModeList).contains(editMode).click();
|
||||
cy.get(this.ldapEditModeInput)
|
||||
.parent()
|
||||
.find("ul")
|
||||
.contains(editMode)
|
||||
.click();
|
||||
cy.findByTestId(this.ldapUsersDnInput).clear().type(usersDn);
|
||||
if (userLdapAtt) {
|
||||
cy.findByTestId(this.ldapUserLdapAttInput).clear().type(userLdapAtt);
|
||||
|
@ -287,7 +294,11 @@ export default class ProviderPage {
|
|||
}
|
||||
if (searchScope) {
|
||||
cy.get(this.ldapSearchScopeInput).click();
|
||||
cy.get(this.#ldapSearchScopeInputList).contains(searchScope).click();
|
||||
cy.get(this.ldapSearchScopeInput)
|
||||
.parent()
|
||||
.find("ul")
|
||||
.contains(searchScope)
|
||||
.click();
|
||||
}
|
||||
if (readTimeout) {
|
||||
cy.findByTestId(this.ldapReadTimeout).clear().type(readTimeout);
|
||||
|
@ -297,7 +308,11 @@ export default class ProviderPage {
|
|||
|
||||
selectCacheType(cacheType: string) {
|
||||
cy.get(this.#cachePolicyInput).click();
|
||||
cy.get(this.#cachePolicyList).contains(cacheType).click();
|
||||
cy.get(this.#cachePolicyInput)
|
||||
.parent()
|
||||
.find("ul")
|
||||
.contains(cacheType)
|
||||
.click();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ class CreateRealmRolePage {
|
|||
clickActionMenu(item: string) {
|
||||
cy.findByTestId("action-dropdown")
|
||||
.click()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.findByText(item).click();
|
||||
});
|
||||
|
|
|
@ -23,49 +23,45 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
userProfileTab = "rs-user-profile-tab";
|
||||
tokensTab = "rs-tokens-tab";
|
||||
selectLoginTheme = "#kc-login-theme";
|
||||
loginThemeList = "#kc-login-theme + ul";
|
||||
loginThemeList = "[data-testid='select-login-theme']";
|
||||
selectAccountTheme = "#kc-account-theme";
|
||||
accountThemeList = "#kc-account-theme + ul";
|
||||
accountThemeList = "[data-testid='select-account-theme']";
|
||||
selectAdminTheme = "#kc-admin-ui-theme";
|
||||
adminThemeList = "#kc-admin-ui-theme + ul";
|
||||
adminThemeList = "[data-testid='select-admin-theme']";
|
||||
selectEmailTheme = "#kc-email-theme";
|
||||
emailThemeList = "#kc-email-theme + ul";
|
||||
emailThemeList = "[data-testid='select-email-theme']";
|
||||
ssoSessionIdleSelectMenu = "#kc-sso-session-idle-select-menu";
|
||||
ssoSessionIdleSelectMenuList = "#kc-sso-session-idle-select-menu > div > ul";
|
||||
ssoSessionIdleSelectMenuList = "#kc-sso-session-idle-select-menu ul";
|
||||
ssoSessionMaxSelectMenu = "#kc-sso-session-max-select-menu";
|
||||
ssoSessionMaxSelectMenuList = "#kc-sso-session-max-select-menu > div > ul";
|
||||
ssoSessionMaxSelectMenuList = "#kc-sso-session-max-select-menu ul";
|
||||
|
||||
ssoSessionMaxRememberMeSelectMenu =
|
||||
"#kc-sso-session-max-remember-me-select-menu";
|
||||
ssoSessionMaxRememberMeSelectMenuList =
|
||||
"#kc-sso-session-max-remember-me-select-menu > div > ul";
|
||||
"#kc-sso-session-max-remember-me-select-menu ul";
|
||||
|
||||
ssoSessionIdleRememberMeSelectMenu =
|
||||
"#kc-sso-session-idle-remember-me-select-menu";
|
||||
ssoSessionIdleRememberMeSelectMenuList =
|
||||
"#kc-sso-session-idle-remember-me-select-menu > div > ul";
|
||||
"#kc-sso-session-idle-remember-me-select-menu ul";
|
||||
|
||||
clientSessionIdleSelectMenu = "#kc-client-session-idle-select-menu";
|
||||
clientSessionIdleSelectMenuList =
|
||||
"#kc-client-session-idle-select-menu > div > ul";
|
||||
clientSessionIdleSelectMenuList = "#kc-client-session-idle-select-menu ul";
|
||||
|
||||
clientSessionMaxSelectMenu = "#kc-client-session-max-select-menu";
|
||||
clientSessionMaxSelectMenuList =
|
||||
"#kc-client-session-max-select-menu > div > ul";
|
||||
clientSessionMaxSelectMenuList = "#kc-client-session-max-select-menu ul";
|
||||
|
||||
offlineSessionIdleSelectMenu = "#kc-offline-session-idle-select-menu";
|
||||
|
||||
loginTimeoutSelectMenu = "#kc-login-timeout-select-menu";
|
||||
loginTimeoutSelectMenuList = "#kc-login-timeout-select-menu > div > ul";
|
||||
loginTimeoutSelectMenuList = "#kc-login-timeout-select-menu ul";
|
||||
|
||||
loginActionTimeoutSelectMenu = "#kc-login-action-timeout-select-menu";
|
||||
loginActionTimeoutSelectMenuList =
|
||||
"#kc-login-action-timeout-select-menu > div > ul";
|
||||
loginActionTimeoutSelectMenuList = "#kc-login-action-timeout-select-menu ul";
|
||||
|
||||
selectDefaultLocale = "#kc-default-locale";
|
||||
defaultLocaleList = "select-default-locale";
|
||||
supportedLocalesTypeahead =
|
||||
"#kc-l-supported-locales-select-multi-typeahead-typeahead";
|
||||
supportedLocalesTypeahead = "#supportedLocales";
|
||||
supportedLocalesToggle = "#kc-l-supported-locales";
|
||||
emailSaveBtn = "email-tab-save";
|
||||
managedAccessSwitch = "userManagedAccessAllowed";
|
||||
|
@ -129,29 +125,27 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
|
||||
accessTokenLifespanSelectMenu = "#kc-access-token-lifespan-select-menu";
|
||||
accessTokenLifespanSelectMenuList =
|
||||
"#kc-access-token-lifespan-select-menu > div > ul";
|
||||
"#kc-access-token-lifespan-select-menu ul";
|
||||
|
||||
parRequestUriLifespanSelectMenu = "#par-request-uri-lifespan-select-menu";
|
||||
parRequestUriLifespanSelectMenuList =
|
||||
"#par-request-uri-lifespan-select-menu > div > ul";
|
||||
"#par-request-uri-lifespan-select-menu ul";
|
||||
|
||||
accessTokenLifespanImplicitSelectMenu =
|
||||
"#kc-access-token-lifespan-implicit-select-menu";
|
||||
accessTokenLifespanImplicitSelectMenuList =
|
||||
"#kc-access-token-lifespan-implicit-select-menu > div > ul";
|
||||
"#kc-access-token-lifespan-implicit-select-menu ul";
|
||||
|
||||
clientLoginTimeoutSelectMenu = "#kc-client-login-timeout-select-menu";
|
||||
clientLoginTimeoutSelectMenuList =
|
||||
"#kc-client-login-timeout-select-menu > div > ul";
|
||||
clientLoginTimeoutSelectMenuList = "#kc-client-login-timeout-select-menu ul";
|
||||
|
||||
offlineSessionMaxSelectMenu = "#kc-offline-session-max-select-menu";
|
||||
offlineSessionMaxSelectMenuList =
|
||||
"#kc-offline-session-max-select-menu > div > ul";
|
||||
offlineSessionMaxSelectMenuList = "#kc-offline-session-max-select-menu ul";
|
||||
|
||||
userInitiatedActionLifespanSelectMenu =
|
||||
"#kc-user-initiated-action-lifespan-select-menu";
|
||||
userInitiatedActionLifespanSelectMenuList =
|
||||
"#kc-user-initiated-action-lifespan-select-menu > div > ul";
|
||||
"#kc-user-initiated-action-lifespan-select-menu ul";
|
||||
|
||||
defaultAdminInitatedInputSelectMenu =
|
||||
"#kc-default-admin-initiated-select-menu";
|
||||
|
@ -159,18 +153,17 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
"#kc-default-admin-initiated-select-menu";
|
||||
|
||||
emailVerificationSelectMenu = "#kc-email-verification-select-menu";
|
||||
emailVerificationSelectMenuList =
|
||||
"#kc-email-verification-select-menu > div > ul";
|
||||
emailVerificationSelectMenuList = "#kc-email-verification-select-menu ul";
|
||||
|
||||
idpEmailVerificationSelectMenu = "#kc-idp-email-verification-select-menu";
|
||||
idpEmailVerificationSelectMenuList =
|
||||
"#kc-idp-email-verification-select-menu > div > ul";
|
||||
"#kc-idp-email-verification-select-menu ul";
|
||||
|
||||
forgotPasswordSelectMenu = "#kc-forgot-pw-select-menu";
|
||||
forgotPasswordSelectMenuList = "#kc-forgot-pw-select-menu > div > ul";
|
||||
forgotPasswordSelectMenuList = "#kc-forgot-pw-select-menu ul";
|
||||
|
||||
executeActionsSelectMenu = "#kc-execute-actions-select-menu";
|
||||
executeActionsSelectMenuList = "#kc-execute-actions-select-menu > div > ul";
|
||||
executeActionsSelectMenuList = "#kc-execute-actions-select-menu ul";
|
||||
|
||||
#formViewProfilesView = "formView-profilesView";
|
||||
#jsonEditorProfilesView = "jsonEditor-profilesView";
|
||||
|
@ -197,7 +190,7 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
#jsonEditorSavePoliciesBtn = "jsonEditor-policies-saveBtn";
|
||||
#jsonEditorReloadBtn = "jsonEditor-reloadBtn";
|
||||
#jsonEditor = ".monaco-scrollable-element.editor-scrollable.vs";
|
||||
#clientPolicyDrpDwn = '[data-testid="action-dropdown"] button';
|
||||
#clientPolicyDrpDwn = '[data-testid="action-dropdown"]';
|
||||
#deleteclientPolicyDrpDwn = "deleteClientPolicyDropdown";
|
||||
#clientProfileOne =
|
||||
'a[href*="realm-settings/client-policies/Test/edit-profile"]';
|
||||
|
@ -206,8 +199,8 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
#clientPolicy = 'a[href*="realm-settings/client-policies/Test/edit-policy"]';
|
||||
#reloadBtn = "reloadProfile";
|
||||
#addExecutor = "addExecutor";
|
||||
#addExecutorDrpDwn = ".pf-v5-c-select__toggle";
|
||||
#addExecutorDrpDwnOption = "executorType-select";
|
||||
#addExecutorDrpDwn = "#kc-executor";
|
||||
#addExecutorDrpDwnOption = ".pf-v5-c-menu__list";
|
||||
#addExecutorCancelBtn = ".pf-v5-c-form__actions a";
|
||||
#addExecutorSaveBtn = "addExecutor-saveBtn";
|
||||
#availablePeriodExecutorFld = "available-period";
|
||||
|
@ -217,22 +210,21 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
|
||||
#listingPage = new ListingPage();
|
||||
#addCondition = "addCondition";
|
||||
#addConditionDrpDwn = ".pf-v5-c-select__toggle";
|
||||
#addConditionDrpDwnOption = "conditionType-select";
|
||||
#addConditionDrpDwn = "#provider";
|
||||
#addConditionDrpDwnOption = ".pf-v5-c-menu__list";
|
||||
#addConditionCancelBtn = "addCondition-cancelBtn";
|
||||
#addConditionSaveBtn = "addCondition-saveBtn";
|
||||
#clientRolesConditionLink = "client-roles-condition-link";
|
||||
#clientScopesConditionLink = "client-scopes-condition-link";
|
||||
#eventListenersFormLabel = ".pf-v5-c-form__label-text";
|
||||
#eventListenersDrpDwn = ".pf-v5-c-select.kc_eventListeners_select";
|
||||
#eventListenersDrpDwn = "#eventsListeners";
|
||||
#eventListenersSaveBtn = "saveEventListenerBtn";
|
||||
#eventListenersRevertBtn = "revertEventListenerBtn";
|
||||
#eventListenersInputFld =
|
||||
".pf-v5-c-form-control.pf-v5-c-select__toggle-typeahead";
|
||||
#eventListenersDrpDwnOption = ".pf-v5-c-select__menu";
|
||||
#eventListenersDrwDwnSelect =
|
||||
".pf-v5-c-button.pf-v5-c-select__toggle-button.pf-m-plain";
|
||||
#eventListenerRemove = '[data-ouia-component-id="Remove"]';
|
||||
"#eventsListeners .pf-v5-c-text-input-group__text-input";
|
||||
#eventListenersDrpDwnOption = ".pf-v5-c-menu__list";
|
||||
#eventListenersDrwDwnSelect = "#eventsListeners .pf-v5-c-menu-toggle__button";
|
||||
#eventListenerRemove = ".pf-v5-c-chip__actions";
|
||||
#roleSelect = "config.roles0";
|
||||
#selectScopeButton = "addValue";
|
||||
#deleteClientRolesConditionBtn = "delete-client-roles-condition";
|
||||
|
@ -753,7 +745,8 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
|
||||
shouldRemoveEventFromEventListener() {
|
||||
cy.get(this.#eventListenerRemove).last().click({ force: true });
|
||||
cy.findByTestId(this.#eventListenersSaveBtn).click({ force: true });
|
||||
cy.get(this.#eventListenersInputFld).click();
|
||||
cy.findByTestId(this.#eventListenersSaveBtn).click();
|
||||
cy.get(this.#alertMessage).should(
|
||||
"be.visible",
|
||||
"Event listener has been updated.",
|
||||
|
@ -762,7 +755,8 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
}
|
||||
|
||||
shouldRemoveAllEventListeners() {
|
||||
cy.get(".pf-v5-c-button.pf-m-plain.pf-v5-c-select__toggle-clear").click();
|
||||
cy.get(".pf-v5-c-chip__actions").first().click();
|
||||
cy.get(".pf-v5-c-chip__actions").click();
|
||||
cy.findByTestId(this.#eventListenersSaveBtn).click();
|
||||
cy.get(this.#eventListenersDrpDwn).should("not.have.text", "jboss-logging");
|
||||
cy.get(this.#eventListenersDrpDwn).should("not.have.text", "email");
|
||||
|
@ -908,7 +902,7 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
cy.get(this.#clientProfileTwo).click();
|
||||
cy.findByTestId(this.#addExecutor).click();
|
||||
cy.get(this.#addExecutorDrpDwn).click();
|
||||
cy.findByTestId(this.#addExecutorDrpDwnOption)
|
||||
cy.get(this.#addExecutorDrpDwnOption)
|
||||
.contains("secure-ciba-signed-authn-req")
|
||||
.click();
|
||||
cy.get(this.#addExecutorCancelBtn).click();
|
||||
|
@ -922,7 +916,7 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
cy.get(this.#clientProfileTwo).click();
|
||||
cy.findByTestId(this.#addExecutor).click();
|
||||
cy.get(this.#addExecutorDrpDwn).click();
|
||||
cy.findByTestId(this.#addExecutorDrpDwnOption)
|
||||
cy.get(this.#addExecutorDrpDwnOption)
|
||||
.contains("secure-ciba-signed-authn-req")
|
||||
.click();
|
||||
cy.findByTestId(this.#addExecutorSaveBtn).click();
|
||||
|
@ -1136,9 +1130,7 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
cy.get(this.#clientPolicy).click();
|
||||
cy.findByTestId(this.#addCondition).click();
|
||||
cy.get(this.#addConditionDrpDwn).click();
|
||||
cy.findByTestId(this.#addConditionDrpDwnOption)
|
||||
.contains("any-client")
|
||||
.click();
|
||||
cy.get(this.#addConditionDrpDwnOption).contains("any-client").click();
|
||||
cy.findByTestId(this.#addConditionCancelBtn).click();
|
||||
cy.get('h2[class*="kc-emptyConditions"]').should(
|
||||
"have.text",
|
||||
|
@ -1150,9 +1142,7 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
cy.get(this.#clientPolicy).click();
|
||||
cy.findByTestId(this.#addCondition).click();
|
||||
cy.get(this.#addConditionDrpDwn).click();
|
||||
cy.findByTestId(this.#addConditionDrpDwnOption)
|
||||
.contains("client-roles")
|
||||
.click();
|
||||
cy.get(this.#addConditionDrpDwnOption).contains("client-roles").click();
|
||||
cy.findByTestId(this.#roleSelect).clear().type("manage-realm");
|
||||
|
||||
cy.findByTestId(this.#addConditionSaveBtn).click();
|
||||
|
@ -1178,9 +1168,7 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
cy.get(this.#clientPolicy).click();
|
||||
cy.findByTestId(this.#addCondition).click();
|
||||
cy.get(this.#addConditionDrpDwn).click();
|
||||
cy.findByTestId(this.#addConditionDrpDwnOption)
|
||||
.contains("client-scopes")
|
||||
.click();
|
||||
cy.get(this.#addConditionDrpDwnOption).contains("client-scopes").click();
|
||||
|
||||
this.addClientScopes();
|
||||
|
||||
|
@ -1293,7 +1281,9 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
|
||||
deleteClientPolicyFromDetails() {
|
||||
cy.get(this.#clientPolicyDrpDwn).click({ force: true });
|
||||
cy.findByTestId(this.#deleteclientPolicyDrpDwn).click({ force: true });
|
||||
cy.findByTestId(this.#deleteclientPolicyDrpDwn)
|
||||
.find("button")
|
||||
.click({ force: true });
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -142,8 +142,12 @@ export default class UserProfile {
|
|||
}
|
||||
|
||||
setAttributeGroup(group: string) {
|
||||
cy.get("#kc-attributeGroup").click();
|
||||
cy.get("button.pf-v5-c-select__menu-item").contains(group).click();
|
||||
cy.get("#group").click();
|
||||
cy.get("#group")
|
||||
.parent()
|
||||
.get(".pf-v5-c-menu__list-item")
|
||||
.contains(group)
|
||||
.click();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ export default class CredentialsPage {
|
|||
}
|
||||
|
||||
clickResetModalAction(index: number) {
|
||||
cy.get("[data-testid=credential-reset-modal] .pf-v5-c-select__menu")
|
||||
cy.get("[data-testid=credential-reset-modal] .pf-v5-c-menu__list")
|
||||
.contains(this.#resetActions[index])
|
||||
.click();
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ export default class ModalUtils extends PageObject {
|
|||
#cancelModalBtn = "cancel";
|
||||
#closeModalBtn = ".pf-v5-c-modal-box .pf-m-plain";
|
||||
#copyToClipboardBtn = '[id*="copy-button"]';
|
||||
#addModalDropdownBtn = "#add-dropdown > button";
|
||||
#addModalDropdownItem = "#add-dropdown [role='menuitem']";
|
||||
#addModalDropdownBtn = "#add-dropdown";
|
||||
#addModalDropdownItem = ".pf-v5-c-modal-box__footer .pf-v5-c-menu__content";
|
||||
#addBtn = "add";
|
||||
#tablePage = new TablePage(TablePage.tableSelector);
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
Form,
|
||||
Modal,
|
||||
} from "@patternfly/react-core";
|
||||
import { SelectVariant } from "@patternfly/react-core/deprecated";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SelectControl } from "@keycloak/keycloak-ui-shared";
|
||||
|
@ -83,7 +82,6 @@ export const BindFlowDialog = ({ flowAlias, onClose }: BindFlowDialogProps) => {
|
|||
value: t(`flow.${REALM_FLOWS.get(key)}`),
|
||||
}))}
|
||||
controller={{ defaultValue: flowKeys[0] }}
|
||||
variant={SelectVariant.single}
|
||||
menuAppendTo="parent"
|
||||
aria-label={t("chooseBindingType")}
|
||||
/>
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
ButtonVariant,
|
||||
DataList,
|
||||
DragDrop,
|
||||
DropdownItem,
|
||||
Droppable,
|
||||
Label,
|
||||
PageSection,
|
||||
|
@ -16,7 +17,6 @@ import {
|
|||
ToolbarContent,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { DomainIcon, TableIcon } from "@patternfly/react-icons";
|
||||
import { useState } from "react";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import type { AuthenticationProviderRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigRepresentation";
|
||||
import { Tooltip } from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { DropdownList, Tooltip } from "@patternfly/react-core";
|
||||
import { Dropdown, DropdownItem, MenuToggle } from "@patternfly/react-core";
|
||||
import { PlusIcon } from "@patternfly/react-icons";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -49,19 +45,24 @@ export const AddFlowDropdown = ({
|
|||
<Tooltip content={t("add")}>
|
||||
<>
|
||||
<Dropdown
|
||||
isPlain
|
||||
position="right"
|
||||
data-testid={`${execution.displayName}-edit-dropdown`}
|
||||
popperProps={{
|
||||
position: "right",
|
||||
}}
|
||||
isOpen={open}
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
variant="plain"
|
||||
onClick={() => setOpen(!open)}
|
||||
aria-label={t("add")}
|
||||
data-testid={`${execution.displayName}-edit-dropdown`}
|
||||
>
|
||||
<PlusIcon />
|
||||
</DropdownToggle>
|
||||
}
|
||||
dropdownItems={[
|
||||
</MenuToggle>
|
||||
)}
|
||||
onSelect={() => setOpen(false)}
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
key="addStep"
|
||||
onClick={() =>
|
||||
|
@ -69,19 +70,18 @@ export const AddFlowDropdown = ({
|
|||
}
|
||||
>
|
||||
{t("addStep")}
|
||||
</DropdownItem>,
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
key="addCondition"
|
||||
onClick={() => setType("condition")}
|
||||
>
|
||||
{t("addCondition")}
|
||||
</DropdownItem>,
|
||||
</DropdownItem>
|
||||
<DropdownItem key="addSubFlow" onClick={() => setType("subFlow")}>
|
||||
{t("addSubFlow")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
onSelect={() => setOpen(false)}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
{type && type !== "subFlow" && (
|
||||
<AddStepModal
|
||||
name={execution.displayName!}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import {
|
||||
MenuToggle,
|
||||
Select,
|
||||
SelectList,
|
||||
SelectOption,
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
|
||||
import type { ExpandableExecution } from "../execution-model";
|
||||
|
||||
|
@ -30,18 +31,26 @@ export const FlowRequirementDropdown = ({
|
|||
<>
|
||||
{flow.requirementChoices && flow.requirementChoices.length > 1 && (
|
||||
<Select
|
||||
className="keycloak__authentication__requirement-dropdown"
|
||||
variant={SelectVariant.single}
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
onOpenChange={(isOpen) => setOpen(isOpen)}
|
||||
onSelect={(_event, value) => {
|
||||
flow.requirement = value.toString();
|
||||
flow.requirement = value?.toString();
|
||||
onChange(flow);
|
||||
setOpen(false);
|
||||
}}
|
||||
selections={[flow.requirement]}
|
||||
selected={flow.requirement}
|
||||
isOpen={open}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
className="keycloak__authentication__requirement-dropdown"
|
||||
ref={ref}
|
||||
onClick={() => setOpen(!open)}
|
||||
isExpanded={open}
|
||||
>
|
||||
{t(`requirements.${flow.requirement}`)}
|
||||
</MenuToggle>
|
||||
)}
|
||||
>
|
||||
{options}
|
||||
<SelectList>{options}</SelectList>
|
||||
</Select>
|
||||
)}
|
||||
{(!flow.requirementChoices || flow.requirementChoices.length <= 1) && (
|
||||
|
|
|
@ -17,9 +17,9 @@ import {
|
|||
ToolbarContent,
|
||||
ToolbarItem,
|
||||
Select,
|
||||
SelectOption,
|
||||
MenuToggle,
|
||||
SelectList,
|
||||
SelectOption,
|
||||
} from "@patternfly/react-core";
|
||||
import { PlusCircleIcon } from "@patternfly/react-icons";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
@ -53,9 +53,6 @@ const PolicySelect = ({ onSelect, selectedPolicies }: PolicySelectProps) => {
|
|||
|
||||
return (
|
||||
<Select
|
||||
style={{
|
||||
width: "300px",
|
||||
}}
|
||||
onSelect={(_, selection) => {
|
||||
onSelect(selection as PasswordPolicyTypeRepresentation);
|
||||
setOpen(false);
|
||||
|
@ -66,6 +63,7 @@ const PolicySelect = ({ onSelect, selectedPolicies }: PolicySelectProps) => {
|
|||
onClick={() => setOpen(!open)}
|
||||
isExpanded={open}
|
||||
isDisabled={policies?.length === 0}
|
||||
style={{ width: "300px" }}
|
||||
data-testid="add-policy"
|
||||
>
|
||||
{t("addPolicy")}
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
Text,
|
||||
TextContent,
|
||||
} from "@patternfly/react-core";
|
||||
import { SelectVariant } from "@patternfly/react-core/deprecated";
|
||||
import { QuestionCircleIcon } from "@patternfly/react-icons";
|
||||
import { useEffect } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
|
@ -84,15 +83,12 @@ const WebauthnSelect = ({
|
|||
<SelectControl
|
||||
name={name}
|
||||
label={t(label)}
|
||||
variant={
|
||||
isMultiSelect ? SelectVariant.typeaheadMulti : SelectVariant.single
|
||||
}
|
||||
variant={isMultiSelect ? "typeaheadMulti" : "single"}
|
||||
controller={{ defaultValue: options[0] }}
|
||||
options={options.map((option) => ({
|
||||
key: option,
|
||||
value: labelPrefix ? t(`${labelPrefix}.${option}`) : option,
|
||||
}))}
|
||||
typeAheadAriaLabel={t(name)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import { AlertVariant } from "@patternfly/react-core";
|
||||
import { Select } from "@patternfly/react-core/deprecated";
|
||||
import {
|
||||
AlertVariant,
|
||||
MenuToggle,
|
||||
Select,
|
||||
SelectList,
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAdminClient } from "../admin-client";
|
||||
|
@ -33,13 +37,19 @@ export const ChangeTypeDropdown = ({
|
|||
|
||||
return (
|
||||
<Select
|
||||
toggleId="change-type-dropdown"
|
||||
aria-label="change-type-to"
|
||||
isOpen={open}
|
||||
selections={[]}
|
||||
isDisabled={selectedRows.length === 0}
|
||||
placeholderText={t("changeTypeTo")}
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
id="change-type-dropdown"
|
||||
isDisabled={selectedRows.length === 0}
|
||||
ref={ref}
|
||||
onClick={() => setOpen(!open)}
|
||||
isExpanded={open}
|
||||
>
|
||||
{t("changeTypeTo")}
|
||||
</MenuToggle>
|
||||
)}
|
||||
onSelect={async (_, value) => {
|
||||
try {
|
||||
await Promise.all(
|
||||
|
@ -63,10 +73,12 @@ export const ChangeTypeDropdown = ({
|
|||
}
|
||||
}}
|
||||
>
|
||||
{clientScopeTypesSelectOptions(
|
||||
t,
|
||||
!clientId ? allClientScopeTypes : undefined,
|
||||
)}
|
||||
<SelectList>
|
||||
{clientScopeTypesSelectOptions(
|
||||
t,
|
||||
!clientId ? allClientScopeTypes : undefined,
|
||||
)}
|
||||
</SelectList>
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,14 +2,14 @@ import {
|
|||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
PageSection,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
KebabToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { EllipsisVIcon } from "@patternfly/react-icons";
|
||||
import { cellWidth } from "@patternfly/react-table";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -256,17 +256,23 @@ export default function ClientScopesSection() {
|
|||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Dropdown
|
||||
toggle={
|
||||
<KebabToggle
|
||||
onToggle={(_event, val) => setKebabOpen(val)}
|
||||
/>
|
||||
}
|
||||
shouldFocusToggleOnSelect
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="kebab"
|
||||
aria-label="Kebab toggle"
|
||||
ref={ref}
|
||||
onClick={() => setKebabOpen(!kebabOpen)}
|
||||
variant="plain"
|
||||
>
|
||||
<EllipsisVIcon />
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={kebabOpen}
|
||||
isPlain
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
key="action"
|
||||
component="button"
|
||||
data-testid="delete"
|
||||
isDisabled={selectedScopes.length === 0}
|
||||
onClick={() => {
|
||||
toggleDeleteDialog();
|
||||
|
@ -274,9 +280,9 @@ export default function ClientScopesSection() {
|
|||
}}
|
||||
>
|
||||
{t("delete")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ import {
|
|||
Alert,
|
||||
AlertVariant,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
PageSection,
|
||||
Tab,
|
||||
TabTitleText,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
|
|
@ -2,12 +2,6 @@ import { useEffect, useState } from "react";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import type { Path } from "react-router-dom";
|
||||
import { Link } from "react-router-dom";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { CaretDownIcon } from "@patternfly/react-icons";
|
||||
|
||||
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
||||
import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
|
||||
|
@ -21,6 +15,12 @@ import {
|
|||
Action,
|
||||
KeycloakDataTable,
|
||||
} from "../../components/table-toolbar/KeycloakDataTable";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
} from "@patternfly/react-core";
|
||||
|
||||
type MapperListProps = {
|
||||
model: ClientScopeRepresentation | ClientRepresentation;
|
||||
|
@ -114,32 +114,27 @@ export const MapperList = ({
|
|||
toolbarItem={
|
||||
<Dropdown
|
||||
onSelect={() => setMapperAction(false)}
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
toggleVariant="primary"
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
variant="primary"
|
||||
id="mapperAction"
|
||||
onToggle={() => setMapperAction(!mapperAction)}
|
||||
toggleIndicator={CaretDownIcon}
|
||||
onClick={() => setMapperAction(!mapperAction)}
|
||||
>
|
||||
{t("addMapper")}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={mapperAction}
|
||||
dropdownItems={[
|
||||
<DropdownItem
|
||||
key="predefined"
|
||||
onClick={() => toggleAddMapperDialog(true)}
|
||||
>
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem onClick={() => toggleAddMapperDialog(true)}>
|
||||
{t("fromPredefinedMapper")}
|
||||
</DropdownItem>,
|
||||
<DropdownItem
|
||||
key="byConfiguration"
|
||||
onClick={() => toggleAddMapperDialog(false)}
|
||||
>
|
||||
</DropdownItem>
|
||||
<DropdownItem onClick={() => toggleAddMapperDialog(false)}>
|
||||
{t("byConfiguration")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
}
|
||||
actions={[
|
||||
{
|
||||
|
|
|
@ -5,11 +5,11 @@ import {
|
|||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
FormGroup,
|
||||
PageSection,
|
||||
TextInput,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
|
||||
import { ActionGroup, Button } from "@patternfly/react-core";
|
||||
import { SelectVariant } from "@patternfly/react-core/deprecated";
|
||||
import { useEffect } from "react";
|
||||
import { FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -129,11 +128,10 @@ export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => {
|
|||
}}
|
||||
/>
|
||||
<SelectControl
|
||||
id="kc-type"
|
||||
name="type"
|
||||
label={t("type")}
|
||||
toggleId="kc-type"
|
||||
labelIcon={t("scopeTypeHelp")}
|
||||
variant={SelectVariant.single}
|
||||
controller={{ defaultValue: allClientScopeTypes[0] }}
|
||||
options={allClientScopeTypes.map((key) => ({
|
||||
key,
|
||||
|
@ -142,11 +140,10 @@ export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => {
|
|||
/>
|
||||
{!clientScope && (
|
||||
<SelectControl
|
||||
id="kc-protocol"
|
||||
name="protocol"
|
||||
label={t("protocol")}
|
||||
toggleId="kc-protocol"
|
||||
labelIcon={t("protocolHelp")}
|
||||
variant={SelectVariant.single}
|
||||
controller={{ defaultValue: providers[0] }}
|
||||
options={providers.map((option) => ({
|
||||
key: option,
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ToolbarItem } from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownToggle,
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
Select,
|
||||
SelectList,
|
||||
SelectOption,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import { FilterIcon } from "@patternfly/react-icons";
|
||||
|
||||
import {
|
||||
|
@ -70,18 +72,20 @@ export const SearchDropdown = ({
|
|||
|
||||
return (
|
||||
<Dropdown
|
||||
className="keycloak__client-scopes__searchtype"
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="clientScopeSearch"
|
||||
ref={ref}
|
||||
id="toggle-id"
|
||||
onToggle={(_event, val) => setSearchToggle(val)}
|
||||
onClick={() => setSearchToggle(!searchToggle)}
|
||||
>
|
||||
<FilterIcon /> {t(`clientScopeSearch.${searchType}`)}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={searchToggle}
|
||||
dropdownItems={options}
|
||||
/>
|
||||
>
|
||||
<DropdownList>{options}</DropdownList>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -109,23 +113,36 @@ export const SearchToolbar = ({
|
|||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Select
|
||||
className="keycloak__client-scopes__searchtype"
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="clientScopeSearchType"
|
||||
ref={ref}
|
||||
isExpanded={open}
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{type === AllClientScopes.none
|
||||
? t("allTypes")
|
||||
: t(`clientScopeTypes.${type}`)}
|
||||
</MenuToggle>
|
||||
)}
|
||||
onOpenChange={(val) => setOpen(val)}
|
||||
isOpen={open}
|
||||
selections={[
|
||||
selected={
|
||||
type === AllClientScopes.none
|
||||
? t("allTypes")
|
||||
: t(`clientScopeTypes.${type}`),
|
||||
]}
|
||||
: t(`clientScopeTypes.${type}`)
|
||||
}
|
||||
onSelect={(_, value) => {
|
||||
onType(value as AllClientScopes);
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<SelectOption value={AllClientScopes.none}>
|
||||
{t("allTypes")}
|
||||
</SelectOption>
|
||||
<>{clientScopeTypesSelectOptions(t)}</>
|
||||
<SelectList>
|
||||
<SelectOption value={AllClientScopes.none}>
|
||||
{t("allTypes")}
|
||||
</SelectOption>
|
||||
{clientScopeTypesSelectOptions(t)}
|
||||
</SelectList>
|
||||
</Select>
|
||||
</ToolbarItem>
|
||||
</>
|
||||
|
@ -141,20 +158,31 @@ export const SearchToolbar = ({
|
|||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Select
|
||||
className="keycloak__client-scopes__searchtype"
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="clientScopeSearchProtocol"
|
||||
ref={ref}
|
||||
isExpanded={open}
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{t(`protocolTypes.${protocol}`)}
|
||||
</MenuToggle>
|
||||
)}
|
||||
onOpenChange={(val) => setOpen(val)}
|
||||
isOpen={open}
|
||||
selections={[t(`protocolTypes.${protocol}`)]}
|
||||
selected={t(`protocolTypes.${protocol}`)}
|
||||
onSelect={(_, value) => {
|
||||
onProtocol?.(value as ProtocolType);
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{PROTOCOLS.map((type) => (
|
||||
<SelectOption key={type} value={type}>
|
||||
{t(`protocolTypes.${type}`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
<SelectList>
|
||||
{PROTOCOLS.map((type) => (
|
||||
<SelectOption key={type} value={type}>
|
||||
{t(`protocolTypes.${type}`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</SelectList>
|
||||
</Select>
|
||||
</ToolbarItem>
|
||||
</>
|
||||
|
|
|
@ -3,13 +3,13 @@ import {
|
|||
AlertVariant,
|
||||
ButtonVariant,
|
||||
Divider,
|
||||
DropdownItem,
|
||||
Label,
|
||||
PageSection,
|
||||
Tab,
|
||||
TabTitleText,
|
||||
Tooltip,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { InfoCircleIcon } from "@patternfly/react-icons";
|
||||
import { cloneDeep, sortBy } from "lodash-es";
|
||||
import { useMemo, useState } from "react";
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import { ActionGroup, Button, FormGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
ActionGroup,
|
||||
Button,
|
||||
FormGroup,
|
||||
MenuToggle,
|
||||
Select,
|
||||
SelectList,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -145,21 +148,30 @@ export const AdvancedSettings = ({
|
|||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
toggleId="keyForCodeExchange"
|
||||
variant={SelectVariant.single}
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
id="keyForCodeExchange"
|
||||
ref={ref}
|
||||
onClick={() => setOpen(!open)}
|
||||
isExpanded={open}
|
||||
>
|
||||
{[field.value || t("choose")]}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={open}
|
||||
onSelect={(_, value) => {
|
||||
field.onChange(value);
|
||||
setOpen(false);
|
||||
}}
|
||||
selections={[field.value || t("choose")]}
|
||||
selected={field.value}
|
||||
>
|
||||
{["", "S256", "plain"].map((v) => (
|
||||
<SelectOption key={v} value={v}>
|
||||
{v || t("choose")}
|
||||
</SelectOption>
|
||||
))}
|
||||
<SelectList>
|
||||
{["", "S256", "plain"].map((v) => (
|
||||
<SelectOption key={v} value={v}>
|
||||
{v || t("choose")}
|
||||
</SelectOption>
|
||||
))}
|
||||
</SelectList>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { FormGroup, Split, SplitItem } from "@patternfly/react-core";
|
||||
import {
|
||||
FormGroup,
|
||||
MenuToggle,
|
||||
Select,
|
||||
SelectList,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
Split,
|
||||
SplitItem,
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -57,19 +60,26 @@ export const TokenLifespan = ({
|
|||
<Split hasGutter>
|
||||
<SplitItem>
|
||||
<Select
|
||||
variant={SelectVariant.single}
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
onClick={() => setOpen(!open)}
|
||||
isExpanded={open}
|
||||
>
|
||||
{isExpireSet(field.value) ? t(expires) : t(inherited)}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={open}
|
||||
onSelect={(_, value) => {
|
||||
field.onChange(value);
|
||||
setOpen(false);
|
||||
}}
|
||||
selections={[
|
||||
isExpireSet(field.value) ? t(expires) : t(inherited),
|
||||
]}
|
||||
selected={isExpireSet(field.value) ? t(expires) : t(inherited)}
|
||||
>
|
||||
<SelectOption value="">{t(inherited)}</SelectOption>
|
||||
<SelectOption value={60}>{t(expires)}</SelectOption>
|
||||
<SelectList>
|
||||
<SelectOption value="">{t(inherited)}</SelectOption>
|
||||
<SelectOption value={60}>{t(expires)}</SelectOption>
|
||||
</SelectList>
|
||||
</Select>
|
||||
</SplitItem>
|
||||
<SplitItem hidden={!isExpireSet(field.value)}>
|
||||
|
|
|
@ -5,6 +5,11 @@ import type ResourceEvaluation from "@keycloak/keycloak-admin-client/lib/defs/re
|
|||
import type ResourceRepresentation from "@keycloak/keycloak-admin-client/lib/defs/resourceRepresentation";
|
||||
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||
import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation";
|
||||
import {
|
||||
HelpItem,
|
||||
SelectControl,
|
||||
TextControl,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
ActionGroup,
|
||||
Button,
|
||||
|
@ -17,19 +22,9 @@ import {
|
|||
Switch,
|
||||
Title,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import { FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
FormErrorText,
|
||||
HelpItem,
|
||||
TextControl,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { ForbiddenSection } from "../../ForbiddenSection";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { useAlerts } from "../../components/alert/Alerts";
|
||||
|
@ -104,13 +99,11 @@ const AuthorizationEvaluateContent = ({ client }: Props) => {
|
|||
control,
|
||||
reset,
|
||||
trigger,
|
||||
formState: { isValid, errors },
|
||||
formState: { isValid },
|
||||
} = form;
|
||||
const { t } = useTranslation();
|
||||
const { addError } = useAlerts();
|
||||
const realm = useRealm();
|
||||
const [scopesDropdownOpen, setScopesDropdownOpen] = useState(false);
|
||||
const [roleDropdownOpen, setRoleDropdownOpen] = useState(false);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const [applyToResourceType, setApplyToResourceType] = useState(false);
|
||||
const [resources, setResources] = useState<ResourceRepresentation[]>([]);
|
||||
|
@ -219,64 +212,26 @@ const AuthorizationEvaluateContent = ({ client }: Props) => {
|
|||
label="users"
|
||||
helpText={t("selectUser")}
|
||||
defaultValue={[]}
|
||||
variant={SelectVariant.typeahead}
|
||||
variant="typeahead"
|
||||
isRequired={roles?.length === 0}
|
||||
/>
|
||||
<FormGroup
|
||||
<SelectControl
|
||||
name="roleIds"
|
||||
label={t("roles")}
|
||||
labelIcon={
|
||||
<HelpItem helpText={t("rolesHelp")} fieldLabelId="roles" />
|
||||
}
|
||||
fieldId="realmRole"
|
||||
isRequired={user.length === 0}
|
||||
>
|
||||
<Controller
|
||||
name="roleIds"
|
||||
control={control}
|
||||
defaultValue={[]}
|
||||
rules={{
|
||||
validate: (value) =>
|
||||
(value || "").length > 0 || user.length > 0,
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
placeholderText={t("selectARole")}
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
toggleId="role"
|
||||
onToggle={(_event, val) => setRoleDropdownOpen(val)}
|
||||
selections={field.value}
|
||||
onSelect={(_, v) => {
|
||||
const option = v.toString();
|
||||
if (field.value?.includes(option)) {
|
||||
field.onChange(
|
||||
field.value.filter(
|
||||
(item: string) => item !== option,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
field.onChange([...(field.value || []), option]);
|
||||
}
|
||||
setRoleDropdownOpen(false);
|
||||
}}
|
||||
onClear={(event) => {
|
||||
event.stopPropagation();
|
||||
field.onChange([]);
|
||||
}}
|
||||
aria-label={t("realmRole")}
|
||||
isOpen={roleDropdownOpen}
|
||||
>
|
||||
{clientRoles.map((role) => (
|
||||
<SelectOption
|
||||
selected={role.name === field.value}
|
||||
key={role.name}
|
||||
value={role.name}
|
||||
/>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
{errors.roleIds && <FormErrorText message={t("required")} />}
|
||||
</FormGroup>
|
||||
labelIcon={t("rolesHelp")}
|
||||
variant="typeaheadMulti"
|
||||
placeholderText={t("selectARole")}
|
||||
controller={{
|
||||
defaultValue: [],
|
||||
rules: {
|
||||
required: {
|
||||
value: user.length === 0,
|
||||
message: t("required"),
|
||||
},
|
||||
},
|
||||
}}
|
||||
options={clientRoles.map((role) => role.name!)}
|
||||
/>
|
||||
</FormAccess>
|
||||
</PanelMainBody>
|
||||
</Panel>
|
||||
|
@ -334,54 +289,16 @@ const AuthorizationEvaluateContent = ({ client }: Props) => {
|
|||
labelIcon={t("resourceTypeHelp")}
|
||||
rules={{ required: t("required") }}
|
||||
/>
|
||||
<FormGroup
|
||||
<SelectControl
|
||||
name="authScopes"
|
||||
label={t("authScopes")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText={t("scopesSelect")}
|
||||
fieldLabelId="client"
|
||||
/>
|
||||
}
|
||||
fieldId="authScopes"
|
||||
>
|
||||
<Controller
|
||||
name="authScopes"
|
||||
defaultValue={[]}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
toggleId="authScopes"
|
||||
onToggle={(_event, val) => setScopesDropdownOpen(val)}
|
||||
onSelect={(_, v) => {
|
||||
const option = v.toString();
|
||||
if (field.value.includes(option)) {
|
||||
field.onChange(
|
||||
field.value.filter(
|
||||
(item: string) => item !== option,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
field.onChange([...field.value, option]);
|
||||
}
|
||||
setScopesDropdownOpen(false);
|
||||
}}
|
||||
selections={field.value}
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
typeAheadAriaLabel={t("selectAuthScopes")}
|
||||
isOpen={scopesDropdownOpen}
|
||||
aria-label={t("selectAuthScopes")}
|
||||
>
|
||||
{scopes.map((scope) => (
|
||||
<SelectOption
|
||||
selected={field.value.includes(scope.name!)}
|
||||
key={scope.id}
|
||||
value={scope.name}
|
||||
/>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
labelIcon={t("scopesSelect")}
|
||||
controller={{
|
||||
defaultValue: [],
|
||||
}}
|
||||
variant="typeaheadMulti"
|
||||
options={scopes.map((s) => s.name!)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<ExpandableSection
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import type ResourceRepresentation from "@keycloak/keycloak-admin-client/lib/defs/resourceRepresentation";
|
||||
import { Button, TextInput } from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { Button, SelectOption, TextInput } from "@patternfly/react-core";
|
||||
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
|
||||
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
|
||||
import { camelCase } from "lodash-es";
|
||||
|
@ -15,6 +10,10 @@ import { useTranslation } from "react-i18next";
|
|||
import { defaultContextAttributes } from "../utils";
|
||||
|
||||
import "./key-based-attribute-input.css";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../../components/select/KeycloakSelect";
|
||||
|
||||
export type AttributeType = {
|
||||
key?: string;
|
||||
|
@ -99,29 +98,28 @@ const ValueInput = ({
|
|||
defaultValue={[]}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId={`${attribute.id}-value`}
|
||||
className="kc-attribute-value-selectable"
|
||||
name={`${name}.${rowIndex}.value`}
|
||||
chipGroupProps={{
|
||||
numChips: 1,
|
||||
expandedText: t("hide"),
|
||||
collapsedText: t("showRemaining"),
|
||||
}}
|
||||
onToggle={(_event, open) => toggleValueSelect(rowIndex, open)}
|
||||
onToggle={(open) => toggleValueSelect(rowIndex, open)}
|
||||
isOpen={isValueOpenArray[rowIndex]}
|
||||
variant={SelectVariant.typeahead}
|
||||
typeAheadAriaLabel={t("selectOrTypeAKey")}
|
||||
placeholderText={t("selectOrTypeAKey")}
|
||||
selections={field.value}
|
||||
onSelect={(_, v) => {
|
||||
onSelect={(v) => {
|
||||
field.onChange(v);
|
||||
|
||||
toggleValueSelect(rowIndex, false);
|
||||
}}
|
||||
>
|
||||
{renderSelectOptionType()}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
|
@ -186,17 +184,16 @@ export const KeyBasedAttributeInput = ({
|
|||
defaultValue=""
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId={`${name}.${rowIndex}.key`}
|
||||
className="kc-attribute-key-selectable"
|
||||
name={`${name}.${rowIndex}.key`}
|
||||
onToggle={(_event, open) => toggleKeySelect(rowIndex, open)}
|
||||
onToggle={(open) => toggleKeySelect(rowIndex, open)}
|
||||
isOpen={isKeyOpenArray[rowIndex]}
|
||||
variant={SelectVariant.typeahead}
|
||||
typeAheadAriaLabel={t("selectOrTypeAKey")}
|
||||
placeholderText={t("selectOrTypeAKey")}
|
||||
selections={field.value}
|
||||
onSelect={(_, v) => {
|
||||
onSelect={(v) => {
|
||||
field.onChange(v.toString());
|
||||
|
||||
toggleKeySelect(rowIndex, false);
|
||||
|
@ -211,7 +208,7 @@ export const KeyBasedAttributeInput = ({
|
|||
{attribute.name}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</Td>
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
import type PolicyRepresentation from "@keycloak/keycloak-admin-client/lib/defs/policyRepresentation";
|
||||
import { DecisionStrategy } from "@keycloak/keycloak-admin-client/lib/defs/policyRepresentation";
|
||||
import {
|
||||
ActionGroup,
|
||||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
FormGroup,
|
||||
PageSection,
|
||||
Radio,
|
||||
Switch,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem, SelectVariant } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import {
|
||||
FormErrorText,
|
||||
HelpItem,
|
||||
TextAreaControl,
|
||||
TextControl,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
ActionGroup,
|
||||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
FormGroup,
|
||||
PageSection,
|
||||
Radio,
|
||||
Switch,
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { useAlerts } from "../../components/alert/Alerts";
|
||||
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
|
||||
|
@ -39,6 +39,7 @@ import {
|
|||
} from "../routes/PermissionDetails";
|
||||
import { ResourcesPolicySelect } from "./ResourcesPolicySelect";
|
||||
import { ScopeSelect } from "./ScopeSelect";
|
||||
import { SelectVariant } from "../../components/select/KeycloakSelect";
|
||||
|
||||
type FormFields = PolicyRepresentation & {
|
||||
resourceType: string;
|
||||
|
|
|
@ -5,15 +5,14 @@ import {
|
|||
AlertVariant,
|
||||
ButtonVariant,
|
||||
DescriptionList,
|
||||
Divider,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
PageSection,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownSeparator,
|
||||
DropdownToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import {
|
||||
ExpandableRowContent,
|
||||
Table,
|
||||
|
@ -209,21 +208,22 @@ export const AuthorizationPermissions = ({
|
|||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Dropdown
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
onToggle={toggleCreate}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
onClick={toggleCreate}
|
||||
isDisabled={isDisabled}
|
||||
toggleVariant="primary"
|
||||
variant="primary"
|
||||
data-testid="permissionCreateDropdown"
|
||||
>
|
||||
{t("createPermission")}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={createOpen}
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
data-testid="create-resource"
|
||||
key="createResourceBasedPermission"
|
||||
isDisabled={isDisabled || disabledCreate?.resources}
|
||||
component="button"
|
||||
onClick={() =>
|
||||
|
@ -237,11 +237,10 @@ export const AuthorizationPermissions = ({
|
|||
}
|
||||
>
|
||||
{t("createResourceBasedPermission")}
|
||||
</DropdownItem>,
|
||||
<DropdownSeparator key="separator" />,
|
||||
</DropdownItem>
|
||||
<Divider />
|
||||
<DropdownItem
|
||||
data-testid="create-scope"
|
||||
key="createScopeBasedPermission"
|
||||
isDisabled={isDisabled || disabledCreate?.scopes}
|
||||
component="button"
|
||||
onClick={() =>
|
||||
|
@ -264,9 +263,9 @@ export const AuthorizationPermissions = ({
|
|||
title={t("noScopeCreateHint")}
|
||||
/>
|
||||
)}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ import {
|
|||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
FormGroup,
|
||||
PageSection,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
|
@ -5,12 +5,13 @@ import type {
|
|||
Clients,
|
||||
PolicyQuery,
|
||||
} from "@keycloak/keycloak-admin-client/lib/resources/clients";
|
||||
import { Button, ButtonVariant, Chip, ChipGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
Chip,
|
||||
ChipGroup,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Controller,
|
||||
|
@ -21,6 +22,11 @@ import { useTranslation } from "react-i18next";
|
|||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
Variant,
|
||||
} from "../../components/select/KeycloakSelect";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { useFetch } from "../../utils/useFetch";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
|
@ -35,7 +41,7 @@ type ResourcesPolicySelectProps = {
|
|||
name: Type;
|
||||
clientId: string;
|
||||
permissionId?: string;
|
||||
variant?: SelectVariant;
|
||||
variant?: Variant;
|
||||
preSelected?: string;
|
||||
isRequired?: boolean;
|
||||
};
|
||||
|
@ -230,11 +236,11 @@ export const ResourcesPolicySelect = ({
|
|||
control={control}
|
||||
rules={{ validate: (value) => !isRequired || value!.length > 0 }}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId={name}
|
||||
variant={variant}
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
onFilter={(_, filter) => {
|
||||
onToggle={(val) => setOpen(val)}
|
||||
onFilter={(filter) => {
|
||||
setSearch(filter);
|
||||
return toSelectOptions();
|
||||
}}
|
||||
|
@ -243,7 +249,7 @@ export const ResourcesPolicySelect = ({
|
|||
setSearch("");
|
||||
}}
|
||||
selections={field.value}
|
||||
onSelect={(_, selectedValue) => {
|
||||
onSelect={(selectedValue) => {
|
||||
const option = selectedValue.toString();
|
||||
if (variant === SelectVariant.typeaheadMulti) {
|
||||
const changedValue = field.value?.find(
|
||||
|
@ -287,7 +293,7 @@ export const ResourcesPolicySelect = ({
|
|||
}
|
||||
>
|
||||
{toSelectOptions()}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
PageSection,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation";
|
||||
import { FormGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import { FormGroup, SelectOption } from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../../components/select/KeycloakSelect";
|
||||
import { useFetch } from "../../utils/useFetch";
|
||||
|
||||
type Scope = {
|
||||
|
@ -42,13 +42,14 @@ export const ScopePicker = ({ clientId }: { clientId: string }) => {
|
|||
[search],
|
||||
);
|
||||
|
||||
const renderScopes = (scopes?: ScopeRepresentation[]) =>
|
||||
scopes?.map((option) => (
|
||||
const renderScopes = (scopes: ScopeRepresentation[]) =>
|
||||
scopes.map((option) => (
|
||||
<SelectOption key={option.id} value={option}>
|
||||
{option.name}
|
||||
</SelectOption>
|
||||
));
|
||||
|
||||
if (!scopes) return <KeycloakSpinner />;
|
||||
return (
|
||||
<FormGroup
|
||||
label={t("authorizationScopes")}
|
||||
|
@ -62,7 +63,7 @@ export const ScopePicker = ({ clientId }: { clientId: string }) => {
|
|||
defaultValue={[]}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId="scopes"
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
chipGroupProps={{
|
||||
|
@ -70,14 +71,14 @@ export const ScopePicker = ({ clientId }: { clientId: string }) => {
|
|||
expandedText: t("hide"),
|
||||
collapsedText: t("showRemaining"),
|
||||
}}
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
onToggle={(val) => setOpen(val)}
|
||||
isOpen={open}
|
||||
selections={field.value.map((o: Scope) => o.name)}
|
||||
onFilter={(_, value) => {
|
||||
onFilter={(value) => {
|
||||
setSearch(value);
|
||||
return renderScopes(scopes);
|
||||
}}
|
||||
onSelect={(_, selectedValue) => {
|
||||
onSelect={(selectedValue) => {
|
||||
const option =
|
||||
typeof selectedValue === "string"
|
||||
? selectedValue
|
||||
|
@ -89,15 +90,14 @@ export const ScopePicker = ({ clientId }: { clientId: string }) => {
|
|||
: [...field.value, selectedValue];
|
||||
field.onChange(changedValue);
|
||||
}}
|
||||
onClear={(event) => {
|
||||
event.stopPropagation();
|
||||
onClear={() => {
|
||||
setSearch("");
|
||||
field.onChange([]);
|
||||
}}
|
||||
typeAheadAriaLabel={t("authorizationScopes")}
|
||||
>
|
||||
{renderScopes(scopes)}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { useRef, useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { useFetch } from "../../utils/useFetch";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../../components/select/KeycloakSelect";
|
||||
import { SelectOption } from "@patternfly/react-core";
|
||||
|
||||
type ScopeSelectProps = {
|
||||
clientId: string;
|
||||
|
@ -87,11 +87,11 @@ export const ScopeSelect = ({
|
|||
control={control}
|
||||
rules={{ validate: (value) => value.length > 0 }}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId="scopes"
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
onToggle={(_event, val) => setOpen(val)}
|
||||
onFilter={(_, filter) => {
|
||||
onToggle={(val) => setOpen(val)}
|
||||
onFilter={(filter) => {
|
||||
setSearch(filter);
|
||||
return toSelectOptions(scopes);
|
||||
}}
|
||||
|
@ -99,8 +99,8 @@ export const ScopeSelect = ({
|
|||
field.onChange([]);
|
||||
setSearch("");
|
||||
}}
|
||||
selections={selectedScopes.map((s) => s.name)}
|
||||
onSelect={(_, selectedValue) => {
|
||||
selections={selectedScopes.map((s) => s.name!)}
|
||||
onSelect={(selectedValue) => {
|
||||
const option =
|
||||
typeof selectedValue === "string"
|
||||
? selectedScopes.find((s) => s.name === selectedValue)!
|
||||
|
@ -120,7 +120,7 @@ export const ScopeSelect = ({
|
|||
typeAheadAriaLabel={t("scopes")}
|
||||
>
|
||||
{toSelectOptions(scopes)}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import type PolicyProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/policyProviderRepresentation";
|
||||
import { ActionGroup, Button, Form } from "@patternfly/react-core";
|
||||
import { Dropdown, DropdownToggle } from "@patternfly/react-core/deprecated";
|
||||
import { SelectControl, TextControl } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
ActionGroup,
|
||||
Button,
|
||||
Dropdown,
|
||||
Form,
|
||||
MenuToggle,
|
||||
} from "@patternfly/react-core";
|
||||
import { useEffect } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SelectControl, TextControl } from "@keycloak/keycloak-ui-shared";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
|
||||
import "./search-dropdown.css";
|
||||
|
@ -50,18 +55,18 @@ export const SearchDropdown = ({
|
|||
|
||||
return (
|
||||
<Dropdown
|
||||
data-testid="searchdropdown_dorpdown"
|
||||
className="pf-v5-u-ml-md"
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
onToggle={toggle}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="searchdropdown_dorpdown"
|
||||
ref={ref}
|
||||
onClick={toggle}
|
||||
className="keycloak__client_authentication__searchdropdown"
|
||||
>
|
||||
{type === "resource" && t("searchClientAuthorizationResource")}
|
||||
{type === "policy" && t("searchClientAuthorizationPolicy")}
|
||||
{type === "permission" && t("searchClientAuthorizationPermission")}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={open}
|
||||
>
|
||||
<FormProvider {...form}>
|
||||
|
|
|
@ -10,12 +10,11 @@ import {
|
|||
ToolbarGroup,
|
||||
ToolbarItem,
|
||||
InputGroupItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
MenuToggle,
|
||||
SelectList,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
} from "@patternfly/react-core";
|
||||
import { SearchIcon } from "@patternfly/react-icons";
|
||||
import { Table, Th, Thead, Tr } from "@patternfly/react-table";
|
||||
import { KeyboardEvent, useMemo, useState } from "react";
|
||||
|
@ -115,38 +114,46 @@ export const Results = ({ evaluateResult, refresh, back }: ResultProps) => {
|
|||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Select
|
||||
width={300}
|
||||
data-testid="filter-type-select"
|
||||
isOpen={filterDropdownOpen}
|
||||
className="kc-filter-type-select"
|
||||
variant={SelectVariant.single}
|
||||
onToggle={toggleFilterDropdown}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
onClick={toggleFilterDropdown}
|
||||
isExpanded={filterDropdownOpen}
|
||||
style={{ width: "300px" }}
|
||||
>
|
||||
{filter}
|
||||
</MenuToggle>
|
||||
)}
|
||||
onSelect={(_, value) => {
|
||||
setFilter(value as ResultsFilter);
|
||||
toggleFilterDropdown();
|
||||
refresh();
|
||||
}}
|
||||
selections={filter}
|
||||
selected={filter}
|
||||
>
|
||||
<SelectOption
|
||||
data-testid="all-results-option"
|
||||
value={ResultsFilter.All}
|
||||
isPlaceholder
|
||||
>
|
||||
{t("allResults")}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
data-testid="result-permit-option"
|
||||
value={ResultsFilter.StatusPermitted}
|
||||
>
|
||||
{t("resultPermit")}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
data-testid="result-deny-option"
|
||||
value={ResultsFilter.StatusDenied}
|
||||
>
|
||||
{t("resultDeny")}
|
||||
</SelectOption>
|
||||
<SelectList>
|
||||
<SelectOption
|
||||
data-testid="all-results-option"
|
||||
value={ResultsFilter.All}
|
||||
>
|
||||
{t("allResults")}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
data-testid="result-permit-option"
|
||||
value={ResultsFilter.StatusPermitted}
|
||||
>
|
||||
{t("resultPermit")}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
data-testid="result-deny-option"
|
||||
value={ResultsFilter.StatusDenied}
|
||||
>
|
||||
{t("resultDeny")}
|
||||
</SelectOption>
|
||||
</SelectList>
|
||||
</Select>
|
||||
</ToolbarItem>
|
||||
</ToolbarGroup>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { SelectVariant } from "@patternfly/react-core/deprecated";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ClientSelect } from "../../../components/client/ClientSelect";
|
||||
|
||||
|
@ -12,7 +11,7 @@ export const Client = () => {
|
|||
helpText={t("policyClientHelp")}
|
||||
required
|
||||
defaultValue={[]}
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
variant="typeaheadMulti"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
PageSection,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
width: max-content;
|
||||
--pf-v5-c-form--m-horizontal__group-label--md--GridColumnWidth: 5rem;
|
||||
--pf-v5-c-form--m-horizontal__group-control--md--GridColumnWidth: 24rem;
|
||||
margin: 0 var(--pf-v5-global--spacer--lg) var(--pf-v5-global--spacer--lg)
|
||||
margin: var(--pf-v5-global--spacer--lg) var(--pf-v5-global--spacer--lg)
|
||||
var(--pf-v5-global--spacer--lg);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,8 @@ export const SignedJWT = ({ clientAuthenticatorType }: SignedJWTProps) => {
|
|||
controller={{
|
||||
defaultValue: "",
|
||||
}}
|
||||
maxHeight={200}
|
||||
isScrollable
|
||||
maxMenuHeight="200px"
|
||||
options={[
|
||||
{ key: "", value: t("anyAlgorithm") },
|
||||
...providers.map((option) => ({ key: option, value: option })),
|
||||
|
|
|
@ -4,9 +4,9 @@ import {
|
|||
ActionGroup,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
PageSection,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
|
@ -2,18 +2,14 @@ import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/
|
|||
import {
|
||||
Button,
|
||||
ButtonVariant,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
Modal,
|
||||
ModalVariant,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownDirection,
|
||||
DropdownItem,
|
||||
DropdownToggle,
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
CaretDownIcon,
|
||||
CaretUpIcon,
|
||||
|
@ -30,6 +26,7 @@ import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState
|
|||
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
import { getProtocolName } from "../utils";
|
||||
import { KeycloakSelect } from "../../components/select/KeycloakSelect";
|
||||
|
||||
import "./client-scopes.css";
|
||||
|
||||
|
@ -123,7 +120,7 @@ export const AddScopeDialog = ({
|
|||
<SelectOption key={2} value={ProtocolType.OpenIDConnect}>
|
||||
{t("protocolTypes.openid-connect")}
|
||||
</SelectOption>,
|
||||
<SelectOption key={3} value={ProtocolType.All} isPlaceholder>
|
||||
<SelectOption key={3} value={ProtocolType.All}>
|
||||
{t("protocolTypes.all")}
|
||||
</SelectOption>,
|
||||
];
|
||||
|
@ -170,24 +167,29 @@ export const AddScopeDialog = ({
|
|||
]
|
||||
: [
|
||||
<Dropdown
|
||||
popperProps={{
|
||||
direction: "up",
|
||||
}}
|
||||
className="keycloak__client-scopes-add__add-dropdown"
|
||||
id="add-dropdown"
|
||||
key="add-dropdown"
|
||||
direction={DropdownDirection.up}
|
||||
isOpen={addToggle}
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
isDisabled={rows.length === 0}
|
||||
onToggle={() => setAddToggle(!addToggle)}
|
||||
toggleVariant="primary"
|
||||
toggleIndicator={CaretUpIcon}
|
||||
id="add-scope-toggle"
|
||||
onClick={() => setAddToggle(!addToggle)}
|
||||
variant="primary"
|
||||
id="add-dropdown"
|
||||
statusIcon={<CaretUpIcon />}
|
||||
>
|
||||
{t("add")}
|
||||
</DropdownToggle>
|
||||
}
|
||||
dropdownItems={clientScopeTypesDropdown(t, action)}
|
||||
/>,
|
||||
</MenuToggle>
|
||||
)}
|
||||
>
|
||||
<DropdownList>
|
||||
{clientScopeTypesDropdown(t, action)}
|
||||
</DropdownList>
|
||||
</Dropdown>,
|
||||
<Button
|
||||
id="modal-cancel"
|
||||
key="cancel"
|
||||
|
@ -214,27 +216,29 @@ export const AddScopeDialog = ({
|
|||
onSelect={() => {
|
||||
onFilterTypeDropdownSelect(filterType);
|
||||
}}
|
||||
data-testid="filter-type-dropdown"
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
data-testid="filter-type-dropdown"
|
||||
id="toggle-id-9"
|
||||
onToggle={toggleIsFilterTypeDropdownOpen}
|
||||
toggleIndicator={CaretDownIcon}
|
||||
onClick={toggleIsFilterTypeDropdownOpen}
|
||||
icon={<FilterIcon />}
|
||||
statusIcon={<CaretDownIcon />}
|
||||
>
|
||||
{filterType}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={isFilterTypeDropdownOpen}
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
data-testid="filter-type-dropdown-item"
|
||||
key="filter-type"
|
||||
>
|
||||
{filterType === FilterType.Name ? t("protocol") : t("name")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
}
|
||||
toolbarItem={
|
||||
filterType === FilterType.Protocol && (
|
||||
|
@ -244,39 +248,40 @@ export const AddScopeDialog = ({
|
|||
onFilterTypeDropdownSelect(filterType);
|
||||
}}
|
||||
data-testid="filter-type-dropdown"
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
id="toggle-id-9"
|
||||
onToggle={toggleIsFilterTypeDropdownOpen}
|
||||
toggleIndicator={CaretDownIcon}
|
||||
onClick={toggleIsFilterTypeDropdownOpen}
|
||||
statusIcon={<CaretDownIcon />}
|
||||
icon={<FilterIcon />}
|
||||
>
|
||||
{filterType}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={isFilterTypeDropdownOpen}
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
data-testid="filter-type-dropdown-item"
|
||||
key="filter-type"
|
||||
>
|
||||
{t("name")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
<Select
|
||||
variant={SelectVariant.single}
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
<KeycloakSelect
|
||||
className="kc-protocolType-select"
|
||||
aria-label={t("selectOne")}
|
||||
onToggle={toggleIsProtocolTypeDropdownOpen}
|
||||
onSelect={(_, value) =>
|
||||
onSelect={(value) =>
|
||||
onProtocolTypeDropdownSelect(value.toString())
|
||||
}
|
||||
selections={protocolType}
|
||||
isOpen={isProtocolTypeDropdownOpen}
|
||||
>
|
||||
{protocolTypeOptions}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ import {
|
|||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
KebabToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import { EllipsisVIcon } from "@patternfly/react-icons";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
|
@ -297,12 +297,21 @@ export const ClientScopes = ({
|
|||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Dropdown
|
||||
toggle={
|
||||
<KebabToggle onToggle={() => setKebabOpen(!kebabOpen)} />
|
||||
}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="kebab"
|
||||
aria-label="Kebab toggle"
|
||||
ref={ref}
|
||||
variant="plain"
|
||||
onClick={() => setKebabOpen(!kebabOpen)}
|
||||
isExpanded={kebabOpen}
|
||||
>
|
||||
<EllipsisVIcon />
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={kebabOpen}
|
||||
isPlain
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
key="deleteAll"
|
||||
isDisabled={selectedRows.length === 0}
|
||||
|
@ -329,9 +338,9 @@ export const ClientScopes = ({
|
|||
}}
|
||||
>
|
||||
{t("remove")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
Grid,
|
||||
GridItem,
|
||||
PageSection,
|
||||
SelectOption,
|
||||
Split,
|
||||
SplitItem,
|
||||
Tab,
|
||||
|
@ -18,11 +19,6 @@ import {
|
|||
Text,
|
||||
TextContent,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { QuestionCircleIcon } from "@patternfly/react-icons";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
|
@ -39,6 +35,10 @@ import { useFetch } from "../../utils/useFetch";
|
|||
import { GeneratedCodeTab } from "./GeneratedCodeTab";
|
||||
|
||||
import "./evaluate.css";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../../components/select/KeycloakSelect";
|
||||
|
||||
export type EvaluateScopesProps = {
|
||||
clientId: string;
|
||||
|
@ -250,14 +250,14 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
|
|||
>
|
||||
<Split hasGutter>
|
||||
<SplitItem isFilled>
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId="scopeParameter"
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
typeAheadAriaLabel={t("scopeParameter")}
|
||||
onToggle={() => setIsScopeOpen(!isScopeOpen)}
|
||||
isOpen={isScopeOpen}
|
||||
selections={selected}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
const option = value as string;
|
||||
if (selected.includes(option)) {
|
||||
if (option !== prefix) {
|
||||
|
@ -273,7 +273,7 @@ export const EvaluateScopes = ({ clientId, protocol }: EvaluateScopesProps) => {
|
|||
{selectableScopes.map((option, index) => (
|
||||
<SelectOption key={index} value={option.name} />
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
</SplitItem>
|
||||
<SplitItem>
|
||||
<ClipboardCopy className="keycloak__scopes_evaluate__clipboard-copy">
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
|
||||
.keycloak__client-scopes__searchtype button {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.keycloak__client-scopes-add__add-dropdown {
|
||||
margin-right: var(--pf-v5-global--spacer--md);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
|
||||
|
||||
import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import {
|
||||
DropdownItem,
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectProps,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import type { TFunction } from "i18next";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toUpperCase } from "../../util";
|
||||
import {
|
||||
DropdownItem,
|
||||
MenuToggle,
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectProps,
|
||||
} from "@patternfly/react-core";
|
||||
|
||||
export enum ClientScope {
|
||||
default = "default",
|
||||
|
@ -50,11 +51,12 @@ export const clientScopeTypesDropdown = (
|
|||
</DropdownItem>
|
||||
));
|
||||
|
||||
type CellDropdownProps = Omit<SelectProps, "onToggle"> & {
|
||||
type CellDropdownProps = Omit<SelectProps, "toggle"> & {
|
||||
clientScope: ClientScopeRepresentation;
|
||||
type: ClientScopeType | AllClientScopeType;
|
||||
all?: boolean;
|
||||
onSelect: (value: ClientScopeType | AllClientScopeType) => void;
|
||||
isDisabled?: boolean;
|
||||
};
|
||||
|
||||
export const CellDropdown = ({
|
||||
|
@ -62,6 +64,7 @@ export const CellDropdown = ({
|
|||
type,
|
||||
onSelect,
|
||||
all = false,
|
||||
isDisabled,
|
||||
...props
|
||||
}: CellDropdownProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -69,11 +72,21 @@ export const CellDropdown = ({
|
|||
|
||||
return (
|
||||
<Select
|
||||
className={`keycloak__client-scope__${type}`}
|
||||
key={clientScope.id}
|
||||
onToggle={() => setOpen(!open)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="cell-dropdown"
|
||||
className={`keycloak__client-scope__${type}`}
|
||||
ref={ref}
|
||||
onClick={() => setOpen(!open)}
|
||||
isExpanded={open}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
{t(`clientScopeType.${type}`)}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={open}
|
||||
selections={[type]}
|
||||
selected={[type]}
|
||||
onSelect={(_, value) => {
|
||||
onSelect(
|
||||
all ? (value as ClientScopeType) : (value as AllClientScopeType),
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
||||
import type { ClientQuery } from "@keycloak/keycloak-admin-client/lib/resources/clients";
|
||||
import { SelectProps, SelectVariant } from "@patternfly/react-core/deprecated";
|
||||
import { SelectControl, SelectVariant } from "@keycloak/keycloak-ui-shared";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SelectControl } from "@keycloak/keycloak-ui-shared";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { useFetch } from "../../utils/useFetch";
|
||||
import type { ComponentProps } from "../dynamic/components";
|
||||
|
||||
type ClientSelectProps = ComponentProps & Pick<SelectProps, "variant">;
|
||||
type ClientSelectProps = ComponentProps & { variant?: `${SelectVariant}` };
|
||||
|
||||
export const ClientSelect = ({
|
||||
name,
|
||||
|
@ -17,7 +16,7 @@ export const ClientSelect = ({
|
|||
defaultValue,
|
||||
isDisabled = false,
|
||||
required = false,
|
||||
variant = SelectVariant.typeahead,
|
||||
variant = "typeahead",
|
||||
}: ClientSelectProps) => {
|
||||
const { adminClient } = useAdminClient();
|
||||
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
import { fetchWithError } from "@keycloak/keycloak-admin-client";
|
||||
import { HelpItem, useHelp } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
Form,
|
||||
FormGroup,
|
||||
MenuToggle,
|
||||
ModalVariant,
|
||||
Select,
|
||||
SelectList,
|
||||
SelectOption,
|
||||
Stack,
|
||||
StackItem,
|
||||
TextArea,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { saveAs } from "file-saver";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { HelpItem, useHelp } from "@keycloak/keycloak-ui-shared";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
|
||||
|
@ -125,29 +124,39 @@ export const DownloadDialog = ({
|
|||
}
|
||||
>
|
||||
<Select
|
||||
toggleId="type"
|
||||
isOpen={openType}
|
||||
onToggle={(_event, isExpanded) => setOpenType(isExpanded)}
|
||||
variant={SelectVariant.single}
|
||||
value={selected}
|
||||
selections={selected}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
id="type"
|
||||
ref={ref}
|
||||
onClick={() => setOpenType(!openType)}
|
||||
isExpanded={openType}
|
||||
>
|
||||
{selected}
|
||||
</MenuToggle>
|
||||
)}
|
||||
selected={selected}
|
||||
onSelect={(_, value) => {
|
||||
setSelected(value.toString());
|
||||
setSelected(value?.toString() || "");
|
||||
setOpenType(false);
|
||||
}}
|
||||
aria-label="Select Input"
|
||||
menuAppendTo={() => document.body}
|
||||
aria-label={t("selectOne")}
|
||||
popperProps={{
|
||||
appendTo: document.body,
|
||||
}}
|
||||
>
|
||||
{configFormats.map((configFormat) => (
|
||||
<SelectOption
|
||||
key={configFormat.id}
|
||||
value={configFormat.id}
|
||||
isSelected={selected === configFormat.id}
|
||||
description={enabled ? configFormat.helpText : undefined}
|
||||
>
|
||||
{configFormat.displayType}
|
||||
</SelectOption>
|
||||
))}
|
||||
<SelectList>
|
||||
{configFormats.map((configFormat) => (
|
||||
<SelectOption
|
||||
key={configFormat.id}
|
||||
value={configFormat.id}
|
||||
isSelected={selected === configFormat.id}
|
||||
description={enabled ? configFormat.helpText : undefined}
|
||||
>
|
||||
{configFormat.displayType}
|
||||
</SelectOption>
|
||||
))}
|
||||
</SelectList>
|
||||
</Select>
|
||||
</FormGroup>
|
||||
</StackItem>
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
import { FormGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import { FormGroup, SelectOption } from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import type { ComponentProps } from "./components";
|
||||
import { convertToName } from "./DynamicComponents";
|
||||
import type { ComponentProps } from "./components";
|
||||
import { KeycloakSelect, SelectVariant } from "../select/KeycloakSelect";
|
||||
|
||||
export const ListComponent = ({
|
||||
name,
|
||||
|
@ -38,11 +33,11 @@ export const ListComponent = ({
|
|||
defaultValue={defaultValue || options?.[0] || ""}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId={name}
|
||||
isDisabled={isDisabled}
|
||||
onToggle={(_event, toggle) => setOpen(toggle)}
|
||||
onSelect={(_, value) => {
|
||||
onToggle={(toggle) => setOpen(toggle)}
|
||||
onSelect={(value) => {
|
||||
field.onChange(value as string);
|
||||
setOpen(false);
|
||||
}}
|
||||
|
@ -56,9 +51,11 @@ export const ListComponent = ({
|
|||
selected={option === field.value}
|
||||
key={option}
|
||||
value={option}
|
||||
/>
|
||||
>
|
||||
{option}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
import { FormGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import { FormGroup, SelectOption } from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import type { ComponentProps } from "./components";
|
||||
import { KeycloakSelect, SelectVariant } from "../select/KeycloakSelect";
|
||||
import { convertToName } from "./DynamicComponents";
|
||||
import type { ComponentProps } from "./components";
|
||||
|
||||
function stringToMultiline(value?: string): string[] {
|
||||
return typeof value === "string" && value.length > 0 ? value.split("##") : [];
|
||||
|
@ -46,7 +41,7 @@ export const MultiValuedListComponent = ({
|
|||
control={control}
|
||||
defaultValue={defaultValue ? [defaultValue] : []}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId={name}
|
||||
data-testid={name}
|
||||
isDisabled={isDisabled}
|
||||
|
@ -57,11 +52,11 @@ export const MultiValuedListComponent = ({
|
|||
}}
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
typeAheadAriaLabel="Select"
|
||||
onToggle={(_event, isOpen) => setOpen(isOpen)}
|
||||
onToggle={(isOpen) => setOpen(isOpen)}
|
||||
selections={
|
||||
stringify ? stringToMultiline(field.value) : field.value
|
||||
}
|
||||
onSelect={(_, v) => {
|
||||
onSelect={(v) => {
|
||||
const option = v.toString();
|
||||
const values = stringify
|
||||
? stringToMultiline(field.value)
|
||||
|
@ -74,17 +69,18 @@ export const MultiValuedListComponent = ({
|
|||
}
|
||||
field.onChange(stringify ? toStringValue(newValue) : newValue);
|
||||
}}
|
||||
onClear={(event) => {
|
||||
event.stopPropagation();
|
||||
onClear={() => {
|
||||
field.onChange(stringify ? "" : []);
|
||||
}}
|
||||
isOpen={open}
|
||||
aria-label={t(label!)}
|
||||
>
|
||||
{options?.map((option) => (
|
||||
<SelectOption key={option} value={option} />
|
||||
<SelectOption key={option} value={option}>
|
||||
{option}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import {
|
||||
Divider,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
Split,
|
||||
SplitItem,
|
||||
Switch,
|
||||
TextContent,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { ExternalLinkAltIcon, HelpIcon } from "@patternfly/react-icons";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -60,20 +59,23 @@ export const HelpHeader = () => {
|
|||
];
|
||||
return (
|
||||
<Dropdown
|
||||
position="right"
|
||||
isPlain
|
||||
popperProps={{
|
||||
position: "right",
|
||||
}}
|
||||
isOpen={open}
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
toggleIndicator={null}
|
||||
onToggle={() => setOpen(!open)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
variant="plain"
|
||||
onClick={() => setOpen(!open)}
|
||||
aria-label="Help"
|
||||
id="help"
|
||||
>
|
||||
<HelpIcon />
|
||||
</DropdownToggle>
|
||||
}
|
||||
dropdownItems={dropdownItems}
|
||||
/>
|
||||
</MenuToggle>
|
||||
)}
|
||||
>
|
||||
<DropdownList>{dropdownItems}</DropdownList>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import { Grid, GridItem, TextInput } from "@patternfly/react-core";
|
||||
import { Select, SelectOption } from "@patternfly/react-core/deprecated";
|
||||
import {
|
||||
Grid,
|
||||
GridItem,
|
||||
SelectOption,
|
||||
TextInput,
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { UseControllerProps, useController } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import useToggle from "../../utils/useToggle";
|
||||
import { DefaultValue } from "./KeyValueInput";
|
||||
import { KeycloakSelect } from "../select/KeycloakSelect";
|
||||
|
||||
type KeySelectProp = UseControllerProps & {
|
||||
selectItems: DefaultValue[];
|
||||
|
@ -22,10 +26,10 @@ export const KeySelect = ({ selectItems, ...rest }: KeySelectProp) => {
|
|||
return (
|
||||
<Grid>
|
||||
<GridItem lg={custom ? 2 : 12}>
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
onToggle={() => toggle()}
|
||||
isOpen={open}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
if (value) {
|
||||
setCustom(false);
|
||||
}
|
||||
|
@ -44,7 +48,7 @@ export const KeySelect = ({ selectItems, ...rest }: KeySelectProp) => {
|
|||
</SelectOption>
|
||||
)),
|
||||
]}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
</GridItem>
|
||||
{custom && (
|
||||
<GridItem lg={10}>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { TextInput } from "@patternfly/react-core";
|
||||
import { Select, SelectOption } from "@patternfly/react-core/deprecated";
|
||||
import { SelectOption, TextInput } from "@patternfly/react-core";
|
||||
import { useMemo, useState } from "react";
|
||||
import { UseControllerProps, useController } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { KeycloakSelect } from "../select/KeycloakSelect";
|
||||
import { DefaultValue } from "./KeyValueInput";
|
||||
|
||||
type ValueSelectProps = UseControllerProps & {
|
||||
|
@ -26,20 +25,20 @@ export const ValueSelect = ({
|
|||
);
|
||||
|
||||
return defaultItem?.values ? (
|
||||
<Select
|
||||
onToggle={(_event, isOpen) => setOpen(isOpen)}
|
||||
<KeycloakSelect
|
||||
onToggle={(isOpen) => setOpen(isOpen)}
|
||||
isOpen={open}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
field.onChange(value);
|
||||
setOpen(false);
|
||||
}}
|
||||
selections={field.value ? [field.value] : t("choose")}
|
||||
placeholder={t("valuePlaceholder")}
|
||||
placeholderText={t("valuePlaceholder")}
|
||||
>
|
||||
{defaultItem.values.map((item) => (
|
||||
<SelectOption key={item} value={item} />
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
) : (
|
||||
<TextInput
|
||||
aria-label={t("customValue")}
|
||||
|
|
|
@ -4,15 +4,19 @@ import {
|
|||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Dropdown,
|
||||
DropdownList,
|
||||
Flex,
|
||||
FlexItem,
|
||||
Label,
|
||||
MenuToggle,
|
||||
MenuToggleElement,
|
||||
} from "@patternfly/react-core";
|
||||
import { Dropdown, KebabToggle } from "@patternfly/react-core/deprecated";
|
||||
import { ReactElement, useState } from "react";
|
||||
import { Link, To } from "react-router-dom";
|
||||
|
||||
import "./keycloak-card.css";
|
||||
import { EllipsisVIcon } from "@patternfly/react-icons";
|
||||
|
||||
export type KeycloakCardProps = {
|
||||
title: string;
|
||||
|
@ -38,18 +42,28 @@ export const KeycloakCard = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<Card isSelectable>
|
||||
<Card isSelectable isClickable>
|
||||
<CardHeader
|
||||
actions={{
|
||||
actions: dropdownItems ? (
|
||||
<Dropdown
|
||||
data-testid={`${title}-dropdown`}
|
||||
isPlain
|
||||
position={"right"}
|
||||
toggle={<KebabToggle onToggle={onDropdownToggle} />}
|
||||
popperProps={{
|
||||
position: "right",
|
||||
}}
|
||||
toggle={(ref: React.Ref<MenuToggleElement>) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
onClick={onDropdownToggle}
|
||||
variant="plain"
|
||||
data-testid={`${title}-dropdown`}
|
||||
>
|
||||
<EllipsisVIcon />
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={isDropdownOpen}
|
||||
dropdownItems={dropdownItems}
|
||||
/>
|
||||
>
|
||||
<DropdownList>{dropdownItems}</DropdownList>
|
||||
</Dropdown>
|
||||
) : undefined,
|
||||
hasNoOffset: false,
|
||||
className: undefined,
|
||||
|
|
|
@ -1,30 +1,27 @@
|
|||
import { label } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
Button,
|
||||
Divider,
|
||||
Dropdown,
|
||||
DropdownGroup,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
Label,
|
||||
MenuToggle,
|
||||
SearchInput,
|
||||
Spinner,
|
||||
Split,
|
||||
SplitItem,
|
||||
Stack,
|
||||
StackItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
ContextSelector,
|
||||
ContextSelectorItem,
|
||||
ContextSelectorItemProps,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { CheckIcon } from "@patternfly/react-icons";
|
||||
import { Fragment, useState, useMemo } from "react";
|
||||
import { Fragment, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, To, useHref } from "react-router-dom";
|
||||
import { label } from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { useRealms } from "../../context/RealmsContext";
|
||||
import { useRecentRealms } from "../../context/RecentRealms";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { useWhoAmI } from "../../context/whoami/WhoAmI";
|
||||
import { toDashboard } from "../../dashboard/routes/Dashboard";
|
||||
import { toAddRealm } from "../../realm/routes/AddRealm";
|
||||
|
@ -83,23 +80,6 @@ const RealmText = ({ name, displayName, showIsRecent }: RealmTextProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
// We need to make all these props partial because of a bug in PatternFly.
|
||||
// See: https://github.com/patternfly/patternfly-react/pull/8670
|
||||
// TODO: Remove this partial when a fix has been released.
|
||||
type ContextSelectorItemLinkProps = Partial<
|
||||
Omit<ContextSelectorItemProps, "href">
|
||||
> & {
|
||||
to: To;
|
||||
};
|
||||
|
||||
const ContextSelectorItemLink = ({
|
||||
to,
|
||||
...props
|
||||
}: ContextSelectorItemLinkProps) => {
|
||||
const href = useHref(to);
|
||||
return <ContextSelectorItem {...props} href={href} />;
|
||||
};
|
||||
|
||||
export const RealmSelector = () => {
|
||||
const { realm } = useRealm();
|
||||
const { realms } = useRealms();
|
||||
|
@ -108,11 +88,11 @@ export const RealmSelector = () => {
|
|||
const [search, setSearch] = useState("");
|
||||
const { t } = useTranslation();
|
||||
const recentRealms = useRecentRealms();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const all = useMemo(
|
||||
() =>
|
||||
realms
|
||||
.filter((r) => r.name !== realm)
|
||||
.map((realm) => {
|
||||
const used = recentRealms.some((name) => name === realm.name);
|
||||
return { realm, used };
|
||||
|
@ -149,82 +129,72 @@ export const RealmSelector = () => {
|
|||
[realm, realms],
|
||||
);
|
||||
|
||||
return realms.length > 5 ? (
|
||||
<ContextSelector
|
||||
data-testid="realmSelector"
|
||||
toggleText={label(t, realmDisplayName, realm)}
|
||||
isOpen={open}
|
||||
screenReaderLabel={label(t, realmDisplayName, realm)}
|
||||
onToggle={() => setOpen(!open)}
|
||||
searchInputValue={search}
|
||||
onSearchInputChange={(event, value) => setSearch(value)}
|
||||
className="keycloak__realm_selector__context_selector"
|
||||
footer={
|
||||
whoAmI.canCreateRealm() && (
|
||||
<ContextSelectorItem key="add">
|
||||
<AddRealm onClick={() => setOpen(false)} />
|
||||
</ContextSelectorItem>
|
||||
)
|
||||
}
|
||||
>
|
||||
{filteredItems.map((item) => (
|
||||
<ContextSelectorItemLink
|
||||
key={item.realm.name}
|
||||
to={toDashboard({ realm: item.realm.name })}
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<RealmText {...item.realm} showIsRecent={item.used} />{" "}
|
||||
</ContextSelectorItemLink>
|
||||
))}
|
||||
</ContextSelector>
|
||||
) : (
|
||||
return (
|
||||
<Dropdown
|
||||
id="realm-select"
|
||||
data-testid="realmSelector"
|
||||
className="keycloak__realm_selector__dropdown"
|
||||
isOpen={open}
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
data-testid="realmSelectorToggle"
|
||||
onToggle={() => {
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
data-testid="realmSelector"
|
||||
onClick={() => {
|
||||
setOpen(!open);
|
||||
}}
|
||||
className="keycloak__realm_selector_dropdown__toggle"
|
||||
isFullWidth
|
||||
>
|
||||
{label(t, realmDisplayName, realm)}
|
||||
</DropdownToggle>
|
||||
}
|
||||
dropdownItems={(realms.length !== 0
|
||||
? realms.map((realm) => (
|
||||
<DropdownItem
|
||||
key={realm.name}
|
||||
component={
|
||||
<Link
|
||||
to={toDashboard({ realm: realm.name })}
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<RealmText {...realm} />
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
))
|
||||
: [
|
||||
<DropdownItem key="loader">
|
||||
<Spinner size="sm" /> {t("loadingRealms")}
|
||||
</DropdownItem>,
|
||||
]
|
||||
).concat([
|
||||
<Fragment key="add-realm">
|
||||
{whoAmI.canCreateRealm() && (
|
||||
<>
|
||||
<Divider key="divider" />
|
||||
<DropdownItem key="add" component="div">
|
||||
<AddRealm onClick={() => setOpen(false)} />
|
||||
</MenuToggle>
|
||||
)}
|
||||
>
|
||||
<DropdownList>
|
||||
{realms.length > 5 && (
|
||||
<>
|
||||
<DropdownGroup>
|
||||
<DropdownList>
|
||||
<SearchInput
|
||||
value={search}
|
||||
onChange={(_, value) => setSearch(value)}
|
||||
onClear={() => setSearch("")}
|
||||
/>
|
||||
</DropdownList>
|
||||
</DropdownGroup>
|
||||
<Divider component="li" />
|
||||
</>
|
||||
)}
|
||||
{(realms.length !== 0
|
||||
? filteredItems.map((i) => (
|
||||
<DropdownItem
|
||||
key={i.realm.name}
|
||||
onClick={() => {
|
||||
navigate(toDashboard({ realm: i.realm.name }));
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<RealmText
|
||||
{...i.realm}
|
||||
showIsRecent={realms.length > 5 && i.used}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</>
|
||||
)}
|
||||
</Fragment>,
|
||||
])}
|
||||
/>
|
||||
))
|
||||
: [
|
||||
<DropdownItem key="loader">
|
||||
<Spinner size="sm" /> {t("loadingRealms")}
|
||||
</DropdownItem>,
|
||||
]
|
||||
).concat([
|
||||
<Fragment key="add-realm">
|
||||
{whoAmI.canCreateRealm() && (
|
||||
<>
|
||||
<Divider key="divider" />
|
||||
<DropdownItem key="add" component="div">
|
||||
<AddRealm onClick={() => setOpen(false)} />
|
||||
</DropdownItem>
|
||||
</>
|
||||
)}
|
||||
</Fragment>,
|
||||
])}
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,45 +1,13 @@
|
|||
.keycloak__realm_selector_dropdown__toggle {
|
||||
--pf-v5-c-dropdown__toggle--Color: var(--pf-v5-c-nav__link--m-current--Color);
|
||||
--pf-v5-c-dropdown__toggle--BackgroundColor: var(
|
||||
--pf-v5-global--BackgroundColor--dark-100
|
||||
);
|
||||
--pf-v5-c-dropdown__toggle--before--BorderTopColor: var(
|
||||
--pf-v5-global--BorderColor--200
|
||||
);
|
||||
--pf-v5-c-dropdown__toggle--before--BorderRightColor: var(
|
||||
--pf-v5-global--BorderColor--200
|
||||
);
|
||||
--pf-v5-c-dropdown__toggle--before--BorderBottomColor: var(
|
||||
--pf-v5-global--BorderColor--100
|
||||
);
|
||||
--pf-v5-c-dropdown__toggle--before--BorderLeftColor: var(
|
||||
--pf-v5-global--BorderColor--200
|
||||
);
|
||||
width: 100%;
|
||||
.keycloak__realm_selector__dropdown .pf-v5-c-menu__list .pf-m-fill {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.keycloak__realm_selector__dropdown .pf-v5-c-dropdown__menu {
|
||||
.keycloak__realm_selector__dropdown .pf-v5-c-menu__list {
|
||||
min-width: 0;
|
||||
width: 15.125rem;
|
||||
|
||||
}
|
||||
.keycloak__realm_selector__dropdown .pf-v5-c-dropdown__menu .pf-m-fill {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.pf-v5-c-context-selector.keycloak__realm_selector__context_selector {
|
||||
--pf-v5-c-context-selector__toggle--Color: var(--pf-v5-c-nav__link--m-current--Color);
|
||||
}
|
||||
|
||||
.keycloak__realm_selector__dropdown {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.keycloak__realm_selector__list-item-split {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.pf-v5-c-nav__item.keycloak__page_nav__nav_item__realm-selector {
|
||||
margin-top: var(--pf-v5-c-nav__link--PaddingTop);
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
Modal,
|
||||
ModalVariant,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { FilterIcon } from "@patternfly/react-icons";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -150,26 +149,28 @@ export const AddRoleMappingModal = ({
|
|||
setSearchToggle(false);
|
||||
refresh();
|
||||
}}
|
||||
data-testid="filter-type-dropdown"
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
onToggle={(_event, val) => setSearchToggle(val)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid="filter-type-dropdown"
|
||||
ref={ref}
|
||||
onClick={() => setSearchToggle(!searchToggle)}
|
||||
icon={<FilterIcon />}
|
||||
>
|
||||
{filterType === "roles"
|
||||
? t("filterByRoles")
|
||||
: t("filterByClients")}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={searchToggle}
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem key="filter-type" data-testid={filterType}>
|
||||
{filterType === "roles"
|
||||
? t("filterByClients")
|
||||
: t("filterByRoles")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
)
|
||||
}
|
||||
|
|
49
js/apps/admin-ui/src/components/select/KeycloakSelect.tsx
Normal file
49
js/apps/admin-ui/src/components/select/KeycloakSelect.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { ChipGroupProps, SelectProps } from "@patternfly/react-core";
|
||||
import { SingleSelect } from "./SingleSelect";
|
||||
import { TypeaheadSelect } from "./TypeaheadSelect";
|
||||
|
||||
export type Variant = `${SelectVariant}`;
|
||||
|
||||
export enum SelectVariant {
|
||||
single = "single",
|
||||
typeahead = "typeahead",
|
||||
typeaheadMulti = "typeaheadMulti",
|
||||
}
|
||||
|
||||
export const propertyToString = (prop: string | number | undefined) =>
|
||||
typeof prop === "number" ? prop + "px" : prop;
|
||||
|
||||
export type KeycloakSelectProps<> = Omit<
|
||||
SelectProps,
|
||||
"name" | "toggle" | "selected" | "onClick" | "onSelect"
|
||||
> & {
|
||||
toggleId?: string;
|
||||
onFilter?: (value: string) => JSX.Element[];
|
||||
onClear?: () => void;
|
||||
variant?: Variant;
|
||||
isDisabled?: boolean;
|
||||
menuAppendTo?: string;
|
||||
maxHeight?: string | number;
|
||||
width?: string | number;
|
||||
toggleIcon?: React.ReactElement;
|
||||
direction?: "up" | "down";
|
||||
placeholderText?: string;
|
||||
onSelect?: (value: string | number | object) => void;
|
||||
onToggle: (val: boolean) => void;
|
||||
selections?: string | string[] | number | number[];
|
||||
validated?: "success" | "warning" | "error" | "default";
|
||||
typeAheadAriaLabel?: string;
|
||||
chipGroupProps?: Omit<ChipGroupProps, "children" | "ref">;
|
||||
chipGroupComponent?: React.ReactNode;
|
||||
footer?: React.ReactNode;
|
||||
};
|
||||
export const KeycloakSelect = ({
|
||||
variant = SelectVariant.single,
|
||||
...rest
|
||||
}: KeycloakSelectProps) => {
|
||||
if (variant === SelectVariant.single) {
|
||||
return <SingleSelect {...rest} />;
|
||||
} else {
|
||||
return <TypeaheadSelect {...rest} variant={variant} />;
|
||||
}
|
||||
};
|
84
js/apps/admin-ui/src/components/select/SingleSelect.tsx
Normal file
84
js/apps/admin-ui/src/components/select/SingleSelect.tsx
Normal file
|
@ -0,0 +1,84 @@
|
|||
import {
|
||||
MenuToggle,
|
||||
Select,
|
||||
SelectList,
|
||||
SelectOptionProps,
|
||||
} from "@patternfly/react-core";
|
||||
import { Children, useRef, useState } from "react";
|
||||
import { KeycloakSelectProps, propertyToString } from "./KeycloakSelect";
|
||||
|
||||
type SingleSelectProps = Omit<KeycloakSelectProps, "variant">;
|
||||
|
||||
export const SingleSelect = ({
|
||||
toggleId,
|
||||
onToggle,
|
||||
onSelect,
|
||||
selections,
|
||||
isOpen,
|
||||
menuAppendTo,
|
||||
direction,
|
||||
width,
|
||||
maxHeight,
|
||||
toggleIcon,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: SingleSelectProps) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const ref = useRef<HTMLElement>();
|
||||
const toggle = () => {
|
||||
setOpen(!open);
|
||||
onToggle(!open);
|
||||
};
|
||||
|
||||
const append = () => {
|
||||
if (menuAppendTo === "parent") {
|
||||
return ref.current?.parentElement || "inline";
|
||||
}
|
||||
return "inline";
|
||||
};
|
||||
|
||||
const childArray = Children.toArray(
|
||||
children,
|
||||
) as React.ReactElement<SelectOptionProps>[];
|
||||
|
||||
return (
|
||||
<Select
|
||||
ref={ref}
|
||||
maxMenuHeight={propertyToString(maxHeight)}
|
||||
isScrollable
|
||||
popperProps={{
|
||||
appendTo: append(),
|
||||
direction,
|
||||
width: propertyToString(width),
|
||||
}}
|
||||
{...props}
|
||||
onClick={toggle}
|
||||
selected={selections}
|
||||
onSelect={(_, value) => {
|
||||
onSelect?.(value || "");
|
||||
toggle();
|
||||
}}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
id={toggleId}
|
||||
ref={ref}
|
||||
className={className}
|
||||
onClick={toggle}
|
||||
isExpanded={isOpen}
|
||||
aria-label={props["aria-label"]}
|
||||
icon={toggleIcon}
|
||||
isFullWidth
|
||||
>
|
||||
{childArray.find((c) => c.props.value === selections)?.props
|
||||
.children ||
|
||||
selections ||
|
||||
props["aria-label"]}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={isOpen}
|
||||
>
|
||||
<SelectList>{children}</SelectList>
|
||||
</Select>
|
||||
);
|
||||
};
|
184
js/apps/admin-ui/src/components/select/TypeaheadSelect.tsx
Normal file
184
js/apps/admin-ui/src/components/select/TypeaheadSelect.tsx
Normal file
|
@ -0,0 +1,184 @@
|
|||
import {
|
||||
Button,
|
||||
Chip,
|
||||
ChipGroup,
|
||||
MenuFooter,
|
||||
MenuToggle,
|
||||
MenuToggleStatus,
|
||||
Select,
|
||||
SelectList,
|
||||
SelectOptionProps,
|
||||
TextInputGroup,
|
||||
TextInputGroupMain,
|
||||
TextInputGroupUtilities,
|
||||
} from "@patternfly/react-core";
|
||||
import { TimesIcon } from "@patternfly/react-icons";
|
||||
import { Children, useRef, useState } from "react";
|
||||
import {
|
||||
KeycloakSelectProps,
|
||||
SelectVariant,
|
||||
propertyToString,
|
||||
} from "./KeycloakSelect";
|
||||
|
||||
export const TypeaheadSelect = ({
|
||||
toggleId,
|
||||
onSelect,
|
||||
onToggle,
|
||||
onFilter,
|
||||
variant,
|
||||
validated,
|
||||
placeholderText,
|
||||
maxHeight,
|
||||
width,
|
||||
toggleIcon,
|
||||
direction,
|
||||
selections,
|
||||
typeAheadAriaLabel,
|
||||
chipGroupComponent,
|
||||
chipGroupProps,
|
||||
footer,
|
||||
children,
|
||||
...rest
|
||||
}: KeycloakSelectProps) => {
|
||||
const [filterValue, setFilterValue] = useState("");
|
||||
const [focusedItemIndex, setFocusedItemIndex] = useState<number>(0);
|
||||
const textInputRef = useRef<HTMLInputElement>();
|
||||
|
||||
const childArray = Children.toArray(
|
||||
children,
|
||||
) as React.ReactElement<SelectOptionProps>[];
|
||||
|
||||
const toggle = () => {
|
||||
onToggle?.(!rest.isOpen);
|
||||
};
|
||||
|
||||
const onInputKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
const focusedItem = childArray[focusedItemIndex];
|
||||
onToggle?.(true);
|
||||
|
||||
switch (event.key) {
|
||||
case "Enter": {
|
||||
event.preventDefault();
|
||||
|
||||
if (variant !== SelectVariant.typeaheadMulti) {
|
||||
setFilterValue(focusedItem.props.value);
|
||||
} else {
|
||||
setFilterValue("");
|
||||
}
|
||||
onSelect?.(focusedItem.props.value);
|
||||
onToggle?.(false);
|
||||
setFocusedItemIndex(0);
|
||||
|
||||
break;
|
||||
}
|
||||
case "Escape": {
|
||||
onToggle?.(false);
|
||||
break;
|
||||
}
|
||||
case "ArrowUp":
|
||||
case "ArrowDown": {
|
||||
event.preventDefault();
|
||||
|
||||
let indexToFocus = 0;
|
||||
|
||||
if (event.key === "ArrowUp") {
|
||||
if (focusedItemIndex === 0) {
|
||||
indexToFocus = childArray.length - 1;
|
||||
} else {
|
||||
indexToFocus = focusedItemIndex - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.key === "ArrowDown") {
|
||||
if (focusedItemIndex === childArray.length - 1) {
|
||||
indexToFocus = 0;
|
||||
} else {
|
||||
indexToFocus = focusedItemIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
setFocusedItemIndex(indexToFocus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
{...rest}
|
||||
onClick={toggle}
|
||||
onSelect={(_, value) => onSelect?.(value || "")}
|
||||
maxMenuHeight={propertyToString(maxHeight)}
|
||||
popperProps={{ direction, width: propertyToString(width) }}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
id={toggleId}
|
||||
variant="typeahead"
|
||||
onClick={() => onToggle?.(true)}
|
||||
icon={toggleIcon}
|
||||
isExpanded={rest.isOpen}
|
||||
isFullWidth
|
||||
status={validated === "error" ? MenuToggleStatus.danger : undefined}
|
||||
>
|
||||
<TextInputGroup isPlain>
|
||||
<TextInputGroupMain
|
||||
placeholder={placeholderText}
|
||||
value={filterValue}
|
||||
onClick={toggle}
|
||||
onChange={(_, value) => {
|
||||
setFilterValue(value);
|
||||
onFilter?.(value);
|
||||
}}
|
||||
onKeyDown={(event) => onInputKeyDown(event)}
|
||||
autoComplete="off"
|
||||
innerRef={textInputRef}
|
||||
role="combobox"
|
||||
isExpanded={rest.isOpen}
|
||||
aria-controls="select-typeahead-listbox"
|
||||
aria-label={typeAheadAriaLabel}
|
||||
>
|
||||
{variant === SelectVariant.typeaheadMulti &&
|
||||
Array.isArray(selections) &&
|
||||
(chipGroupComponent ? (
|
||||
chipGroupComponent
|
||||
) : (
|
||||
<ChipGroup {...chipGroupProps}>
|
||||
{selections.map((selection, index: number) => (
|
||||
<Chip
|
||||
key={index}
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
onSelect?.(selection);
|
||||
}}
|
||||
>
|
||||
{selection}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
))}
|
||||
</TextInputGroupMain>
|
||||
<TextInputGroupUtilities>
|
||||
{!!filterValue && (
|
||||
<Button
|
||||
variant="plain"
|
||||
onClick={() => {
|
||||
onSelect?.("");
|
||||
setFilterValue("");
|
||||
textInputRef?.current?.focus();
|
||||
}}
|
||||
aria-label="Clear input value"
|
||||
>
|
||||
<TimesIcon aria-hidden />
|
||||
</Button>
|
||||
)}
|
||||
</TextInputGroupUtilities>
|
||||
</TextInputGroup>
|
||||
</MenuToggle>
|
||||
)}
|
||||
>
|
||||
<SelectList>{children}</SelectList>
|
||||
{footer && <MenuFooter>{footer}</MenuFooter>}
|
||||
</Select>
|
||||
);
|
||||
};
|
|
@ -1,17 +1,17 @@
|
|||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
SelectOption,
|
||||
Split,
|
||||
SplitItem,
|
||||
TextInput,
|
||||
TextInputProps,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
DropdownProps,
|
||||
Select,
|
||||
SelectOption,
|
||||
KeycloakSelect,
|
||||
KeycloakSelectProps,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
} from "../select/KeycloakSelect";
|
||||
|
||||
export type Unit = "second" | "minute" | "hour" | "day";
|
||||
|
||||
|
@ -28,7 +28,7 @@ export type TimeSelectorProps = Omit<
|
|||
TextInputProps,
|
||||
"onChange" | "defaultValue"
|
||||
> &
|
||||
Pick<DropdownProps, "menuAppendTo"> & {
|
||||
Pick<KeycloakSelectProps, "menuAppendTo"> & {
|
||||
value?: number;
|
||||
units?: Unit[];
|
||||
onChange?: (time: number | string) => void;
|
||||
|
@ -131,17 +131,17 @@ export const TimeSelector = ({
|
|||
/>
|
||||
</SplitItem>
|
||||
<SplitItem id={`${className}-select-menu`}>
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
variant={SelectVariant.single}
|
||||
aria-label={t("unitLabel")}
|
||||
className={`${className}-select`}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
setMultiplier(value as number);
|
||||
updateTimeout(timeValue, value as number);
|
||||
setOpen(false);
|
||||
}}
|
||||
menuAppendTo={menuAppendTo}
|
||||
selections={[multiplier]}
|
||||
selections={multiplier}
|
||||
onToggle={() => {
|
||||
setOpen(!open);
|
||||
}}
|
||||
|
@ -157,7 +157,7 @@ export const TimeSelector = ({
|
|||
{t(time.label)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
);
|
||||
|
|
|
@ -7,25 +7,22 @@ import {
|
|||
ButtonVariant,
|
||||
InputGroup,
|
||||
InputGroupItem,
|
||||
SelectOption,
|
||||
Text,
|
||||
TextContent,
|
||||
TextInput,
|
||||
TextVariants,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { CheckIcon } from "@patternfly/react-icons";
|
||||
import { ReactNode, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form } from "react-router-dom";
|
||||
import { label } from "@keycloak/keycloak-ui-shared";
|
||||
import { SelectVariant, label } from "@keycloak/keycloak-ui-shared";
|
||||
|
||||
import { useAlerts } from "../alert/Alerts";
|
||||
import { UserAttribute } from "./UserDataTable";
|
||||
import { KeycloakSelect } from "../select/KeycloakSelect";
|
||||
|
||||
type UserDataTableAttributeSearchFormProps = {
|
||||
activeFilters: UserAttribute[];
|
||||
|
@ -132,12 +129,12 @@ export function UserDataTableAttributeSearchForm({
|
|||
const createAttributeKeyInputField = () => {
|
||||
if (profile) {
|
||||
return (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
data-testid="search-attribute-name"
|
||||
variant={SelectVariant.typeahead}
|
||||
onToggle={(_event, isOpen) => setSelectAttributeKeyOpen(isOpen)}
|
||||
onToggle={(isOpen) => setSelectAttributeKeyOpen(isOpen)}
|
||||
selections={getValues().displayName}
|
||||
onSelect={(_, selectedValue) => {
|
||||
onSelect={(selectedValue) => {
|
||||
setValue("displayName", selectedValue.toString());
|
||||
if (isAttributeKeyDuplicate()) {
|
||||
setError("name", { type: "conflict" });
|
||||
|
@ -165,7 +162,7 @@ export function UserDataTableAttributeSearchForm({
|
|||
}}
|
||||
/>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
|
|
|
@ -7,13 +7,12 @@ import {
|
|||
SearchInput,
|
||||
ToolbarItem,
|
||||
InputGroupItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
MenuToggle,
|
||||
DropdownList,
|
||||
DropdownItem,
|
||||
KebabToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { ArrowRightIcon } from "@patternfly/react-icons";
|
||||
} from "@patternfly/react-core";
|
||||
import { ArrowRightIcon, EllipsisVIcon } from "@patternfly/react-icons";
|
||||
import { ReactNode, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
|
@ -170,10 +169,20 @@ export function UserDataTableToolbarItems({
|
|||
) : (
|
||||
<ToolbarItem>
|
||||
<Dropdown
|
||||
toggle={<KebabToggle onToggle={(_event, open) => setKebabOpen(open)} />}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
isExpanded={kebabOpen}
|
||||
variant="plain"
|
||||
onClick={() => setKebabOpen(!kebabOpen)}
|
||||
>
|
||||
<EllipsisVIcon />
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={kebabOpen}
|
||||
isPlain
|
||||
dropdownItems={[
|
||||
shouldFocusToggleOnSelect
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
key="deleteUser"
|
||||
component="button"
|
||||
|
@ -184,7 +193,7 @@ export function UserDataTableToolbarItems({
|
|||
}}
|
||||
>
|
||||
{t("deleteUser")}
|
||||
</DropdownItem>,
|
||||
</DropdownItem>
|
||||
|
||||
<DropdownItem
|
||||
key="unlock"
|
||||
|
@ -195,9 +204,9 @@ export function UserDataTableToolbarItems({
|
|||
}}
|
||||
>
|
||||
{t("unlockAllUsers")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
);
|
||||
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
|
||||
import type { UserQuery } from "@keycloak/keycloak-admin-client/lib/resources/users";
|
||||
import { FormGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
Button,
|
||||
Chip,
|
||||
ChipGroup,
|
||||
FormGroup,
|
||||
MenuToggle,
|
||||
Select,
|
||||
SelectList,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
TextInputGroup,
|
||||
TextInputGroupMain,
|
||||
TextInputGroupUtilities,
|
||||
} from "@patternfly/react-core";
|
||||
import { debounce } from "lodash-es";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FormErrorText, HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
|
@ -15,9 +22,12 @@ import { useAdminClient } from "../../admin-client";
|
|||
import { useFetch } from "../../utils/useFetch";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
import type { ComponentProps } from "../dynamic/components";
|
||||
import { TimesIcon } from "@patternfly/react-icons";
|
||||
|
||||
type UserSelectVariant = "typeaheadMulti" | "typeahead";
|
||||
|
||||
type UserSelectProps = ComponentProps & {
|
||||
variant?: SelectVariant;
|
||||
variant?: UserSelectVariant;
|
||||
isRequired?: boolean;
|
||||
};
|
||||
|
||||
|
@ -27,7 +37,7 @@ export const UserSelect = ({
|
|||
helpText,
|
||||
defaultValue,
|
||||
isRequired,
|
||||
variant = SelectVariant.typeaheadMulti,
|
||||
variant = "typeaheadMulti",
|
||||
}: UserSelectProps) => {
|
||||
const { adminClient } = useAdminClient();
|
||||
|
||||
|
@ -39,9 +49,11 @@ export const UserSelect = ({
|
|||
} = useFormContext();
|
||||
const values: string[] | undefined = getValues(name!);
|
||||
|
||||
const [open, toggleOpen] = useToggle();
|
||||
const [open, toggleOpen, setOpen] = useToggle();
|
||||
const [users, setUsers] = useState<(UserRepresentation | undefined)[]>([]);
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [search, setSearch] = useState("");
|
||||
const textInputRef = useRef<HTMLInputElement>();
|
||||
|
||||
const debounceFn = useCallback(debounce(setSearch, 1000), []);
|
||||
|
||||
|
@ -90,28 +102,97 @@ export const UserSelect = ({
|
|||
defaultValue={defaultValue}
|
||||
control={control}
|
||||
rules={
|
||||
isRequired && variant === SelectVariant.typeaheadMulti
|
||||
isRequired && variant === "typeaheadMulti"
|
||||
? { validate: (value) => value.length > 0 }
|
||||
: { required: isRequired }
|
||||
}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
toggleId={name!}
|
||||
variant={variant}
|
||||
placeholderText={t("selectAUser")}
|
||||
onToggle={toggleOpen}
|
||||
id={name!}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
data-testid={name!}
|
||||
ref={ref}
|
||||
variant="typeahead"
|
||||
onClick={toggleOpen}
|
||||
isExpanded={open}
|
||||
isFullWidth
|
||||
status={errors[name!] ? "danger" : undefined}
|
||||
>
|
||||
<TextInputGroup isPlain>
|
||||
<TextInputGroupMain
|
||||
value={inputValue}
|
||||
onClick={toggleOpen}
|
||||
onChange={(_, value) => {
|
||||
setOpen(true);
|
||||
setInputValue(value);
|
||||
debounceFn(value);
|
||||
}}
|
||||
autoComplete="off"
|
||||
innerRef={textInputRef}
|
||||
placeholderText={t("selectAUser")}
|
||||
{...(field.value && {
|
||||
"aria-activedescendant": field.value,
|
||||
})}
|
||||
role="combobox"
|
||||
isExpanded={open}
|
||||
aria-controls="select-create-typeahead-listbox"
|
||||
>
|
||||
{variant === "typeaheadMulti" &&
|
||||
Array.isArray(field.value) && (
|
||||
<ChipGroup aria-label="Current selections">
|
||||
{field.value.map(
|
||||
(selection: string, index: number) => (
|
||||
<Chip
|
||||
key={index}
|
||||
onClick={(ev) => {
|
||||
ev.stopPropagation();
|
||||
field.onChange(
|
||||
field.value.filter(
|
||||
(item: string) => item !== selection,
|
||||
),
|
||||
);
|
||||
}}
|
||||
>
|
||||
{selection}
|
||||
</Chip>
|
||||
),
|
||||
)}
|
||||
</ChipGroup>
|
||||
)}
|
||||
</TextInputGroupMain>
|
||||
<TextInputGroupUtilities>
|
||||
{!!search && (
|
||||
<Button
|
||||
variant="plain"
|
||||
onClick={() => {
|
||||
setInputValue("");
|
||||
setSearch("");
|
||||
field.onChange([]);
|
||||
textInputRef?.current?.focus();
|
||||
}}
|
||||
aria-label="Clear input value"
|
||||
>
|
||||
<TimesIcon aria-hidden />
|
||||
</Button>
|
||||
)}
|
||||
</TextInputGroupUtilities>
|
||||
</TextInputGroup>
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={open}
|
||||
selections={field.value}
|
||||
onFilter={(_, value) => {
|
||||
debounceFn(value);
|
||||
return convert(users);
|
||||
}}
|
||||
selected={field.value}
|
||||
onSelect={(_, v) => {
|
||||
const option = v.toString();
|
||||
if (variant !== SelectVariant.typeaheadMulti) {
|
||||
field.value.includes(option)
|
||||
? field.onChange([])
|
||||
: field.onChange([option]);
|
||||
const option = v?.toString();
|
||||
if (variant !== "typeaheadMulti") {
|
||||
const removed = field.value.includes(option);
|
||||
removed ? field.onChange([]) : field.onChange([option]);
|
||||
setInputValue(
|
||||
removed
|
||||
? ""
|
||||
: users.find((u) => u?.id === option)?.username || "",
|
||||
);
|
||||
setOpen(false);
|
||||
} else {
|
||||
const changedValue = field.value.find(
|
||||
(v: string) => v === option,
|
||||
|
@ -120,11 +201,10 @@ export const UserSelect = ({
|
|||
: [...field.value, option];
|
||||
field.onChange(changedValue);
|
||||
}
|
||||
toggleOpen();
|
||||
}}
|
||||
aria-label={t(name!)}
|
||||
>
|
||||
{convert(users)}
|
||||
<SelectList>{convert(users)}</SelectList>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -2,8 +2,11 @@ import {
|
|||
Badge,
|
||||
Button,
|
||||
Divider,
|
||||
Dropdown,
|
||||
DropdownList,
|
||||
Level,
|
||||
LevelItem,
|
||||
MenuToggle,
|
||||
PageSection,
|
||||
Switch,
|
||||
Text,
|
||||
|
@ -12,11 +15,6 @@ import {
|
|||
ToolbarContent,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownPosition,
|
||||
DropdownToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import {
|
||||
ReactElement,
|
||||
ReactNode,
|
||||
|
@ -151,20 +149,24 @@ export const ViewHeader = ({
|
|||
{dropdownItems && (
|
||||
<ToolbarItem>
|
||||
<Dropdown
|
||||
position={DropdownPosition.right}
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
popperProps={{
|
||||
position: "right",
|
||||
}}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
isDisabled={isDropdownDisabled}
|
||||
id={actionsDropdownId}
|
||||
onToggle={onDropdownToggle}
|
||||
onClick={onDropdownToggle}
|
||||
data-testid="action-dropdown"
|
||||
>
|
||||
{t("action")}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={isDropdownOpen}
|
||||
dropdownItems={dropdownItems}
|
||||
data-testid="action-dropdown"
|
||||
/>
|
||||
>
|
||||
<DropdownList>{dropdownItems}</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
)}
|
||||
</ToolbarContent>
|
||||
|
@ -193,18 +195,20 @@ export const ViewHeader = ({
|
|||
{lowerDropdownItems && (
|
||||
<Dropdown
|
||||
className="keycloak__user-federation__dropdown"
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
onToggle={() => onLowerDropdownToggle()}
|
||||
toggleVariant="primary"
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
onClick={onLowerDropdownToggle}
|
||||
variant="primary"
|
||||
id="ufToggleId"
|
||||
>
|
||||
{t(lowerDropdownMenuTitle)}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={isLowerDropdownOpen}
|
||||
dropdownItems={lowerDropdownItems}
|
||||
/>
|
||||
>
|
||||
<DropdownList>{lowerDropdownItems}</DropdownList>
|
||||
</Dropdown>
|
||||
)}
|
||||
{lowerButton && (
|
||||
<Button
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type AdminEventRepresentation from "@keycloak/keycloak-admin-client/lib/defs/adminEventRepresentation";
|
||||
import { TextControl } from "@keycloak/keycloak-ui-shared";
|
||||
import { CodeEditor, Language } from "@patternfly/react-code-editor";
|
||||
import {
|
||||
ActionGroup,
|
||||
|
@ -12,12 +13,8 @@ import {
|
|||
FormGroup,
|
||||
Modal,
|
||||
ModalVariant,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Table,
|
||||
TableVariant,
|
||||
|
@ -32,10 +29,13 @@ import { pickBy } from "lodash-es";
|
|||
import { PropsWithChildren, useMemo, useState } from "react";
|
||||
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TextControl } from "@keycloak/keycloak-ui-shared";
|
||||
import { useAdminClient } from "../admin-client";
|
||||
import DropdownPanel from "../components/dropdown-panel/DropdownPanel";
|
||||
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../components/select/KeycloakSelect";
|
||||
import {
|
||||
Action,
|
||||
KeycloakDataTable,
|
||||
|
@ -285,9 +285,8 @@ export const AdminEvents = () => {
|
|||
name="resourceTypes"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
className="keycloak__events_search__type_select"
|
||||
name="resourceTypes"
|
||||
data-testid="resource-types-searchField"
|
||||
chipGroupProps={{
|
||||
numChips: 1,
|
||||
|
@ -296,11 +295,11 @@ export const AdminEvents = () => {
|
|||
}}
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
typeAheadAriaLabel="Select"
|
||||
onToggle={(_event, isOpen) =>
|
||||
onToggle={(isOpen) =>
|
||||
setSelectResourceTypesOpen(isOpen)
|
||||
}
|
||||
selections={field.value}
|
||||
onSelect={(_, selectedValue) => {
|
||||
onSelect={(selectedValue) => {
|
||||
const option = selectedValue.toString();
|
||||
const changedValue = field.value.includes(option)
|
||||
? field.value.filter((item) => item !== option)
|
||||
|
@ -308,8 +307,7 @@ export const AdminEvents = () => {
|
|||
|
||||
field.onChange(changedValue);
|
||||
}}
|
||||
onClear={(resource) => {
|
||||
resource.stopPropagation();
|
||||
onClear={() => {
|
||||
field.onChange([]);
|
||||
}}
|
||||
isOpen={selectResourceTypesOpen}
|
||||
|
@ -337,7 +335,7 @@ export const AdminEvents = () => {
|
|||
{resourceTypes?.map((option) => (
|
||||
<SelectOption key={option} value={option} />
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
@ -350,9 +348,8 @@ export const AdminEvents = () => {
|
|||
name="operationTypes"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
className="keycloak__events_search__type_select"
|
||||
name="operationTypes"
|
||||
data-testid="operation-types-searchField"
|
||||
chipGroupProps={{
|
||||
numChips: 1,
|
||||
|
@ -361,11 +358,11 @@ export const AdminEvents = () => {
|
|||
}}
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
typeAheadAriaLabel="Select"
|
||||
onToggle={(_event, isOpen) =>
|
||||
onToggle={(isOpen) =>
|
||||
setSelectOperationTypesOpen(isOpen)
|
||||
}
|
||||
selections={field.value}
|
||||
onSelect={(_, selectedValue) => {
|
||||
onSelect={(selectedValue) => {
|
||||
const option = selectedValue.toString();
|
||||
const changedValue = field.value.includes(option)
|
||||
? field.value.filter((item) => item !== option)
|
||||
|
@ -373,8 +370,7 @@ export const AdminEvents = () => {
|
|||
|
||||
field.onChange(changedValue);
|
||||
}}
|
||||
onClear={(operation) => {
|
||||
operation.stopPropagation();
|
||||
onClear={() => {
|
||||
field.onChange([]);
|
||||
}}
|
||||
isOpen={selectOperationTypesOpen}
|
||||
|
@ -400,9 +396,12 @@ export const AdminEvents = () => {
|
|||
}
|
||||
>
|
||||
{operationTypes?.map((option) => (
|
||||
<SelectOption key={option} value={option} />
|
||||
<SelectOption
|
||||
key={option.toString()}
|
||||
value={option}
|
||||
/>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type EventRepresentation from "@keycloak/keycloak-admin-client/lib/defs/eventRepresentation";
|
||||
import type EventType from "@keycloak/keycloak-admin-client/lib/defs/eventTypes";
|
||||
import type { RealmEventsConfigRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/realmEventsConfigRepresentation";
|
||||
import { TextControl } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
ActionGroup,
|
||||
Button,
|
||||
|
@ -17,15 +18,11 @@ import {
|
|||
FormGroup,
|
||||
Icon,
|
||||
PageSection,
|
||||
SelectOption,
|
||||
Tab,
|
||||
TabTitleText,
|
||||
Tooltip,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { CheckCircleIcon, WarningTriangleIcon } from "@patternfly/react-icons";
|
||||
import { cellWidth, expandable } from "@patternfly/react-table";
|
||||
import { pickBy } from "lodash-es";
|
||||
|
@ -33,7 +30,6 @@ import { useState } from "react";
|
|||
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { TextControl } from "@keycloak/keycloak-ui-shared";
|
||||
import { useAdminClient } from "../admin-client";
|
||||
import DropdownPanel from "../components/dropdown-panel/DropdownPanel";
|
||||
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
||||
|
@ -41,6 +37,10 @@ import {
|
|||
RoutableTabs,
|
||||
useRoutableTab,
|
||||
} from "../components/routable-tabs/RoutableTabs";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../components/select/KeycloakSelect";
|
||||
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
|
@ -266,9 +266,8 @@ export default function EventsSection() {
|
|||
name="type"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
className="keycloak__events_search__type_select"
|
||||
name="eventType"
|
||||
data-testid="event-type-searchField"
|
||||
chipGroupProps={{
|
||||
numChips: 1,
|
||||
|
@ -277,9 +276,9 @@ export default function EventsSection() {
|
|||
}}
|
||||
variant={SelectVariant.typeaheadMulti}
|
||||
typeAheadAriaLabel="Select"
|
||||
onToggle={(_event, isOpen) => setSelectOpen(isOpen)}
|
||||
onToggle={(isOpen) => setSelectOpen(isOpen)}
|
||||
selections={field.value}
|
||||
onSelect={(_, selectedValue) => {
|
||||
onSelect={(selectedValue) => {
|
||||
const option = selectedValue.toString() as EventType;
|
||||
const changedValue = field.value.includes(option)
|
||||
? field.value.filter((item) => item !== option)
|
||||
|
@ -287,8 +286,7 @@ export default function EventsSection() {
|
|||
|
||||
field.onChange(changedValue);
|
||||
}}
|
||||
onClear={(event) => {
|
||||
event.stopPropagation();
|
||||
onClear={() => {
|
||||
field.onChange([]);
|
||||
}}
|
||||
isOpen={selectOpen}
|
||||
|
@ -316,7 +314,7 @@ export default function EventsSection() {
|
|||
{t(`eventTypes.${option}.name`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
line-height: 0px;
|
||||
}
|
||||
|
||||
.keycloak__events_search__type_select .pf-v5-c-select__menu {
|
||||
.keycloak__events_search__type_select .pf-v5-c-menu__list {
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
DrawerContentBody,
|
||||
DrawerHead,
|
||||
DrawerPanelContent,
|
||||
DropdownItem,
|
||||
PageSection,
|
||||
PageSectionVariants,
|
||||
Tab,
|
||||
|
@ -13,7 +14,6 @@ import {
|
|||
Tabs,
|
||||
Tooltip,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { AngleLeftIcon, TreeIcon } from "@patternfly/react-icons";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation";
|
||||
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
|
||||
import { SubGroupQuery } from "@keycloak/keycloak-admin-client/lib/resources/groups";
|
||||
import { Button, Checkbox, ToolbarItem } from "@patternfly/react-core";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
KebabToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import { EllipsisVIcon } from "@patternfly/react-icons";
|
||||
import { uniqBy } from "lodash-es";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -202,15 +206,22 @@ export const Members = () => {
|
|||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Dropdown
|
||||
toggle={
|
||||
<KebabToggle
|
||||
onToggle={() => setIsKebabOpen(!isKebabOpen)}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
variant="plain"
|
||||
onClick={() => setIsKebabOpen(!isKebabOpen)}
|
||||
isExpanded={isKebabOpen}
|
||||
isDisabled={selectedRows.length === 0}
|
||||
/>
|
||||
}
|
||||
aria-label="Actions"
|
||||
>
|
||||
<EllipsisVIcon />
|
||||
</MenuToggle>
|
||||
)}
|
||||
shouldFocusToggleOnSelect
|
||||
isOpen={isKebabOpen}
|
||||
isPlain
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
key="action"
|
||||
component="button"
|
||||
|
@ -236,9 +247,9 @@ export const Members = () => {
|
|||
}}
|
||||
>
|
||||
{t("leave")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { Button, ToolbarItem } from "@patternfly/react-core";
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
KebabToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
|
||||
import { useSubGroups } from "../SubGroupsContext";
|
||||
DropdownList,
|
||||
MenuToggle,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import { EllipsisVIcon } from "@patternfly/react-icons";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAccess } from "../../context/access/Access";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
import { useSubGroups } from "../SubGroupsContext";
|
||||
|
||||
type GroupToolbarProps = {
|
||||
toggleCreate: () => void;
|
||||
|
@ -43,12 +45,21 @@ export const GroupToolbar = ({
|
|||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<Dropdown
|
||||
toggle={
|
||||
<KebabToggle onToggle={toggleKebab} isDisabled={kebabDisabled} />
|
||||
}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
isExpanded={openKebab}
|
||||
onClick={toggleKebab}
|
||||
isDisabled={kebabDisabled}
|
||||
variant="plain"
|
||||
aria-label="Actions"
|
||||
>
|
||||
<EllipsisVIcon />
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={openKebab}
|
||||
isPlain
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem
|
||||
key="action"
|
||||
component="button"
|
||||
|
@ -58,9 +69,9 @@ export const GroupToolbar = ({
|
|||
}}
|
||||
>
|
||||
{t("delete")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -8,15 +8,14 @@ import {
|
|||
Tooltip,
|
||||
TreeView,
|
||||
TreeViewDataItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
MenuToggle,
|
||||
DropdownList,
|
||||
Divider,
|
||||
DropdownItem,
|
||||
DropdownPosition,
|
||||
DropdownSeparator,
|
||||
KebabToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { AngleRightIcon } from "@patternfly/react-icons";
|
||||
} from "@patternfly/react-core";
|
||||
|
||||
import { AngleRightIcon, EllipsisVIcon } from "@patternfly/react-icons";
|
||||
import { unionBy } from "lodash-es";
|
||||
import { useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -104,26 +103,38 @@ const GroupTreeContextMenu = ({
|
|||
}}
|
||||
/>
|
||||
<Dropdown
|
||||
toggle={<KebabToggle onToggle={toggleOpen} />}
|
||||
popperProps={{
|
||||
position: "right",
|
||||
}}
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
onClick={toggleOpen}
|
||||
isExpanded={isOpen}
|
||||
variant="plain"
|
||||
aria-label="Actions"
|
||||
>
|
||||
<EllipsisVIcon />
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={isOpen}
|
||||
isPlain
|
||||
position={DropdownPosition.right}
|
||||
dropdownItems={[
|
||||
>
|
||||
<DropdownList>
|
||||
<DropdownItem key="rename" onClick={toggleRenameOpen}>
|
||||
{t("rename")}
|
||||
</DropdownItem>,
|
||||
</DropdownItem>
|
||||
<DropdownItem key="move" onClick={toggleMoveOpen}>
|
||||
{t("moveTo")}
|
||||
</DropdownItem>,
|
||||
</DropdownItem>
|
||||
<DropdownItem key="create" onClick={toggleCreateOpen}>
|
||||
{t("createChildGroup")}
|
||||
</DropdownItem>,
|
||||
<DropdownSeparator key="separator" />,
|
||||
</DropdownItem>
|
||||
<Divider key="separator" />,
|
||||
<DropdownItem key="delete" onClick={toggleDeleteOpen}>
|
||||
{t("delete")}
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,7 +7,12 @@ import {
|
|||
Button,
|
||||
ButtonVariant,
|
||||
CardTitle,
|
||||
Dropdown,
|
||||
DropdownGroup,
|
||||
DropdownItem,
|
||||
DropdownList,
|
||||
Gallery,
|
||||
MenuToggle,
|
||||
PageSection,
|
||||
Split,
|
||||
SplitItem,
|
||||
|
@ -16,12 +21,6 @@ import {
|
|||
TextVariants,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownGroup,
|
||||
DropdownItem,
|
||||
DropdownToggle,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { IFormatterValueType } from "@patternfly/react-table";
|
||||
import { groupBy, sortBy } from "lodash-es";
|
||||
import { Fragment, useState } from "react";
|
||||
|
@ -128,18 +127,19 @@ export default function IdentityProvidersSection() {
|
|||
<DropdownItem
|
||||
key={provider.id}
|
||||
value={provider.id}
|
||||
component={
|
||||
<Link
|
||||
to={toIdentityProviderCreate({
|
||||
component="a"
|
||||
data-testid={provider.id}
|
||||
onClick={() =>
|
||||
navigate(
|
||||
toIdentityProviderCreate({
|
||||
realm,
|
||||
providerId: provider.id,
|
||||
})}
|
||||
data-testid={provider.id}
|
||||
>
|
||||
{provider.name}
|
||||
</Link>
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
>
|
||||
{provider.name}
|
||||
</DropdownItem>
|
||||
))}
|
||||
</DropdownGroup>
|
||||
));
|
||||
|
@ -229,17 +229,19 @@ export default function IdentityProvidersSection() {
|
|||
<ToolbarItem>
|
||||
<Dropdown
|
||||
data-testid="addProviderDropdown"
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
onToggle={() => setAddProviderOpen(!addProviderOpen)}
|
||||
toggleVariant="primary"
|
||||
toggle={(ref) => (
|
||||
<MenuToggle
|
||||
ref={ref}
|
||||
onClick={() => setAddProviderOpen(!addProviderOpen)}
|
||||
variant="primary"
|
||||
>
|
||||
{t("addProvider")}
|
||||
</DropdownToggle>
|
||||
}
|
||||
</MenuToggle>
|
||||
)}
|
||||
isOpen={addProviderOpen}
|
||||
dropdownItems={identityProviderOptions()}
|
||||
/>
|
||||
>
|
||||
<DropdownList>{identityProviderOptions()}</DropdownList>
|
||||
</Dropdown>
|
||||
</ToolbarItem>
|
||||
|
||||
<ToolbarItem>
|
||||
|
|
|
@ -6,9 +6,9 @@ import {
|
|||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
PageSection,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
import type IdentityProviderMapperRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperRepresentation";
|
||||
import type { IdentityProviderMapperTypeRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/identityProviderMapperTypeRepresentation";
|
||||
import { FormGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { Controller, UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
HelpItem,
|
||||
SelectControl,
|
||||
TextControl,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import { FormGroup, SelectOption } from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, UseFormReturn } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../../components/select/KeycloakSelect";
|
||||
import type { IdPMapperRepresentationWithAttributes } from "./AddMapper";
|
||||
|
||||
type AddMapperFormProps = {
|
||||
|
@ -74,13 +73,12 @@ export const AddMapperForm = ({
|
|||
defaultValue={mapperTypes[0].id}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId="identityProviderMapper"
|
||||
data-testid="idp-mapper-select"
|
||||
isDisabled={!!id}
|
||||
required
|
||||
onToggle={() => setMapperTypeOpen(!mapperTypeOpen)}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
const mapperType =
|
||||
value as IdentityProviderMapperTypeRepresentation;
|
||||
updateMapperType(mapperType);
|
||||
|
@ -102,7 +100,7 @@ export const AddMapperForm = ({
|
|||
{option.name}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import type AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation";
|
||||
import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
|
||||
import {
|
||||
FormGroup,
|
||||
Switch,
|
||||
TextInput,
|
||||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
FormErrorText,
|
||||
HelpItem,
|
||||
SelectControl,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
FormGroup,
|
||||
SelectOption,
|
||||
Switch,
|
||||
TextInput,
|
||||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../../components/select/KeycloakSelect";
|
||||
import { useFetch } from "../../utils/useFetch";
|
||||
import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled";
|
||||
import type { FieldProps } from "../component/FormGroupField";
|
||||
|
@ -59,11 +59,10 @@ const LoginFlow = ({
|
|||
defaultValue={defaultValue}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId={label}
|
||||
required
|
||||
onToggle={() => setOpen(!open)}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
field.onChange(value as string);
|
||||
setOpen(false);
|
||||
}}
|
||||
|
@ -90,7 +89,7 @@ const LoginFlow = ({
|
|||
</SelectOption>
|
||||
)) || []),
|
||||
]}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -5,16 +5,13 @@ import {
|
|||
Button,
|
||||
ButtonVariant,
|
||||
Divider,
|
||||
DropdownItem,
|
||||
Form,
|
||||
PageSection,
|
||||
Tab,
|
||||
TabTitleText,
|
||||
ToolbarItem,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
DropdownItem,
|
||||
DropdownSeparator,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { useMemo, useState } from "react";
|
||||
import {
|
||||
Controller,
|
||||
|
@ -209,7 +206,7 @@ const Header = ({ onChange, value, save, toggleDeleteDialog }: HeaderProps) => {
|
|||
</DropdownItem>,
|
||||
]
|
||||
: []),
|
||||
<DropdownSeparator key="separator" />,
|
||||
<Divider key="separator" />,
|
||||
<DropdownItem key="delete" onClick={() => toggleDeleteDialog()}>
|
||||
{t("delete")}
|
||||
</DropdownItem>,
|
||||
|
|
|
@ -3,17 +3,14 @@ import {
|
|||
Form,
|
||||
FormGroup,
|
||||
NumberInput,
|
||||
} from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
} from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import { HelpItem, SelectVariant } from "@keycloak/keycloak-ui-shared";
|
||||
import { KeycloakSelect } from "../../components/select/KeycloakSelect";
|
||||
import { FormGroupField } from "../component/FormGroupField";
|
||||
import { SwitchField } from "../component/SwitchField";
|
||||
import { TextField } from "../component/TextField";
|
||||
|
@ -65,11 +62,10 @@ export const ExtendedNonDiscoverySettings = () => {
|
|||
defaultValue=""
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId="prompt"
|
||||
required
|
||||
onToggle={() => setPromptOpen(!promptOpen)}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
field.onChange(value as string);
|
||||
setPromptOpen(false);
|
||||
}}
|
||||
|
@ -87,7 +83,7 @@ export const ExtendedNonDiscoverySettings = () => {
|
|||
{t(`prompts.${key}`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroupField>
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
import { FormGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { FormGroup, SelectOption } from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -14,6 +9,10 @@ import { SwitchField } from "../component/SwitchField";
|
|||
import { sortProviders } from "../../util";
|
||||
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
|
||||
import { TextField } from "../component/TextField";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectVariant,
|
||||
} from "../../components/select/KeycloakSelect";
|
||||
|
||||
const clientAuthentications = [
|
||||
"client_secret_post",
|
||||
|
@ -52,11 +51,10 @@ export const OIDCAuthentication = ({ create = true }: { create?: boolean }) => {
|
|||
defaultValue={clientAuthentications[0]}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId="clientAuthentication"
|
||||
required
|
||||
onToggle={() => setOpenClientAuth(!openClientAuth)}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
field.onChange(value as string);
|
||||
setOpenClientAuth(false);
|
||||
}}
|
||||
|
@ -74,7 +72,7 @@ export const OIDCAuthentication = ({ create = true }: { create?: boolean }) => {
|
|||
{t(`clientAuthentications.${option}`)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
@ -97,11 +95,11 @@ export const OIDCAuthentication = ({ create = true }: { create?: boolean }) => {
|
|||
defaultValue=""
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
maxHeight={200}
|
||||
toggleId="clientAssertionSigningAlg"
|
||||
onToggle={() => setOpenClientAuthSigAlg(!openClientAuthSigAlg)}
|
||||
onSelect={(_, value) => {
|
||||
onSelect={(value) => {
|
||||
field.onChange(value.toString());
|
||||
setOpenClientAuthSigAlg(false);
|
||||
}}
|
||||
|
@ -119,10 +117,12 @@ export const OIDCAuthentication = ({ create = true }: { create?: boolean }) => {
|
|||
selected={option === field.value}
|
||||
key={option}
|
||||
value={option}
|
||||
/>
|
||||
>
|
||||
{option}
|
||||
</SelectOption>
|
||||
)),
|
||||
]}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
import { FormGroup } from "@patternfly/react-core";
|
||||
import {
|
||||
Select,
|
||||
SelectOption,
|
||||
SelectVariant,
|
||||
} from "@patternfly/react-core/deprecated";
|
||||
import { FormGroup, SelectOption } from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { HelpItem } from "@keycloak/keycloak-ui-shared";
|
||||
import { HelpItem, SelectVariant } from "@keycloak/keycloak-ui-shared";
|
||||
import { MultiLineInput } from "../../components/multi-line-input/MultiLineInput";
|
||||
import { KeycloakSelect } from "../../components/select/KeycloakSelect";
|
||||
|
||||
const comparisonValues = ["exact", "minimum", "maximum", "better"];
|
||||
|
||||
|
@ -31,12 +27,11 @@ export const ReqAuthnConstraints = () => {
|
|||
defaultValue={comparisonValues[0]}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
<KeycloakSelect
|
||||
toggleId="comparison"
|
||||
required
|
||||
direction="up"
|
||||
onToggle={(_event, isExpanded) => setComparisonOpen(isExpanded)}
|
||||
onSelect={(_, value) => {
|
||||
onToggle={(isExpanded) => setComparisonOpen(isExpanded)}
|
||||
onSelect={(value) => {
|
||||
field.onChange(value.toString());
|
||||
setComparisonOpen(false);
|
||||
}}
|
||||
|
@ -54,7 +49,7 @@ export const ReqAuthnConstraints = () => {
|
|||
{t(option)}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
</KeycloakSelect>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { ButtonVariant } from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { ButtonVariant, DropdownItem } from "@patternfly/react-core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useAdminClient } from "../admin-client";
|
||||
|
|
|
@ -2,11 +2,11 @@ import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/ro
|
|||
import {
|
||||
AlertVariant,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
PageSection,
|
||||
Tab,
|
||||
TabTitleText,
|
||||
} from "@patternfly/react-core";
|
||||
import { DropdownItem } from "@patternfly/react-core/deprecated";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
FormProvider,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue