724 lines
23 KiB
TypeScript
724 lines
23 KiB
TypeScript
import {
|
|
Avatar,
|
|
Box,
|
|
Button,
|
|
Checkbox,
|
|
CircularProgress,
|
|
DialogActions,
|
|
DialogContent,
|
|
DialogTitle,
|
|
Divider,
|
|
FormControl,
|
|
FormControlLabel,
|
|
FormGroup,
|
|
FormLabel,
|
|
Grid2,
|
|
IconButton,
|
|
List,
|
|
ListItem,
|
|
ListItemAvatar,
|
|
ListItemSecondaryAction,
|
|
ListItemText,
|
|
PaletteColor,
|
|
Stack,
|
|
Theme,
|
|
Tooltip,
|
|
Typography,
|
|
useTheme
|
|
} from "@mui/material";
|
|
import RemoveUserIcon from "@mui/icons-material/RemoveCircle";
|
|
import EditIcon from "@mui/icons-material/EditOutlined";
|
|
import ShareIcon from "@mui/icons-material/Share";
|
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
|
import { usePermissionAPI, usePrevious, useSnackbar, useUserAPI } from "hooks";
|
|
import { cloneDeep, isEqual } from "lodash";
|
|
import { Scope, User } from "models";
|
|
import { sortUsersByRole, userRoleFromPermissions } from "pbHelpers/User";
|
|
import { pond } from "protobuf-ts/pond";
|
|
import React, { useCallback, useEffect, useState } from "react";
|
|
import { or } from "utils/types";
|
|
import RemoveSelfFromObject from "user/RemoveSelfFromObject";
|
|
import ShareObject from "user/ShareObject";
|
|
import { useGlobalState } from "providers";
|
|
import { red, blue } from "@mui/material/colors";
|
|
import { makeStyles } from "@mui/styles";
|
|
|
|
const useStyles = makeStyles((theme: Theme) => {
|
|
const avatarBG = theme.palette.secondary["700" as keyof PaletteColor];
|
|
return {
|
|
dialogContent: {
|
|
padding: `${theme.spacing(1)}px ${theme.spacing(2)}px`,
|
|
[theme.breakpoints.up("sm")]: {
|
|
padding: `${theme.spacing(1)}px ${theme.spacing(3)}px`
|
|
}
|
|
},
|
|
userAvatar: {
|
|
color: "#fff",
|
|
backgroundColor: avatarBG
|
|
},
|
|
userPermissions: {
|
|
paddingLeft: theme.spacing(4),
|
|
paddingBottom: theme.spacing(1)
|
|
},
|
|
textOverflowEllipsis: {
|
|
whiteSpace: "nowrap",
|
|
overflow: "hidden",
|
|
textOverflow: "ellipsis"
|
|
},
|
|
removeIcon: {
|
|
color: red["500"],
|
|
"&:hover": {
|
|
color: red["600"]
|
|
}
|
|
},
|
|
verticalSpacing: {
|
|
paddingTop: theme.spacing(4),
|
|
paddingBottom: theme.spacing(3)
|
|
},
|
|
lessSpacing: {
|
|
paddingTop: theme.spacing(1),
|
|
paddingBottom: theme.spacing(1)
|
|
},
|
|
iconButton: {
|
|
margin: theme.spacing(1)
|
|
},
|
|
shareIcon: {
|
|
color: blue["600"],
|
|
"&:hover": {
|
|
color: blue["700"]
|
|
}
|
|
},
|
|
editIcon: {
|
|
color: blue["300"],
|
|
"&:hover": {
|
|
color: blue["400"]
|
|
}
|
|
}
|
|
};
|
|
});
|
|
|
|
interface Props {
|
|
scope: Scope;
|
|
label: string;
|
|
permissions: pond.Permission[];
|
|
isDialogOpen: boolean;
|
|
closeDialogCallback: Function;
|
|
refreshCallback: Function;
|
|
userCallback?: (users?: User[] | undefined) => void;
|
|
dialog?: string;
|
|
cardMode?: boolean;
|
|
useImitation?: boolean;
|
|
shareLabel?: string; // s string to replace the share icon button with a labelled button
|
|
}
|
|
|
|
export default function ObjectUsers(props: Props) {
|
|
const classes = useStyles();
|
|
const theme = useTheme();
|
|
const permissionAPI = usePermissionAPI();
|
|
const [{ user, team }, dispatch] = useGlobalState();
|
|
const isAdmin = user.hasAdmin();
|
|
const userAPI = useUserAPI();
|
|
const { error, success, warning } = useSnackbar();
|
|
const {
|
|
scope,
|
|
label,
|
|
permissions,
|
|
isDialogOpen,
|
|
closeDialogCallback,
|
|
refreshCallback,
|
|
userCallback,
|
|
dialog,
|
|
cardMode,
|
|
//useImitation
|
|
shareLabel
|
|
} = props;
|
|
const prevPermissions = usePrevious(permissions);
|
|
const prevIsDialogOpen = usePrevious(isDialogOpen);
|
|
const [initialUsers, setInitialUsers] = useState<User[]>([]);
|
|
const [users, setUsers] = useState<User[]>([]);
|
|
const [canManageUsers, setCanManageUsers] = useState<boolean>(
|
|
permissions.includes(pond.Permission.PERMISSION_USERS)
|
|
);
|
|
const [canShare, setCanShare] = useState<boolean>(
|
|
permissions.includes(pond.Permission.PERMISSION_SHARE)
|
|
);
|
|
const [canShareBilling, setCanShareBilling] = useState<boolean>(
|
|
permissions.includes(pond.Permission.PERMISSION_SHARE) &&
|
|
permissions.includes(pond.Permission.PERMISSION_USERS) &&
|
|
permissions.includes(pond.Permission.PERMISSION_WRITE)
|
|
);
|
|
const [removedUsers, setRemovedUsers] = useState<string[]>([]);
|
|
const [removeSelfDialogIsOpen, setRemoveSelfDialogIsOpen] = useState<boolean>(false);
|
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
const [isShareObjectDialogOpen, setIsShareObjectDialogOpen] = useState<boolean>(false);
|
|
const [numOwners, setNumOwners] = useState(0);
|
|
const [useImitation] = useState<boolean>(
|
|
props.useImitation !== undefined ? props.useImitation : true
|
|
);
|
|
// const [editUserDialog, setEditUserDialog] = useState(false);
|
|
const [userForDialog, setUserForDialog] = useState<User | undefined>(undefined);
|
|
|
|
const setDefaultState = () => {
|
|
setInitialUsers([]);
|
|
setUsers([]);
|
|
setRemovedUsers([]);
|
|
};
|
|
|
|
const load = useCallback(() => {
|
|
setIsLoading(true);
|
|
userAPI
|
|
.listObjectUsers(scope)
|
|
.then((response: any) => {
|
|
let rUsers: User[] = [];
|
|
or(response.data, { users: [] }).users.forEach((user: any) => {
|
|
rUsers.push(User.any(user));
|
|
});
|
|
rUsers = rUsers.filter(u => u.permissions.length > 0);
|
|
setInitialUsers(cloneDeep(rUsers));
|
|
let numOwners = 0;
|
|
rUsers.forEach(user => {
|
|
if (userRoleFromPermissions(user.permissions) === "Owner") numOwners++;
|
|
});
|
|
setNumOwners(numOwners);
|
|
setUsers(rUsers);
|
|
})
|
|
.catch((err: any) => {
|
|
console.log(err);
|
|
setInitialUsers([]);
|
|
setUsers([]);
|
|
})
|
|
.finally(() => setIsLoading(false));
|
|
}, [scope, userAPI]);
|
|
|
|
useEffect(() => {
|
|
if (!prevIsDialogOpen && isDialogOpen) {
|
|
load();
|
|
}
|
|
if (prevPermissions !== permissions) {
|
|
setCanManageUsers(permissions.includes(pond.Permission.PERMISSION_USERS));
|
|
setCanShare(permissions.includes(pond.Permission.PERMISSION_SHARE));
|
|
setCanShareBilling(
|
|
permissions.includes(pond.Permission.PERMISSION_SHARE) &&
|
|
permissions.includes(pond.Permission.PERMISSION_USERS) &&
|
|
permissions.includes(pond.Permission.PERMISSION_WRITE)
|
|
);
|
|
}
|
|
}, [isDialogOpen, load, permissions, prevIsDialogOpen, prevPermissions]);
|
|
|
|
const closeRemoveSelfDialog = () => {
|
|
setRemoveSelfDialogIsOpen(false);
|
|
};
|
|
|
|
const close = () => {
|
|
closeRemoveSelfDialog();
|
|
closeDialogCallback();
|
|
setDefaultState();
|
|
};
|
|
|
|
const submit = () => {
|
|
console.log(users);
|
|
permissionAPI
|
|
.updatePermissions(scope, users)
|
|
.then((_response: any) => {
|
|
success("Users were sucessfully updated for " + label);
|
|
close();
|
|
refreshCallback();
|
|
userCallback && userCallback(users);
|
|
users.forEach(u => {
|
|
if (u.id() === user.id()) {
|
|
if (scope.kind === "team" && scope.key === team.key()) {
|
|
dispatch({ key: "userTeamPermissions", value: u.permissions });
|
|
}
|
|
}
|
|
});
|
|
if (cardMode) {
|
|
load();
|
|
}
|
|
})
|
|
.catch((err: any) => {
|
|
err.response.data.error
|
|
? warning(err.response.data.error)
|
|
: error("Error occured when updating users for " + label);
|
|
close();
|
|
})
|
|
.finally(() => setUserForDialog(undefined));
|
|
};
|
|
|
|
const changeUserPermissions = (user: pond.IUser) => (event: any) => {
|
|
let updatedUsers = cloneDeep(users);
|
|
let permissionMapping = new Map<string, pond.Permission>([
|
|
["2", pond.Permission.PERMISSION_READ],
|
|
["3", pond.Permission.PERMISSION_WRITE],
|
|
["4", pond.Permission.PERMISSION_SHARE],
|
|
["1", pond.Permission.PERMISSION_USERS],
|
|
["5", pond.Permission.PERMISSION_BILLING],
|
|
["6", pond.Permission.PERMISSION_FILE_MANAGEMENT]
|
|
]);
|
|
let permission = or(
|
|
permissionMapping.get(event.target.value),
|
|
pond.Permission.PERMISSION_INVALID
|
|
);
|
|
for (let i = 0; i < updatedUsers.length; i++) {
|
|
let currUser = updatedUsers[i];
|
|
if (
|
|
user &&
|
|
user.settings &&
|
|
currUser &&
|
|
currUser.settings &&
|
|
currUser.settings.id === user.settings.id
|
|
) {
|
|
let permissions = user.permissions ? cloneDeep(user.permissions) : [];
|
|
if (permissions.includes(permission)) {
|
|
permissions = permissions.filter(
|
|
(curPermission: pond.Permission) => curPermission !== permission
|
|
);
|
|
} else {
|
|
permissions.push(permission);
|
|
}
|
|
updatedUsers[i].permissions = permissions;
|
|
user.permissions = permissions;
|
|
break;
|
|
}
|
|
}
|
|
setUsers(updatedUsers);
|
|
};
|
|
|
|
const removeUser = (user: string) => {
|
|
let updatedUsers = cloneDeep(users);
|
|
let updatedRemovedUsers = cloneDeep(removedUsers);
|
|
for (let i = 0; i < updatedUsers.length; i++) {
|
|
let currUser = updatedUsers[i];
|
|
if (currUser && currUser.settings && currUser.settings.id === user) {
|
|
updatedRemovedUsers.push(currUser.settings.id);
|
|
updatedUsers[i].permissions = [];
|
|
break;
|
|
}
|
|
}
|
|
setUsers(updatedUsers);
|
|
setRemovedUsers(updatedRemovedUsers);
|
|
};
|
|
|
|
const checkIsSelf = (checkUser: pond.IUser): boolean => {
|
|
const id = checkUser && checkUser.settings ? checkUser.settings.id : "";
|
|
return user.id() === id;
|
|
};
|
|
|
|
const userIsRemoved = (user: pond.IUser): boolean => {
|
|
const id = user && user.settings ? user.settings.id : "";
|
|
return removedUsers.includes(or(id, ""));
|
|
};
|
|
|
|
const objectUsersUnchanged = (): boolean => {
|
|
return isEqual(initialUsers, users);
|
|
};
|
|
|
|
const openRemoveSelfDialog = () => {
|
|
setRemoveSelfDialogIsOpen(true);
|
|
};
|
|
|
|
const openShareObjectDialog = () => {
|
|
setIsShareObjectDialogOpen(true);
|
|
};
|
|
|
|
const closeShareObjectDialog = (shared: boolean | undefined) => {
|
|
setIsShareObjectDialogOpen(false);
|
|
if (shared) {
|
|
load();
|
|
}
|
|
};
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI BEGINS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
const title = () => {
|
|
return (
|
|
// <Grid container direction="column" justify="space-between">
|
|
// <Grid container direction="row" justify="space-between">
|
|
// <Grid item xs={8}>
|
|
// Users
|
|
// <Typography variant="body2" color="textSecondary">
|
|
// {label}
|
|
// </Typography>
|
|
// </Grid>
|
|
// <Grid item xs={4} container justify="flex-end">
|
|
// {canShare && (
|
|
// <Tooltip title={"Share " + label}>
|
|
// <IconButton
|
|
// aria-label="Share"
|
|
// className={classes.iconButton}
|
|
// onClick={openShareObjectDialog}>
|
|
// <ShareIcon className={classes.shareIcon} />
|
|
// </IconButton>
|
|
// </Tooltip>
|
|
// )}
|
|
// </Grid>
|
|
// </Grid>
|
|
// {dialog && (
|
|
// <Typography variant="body2" color="textSecondary" style={{ marginTop: "4px" }}>
|
|
// {dialog}
|
|
// </Typography>
|
|
// )}
|
|
// </Grid>
|
|
<Stack direction="column" spacing={2}>
|
|
<Stack direction="row" spacing={2} justifyContent="space-between">
|
|
<Box>
|
|
Users
|
|
<Typography variant="body2" color="textSecondary">
|
|
{label}
|
|
</Typography>
|
|
</Box>
|
|
<Box display="flex" justifyContent="flex-end">
|
|
{canShare && (
|
|
<Tooltip title={`Share ${label}`}>
|
|
{shareLabel ?
|
|
<Button variant="contained" color="primary" aria-label="Share" onClick={openShareObjectDialog}>
|
|
{shareLabel}
|
|
</Button>
|
|
:
|
|
<IconButton
|
|
aria-label="Share"
|
|
onClick={openShareObjectDialog}>
|
|
<ShareIcon />
|
|
</IconButton>
|
|
}
|
|
</Tooltip>
|
|
)}
|
|
</Box>
|
|
</Stack>
|
|
{dialog && (
|
|
<Typography variant="body2" color="textSecondary" sx={{ mt: 1 }}>
|
|
{dialog}
|
|
</Typography>
|
|
)}
|
|
</Stack>
|
|
);
|
|
};
|
|
|
|
const userPermissionManagement = (user: User) => {
|
|
let permissions = user.permissions;
|
|
if (
|
|
!canManageUsers ||
|
|
(checkIsSelf(user) && !canShareBilling) ||
|
|
userIsRemoved(user) ||
|
|
(permissions.includes(pond.Permission.PERMISSION_USERS) &&
|
|
permissions.includes(pond.Permission.PERMISSION_READ) &&
|
|
permissions.includes(pond.Permission.PERMISSION_WRITE) &&
|
|
permissions.includes(pond.Permission.PERMISSION_SHARE) &&
|
|
permissions.includes(pond.Permission.PERMISSION_BILLING) &&
|
|
permissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT) &&
|
|
!cardMode)
|
|
) {
|
|
return null;
|
|
}
|
|
const canRead = permissions.includes(pond.Permission.PERMISSION_READ);
|
|
const xs = cardMode ? 12 : 4;
|
|
const sm = cardMode ? 4 : 3;
|
|
const justify = cardMode ? "flex-start" : "center";
|
|
return (
|
|
<FormControl component="fieldset" fullWidth className={classes.userPermissions}>
|
|
<FormLabel component="legend"></FormLabel>
|
|
<FormGroup>
|
|
<Grid2 container direction="row" justifyContent={justify} spacing={2}>
|
|
<Grid2 sx={{ gridColumn: `span ${xs} / span ${sm}` }}>
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
checked={permissions.includes(pond.Permission.PERMISSION_READ)}
|
|
onChange={changeUserPermissions(user)}
|
|
value={pond.Permission.PERMISSION_READ}
|
|
/>
|
|
}
|
|
label="View"
|
|
labelPlacement="end"
|
|
/>
|
|
</Grid2>
|
|
|
|
<Grid2 sx={{ gridColumn: `span ${xs} / span ${sm}` }}>
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
disabled={!canRead}
|
|
checked={permissions.includes(pond.Permission.PERMISSION_WRITE)}
|
|
onChange={changeUserPermissions(user)}
|
|
value={pond.Permission.PERMISSION_WRITE}
|
|
/>
|
|
}
|
|
label="Edit"
|
|
labelPlacement="end"
|
|
/>
|
|
</Grid2>
|
|
|
|
<Grid2 sx={{ gridColumn: `span ${xs} / span ${sm}` }}>
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
disabled={!canRead}
|
|
checked={permissions.includes(pond.Permission.PERMISSION_SHARE)}
|
|
onChange={changeUserPermissions(user)}
|
|
value={pond.Permission.PERMISSION_SHARE}
|
|
/>
|
|
}
|
|
label="Share"
|
|
labelPlacement="end"
|
|
/>
|
|
</Grid2>
|
|
|
|
<Grid2 sx={{ gridColumn: `span ${xs} / span ${sm}` }}>
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
disabled={!canRead}
|
|
checked={permissions.includes(pond.Permission.PERMISSION_USERS)}
|
|
onChange={changeUserPermissions(user)}
|
|
value={pond.Permission.PERMISSION_USERS}
|
|
/>
|
|
}
|
|
label="Manage Users"
|
|
labelPlacement="end"
|
|
/>
|
|
</Grid2>
|
|
|
|
<Grid2 sx={{ gridColumn: 'span 6 / span 3' }}>
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
checked={permissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT)}
|
|
onChange={changeUserPermissions(user)}
|
|
value={pond.Permission.PERMISSION_FILE_MANAGEMENT}
|
|
/>
|
|
}
|
|
label="Files"
|
|
labelPlacement="end"
|
|
/>
|
|
</Grid2>
|
|
|
|
<Grid2 sx={{ gridColumn: `span ${xs} / span ${sm}` }}>
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
disabled={!canShareBilling}
|
|
checked={permissions.includes(pond.Permission.PERMISSION_BILLING)}
|
|
onChange={changeUserPermissions(user)}
|
|
value={pond.Permission.PERMISSION_BILLING}
|
|
/>
|
|
}
|
|
label="Billing"
|
|
labelPlacement="end"
|
|
/>
|
|
</Grid2>
|
|
</Grid2>
|
|
</FormGroup>
|
|
</FormControl>
|
|
);
|
|
};
|
|
|
|
const userListItem = (user: User) => {
|
|
let isSelf = checkIsSelf(user);
|
|
let isRemoved = userIsRemoved(user);
|
|
let name = user.name();
|
|
let permissions = user.permissions;
|
|
let userSettings = pond.UserSettings.create(user.settings !== null ? user.settings : undefined);
|
|
|
|
return (
|
|
<ListItem alignItems="flex-start" >
|
|
<ListItemAvatar>
|
|
<Avatar
|
|
alt={name}
|
|
src={
|
|
userSettings.avatar && userSettings.avatar !== "" ? userSettings.avatar : undefined
|
|
}
|
|
className={classes.userAvatar}>
|
|
{!(userSettings.avatar && userSettings.avatar !== "") && name}
|
|
</Avatar>
|
|
</ListItemAvatar>
|
|
<ListItemText
|
|
className={classes.textOverflowEllipsis}
|
|
disableTypography
|
|
primary={
|
|
<Typography component="div" variant="body1" color="textPrimary">
|
|
{name + (isSelf ? " (you)" : "")}
|
|
</Typography>
|
|
}
|
|
secondary={
|
|
<React.Fragment>
|
|
<Typography component="div" variant="caption" color="textSecondary">
|
|
{user.settings.email}
|
|
</Typography>
|
|
<Typography component="div" variant="caption" color="textSecondary">
|
|
{isRemoved ? "REMOVED " : userRoleFromPermissions(permissions)}
|
|
</Typography>
|
|
</React.Fragment>
|
|
}
|
|
/>
|
|
{isSelf && !canShareBilling ? (
|
|
<ListItemSecondaryAction>
|
|
<Tooltip title={"Remove yourself from " + label}>
|
|
<IconButton
|
|
edge="end"
|
|
aria-label={"Remove yourself from " + label}
|
|
onClick={openRemoveSelfDialog}>
|
|
<RemoveUserIcon className={classes.removeIcon} />
|
|
</IconButton>
|
|
</Tooltip>
|
|
</ListItemSecondaryAction>
|
|
) : (canManageUsers || isAdmin) && !isRemoved && !cardMode ? (
|
|
<ListItemSecondaryAction>
|
|
<Tooltip title="Revoke user's access">
|
|
<IconButton
|
|
edge="end"
|
|
aria-label="Remove user from device"
|
|
onClick={() => removeUser(or(user.settings, { id: "" }).id)}>
|
|
<RemoveUserIcon className={classes.removeIcon} />
|
|
</IconButton>
|
|
</Tooltip>
|
|
</ListItemSecondaryAction>
|
|
) : (
|
|
(canManageUsers || isAdmin) && (
|
|
<ListItemSecondaryAction>
|
|
<Tooltip title="Edit user's permissions">
|
|
<IconButton
|
|
edge="end"
|
|
aria-label="Edit user permissions"
|
|
disabled={!canManageUsers}
|
|
onClick={() => setUserForDialog(user)}>
|
|
<EditIcon className={classes.editIcon} />
|
|
</IconButton>
|
|
</Tooltip>
|
|
</ListItemSecondaryAction>
|
|
)
|
|
)}
|
|
</ListItem>
|
|
);
|
|
};
|
|
|
|
const objectUsersList = () => {
|
|
const sortedUsers = sortUsersByRole(users);
|
|
|
|
let userListItems: any = [];
|
|
for (var i = 0; i < sortedUsers.length; i++) {
|
|
let user = sortedUsers[i];
|
|
if (user) {
|
|
userListItems.push(
|
|
<React.Fragment key={i}>
|
|
{userListItem(user)}
|
|
{!cardMode && userPermissionManagement(user)}
|
|
<Divider />
|
|
</React.Fragment>
|
|
);
|
|
}
|
|
}
|
|
|
|
return <List>{userListItems}</List>;
|
|
};
|
|
|
|
const content = () => {
|
|
if (isLoading) {
|
|
return (
|
|
<Grid2 container justifyContent="center" alignContent="center" className={classes.verticalSpacing}>
|
|
<CircularProgress />
|
|
</Grid2>
|
|
);
|
|
}
|
|
|
|
if (users.length < 1) {
|
|
return (
|
|
<React.Fragment>
|
|
<Typography
|
|
variant="h6"
|
|
align="center"
|
|
color="textSecondary"
|
|
className={!cardMode ? classes.verticalSpacing : ""}
|
|
style={{ padding: cardMode ? 0 : "" }}>
|
|
No users found.
|
|
</Typography>
|
|
</React.Fragment>
|
|
);
|
|
}
|
|
|
|
return objectUsersList();
|
|
};
|
|
|
|
const actions = () => {
|
|
return (
|
|
<Grid2 container direction="row" justifyContent="space-between">
|
|
<Grid2 sx={{ gridColumn: `span ${4} ` }} ></Grid2>
|
|
<Grid2 sx={{ gridColumn: `span ${8} ` }} container justifyContent="flex-end">
|
|
{!cardMode && (
|
|
<Button onClick={close} color="primary">
|
|
Cancel
|
|
</Button>
|
|
)}
|
|
{canManageUsers && !cardMode && (
|
|
<Button onClick={submit} color="primary" disabled={objectUsersUnchanged()}>
|
|
{cardMode ? "Update" : "Submit"}
|
|
</Button>
|
|
)}
|
|
</Grid2>
|
|
</Grid2>
|
|
);
|
|
};
|
|
|
|
const dialogs = () => {
|
|
return (
|
|
<React.Fragment>
|
|
<RemoveSelfFromObject
|
|
scope={scope}
|
|
label={label}
|
|
isDialogOpen={removeSelfDialogIsOpen}
|
|
closeDialogCallback={closeRemoveSelfDialog}
|
|
numberOfOwners={numOwners}
|
|
/>
|
|
<ShareObject
|
|
scope={scope}
|
|
label={label}
|
|
permissions={permissions}
|
|
isDialogOpen={isShareObjectDialogOpen}
|
|
closeDialogCallback={closeShareObjectDialog}
|
|
useImitation={useImitation}
|
|
sharedUsers={users}
|
|
/>
|
|
</React.Fragment>
|
|
);
|
|
};
|
|
|
|
if (cardMode) {
|
|
return (
|
|
<React.Fragment>
|
|
<Typography variant="h6">{title()}</Typography>
|
|
<div style={{ overflowY: "scroll" }}>
|
|
<Divider />
|
|
{content()}
|
|
{actions()}
|
|
{dialogs()}
|
|
<div style={{ marginTop: theme.spacing(2) }} />
|
|
</div>
|
|
<ResponsiveDialog
|
|
open={userForDialog !== undefined}
|
|
onClose={() => setUserForDialog(undefined)}>
|
|
<DialogTitle>Change {userForDialog?.name()}'s Permissions?</DialogTitle>
|
|
<DialogContent>{userForDialog && userPermissionManagement(userForDialog)}</DialogContent>
|
|
<DialogActions>
|
|
<Button onClick={() => setUserForDialog(undefined)}>Close</Button>
|
|
<Button color="primary" onClick={submit}>
|
|
Submit
|
|
</Button>
|
|
</DialogActions>
|
|
</ResponsiveDialog>
|
|
</React.Fragment>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<ResponsiveDialog
|
|
fullWidth
|
|
maxWidth="xs"
|
|
open={props.isDialogOpen}
|
|
onClose={close}
|
|
aria-labelledby="object-users-dialog">
|
|
<DialogTitle id="object-users-title">{title()}</DialogTitle>
|
|
<Divider />
|
|
<DialogContent className={classes.dialogContent}>{content()}</DialogContent>
|
|
<DialogActions>{actions()}</DialogActions>
|
|
{dialogs()}
|
|
</ResponsiveDialog>
|
|
);
|
|
}
|