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

user component now integrated with /api/users GET endpoint #583

Merged
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
2 changes: 1 addition & 1 deletion config/postgres/initdb/scripts/initial_credentials.dev.sql
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
SELECT * FROM USERS_CREATE( '[email protected]', 'pbkdf2:sha256:150000$c30CjWVB$d1d6d544dfffd2dee5488cfe89cc2f965a8c4cddbf9180ad206f272237a5fa1a', 'Ima Admin', 'Ima Group', true);
SELECT * FROM USERS_CREATE('[email protected]', 'pbkdf2:sha256:150000$K5efuBwy$fcaa41a3203fd8f64b5d4aee241365ffa35e0a3a1c02f605bbc20cbea701cf89', 'Ima User', 'Ima Group' , true);
SELECT * FROM USERS_CREATE('[email protected]', 'pbkdf2:sha256:150000$K5efuBwy$fcaa41a3203fd8f64b5d4aee241365ffa35e0a3a1c02f605bbc20cbea701cf89', 'Ima User', 'Ima Group' , false);
4 changes: 2 additions & 2 deletions src/backend/expungeservice/endpoints/usersview.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ def get(self, user_id):
response_data: Dict[str, List[Dict[str, str]]] = {"users": []}
for user_entry in user_db_data:
response_data["users"].append({
"user_id": user_entry["user_id"],
"id": user_entry["user_id"],
"email": user_entry["email"],
"name": user_entry["name"],
"group_name": user_entry["group_name"],
"group": user_entry["group_name"],
"admin": user_entry["admin"],
"timestamp": user_entry["date_created"]
})
Expand Down
4 changes: 2 additions & 2 deletions src/backend/tests/endpoints/test_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ def test_get_users_success(self):
assert data["users"][0]["admin"] in [True, False]
assert data["users"][0]["timestamp"]
assert data["users"][0]["name"]
assert data["users"][0]["group_name"]
assert data["users"][0]["user_id"]
assert data["users"][0]["group"]
assert data["users"][0]["id"]

def test_get_users_not_admin(self):
self.login(self.user_data["user1"]["email"], self.user_data["user1"]["password"])
Expand Down
17 changes: 17 additions & 0 deletions src/frontend/src/components/LoadingSpinner/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

interface Props {
inputString: string;
}

class LoadingSpinner extends React.Component<Props> {
render() {
return (
<p className="bg-white mv4 pa4 br3 fw6 tc">
<span className="spinner mr2"></span>Loading {this.props.inputString}...
</p>
);
}
}

export default LoadingSpinner;
2 changes: 1 addition & 1 deletion src/frontend/src/components/LogIn/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class LogIn extends React.Component<Props, State> {
) : null}
{this.state.invalidResponse === true ? (
<p id="no_match_msg" className="bg-washed-red mv4 pa3 br3 fw6">
Technical difficulties try again later.
Technical difficulties, please contact system administrator.
</p>
) : null}
</div>
Expand Down
14 changes: 14 additions & 0 deletions src/frontend/src/components/NotAuthorized/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

class NotAuthorized extends React.Component {
render() {
return (
<p className="bg-white mv4 pa4 br3 fw6 tc shadow br3">
You are not authorized to view this content, please contact system
administrator.
</p>
);
}
}

export default NotAuthorized;
2 changes: 1 addition & 1 deletion src/frontend/src/components/OeciLogin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class OeciLogin extends React.Component<Props, State> {
) : null}
{this.state.invalidResponse === true ? (
<p id="no_match_msg" className="bg-washed-red mv4 pa3 br3 fw6">
Technical difficulties try again later.
Technical difficulties, please contact system administrator.
</p>
) : null}
</div>
Expand Down
9 changes: 0 additions & 9 deletions src/frontend/src/components/Spinner/index.tsx

This file was deleted.

14 changes: 14 additions & 0 deletions src/frontend/src/components/TechnicalDifficulties/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

class TechnicalDifficulties extends React.Component {
render() {
return (
<p className="bg-white mv4 pa4 br3 fw6 tc shadow br3">
Something went wrong, please contact system administrator to report
technical difficulties.
</p>
);
}
}

export default TechnicalDifficulties;
24 changes: 19 additions & 5 deletions src/frontend/src/components/User/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,28 @@ interface Props {
class User extends React.Component<Props> {
public render() {
return (
<tr>
<td className="pa3 bb b--black-20">
<a href="#" className="underline">
<tr className="bt b--black-20">
<td className="pa3">
<a href="/admin" className="underline">
{this.props.user.name}
</a>
</td>
<td className="pa3 bb b--black-20">{this.props.user.role}</td>
<td className="pa3 bb b--black-20">{this.props.user.group}</td>
<td className="pa3">{this.props.user.admin ? 'Admin' : 'Search'}</td>
<td className="pa3">{this.props.user.group}</td>
<td className="pa3 flex justify-end">
<button
aria-label={`edit user: ${this.props.user.name}`}
className="navy hover-dark-blue"
>
<i aria-hidden="true" className="fa fa-pen pr3" />
</button>
<button
aria-label={`delete user: ${this.props.user.name}`}
className="navy hover-dark-blue"
>
<i aria-hidden="true" className="fa fa-trash" />
</button>
</td>
</tr>
);
}
Expand Down
107 changes: 70 additions & 37 deletions src/frontend/src/components/UserList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,90 @@
import React from 'react';
import { connect } from 'react-redux';
import { AppState } from '../../redux/store';
import { loadUsers } from '../../redux/users/actions';
import { User as UserTypes, UserState } from '../../redux/users/types';
import { loadUsers, clearUsers } from '../../redux/users/actions';
import { UserState } from '../../redux/users/types';
import User from '../User';
import LoadingSpinner from '../LoadingSpinner';
import NotAuthorized from '../NotAuthorized';
import TechnicalDifficulties from '../TechnicalDifficulties';

interface Props {
users: UserState;
loadUsers: Function;
loadUsers: () => Promise<void>;
clearUsers: Function;
}

interface State {
errorType: string;
}

class UserList extends React.Component<Props> {
public componentWillMount() {
state: State = {
errorType: 'none'
};
componentDidMount() {
// this will call the axios request to populate the component with userList
this.props.loadUsers();
this.props.loadUsers().catch(error => {
if (error.response.status === 403) {
// error if user is not admin
this.setState({ errorType: 'unauthorized' });
} else {
this.setState({ errorType: 'technical' });
}
});
}

public displayUsers = (inputUsers: UserTypes[]) => {
if (inputUsers) {
const returnList = inputUsers.map(user => {
return <User key={user.id} user={user} />;
});
componentWillUnmount() {
this.props.clearUsers();
}

return returnList;
displayNoUsers = () => {
if (this.state.errorType === 'none') {
return <LoadingSpinner inputString={'Users'} />;
} else if (this.state.errorType === 'unauthorized') {
return <NotAuthorized />;
} else {
return <TechnicalDifficulties />;
}
};

public render() {
return (
<section className="cf bg-white shadow br3 mb5">
<div className="pv4 ph3">
<h1 className="f3 fw6 dib">Users</h1>
<button className="bg-navy white bg-animate hover-bg-dark-blue fw6 br2 pv2 ph3 fr">
New User
</button>
</div>
displayUserList = () => {
const returnList = this.props.users.userList.map(user => {
return <User key={user.id} user={user} />;
});

return returnList;
};

displayUsers = () => (
<section className="cf bg-white shadow br3 mb5">
<div className="pv4 ph3">
<h1 className="f3 fw6 dib">Users</h1>
<button className="bg-navy white bg-animate hover-bg-dark-blue fw6 br2 pv2 ph3 fr">
New User
</button>
</div>

<div className="overflow-auto">
<table className="f6 w-100 mw8 center collapse">
<thead className="bb b--black-20">
<tr>
<th className="fw6 tl pb3 ph3 bg-white">Name</th>
<th className="fw6 tl pb3 ph3 bg-white">Role</th>
<th className="fw6 tl pb3 ph3 bg-white">Group</th>
</tr>
</thead>

<tbody className="lh-copy">{this.displayUserList()}</tbody>
</table>
</div>
</section>
);

<div className="overflow-auto">
<table className="f6 w-100 mw8 center" data-cellspacing="0">
<thead>
<tr>
<th className="fw6 bb b--black-20 tl pb3 ph3 bg-white">Name</th>
<th className="fw6 bb b--black-20 tl pb3 ph3 bg-white">Role</th>
<th className="fw6 bb b--black-20 tl pb3 ph3 bg-white">Group</th>
</tr>
</thead>
{this.props.users
? this.displayUsers(this.props.users.userList)
: null}
</table>
</div>
</section>
);
render() {
return this.props.users.userList.length > 0
? this.displayUsers()
: this.displayNoUsers();
}
}

Expand All @@ -61,5 +94,5 @@ const mapStateToProps = (state: AppState) => ({

export default connect(
mapStateToProps,
{ loadUsers }
{ loadUsers, clearUsers }
)(UserList);
11 changes: 7 additions & 4 deletions src/frontend/src/containers/AllRecords.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ const mapStateToProps = (state: AppState) => {
};
};

export default connect(mapStateToProps, {
fetchRecords: loadSearchRecords,
clearRecords: clearSearchRecords
})(AllRecords);
export default connect(
mapStateToProps,
{
fetchRecords: loadSearchRecords,
clearRecords: clearSearchRecords
}
)(AllRecords);
8 changes: 6 additions & 2 deletions src/frontend/src/containers/AllStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { connect } from 'react-redux';
import { AppState } from '../redux/store';
import Spinner from '../components/Spinner';
import LoadingSpinner from '../components/LoadingSpinner';
import NoSearchResults from '../components/NoSearchResults';

type Props = {
Expand All @@ -12,7 +12,11 @@ class AllStatus extends React.Component<Props> {
render() {
return (
<section>
{this.props.loading ? <Spinner /> : <NoSearchResults />}
{this.props.loading ? (
<LoadingSpinner inputString={'your search results'} />
) : (
<NoSearchResults />
)}
</section>
);
}
Expand Down
Loading