Merge pull request #2777 from urbit/ixv/publish-groupify

publish: groupify notebooks
This commit is contained in:
Fang 2020-04-23 02:00:24 +02:00 committed by GitHub
commit a810468dcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 239 additions and 11 deletions

View File

@ -1702,8 +1702,107 @@
:~ [%give %fact [/primary]~ %publish-primary-delta !>(act)]
[%give %fact [/publishtile]~ %json !>(jon)]
==
:: %groupify
::
%groupify
?. (team:title our.bol src.bol)
~|("action not permitted" !!)
=/ book (~(get by books) our.bol book.act)
?~ book
~|("nonexistent notebook: {<book.act>}" !!)
::
=/ old-write writers.u.book
=/ old-read subscribers.u.book
?> ?=([%'~' ^] old-write)
=/ destroy-old-groups=(list card)
:~ (group-poke [%unbundle old-write])
(group-poke [%unbundle old-read])
(group-hook-poke [%remove old-write])
(group-hook-poke [%remove old-read])
(perm-hook-poke [%remove old-write])
(perm-hook-poke [%remove old-read])
==
::
?~ target.act
:: create new group from subscribers
::
=. writers.u.book (slag 1 writers.u.book)
=. subscribers.u.book writers.u.book
=/ del=notebook-delta [%edit-book our.bol book.act u.book]
:_ state(books (~(put by books) [our.bol book.act] u.book))
%+ weld destroy-old-groups
^- (list card)
:~ [%give %fact [/notebook/[book.act]]~ %publish-notebook-delta !>(del)]
[%give %fact [/primary]~ %publish-primary-delta !>(del)]
%- contact-view-create
:* writers.u.book
(get-subscribers book.act)
title.u.book
description.u.book
==
%- metadata-poke
:* %add
writers.u.book
[%publish /(scot %p our.bol)/[book.act]]
title.u.book
description.u.book
0x0
date-created.u.book
our.bol
==
==
::
?> ?=(^ u.target.act)
=. writers.u.book u.target.act
=. subscribers.u.book u.target.act
=/ group-host=@p (slav %p i.u.target.act)
::
=/ scry-pax :(weld /=group-store/(scot %da now.bol) u.target.act /noun)
=/ old-group=(set @p) (need .^((unit (set @p)) %gx scry-pax))
=/ dif-peeps=(set @p) (~(dif in (get-subscribers book.act)) old-group)
::
=/ del=notebook-delta [%edit-book our.bol book.act u.book]
:_ state(books (~(put by books) [our.bol book.act] u.book))
%+ weld
%+ weld destroy-old-groups
^- (list card)
:~ [%give %fact [/notebook/[book.act]]~ %publish-notebook-delta !>(del)]
[%give %fact [/primary]~ %publish-primary-delta !>(del)]
%- metadata-poke
:* %add
writers.u.book
[%publish /(scot %p our.bol)/[book.act]]
title.u.book
description.u.book
0x0
date-created.u.book
our.bol
==
==
?: ?& inclusive.act
=(group-host our.bol)
==
:: add all subscribers to group
::
[(group-poke [%add dif-peeps u.target.act])]~
:: kick subscribers who are not already in group
::
%+ turn ~(tap in dif-peeps)
|= who=@p
^- card
[%give %kick [/notebook/[book.act]]~ `who]
==
::
++ get-subscribers
|= book=@tas
^- (set @p)
%+ roll ~(val by sup.bol)
|= [[who=@p pax=path] out=(set @p)]
^- (set @p)
?. ?=([%notebook @ ~] pax) out
?. =(book i.t.pax) out
(~(put in out) who)
::
++ get-notebook
|= [host=@p book-name=@tas sty=_state]
^- (unit notebook)
@ -1732,6 +1831,11 @@
[%give %fact [/publishtile]~ %json !>(jon)]
==
::
++ metadata-poke
|= act=metadata-action
^- card
[%pass / %agent [our.bol %metadata-hook] %poke %metadata-action !>(act)]
::
++ emit-metadata
|= del=metadata-delta
^- (list card)
@ -1762,11 +1866,6 @@
^- (list card)
[(metadata-poke [%add group-path [%publish app-path] metadata])]~
::
++ metadata-poke
|= act=metadata-action
^- card
[%pass / %agent [our.bol %metadata-hook] %poke %metadata-action !>(act)]
::
++ metadata-scry
|= [group-path=path app-path=path]
^- (unit metadata)

View File

@ -32,6 +32,7 @@
subscribe+subscribe
unsubscribe+unsubscribe
read+read
groupify+groupify
==
::
++ new-book
@ -114,6 +115,12 @@
book+so
note+so
==
++ groupify
%- ot
:~ book+so
target+(mu pa)
inclusive+bo
==
++ group-info
%- ot
:~ group-path+pa

View File

@ -25,6 +25,8 @@
[%unsubscribe who=@p book=@tas]
::
[%read who=@p book=@tas note=@tas]
::
[%groupify book=@tas target=(unit path) inclusive=?]
==
::
+$ comment comment-3

View File

@ -99,7 +99,7 @@ export class Notebook extends Component {
list={notesList}
host={props.ship}
notebookName={props.book}
contacts={props.contacts}
contacts={props.notebookContacts}
/>
break;
case "about":
@ -119,6 +119,8 @@ export class Notebook extends Component {
book={this.props.book}
notebook={notebook}
groups={this.props.groups}
contacts={this.props.contacts}
associations={this.props.associations}
history={this.props.history}/>
break;
default:
@ -126,8 +128,8 @@ export class Notebook extends Component {
}
// displaying nicknames, sigil colors for contacts
let contact = !!(props.ship.substr(1) in props.contacts)
? props.contacts[props.ship.substr(1)] : false;
let contact = !!(props.ship.substr(1) in props.notebookContacts)
? props.notebookContacts[props.ship.substr(1)] : false;
let name = props.ship;
if (contact) {
name = (contact.nickname.length > 0)

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import { writeText } from '../../lib/util';
import { Spinner } from './icons/icon-spinner';
import { InviteSearch } from '/components/lib/invite-search';
export class Settings extends Component {
constructor(props){
@ -10,12 +11,16 @@ export class Settings extends Component {
description: "",
comments: false,
disabled: false,
type: "Editing"
type: "Editing",
targetGroup: null,
inclusive: false,
}
this.deleteNotebook = this.deleteNotebook.bind(this);
this.changeTitle = this.changeTitle.bind(this);
this.changeDescription = this.changeDescription.bind(this);
this.changeComments = this.changeComments.bind(this);
this.changeTargetGroup = this.changeTargetGroup.bind(this);
this.changeInclusive = this.changeInclusive.bind(this);
}
componentDidMount() {
@ -84,6 +89,111 @@ export class Settings extends Component {
});
}
changeTargetGroup(target) {
if (target.groups.length === 1) {
this.setState({ targetGroup: target.groups[0] });
} else {
this.setState({ targetGroup: null });
}
}
changeInclusive(event) {
this.setState({ inclusive: !!event.target.checked });
}
groupifyNotebook() {
const { props, state } = this;
this.setState({
disabled: true,
type: 'Converting'
}, (() => {
window.api.action("publish", "publish-action", {
groupify: {
book: props.book,
target: state.targetGroup,
inclusive: state.inclusive,
}
}).then(() => this.setState({disabled: false}));
}));
}
renderGroupify() {
const { props, state } = this;
const owner = (props.host.slice(1) === window.ship);
const ownedUnmanaged =
owner &&
props.notebook['writers-group-path'].slice(0, 3) === '/~/';
if (!ownedUnmanaged) {
return null;
} else {
// don't give the option to make inclusive if we don't own the target
// group
let targetOwned = (state.targetGroup)
? state.targetGroup.slice(0, window.ship.length+3) === `/~${window.ship}/`
: false;
let inclusiveToggle = <div/>
if (targetOwned) {
//TODO toggle component into /lib
let inclusiveClasses = state.inclusive
? "relative checked bg-green2 br3 h1 toggle v-mid z-0"
: "relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0";
inclusiveToggle = (
<div className="mt4">
<input
type="checkbox"
style={{ WebkitAppearance: "none", width: 28 }}
className={inclusiveClasses}
onChange={this.changeInclusive}
/>
<span className="dib f9 white-d inter ml3">
Add all members to group
</span>
<p className="f9 gray2 pt1" style={{ paddingLeft: 40 }}>
Add notebook members to the group if they aren't in it yet
</p>
</div>
);
}
return (
<div>
<div className={"w-100 fl mt3 mb3"} style={{maxWidth: "29rem"}}>
<p className="f8 mt3 lh-copy db">Convert Notebook</p>
<p className="f9 gray2 db mb4">
Convert this notebook into a group with associated chat, or select a
group to add this notebook to.
</p>
<InviteSearch
groups={props.groups}
contacts={props.contacts}
associations={props.associations}
groupResults={true}
shipResults={false}
invites={{
groups: state.targetGroup ? [state.targetGroup] : [],
ships: []
}}
setInvite={this.changeTargetGroup}
/>
{inclusiveToggle}
<button
onClick={this.groupifyNotebook.bind(this)}
className={"dib f9 black gray4-d bg-gray0-d ba pa2 mt4 b--black b--gray1-d pointer"}
disabled={this.state.disabled}>
Convert to group
</button>
</div>
</div>
);
}
}
render() {
let commentsSwitchClasses = (this.state.comments)
? "relative checked bg-green2 br3 h1 toggle v-mid z-0"
@ -115,6 +225,7 @@ export class Settings extends Component {
return (
<div className="flex-column">
{copyShortcode}
{this.renderGroupify()}
<p className="f9 mt6 lh-copy db">Delete Notebook</p>
<p className="f9 gray2 db mb4">
Permanently delete this notebook. (All current members will no

View File

@ -135,6 +135,7 @@ export class Root extends Component {
let bookGroupPath =
state.notebooks[ship][notebook]["subscribers-group-path"];
let notebookContacts = (bookGroupPath in contacts)
? contacts[bookGroupPath] : {};
@ -181,7 +182,9 @@ export class Root extends Component {
ship={ship}
book={notebook}
groups={state.groups}
contacts={notebookContacts}
contacts={contacts}
notebookContacts={notebookContacts}
associations={associations.contacts}
sidebarShown={state.sidebarShown}
popout={popout}
permissions={state.permissions}
@ -264,4 +267,4 @@ export class Root extends Component {
}
}
export default Root;
export default Root;

View File

@ -133,6 +133,10 @@ export class PrimaryReducer {
state.notebooks[host][book]["num-notes"] = json[host][book]["num-notes"];
state.notebooks[host][book]["num-unread"] = json[host][book]["num-unread"];
state.notebooks[host][book]["title"] = json[host][book]["title"];
state.notebooks[host][book]["writers-group-path"] =
json[host][book]["writers-group-path"];
state.notebooks[host][book]["subscribers-group-path"] =
json[host][book]["subscribers-group-path"];
}
}