-
-
-
Share a link to this notebook
-
-
-
-
-
+ constructor(props){
+ super(props)
+ this.deleteNotebook = this.deleteNotebook.bind(this);
+ }
-
-
-
Change the name of this notebook
-
-
-
-
-
-
-
Change the name of this notebook
-
-
- )
+ )
+ } else {
+ return null;
+ }
}
}
diff --git a/pkg/interface/publish/src/js/components/lib/subscriber-item.js b/pkg/interface/publish/src/js/components/lib/subscriber-item.js
deleted file mode 100644
index 612f166e14..0000000000
--- a/pkg/interface/publish/src/js/components/lib/subscriber-item.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React, { Component } from 'react'
-
-//TODO fill sigil/avatar + name from props
-
-export class SubscriberItem extends Component {
- render() {
- return (
-
-
-
- )
- }
-}
-
-export default SubscriberItem
diff --git a/pkg/interface/publish/src/js/components/lib/subscribers.js b/pkg/interface/publish/src/js/components/lib/subscribers.js
index 4e3b812191..2d36247b1e 100644
--- a/pkg/interface/publish/src/js/components/lib/subscribers.js
+++ b/pkg/interface/publish/src/js/components/lib/subscribers.js
@@ -1,53 +1,184 @@
import React, { Component } from 'react';
-import { SubscriberItem } from './subscriber-item';
-
-//TODO map list of subscriber-items from props
+import { Dropdown } from './dropdown';
export class Subscribers extends Component {
+ constructor(props){
+ super(props);
+ this.redirect = this.redirect.bind(this);
+ this.addUser = this.addUser.bind(this);
+ this.removeUser = this.removeUser.bind(this);
+ }
+
+ addUser(who, path) {
+ let action = {
+ add: {
+ members: [who],
+ path: path,
+ }
+ }
+ window.api.action("group-store", "group-action", action);
+ }
+
+ removeUser(who, path) {
+ let action = {
+ remove: {
+ members: [who],
+ path: path,
+ }
+ }
+ window.api.action("group-store", "group-action", action);
+ }
+
+ redirect(url) {
+ window.location.href = url;
+ }
+
render() {
+ let readPath = this.props.notebook["subscribers-group-path"]
+ let readPerms = (readPath)
+ ? this.props.permissions[readPath]
+ : null;
+ let writePath = this.props.notebook["writers-group-path"]
+ let writePerms = (writePath)
+ ? this.props.permissions[writePath]
+ : null;
+
+ let writers = [];
+ if (writePerms && writePerms.kind === 'white') {
+ let withoutUs = new Set(writePerms.who)
+ withoutUs.delete(window.ship);
+ writers = Array.from(withoutUs).map((who, i) => {
+ let width = 0;
+ let options = [];
+ if (readPath === writePath) {
+ width = 258;
+ let url = `/~contacts${writePath}`;
+ options = [{
+ cls: "tl pointer",
+ txt: "Manage this group in the contacts view",
+ action: () => {this.redirect(url)}
+ }];
+ } else {
+ width = 157;
+ options = [{
+ cls: "tl pointer",
+ txt: "Demote to subscriber",
+ action: () => {this.removeUser(`~${who}`, writePath)}
+ }];
+ }
+ return (
+
+ )
+ });
+ }
+
+ if (writers.length === 0) {
+ writers =
+
+ There are no participants on this notebook.
+
+ }
+
+ let subscribers = null;
+ if (readPath !== writePath) {
+ if (this.props.notebook.subscribers){
+ let width = 162;
+ subscribers = this.props.notebook.subscribers.map((who, i) => {
+ let options = [
+ { cls: "tl mb2 pointer",
+ txt: "Promote to participant",
+ action: () => {this.addUser(who, writePath)}
+ },
+ { cls: "tl red2 pointer",
+ txt: "Ban",
+ action: () => {this.addUser(who, readPath)}
+ },
+ ];
+ return (
+
+ )
+ });
+ }
+ if (subscribers.length === 0) {
+ subscribers =
+
+ There are no subscribers to this notebook.
+
+ }
+ }
+
+ let subsContainer = (readPath === writePath)
+ ? null
+ :
+
Subscribers (read access only)
+ {subscribers}
+
;
+
+
+ let bannedContainer = null;
+ if (readPerms && readPerms.kind === 'black') {
+ let width = 72;
+ let banned = Array.from(readPerms.who).map((who, i) => {
+ let options = [{
+ cls: "tl red2 pointer",
+ txt: "Unban",
+ action: () => {this.removeUser(`~${who}`, readPath)}
+ }];
+ return (
+
+ )
+ });
+ if (banned.length === 0) {
+ banned =
+
+ There are no users banned from this notebook.
+
+ }
+ bannedContainer =
+
;
+ }
+
+
return (
-
-
Host
-
-
-
~fabled-faster
-
Last active
+
-
-
-
Participants (read and write access)
-
There are no paticipants in this notebook.
-
-
-
~fabled-faster
-
Last active
+
+
+ Participants (read and write access)
-
Options ⌃
+ {writers}
-
-
-
Subscribers (read access only)
-
-
-
~fabled-faster
-
Last active
-
-
Options ⌃
-
-
-
-
Banned
-
-
-
~fabled-faster
-
Last active
-
-
Options ⌃
-
-
+ {subsContainer}
+ {bannedContainer}
)
}
diff --git a/pkg/interface/publish/src/js/components/root.js b/pkg/interface/publish/src/js/components/root.js
index 3edbe1971c..02253cfa76 100644
--- a/pkg/interface/publish/src/js/components/root.js
+++ b/pkg/interface/publish/src/js/components/root.js
@@ -143,6 +143,7 @@ export class Root extends Component {
contacts={notebookContacts}
sidebarShown={state.sidebarShown}
popout={popout}
+ permissions={state.permissions}
{...props}
/>
diff --git a/pkg/interface/publish/src/js/reducers/permission.js b/pkg/interface/publish/src/js/reducers/permission.js
new file mode 100644
index 0000000000..80af6f4c53
--- /dev/null
+++ b/pkg/interface/publish/src/js/reducers/permission.js
@@ -0,0 +1,58 @@
+import _ from 'lodash';
+
+export class PermissionReducer {
+ reduce(json, state) {
+ let data = _.get(json, 'permission-initial', false);
+ if (data) {
+ for (let perm in data) {
+ state.permissions[perm] = {
+ who: new Set(data[perm].who),
+ kind: data[perm].kind
+ }
+ }
+ }
+ data = _.get(json, 'permission-update', false);
+ if (data) {
+ this.create(data, state);
+ this.delete(data, state);
+ this.add(data, state);
+ this.remove(data, state);
+ }
+ }
+
+ create(json, state) {
+ let data = _.get(json, 'create', false);
+ if (data) {
+ state.permissions[data.path] = {
+ kind: data.kind,
+ who: new Set(data.who)
+ };
+ }
+ }
+
+ delete(json, state) {
+ let data = _.get(json, 'delete', false);
+ if (data) {
+ delete state.permissions[data.path];
+ }
+ }
+
+ add(json, state) {
+ let data = _.get(json, 'add', false);
+ if (data) {
+ for (let member of data.who) {
+ state.permissions[data.path].who.add(member);
+ }
+ }
+ }
+
+ remove(json, state) {
+ let data = _.get(json, 'remove', false);
+ if (data) {
+ for (let member of data.who) {
+ state.permissions[data.path].who.delete(member);
+ }
+ }
+ }
+}
+
diff --git a/pkg/interface/publish/src/js/reducers/response.js b/pkg/interface/publish/src/js/reducers/response.js
index 64a9d8c021..ec9849d0d3 100644
--- a/pkg/interface/publish/src/js/reducers/response.js
+++ b/pkg/interface/publish/src/js/reducers/response.js
@@ -64,6 +64,14 @@ export class ResponseReducer {
if (state.notebooks[json.host][json.notebook]) {
state.notebooks[json.host][json.notebook]["notes-by-date"] =
json.data.notebook["notes-by-date"];
+ state.notebooks[json.host][json.notebook].subscribers =
+ json.data.notebook.subscribers;
+ state.notebooks[json.host][json.notebook].comments =
+ json.data.notebook.comments;
+ state.notebooks[json.host][json.notebook]["subscribers-group-path"] =
+ json.data.notebook["subscribers-group-path"];
+ state.notebooks[json.host][json.notebook]["writers-group-path"] =
+ json.data.notebook["writers-group-path"];
if (state.notebooks[json.host][json.notebook].notes) {
for (var key in json.data.notebook.notes) {
let oldNote = state.notebooks[json.host][json.notebook].notes[key];
diff --git a/pkg/interface/publish/src/js/store.js b/pkg/interface/publish/src/js/store.js
index 408aa65451..11569a176f 100644
--- a/pkg/interface/publish/src/js/store.js
+++ b/pkg/interface/publish/src/js/store.js
@@ -1,8 +1,9 @@
-import { InitialReducer } from '/reducers/initial';
-import { PrimaryReducer } from '/reducers/primary';
-import { ResponseReducer } from '/reducers/response';
-import { GroupReducer } from '/reducers/group';
-import { InviteReducer } from '/reducers/invite';
+import { InitialReducer } from '/reducers/initial';
+import { PrimaryReducer } from '/reducers/primary';
+import { ResponseReducer } from '/reducers/response';
+import { GroupReducer } from '/reducers/group';
+import { InviteReducer } from '/reducers/invite';
+import { PermissionReducer } from '/reducers/permission';
class Store {
constructor() {
@@ -16,11 +17,12 @@ class Store {
sidebarShown: true
}
- this.initialReducer = new InitialReducer();
- this.primaryReducer = new PrimaryReducer();
- this.responseReducer = new ResponseReducer();
- this.groupReducer = new GroupReducer();
- this.inviteReducer = new InviteReducer();
+ this.initialReducer = new InitialReducer();
+ this.primaryReducer = new PrimaryReducer();
+ this.responseReducer = new ResponseReducer();
+ this.groupReducer = new GroupReducer();
+ this.inviteReducer = new InviteReducer();
+ this.permissionReducer = new PermissionReducer();
this.setState = () => {};
this.initialReducer.reduce(window.injectedState, this.state);
@@ -33,6 +35,7 @@ class Store {
handleEvent(evt) {
if (evt.from && evt.from.path === '/all') {
this.groupReducer.reduce(evt.data, this.state);
+ this.permissionReducer.reduce(evt.data, this.state);
}
else if (evt.from && evt.from.path === '/primary'){
this.primaryReducer.reduce(evt.data, this.state);
diff --git a/pkg/interface/publish/src/js/subscription.js b/pkg/interface/publish/src/js/subscription.js
index b882bfe279..2cd9223c59 100644
--- a/pkg/interface/publish/src/js/subscription.js
+++ b/pkg/interface/publish/src/js/subscription.js
@@ -24,6 +24,9 @@ export class Subscription {
api.bind('/primary', 'PUT', api.authTokens.ship, 'invite-view',
this.handleEvent.bind(this),
this.handleError.bind(this));
+ api.bind('/all', 'PUT', api.authTokens.ship, 'permission-store',
+ this.handleEvent.bind(this),
+ this.handleError.bind(this));
}
handleEvent(diff) {