@ -30,10 +30,6 @@ const Wrapper = styled.li`
|
|||||||
padding: ${props => (props.compact ? '8px' : '12px')} 0;
|
padding: ${props => (props.compact ? '8px' : '12px')} 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-bottom: 1px solid ${props => props.theme.divider};
|
border-bottom: 1px solid ${props => props.theme.divider};
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Image = styled(Flex)`
|
const Image = styled(Flex)`
|
||||||
|
@ -14,14 +14,12 @@ import importFile from 'utils/importFile';
|
|||||||
import Collection from 'models/Collection';
|
import Collection from 'models/Collection';
|
||||||
import UiStore from 'stores/UiStore';
|
import UiStore from 'stores/UiStore';
|
||||||
import DocumentsStore from 'stores/DocumentsStore';
|
import DocumentsStore from 'stores/DocumentsStore';
|
||||||
import PoliciesStore from 'stores/PoliciesStore';
|
|
||||||
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
|
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
label?: React.Node,
|
label?: React.Node,
|
||||||
position?: 'left' | 'right' | 'center',
|
position?: 'left' | 'right' | 'center',
|
||||||
ui: UiStore,
|
ui: UiStore,
|
||||||
policies: PoliciesStore,
|
|
||||||
documents: DocumentsStore,
|
documents: DocumentsStore,
|
||||||
collection: Collection,
|
collection: Collection,
|
||||||
history: RouterHistory,
|
history: RouterHistory,
|
||||||
@ -91,15 +89,7 @@ class CollectionMenu extends React.Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const { collection, label, position, onOpen, onClose } = this.props;
|
||||||
policies,
|
|
||||||
collection,
|
|
||||||
label,
|
|
||||||
position,
|
|
||||||
onOpen,
|
|
||||||
onClose,
|
|
||||||
} = this.props;
|
|
||||||
const can = policies.abilties(collection.id);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@ -110,7 +100,7 @@ class CollectionMenu extends React.Component<Props> {
|
|||||||
accept="text/markdown, text/plain"
|
accept="text/markdown, text/plain"
|
||||||
/>
|
/>
|
||||||
<Modal
|
<Modal
|
||||||
title="Collection members"
|
title="Collection permissions"
|
||||||
onRequestClose={this.handlePermissionsModalClose}
|
onRequestClose={this.handlePermissionsModalClose}
|
||||||
isOpen={this.permissionsModalOpen}
|
isOpen={this.permissionsModalOpen}
|
||||||
>
|
>
|
||||||
@ -134,24 +124,16 @@ class CollectionMenu extends React.Component<Props> {
|
|||||||
Import document
|
Import document
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<hr />
|
<hr />
|
||||||
{can.update && (
|
<DropdownMenuItem onClick={this.onEdit}>Edit…</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={this.onEdit}>Edit…</DropdownMenuItem>
|
<DropdownMenuItem onClick={this.onPermissions}>
|
||||||
)}
|
Permissions…
|
||||||
{can.update && (
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={this.onPermissions}>
|
<DropdownMenuItem onClick={this.onExport}>
|
||||||
Members…
|
Export…
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
|
||||||
{can.export && (
|
|
||||||
<DropdownMenuItem onClick={this.onExport}>
|
|
||||||
Export…
|
|
||||||
</DropdownMenuItem>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
{can.delete && (
|
<DropdownMenuItem onClick={this.onDelete}>Delete…</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={this.onDelete}>Delete…</DropdownMenuItem>
|
|
||||||
)}
|
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
@ -165,6 +147,4 @@ const HiddenInput = styled.input`
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default inject('ui', 'documents', 'policies')(
|
export default inject('ui', 'documents')(withRouter(CollectionMenu));
|
||||||
withRouter(CollectionMenu)
|
|
||||||
);
|
|
||||||
|
@ -152,7 +152,7 @@ class CollectionScene extends React.Component<Props> {
|
|||||||
)}
|
)}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
<Modal
|
<Modal
|
||||||
title="Collection members"
|
title="Collection permissions"
|
||||||
onRequestClose={this.handlePermissionsModalClose}
|
onRequestClose={this.handlePermissionsModalClose}
|
||||||
isOpen={this.permissionsModalOpen}
|
isOpen={this.permissionsModalOpen}
|
||||||
>
|
>
|
||||||
|
@ -6,7 +6,6 @@ import { inject, observer } from 'mobx-react';
|
|||||||
import Input from 'components/Input';
|
import Input from 'components/Input';
|
||||||
import InputRich from 'components/InputRich';
|
import InputRich from 'components/InputRich';
|
||||||
import Button from 'components/Button';
|
import Button from 'components/Button';
|
||||||
import Switch from 'components/Switch';
|
|
||||||
import Flex from 'shared/components/Flex';
|
import Flex from 'shared/components/Flex';
|
||||||
import HelpText from 'components/HelpText';
|
import HelpText from 'components/HelpText';
|
||||||
import ColorPicker from 'components/ColorPicker';
|
import ColorPicker from 'components/ColorPicker';
|
||||||
@ -26,13 +25,11 @@ class CollectionEdit extends React.Component<Props> {
|
|||||||
@observable description: string = '';
|
@observable description: string = '';
|
||||||
@observable color: string = '#4E5C6E';
|
@observable color: string = '#4E5C6E';
|
||||||
@observable isSaving: boolean;
|
@observable isSaving: boolean;
|
||||||
@observable private: boolean = false;
|
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.name = this.props.collection.name;
|
this.name = this.props.collection.name;
|
||||||
this.description = this.props.collection.description;
|
this.description = this.props.collection.description;
|
||||||
this.color = this.props.collection.color;
|
this.color = this.props.collection.color;
|
||||||
this.private = this.props.collection.private;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit = async (ev: SyntheticEvent<*>) => {
|
handleSubmit = async (ev: SyntheticEvent<*>) => {
|
||||||
@ -44,7 +41,6 @@ class CollectionEdit extends React.Component<Props> {
|
|||||||
name: this.name,
|
name: this.name,
|
||||||
description: this.description,
|
description: this.description,
|
||||||
color: this.color,
|
color: this.color,
|
||||||
private: this.private,
|
|
||||||
});
|
});
|
||||||
this.props.onSubmit();
|
this.props.onSubmit();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -66,10 +62,6 @@ class CollectionEdit extends React.Component<Props> {
|
|||||||
this.color = color;
|
this.color = color;
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePrivateChange = (ev: SyntheticInputEvent<*>) => {
|
|
||||||
this.private = ev.target.checked;
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Flex column>
|
<Flex column>
|
||||||
@ -99,15 +91,6 @@ class CollectionEdit extends React.Component<Props> {
|
|||||||
minHeight={68}
|
minHeight={68}
|
||||||
maxHeight={200}
|
maxHeight={200}
|
||||||
/>
|
/>
|
||||||
<Switch
|
|
||||||
id="private"
|
|
||||||
label="Private collection"
|
|
||||||
onChange={this.handlePrivateChange}
|
|
||||||
checked={this.private}
|
|
||||||
/>
|
|
||||||
<HelpText>
|
|
||||||
A private collection will only be visible to invited team members.
|
|
||||||
</HelpText>
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={this.isSaving || !this.props.collection.name}
|
disabled={this.isSaving || !this.props.collection.name}
|
||||||
|
@ -4,11 +4,13 @@ import { reject } from 'lodash';
|
|||||||
import { observable } from 'mobx';
|
import { observable } from 'mobx';
|
||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
import Flex from 'shared/components/Flex';
|
import Flex from 'shared/components/Flex';
|
||||||
|
import Fade from 'components/Fade';
|
||||||
import Input from 'components/Input';
|
import Input from 'components/Input';
|
||||||
import HelpText from 'components/HelpText';
|
import HelpText from 'components/HelpText';
|
||||||
import Subheading from 'components/Subheading';
|
import Subheading from 'components/Subheading';
|
||||||
import List from 'components/List';
|
import List from 'components/List';
|
||||||
import Placeholder from 'components/List/Placeholder';
|
import Placeholder from 'components/List/Placeholder';
|
||||||
|
import Switch from 'components/Switch';
|
||||||
import UserListItem from './components/UserListItem';
|
import UserListItem from './components/UserListItem';
|
||||||
import MemberListItem from './components/MemberListItem';
|
import MemberListItem from './components/MemberListItem';
|
||||||
import Collection from 'models/Collection';
|
import Collection from 'models/Collection';
|
||||||
@ -40,11 +42,7 @@ class CollectionPermissions extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePrivateChange = async (ev: SyntheticInputEvent<HTMLInputElement>) => {
|
handlePrivateChange = async (ev: SyntheticInputEvent<*>) => {
|
||||||
console.log('handlePrivateChange');
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
|
|
||||||
const { collection } = this.props;
|
const { collection } = this.props;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -102,46 +100,60 @@ class CollectionPermissions extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<Flex column>
|
<Flex column>
|
||||||
<HelpText>
|
<HelpText>
|
||||||
Choose which team members have access to read and edit documents in
|
Choose which people on the team have access to read and edit documents
|
||||||
the <strong>{collection.name}</strong> collection.
|
in the <strong>{collection.name}</strong> collection. By default
|
||||||
|
collections are visible to all team members.
|
||||||
</HelpText>
|
</HelpText>
|
||||||
|
|
||||||
<Subheading>Members</Subheading>
|
<Switch
|
||||||
<List>
|
id="private"
|
||||||
{isFirstLoadingUsers ? (
|
label="Private collection"
|
||||||
<Placeholder />
|
onChange={this.handlePrivateChange}
|
||||||
) : (
|
checked={collection.private}
|
||||||
collection.users.map(member => (
|
/>
|
||||||
<MemberListItem
|
|
||||||
key={member.id}
|
|
||||||
user={member}
|
|
||||||
showRemove={user.id !== member.id}
|
|
||||||
onRemove={() => this.handleRemoveUser(member)}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
|
|
||||||
{hasOtherUsers && (
|
{collection.private && (
|
||||||
<React.Fragment>
|
<Fade>
|
||||||
<Subheading>Others</Subheading>
|
<Flex column>
|
||||||
<Input
|
<Subheading>Invited ({collection.users.length})</Subheading>
|
||||||
onChange={this.handleFilter}
|
<List>
|
||||||
placeholder="Find a team member…"
|
{isFirstLoadingUsers ? (
|
||||||
value={this.filter}
|
<Placeholder />
|
||||||
type="search"
|
) : (
|
||||||
/>
|
collection.users.map(member => (
|
||||||
<List>
|
<MemberListItem
|
||||||
{filteredUsers.map(member => (
|
key={member.id}
|
||||||
<UserListItem
|
user={member}
|
||||||
key={member.id}
|
showRemove={user.id !== member.id}
|
||||||
user={member}
|
onRemove={() => this.handleRemoveUser(member)}
|
||||||
onAdd={() => this.handleAddUser(member)}
|
/>
|
||||||
showAdd
|
))
|
||||||
/>
|
)}
|
||||||
))}
|
</List>
|
||||||
</List>
|
|
||||||
</React.Fragment>
|
{hasOtherUsers && (
|
||||||
|
<React.Fragment>
|
||||||
|
<Subheading>Team Members</Subheading>
|
||||||
|
<Input
|
||||||
|
onChange={this.handleFilter}
|
||||||
|
placeholder="Filter…"
|
||||||
|
value={this.filter}
|
||||||
|
type="search"
|
||||||
|
/>
|
||||||
|
<List>
|
||||||
|
{filteredUsers.map(member => (
|
||||||
|
<UserListItem
|
||||||
|
key={member.id}
|
||||||
|
user={member}
|
||||||
|
onAdd={() => this.handleAddUser(member)}
|
||||||
|
showAdd
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Fade>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { PlusIcon } from 'outline-icons';
|
|
||||||
import Avatar from 'components/Avatar';
|
import Avatar from 'components/Avatar';
|
||||||
import Button from 'components/Button';
|
import Button from 'components/Button';
|
||||||
import ListItem from 'components/List/Item';
|
import ListItem from 'components/List/Item';
|
||||||
@ -19,8 +18,8 @@ const UserListItem = ({ user, onAdd, showAdd }: Props) => {
|
|||||||
image={<Avatar src={user.avatarUrl} size={32} />}
|
image={<Avatar src={user.avatarUrl} size={32} />}
|
||||||
actions={
|
actions={
|
||||||
showAdd ? (
|
showAdd ? (
|
||||||
<Button type="button" onClick={onAdd} icon={<PlusIcon />} neutral>
|
<Button type="button" onClick={onAdd} neutral>
|
||||||
Add
|
Invite
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
undefined
|
undefined
|
||||||
|
Reference in New Issue
Block a user