mirror of
https://github.com/getredash/redash.git
synced 2026-05-10 15:00:16 -04:00
225 lines
7.1 KiB
JavaScript
225 lines
7.1 KiB
JavaScript
import { includes, map } from 'lodash';
|
|
import React from 'react';
|
|
import { react2angular } from 'react2angular';
|
|
import Button from 'antd/lib/button';
|
|
|
|
import { Paginator } from '@/components/Paginator';
|
|
|
|
import { wrap as liveItemsList, ControllerType } from '@/components/items-list/ItemsList';
|
|
import { ResourceItemsSource } from '@/components/items-list/classes/ItemsSource';
|
|
import { StateStorage } from '@/components/items-list/classes/StateStorage';
|
|
|
|
import LoadingState from '@/components/items-list/components/LoadingState';
|
|
import ItemsTable, { Columns } from '@/components/items-list/components/ItemsTable';
|
|
import SelectItemsDialog from '@/components/SelectItemsDialog';
|
|
import { UserPreviewCard } from '@/components/PreviewCard';
|
|
|
|
import GroupName from '@/components/groups/GroupName';
|
|
import ListItemAddon from '@/components/groups/ListItemAddon';
|
|
import Sidebar from '@/components/groups/DetailsPageSidebar';
|
|
import Layout from '@/components/layouts/ContentWithSidebar';
|
|
|
|
import { toastr } from '@/services/ng';
|
|
import { currentUser } from '@/services/auth';
|
|
import { Group } from '@/services/group';
|
|
import { User } from '@/services/user';
|
|
import navigateTo from '@/services/navigateTo';
|
|
import { routesToAngularRoutes, cancelEvent } from '@/lib/utils';
|
|
|
|
class GroupMembers extends React.Component {
|
|
static propTypes = {
|
|
controller: ControllerType.isRequired,
|
|
};
|
|
|
|
groupId = parseInt(this.props.controller.params.groupId, 10);
|
|
|
|
group = null;
|
|
|
|
sidebarMenu = [
|
|
{
|
|
key: 'users',
|
|
href: `groups/${this.groupId}`,
|
|
title: 'Members',
|
|
},
|
|
{
|
|
key: 'datasources',
|
|
href: `groups/${this.groupId}/data_sources`,
|
|
title: 'Data Sources',
|
|
isAvailable: () => currentUser.isAdmin,
|
|
},
|
|
];
|
|
|
|
listColumns = [
|
|
Columns.custom((text, user) => (
|
|
<UserPreviewCard user={user} withLink />
|
|
), {
|
|
title: 'Name',
|
|
field: 'name',
|
|
width: null,
|
|
}),
|
|
Columns.custom((text, user) => {
|
|
if (!this.group) {
|
|
return null;
|
|
}
|
|
|
|
// cannot remove self from built-in groups
|
|
if ((this.group.type === 'builtin') && (currentUser.id === user.id)) {
|
|
return null;
|
|
}
|
|
return <Button className="w-100" type="danger" onClick={event => this.removeGroupMember(event, user)}>Remove</Button>;
|
|
}, {
|
|
width: '1%',
|
|
isAvailable: () => currentUser.isAdmin,
|
|
}),
|
|
];
|
|
|
|
removeGroupMember = cancelEvent((user) => {
|
|
Group.removeMember({ id: this.groupId, userId: user.id }).$promise
|
|
.then(() => {
|
|
this.props.controller.updatePagination({ page: 1 });
|
|
this.props.controller.update();
|
|
})
|
|
.catch(() => {
|
|
toastr.error('Failed to remove member from group.');
|
|
});
|
|
});
|
|
|
|
componentDidMount() {
|
|
Group.get({ id: this.groupId }).$promise.then((group) => {
|
|
this.group = group;
|
|
this.forceUpdate();
|
|
});
|
|
}
|
|
|
|
onTableRowClick = (event, item) => navigateTo('users/' + item.id);
|
|
|
|
addMembers = () => {
|
|
const alreadyAddedUsers = map(this.props.controller.allItems, u => u.id);
|
|
SelectItemsDialog.showModal({
|
|
dialogTitle: 'Add Members',
|
|
inputPlaceholder: 'Search users...',
|
|
selectedItemsTitle: 'New Members',
|
|
searchItems: searchTerm => User.query({ q: searchTerm }).$promise.then(({ results }) => results),
|
|
renderItem: (item, { isSelected }) => {
|
|
const alreadyInGroup = includes(alreadyAddedUsers, item.id);
|
|
return {
|
|
content: (
|
|
<UserPreviewCard user={item}>
|
|
<ListItemAddon isSelected={isSelected} alreadyInGroup={alreadyInGroup} />
|
|
</UserPreviewCard>
|
|
),
|
|
isDisabled: alreadyInGroup,
|
|
className: isSelected || alreadyInGroup ? 'selected' : '',
|
|
};
|
|
},
|
|
renderStagedItem: (item, { isSelected }) => ({
|
|
content: (
|
|
<UserPreviewCard user={item}>
|
|
<ListItemAddon isSelected={isSelected} isStaged />
|
|
</UserPreviewCard>
|
|
),
|
|
}),
|
|
save: (items) => {
|
|
const promises = map(items, u => Group.addMember({ id: this.groupId }, { user_id: u.id }).$promise);
|
|
return Promise.all(promises);
|
|
},
|
|
}).result.finally(() => {
|
|
this.props.controller.update();
|
|
});
|
|
};
|
|
|
|
render() {
|
|
const { controller } = this.props;
|
|
return (
|
|
<div data-test="Group">
|
|
<GroupName className="d-block m-t-0 m-b-15" group={this.group} onChange={() => this.forceUpdate()} />
|
|
<Layout>
|
|
<Layout.Sidebar>
|
|
<Sidebar
|
|
controller={controller}
|
|
group={this.group}
|
|
items={this.sidebarMenu}
|
|
canAddMembers={currentUser.isAdmin}
|
|
onAddMembersClick={this.addMembers}
|
|
onGroupDeleted={() => navigateTo('/groups', true)}
|
|
/>
|
|
</Layout.Sidebar>
|
|
<Layout.Content>
|
|
{!controller.isLoaded && <LoadingState className="" />}
|
|
{controller.isLoaded && controller.isEmpty && (
|
|
<div className="text-center">
|
|
There are no members in this group yet.
|
|
{currentUser.isAdmin && (
|
|
<div className="m-t-5">
|
|
<a href="javascript:void(0)" onClick={this.addMembers}>Click here</a>
|
|
{' '} to add members.
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
{
|
|
controller.isLoaded && !controller.isEmpty && (
|
|
<div className="table-responsive">
|
|
<ItemsTable
|
|
items={controller.pageItems}
|
|
columns={this.listColumns}
|
|
showHeader={false}
|
|
onRowClick={this.onTableRowClick}
|
|
context={this.actions}
|
|
orderByField={controller.orderByField}
|
|
orderByReverse={controller.orderByReverse}
|
|
toggleSorting={controller.toggleSorting}
|
|
/>
|
|
<Paginator
|
|
totalCount={controller.totalItemsCount}
|
|
itemsPerPage={controller.itemsPerPage}
|
|
page={controller.page}
|
|
onChange={page => controller.updatePagination({ page })}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
</Layout.Content>
|
|
</Layout>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default function init(ngModule) {
|
|
ngModule.component('pageGroupMembers', react2angular(liveItemsList(
|
|
GroupMembers,
|
|
new ResourceItemsSource({
|
|
isPlainList: true,
|
|
getRequest(unused, { params: { groupId } }) {
|
|
return { id: groupId };
|
|
},
|
|
getResource() {
|
|
return Group.members.bind(Group);
|
|
},
|
|
getItemProcessor() {
|
|
return (item => new User(item));
|
|
},
|
|
}),
|
|
new StateStorage({ orderByField: 'name' }),
|
|
)));
|
|
|
|
return routesToAngularRoutes([
|
|
{
|
|
path: '/groups/:groupId',
|
|
title: 'Group Members',
|
|
key: 'users',
|
|
},
|
|
], {
|
|
reloadOnSearch: false,
|
|
template: '<settings-screen><page-group-members on-error="handleError"></page-group-members></settings-screen>',
|
|
controller($scope, $exceptionHandler) {
|
|
'ngInject';
|
|
|
|
$scope.handleError = $exceptionHandler;
|
|
},
|
|
});
|
|
}
|
|
|
|
init.init = true;
|