diff --git a/.gitignore b/.gitignore
index 3f78ed6b9..679f0afa4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
*.iml
.idea
+.vscode
node_modules*/
.sass-cache
diff --git a/package.json b/package.json
index 77cb9409e..3e2f41a79 100644
--- a/package.json
+++ b/package.json
@@ -59,6 +59,7 @@
"react-stub-context": "^0.7.0",
"react-tap-event-plugin": "^2.0.1",
"react-test-renderer": "^15.6.0",
+ "recompose": "^0.26.0",
"rxjs": "^5.4.3",
"sass-loader": "^6.0.2",
"style-loader": "^0.18.2",
diff --git a/src/sharing/Access.component.js b/src/sharing/Access.component.js
new file mode 100644
index 000000000..f74c68cf8
--- /dev/null
+++ b/src/sharing/Access.component.js
@@ -0,0 +1,170 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { compose, mapProps, getContext, withProps } from 'recompose';
+import FontIcon from 'material-ui/FontIcon';
+import { config } from 'd2/lib/d2';
+import IconButton from 'material-ui/IconButton';
+
+import PermissionPicker from './PermissionPicker.component';
+
+import {
+ accessStringToObject,
+ accessObjectToString,
+} from './utils';
+
+config.i18n.strings.add('public_access');
+config.i18n.strings.add('external_access');
+config.i18n.strings.add('anyone_can_view_without_a_login');
+config.i18n.strings.add('anyone_can_find_view_and_edit');
+config.i18n.strings.add('anyone_can_find_and_view');
+config.i18n.strings.add('no_access');
+
+const styles = {
+ accessView: {
+ fontWeight: '400',
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ padding: '4px 8px',
+ },
+ accessDescription: {
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ paddingLeft: 16,
+ },
+};
+
+const d2Context = {
+ d2: PropTypes.object.isRequired,
+};
+
+const getAccessIcon = (userType) => {
+ switch (userType) {
+ case 'user': return 'person';
+ case 'userGroup': return 'group';
+ case 'external': return 'public';
+ case 'public': return 'business';
+ default: return 'person';
+ }
+};
+
+const useAccessObjectFormat = props => ({
+ ...props,
+ access: accessStringToObject(props.access),
+ onChange: (newAccess) => {
+ props.onChange(accessObjectToString(newAccess));
+ },
+});
+
+export const Access = ({
+ access,
+ accessType,
+ accessOptions,
+ primaryText,
+ secondaryText,
+ onChange,
+ onRemove,
+ disabled,
+}) => (
+
+
+ {getAccessIcon(accessType)}
+
+
+
{primaryText}
+
{secondaryText || ' '}
+
+
+
+
+
{})}
+ >clear
+
+);
+
+Access.contextTypes = d2Context;
+
+Access.propTypes = {
+ access: PropTypes.object.isRequired,
+ accessType: PropTypes.string.isRequired,
+ accessOptions: PropTypes.object.isRequired,
+ primaryText: PropTypes.string.isRequired,
+ onChange: PropTypes.func.isRequired,
+ disabled: PropTypes.bool,
+ secondaryText: PropTypes.string,
+ onRemove: PropTypes.func,
+};
+
+Access.defaultProps = {
+ secondaryText: undefined,
+ onRemove: undefined,
+ disabled: false,
+};
+
+export const GroupAccess = compose(
+ mapProps(useAccessObjectFormat),
+ withProps(props => ({
+ accessType: props.groupType,
+ primaryText: props.groupName,
+ accessOptions: {
+ meta: { canView: true, canEdit: true, noAccess: false },
+ data: props.dataShareable && { canView: true, canEdit: true, noAccess: true },
+ },
+ })),
+)(Access);
+
+export const ExternalAccess = compose(
+ getContext(d2Context),
+ withProps(props => ({
+ accessType: 'external',
+ primaryText: props.d2.i18n.getTranslation('external_access'),
+ secondaryText: props.access
+ ? props.d2.i18n.getTranslation('anyone_can_view_without_a_login')
+ : props.d2.i18n.getTranslation('no_access'),
+ access: {
+ meta: { canEdit: false, canView: props.access },
+ data: { canEdit: false, canView: false },
+ },
+ onChange: (newAccess) => {
+ props.onChange(newAccess.meta.canView);
+ },
+ accessOptions: {
+ meta: { canView: true, canEdit: false, noAccess: true },
+ },
+ })),
+)(Access);
+
+const constructSecondaryText = ({ canView, canEdit }) => {
+ if (canEdit) {
+ return 'anyone_can_find_view_and_edit';
+ }
+
+ return canView
+ ? 'anyone_can_find_and_view'
+ : 'no_access';
+};
+
+export const PublicAccess = compose(
+ mapProps(useAccessObjectFormat),
+ getContext(d2Context),
+ withProps(props => ({
+ accessType: 'public',
+ primaryText: props.d2.i18n.getTranslation('public_access'),
+ secondaryText: props.d2.i18n.getTranslation(constructSecondaryText(props.access.meta)),
+ accessOptions: {
+ meta: { canView: true, canEdit: true, noAccess: true },
+ data: props.dataShareable && { canView: true, canEdit: true, noAccess: true },
+ },
+ })),
+)(Access);
diff --git a/src/sharing/CreatedBy.component.js b/src/sharing/CreatedBy.component.js
index fa1ca1d7c..f8ddcae5e 100644
--- a/src/sharing/CreatedBy.component.js
+++ b/src/sharing/CreatedBy.component.js
@@ -5,18 +5,16 @@ import { config } from 'd2/lib/d2';
config.i18n.strings.add('created_by');
config.i18n.strings.add('no_author');
-const CreatedBy = ({ user }, context) => {
- const createdByText = user && user.name ?
- `${context.d2.i18n.getTranslation('created_by')}: ${user.name}` :
+const CreatedBy = ({ author }, context) => {
+ const createdByText = author ?
+ `${context.d2.i18n.getTranslation('created_by')}: ${author.name}` :
context.d2.i18n.getTranslation('no_author');
return {createdByText}
;
};
CreatedBy.propTypes = {
- user: PropTypes.shape({
- name: PropTypes.string,
- }).isRequired,
+ author: PropTypes.object.isRequired,
};
CreatedBy.contextTypes = {
diff --git a/src/sharing/ExternalAccess.component.js b/src/sharing/ExternalAccess.component.js
deleted file mode 100644
index d0dc3ea7a..000000000
--- a/src/sharing/ExternalAccess.component.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/* eslint react/jsx-no-bind: 0 */
-
-import PropTypes from 'prop-types';
-import React from 'react';
-import { config } from 'd2/lib/d2';
-
-import Rule from './Rule.component';
-
-config.i18n.strings.add('external_access');
-config.i18n.strings.add('anyone_can_view_without_a_login');
-config.i18n.strings.add('no_access');
-
-const ExternalAccess = ({ canView, disabled, onChange }, context) => (
-
-);
-
-ExternalAccess.propTypes = {
- canView: PropTypes.bool.isRequired,
- onChange: PropTypes.func.isRequired,
- disabled: PropTypes.bool,
-};
-
-ExternalAccess.contextTypes = {
- d2: PropTypes.object.isRequired,
-};
-
-export default ExternalAccess;
diff --git a/src/sharing/PermissionOption.component.js b/src/sharing/PermissionOption.component.js
new file mode 100644
index 000000000..8f49a75a4
--- /dev/null
+++ b/src/sharing/PermissionOption.component.js
@@ -0,0 +1,47 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import FontIcon from 'material-ui/FontIcon';
+import MenuItem from 'material-ui/MenuItem';
+
+class PermissionOption extends Component {
+ ref = null;
+
+ render = () => {
+ if (this.props.disabled) {
+ return null;
+ }
+
+ return (
+