Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fixes related to conosle settings in primary organizations for managed deployments #6973

Merged
merged 8 commits into from
Oct 14, 2024
Merged
6 changes: 6 additions & 0 deletions .changeset/ninety-ads-teach.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@wso2is/admin.console-settings.v1": patch
"@wso2is/admin.roles.v2": patch
---

Bug fixes related to conosle settings in primary organizations for managed deployments
4 changes: 4 additions & 0 deletions features/admin.administrators.v1/constants/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ export class AdministratorConstants {
// Timeout for the debounce function.
public static readonly DEBOUNCE_TIMEOUT: number = 1000;

public static readonly INVITE_INTERNAL_USER_FORM_ID: string = "inviteInternalUserForm";

public static readonly INVITE_EXTERNAL_USER_FORM_ID: string = "inviteExternalUserForm";

/**
* Get the consumer users paths as a map.
*
Expand Down
390 changes: 227 additions & 163 deletions features/admin.administrators.v1/wizard/steps/admin-user-basic.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import React, {
useEffect,
useState
} from "react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import AdministratorsList from "./administrators-list/administrators-list";
import InvitedAdministratorsList from "./invited-administrators/invited-administrators-list";
Expand All @@ -57,6 +58,7 @@ const ConsoleAdministrators: FunctionComponent<ConsoleAdministratorsInterface> =
const { [ "data-componentid" ]: componentId } = props;

const { isFirstLevelOrganization, isSubOrganization } = useGetCurrentOrganizationType();
const { t } = useTranslation();

const consoleSettingsFeatureConfig: FeatureAccessConfigInterface =
useSelector((state: AppState) => state?.config?.ui?.features?.consoleSettings);
Expand All @@ -71,6 +73,7 @@ const ConsoleAdministrators: FunctionComponent<ConsoleAdministratorsInterface> =
const [ isEnterpriseLoginEnabled, setIsEnterpriseLoginEnabled ] = useState<boolean>(false);

const organizationName: string = store.getState().auth.tenantDomain;
const productName: string = useSelector((state: AppState) => state.config.ui.productName);

const useOrgConfig: UseOrganizationConfigType = useOrganizationConfigV2;

Expand Down Expand Up @@ -186,8 +189,12 @@ const ConsoleAdministrators: FunctionComponent<ConsoleAdministratorsInterface> =
value={ activeAdministratorGroup }
onChange={ (_: ChangeEvent<HTMLInputElement>, value: string) => setActiveAdministratorGroup(value) }
>
<FormControlLabel value="administrators" control={ <Radio /> } label="Administrators" />
<FormControlLabel value="privilegedUsers" control={ <Radio /> } label="Privileged Users" />
<FormControlLabel value="administrators" control={ <Radio /> } label={ productName } />
<FormControlLabel
value="privilegedUsers"
control={ <Radio /> }
label={ t("common:organizationName", { orgName: organizationName }) }
/>
</RadioGroup>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
.submit-button {
margin-top: 2rem;
}

.multi-option-radio-group {
gap: 40px;
margin: 20px 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
* under the License.
*/

import FormControlLabel from "@oxygen-ui/react/FormControlLabel";
import Radio from "@oxygen-ui/react/Radio";
import RadioGroup from "@oxygen-ui/react/RadioGroup";
import { FeatureStatus, useCheckFeatureStatus, useRequiredScopes } from "@wso2is/access-control";
import { useOrganizationConfigV2 } from "@wso2is/admin.administrators.v1/api/useOrganizationConfigV2";
import { UseOrganizationConfigType } from "@wso2is/admin.administrators.v1/models";
Expand All @@ -30,7 +33,7 @@ import { RoleAudienceTypes } from "@wso2is/admin.roles.v2/constants/role-constan
import { RoleConstants } from "@wso2is/core/constants";
import { FeatureAccessConfigInterface, IdentifiableComponentInterface, RolesInterface } from "@wso2is/core/models";
import { ResourceTab, ResourceTabPaneInterface } from "@wso2is/react-components";
import React, { FunctionComponent, ReactElement, useEffect, useState } from "react";
import React, { ChangeEvent, FunctionComponent, ReactElement, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import ConsoleRolePermissions from "./console-role-permissions";
Expand Down Expand Up @@ -64,40 +67,42 @@ interface ConsoleRolesEditPropsInterface extends IdentifiableComponentInterface
* @param props - contains role details to be edited.
*/
const ConsoleRolesEdit: FunctionComponent<ConsoleRolesEditPropsInterface> = (
props: ConsoleRolesEditPropsInterface): ReactElement => {

const {
isLoading,
roleObject,
onRoleUpdate,
defaultActiveIndex
} = props;
props: ConsoleRolesEditPropsInterface
): ReactElement => {
const { isLoading, roleObject, onRoleUpdate, defaultActiveIndex } = props;

const { t } = useTranslation();
const { isFirstLevelOrganization, isSubOrganization, organizationType } = useGetCurrentOrganizationType();

const userRolesFeatureConfig: FeatureAccessConfigInterface = useSelector(
(state: AppState) => state?.config?.ui?.features?.userRoles);
(state: AppState) => state?.config?.ui?.features?.userRoles
);
const hasRolesUpdatePermissions: boolean = useRequiredScopes(userRolesFeatureConfig?.scopes?.update);

const administratorRoleDisplayName: string = useSelector(
(state: AppState) => state?.config?.ui?.administratorRoleDisplayName);
(state: AppState) => state?.config?.ui?.administratorRoleDisplayName
);

const consoleSettingsFeatureConfig: FeatureAccessConfigInterface =
useSelector((state: AppState) => state?.config?.ui?.features?.consoleSettings);
const consoleSettingsFeatureConfig: FeatureAccessConfigInterface = useSelector(
(state: AppState) => state?.config?.ui?.features?.consoleSettings
);
const isConsoleRolesEditable: boolean = !consoleSettingsFeatureConfig?.disabledFeatures?.includes(
"consoleSettings.editableConsoleRoles"
);
const isPrivilegedUsersInConsoleSettingsEnabled: boolean =
!consoleSettingsFeatureConfig?.disabledFeatures?.includes(
"consoleSettings.privilegedUsers"
);

const [ isAdminRole, setIsAdminRole ] = useState<boolean>(false);
const [ isEnterpriseLoginEnabled, setIsEnterpriseLoginEnabled ] = useState<boolean>(false);
const [ activeUserStore, setActiveUserStore ] = useState<string>("PRIMARY");

const organizationName: string = store.getState().auth.tenantDomain;

const useOrgConfig: UseOrganizationConfigType = useOrganizationConfigV2;

const saasFeatureStatus : FeatureStatus = useCheckFeatureStatus(
FeatureGateConstants.SAAS_FEATURES_IDENTIFIER);
const saasFeatureStatus: FeatureStatus = useCheckFeatureStatus(FeatureGateConstants.SAAS_FEATURES_IDENTIFIER);

const {
data: OrganizationConfig,
Expand All @@ -121,10 +126,12 @@ const ConsoleRolesEdit: FunctionComponent<ConsoleRolesEditPropsInterface> = (
* Set the if the role is `Internal/admin`.
*/
useEffect(() => {
if(roleObject) {
setIsAdminRole(roleObject.displayName === RoleConstants.ADMIN_ROLE ||
roleObject?.displayName === RoleConstants.ADMIN_GROUP ||
roleObject?.displayName === administratorRoleDisplayName);
if (roleObject) {
setIsAdminRole(
roleObject.displayName === RoleConstants.ADMIN_ROLE ||
roleObject?.displayName === RoleConstants.ADMIN_GROUP ||
roleObject?.displayName === administratorRoleDisplayName
);
}
}, [ roleObject ]);

Expand All @@ -135,8 +142,9 @@ const ConsoleRolesEdit: FunctionComponent<ConsoleRolesEditPropsInterface> = (
render: () => (
<ResourceTab.Pane controlledSegmentation attached={ false }>
<BasicRoleDetails
isReadOnly={ isSubOrg || isAdminRole || !isConsoleRolesEditable
|| !hasRolesUpdatePermissions }
isReadOnly={
isSubOrg || isAdminRole || !isConsoleRolesEditable || !hasRolesUpdatePermissions
}
role={ roleObject }
onRoleUpdate={ onRoleUpdate }
tabIndex={ 0 }
Expand All @@ -151,10 +159,7 @@ const ConsoleRolesEdit: FunctionComponent<ConsoleRolesEditPropsInterface> = (
<ResourceTab.Pane controlledSegmentation attached={ false }>
<ConsoleRolePermissions
isReadOnly={
isSubOrg
|| isAdminRole
|| !isConsoleRolesEditable
|| !hasRolesUpdatePermissions
isSubOrg || isAdminRole || !isConsoleRolesEditable || !hasRolesUpdatePermissions
}
role={ roleObject }
onRoleUpdate={ onRoleUpdate }
Expand All @@ -164,7 +169,7 @@ const ConsoleRolesEdit: FunctionComponent<ConsoleRolesEditPropsInterface> = (
</ResourceTab.Pane>
)
},
( (isFirstLevelOrganization() && isEnterpriseLoginEnabled) || isSubOrganization() ) && {
((isFirstLevelOrganization() && isEnterpriseLoginEnabled) || isSubOrganization()) && {
menuItem: t("roles:edit.menuItems.groups"),
render: () => (
<ResourceTab.Pane controlledSegmentation attached={ false }>
Expand All @@ -181,10 +186,34 @@ const ConsoleRolesEdit: FunctionComponent<ConsoleRolesEditPropsInterface> = (
menuItem: t("roles:edit.menuItems.users"),
render: () => (
<ResourceTab.Pane controlledSegmentation attached={ false }>
{ isFirstLevelOrganization() &&
isEnterpriseLoginEnabled &&
isPrivilegedUsersInConsoleSettingsEnabled && (
<RadioGroup
row
aria-labelledby="console-administrators-radio-group"
className="multi-option-radio-group"
defaultValue="PRIMARY"
name="console-administrators-radio-group-2"
value={ activeUserStore }
onChange={ (_: ChangeEvent<HTMLInputElement>, value: string) => {
setActiveUserStore(value);
} }
>
<FormControlLabel value="PRIMARY" control={ <Radio /> } label="Asgardeo" />
<FormControlLabel
value="DEFAULT"
control={ <Radio /> }
label={ organizationName + " organization" }
/>
</RadioGroup>
) }

pavinduLakshan marked this conversation as resolved.
Show resolved Hide resolved
<RoleUsersList
isReadOnly={ !hasRolesUpdatePermissions }
role={ roleObject }
onRoleUpdate={ onRoleUpdate }
activeUserStore={ activeUserStore }
tabIndex={ 3 }
/>
</ResourceTab.Pane>
Expand All @@ -211,12 +240,10 @@ const ConsoleRolesEdit: FunctionComponent<ConsoleRolesEditPropsInterface> = (
return panes;
};

return (
<ResourceTab
isLoading={ isLoading }
defaultActiveIndex={ defaultActiveIndex }
panes={ resolveResourcePanes() }
/>
return (<ResourceTab
isLoading={ isLoading }
defaultActiveIndex={ defaultActiveIndex }
panes={ resolveResourcePanes() } />
);
};

Expand Down
75 changes: 47 additions & 28 deletions features/admin.roles.v2/components/edit-role/edit-role-users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const RoleUsersList: FunctionComponent<RoleUsersPropsInterface> = (
onRoleUpdate,
isReadOnly,
tabIndex,
activeUserStore,
[ "data-componentid" ]: componentId
} = props;

Expand All @@ -97,7 +98,8 @@ export const RoleUsersList: FunctionComponent<RoleUsersPropsInterface> = (
const [ activeOption, setActiveOption ] = useState<GroupsInterface|UserBasicInterface>(undefined);
const [ availableUserStores, setAvailableUserStores ] = useState<UserstoreDisplayItem[]>([]);
const [ selectedUserStoreDomainName, setSelectedUserStoreDomainName ] = useState<string>(
disabledUserstores.includes(RemoteUserStoreConstants.PRIMARY_USER_STORE_NAME) ? "DEFAULT" : "Primary"
activeUserStore ??
disabledUserstores.includes(RemoteUserStoreConstants.PRIMARY_USER_STORE_NAME) ? "DEFAULT" : "PRIMARY"
);
const [ isPlaceholderVisible, setIsPlaceholderVisible ] = useState<boolean>(true);
const [ selectedUsersFromUserStore, setSelectedUsersFromUserStore ] = useState<UserBasicInterface[]>([]);
Expand Down Expand Up @@ -125,10 +127,14 @@ export const RoleUsersList: FunctionComponent<RoleUsersPropsInterface> = (
const isUserBelongToSelectedUserStore = (user: UserBasicInterface, userStoreName: string) => {
const userNameChunks: string[] = user.userName.split("/");

return (userNameChunks.length === 1 && userStoreName === "Primary")
return (userNameChunks.length === 1 && userStoreName === "PRIMARY")
|| (userNameChunks.length === 2 && userNameChunks[0] === userStoreName.toUpperCase());
};

useEffect(() => {
setSelectedUserStoreDomainName(activeUserStore);
}, [ activeUserStore ]);

useEffect(() => {
if (!role?.users?.length) {
return;
Expand Down Expand Up @@ -303,8 +309,15 @@ export const RoleUsersList: FunctionComponent<RoleUsersPropsInterface> = (
const removedUsers: RolesMemberInterface[] = role?.users?.filter((user: RolesMemberInterface) => {
return selectedUsers?.find(
(selectedUser: UserBasicInterface) => selectedUser.id === user.value) === undefined;
}).filter((user: RolesMemberInterface) => {
const userNameChunks: string[] = user.display.split("/");

return (userNameChunks.length === 1 && selectedUserStoreDomainName === "PRIMARY")
|| (userNameChunks.length === 2 && userNameChunks[0] === selectedUserStoreDomainName.toUpperCase());
}) ?? [];



pavinduLakshan marked this conversation as resolved.
Show resolved Hide resolved
const removeOperations: PatchUserRemoveOpInterface[] = removedUsers?.map((user: RolesMemberInterface) => {
return ({
"op": "remove",
Expand Down Expand Up @@ -390,33 +403,39 @@ export const RoleUsersList: FunctionComponent<RoleUsersPropsInterface> = (
{
users && availableUserStores && !isReadOnly && (
<Grid container spacing={ 1 }>
<Grid xs={ 12 } sm={ 4 } md={ 2 } alignItems="center">
<FormControl fullWidth size="medium">
<Select
value={ selectedUserStoreDomainName }
onChange={
(e: SelectChangeEvent<unknown>) => {
updateSelectedAllUsers();
setSelectedUsersFromUserStore([]);
setSelectedUserStoreDomainName(e.target.value as string);
{ !activeUserStore && (
<Grid xs={ 12 } sm={ 4 } md={ 2 } alignItems="center">
<FormControl fullWidth size="medium">
<Select
value={ selectedUserStoreDomainName }
onChange={
(e: SelectChangeEvent<unknown>) => {
updateSelectedAllUsers();
setSelectedUsersFromUserStore([]);
setSelectedUserStoreDomainName(
e.target.value as string
);
}
}
}
data-componentid={ `${ componentId }-user-store-domain-dropdown` }
>
{ isUserStoresLoading
? <p>{ t("common:loading") }</p>
: availableUserStores?.map((userstore: UserStoreListItem) =>
(<MenuItem
key={ userstore.name }
value={ userstore.name }
>
{ userstore.name }
</MenuItem>)
)
}
</Select>
</FormControl>
</Grid>
data-componentid={
`${ componentId }-user-store-domain-dropdown`
}
>
{ isUserStoresLoading
? <p>{ t("common:loading") }</p>
: availableUserStores?.map((userstore: UserStoreListItem) =>
(<MenuItem
key={ userstore.name }
value={ userstore.name }
>
{ userstore.name }
</MenuItem>)
)
}
</Select>
</FormControl>
</Grid>
) }
<Grid xs={ 12 } sm={ 4 } md={ 8 }>
<Autocomplete
multiple
Expand Down
7 changes: 7 additions & 0 deletions features/admin.roles.v2/models/roles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ export interface RoleEditSectionsInterface {
* Tab index
*/
tabIndex: number;
/**
* active user store
*
* Note: used to conditionally determine whether the userstore is handled
* outside the component.
*/
activeUserStore?: string
}

/**
Expand Down
1 change: 1 addition & 0 deletions modules/i18n/src/models/namespaces/common-ns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export interface CommonNS {
name: string;
new: string;
next: string;
organizationName: string;
operatingSystem: string;
operations: string;
overview: string;
Expand Down
Loading
Loading