Skip to content

Commit

Permalink
Merge pull request #2707 from okauppinen/admin-users-role-fix
Browse files Browse the repository at this point in the history
AdminUsers role select fix
  • Loading branch information
ZakarFin authored Oct 25, 2024
2 parents 8a9489f + 8401820 commit b4619bf
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 91 deletions.
42 changes: 27 additions & 15 deletions bundles/framework/admin-users/handler/AdminUsersHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class UIHandler extends StateHandler {
if (!response.ok) {
throw new Error(response.statusText);
}
const { users, total_count } = await response.json();
const { users = [], total_count } = await response.json();
this.updateState({
users,
userPagination: {
Expand Down Expand Up @@ -143,11 +143,6 @@ class UIHandler extends StateHandler {
this.updateState({ usersByRole: { users, roleId } });
}

async getUserCountByRole (roleId) {
const users = await this.fetchUsersByRole(roleId);
return users.length;
}

async fetchUsersByRole (roleId) {
try {
const response = await fetch(Oskari.urls.buildUrl(this.restUrl, {
Expand All @@ -170,13 +165,30 @@ class UIHandler extends StateHandler {
}

setAddingUser () {
this.updateState({
userFormState: this.initUserForm()
});
this.setEditingUser(this.initUser());
}

editUserById (id) {
const user = this.getState().users.find(u => u.id === id);
this.setEditingUser(user);
}

editUserFromRoles (id, userName) {
this.setActiveTab('admin-users-tab');
// fetchUsersByRole doesn't return roles so usersByRole.users doesn't have roles
// search user by name if not found in paginated results
const user = this.getState().users.find(u => u.id === id);
if (user) {
this.setEditingUser(user);
} else {
this.search(userName);
}
}

setEditingUser (id) {
const user = this.state.users.find(u => u.id === id) || {};
setEditingUser (user) {
if (!user) {
Messaging.error(Oskari.getMsg('AdminUsers', 'users.noMatch'));
}
this.updateState({
userFormState: {
...user,
Expand Down Expand Up @@ -220,7 +232,7 @@ class UIHandler extends StateHandler {
}
}

initUserForm () {
initUser () {
return {
firstName: '',
lastName: '',
Expand Down Expand Up @@ -445,7 +457,8 @@ class UIHandler extends StateHandler {
const wrapped = controllerMixin(UIHandler, [
'setActiveTab',
'setAddingUser',
'setEditingUser',
'editUserById',
'editUserFromRoles',
'updateUserFormState',
'closeUserForm',
'saveUser',
Expand All @@ -458,8 +471,7 @@ const wrapped = controllerMixin(UIHandler, [
'setEditingRole',
'updateRole',
'updateEditingRole',
'showUsersByRole',
'getUserCountByRole'
'showUsersByRole'
]);

export { wrapped as AdminUsersHandler };
6 changes: 6 additions & 0 deletions bundles/framework/admin-users/view/AdminUsersFlyout.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Tabs, Message } from 'oskari-ui';
import { RolesTab } from './RolesTab';
import { UsersTab } from './UsersTab';
Expand Down Expand Up @@ -37,3 +38,8 @@ export const AdminUsersFlyout = ({ state, controller, isExternal = false }) => {
</div>
);
};
AdminUsersFlyout.propTypes = {
state: PropTypes.object.isRequired,
controller: PropTypes.object.isRequired,
isExternal: PropTypes.bool
};
17 changes: 16 additions & 1 deletion bundles/framework/admin-users/view/RoleBlock.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TextInput, Message } from 'oskari-ui';
import { UserOutlined } from '@ant-design/icons';
import { Block, Button, ButtonContainer } from './styled';

const ADMIN = 'admin';

export const RoleBlock = ({ role, controller, isSystemRole, editingRole }) => {
const { id, name } = role;
const { id, name, type } = role;
if (isSystemRole) {
return (
<Block>
<span>{name}</span>
{ type === ADMIN &&
<Button
icon={<UserOutlined />}
title={<Message messageKey='roles.showUsers'/>}
onClick={() => controller.showUsersByRole(id)} />
}
</Block>
);
}
Expand Down Expand Up @@ -41,3 +50,9 @@ export const RoleBlock = ({ role, controller, isSystemRole, editingRole }) => {
</Block>
);
};
RoleBlock.propTypes = {
role: PropTypes.object.isRequired,
controller: PropTypes.object.isRequired,
editingRole: PropTypes.object,
isSystemRole: PropTypes.bool
};
44 changes: 44 additions & 0 deletions bundles/framework/admin-users/view/RoleSelect.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Select, Message } from 'oskari-ui';

const ADMIN = 'admin';
const GUEST = 'anonymous';

const getOptionGroup = (type, roles) => {
const options = roles.map(({ name, id }) => ({ label: name, value: id }));
return {
title: type,
label: <Message messageKey={`roles.types.${type}`} />,
options
};
};

export const RoleSelect = ({ state, value, error, multiple, onlyAdmin, onChange }) => {
const { roles, systemRoles } = state;
const system = onlyAdmin
? systemRoles.filter(role => role.type === ADMIN)
: systemRoles.filter(role => role.type !== GUEST);
const options = [
getOptionGroup('system', system),
getOptionGroup('other', roles)
];
return <Select
className='t_roles'
mode={multiple ? 'multiple' : null}
status={error ? 'error' : null}
onChange={(value) => onChange(value)}
placeholder={<Message messageKey='usersByRole.selectRole' />}
value={value}
style={multiple ? { width: 210 } : null}
options={options}/>;
};

RoleSelect.propTypes = {
state: PropTypes.object.isRequired,
value: PropTypes.any,
onChange: PropTypes.func.isRequired,
multiple: PropTypes.bool,
onlyAdmin: PropTypes.bool,
error: PropTypes.bool
};
7 changes: 6 additions & 1 deletion bundles/framework/admin-users/view/RolesTab.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Message } from 'oskari-ui';
import { PrimaryButton } from 'oskari-ui/components/buttons';
import { RoleBlock } from './RoleBlock';
Expand All @@ -24,7 +25,7 @@ export const RolesTab = ({ state, controller }) => {
controller.addRole(roleName);
setStatus('');
setRoleName('');
}
};
const { roles, systemRoles, editingRole } = state;
return (
<Content>
Expand All @@ -48,3 +49,7 @@ export const RolesTab = ({ state, controller }) => {
</Content>
);
};
RolesTab.propTypes = {
state: PropTypes.object.isRequired,
controller: PropTypes.object.isRequired
};
10 changes: 10 additions & 0 deletions bundles/framework/admin-users/view/UserField.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Message } from 'oskari-ui';
import { getMandatoryIcon } from 'oskari-ui/util/validators';
import { LabelledField, StyledLabel, StyledInput } from './styled';
Expand Down Expand Up @@ -26,3 +27,12 @@ export const UserField = ({ field, value, controller, error, readonly = false, t
</LabelledField>
);
};
UserField.propTypes = {
field: PropTypes.string.isRequired,
value: PropTypes.string,
controller: PropTypes.object.isRequired,
type: PropTypes.string,
error: PropTypes.bool,
readonly: PropTypes.bool,
mandatory: PropTypes.bool
};
51 changes: 17 additions & 34 deletions bundles/framework/admin-users/view/UserForm.jsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
import React from 'react';
import { Message, Label, Select } from 'oskari-ui';
import PropTypes from 'prop-types';
import { Message } from 'oskari-ui';
import { PrimaryButton, SecondaryButton, DeleteButton, ButtonContainer } from 'oskari-ui/components/buttons';
import styled from 'styled-components';
import { UserField } from './UserField';
import { RoleSelect } from './RoleSelect';
import { Content, LabelledField, StyledLabel } from './styled';

const StyledSelect = styled(Select)`
width: 210px;
`;

const FIELDS = ['user', 'firstName', 'lastName', 'email'];
const PASS_FIELDS = ['password', 'rePassword'];

const getRoleOptions = (roles, systemRole) => {
const filtered = roles.filter(role => role.systemRole === systemRole);
return filtered.map(role => ({
label: role.name,
value: role.id
}));
};

export const UserForm = ({ userFormState, roles, controller, isExternal }) => {
const { errors = [], passwordErrors = {}, id, password } = userFormState;
export const UserForm = ({ state, controller, isExternal }) => {
const { userFormState } = state;
const { errors = [], passwordErrors = {}, id, password, roles } = userFormState;
const passwordRequired = !id || password.length > 0;
return (
<Content>
Expand All @@ -35,24 +25,12 @@ export const UserForm = ({ userFormState, roles, controller, isExternal }) => {
)}
<LabelledField>
<StyledLabel><Message messageKey='users.addRole' /></StyledLabel>
<StyledSelect
className='t_roles'
mode='multiple'
allowClear
onChange={(value) => controller.updateUserFormState('roles', value)}
defaultValue={userFormState.roles}
status={errors.includes('roles') ? 'error' : null}
options={[
{
label: <Message messageKey='roles.types.system' />,
options: getRoleOptions(roles, true)
},
{
label: <Message messageKey='roles.types.other' />,
options: getRoleOptions(roles, false)
}
]}
/>
<RoleSelect
multiple
state={state}
value={roles}
error={errors.includes('roles')}
onChange={value => controller.updateUserFormState('roles', value)}/>
</LabelledField>
<ButtonContainer>
<SecondaryButton
Expand All @@ -73,3 +51,8 @@ export const UserForm = ({ userFormState, roles, controller, isExternal }) => {
</Content>
);
};
UserForm.propTypes = {
state: PropTypes.object.isRequired,
controller: PropTypes.object.isRequired,
isExternal: PropTypes.bool
};
48 changes: 19 additions & 29 deletions bundles/framework/admin-users/view/UsersByRoleTab.jsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,40 @@
import React from 'react';
import { Select, Message } from 'oskari-ui';
import PropTypes from 'prop-types';
import { Message } from 'oskari-ui';
import styled from 'styled-components';
import { Block, Content } from './styled';
import { Block, Content, Button } from './styled';
import { RoleSelect } from './RoleSelect';

const StyledSelect = styled(Select)`
const Margin = styled.div`
margin-bottom: 20px;
`;
const ADMIN = 'admin';

const getOptionGroup = (type, roles) => {
const options = roles.map(({ name, id }) => ({ label: name, value: id }));
return {
title: type,
label: <Message messageKey={`roles.types.${type}`} />,
options
};
};

export const UsersByRoleTab = ({ state, controller }) => {
const { usersByRole, roles, systemRoles } = state;
const { users = [], roleId } = usersByRole;

const { users = [], roleId } = state.usersByRole;
const showNoUsers = roleId && users.length === 0;
const onlyAdmin = systemRoles.filter(role => role.type === ADMIN);
const options = [
getOptionGroup('system', onlyAdmin),
getOptionGroup('other', roles)
];
return (
<Content>
<StyledSelect
className='t_roles'
onChange={(value) => controller.showUsersByRole(value)}
placeholder={<Message messageKey='usersByRole.selectRole' />}
defaultValue={roleId}
options={options}/>
<RoleSelect
onlyAdmin
state={state}
value={roleId}
onChange={controller.showUsersByRole}/>
<Margin />
{users.map(item => {
const { id, user, firstName, lastName } = item;
const details = firstName || lastName ? ` (${firstName} ${lastName})` : '';
return (
<Block key={id}>
<span>{user}{details}</span>
<Button type='edit' onClick={() => controller.editUserFromRoles(id, user)} />
</Block>
)})
}
);
})}
{showNoUsers && <Message messageKey='usersByRole.noUsers' />}
</Content>
);
};
UsersByRoleTab.propTypes = {
state: PropTypes.object.isRequired,
controller: PropTypes.object.isRequired
};
Loading

0 comments on commit b4619bf

Please sign in to comment.