Skip to content
Snippets Groups Projects
Commit 18dec7b3 authored by Tom Robinson's avatar Tom Robinson
Browse files

Port admin groups pages to mostly use entities system

parent ab22242a
Branches
Tags
No related merge requests found
......@@ -12,7 +12,6 @@ import {
} from "metabase/lib/groups";
import { KEYCODE_ENTER } from "metabase/lib/keyboard";
import { PermissionsApi } from "metabase/services";
import { t } from "c-3po";
import Icon from "metabase/components/Icon.jsx";
import InputBlurChange from "metabase/components/InputBlurChange.jsx";
......@@ -187,7 +186,7 @@ function GroupRow({
<span className="ml2 text-bold">{getGroupNameLocalized(group)}</span>
</Link>
</td>
<td>{group.members || 0}</td>
<td>{group.member_count || 0}</td>
<td className="text-right">
{showActionsButton ? (
<ActionsPopover
......@@ -245,17 +244,12 @@ function GroupsTable({
// ------------------------------------------------------------ Logic ------------------------------------------------------------
function sortGroups(groups) {
return _.sortBy(groups, group => group.name && group.name.toLowerCase());
}
export default class GroupsListing extends Component {
constructor(props, context) {
super(props, context);
this.state = {
text: "",
showAddGroupRow: false,
groups: null,
groupBeingEdited: null,
alertMessage: null,
};
......@@ -272,26 +266,21 @@ export default class GroupsListing extends Component {
}
// TODO: move this to Redux
onAddGroupCreateButtonClicked() {
async onAddGroupCreateButtonClicked() {
MetabaseAnalytics.trackEvent("People Groups", "Group Added");
PermissionsApi.createGroup({ name: this.state.text }).then(
newGroup => {
const groups = this.state.groups || this.props.groups || [];
const newGroups = sortGroups(_.union(groups, [newGroup]));
this.setState({
groups: newGroups,
showAddGroupRow: false,
text: "",
});
},
error => {
console.error("Error creating group:", error);
if (error.data && typeof error.data === "string") {
this.alert(error.data);
}
},
);
try {
await this.props.create({ name: this.state.text });
this.setState({
showAddGroupRow: false,
text: "",
});
} catch (error) {
console.error("Error creating group:", error);
if (error.data && typeof error.data === "string") {
this.alert(error.data);
}
}
}
onAddGroupTextChanged(newText) {
......@@ -310,18 +299,16 @@ export default class GroupsListing extends Component {
onEditGroupClicked(group) {
this.setState({
groupBeingEdited: _.clone(group),
groupBeingEdited: { ...group },
text: "",
showAddGroupRow: false,
});
}
onEditGroupTextChange(newText) {
let groupBeingEdited = this.state.groupBeingEdited;
groupBeingEdited.name = newText;
const { groupBeingEdited } = this.state;
this.setState({
groupBeingEdited: groupBeingEdited,
groupBeingEdited: { ...groupBeingEdited, name: newText },
});
}
......@@ -331,68 +318,45 @@ export default class GroupsListing extends Component {
});
}
// TODO: move this to Redux
onEditGroupDoneClicked() {
const groups = this.state.groups || this.props.groups || [];
const originalGroup = _.findWhere(groups, {
id: this.state.groupBeingEdited.id,
});
async onEditGroupDoneClicked() {
const { groups } = this.props;
const group = this.state.groupBeingEdited;
const originalGroup = _.findWhere(groups, { id: group.id });
// if name hasn't changed there is nothing to do
if (originalGroup.name === group.name) {
this.setState({
groupBeingEdited: null,
});
return;
}
// ok, fire off API call to change the group
MetabaseAnalytics.trackEvent("People Groups", "Group Updated");
PermissionsApi.updateGroup({ id: group.id, name: group.name }).then(
newGroup => {
// now replace the original group with the new group and update state
let newGroups = _.reject(groups, g => g.id === group.id);
newGroups = sortGroups(_.union(newGroups, [newGroup]));
this.setState({
groups: newGroups,
groupBeingEdited: null,
});
},
error => {
this.setState({ groupBeingEdited: null });
} else {
// ok, fire off API call to change the group
MetabaseAnalytics.trackEvent("People Groups", "Group Updated");
try {
await this.props.update({ id: group.id, name: group.name });
this.setState({ groupBeingEdited: null });
} catch (error) {
console.error("Error updating group name:", error);
if (error.data && typeof error.data === "string") {
this.alert(error.data);
}
},
);
}
}
}
// TODO: move this to Redux
async onDeleteGroupClicked(group) {
const groups = this.state.groups || this.props.groups || [];
MetabaseAnalytics.trackEvent("People Groups", "Group Deleted");
PermissionsApi.deleteGroup({ id: group.id }).then(
() => {
const newGroups = sortGroups(_.reject(groups, g => g.id === group.id));
this.setState({
groups: newGroups,
});
},
error => {
console.error("Error deleting group: ", error);
if (error.data && typeof error.data === "string") {
this.alert(error.data);
}
},
);
try {
await this.props.delete(group);
} catch (error) {
console.error("Error deleting group: ", error);
if (error.data && typeof error.data === "string") {
this.alert(error.data);
}
}
}
render() {
const { groups } = this.props;
const { alertMessage } = this.state;
let { groups } = this.props;
groups = this.state.groups || groups || [];
return (
<AdminPaneLayout
......
import React, { Component } from "react";
import { connect } from "react-redux";
import { getGroup, getGroups, getUsersWithMemberships } from "../selectors";
import { loadGroups, loadGroupDetails } from "../people";
import User from "metabase/entities/users";
import Group from "metabase/entities/groups";
import { getUsersWithMemberships } from "../selectors";
import GroupDetail from "../components/GroupDetail.jsx";
function mapStateToProps(state, props) {
return {
group: getGroup(state, props),
groups: getGroups(state, props),
users: getUsersWithMemberships(state, props),
};
}
const mapDispatchToProps = {
loadGroups,
loadGroupDetails,
};
@connect(mapStateToProps, mapDispatchToProps)
@User.listLoader()
@Group.loader({ id: (state, props) => props.params.groupId })
@Group.listLoader()
@connect((state, props) => ({
users: getUsersWithMemberships(state, props),
}))
export default class GroupDetailApp extends Component {
async componentWillMount() {
this.props.loadGroups();
this.props.loadGroupDetails(this.props.params.groupId);
}
async componentWillReceiveProps(nextProps) {
if (nextProps.params.groupId !== this.props.params.groupId) {
this.props.loadGroupDetails(nextProps.params.groupId);
}
}
render() {
return <GroupDetail {...this.props} />;
}
......
import React, { Component } from "react";
import { connect } from "react-redux";
import { getGroups } from "../selectors";
import { loadGroups } from "../people";
import Group from "metabase/entities/groups";
import GroupsListing from "../components/GroupsListing.jsx";
const mapStateToProps = function(state, props) {
return {
groups: getGroups(state, props),
};
};
const mapDispatchToProps = {
loadGroups,
};
@connect(mapStateToProps, mapDispatchToProps)
@Group.listLoader()
export default class GroupsListingApp extends Component {
async componentWillMount() {
await this.props.loadGroups();
}
render() {
return <GroupsListing {...this.props} />;
}
......
import { createSelector } from "reselect";
import _ from "underscore";
export const getGroups = state => state.admin.people.groups;
export const getGroup = state => state.admin.people.group;
export const getMemberships = state => state.admin.people.memberships;
export const getUsersWithMemberships = createSelector(
......
......@@ -32,7 +32,7 @@ const Users = createEntity({
REACTIVATE,
PASSWORD_RESET_EMAIL,
PASSWORD_RESET_MANUAL,
RESEND_INVITE
RESEND_INVITE,
},
actionDecorators: {
......@@ -65,7 +65,10 @@ const Users = createEntity({
await SessionApi.forgot_password({ email });
return { type: PASSWORD_RESET_EMAIL };
},
passwordResetManual: async ({ id }, password = MetabaseUtils.generatePassword()) => {
passwordResetManual: async (
{ id },
password = MetabaseUtils.generatePassword(),
) => {
MetabaseAnalytics.trackEvent("People Admin", "Manual Password Reset");
await UserApi.update_password({ id, password });
return { type: PASSWORD_RESET_MANUAL, payload: { id, password } };
......
......@@ -112,8 +112,8 @@
(api/check-superuser)
(let [group-id->members (group-id->num-members)]
(for [group (ordered-groups)]
(assoc group :members (or (group-id->members (u/get-id group))
0)))))
(assoc group :member_count (or (group-id->members (u/get-id group))
0)))))
(api/defendpoint GET "/group/:id"
"Fetch the details for a certain permissions group."
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment