Merge branch 'os1-rc' of https://github.com/urbit/urbit into m/link-meta

This commit is contained in:
Fang 2020-03-04 18:55:29 +01:00
commit 396d13ee1a
No known key found for this signature in database
GPG Key ID: EB035760C1BBA972
14 changed files with 374 additions and 37 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:41dcebff628fa80e316b64e38309b703cc459518e50fc6b845a52569a5d35f10
size 10775767
oid sha256:c530047e7210f68498940374e3f1679a0cf7ae1722d159ca172a7359459a9cdc
size 10870523

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2105b8e617f7e17a9f70f086e6ee30588002ea4cc846a7cb9a371eebef5e2afa
size 13200641
oid sha256:1362758ea72a8dfa41a2a283b8cb881e7603e3aad047344cc2b2a3331cb4d52a
size 13298466

View File

@ -224,13 +224,16 @@
?> ?=(^ app-path.act)
%- zing
:~ :~ (chat-hook-poke [%remove app-path.act])
(metadata-store-poke [%remove group-path [%chat app-path.act]])
(chat-poke [%delete app-path.act])
==
::
?. (is-creator group-path %chat app-path.act) ~
[(metadata-poke [%remove group-path [%chat app-path.act]])]~
::
?: (is-managed group-path) ~
:~ (group-poke [%unbundle group-path])
(metadata-hook-poke [%remove group-path])
(metadata-store-poke [%remove group-path [%chat app-path.act]])
==
==
::
@ -300,7 +303,7 @@
?: (is-managed app-path) (snag 0 app-path)
(snag 1 app-path)
==
:~ (metadata-store-poke [%add group-path [%chat app-path] metadata])
:~ (metadata-poke [%add group-path [%chat app-path] metadata])
(metadata-hook-poke [%add-owned group-path])
==
::
@ -309,6 +312,11 @@
^- card
[%pass / %agent [our.bol %contact-view] %poke %contact-view-action !>(act)]
::
++ metadata-poke
|= act=metadata-action
^- card
[%pass / %agent [our.bol %metadata-hook] %poke %metadata-action !>(act)]
::
++ metadata-store-poke
|= act=metadata-action
^- card
@ -364,6 +372,23 @@
^- ?
?> ?=(^ path)
!=(i.path '~')
::
++ is-creator
|= [group-path=path app-name=@ta app-path=path]
^- ?
=/ =metadata
.^ metadata
%gx
(scot %p our.bol)
%metadata-store
(scot %da now.bol)
%metadata
(scot %t (spat group-path))
app-name
(scot %t (spat app-path))
/noun
==
=(our.bol creator.metadata)
--
::
++ diff-chat-update

File diff suppressed because one or more lines are too long

View File

@ -42,6 +42,9 @@
=^ cards state
(poke-hook-action:hc !<(metadata-hook-action vase))
[cards this]
::
%metadata-action
[(poke-action:hc !<(metadata-action vase)) this]
==
::
++ on-watch
@ -106,6 +109,43 @@
[%pass path %agent [ship %metadata-hook] %leave ~]~
--
::
++ poke-action
|= act=metadata-action
^- (list card)
|^
?: (team:title our.bowl src.bowl)
?- -.act
%add (send group-path.act)
%remove (send group-path.act)
==
?> (is-permitted src.bowl group-path.act)
?- -.act
%add (metadata-poke our.bowl %metadata-store)
%remove (metadata-poke our.bowl %metadata-store)
==
::
++ send
|= =group-path
^- (list card)
=/ =ship
%+ slav %p
?: (is-managed group-path) (snag 0 group-path)
(snag 1 group-path)
=/ app ?:(=(ship our.bowl) %metadata-store %metadata-hook)
(metadata-poke ship app)
::
++ metadata-poke
|= [=ship app=@tas]
^- (list card)
[%pass / %agent [ship app] %poke %metadata-action !>(act)]~
::
++ is-managed
|= =path
^- ?
?> ?=(^ path)
!=(i.path '~')
--
::
++ watch-group
|= =path
^- (list card)
@ -117,17 +157,6 @@
^- card
[%give %fact ~ %metadata-update !>([%add group-path resource metadata])]
::
++ is-permitted
|= [=ship pax=^path]
^- ?
=. pax
;: weld
/=permission-store/(scot %da now.bowl)/permitted
[(scot %p ship) pax]
/noun
==
.^(? %gx pax)
::
++ metadata-scry
|= pax=^path
^- associations
@ -203,4 +232,15 @@
^- (quip card _state)
?> ?=(^ wir)
[~ ?~(saw state state(synced (~(del by synced) t.wir)))]
::
++ is-permitted
|= [=ship pax=path]
^- ?
=. pax
;: weld
/=permission-store/(scot %da now.bowl)/permitted
[(scot %p ship) pax]
/noun
==
.^(? %gx pax)
--

View File

@ -8,7 +8,7 @@
%+ turn ~(tap by associations)
|= [[=group-path =resource] =metadata]
^- [cord json]
:-
:-
%- crip
;: weld
(trip (spat group-path))
@ -22,6 +22,50 @@
[%metadata (metadata-to-json metadata)]
==
::
++ json-to-action
|= jon=json
^- metadata-action
=, dejs:format
=< (parse-json jon)
|%
++ parse-json
%- of
:~ [%add add]
[%remove remove]
==
::
++ add
%- ot
:~ [%group-path pa]
[%resource resource]
[%metadata metadata]
==
++ remove
%- ot
:~ [%group-path pa]
[%resource resource]
==
::
++ nu
|= jon=json
?> ?=({$s *} jon)
(rash p.jon hex)
::
++ metadata
%- ot
:~ [%title so]
[%description so]
[%color nu]
[%date-created (se %da)]
[%creator (su ;~(pfix sig fed:ag))]
==
++ resource
%- ot
:~ [%app-name so]
[%app-path pa]
==
--
::
++ metadata-to-json
|= met=metadata
^- json

View File

@ -0,0 +1,11 @@
/+ *metadata-json
=, dejs:format
|_ act=metadata-action
++ grab
|%
++ noun metadata-action
++ json
|= jon=^json
(json-to-action jon)
--
--

View File

@ -429,9 +429,6 @@
.tr {
text-align: right;
}
.pt1 {
padding-top: 0.25rem;
}
.pb2 {
padding-bottom: 0.5rem;
}
@ -490,7 +487,7 @@
;p:"Urbit ID"
;input(value "{(scow %p our)}", disabled "true", class "mono");
;p:"Access Key"
;p.f9.gray2.pt1
;p.f9.gray2
; Get key from Bridge, or
;span.mono.pr1:"+code"
; in dojo

View File

@ -181,6 +181,30 @@ class UrbitApi {
});
}
metadataAction(data) {
return this.action("metadata-hook", "metadata-action", data);
}
metadataAdd(appPath, groupPath, title, description, dateCreated, color) {
let creator = `~${window.ship}`
return this.metadataAction({
add: {
"group-path": groupPath,
resource: {
"app-path": appPath,
"app-name": "chat"
},
metadata: {
title,
description,
color,
'date-created': dateCreated,
creator
}
}
})
}
sidebarToggle() {
let sidebarBoolean = true;
if (store.state.sidebarShown === true) {

View File

@ -125,15 +125,15 @@ export class Message extends Component {
);
} else {
let chatroom = letter.text.match(
/(~[a-z]{3,6})(-[a-z]{6})?([/])(([a-z])+([/-])?)+/
/([~][/])?(~[a-z]{3,6})(-[a-z]{6})?([/])(([a-z])+([/-])?)+/
);
if ((chatroom !== null) // matched possible chatroom
&& (chatroom[1].length > 2) // possible ship?
&& (urbitOb.isValidPatp(chatroom[1]) // valid patp?
&& (chatroom[2].length > 2) // possible ship?
&& (urbitOb.isValidPatp(chatroom[2]) // valid patp?
&& (chatroom[0] === letter.text))) { // entire message is room name?
return (
<Link
className="bb b--black f7 mono lh-copy v-top"
className="bb b--black b--white-d f7 mono lh-copy v-top"
to={"/~chat/join/" + chatroom.input}>
{letter.text}
</Link>

View File

@ -45,12 +45,13 @@ export class Root extends Component {
state.invites['/chat'] : {};
let contacts = !!state.contacts ? state.contacts : {};
let associations = !!state.associations ? state.associations : new Map;
const renderChannelSidebar = (props, station) => (
<Sidebar
inbox={state.inbox}
messagePreviews={messagePreviews}
associations={state.associations || new Map}
associations={associations}
contacts={contacts}
invites={invites}
unreads={unreads}
@ -152,8 +153,14 @@ export class Root extends Component {
envelopes: []
};
let roomContacts = (station in contacts)
? contacts[station] : {};
let roomContacts = {};
let associatedGroup = ((associations.has(station)) &&
(associations.get(station)["group-path"]))
? associations.get(station)["group-path"] : "";
if ((associations.has(station)) && (associatedGroup in contacts)) {
roomContacts = contacts[associatedGroup]
}
let group = state.groups[station] || new Set([]);
let popout = props.match.url.includes("/popout/");
@ -210,7 +217,7 @@ export class Root extends Component {
spinner={state.spinner}
sidebarShown={state.sidebarShown}
popout={popout}
sidebar={renderChannelSidebar(props)}
sidebar={renderChannelSidebar(props, station)}
>
<MemberScreen
{...props}
@ -240,17 +247,21 @@ export class Root extends Component {
let popout = props.match.url.includes("/popout/");
let association = (associations.has(station))
? associations.get(station) : {};
return (
<Skeleton
sidebarHideOnMobile={true}
spinner={state.spinner}
popout={popout}
sidebarShown={state.sidebarShown}
sidebar={renderChannelSidebar(props)}
sidebar={renderChannelSidebar(props, station)}
>
<SettingsScreen
{...props}
station={station}
association={association}
api={api}
station={station}
group={group}

View File

@ -1,8 +1,7 @@
import React, { Component } from 'react';
import classnames from 'classnames';
import { deSig } from '/lib/util';
import { deSig, uxToHex } from '/lib/util';
import { Route, Link } from "react-router-dom";
import { store } from "/store";
import { ChatTabBar } from '/components/lib/chat-tabbar';
@ -14,10 +13,26 @@ export class SettingsScreen extends Component {
super(props);
this.state = {
isLoading: false
isLoading: false,
title: "",
description: "",
color: ""
};
this.renderDelete = this.renderDelete.bind(this);
this.changeTitle = this.changeTitle.bind(this);
this.changeDescription = this.changeDescription.bind(this);
this.changeColor = this.changeColor.bind(this);
}
componentDidMount() {
if ((this.props.association) && (this.props.association.metadata)) {
this.setState({
title: this.props.association.metadata.title,
description: this.props.association.metadata.description,
color: uxToHex(this.props.association.metadata.color)
});
}
}
componentDidUpdate(prevProps, prevState) {
@ -30,6 +45,26 @@ export class SettingsScreen extends Component {
props.history.push('/~chat');
});
}
if ((this.state.title === "") && (prevProps !== this.props)) {
if ((props.association) && (props.association.metadata))
this.setState({
title: props.association.metadata.title,
description: props.association.metadata.description,
color: uxToHex(props.association.metadata.color)});
}
}
changeTitle() {
this.setState({title: event.target.value})
}
changeDescription() {
this.setState({description: event.target.value});
}
changeColor() {
this.setState({color: event.target.value});
}
deleteChat() {
@ -61,7 +96,7 @@ export class SettingsScreen extends Component {
</div>
<div className={"w-100 fl mt3 " + ((!chatOwner) ? 'o-30' : '')}>
<p className="f8 mt3 lh-copy db">Delete Chat</p>
<p className="f9 gray2 db mb4">Permenantly delete this chat. (All current members will no longer see this chat)</p>
<p className="f9 gray2 db mb4">Permanently delete this chat. All current members will no longer see this chat.</p>
<a onClick={(chatOwner) ? this.deleteChat.bind(this) : null}
className={"dib f9 ba pa2 " + deleteButtonClasses}>Delete this chat</a>
</div>
@ -69,6 +104,124 @@ export class SettingsScreen extends Component {
);
}
renderMetadataSettings() {
const { props, state } = this;
let chatOwner = (deSig(props.match.params.ship) === window.ship);
let association = ((props.association) && (props.association.metadata))
? props.association : {};
return(
<div>
<div className={"w-100 pb6 fl mt3 " + ((chatOwner) ? '' : 'o-30')}>
<p className="f8 mt3 lh-copy">Rename</p>
<p className="f9 gray2 db mb4">Change the name of this chat</p>
<div className="relative w-100 flex"
style={{maxWidth: "29rem"}}>
<input
className={"f8 ba b--gray3 b--gray2-d bg-gray0-d white-d " +
"focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3"}
value={this.state.title}
disabled={!chatOwner}
onChange={this.changeTitle}
/>
<span className={"f8 absolute pa3 inter " +
((chatOwner) ? "pointer" : "")}
style={{ right: 12, top: 1 }}
ref="rename"
onClick={() => {
if (chatOwner) {
props.api.setSpinner(true);
props.api.metadataAdd(
association['app-path'],
association['group-path'],
this.state.title,
association.metadata.description,
association.metadata['date-created'],
uxToHex(association.metadata.color)
).then(() => {
this.refs.rename.innerText = "Saved";
props.api.setSpinner(false);
})
}
}}>
Save
</span>
</div>
<p className="f8 mt3 lh-copy">Change description</p>
<p className="f9 gray2 db mb4">Change the description of this chat</p>
<div className="relative w-100 flex"
style={{ maxWidth: "29rem" }}>
<input
className={"f8 ba b--gray3 b--gray2-d bg-gray0-d white-d " +
"focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3"}
value={this.state.description}
disabled={!chatOwner}
onChange={this.changeDescription}
/>
<span className={"f8 absolute pa3 inter " +
((chatOwner) ? "pointer" : "")}
style={{ right: 12, top: 1 }}
ref="description"
onClick={() => {
if (chatOwner) {
props.api.setSpinner(true);
props.api.metadataAdd(
association['app-path'],
association['group-path'],
association.metadata.title,
this.state.description,
association.metadata['date-created'],
uxToHex(association.metadata.color)
).then(() => {
this.refs.description.innerText = "Saved";
props.api.setSpinner(false);
})
}
}}>
Save
</span>
</div>
<p className="f8 mt3 lh-copy">Change color</p>
<p className="f9 gray2 db mb4">Give this chat a color when viewing group channels</p>
<div className="relative w-100 flex"
style={{ maxWidth: "20rem" }}>
<input
className={"f8 ba b--gray3 b--gray2-d bg-gray0-d white-d " +
"focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3"}
value={this.state.color}
disabled={!chatOwner}
onChange={this.changeColor}
/>
<span className={"f8 absolute pa3 inter " +
((chatOwner) ? "pointer" : "")}
style={{ right: 12, top: 1 }}
ref="color"
onClick={() => {
if ((chatOwner) && (this.state.color.match(/[0-9A-F]{6}/i))) {
props.api.setSpinner(true);
props.api.metadataAdd(
association['app-path'],
association['group-path'],
association.metadata.title,
association.metadata.description,
association.metadata['date-created'],
this.state.color
).then(() => {
this.refs.color.innerText = "Saved";
props.api.setSpinner(false);
})
}
}}>
Save
</span>
</div>
</div>
</div>
)
}
render() {
const { props, state } = this;
const isinPopout = this.props.popout ? "popout/" : "";
@ -148,7 +301,29 @@ export class SettingsScreen extends Component {
</div>
<div className="w-100 pl3 mt4 cf">
<h2 className="f8 pb2">Chat Settings</h2>
<div className="w-100 mt3">
<p className="f8 mt3 lh-copy">Share</p>
<p className="f9 gray2 mb4">Share a shortcode to join this chat</p>
<div className="relative w-100 flex"
style={{ maxWidth: "29rem" }}>
<input
className="f8 mono ba b--gray3 b--gray2-d bg-gray0-d white-d pa3 db w-100 flex-auto mr3"
disabled={true}
value={props.station.substr(1)}
/>
<span className="f8 pointer absolute pa3 inter"
style={{right: 12, top: 1}}
ref="copy"
onClick={() => {
navigator.clipboard.writeText(props.station.substr(1));
this.refs.copy.innerText = "Copied";
}}>
Copy
</span>
</div>
</div>
{this.renderDelete()}
{this.renderMetadataSettings()}
</div>
</div>
);

View File

@ -6,6 +6,7 @@ export class MetadataReducer {
if (data) {
this.associations(data, state);
this.add(data, state);
this.update(data, state);
}
}
@ -29,4 +30,13 @@ export class MetadataReducer {
state.associations = metadata;
}
}
update(json, state) {
let data = _.get(json, 'update-metadata', false);
if (data) {
let metadata = state.associations;
metadata.set(data["app-path"], data);
state.associations = metadata;
}
}
}

View File

@ -50,7 +50,7 @@ export class Root extends Component {
contacts={contacts}
groups={groups}
invites={invites}>
<div className="h-100 w-100 overflow-x-hidden bg-white dn db-ns">
<div className="h-100 w-100 overflow-x-hidden bg-white bg-gray0-d dn db-ns">
<div className="pl3 pr3 pt2 dt pb3 w-100 h-100">
<p className="f9 pt3 gray2 w-100 h-100 dtc v-mid tc">
Select a group to begin.