This repository has been archived on 2022-08-14. You can view files and clone it, but cannot push or open issues or pull requests.
Saumya Pandey 4929fbaccb
fix: Move "public document sharing" to "Permissions" (#2496)
* Convert to functional component

* Move public sharing to permissions

* Add collections.permission_changed event

* Account for null

* Update server/events.js

Co-authored-by: Tom Moor <tom.moor@gmail.com>

* Add collections.permission_changed event

* Remove name

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2021-08-30 11:43:42 +05:30

333 lines
9.5 KiB
JavaScript

// @flow
import { observer } from "mobx-react";
import { PlusIcon } from "outline-icons";
import * as React from "react";
import { useTranslation, Trans } from "react-i18next";
import styled from "styled-components";
import Collection from "models/Collection";
import Button from "components/Button";
import Divider from "components/Divider";
import Flex from "components/Flex";
import HelpText from "components/HelpText";
import InputSelectPermission from "components/InputSelectPermission";
import Labeled from "components/Labeled";
import Modal from "components/Modal";
import PaginatedList from "components/PaginatedList";
import Switch from "components/Switch";
import AddGroupsToCollection from "./AddGroupsToCollection";
import AddPeopleToCollection from "./AddPeopleToCollection";
import CollectionGroupMemberListItem from "./components/CollectionGroupMemberListItem";
import MemberListItem from "./components/MemberListItem";
import useBoolean from "hooks/useBoolean";
import useCurrentUser from "hooks/useCurrentUser";
import useStores from "hooks/useStores";
import useToasts from "hooks/useToasts";
type Props = {|
collection: Collection,
|};
function CollectionPermissions({ collection }: Props) {
const { t } = useTranslation();
const user = useCurrentUser();
const {
memberships,
collectionGroupMemberships,
users,
groups,
auth,
} = useStores();
const { showToast } = useToasts();
const [
addGroupModalOpen,
handleAddGroupModalOpen,
handleAddGroupModalClose,
] = useBoolean();
const [
addMemberModalOpen,
handleAddMemberModalOpen,
handleAddMemberModalClose,
] = useBoolean();
const handleRemoveUser = React.useCallback(
async (user) => {
try {
await memberships.delete({
collectionId: collection.id,
userId: user.id,
});
showToast(
t(`{{ userName }} was removed from the collection`, {
userName: user.name,
}),
{
type: "success",
}
);
} catch (err) {
showToast(t("Could not remove user"), { type: "error" });
}
},
[memberships, showToast, collection, t]
);
const handleUpdateUser = React.useCallback(
async (user, permission) => {
try {
await memberships.create({
collectionId: collection.id,
userId: user.id,
permission,
});
showToast(
t(`{{ userName }} permissions were updated`, { userName: user.name }),
{
type: "success",
}
);
} catch (err) {
showToast(t("Could not update user"), { type: "error" });
}
},
[memberships, showToast, collection, t]
);
const handleRemoveGroup = React.useCallback(
async (group) => {
try {
await collectionGroupMemberships.delete({
collectionId: collection.id,
groupId: group.id,
});
showToast(
t(`The {{ groupName }} group was removed from the collection`, {
groupName: group.name,
}),
{
type: "success",
}
);
} catch (err) {
showToast(t("Could not remove group"), { type: "error" });
}
},
[collectionGroupMemberships, showToast, collection, t]
);
const handleUpdateGroup = React.useCallback(
async (group, permission) => {
try {
await collectionGroupMemberships.create({
collectionId: collection.id,
groupId: group.id,
permission,
});
showToast(
t(`{{ groupName }} permissions were updated`, {
groupName: group.name,
}),
{
type: "success",
}
);
} catch (err) {
showToast(t("Could not update user"), { type: "error" });
}
},
[collectionGroupMemberships, showToast, collection, t]
);
const handleChangePermission = React.useCallback(
async (ev) => {
try {
await collection.save({ permission: ev.target.value });
showToast(t("Default access permissions were updated"), {
type: "success",
});
} catch (err) {
showToast(t("Could not update permissions"), { type: "error" });
}
},
[collection, showToast, t]
);
const fetchOptions = React.useMemo(() => ({ id: collection.id }), [
collection.id,
]);
const handleSharingChange = React.useCallback(
async (ev: SyntheticInputEvent<*>) => {
try {
await collection.save({ sharing: ev.target.checked });
showToast(t("Public document sharing permissions were updated"), {
type: "success",
});
} catch (err) {
showToast(t("Could not update public document sharing"), {
type: "error",
});
}
},
[collection, showToast, t]
);
const collectionName = collection.name;
const collectionGroups = groups.inCollection(collection.id);
const collectionUsers = users.inCollection(collection.id);
const isEmpty = !collectionGroups.length && !collectionUsers.length;
const sharing = collection.sharing;
const teamSharingEnabled = !!auth.team && auth.team.sharing;
return (
<Flex column>
<InputSelectPermission
onChange={handleChangePermission}
value={collection.permission || ""}
short
/>
<PermissionExplainer>
{!collection.permission && (
<Trans
defaults="The <em>{{ collectionName }}</em> collection is private. Team members have no access to it by default."
values={{ collectionName }}
components={{ em: <strong /> }}
/>
)}
{collection.permission === "read" && (
<Trans
defaults="Team members can view documents in the <em>{{ collectionName }}</em> collection by default."
values={{ collectionName }}
components={{ em: <strong /> }}
/>
)}
{collection.permission === "read_write" && (
<Trans
defaults="Team members can view and edit documents in the <em>{{ collectionName }}</em> collection by
default."
values={{ collectionName }}
components={{ em: <strong /> }}
/>
)}
</PermissionExplainer>
<Switch
id="sharing"
label={t("Public document sharing")}
onChange={handleSharingChange}
checked={sharing && teamSharingEnabled}
disabled={!teamSharingEnabled}
/>
<HelpText>
{teamSharingEnabled ? (
<Trans>
When enabled, documents can be shared publicly on the internet.
</Trans>
) : (
<Trans>
Public sharing is currently disabled in the team security settings.
</Trans>
)}
</HelpText>
<Labeled label={t("Additional access")}>
<Actions>
<Button
type="button"
onClick={handleAddGroupModalOpen}
icon={<PlusIcon />}
neutral
>
{t("Add groups")}
</Button>{" "}
<Button
type="button"
onClick={handleAddMemberModalOpen}
icon={<PlusIcon />}
neutral
>
{t("Add people")}
</Button>
</Actions>
</Labeled>
<Divider />
{isEmpty && (
<Empty>
<Trans>
Add specific access for individual groups and team members
</Trans>
</Empty>
)}
<PaginatedList
items={collectionGroups}
fetch={collectionGroupMemberships.fetchPage}
options={fetchOptions}
renderItem={(group) => (
<CollectionGroupMemberListItem
key={group.id}
group={group}
collectionGroupMembership={collectionGroupMemberships.get(
`${group.id}-${collection.id}`
)}
onRemove={() => handleRemoveGroup(group)}
onUpdate={(permission) => handleUpdateGroup(group, permission)}
/>
)}
/>
{collectionGroups.length ? <Divider /> : null}
<PaginatedList
key={`collection-users-${collection.permission || "none"}`}
items={collectionUsers}
fetch={memberships.fetchPage}
options={fetchOptions}
renderItem={(item) => (
<MemberListItem
key={item.id}
user={item}
membership={memberships.get(`${item.id}-${collection.id}`)}
canEdit={item.id !== user.id}
onRemove={() => handleRemoveUser(item)}
onUpdate={(permission) => handleUpdateUser(item, permission)}
/>
)}
/>
<Modal
title={t(`Add groups to {{ collectionName }}`, {
collectionName: collection.name,
})}
onRequestClose={handleAddGroupModalClose}
isOpen={addGroupModalOpen}
>
<AddGroupsToCollection
collection={collection}
onSubmit={handleAddGroupModalClose}
/>
</Modal>
<Modal
title={t(`Add people to {{ collectionName }}`, {
collectionName: collection.name,
})}
onRequestClose={handleAddMemberModalClose}
isOpen={addMemberModalOpen}
>
<AddPeopleToCollection
collection={collection}
onSubmit={handleAddMemberModalClose}
/>
</Modal>
</Flex>
);
}
const Empty = styled(HelpText)`
margin-top: 8px;
`;
const PermissionExplainer = styled(HelpText)`
margin-top: -8px;
margin-bottom: 24px;
`;
const Actions = styled.div`
margin-bottom: 12px;
`;
export default observer(CollectionPermissions);