/* Copyright (C) 2017 Cloudbase Solutions SRL This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import React from 'react' import { Link } from 'react-router-dom' import { observer } from 'mobx-react' import styled, { css } from 'styled-components' import AlertModal from '@src/components/ui/AlertModal' import Table from '@src/components/ui/Table' import CopyValue from '@src/components/ui/CopyValue' import CopyMultilineValue from '@src/components/ui/CopyMultilineValue' import StatusImage from '@src/components/ui/StatusComponents/StatusImage' import DropdownLink from '@src/components/ui/Dropdowns/DropdownLink' import Button from '@src/components/ui/Button' import type { Project, RoleAssignment, Role } from '@src/@types/Project' import type { User } from '@src/@types/User' import { ThemePalette, ThemeProps } from '@src/components/Theme' const Wrapper = styled.div` ${ThemeProps.exactWidth(ThemeProps.contentWidth)} margin: 0 auto; padding-left: 126px; ` const Info = styled.div` display: flex; flex-wrap: wrap; margin-top: 32px; margin-left: -32px; ` const Field = styled.div` ${ThemeProps.exactWidth('calc(50% - 32px)')} margin-bottom: 32px; margin-left: 32px; ` const Value = styled.div`` const Label = styled.div` font-size: 10px; font-weight: ${ThemeProps.fontWeights.medium}; color: ${ThemePalette.grayscale[3]}; text-transform: uppercase; margin-bottom: 3px; ` const LoadingWrapper = styled.div` display: flex; justify-content: center; width: 100%; margin: 32px 0 64px 0; ` const TableStyled = styled(Table)` margin-top: 42px; margin-bottom: 32px; ` const Buttons = styled.div` margin-top: 64px; display: flex; justify-content: space-between; ` const UserColumn = styled.div` ${props => (props.disabled ? css`color: ${ThemePalette.grayscale[3]};` : '')} ` const UserName = styled(Link)` ${props => (props.disabled ? css`opacity: 0.7;` : '')} color: ${ThemePalette.primary}; text-decoration: none; ` const ButtonsColumn = styled.div` display: flex; flex-direction: column; button { margin-bottom: 16px; &:last-child { margin-bottom: 0; } } ` type Props = { project: Project | null, loading: boolean, users: User[], usersLoading: boolean, roleAssignments: RoleAssignment[], roles: Role[], loggedUserId: string, onEnableUser: (user: User) => void, onRemoveUser: (user: User) => void, onUserRoleChange: (user: User, roleId: string, toggled: boolean) => void, onAddMemberClick: () => void, onDeleteClick: () => void, } type State = { showRemoveUserAlert: boolean, } const testName = 'pdContent' @observer class ProjectDetailsContent extends React.Component { state = { showRemoveUserAlert: false, } selectedUser: User | null = null handleRemoveUserAction(user: User) { this.selectedUser = user this.setState({ showRemoveUserAlert: true }) } handleUserAction(user: User, item: { label: string, value: string }) { switch (item.value) { case 'enable': this.props.onEnableUser(user) break case 'remove': this.handleRemoveUserAction(user) break default: break } } handleRemoveUserConfirmation() { if (this.selectedUser) { this.props.onRemoveUser(this.selectedUser) } this.setState({ showRemoveUserAlert: false }) } handleCloseRemoveUserConfirmation() { this.setState({ showRemoveUserAlert: false }) } renderLoading() { return ( ) } renderButtons() { if (this.props.loading) return null return ( ) } renderInfo() { if (this.props.loading || !this.props.project) { return null } const project = this.props.project return ( {this.renderValue(project.name, 'name')} {project.description ? ( ) : -} {this.renderValue(project.id, 'id')} {project.enabled ? 'Yes' : 'No'} ) } renderUsers() { if (this.props.usersLoading || this.props.loading) { return null } const rows: React.ReactNode[][] = [] const actions = (user: User) => [ { label: `${user.enabled ? 'Disable' : 'Enable'} User`, value: 'enable', }, { label: 'Remove', value: 'remove', }, ] const getUserRoles = (user: RoleAssignment['user']) => { const projectId = this.props.project ? this.props.project.id : '' const roles = this.props.roleAssignments .filter(a => a.scope.project && a.scope.project.id === projectId) .filter(a => a.user.id === user.id) .map(a => ({ value: a.role.id, label: a.role.name })) return roles } const allRoles = this.props.roles .filter(r => r.name !== 'key-manager:service-admin') .map(r => ({ value: r.id, label: r.name })) this.props.users.forEach(user => { const userActions = actions(user) const userRoles = getUserRoles(user) const columns = [ {user.name} , (userRoles.length > 0 ? userRoles.map(r => r.label).join(', ') : 'No roles')} selectedItems={userRoles.map(r => r.value)} listWidth="120px" multipleSelection items={allRoles} labelStyle={{ color: ThemePalette.grayscale[4] }} disabled={!user.enabled} style={{ opacity: user.enabled ? 1 : 0.7 }} onChange={item => { this.props.onUserRoleChange( user, item.value, !userRoles.find(i => i.value === item.value), ) }} />, {user.enabled ? 'Enabled' : 'Disabled'}, { this.handleUserAction(user, item) }} disabled={user.id === this.props.loggedUserId} style={{ opacity: user.id === this.props.loggedUserId ? 0.7 : 1 }} itemStyle={item => `color: ${item.value === 'remove' ? ThemePalette.alert : ThemePalette.black};`} />, ] rows.push(columns) }) return ( ) } renderValue(value: string, dataTestId: string) { return value !== '-' ? ( ) : {value} } render() { return ( {this.renderInfo()} {this.props.loading ? this.renderLoading() : null} {this.renderUsers()} {!this.props.loading && this.props.usersLoading ? this.renderLoading() : null} {this.renderButtons()} {this.state.showRemoveUserAlert ? ( { this.handleRemoveUserConfirmation() }} onRequestClose={() => { this.handleCloseRemoveUserConfirmation() }} /> ) : null} ) } } export default ProjectDetailsContent