| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- /*
- 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 <http://www.gnu.org/licenses/>.
- */
- 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<any>`
- ${ThemeProps.exactWidth(ThemeProps.contentWidth)}
- margin: 0 auto;
- padding-left: 126px;
- `
- const Info = styled.div<any>`
- display: flex;
- flex-wrap: wrap;
- margin-top: 32px;
- margin-left: -32px;
- `
- const Field = styled.div<any>`
- ${ThemeProps.exactWidth('calc(50% - 32px)')}
- margin-bottom: 32px;
- margin-left: 32px;
- `
- const Value = styled.div<any>``
- const Label = styled.div<any>`
- font-size: 10px;
- font-weight: ${ThemeProps.fontWeights.medium};
- color: ${ThemePalette.grayscale[3]};
- text-transform: uppercase;
- margin-bottom: 3px;
- `
- const LoadingWrapper = styled.div<any>`
- 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<any>`
- margin-top: 64px;
- display: flex;
- justify-content: space-between;
- `
- const UserColumn = styled.div<any>`
- ${props => (props.disabled ? css`color: ${ThemePalette.grayscale[3]};` : '')}
- `
- const UserName = styled(Link)<any>`
- ${props => (props.disabled ? css`opacity: 0.7;` : '')}
- color: ${ThemePalette.primary};
- text-decoration: none;
- `
- const ButtonsColumn = styled.div<any>`
- 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<Props, State> {
- 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 (
- <LoadingWrapper>
- <StatusImage />
- </LoadingWrapper>
- )
- }
- renderButtons() {
- if (this.props.loading) return null
- return (
- <Buttons>
- <ButtonsColumn>
- <Button
- onClick={this.props.onAddMemberClick}
- >Add Member
- </Button>
- </ButtonsColumn>
- <ButtonsColumn>
- <Button
- alert
- hollow
- onClick={() => { this.props.onDeleteClick() }}
- >Delete Project
- </Button>
- </ButtonsColumn>
- </Buttons>
- )
- }
- renderInfo() {
- if (this.props.loading || !this.props.project) {
- return null
- }
- const project = this.props.project
- return (
- <Info>
- <Field>
- <Label>Name</Label>
- {this.renderValue(project.name, 'name')}
- </Field>
- <Field>
- <Label>Description</Label>
- {project.description ? (
- <CopyMultilineValue
- value={project.description}
- />
- ) : <Value>-</Value>}
- </Field>
- <Field>
- <Label>ID</Label>
- {this.renderValue(project.id, 'id')}
- </Field>
- <Field>
- <Label>Enabled</Label>
- <Value>{project.enabled ? 'Yes' : 'No'}</Value>
- </Field>
- </Info>
- )
- }
- 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 = [
- <UserName
- data-test-id={`pdContent-users-${user.name}`}
- disabled={!user.enabled}
- to={`/users/${user.id}`}
- >{user.name}
- </UserName>,
- <DropdownLink
- data-test-id={`${testName}-roles-${user.name}`}
- width="214px"
- getLabel={() => (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),
- )
- }}
- />,
- <UserColumn disabled={!user.enabled}>{user.enabled ? 'Enabled' : 'Disabled'}</UserColumn>,
- <DropdownLink
- data-test-id={`${testName}-actions-${user.name}`}
- noCheckmark
- width="82px"
- items={userActions}
- selectedItem=""
- selectItemLabel="Actions"
- listWidth="120px"
- onChange={item => { 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 (
- <TableStyled
- data-test-id={`${testName}-members`}
- header={['Member', 'Roles', 'Status', '']}
- items={rows}
- noItemsLabel="No members available!"
- columnsStyle={[css`color: ${ThemePalette.black};`]}
- />
- )
- }
- renderValue(value: string, dataTestId: string) {
- return value !== '-' ? (
- <CopyValue
- data-test-id={`${testName}-${dataTestId}`}
- value={value}
- maxWidth="90%"
- />
- ) : <Value>{value}</Value>
- }
- render() {
- return (
- <Wrapper>
- {this.renderInfo()}
- {this.props.loading ? this.renderLoading() : null}
- {this.renderUsers()}
- {!this.props.loading && this.props.usersLoading ? this.renderLoading() : null}
- {this.renderButtons()}
- {this.state.showRemoveUserAlert ? (
- <AlertModal
- isOpen
- title="Remove User?"
- message="Are you sure you want to remove this user from the project?"
- extraMessage=" "
- onConfirmation={() => { this.handleRemoveUserConfirmation() }}
- onRequestClose={() => { this.handleCloseRemoveUserConfirmation() }}
- />
- ) : null}
- </Wrapper>
- )
- }
- }
- export default ProjectDetailsContent
|