/*
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