Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions app/javascript/components/settings-users-form/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useState } from 'react';
import { Button } from 'carbon-components-react';

/** button component used as a mapper to change the password */
export const ChangePasswordButton = (props) => {
const { newRecord, enableConfirmPassword, isConfirmPasswordEnabled } = props;
const [isChangingPassword, setIsChangingPassword] = useState(false);

const handleClick = () => {
/**Enable change password button if its not a new record */
if (!newRecord) {
enableConfirmPassword(!isConfirmPasswordEnabled);
setIsChangingPassword(!isChangingPassword);
}
};

return !newRecord ? (
<div className="change-button-container">
<Button kind="secondary" onClick={handleClick} className="change-button">
{isChangingPassword ? "Cancel" : "Change"}
</Button>
</div>
) : null;
};
134 changes: 134 additions & 0 deletions app/javascript/components/settings-users-form/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import React, { useState, useEffect } from 'react';
import MiqFormRenderer from '@@ddf';
import PropTypes from 'prop-types';
import createSchema from './schema';
import { resources } from '../../spec/schedule-form/data';
import handleFailure from '../../helpers/handle-failure';
import componentMapper from '../../forms/mappers/componentMapper';
import { ChangePasswordButton } from './helper';

const SettingsUsersForm = ({ recordId }) => {
const newRecord = recordId === 'new';

const [data, setData] = useState({
isLoading: !!recordId,
groups: [],
initialValues: undefined,
userid: '',
});


const enableConfirmPassword = (enable) => {
setIsConfirmPasswordEnabled(enable);
};

/** State variable to control the Confirm Password field */
const [isConfirmPasswordEnabled, setIsConfirmPasswordEnabled] = useState(!newRecord);

const mapper = {
...componentMapper,
'changePassword': ChangePasswordButton,
};

const validatorMapper = {
'same-password': () => (value, allValues) => value !== allValues.password ? 'Password do not match' : undefined
}

const redirectUrl = (newRecord, button) => `/ops/settings_users_helper/${newRecord}?button=${button}`;

const USER_ACTIONS = {
CREATE: 'create',
SAVE: 'save',
CANCEL: 'cancel',
RESET: 'reset',
};

/** Generate dropdown options from resources */
const groupOptions = (resources) => resources.map((item) => ({label: item.description, value: item.id}))

/** Fetch data from the API on component mount */
useEffect(() => {
if (recordId && !newRecord) {
Promise.all([
API.get(`/api/groups?expand=resources`),
API.get(`/api/users/${recordId}?expand=resources/`)])
.then(([groups, users]) => {
console.log(groups,"groupid");
console.log(users,"userid");
setData({
...data,
isLoading: false,
groups: groupOptions(groups.resources),
initialValues: users,
userid: users.userid || '',
});
});
} else {
API.get(`/api/groups?expand=resources`).then(({resources}) => {
setData({
...data,
groups: groupOptions(resources),
isLoading: false
});
})
}
}, [recordId]);

console.log(data,"initial values")

/** Function to handle form submission */
const onSubmit = (values, newRecord, recordId) => {
const userPayload = {
userid: values.userid,
password: values.password,
name: values.name,
email:values.email,
// group: { id:20},
group: values.current_group_id,
};

console.log(values,"values")
const url = newRecord ? '/api/users' : `/api/users/${recordId}`;
API.post(url, userPayload, {
skipErrors: [400, 500]
})
.then((response) => {
const createdRecordId = newRecord ? response.id : recordId;
window.miqJqueryRequest(redirectUrl(createdRecordId));
})
.catch(handleFailure);

};

const onCancel = () => {
/** If it's a new record, redirect to the previous page */
if (newRecord) {
window.miqJqueryRequest(redirectUrl(recordId, USER_ACTIONS.CANCEL));
} else {
/** For an existing user, reset the form values to the initial state */
setData({ initialValues, isLoading: false });
}
};

return !data.isLoading && (
<MiqFormRenderer
schema={createSchema(newRecord, data.groups, data.userid, isConfirmPasswordEnabled)}
initialValues={data.initialValues}
// componentMapper={mapper}
componentMapper={{ ...mapper, 'changePassword': (props) => <ChangePasswordButton {...props} newRecord={newRecord} enableConfirmPassword={enableConfirmPassword} /> }}
onSubmit={onSubmit}
onCancel={() => onCancel()}
canReset={!newRecord}
buttonsLabels={{
submitLabel: newRecord ? __('Add') : __('Save')
}}
validatorMapper={validatorMapper}
/>
);
};

SettingsUsersForm.propTypes = {
recordId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
};

export default SettingsUsersForm;
95 changes: 95 additions & 0 deletions app/javascript/components/settings-users-form/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { componentTypes, validatorTypes } from '@@ddf';
import FormSpy from '@data-driven-forms/react-form-renderer/form-spy';

const formSchema = (newRecord, groups, userid, isConfirmPasswordEnabled ) => ({
fields: [
{
component: componentTypes.SUB_FORM,
id: 'name-wrapper',
name: 'subform-1',
title: __('User Information'),
fields: [
{
component: componentTypes.TEXT_FIELD,
id: 'name',
name: 'name',
label: __('Full Name'),
maxLength: 50,
// validate: [{ type: validatorTypes.REQUIRED }],
isRequired: newRecord,
isDisabled: userid === 'admin',
},
{
component: componentTypes.TEXT_FIELD,
id: 'userid',
name: 'userid',
label: __('Username'),
maxLength: 50,
isRequired: newRecord,
isDisabled: userid === 'admin',
},
{
component: componentTypes.TEXT_FIELD,
id: 'password',
name: 'password',
// type: 'password',
label: __('Password'),
placeholder: newRecord ? ' ' : '●●●●●●●●',
maxLength: 50,
isRequired: newRecord,
isDisabled: !newRecord && isConfirmPasswordEnabled, // Disable when not a new record or isConfirmPasswordEnabled is false
},
{
component: 'changePassword',
id: 'changePassword',
name: 'changePassword',
label: __('Change Password'),
},
{
component: componentTypes.TEXT_FIELD,
id: 'verify',
name: 'verify',
type: 'password',
maxLength: 50,
validate: [
{ type: 'same-password', errorText: 'Passwords do not match' } // Add an error message
],
label: __('Confirm Password'),
isRequired: newRecord,
condition: {
when: 'password',
isNotEmpty: true
}
},
{
component: componentTypes.TEXT_FIELD,
id: 'email',
name: 'email',
label: __('E-mail Address'),
maxLength: 253,
autoComplete: 'off',
validate: [
{
type: 'pattern',
pattern: '[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$',
message: 'Invalid email format',
},
],
isRequired: newRecord,
},
{
component: componentTypes.SELECT,
id: 'available_groups',
name: 'available_groups',
label: __('Available Groups'),
placeholder: __('Choose one or more Groups'),
isRequired: newRecord,
// isMulti: true,
options: groups,
},
],
},
],
});

export default formSchema;
2 changes: 2 additions & 0 deletions app/javascript/packs/component-definitions-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ import StorageServiceForm from '../components/storage-service-form';
import VolumeMappingForm from '../components/volume-mapping-form';
import ZoneForm from '../components/zone-form';
import AnsiblePlayBookEditCatalogForm from '../components/ansible-playbook-edit-catalog-form';
import SettingsUsersForm from '../components/settings-users-form';

/**
* Add component definitions to this file.
Expand Down Expand Up @@ -331,3 +332,4 @@ ManageIQ.component.addReact('VolumeMappingForm', VolumeMappingForm);
ManageIQ.component.addReact('VmCommonRenameForm', VmCommonRenameForm);
ManageIQ.component.addReact('ZoneForm', ZoneForm);
ManageIQ.component.addReact('AnsiblePlayBookEditCatalogForm', AnsiblePlayBookEditCatalogForm);
ManageIQ.component.addReact('SettingsUsersForm', SettingsUsersForm);
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import toJson from 'enzyme-to-json';
import fetchMock from 'fetch-mock';
import { act } from 'react-dom/test-utils';

import { mount } from '../helpers/mountForm';
import SettingsUsersForm from '../../components/settings-users-form';

describe('SettingsUsersForm Component', () => {
afterEach(() => {
fetchMock.reset();
fetchMock.restore();
});
it('should render a new SettingsUsersForm form', async(done) => {
let wrapper;
await act(async() => {
wrapper = mount(<SettingsUsersForm recordId="new" />);
});
wrapper.update();
expect(toJson(wrapper)).toMatchSnapshot();
done();
});

it('should render edit SettingsUsersForm', async(done) => {
fetchMock.getOnce('/api/groups?expand=resources/', {});
let wrapper;
await act(async() => {
wrapper = mount(<SettingsUsersForm recordId="100" />);
});
expect(fetchMock.calls()).toHaveLength(1);
expect(fetchMock.called('/api/groups?expand=resources/100')).toBe(true);
expect(toJson(wrapper)).toMatchSnapshot();
done();
});
});
3 changes: 3 additions & 0 deletions app/views/ops/_rbac_user_details.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
- if @edit
= react('SettingsUsersForm', {:recordId => params[:id] || "new"})
-# = params[:id]
-# = @edit[:user_id]
- change_stored_password ||= _("Change")
- cancel_password_change ||= _("Cancel")
- stored_password_placeholder = "●●●●●●●●"
Expand Down