diff --git a/js/apps/admin-ui/src/clients/ClientDetails.tsx b/js/apps/admin-ui/src/clients/ClientDetails.tsx index 72705d32df..491cc6dc50 100644 --- a/js/apps/admin-ui/src/clients/ClientDetails.tsx +++ b/js/apps/admin-ui/src/clients/ClientDetails.tsx @@ -38,18 +38,16 @@ import { import { useAccess } from "../context/access/Access"; import { useAdminClient, useFetch } from "../context/auth/AdminClient"; import { useRealm } from "../context/realm-context/RealmContext"; +import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { convertAttributeNameToForm, convertFormValuesToObject, convertToFormValues, exportClient, } from "../util"; -import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; import { useParams } from "../utils/useParams"; import useToggle from "../utils/useToggle"; import { AdvancedTab } from "./AdvancedTab"; -import { ClientSessions } from "./ClientSessions"; -import { ClientSettings } from "./ClientSettings"; import { AuthorizationEvaluate } from "./authorization/AuthorizationEvaluate"; import { AuthorizationExport } from "./authorization/AuthorizationExport"; import { AuthorizationPermissions } from "./authorization/Permissions"; @@ -57,6 +55,8 @@ import { AuthorizationPolicies } from "./authorization/Policies"; import { AuthorizationResources } from "./authorization/Resources"; import { AuthorizationScopes } from "./authorization/Scopes"; import { AuthorizationSettings } from "./authorization/Settings"; +import { ClientSessions } from "./ClientSessions"; +import { ClientSettings } from "./ClientSettings"; import { Credentials } from "./credentials/Credentials"; import { Keys } from "./keys/Keys"; import { SamlKeys } from "./keys/SamlKeys"; @@ -66,8 +66,8 @@ import { } from "./routes/AuthenticationTab"; import { ClientParams, ClientTab, toClient } from "./routes/Client"; import { toClientRole } from "./routes/ClientRole"; -import { ClientScopesTab, toClientScopesTab } from "./routes/ClientScopeTab"; import { toClients } from "./routes/Clients"; +import { ClientScopesTab, toClientScopesTab } from "./routes/ClientScopeTab"; import { toCreateRole } from "./routes/NewRole"; import { ClientScopes } from "./scopes/ClientScopes"; import { EvaluateScopes } from "./scopes/EvaluateScopes"; @@ -191,16 +191,17 @@ export default function ClientDetails() { const { adminClient } = useAdminClient(); const { addAlert, addError } = useAlerts(); const { realm } = useRealm(); - const { hasAccess } = useAccess(); - const isFeatureEnabled = useIsFeatureEnabled(); + const { profileInfo } = useServerInfo(); + const { hasAccess } = useAccess(); const hasManageAuthorization = hasAccess("manage-authorization"); + const permissionsEnabled = + !profileInfo?.disabledFeatures?.includes("ADMIN_FINE_GRAINED_AUTHZ") && + hasManageAuthorization; const hasManageClients = hasAccess("manage-clients"); const hasViewClients = hasAccess("view-clients"); const hasViewUsers = hasAccess("view-users"); const hasQueryUsers = hasAccess("query-users"); - const permissionsEnabled = - isFeatureEnabled(Feature.AdminFineGrainedAuthz) && hasManageAuthorization; const navigate = useNavigate(); diff --git a/js/apps/admin-ui/src/groups/GroupsSection.tsx b/js/apps/admin-ui/src/groups/GroupsSection.tsx index 111bbb2092..713d6c7670 100644 --- a/js/apps/admin-ui/src/groups/GroupsSection.tsx +++ b/js/apps/admin-ui/src/groups/GroupsSection.tsx @@ -1,40 +1,41 @@ -import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; +import { useState } from "react"; +import { useLocation, useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; import { - Drawer, - DrawerContent, - DrawerContentBody, - DrawerHead, - DrawerPanelContent, DropdownItem, PageSection, PageSectionVariants, Tab, TabTitleText, Tabs, + Drawer, + DrawerContent, + DrawerContentBody, + DrawerPanelContent, + DrawerHead, } from "@patternfly/react-core"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { useLocation, useNavigate } from "react-router-dom"; +import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; -import { GroupBreadCrumbs } from "../components/bread-crumb/GroupBreadCrumbs"; -import { PermissionsTab } from "../components/permission-tab/PermissionTab"; import { ViewHeader } from "../components/view-header/ViewHeader"; -import { useAccess } from "../context/access/Access"; -import { useAdminClient, useFetch } from "../context/auth/AdminClient"; +import { useFetch, useAdminClient } from "../context/auth/AdminClient"; import { useRealm } from "../context/realm-context/RealmContext"; -import helpUrls from "../help-urls"; -import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; -import useToggle from "../utils/useToggle"; -import { GroupAttributes } from "./GroupAttributes"; -import { GroupRoleMapping } from "./GroupRoleMapping"; -import { GroupTable } from "./GroupTable"; -import { GroupsModal } from "./GroupsModal"; -import { Members } from "./Members"; + import { useSubGroups } from "./SubGroupsContext"; -import { DeleteGroup } from "./components/DeleteGroup"; -import { GroupTree } from "./components/GroupTree"; +import { GroupTable } from "./GroupTable"; import { getId, getLastId } from "./groupIdUtils"; +import { Members } from "./Members"; +import { GroupAttributes } from "./GroupAttributes"; +import { GroupsModal } from "./GroupsModal"; import { toGroups } from "./routes/Groups"; +import { GroupRoleMapping } from "./GroupRoleMapping"; +import helpUrls from "../help-urls"; +import { PermissionsTab } from "../components/permission-tab/PermissionTab"; +import { useAccess } from "../context/access/Access"; +import { useServerInfo } from "../context/server-info/ServerInfoProvider"; +import { GroupTree } from "./components/GroupTree"; +import { DeleteGroup } from "./components/DeleteGroup"; +import useToggle from "../utils/useToggle"; +import { GroupBreadCrumbs } from "../components/bread-crumb/GroupBreadCrumbs"; import "./GroupsSection.css"; @@ -42,6 +43,8 @@ export default function GroupsSection() { const { t } = useTranslation("groups"); const [activeTab, setActiveTab] = useState(0); + const { profileInfo } = useServerInfo(); + const { adminClient } = useAdminClient(); const { subGroups, setSubGroups, currentGroup } = useSubGroups(); const { realm } = useRealm(); @@ -57,9 +60,8 @@ export default function GroupsSection() { const refresh = () => setKey(key + 1); const { hasAccess } = useAccess(); - const isFeatureEnabled = useIsFeatureEnabled(); const canViewPermissions = - isFeatureEnabled(Feature.AdminFineGrainedAuthz) && + !profileInfo?.disabledFeatures?.includes("ADMIN_FINE_GRAINED_AUTHZ") && hasAccess("manage-authorization", "manage-users", "manage-clients"); const canManageGroup = hasAccess("manage-users") || currentGroup()?.access?.manage; diff --git a/js/apps/admin-ui/src/identity-providers/add/DetailSettings.tsx b/js/apps/admin-ui/src/identity-providers/add/DetailSettings.tsx index efaf8a85ad..3229ce4865 100644 --- a/js/apps/admin-ui/src/identity-providers/add/DetailSettings.tsx +++ b/js/apps/admin-ui/src/identity-providers/add/DetailSettings.tsx @@ -36,8 +36,8 @@ import { import { ViewHeader } from "../../components/view-header/ViewHeader"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient"; import { useRealm } from "../../context/realm-context/RealmContext"; +import { useServerInfo } from "../../context/server-info/ServerInfoProvider"; import { toUpperCase } from "../../util"; -import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled"; import { useParams } from "../../utils/useParams"; import { ExtendedFieldsForm } from "../component/ExtendedFieldsForm"; import { toIdentityProviderAddMapper } from "../routes/AddMapper"; @@ -156,7 +156,7 @@ const MapperLink = ({ name, mapperId, provider }: MapperLinkProps) => { export default function DetailSettings() { const { t } = useTranslation("identity-providers"); const { alias, providerId } = useParams(); - const isFeatureEnabled = useIsFeatureEnabled(); + const form = useForm(); const { handleSubmit, getValues, reset } = form; const [provider, setProvider] = useState(); @@ -168,6 +168,7 @@ export default function DetailSettings() { const navigate = useNavigate(); const { realm } = useRealm(); const [key, setKey] = useState(0); + const { profileInfo } = useServerInfo(); const refresh = () => setKey(key + 1); useFetch( @@ -495,7 +496,9 @@ export default function DetailSettings() { ]} /> - {isFeatureEnabled(Feature.AdminFineGrainedAuthz) && ( + {!profileInfo?.disabledFeatures?.includes( + "ADMIN_FINE_GRAINED_AUTHZ" + ) && ( ({ mode: "onChange", @@ -68,6 +67,8 @@ export default function RealmRoleTabs() { const [key, setKey] = useState(0); const [attributes, setAttributes] = useState(); + const { profileInfo } = useServerInfo(); + const refresh = () => setKey(key + 1); const { addAlert, addError } = useAlerts(); @@ -390,7 +391,9 @@ export default function RealmRoleTabs() { )} - {isFeatureEnabled(Feature.AdminFineGrainedAuthz) && ( + {!profileInfo?.disabledFeatures?.includes( + "ADMIN_FINE_GRAINED_AUTHZ" + ) && ( {t("common:permissions")}} {...permissionsTab} diff --git a/js/apps/admin-ui/src/realm-settings/RealmSettingsTabs.tsx b/js/apps/admin-ui/src/realm-settings/RealmSettingsTabs.tsx index 837ac7ee71..bc86f5447c 100644 --- a/js/apps/admin-ui/src/realm-settings/RealmSettingsTabs.tsx +++ b/js/apps/admin-ui/src/realm-settings/RealmSettingsTabs.tsx @@ -22,32 +22,33 @@ import { useRoutableTab, } from "../components/routable-tabs/RoutableTabs"; import { ViewHeader } from "../components/view-header/ViewHeader"; -import { useRealms } from "../context/RealmsContext"; import { useAdminClient } from "../context/auth/AdminClient"; import { useRealm } from "../context/realm-context/RealmContext"; +import { useRealms } from "../context/RealmsContext"; import { toDashboard } from "../dashboard/routes/Dashboard"; import environment from "../environment"; import helpUrls from "../help-urls"; import { convertFormValuesToObject, convertToFormValues } from "../util"; import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; import { RealmSettingsEmailTab } from "./EmailTab"; +import { EventsTab } from "./event-config/EventsTab"; import { RealmSettingsGeneralTab } from "./GeneralTab"; +import { KeysTab } from "./keys/KeysTab"; import { LocalizationTab } from "./LocalizationTab"; import { RealmSettingsLoginTab } from "./LoginTab"; import { PartialExportDialog } from "./PartialExport"; import { PartialImportDialog } from "./PartialImport"; import { PoliciesTab } from "./PoliciesTab"; import ProfilesTab from "./ProfilesTab"; -import { RealmSettingsSessionsTab } from "./SessionsTab"; -import { RealmSettingsThemesTab } from "./ThemesTab"; -import { RealmSettingsTokensTab } from "./TokensTab"; -import { UserRegistration } from "./UserRegistration"; -import { EventsTab } from "./event-config/EventsTab"; -import { KeysTab } from "./keys/KeysTab"; import { ClientPoliciesTab, toClientPolicies } from "./routes/ClientPolicies"; import { RealmSettingsTab, toRealmSettings } from "./routes/RealmSettings"; import { SecurityDefenses } from "./security-defences/SecurityDefenses"; +import { RealmSettingsSessionsTab } from "./SessionsTab"; +import { RealmSettingsThemesTab } from "./ThemesTab"; +import { RealmSettingsTokensTab } from "./TokensTab"; import { UserProfileTab } from "./user-profile/UserProfileTab"; +import { UserRegistration } from "./UserRegistration"; +import { useServerInfo } from "../context/server-info/ServerInfoProvider"; type RealmSettingsHeaderProps = { onChange: (value: boolean) => void; @@ -236,6 +237,8 @@ export const RealmSettingsTabs = ({ const sessionsTab = useTab("sessions"); const tokensTab = useTab("tokens"); const clientPoliciesTab = useTab("client-policies"); + const clientPoliciesDisabled = + useServerInfo().profileInfo?.disabledFeatures?.includes("CLIENT_POLICIES"); const userProfileTab = useTab("user-profile"); const userRegistrationTab = useTab("user-registration"); @@ -350,7 +353,7 @@ export const RealmSettingsTabs = ({ > - {isFeatureEnabled(Feature.ClientPolicies) && ( + {!clientPoliciesDisabled && ( diff --git a/js/apps/admin-ui/src/user-federation/UserFederationLdapForm.tsx b/js/apps/admin-ui/src/user-federation/UserFederationLdapForm.tsx index a065f5a098..4544badfb9 100644 --- a/js/apps/admin-ui/src/user-federation/UserFederationLdapForm.tsx +++ b/js/apps/admin-ui/src/user-federation/UserFederationLdapForm.tsx @@ -6,7 +6,6 @@ import { useNavigate } from "react-router-dom"; import { ScrollForm } from "../components/scroll-form/ScrollForm"; import { useRealm } from "../context/realm-context/RealmContext"; -import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; import { LdapSettingsAdvanced } from "./ldap/LdapSettingsAdvanced"; import { LdapSettingsConnection } from "./ldap/LdapSettingsConnection"; import { LdapSettingsGeneral } from "./ldap/LdapSettingsGeneral"; @@ -15,6 +14,7 @@ import { LdapSettingsSearching } from "./ldap/LdapSettingsSearching"; import { LdapSettingsSynchronization } from "./ldap/LdapSettingsSynchronization"; import { toUserFederation } from "./routes/UserFederation"; import { SettingsCache } from "./shared/SettingsCache"; +import { useServerInfo } from "../context/server-info/ServerInfoProvider"; export type LdapComponentRepresentation = ComponentRepresentation & { config?: { @@ -36,7 +36,8 @@ export const UserFederationLdapForm = ({ const form = useFormContext(); const navigate = useNavigate(); const { realm } = useRealm(); - const isFeatureEnabled = useIsFeatureEnabled(); + const kerberosDisabled = + useServerInfo().profileInfo?.disabledFeatures?.includes("KERBEROS"); return ( <> @@ -61,7 +62,7 @@ export const UserFederationLdapForm = ({ { title: t("kerberosIntegration"), panel: , - isHidden: !isFeatureEnabled(Feature.Kerberos), + isHidden: kerberosDisabled, }, { title: t("cacheSettings"), panel: }, { diff --git a/js/apps/admin-ui/src/user-federation/UserFederationLdapWizard.tsx b/js/apps/admin-ui/src/user-federation/UserFederationLdapWizard.tsx index a9f2c83017..85e8a4ef09 100644 --- a/js/apps/admin-ui/src/user-federation/UserFederationLdapWizard.tsx +++ b/js/apps/admin-ui/src/user-federation/UserFederationLdapWizard.tsx @@ -1,26 +1,28 @@ -import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; import { Button, Wizard, WizardContextConsumer, WizardFooter, } from "@patternfly/react-core"; -import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; -import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; -import { LdapSettingsAdvanced } from "./ldap/LdapSettingsAdvanced"; -import { LdapSettingsConnection } from "./ldap/LdapSettingsConnection"; import { LdapSettingsGeneral } from "./ldap/LdapSettingsGeneral"; -import { LdapSettingsKerberosIntegration } from "./ldap/LdapSettingsKerberosIntegration"; +import { LdapSettingsConnection } from "./ldap/LdapSettingsConnection"; import { LdapSettingsSearching } from "./ldap/LdapSettingsSearching"; import { LdapSettingsSynchronization } from "./ldap/LdapSettingsSynchronization"; +import { LdapSettingsKerberosIntegration } from "./ldap/LdapSettingsKerberosIntegration"; import { SettingsCache } from "./shared/SettingsCache"; +import { LdapSettingsAdvanced } from "./ldap/LdapSettingsAdvanced"; +import { useTranslation } from "react-i18next"; +import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; + +import { useForm } from "react-hook-form"; +import { useServerInfo } from "../context/server-info/ServerInfoProvider"; export const UserFederationLdapWizard = () => { const form = useForm(); const { t } = useTranslation("user-federation"); - const isFeatureEnabled = useIsFeatureEnabled(); + const kerberosDisabled = + useServerInfo().profileInfo?.disabledFeatures?.includes("KERBEROS"); const steps = [ { @@ -77,7 +79,7 @@ export const UserFederationLdapWizard = () => { showSectionDescription /> ), - isDisabled: !isFeatureEnabled(Feature.Kerberos), + isDisabled: kerberosDisabled, }, { name: t("cacheSettings"), diff --git a/js/apps/admin-ui/src/user/UsersSection.tsx b/js/apps/admin-ui/src/user/UsersSection.tsx index d89bd5c56b..6f80eaa3d7 100644 --- a/js/apps/admin-ui/src/user/UsersSection.tsx +++ b/js/apps/admin-ui/src/user/UsersSection.tsx @@ -1,3 +1,6 @@ +import { useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; import { AlertVariant, Button, @@ -26,34 +29,31 @@ import { WarningTriangleIcon, } from "@patternfly/react-icons"; import type { IRowData } from "@patternfly/react-table"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { Link, useNavigate } from "react-router-dom"; import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; -import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; +import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; +import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useAlerts } from "../components/alert/Alerts"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; -import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner"; import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; +import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; +import { ViewHeader } from "../components/view-header/ViewHeader"; +import { useAdminClient, useFetch } from "../context/auth/AdminClient"; +import { useRealm } from "../context/realm-context/RealmContext"; +import { emptyFormatter } from "../util"; +import { toUser } from "./routes/User"; +import { toAddUser } from "./routes/AddUser"; +import helpUrls from "../help-urls"; +import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner"; import { PermissionsTab } from "../components/permission-tab/PermissionTab"; -import { BruteUser, findUsers } from "../components/role-mapping/resource"; +import { toUsers, UserTab } from "./routes/Users"; import { RoutableTabs, useRoutableTab, } from "../components/routable-tabs/RoutableTabs"; -import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; -import { ViewHeader } from "../components/view-header/ViewHeader"; import { useAccess } from "../context/access/Access"; -import { useAdminClient, useFetch } from "../context/auth/AdminClient"; -import { useRealm } from "../context/realm-context/RealmContext"; -import helpUrls from "../help-urls"; -import { emptyFormatter } from "../util"; -import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; -import { toAddUser } from "./routes/AddUser"; -import { toUser } from "./routes/User"; -import { UserTab, toUsers } from "./routes/Users"; +import { BruteUser, findUsers } from "../components/role-mapping/resource"; import "./user-section.css"; @@ -68,7 +68,7 @@ export default function UsersSection() { const [realm, setRealm] = useState(); const [kebabOpen, setKebabOpen] = useState(false); const [selectedRows, setSelectedRows] = useState([]); - const isFeatureEnabled = useIsFeatureEnabled(); + const { profileInfo } = useServerInfo(); const [key, setKey] = useState(0); const refresh = () => setKey(key + 1); @@ -420,7 +420,9 @@ export default function UsersSection() { ]} /> - {isFeatureEnabled(Feature.AdminFineGrainedAuthz) && ( + {!profileInfo?.disabledFeatures?.includes( + "ADMIN_FINE_GRAINED_AUTHZ" + ) && ( !disabledFilters.includes(feature) + ); return function isFeatureEnabled(feature: Feature) { - return !disabledFilters.includes(feature); + return enabledFeatures.includes(feature); }; }