mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
feat/update project access (#571)
* feat: add user guidance in project access tab * feat: add role description to the menu list * feat: add tooltip to delete button * feat: add role description to add user menu * feat: auto select user when there is only one option * fix: refactor role select * fix: remove minwidth from form control Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
This commit is contained in:
parent
21ba2d8b7c
commit
3a41de2246
@ -0,0 +1,33 @@
|
|||||||
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(theme => ({
|
||||||
|
pageContent: {
|
||||||
|
minHeight: '200px',
|
||||||
|
},
|
||||||
|
divider: {
|
||||||
|
height: '1px',
|
||||||
|
width: '106.65%',
|
||||||
|
marginLeft: '-2rem',
|
||||||
|
backgroundColor: '#efefef',
|
||||||
|
marginTop: '2rem',
|
||||||
|
},
|
||||||
|
actionList: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
inputLabel: { backgroundColor: '#fff' },
|
||||||
|
roleName: {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
padding: '5px 0px',
|
||||||
|
},
|
||||||
|
iconButton: {
|
||||||
|
marginLeft: '0.5rem',
|
||||||
|
},
|
||||||
|
menuItem: {
|
||||||
|
width: '340px',
|
||||||
|
whiteSpace: 'normal',
|
||||||
|
},
|
||||||
|
projectRoleSelect: {
|
||||||
|
minWidth: '150px',
|
||||||
|
},
|
||||||
|
}));
|
@ -1,6 +1,5 @@
|
|||||||
/* eslint-disable react/jsx-no-target-blank */
|
/* eslint-disable react/jsx-no-target-blank */
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Button,
|
Button,
|
||||||
@ -9,28 +8,30 @@ import {
|
|||||||
DialogContent,
|
DialogContent,
|
||||||
DialogContentText,
|
DialogContentText,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
InputLabel,
|
|
||||||
IconButton,
|
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
ListItemAvatar,
|
ListItemAvatar,
|
||||||
ListItemSecondaryAction,
|
ListItemSecondaryAction,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Select,
|
|
||||||
FormControl,
|
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
import { Delete } from '@material-ui/icons';
|
import { Delete } from '@material-ui/icons';
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from '@material-ui/lab';
|
||||||
|
|
||||||
import AddUserComponent from './access-add-user';
|
import AddUserComponent from '../access-add-user';
|
||||||
|
|
||||||
import projectApi from '../../store/project/api';
|
import projectApi from '../../../store/project/api';
|
||||||
import PageContent from '../common/PageContent';
|
import PageContent from '../../common/PageContent';
|
||||||
import useUiConfig from '../../hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from '../../../hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
|
import { useStyles } from './ProjectAccess.styles';
|
||||||
|
import PermissionIconButton from '../../common/PermissionIconButton/PermissionIconButton';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { IFeatureViewParams } from '../../../interfaces/params';
|
||||||
|
import ProjectRoleSelect from './ProjectRoleSelect/ProjectRoleSelect';
|
||||||
|
|
||||||
|
const ProjectAccess = () => {
|
||||||
function AccessComponent({ projectId, project }) {
|
const { id } = useParams<IFeatureViewParams>();
|
||||||
|
const styles = useStyles();
|
||||||
const [roles, setRoles] = useState([]);
|
const [roles, setRoles] = useState([]);
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState([]);
|
||||||
const [error, setError] = useState();
|
const [error, setError] = useState();
|
||||||
@ -39,13 +40,11 @@ function AccessComponent({ projectId, project }) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAccess();
|
fetchAccess();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [projectId]);
|
}, [id]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const fetchAccess = async () => {
|
const fetchAccess = async () => {
|
||||||
try {
|
try {
|
||||||
const access = await projectApi.fetchAccess(projectId);
|
const access = await projectApi.fetchAccess(id);
|
||||||
setRoles(access.roles);
|
setRoles(access.roles);
|
||||||
setUsers(
|
setUsers(
|
||||||
access.users.map(u => ({ ...u, name: u.name || '(No name)' }))
|
access.users.map(u => ({ ...u, name: u.name || '(No name)' }))
|
||||||
@ -57,19 +56,24 @@ function AccessComponent({ projectId, project }) {
|
|||||||
|
|
||||||
if (isOss()) {
|
if (isOss()) {
|
||||||
return (
|
return (
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<Alert severity="error">
|
<Alert severity="error">
|
||||||
Controlling access to projects requires a paid version of Unleash.
|
Controlling access to projects requires a paid version of
|
||||||
Check out <a href="https://www.getunleash.io" target="_blank">getunleash.io</a> to find out more.
|
Unleash. Check out{' '}
|
||||||
</Alert>
|
<a href="https://www.getunleash.io" target="_blank">
|
||||||
</PageContent>);
|
getunleash.io
|
||||||
|
</a>{' '}
|
||||||
|
to find out more.
|
||||||
|
</Alert>
|
||||||
|
</PageContent>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRoleChange = (userId, currRoleId) => async evt => {
|
const handleRoleChange = (userId, currRoleId) => async evt => {
|
||||||
const roleId = evt.target.value;
|
const roleId = evt.target.value;
|
||||||
try {
|
try {
|
||||||
await projectApi.removeUserFromRole(projectId, currRoleId, userId);
|
await projectApi.removeUserFromRole(id, currRoleId, userId);
|
||||||
await projectApi.addUserToRole(projectId, roleId, userId);
|
await projectApi.addUserToRole(id, roleId, userId);
|
||||||
const newUsers = users.map(u => {
|
const newUsers = users.map(u => {
|
||||||
if (u.id === userId) {
|
if (u.id === userId) {
|
||||||
return { ...u, roleId };
|
return { ...u, roleId };
|
||||||
@ -83,7 +87,7 @@ function AccessComponent({ projectId, project }) {
|
|||||||
|
|
||||||
const addUser = async (userId, roleId) => {
|
const addUser = async (userId, roleId) => {
|
||||||
try {
|
try {
|
||||||
await projectApi.addUserToRole(projectId, roleId, userId);
|
await projectApi.addUserToRole(id, roleId, userId);
|
||||||
await fetchAccess();
|
await fetchAccess();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err.message || 'Server problems when adding users.');
|
setError(err.message || 'Server problems when adding users.');
|
||||||
@ -92,7 +96,7 @@ function AccessComponent({ projectId, project }) {
|
|||||||
|
|
||||||
const removeAccess = (userId, roleId) => async () => {
|
const removeAccess = (userId, roleId) => async () => {
|
||||||
try {
|
try {
|
||||||
await projectApi.removeUserFromRole(projectId, roleId, userId);
|
await projectApi.removeUserFromRole(id, roleId, userId);
|
||||||
const newUsers = users.filter(u => u.id !== userId);
|
const newUsers = users.filter(u => u.id !== userId);
|
||||||
setUsers(newUsers);
|
setUsers(newUsers);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -105,9 +109,7 @@ function AccessComponent({ projectId, project }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent
|
<PageContent className={styles.pageContent}>
|
||||||
style={{ minHeight: '400px' }}
|
|
||||||
>
|
|
||||||
<AddUserComponent roles={roles} addUserToRole={addUser} />
|
<AddUserComponent roles={roles} addUserToRole={addUser} />
|
||||||
<Dialog
|
<Dialog
|
||||||
open={!!error}
|
open={!!error}
|
||||||
@ -131,15 +133,7 @@ function AccessComponent({ projectId, project }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<div
|
<div className={styles.divider}></div>
|
||||||
style={{
|
|
||||||
height: '1px',
|
|
||||||
width: '106.65%',
|
|
||||||
marginLeft: '-2rem',
|
|
||||||
backgroundColor: '#efefef',
|
|
||||||
marginTop: '2rem',
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<List>
|
<List>
|
||||||
{users.map(user => {
|
{users.map(user => {
|
||||||
const labelId = `checkbox-list-secondary-label-${user.id}`;
|
const labelId = `checkbox-list-secondary-label-${user.id}`;
|
||||||
@ -154,51 +148,40 @@ function AccessComponent({ projectId, project }) {
|
|||||||
secondary={user.email || user.username}
|
secondary={user.email || user.username}
|
||||||
/>
|
/>
|
||||||
<ListItemSecondaryAction
|
<ListItemSecondaryAction
|
||||||
style={{
|
className={styles.actionList}
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<FormControl variant="outlined" size="small">
|
<ProjectRoleSelect
|
||||||
<InputLabel
|
labelId={`role-${user.id}-select-label`}
|
||||||
style={{ backgroundColor: '#fff' }}
|
id={`role-${user.id}-select`}
|
||||||
for="add-user-select-role-label"
|
key={user.id}
|
||||||
>
|
placeholder="Choose role"
|
||||||
Role
|
onChange={handleRoleChange(
|
||||||
</InputLabel>
|
user.id,
|
||||||
<Select
|
user.roleId
|
||||||
labelId={`role-${user.id}-select-label`}
|
)}
|
||||||
id={`role-${user.id}-select`}
|
roles={roles}
|
||||||
key={user.id}
|
value={user.roleId || ''}
|
||||||
placeholder="Choose role"
|
>
|
||||||
value={user.roleId || ''}
|
<MenuItem value="" disabled>
|
||||||
onChange={handleRoleChange(
|
Choose role
|
||||||
user.id,
|
</MenuItem>
|
||||||
user.roleId
|
</ProjectRoleSelect>
|
||||||
)}
|
|
||||||
>
|
<PermissionIconButton
|
||||||
<MenuItem value="" disabled>
|
className={styles.iconButton}
|
||||||
Choose role
|
|
||||||
</MenuItem>
|
|
||||||
{roles.map(role => (
|
|
||||||
<MenuItem
|
|
||||||
key={`${user.id}:${role.id}`}
|
|
||||||
value={role.id}
|
|
||||||
>
|
|
||||||
{role.name}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
<IconButton
|
|
||||||
style={{ marginLeft: '0.5rem' }}
|
|
||||||
edge="end"
|
edge="end"
|
||||||
aria-label="delete"
|
aria-label="delete"
|
||||||
title="Remove access"
|
title="Remove access"
|
||||||
onClick={removeAccess(user.id, user.roleId)}
|
onClick={removeAccess(user.id, user.roleId)}
|
||||||
|
disabled={users.length === 1}
|
||||||
|
tooltip={
|
||||||
|
users.length === 1
|
||||||
|
? 'A project must have at least one owner'
|
||||||
|
: 'Remove acccess'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Delete />
|
<Delete />
|
||||||
</IconButton>
|
</PermissionIconButton>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
@ -206,11 +189,6 @@ function AccessComponent({ projectId, project }) {
|
|||||||
</List>
|
</List>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
AccessComponent.propTypes = {
|
|
||||||
projectId: PropTypes.string.isRequired,
|
|
||||||
project: PropTypes.object,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AccessComponent;
|
export default ProjectAccess;
|
@ -0,0 +1,70 @@
|
|||||||
|
import { FormControl, InputLabel, Select, MenuItem } from '@material-ui/core';
|
||||||
|
import React from 'react';
|
||||||
|
import IRole from '../../../../interfaces/role';
|
||||||
|
|
||||||
|
import { useStyles } from '../ProjectAccess.styles';
|
||||||
|
|
||||||
|
interface IProjectRoleSelect {
|
||||||
|
roles: IRole[];
|
||||||
|
labelId: string;
|
||||||
|
id: string;
|
||||||
|
placeholder?: string;
|
||||||
|
onChange: () => void;
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectRoleSelect: React.FC<IProjectRoleSelect> = ({
|
||||||
|
roles,
|
||||||
|
onChange,
|
||||||
|
labelId,
|
||||||
|
id,
|
||||||
|
value,
|
||||||
|
placeholder,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const styles = useStyles();
|
||||||
|
return (
|
||||||
|
<FormControl variant="outlined" size="small">
|
||||||
|
<InputLabel
|
||||||
|
style={{ backgroundColor: '#fff' }}
|
||||||
|
id="add-user-select-role-label"
|
||||||
|
>
|
||||||
|
Role
|
||||||
|
</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId={labelId}
|
||||||
|
id={id}
|
||||||
|
classes={{ root: styles.projectRoleSelect }}
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={value || ''}
|
||||||
|
onChange={onChange}
|
||||||
|
renderValue={roleId => {
|
||||||
|
return roles?.find(role => {
|
||||||
|
return role.id === roleId;
|
||||||
|
}).name;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{roles?.map(role => (
|
||||||
|
<MenuItem
|
||||||
|
key={role.id}
|
||||||
|
value={role.id}
|
||||||
|
classes={{
|
||||||
|
root: styles.menuItem,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span className={styles.roleName}>{role.name}</span>
|
||||||
|
<p>
|
||||||
|
{role.description ||
|
||||||
|
'No role description available.'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProjectRoleSelect;
|
@ -2,24 +2,23 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import projectApi from '../../store/project/api';
|
import projectApi from '../../store/project/api';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
Select,
|
|
||||||
MenuItem,
|
|
||||||
TextField,
|
TextField,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
InputLabel,
|
|
||||||
FormControl,
|
|
||||||
Grid,
|
Grid,
|
||||||
Button,
|
Button,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
import { Search } from '@material-ui/icons';
|
import { Search } from '@material-ui/icons';
|
||||||
import Autocomplete from '@material-ui/lab/Autocomplete';
|
import Autocomplete from '@material-ui/lab/Autocomplete';
|
||||||
|
import { Alert } from '@material-ui/lab';
|
||||||
|
import ProjectRoleSelect from './ProjectAccess/ProjectRoleSelect/ProjectRoleSelect';
|
||||||
|
|
||||||
function AddUserComponent({ roles, addUserToRole }) {
|
function AddUserComponent({ roles, addUserToRole }) {
|
||||||
const [user, setUser] = useState();
|
const [user, setUser] = useState();
|
||||||
const [role, setRole] = useState({});
|
const [role, setRole] = useState({});
|
||||||
const [options, setOptions] = useState([]);
|
const [options, setOptions] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [select, setSelect] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (roles.length > 0) {
|
if (roles.length > 0) {
|
||||||
@ -39,13 +38,17 @@ function AddUserComponent({ roles, addUserToRole }) {
|
|||||||
} else {
|
} else {
|
||||||
setOptions([]);
|
setOptions([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleQueryUpdate = evt => {
|
const handleQueryUpdate = evt => {
|
||||||
const q = evt.target.value;
|
const q = evt.target.value;
|
||||||
search(q);
|
search(q);
|
||||||
|
if (options.length === 1) {
|
||||||
|
setSelect(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSelect(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectUser = (evt, value) => {
|
const handleSelectUser = (evt, value) => {
|
||||||
@ -67,96 +70,85 @@ function AddUserComponent({ roles, addUserToRole }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={3} alignItems="flex-end">
|
<>
|
||||||
<Grid item>
|
<Alert severity="info" style={{ marginBottom: '20px' }}>
|
||||||
<Autocomplete
|
The user must have an Unleash root role before added to the
|
||||||
id="add-user-component"
|
project.
|
||||||
style={{ width: 300 }}
|
</Alert>
|
||||||
noOptionsText="No users found."
|
<Grid container spacing={3} alignItems="flex-end">
|
||||||
onChange={handleSelectUser}
|
<Grid item>
|
||||||
autoSelect={false}
|
<Autocomplete
|
||||||
value={user || ''}
|
id="add-user-component"
|
||||||
freeSolo
|
style={{ width: 300 }}
|
||||||
getOptionSelected={() => true}
|
noOptionsText="No users found."
|
||||||
filterOptions={o => o}
|
onChange={handleSelectUser}
|
||||||
getOptionLabel={option => {
|
autoSelect={select}
|
||||||
if (option) {
|
value={user || ''}
|
||||||
return `${option.name || '(Empty name)'} <${
|
freeSolo
|
||||||
option.email || option.username
|
getOptionSelected={() => true}
|
||||||
}>`;
|
filterOptions={o => o}
|
||||||
} else return '';
|
getOptionLabel={option => {
|
||||||
}}
|
if (option) {
|
||||||
options={options}
|
return `${option.name || '(Empty name)'} <${
|
||||||
loading={loading}
|
option.email || option.username
|
||||||
renderInput={params => (
|
}>`;
|
||||||
<TextField
|
} else return '';
|
||||||
{...params}
|
}}
|
||||||
label="User"
|
options={options}
|
||||||
variant="outlined"
|
loading={loading}
|
||||||
size="small"
|
renderInput={params => (
|
||||||
name="search"
|
<TextField
|
||||||
onChange={handleQueryUpdate}
|
{...params}
|
||||||
InputProps={{
|
label="User"
|
||||||
...params.InputProps,
|
variant="outlined"
|
||||||
startAdornment: (
|
size="small"
|
||||||
<InputAdornment position="start">
|
name="search"
|
||||||
<Search />
|
onChange={handleQueryUpdate}
|
||||||
</InputAdornment>
|
InputProps={{
|
||||||
),
|
...params.InputProps,
|
||||||
endAdornment: (
|
startAdornment: (
|
||||||
<React.Fragment>
|
<InputAdornment position="start">
|
||||||
{loading ? (
|
<Search />
|
||||||
<CircularProgress
|
</InputAdornment>
|
||||||
color="inherit"
|
),
|
||||||
size={20}
|
endAdornment: (
|
||||||
/>
|
<React.Fragment>
|
||||||
) : null}
|
{loading ? (
|
||||||
{params.InputProps.endAdornment}
|
<CircularProgress
|
||||||
</React.Fragment>
|
color="inherit"
|
||||||
),
|
size={20}
|
||||||
}}
|
/>
|
||||||
/>
|
) : null}
|
||||||
)}
|
{params.InputProps.endAdornment}
|
||||||
/>
|
</React.Fragment>
|
||||||
</Grid>
|
),
|
||||||
<Grid item>
|
}}
|
||||||
<FormControl
|
/>
|
||||||
variant="outlined"
|
)}
|
||||||
size="small"
|
/>
|
||||||
style={{ minWidth: '125px' }}
|
</Grid>
|
||||||
>
|
<Grid item>
|
||||||
<InputLabel
|
<ProjectRoleSelect
|
||||||
style={{ backgroundColor: '#fff' }}
|
|
||||||
id="add-user-select-role-label"
|
|
||||||
>
|
|
||||||
Role
|
|
||||||
</InputLabel>
|
|
||||||
<Select
|
|
||||||
labelId="add-user-select-role-label"
|
labelId="add-user-select-role-label"
|
||||||
id="add-user-select-role"
|
id="add-user-select-role"
|
||||||
placeholder="Project role"
|
placeholder="Project role"
|
||||||
value={role.id || ''}
|
value={role.id || ''}
|
||||||
onChange={handleRoleChange}
|
onChange={handleRoleChange}
|
||||||
|
roles={roles}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
disabled={!user}
|
||||||
|
onClick={handleSubmit}
|
||||||
>
|
>
|
||||||
{roles.map(role => (
|
Add user
|
||||||
<MenuItem key={role.id} value={role.id}>
|
</Button>
|
||||||
{role.name}
|
</Grid>
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
</>
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
disabled={!user}
|
|
||||||
onClick={handleSubmit}
|
|
||||||
>
|
|
||||||
Add user
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import Component from './access-component';
|
import Component from './ProjectAccess/ProjectAccess';
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => {
|
const mapStateToProps = (state, props) => {
|
||||||
const projectBase = { id: '', name: '', description: '' };
|
const projectBase = { id: '', name: '', description: '' };
|
||||||
const realProject = state.projects.toJS().find(n => n.id === props.projectId);
|
const realProject = state.projects
|
||||||
|
.toJS()
|
||||||
|
.find(n => n.id === props.projectId);
|
||||||
const project = Object.assign(projectBase, realProject);
|
const project = Object.assign(projectBase, realProject);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
Loading…
Reference in New Issue
Block a user