Skip to content

Commit 27ee4e9

Browse files
committed
Fixed routing issues on user-management component.
1 parent 23a12eb commit 27ee4e9

File tree

16 files changed

+160
-40
lines changed

16 files changed

+160
-40
lines changed

app/assets/javascripts/controllers/tree_view_controller.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
(function() {
33
var CONTROLLER_NAME = 'treeViewController';
44

5-
var TreeViewController = function($http, $scope) {
5+
var TreeViewController = function($http, $scope, $timeout) {
66
var vm = this;
77
vm.$http = $http;
88
vm.$scope = $scope;
@@ -26,7 +26,9 @@
2626
}
2727

2828
if (payload.updateTreeNode && _.isObject(payload.updateTreeNode) && Object.keys(payload.updateTreeNode).length > 0) {
29-
vm.updateTreeNode(payload.updateTreeNode);
29+
$timeout(function() {
30+
vm.updateTreeNode(payload.updateTreeNode);
31+
})
3032
vm.$scope.$apply();
3133
}
3234
});
@@ -91,11 +93,15 @@
9193
};
9294

9395
vm.initData = function(tree, data, selected) {
96+
sendDataWithRx({ treeInit: { type: 'tree-initialized', tree: tree, selected: selected, data: data } }); // TO DO delete if not necesarry
9497
vm.data[tree] = vm.data[tree] || data;
9598
vm.selectedNodes[tree] = vm.selectedNodes[tree] || { key: selected };
9699
};
97100

98101
vm.lazyLoad = function(node, name, url) {
102+
if (!vm.reactRouting && node.key === 'xx-u') {
103+
return;
104+
}
99105
return new Promise(function(resolve) {
100106
vm.$http.post(url, {
101107
id: node.key,
@@ -138,6 +144,6 @@
138144
};
139145
};
140146

141-
TreeViewController.$inject = ['$http', '$scope'];
147+
TreeViewController.$inject = ['$http', '$scope', '$timeout'];
142148
window.miqHttpInject(angular.module('ManageIQ.treeView')).controller(CONTROLLER_NAME, TreeViewController);
143149
})();

app/assets/javascripts/miq_application.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,20 @@ function miqSelectPickerEvent(element, url, options) {
12701270
}
12711271

12721272
function miqAccordSelect(e) {
1273+
/**
1274+
* clean lingering React components from virtual DOM and reset routing
1275+
*/
1276+
ManageIQ.component.cleanVirtualDom();
1277+
var historyReducer = ManageIQ.redux.store.getState().historyReducer;
1278+
if (historyReducer && historyReducer.activeController) {
1279+
/**
1280+
* store last React router action to history reducer
1281+
*/
1282+
ManageIQ.redux.storeLastRoute({ route: ManageIQ.redux.history.location.pathname });
1283+
ManageIQ.redux.push('/');
1284+
ManageIQ.redux.registerController({ controller: null });
1285+
}
1286+
12731287
if (ManageIQ.noCollapseEvent) { // implicitly return true when the noCollapseEvent is set
12741288
return true;
12751289
}

app/assets/javascripts/miq_tree.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ function miqInitTree(options, tree) {
575575
miqTreeState(options.cookie_id, node.key, false);
576576
},
577577
lazyLoad: function(node, display) {
578-
if (options.autoload) {
578+
if (options.autoload && node.key !== 'xx-u') {
579579
$.ajax({
580580
url: '/' + options.controller + '/tree_autoload',
581581
type: 'post',

app/controllers/ops_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ def update_toolbar
111111
when "user_center_tb"
112112
@record = User.find(params[:id]) if params[:id]
113113
end
114-
toolbar = build_toolbar(params[:toolbar_name])
115-
render :json => {:toolbar => toolbar, :id => params[:id]}
114+
@explorer = true
115+
render :json => {:toolbar => toolbar_from_hash, :id => params[:id]}
116116
end
117117

118118
def user_tags

app/helpers/application_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,7 @@ def _toolbar_chooser
766766
# keys are toolbar <div> names and values are toobar identifiers (now YAML files)
767767
#
768768
def calculate_toolbars
769+
controller = try(:controller) || self unless defined?(controller) && controller.present?
769770
toolbars = {}
770771
if inner_layout_present? # x_taskbar branch
771772
toolbars['history_tb'] = history_toolbar_filename

app/javascript/components/rbac-user-module/components/user-add.jsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,17 @@ class UserAdd extends Component {
4848
<div>
4949
<h1>User add</h1>
5050
<RbacUserForm
51-
groups={groups}
51+
groups={groups.sort((first, second) => {
52+
const firstLabel = first.label.toUpperCase();
53+
const secondLabel = second.label.toUpperCase();
54+
if (firstLabel < secondLabel) {
55+
return -1;
56+
}
57+
if (firstLabel > secondLabel) {
58+
return 1;
59+
}
60+
return 0;
61+
})}
5262
editDisabled={isEditing && initialValues.userid === 'admin'}
5363
newRecord={!isEditing}
5464
initialValues={initialValues

app/javascript/components/rbac-user-module/components/user-detail.jsx

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,25 @@ export class UserDetail extends Component {
3939
return (
4040
<div>
4141
<RbacUserPreview user={this.props.user} />
42-
<div className="form-horizontal rbac-user-preview">
43-
<Grid fluid>
44-
<Row>
45-
<FormGroup>
46-
<Col md={2} componentClass="label" className="control-label">
47-
Custom button events
48-
</Col>
49-
<Col md={8}>
50-
{ customEvents && customEvents.length > 0
51-
? <Fragment><Icon type="fa" name="star" />&nbsp;<Link to={`${this.props.match.url}/custom-button-events`}>{customEvents.length}</Link></Fragment>
52-
: customEvents && customEvents.length === 0 ? 'None' : <Spinner inline loading size="sm" />}
53-
</Col>
54-
</FormGroup>
55-
</Row>
56-
</Grid>
57-
</div>
42+
{ customEvents && customEvents.length > 0 &&
43+
<div className="form-horizontal rbac-user-preview">
44+
<Grid fluid>
45+
<Row>
46+
<FormGroup>
47+
<Col md={2} componentClass="label" className="control-label">
48+
Custom button events
49+
</Col>
50+
<Col md={8}>
51+
<Fragment>
52+
<Icon type="fa" name="star" />&nbsp;
53+
<Link to={`${this.props.match.url}/custom-button-events`}>{customEvents.length}</Link>
54+
</Fragment>
55+
</Col>
56+
</FormGroup>
57+
</Row>
58+
</Grid>
59+
</div>
60+
}
5861
<hr />
5962
<RbacUserTagsList tags={tags} tenant={tenant} />
6063
</div>

app/javascript/components/rbac-user-module/index.jsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { Component } from 'react';
2-
import { bindActionCreators, combineReducers } from 'redux';
2+
import { bindActionCreators } from 'redux';
33
import { connect } from 'react-redux';
44
import { Spinner, Grid, Row, Col } from 'patternfly-react';
55
import { ConnectedRouter } from 'connected-react-router';
@@ -25,11 +25,13 @@ import {
2525
RBAC_USER_LIST_TAGS,
2626
RBAC_USER_LIST_DELETE,
2727
} from './rx-routing';
28+
import historyReducer from '../../miq-redux/history-reducer';
2829

2930
class RbacModule extends Component {
3031
constructor(props) {
3132
super(props);
32-
ManageIQ.redux.addReducer(combineReducers({ usersReducer }));
33+
ManageIQ.redux.addReducer({ usersReducer, historyReducer });
34+
ManageIQ.redux.registerController({ controller: 'configurationRbac' });
3335
this.historyUnlisten = ManageIQ.redux.history.listen(({ pathname }, action) => {
3436
if (pathname === '/add' || pathname === '/add/copy' || pathname === '/assign-company-tags' || pathname.match(/^\/edit\/[0-9]+$/)) {
3537
// hide toolbar when adding or editing
@@ -39,19 +41,24 @@ class RbacModule extends Component {
3941
const toolbarUrl = `/ops/update_toolbar?toolbar_name=user${pathname === '/' ? 's' : ''}_center_tb${pathname.match(/\/preview\/[0-9]+/)
4042
? `&id=${pathname.replace(/^\D+/g, '')}`
4143
: ''}`;
42-
http.get(toolbarUrl).then(data => sendDataWithRx({ redrawToolbar: [data.toolbar] }));
44+
http.get(toolbarUrl).then(data => sendDataWithRx({ redrawToolbar: data.toolbar.filter(item => item !== null) }));
4345
const treeUrl = '/tree/ops_rbac?id=xx-u';
4446
if (pathname === '/' && action === 'POP') {
4547
http.get(treeUrl).then(() => this.sendTreeUpdate({ state: { selected: true } }));
46-
} else if (action === 'POP') {
48+
} else {
4749
http.get(treeUrl).then(users => users.map(user => ({
4850
...user,
4951
state: { selected: user.key === `u-${pathname.replace(/^\D+/g, '')}` },
5052
}))).then(data => this.sendTreeUpdate({ nodes: [...data], state: { selected: false } }));
5153
}
5254
});
53-
this.rxSubscription = listenToRx(({ rbacRouting }) => {
55+
this.rxSubscription = listenToRx(({ rbacRouting, treeInit }) => {
5456
if (rbacRouting) this.chooseRoute(rbacRouting.type)();
57+
if (treeInit && treeInit.tree === 'rbac_tree') {
58+
if (ManageIQ.redux.history.location.pathname === '/' && treeInit.selected.match(/^u-[0-9]+$/)) {
59+
this.props.navigate(`/preview/${treeInit.selected.split('-').pop()}`);
60+
}
61+
}
5562
});
5663
}
5764

@@ -61,12 +68,18 @@ class RbacModule extends Component {
6168
http.get(treeUrl).then(users => users.map(user => ({
6269
...user,
6370
state: { selected: user.key === `u-${this.props.pathname.replace(/^\D+/g, '')}` },
64-
}))).then(data => setTimeout(this.sendTreeUpdate({ nodes: [...data], state: { selected: this.props.pathname === '/' } }), 2000)); // have to w8 for the tree to initialize first...
71+
}))).then((data) => {
72+
setTimeout(this.sendTreeUpdate({ nodes: [...data], state: { selected: this.props.pathname === '/' } }), 2000);
73+
}); // have to w8 for the tree to initialize first...
6574

6675
const toolbarUrl = `/ops/update_toolbar?toolbar_name=user${this.props.pathname === '/' ? 's' : ''}_center_tb${this.props.pathname.match(/\/preview\/[0-9]+/)
6776
? `&id=${this.props.pathname.replace(/^\D+/g, '')}`
6877
: ''}`;
69-
http.get(toolbarUrl).then(data => sendDataWithRx({ redrawToolbar: [data.toolbar] }));
78+
http.get(toolbarUrl).then(data => sendDataWithRx({ redrawToolbar: data.toolbar.filter(item => item !== null) }));
79+
80+
if (this.props.lastAction) {
81+
this.props.navigate(this.props.lastAction);
82+
}
7083
}
7184

7285
componentWillUnmount() {
@@ -122,13 +135,14 @@ class RbacModule extends Component {
122135
}
123136
}
124137

125-
const mapStateToProps = ({ usersReducer, router: { location: { pathname } } }) => ({
138+
const mapStateToProps = ({ historyReducer, usersReducer, router: { location: { pathname } } }) => ({
126139
isLoaded: !!usersReducer && !!usersReducer.rows,
127140
selectedUsers: !!usersReducer && usersReducer.selectedUsers,
128141
editUserId: !!usersReducer && usersReducer.selectedUsers && usersReducer.selectedUsers.length > 0
129142
? usersReducer.selectedUsers[0].id
130143
: undefined,
131144
pathname,
145+
lastAction: pathname === '/' && historyReducer && historyReducer.configurationRbac,
132146
});
133147

134148
const mapDispatchToProps = dispatch => bindActionCreators({
@@ -147,11 +161,13 @@ RbacModule.propTypes = {
147161
deleteMultipleusers: PropTypes.func.isRequired,
148162
selectedUsers: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.bool]),
149163
isLoaded: PropTypes.bool.isRequired,
164+
lastAction: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
150165
};
151166

152167
RbacModule.defaultProps = {
153168
editUserId: undefined,
154169
selectedUsers: false,
170+
lastAction: undefined,
155171
};
156172

157173
export default connect(mapStateToProps, mapDispatchToProps)(RbacModule);

app/javascript/components/rbac-user-module/redux/actions.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { push } from 'connected-react-router';
1+
import { push, goBack } from 'connected-react-router';
22
import * as actionTypes from './action-types';
33
import * as endpoints from './endpoints';
44
import { API, http } from '../../../http_api';
@@ -95,7 +95,16 @@ export const requestUsers = () => (dispatch) => {
9595
groupId: group.id,
9696
value: group.id,
9797
onClick: () => dispatch(handleUserDetailLinkAction(`g-${group.id}`)),
98-
})),
98+
})).sort((a, b) => {
99+
const firstValue = a.label.toLowerCase();
100+
const secondValue = b.label.toLowerCase();
101+
if (firstValue < secondValue) {
102+
return -1;
103+
} else if (firstValue > secondValue) {
104+
return 1;
105+
}
106+
return 0;
107+
}),
99108
})))
100109
.then(data => dispatch(loadUsersData({ rows: data })))
101110
.then(() => dispatch(fetchSucesfull()))
@@ -164,7 +173,7 @@ export const editUser = (user, userId) => (dispatch) => {
164173
dispatch(fetchData(actionTypes.EDIT_USER));
165174
return API.put(endpoints.modifyUserUrl(userId), user, { skipErrors: [500] })
166175
.then(
167-
() => dispatch(navigate('/')),
176+
() => dispatch(goBack()),
168177
(err) => { throw err; },
169178
)
170179
.then(() => dispatch(createFlashMessage(sprintf(__('User "%s" was saved'), user.name), 'success')))
@@ -294,6 +303,7 @@ const loadUserCustomEvents = userid => dispatch =>
294303

295304
export const fetchCustomEventsIfNeeded = userid => (dispatch, getState) => {
296305
const { usersReducer: { userCustomEvents } } = getState();
306+
if (!JSON.parse(localStorage.userFeatures).includes('everything')) return;
297307
if (!userCustomEvents[userid]) return dispatch(loadUserCustomEvents(userid));
298308
return Promise.resolve();
299309
};

app/javascript/components/rbac-user-module/redux/test/actions.test.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,13 @@ describe('Rbac user async actions', () => {
344344
.getOnce(endpoints.getUsersUrl, { resources: [] });
345345
const expectedActions = [{
346346
type: actionTypes.EDIT_USER,
347-
}, routeToRootAction, expect.objectContaining({
347+
}, {
348+
type: '@@router/CALL_HISTORY_METHOD',
349+
payload: expect.objectContaining({
350+
args: [],
351+
method: 'goBack',
352+
}),
353+
}, expect.objectContaining({
348354
flashMessage: sucesfullFlashMessage,
349355
type: actionTypes.ADD_FLASH_MESSAGE,
350356
}), {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export const prefix = '@@router-history/';
2+
3+
export const STORE_LAST_ACTION = `${prefix}Store last action`;
4+
export const REMOVE_LAST_ACTION = `${prefix}Remove last action`;
5+
export const REGISTER_CONTROLLER = `${prefix}Register controller`;
6+
7+
const initialState = {};
8+
9+
const historyReducer = (state = initialState, action) => {
10+
switch (action.type) {
11+
case STORE_LAST_ACTION:
12+
return { ...state, [state.activeController]: action.payload.route };
13+
case REMOVE_LAST_ACTION:
14+
return { ...state, [state.activeController]: undefined };
15+
case REGISTER_CONTROLLER:
16+
return { ...state, activeController: action.payload.controller };
17+
default:
18+
return state;
19+
}
20+
};
21+
22+
export default historyReducer;
Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,33 @@
11
import { push, replace, go, goBack, goForward } from 'connected-react-router';
2+
import { STORE_LAST_ACTION, REMOVE_LAST_ACTION, REGISTER_CONTROLLER } from './history-reducer';
23

3-
const createReduxRoutingActions = ({ dispatch }) => ({
4-
push: where => dispatch(push(where)),
4+
export const createReduxRoutingActions = ({ dispatch }) => ({
5+
push: (where) => {
6+
if (ManageIQ.redux.history.location.pathname !== where) {
7+
dispatch(push(where));
8+
}
9+
},
510
replace: where => dispatch(replace(where)),
611
go: howMany => dispatch(go(howMany)),
712
goBack: () => dispatch(goBack()),
813
goForward: () => dispatch(goForward()),
914
});
1015

16+
export const storeLastRoute = ({ route }) => ({
17+
type: STORE_LAST_ACTION,
18+
payload: {
19+
route,
20+
},
21+
});
22+
23+
export const removeLastRoute = ({ controller }) => ({
24+
type: REMOVE_LAST_ACTION,
25+
payload: { controller },
26+
});
27+
28+
export const registerController = ({ controller }) => ({
29+
type: REGISTER_CONTROLLER,
30+
payload: { controller },
31+
});
32+
1133
export default createReduxRoutingActions;

app/javascript/packs/application-common.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { rxSubject, sendDataWithRx, listenToRx } from '../miq_observable';
2222

2323
import { initializeStore } from '../miq-redux';
2424
import { history } from '../miq-component/react-history.ts';
25-
import createReduxRoutingActions from '../miq-redux/redux-router-actions';
25+
import createReduxRoutingActions, { storeLastRoute, removeLastRoute, registerController } from '../miq-redux/redux-router-actions';
2626

2727
ManageIQ.react = {
2828
mount,
@@ -42,6 +42,9 @@ ManageIQ.redux = {
4242
addReducer: store.injectReducers,
4343
history,
4444
...createReduxRoutingActions(store),
45+
storeLastRoute: data => ManageIQ.redux.store.dispatch(storeLastRoute(data)),
46+
removeLastRoute: data => ManageIQ.redux.store.dispatch(removeLastRoute(data)),
47+
registerController: data => ManageIQ.redux.store.dispatch(registerController(data)),
4548
};
4649

4750
ManageIQ.angular.rxSubject = rxSubject;

app/views/ops/_rbac_group_details.html.haml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
- if role_allows?(:feature => "rbac_user_show")
8484
- @group.users.sort_by { |a| a.name.downcase }.each do |u|
8585
- params = {:class => "pointer",
86-
:onclick => "miqOnClickSelectRbacTreeNode('u-#{u.id}'); ManageIQ.redux.push('/preview/#{u.id}')",
86+
:onclick => "miqOnClickSelectRbacTreeNode('u-#{u.id}');ManageIQ.redux.push('/preview/#{u.id}');ManageIQ.redux.storeLastRoute({route: '/preview/#{u.id}'})",
8787
:title => _("View this User")}
8888
%i.pficon.pficon-user{params}
8989
= link_to(u.name, "#", params)

0 commit comments

Comments
 (0)