From d91de5f2769060e81bd46c696f373064a9bf9033 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Sat, 1 Aug 2020 11:11:13 +1000 Subject: [PATCH 01/58] lib-hooks: document with comments --- pkg/arvo/lib/pull-hook.hoon | 38 ++++++++++++++++++++++-- pkg/arvo/lib/push-hook.hoon | 58 +++++++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/lib/pull-hook.hoon b/pkg/arvo/lib/pull-hook.hoon index 6fdbf1007c..19f861f809 100644 --- a/pkg/arvo/lib/pull-hook.hoon +++ b/pkg/arvo/lib/pull-hook.hoon @@ -1,3 +1,24 @@ +:: lib/pull-hook/hoon: helper for creating a push hook +:: +:: lib/pull-hook is a helper for automatically pulling data from a +:: corresponding push-hook to a store. +:: +:: ## Interfacing notes: +:: +:: lib/push-hook provides the inner door with its own separate state. +:: The inner door may interact with the library by producing cards or +:: scrying. Do not pass any cards on a wire beginning with /helper as +:: these wires are reserved by this library. Any watches/pokes/peeks +:: not listed below will be routed to the inner door. +:: +:: ## Subscription paths +:: +:: /tracking: The set of resources we are pulling +:: +:: ## Pokes +:: +:: %pull-hook-action: Add/remove a resource from pulling. +:: /- *pull-hook /+ default-agent, resource :: @@ -5,13 +26,24 @@ |% +$ card card:agent:gall :: +:: $config: configuration for the pull hook +:: +:: .store-name: name of the store to proxy subscriptions to. +:: .update-mark: mark that updates will be tagged with +:: .push-hook-name: name of the corresponding push-hook + +$ config $: store-name=term update=mold update-mark=term push-hook-name=term == +:: +:: $state-0: state for the pull hook :: +:: .tracking: a map of resources we are pulling, and the ships that +:: we are pulling them from. +:: .inner-state: state given to internal door +$ state-0 $: %0 tracking=(map resource ship) @@ -37,7 +69,7 @@ |* config $_ ^| |_ bowl:gall - :: + :: from agent:gall ++ on-init *[(list card) _^|(..on-init)] :: @@ -77,7 +109,9 @@ *[(list card) _^|(..on-init)] :: +on-pull-nack: handle failed pull subscription :: - :: This arm is called when a pull subscription fails. + :: This arm is called when a pull subscription fails. lib/pull-hook + :: will automatically delete the resource from .tracking by the + :: time this arm is called. :: ++ on-pull-nack |~ [resource tang] diff --git a/pkg/arvo/lib/push-hook.hoon b/pkg/arvo/lib/push-hook.hoon index 776aa0f597..e922283534 100644 --- a/pkg/arvo/lib/push-hook.hoon +++ b/pkg/arvo/lib/push-hook.hoon @@ -1,8 +1,42 @@ +:: lib/push-hook/hoon: helper for creating a push hook +:: +:: lib/push-hook is a helper for automatically pushing data from a +:: local store to the corresponding pull-hook on remote ships. It also +:: proxies remote pokes to the store. +:: +:: ## Interfacing notes: +:: +:: lib/push-hook provides the inner door with its own separate state. +:: The inner door may interact with the library by producing cards or +:: scrying. Do not pass any cards on a wire beginning with /helper as +:: these wires are reserved by this library. Any watches/pokes/peeks +:: not listed below will be routed to the inner door. +:: +:: ## Subscription paths +:: +:: /resource/[resource]: Receive initial state and updates to +:: .resource. .resource should be encoded with de-path:resource from +:: /lib/resource. Facts on this path will be of mark +:: update-mark.config +:: +:: ## Pokes +:: +:: %push-hook-action: Add/remove a resource from pushing. +:: [update-mark.config]: A poke to proxy to the local store +:: /- *push-hook /+ default-agent, resource |% +$ card card:agent:gall :: +:: $config: configuration for the push hook +:: +:: .store-name: name of the store to proxy pokes and +:: subscriptions to +:: .store-path: subscription path to receive updates on +:: .update-mark: mark that updates will be tagged with +:: .pull-hook-name: name of the corresponding pull-hook +:: +$ config $: store-name=term store-path=path @@ -10,6 +44,12 @@ update-mark=term pull-hook-name=term == +:: +:: $state-0: state for the push hook +:: +:: .sharing: resources that the push hook is proxying +:: .inner-state: state given to internal door +:: +$ state-0 $: %0 sharing=(set resource) @@ -20,6 +60,7 @@ |* =config $_ ^| |_ bowl:gall + :: from agent:gall :: ++ on-init *[(list card) _^|(..on-init)] @@ -58,14 +99,21 @@ ++ on-fail |~ [term tang] *[(list card) _^|(..on-init)] + :: :: +resource-for-update: get affected resource from an update + :: + :: Given a vase of the update, the mark of which is + :: update-mark.config, produce the affected resource, if any. + :: ++ resource-for-update |~ vase *(unit resource) :: :: +on-update: handle update from store :: - :: Do extra stuff on store update + :: Given an update from the store, do other things after proxying + :: the update + :: ++ take-update |~ vase *[(list card) _^|(..on-init)] @@ -81,7 +129,13 @@ :: +initial-watch: produce initial state for a subscription :: :: .resource is the resource being subscribed to. - :: .path is any additional information in the subscription wire + :: .path is any additional information in the subscription wire. + :: This would typically be used to encode state that the subscriber + :: already has. For example, a chat client might encode + :: the number of messages that it already has, or the date it last + :: received an update. + :: + :: If +initial-watch crashes, the subscription fails. :: ++ initial-watch |~ [path resource] From 531d53ddfc2b52512544f5206af47f8d28441a91 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 5 Aug 2020 13:55:12 +1000 Subject: [PATCH 02/58] lib-hooks: address mark review --- pkg/arvo/lib/pull-hook.hoon | 57 ++++++++++++------------ pkg/arvo/lib/push-hook.hoon | 88 ++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 72 deletions(-) diff --git a/pkg/arvo/lib/pull-hook.hoon b/pkg/arvo/lib/pull-hook.hoon index 19f861f809..5afd0275d7 100644 --- a/pkg/arvo/lib/pull-hook.hoon +++ b/pkg/arvo/lib/pull-hook.hoon @@ -1,11 +1,10 @@ -:: lib/pull-hook/hoon: helper for creating a push hook +:: lib/pull-hook: helper for creating a push hook :: :: lib/pull-hook is a helper for automatically pulling data from a :: corresponding push-hook to a store. :: :: ## Interfacing notes: :: -:: lib/push-hook provides the inner door with its own separate state. :: The inner door may interact with the library by producing cards or :: scrying. Do not pass any cards on a wire beginning with /helper as :: these wires are reserved by this library. Any watches/pokes/peeks @@ -28,10 +27,10 @@ :: :: $config: configuration for the pull hook :: -:: .store-name: name of the store to proxy subscriptions to. +:: .store-name: name of the store to send subscription updates to. :: .update-mark: mark that updates will be tagged with :: .push-hook-name: name of the corresponding push-hook - +:: +$ config $: store-name=term update=mold @@ -44,6 +43,7 @@ :: .tracking: a map of resources we are pulling, and the ships that :: we are pulling them from. :: .inner-state: state given to internal door +:: +$ state-0 $: %0 tracking=(map resource ship) @@ -69,6 +69,28 @@ |* config $_ ^| |_ bowl:gall + :: +on-pull-nack: handle failed pull subscription + :: + :: This arm is called when a pull subscription fails. lib/pull-hook + :: will automatically delete the resource from .tracking by the + :: time this arm is called. + :: + ++ on-pull-nack + |~ [resource tang] + *[(list card) _^|(..on-init)] + :: +on-pull-kick: produce any additional resubscribe path + :: + :: If non-null, the produced path is appended to the original + :: subscription path. This should be used to encode extra + :: information onto the path in order to reduce the payload of a + :: kick and resubscribe. + :: + :: If null, a resubscribe is not attempted + :: + ++ on-pull-kick + |~ resource + *(unit path) + :: :: from agent:gall ++ on-init *[(list card) _^|(..on-init)] @@ -107,28 +129,6 @@ ++ on-fail |~ [term tang] *[(list card) _^|(..on-init)] - :: +on-pull-nack: handle failed pull subscription - :: - :: This arm is called when a pull subscription fails. lib/pull-hook - :: will automatically delete the resource from .tracking by the - :: time this arm is called. - :: - ++ on-pull-nack - |~ [resource tang] - *[(list card) _^|(..on-init)] - :: +on-pull-kick: produce any additional resubscribe path - :: - :: If non-null, the produced path is appended to the original - :: subscription path. This should be used to encode extra - :: information onto the path in order to reduce the payload of a - :: kick and resubscribe. - :: - :: If null, a resubscribe is not attempted - :: - ++ on-pull-kick - |~ resource - *(unit path) - :: :: -- ++ agent |* =config @@ -243,7 +243,10 @@ =^ cards pull-hook (on-fail:og term tang) [cards this] - ++ on-peek on-peek:def + ++ on-peek + |= =path + ^- (unit (unit cage)) + (on-peek:og path) -- |_ =bowl:gall +* og ~(. pull-hook bowl) diff --git a/pkg/arvo/lib/push-hook.hoon b/pkg/arvo/lib/push-hook.hoon index e922283534..1ddc07a76a 100644 --- a/pkg/arvo/lib/push-hook.hoon +++ b/pkg/arvo/lib/push-hook.hoon @@ -1,4 +1,4 @@ -:: lib/push-hook/hoon: helper for creating a push hook +:: lib/push-hook: helper for creating a push hook :: :: lib/push-hook is a helper for automatically pushing data from a :: local store to the corresponding pull-hook on remote ships. It also @@ -6,7 +6,6 @@ :: :: ## Interfacing notes: :: -:: lib/push-hook provides the inner door with its own separate state. :: The inner door may interact with the library by producing cards or :: scrying. Do not pass any cards on a wire beginning with /helper as :: these wires are reserved by this library. Any watches/pokes/peeks @@ -15,7 +14,7 @@ :: ## Subscription paths :: :: /resource/[resource]: Receive initial state and updates to -:: .resource. .resource should be encoded with de-path:resource from +:: .resource. .resource should be encoded with en-path:resource from :: /lib/resource. Facts on this path will be of mark :: update-mark.config :: @@ -60,6 +59,47 @@ |* =config $_ ^| |_ bowl:gall + :: + :: +resource-for-update: get affected resource from an update + :: + :: Given a vase of the update, the mark of which is + :: update-mark.config, produce the affected resource, if any. + :: + ++ resource-for-update + |~ vase + *(unit resource) + :: + :: +take-update: handle update from store + :: + :: Given an update from the store, do other things after proxying + :: the update + :: + ++ take-update + |~ vase + *[(list card) _^|(..on-init)] + :: +should-proxy-update: should forward update to store + :: + :: If %.y is produced, then the update is forwarded to the local + :: store. If %.n is produced then the update is not forwarded and + :: the poke fails. + :: + ++ should-proxy-update + |~ vase + *? + :: +initial-watch: produce initial state for a subscription + :: + :: .resource is the resource being subscribed to. + :: .path is any additional information in the subscription wire. + :: This would typically be used to encode state that the subscriber + :: already has. For example, a chat client might encode + :: the number of messages that it already has, or the date it last + :: received an update. + :: + :: If +initial-watch crashes, the subscription fails. + :: + ++ initial-watch + |~ [path resource] + *vase :: from agent:gall :: ++ on-init @@ -99,48 +139,6 @@ ++ on-fail |~ [term tang] *[(list card) _^|(..on-init)] - :: - :: +resource-for-update: get affected resource from an update - :: - :: Given a vase of the update, the mark of which is - :: update-mark.config, produce the affected resource, if any. - :: - ++ resource-for-update - |~ vase - *(unit resource) - :: - :: +on-update: handle update from store - :: - :: Given an update from the store, do other things after proxying - :: the update - :: - ++ take-update - |~ vase - *[(list card) _^|(..on-init)] - :: +should-proxy-update: should forward update to store - :: - :: If %.y is produced, then the update is forwarded to the local - :: store. If %.n is produced then the update is not forwarded and - :: the poke fails. - :: - ++ should-proxy-update - |~ vase - *? - :: +initial-watch: produce initial state for a subscription - :: - :: .resource is the resource being subscribed to. - :: .path is any additional information in the subscription wire. - :: This would typically be used to encode state that the subscriber - :: already has. For example, a chat client might encode - :: the number of messages that it already has, or the date it last - :: received an update. - :: - :: If +initial-watch crashes, the subscription fails. - :: - ++ initial-watch - |~ [path resource] - *vase - :: -- ++ agent |* =config From f1fd99a8987e021e8e1a491de2793d8d6c61d0e0 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Wed, 5 Aug 2020 12:27:48 -0400 Subject: [PATCH 03/58] links: fix direct loading of link entry If you go directly to a link's page, it will never load, because we don't look for 'link-update' in our data, post-global store. This checks properly. --- pkg/interface/src/api/links.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interface/src/api/links.ts b/pkg/interface/src/api/links.ts index de4af1e904..c6ce04e9e6 100644 --- a/pkg/interface/src/api/links.ts +++ b/pkg/interface/src/api/links.ts @@ -44,8 +44,8 @@ export default class LinksApi extends BaseApi { this.fetchLink( endpoint, (res) => { - if (res.data.submission) { - callback(res.data.submission); + if (res.data?.['link-update']?.submission) { + callback(res.data?.['link-update']?.submission); } else { console.error('unexpected submission response', res); } From d2579b16583d338ee8685681559f9f818b8ddd2b Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Fri, 14 Aug 2020 16:25:08 -0400 Subject: [PATCH 04/58] links: remove members page --- pkg/interface/src/views/apps/links/app.js | 51 +----------- .../links/components/lib/invite-element.js | 78 ------------------- .../apps/links/components/lib/links-tabbar.js | 20 +---- .../src/views/apps/links/components/member.js | 70 ----------------- 4 files changed, 3 insertions(+), 216 deletions(-) delete mode 100644 pkg/interface/src/views/apps/links/components/lib/invite-element.js delete mode 100644 pkg/interface/src/views/apps/links/components/member.js diff --git a/pkg/interface/src/views/apps/links/app.js b/pkg/interface/src/views/apps/links/app.js index baa7629d8a..e184aa7c0b 100644 --- a/pkg/interface/src/views/apps/links/app.js +++ b/pkg/interface/src/views/apps/links/app.js @@ -7,7 +7,6 @@ import './css/custom.css'; import { Skeleton } from './components/skeleton'; import { NewScreen } from './components/new'; -import { MemberScreen } from './components/member'; import { SettingsScreen } from './components/settings'; import { MessageScreen } from './components/lib/message-screen'; import { Links } from './components/links-list'; @@ -18,7 +17,6 @@ import { base64urlDecode } from '../../../logic/lib/util'; - export class LinksApp extends Component { constructor(props) { super(props); @@ -41,7 +39,6 @@ export class LinksApp extends Component { this.props.subscription.stopApp('link'); } - render() { const { props } = this; @@ -69,7 +66,6 @@ export class LinksApp extends Component { const invites = props.invites ? props.invites : {}; - const listening = props.linkListening; const { api, sidebarShown } = this.props; @@ -133,46 +129,6 @@ export class LinksApp extends Component { autoJoin(); }} /> - { - const popout = props.match.url.includes('/popout/'); - const resourcePath = '/' + props.match.params.resource; - const resource = associations.link[resourcePath] || { metadata: {} }; - - const contactDetails = contacts[resource['group-path']] || {}; - const group = groups[resource['group-path']] || new Set([]); - const amOwner = amOwnerOfGroup(resource['group-path']); - - return ( - - - - ); - }} - /> { const popout = props.match.url.includes('/popout/'); @@ -283,11 +239,8 @@ export class LinksApp extends Component { const page = props.match.params.page || 0; const url = base64urlDecode(props.match.params.encodedUrl); - const data = links[resourcePath] - ? links[resourcePath][page] - ? links[resourcePath][page][index] - : {} - : {}; + const data = links?.[resourcePath]?.[page]?.[index] || {}; + const coms = !comments[resourcePath] ? undefined : comments[resourcePath][url]; diff --git a/pkg/interface/src/views/apps/links/components/lib/invite-element.js b/pkg/interface/src/views/apps/links/components/lib/invite-element.js deleted file mode 100644 index 94da5d5752..0000000000 --- a/pkg/interface/src/views/apps/links/components/lib/invite-element.js +++ /dev/null @@ -1,78 +0,0 @@ -import React, { Component } from 'react'; -import { InviteSearch } from '../../../../components/InviteSearch'; -import { Spinner } from '../../../../components/Spinner'; - -export class InviteElement extends Component { - constructor(props) { - super(props); - this.state = { - members: [], - error: false, - success: false, - awaiting: false - }; - this.setInvite = this.setInvite.bind(this); - } - - modifyMembers() { - const { props, state } = this; - - const aud = state.members.map(mem => `~${mem}`); - - if (state.members.length === 0) { - this.setState({ - error: true, - success: false - }); - return; - } - - this.setState({ awaiting: true }); - - this.setState({ - error: false, - success: true, - members: [] - }, () => { - props.api.links.inviteToCollection(props.resourcePath, aud).then(() => { - this.setState({ awaiting: false }); - }); - }); - } - - setInvite(invite) { - this.setState({ members: invite.ships }); - } - - render() { - const { props, state } = this; - - let modifyButtonClasses = 'mt4 db f9 ba pa2 white-d bg-gray0-d b--black b--gray2-d pointer'; - if (state.error) { - modifyButtonClasses = modifyButtonClasses + ' gray3'; - } - - return ( -
- - - -
- ); - } -} diff --git a/pkg/interface/src/views/apps/links/components/lib/links-tabbar.js b/pkg/interface/src/views/apps/links/components/lib/links-tabbar.js index 31ed9833c8..9c46ffc919 100644 --- a/pkg/interface/src/views/apps/links/components/lib/links-tabbar.js +++ b/pkg/interface/src/views/apps/links/components/lib/links-tabbar.js @@ -6,17 +6,11 @@ export class LinksTabBar extends Component { render() { const props = this.props; - let memColor = '', - setColor = ''; + let setColor = ''; if (props.location.pathname.includes('/settings')) { - memColor = 'gray3'; setColor = 'black white-d'; - } else if (props.location.pathname.includes('/members')) { - memColor = 'black white-d'; - setColor = 'gray3'; } else { - memColor = 'gray3'; setColor = 'gray3'; } @@ -26,18 +20,6 @@ export class LinksTabBar extends Component { return (
- {props.amOwner ? ( -
- - Members - -
- ) : ( -
- )}
; - } - - return ( -
-
- {'⟵ All Collections'} -
-
- - -

- {props.resource.metadata.title} -

- - -
-
- -
-
- ); - } -} From 6046936bef68af494fac64d13bed4df283c4da2c Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Fri, 14 Aug 2020 16:42:17 -0400 Subject: [PATCH 05/58] links: simplify comment-item component --- .../apps/links/components/lib/comment-item.js | 33 ++++++++----------- .../apps/links/components/lib/comments.js | 6 ++-- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/pkg/interface/src/views/apps/links/components/lib/comment-item.js b/pkg/interface/src/views/apps/links/components/lib/comment-item.js index 3ef26e5fd0..3ac005a11a 100644 --- a/pkg/interface/src/views/apps/links/components/lib/comment-item.js +++ b/pkg/interface/src/views/apps/links/components/lib/comment-item.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import { Sigil } from '../../../../../logic/lib/sigil'; import { cite } from '../../../../../logic/lib/util'; import moment from 'moment'; +import { Box, Text, Row } from '@tlon/indigo-react'; export class CommentItem extends Component { constructor(props) { @@ -33,36 +34,30 @@ export class CommentItem extends Component { render() { const props = this.props; - const member = props.member || false; - - const pending = props.pending ? 'o-60' : ''; - const img = (props.avatar) ? : ; return ( -
-
- {img} -

- + + + {img} + + {props.nickname ? props.nickname : cite(props.ship)} - - + + {this.state.timeSinceComment} - -

-
-

{props.content}

-
+ + + + {props.content} + ); } } diff --git a/pkg/interface/src/views/apps/links/components/lib/comments.js b/pkg/interface/src/views/apps/links/components/lib/comments.js index a62c2074f4..c81207b04d 100644 --- a/pkg/interface/src/views/apps/links/components/lib/comments.js +++ b/pkg/interface/src/views/apps/links/components/lib/comments.js @@ -51,8 +51,6 @@ export class Comments extends Component { const { nickname, color, member, avatar } = getContactDetails(contacts[ship]); - const nameClass = nickname ? 'inter' : 'mono'; - return( ); }); From ecfcb55c17cba20622ef00bb289add435abf5061 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Wed, 19 Aug 2020 21:03:01 -0400 Subject: [PATCH 06/58] interface: componentise metadata settings --- .../views/apps/chat/components/settings.js | 12 ++++---- .../metadata/color.js} | 6 +--- .../metadata/input.js} | 0 .../metadata/settings.js} | 28 ++++++++++--------- 4 files changed, 21 insertions(+), 25 deletions(-) rename pkg/interface/src/views/{apps/chat/components/lib/metadata-color.js => components/metadata/color.js} (92%) rename pkg/interface/src/views/{apps/chat/components/lib/metadata-input.js => components/metadata/input.js} (100%) rename pkg/interface/src/views/{apps/chat/components/lib/metadata-settings.js => components/metadata/settings.js} (81%) diff --git a/pkg/interface/src/views/apps/chat/components/settings.js b/pkg/interface/src/views/apps/chat/components/settings.js index 9b1b339367..cdb22f5b5f 100644 --- a/pkg/interface/src/views/apps/chat/components/settings.js +++ b/pkg/interface/src/views/apps/chat/components/settings.js @@ -1,15 +1,11 @@ import React, { Component, Fragment } from 'react'; import { deSig } from '~/logic/lib/util'; -import { Link } from 'react-router-dom'; import { ChatHeader } from './lib/chat-header'; -import { MetadataSettings } from './lib/metadata-settings'; +import { MetadataSettings } from '~/views/components/metadata/settings'; import { DeleteButton } from './lib/delete-button'; import { GroupifyButton } from './lib/groupify-button'; import { Spinner } from '~/views/components/Spinner'; -import { ChatTabBar } from './lib/chat-tabbar'; -import SidebarSwitcher from '~/views/components/SidebarSwitch'; - export class SettingsScreen extends Component { constructor(props) { @@ -95,6 +91,8 @@ export class SettingsScreen extends Component { changeLoading={this.changeLoading} api={api} association={association} + resource="chat" + app="chat" station={station} /> -

Change color

-

Give this chat a color when viewing group channels

+

Give this {props.resource} a color when viewing group channels

diff --git a/pkg/interface/src/views/apps/chat/components/lib/metadata-input.js b/pkg/interface/src/views/components/metadata/input.js similarity index 100% rename from pkg/interface/src/views/apps/chat/components/lib/metadata-input.js rename to pkg/interface/src/views/components/metadata/input.js diff --git a/pkg/interface/src/views/apps/chat/components/lib/metadata-settings.js b/pkg/interface/src/views/components/metadata/settings.js similarity index 81% rename from pkg/interface/src/views/apps/chat/components/lib/metadata-settings.js rename to pkg/interface/src/views/components/metadata/settings.js index 942135cfcc..d8b6adf329 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/metadata-settings.js +++ b/pkg/interface/src/views/components/metadata/settings.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; -import { MetadataColor } from './metadata-color'; -import { MetadataInput } from './metadata-input'; +import { MetadataColor } from './color'; +import { MetadataInput } from './input'; import { uxToHex } from '~/logic/lib/util'; @@ -11,13 +11,14 @@ export const MetadataSettings = (props) => { association, changeLoading, api, - station + resource, + app } = props; - const title = + const title = (props.association && 'metadata' in props.association) ? association.metadata.title : ''; - const description = + const description = (props.association && 'metadata' in props.association) ? association.metadata.description : ''; const color = @@ -28,13 +29,13 @@ export const MetadataSettings = (props) => {
{ - changeLoading(false, true, 'Editing chat...', () => { + changeLoading(false, true, `Editing ${resource}...`, () => { api.metadata.metadataAdd( - 'chat', + app, association['app-path'], association['group-path'], val, @@ -48,13 +49,13 @@ export const MetadataSettings = (props) => { }} /> { changeLoading(false, true, 'Editing chat...', () => { api.metadata.metadataAdd( - 'chat', + app, association['app-path'], association['group-path'], association.metadata.title, @@ -67,12 +68,13 @@ export const MetadataSettings = (props) => { }); }} /> { - changeLoading(false, true, 'Editing chat...', () => { + changeLoading(false, true, `Editing ${resource}...`, () => { props.api.metadata.metadataAdd( - 'chat', + app, association['app-path'], association['group-path'], association.metadata.title, From 0dbd879443b325cac7764af94fdbb66c3a0c535a Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Wed, 19 Aug 2020 21:17:33 -0400 Subject: [PATCH 07/58] links: use componentised metadata --- .../views/apps/chat/components/settings.js | 2 +- .../views/apps/links/components/settings.js | 205 ++---------------- .../src/views/components/metadata/settings.js | 4 +- 3 files changed, 27 insertions(+), 184 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/components/settings.js b/pkg/interface/src/views/apps/chat/components/settings.js index cdb22f5b5f..c450b9e794 100644 --- a/pkg/interface/src/views/apps/chat/components/settings.js +++ b/pkg/interface/src/views/apps/chat/components/settings.js @@ -93,7 +93,7 @@ export class SettingsScreen extends Component { association={association} resource="chat" app="chat" - station={station} /> + /> { - this.setState({ disabled: false }); - }); - } - } + changeLoading(isLoading, awaiting, type, closure) { + this.setState({ + isLoading, + awaiting, + type + }, closure); } removeCollection() { @@ -115,7 +50,7 @@ export class SettingsScreen extends Component { this.setState({ isLoading: true, - disabled: true, + awaiting: true, type: 'Removing' }); props.api.links.removeCollection(props.resourcePath) @@ -131,7 +66,7 @@ export class SettingsScreen extends Component { this.setState({ isLoading: true, - disabled: true, + awaiting: true, type: 'Deleting' }); props.api.links.deleteCollection(props.resourcePath) @@ -175,7 +110,7 @@ export class SettingsScreen extends Component { Delete this collection, for you and all group members.

Delete collection @@ -184,105 +119,6 @@ export class SettingsScreen extends Component { } } - renderMetadataSettings() { - const { props, state } = this; - const { resource } = props; - - if (!('metadata' in resource)) { - resource.metadata = {}; - } - - return( -
-
-

Rename

-

Change the name of this collection

-
- { - if (props.amOwner) { - this.setState({ disabled: true }); - props.api.metadata.metadataAdd( - 'link', - props.resourcePath, - props.groupPath, - state.title, - resource.metadata.description, - resource.metadata['date-created'], - uxToHex(resource.metadata.color) - ).then(() => { - this.setState({ disabled: false }); - }); - } - }} - /> -
-

Change description

-

- Change the description of this collection -

-
- { - if (props.amOwner) { - this.setState({ disabled: true }); - props.api.metadata.metadataAdd( - 'link', - props.resourcePath, - props.groupPath, - resource.metadata.title, - state.description, - resource.metadata['date-created'], - uxToHex(resource.metadata.color) - ).then(() => { - this.setState({ disabled: false }); - }); - } - }} - /> -
-

Change color

-

Give this collection a color when viewing group channels

-
-
- -
-
-
- ); - } - render() { const { props, state } = this; @@ -367,11 +203,18 @@ export class SettingsScreen extends Component { {this.renderRemove()} {this.renderDelete()} - {this.renderMetadataSettings()} +
diff --git a/pkg/interface/src/views/components/metadata/settings.js b/pkg/interface/src/views/components/metadata/settings.js index d8b6adf329..86c64d66eb 100644 --- a/pkg/interface/src/views/components/metadata/settings.js +++ b/pkg/interface/src/views/components/metadata/settings.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React from 'react'; import { MetadataColor } from './color'; import { MetadataInput } from './input'; @@ -53,7 +53,7 @@ export const MetadataSettings = (props) => { isDisabled={!isOwner} initialValue={description} setValue={(val) => { - changeLoading(false, true, 'Editing chat...', () => { + changeLoading(false, true, `Editing ${resource}...`, () => { api.metadata.metadataAdd( app, association['app-path'], From 1fd147f6cb89cda5495c4524151303d58514dda5 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Wed, 19 Aug 2020 21:37:20 -0400 Subject: [PATCH 08/58] chat, links: componentise tabBar --- .../apps/chat/components/lib/chat-header.js | 53 ++++++++++--------- .../apps/links/components/lib/links-tabbar.js | 48 ----------------- .../src/views/apps/links/components/link.js | 9 +++- .../chat-link-tabbar.js} | 13 ++--- 4 files changed, 42 insertions(+), 81 deletions(-) delete mode 100644 pkg/interface/src/views/apps/links/components/lib/links-tabbar.js rename pkg/interface/src/views/{apps/chat/components/lib/chat-tabbar.js => components/chat-link-tabbar.js} (78%) diff --git a/pkg/interface/src/views/apps/chat/components/lib/chat-header.js b/pkg/interface/src/views/apps/chat/components/lib/chat-header.js index df43d08ac6..ab63978f26 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/chat-header.js +++ b/pkg/interface/src/views/apps/chat/components/lib/chat-header.js @@ -1,58 +1,61 @@ -import React, { Component, Fragment } from "react"; -import { Link } from "react-router-dom"; - -import { ChatTabBar } from "./chat-tabbar"; -import { SidebarSwitcher } from "~/views/components/SidebarSwitch"; -import { deSig } from "~/logic/lib/util"; +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import { TabBar } from '~/views/components/chat-link-tabbar'; +import { SidebarSwitcher } from '~/views/components/SidebarSwitch'; +import { deSig } from '~/logic/lib/util'; export const ChatHeader = (props) => { - const isInPopout = props.popout ? "popout/" : ""; + const isInPopout = props.popout ? 'popout/' : ''; const group = Array.from(props.group.members); let title = props.station.substr(1); - if (props.association && - "metadata" in props.association && - props.association.metadata.tile !== "") { - title = props.association.metadata.title + if (props.association && + 'metadata' in props.association && + props.association.metadata.tile !== '') { + title = props.association.metadata.title; } return (
- {"⟵ All Chats"} + style={{ height: '1rem' }} + > + {'⟵ All Chats'}
+ style={{ height: 48 }} + > + to={'/~chat/' + isInPopout + 'room' + props.station} + className="pt2 white-d" + >

+ style={{ width: 'max-content' }} + > {title}

-
); -} +}; diff --git a/pkg/interface/src/views/apps/links/components/lib/links-tabbar.js b/pkg/interface/src/views/apps/links/components/lib/links-tabbar.js deleted file mode 100644 index bc6664a08d..0000000000 --- a/pkg/interface/src/views/apps/links/components/lib/links-tabbar.js +++ /dev/null @@ -1,48 +0,0 @@ -import React, { Component } from 'react'; -import { Link } from 'react-router-dom'; -import { makeRoutePath } from '~/logic/lib/util'; - -export class LinksTabBar extends Component { - render() { - const props = this.props; - - let setColor = ''; - - if (props.location.pathname.includes('/settings')) { - setColor = 'black white-d'; - } else { - setColor = 'gray3'; - } - - const hidePopoutIcon = (props.popout) - ? 'dn-m dn-l dn-xl' - : 'dib-m dib-l dib-xl'; - - return ( -
-
- - Settings - -
- - - -
- ); - } -} - -export default LinksTabBar; diff --git a/pkg/interface/src/views/apps/links/components/link.js b/pkg/interface/src/views/apps/links/components/link.js index a9e1c57db8..bf4ba15057 100644 --- a/pkg/interface/src/views/apps/links/components/link.js +++ b/pkg/interface/src/views/apps/links/components/link.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { LinksTabBar } from './lib/links-tabbar'; +import { TabBar } from '~/views/components/chat-link-tabbar'; import { LinkPreview } from './lib/link-detail-preview'; import { SidebarSwitcher } from '~/views/components/SidebarSwitch'; import { Link } from 'react-router-dom'; @@ -147,7 +147,12 @@ export class LinkDetail extends Component { > {`<- ${props.resource.metadata.title}`} - +
diff --git a/pkg/interface/src/views/apps/chat/components/lib/chat-tabbar.js b/pkg/interface/src/views/components/chat-link-tabbar.js similarity index 78% rename from pkg/interface/src/views/apps/chat/components/lib/chat-tabbar.js rename to pkg/interface/src/views/components/chat-link-tabbar.js index 69df556d31..da6e48dff7 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/chat-tabbar.js +++ b/pkg/interface/src/views/components/chat-link-tabbar.js @@ -1,10 +1,11 @@ -import React, { Component } from 'react'; +import React from 'react'; import { Link } from 'react-router-dom'; -export const ChatTabBar = (props) => { +export const TabBar = (props) => { const { location, - station + settings, + popoutHref } = props; let setColor = '', popout = ''; @@ -22,11 +23,11 @@ export const ChatTabBar = (props) => {
+ to={settings}> Settings
- @@ -38,4 +39,4 @@ export const ChatTabBar = (props) => {
); -} +}; From ffadf5718dbad49e31b574433f015783b9c250a1 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Wed, 19 Aug 2020 21:44:45 -0400 Subject: [PATCH 09/58] links: use tabbar in links-list, settings --- .../views/apps/links/components/links-list.js | 12 ++++++------ .../views/apps/links/components/settings.js | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/pkg/interface/src/views/apps/links/components/links-list.js b/pkg/interface/src/views/apps/links/components/links-list.js index 577b3ee057..822b558af3 100644 --- a/pkg/interface/src/views/apps/links/components/links-list.js +++ b/pkg/interface/src/views/apps/links/components/links-list.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import { LoadingScreen } from './loading'; import { MessageScreen } from './lib/message-screen'; -import { LinksTabBar } from './lib/links-tabbar'; +import { TabBar } from '~/views/components/chat-link-tabbar'; import { SidebarSwitcher } from '~/views/components/SidebarSwitch'; import { Link } from 'react-router-dom'; import { LinkItem } from './lib/link-item'; @@ -127,11 +127,11 @@ export class Links extends Component { {props.resource.metadata.title} -
diff --git a/pkg/interface/src/views/apps/links/components/settings.js b/pkg/interface/src/views/apps/links/components/settings.js index d0f0517f74..cde12519d0 100644 --- a/pkg/interface/src/views/apps/links/components/settings.js +++ b/pkg/interface/src/views/apps/links/components/settings.js @@ -5,7 +5,7 @@ import { Link } from 'react-router-dom'; import { LoadingScreen } from './loading'; import { Spinner } from '~/views/components/Spinner'; -import { LinksTabBar } from './lib/links-tabbar'; +import { TabBar } from '~/views/components/chat-link-tabbar'; import SidebarSwitcher from '~/views/components/SidebarSwitch'; import { MetadataSettings } from '~/views/components/metadata/settings'; @@ -154,7 +154,12 @@ export class SettingsScreen extends Component { {props.resource.metadata.title} - +

Removing...

@@ -190,8 +195,13 @@ export class SettingsScreen extends Component { {props.resource.metadata.title} - -
+ +

Collection Settings

Mark all links as read

From c383d31c24f75a00fd0acb50fb8d4dfde37a1450 Mon Sep 17 00:00:00 2001 From: Tyler Brown Cifu Shuster Date: Fri, 21 Aug 2020 16:14:10 -0700 Subject: [PATCH 10/58] chat: updated Leave Group copy --- .../apps/chat/components/lib/delete-button.js | 97 ++++++++++--------- .../views/apps/chat/components/settings.js | 2 + 2 files changed, 52 insertions(+), 47 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/components/lib/delete-button.js b/pkg/interface/src/views/apps/chat/components/lib/delete-button.js index cb7b75ae75..1abb19f7e9 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/delete-button.js +++ b/pkg/interface/src/views/apps/chat/components/lib/delete-button.js @@ -1,51 +1,54 @@ -import React, { Component } from 'react'; +import React, { memo } from 'react'; +export const DeleteButton = memo(({ isOwner, station, changeLoading, association, contacts, api }) => { + const leaveButtonClasses = (!isOwner) ? 'pointer' : 'c-default'; + const deleteButtonClasses = (isOwner) ? + 'b--red2 red2 pointer bg-gray0-d' : + 'b--gray3 gray3 bg-gray0-d c-default'; -export const DeleteButton = (props) => { - const { isOwner, station, changeLoading, api } = props; - const leaveButtonClasses = (!isOwner) ? 'pointer' : 'c-default'; - const deleteButtonClasses = (isOwner) ? - 'b--red2 red2 pointer bg-gray0-d' : - 'b--gray3 gray3 bg-gray0-d c-default'; - - const deleteChat = () => { - changeLoading( - true, - true, - isOwner ? 'Deleting chat...' : 'Leaving chat...', - () => { - api.chat.delete(station); - } - ); - }; - - return ( -
-
-

Leave Chat

-

- Remove this chat from your chat list.{' '} - You will need to request for access again. -

- - Leave this chat - -
-
-

Delete Chat

-

- Permanently delete this chat.{' '} - All current members will no longer see this chat. -

- Delete this chat -
-
+ const deleteChat = () => { + changeLoading( + true, + true, + isOwner ? 'Deleting chat...' : 'Leaving chat...', + () => { + api.chat.delete(station); + } ); -}; + }; + const groupPath = association['group-path']; + const unmanagedVillage = !contacts[groupPath]; + + return ( +
+
+

Leave Chat

+

+ Remove this chat from your chat list.{' '} + {unmanagedVillage + ? 'You will need to request for access again' + : 'You will need to join again from the group page.' + } +

+ + Leave this chat + +
+
+

Delete Chat

+

+ Permanently delete this chat.{' '} + All current members will no longer see this chat. +

+ Delete this chat +
+
+ ); +}) \ No newline at end of file diff --git a/pkg/interface/src/views/apps/chat/components/settings.js b/pkg/interface/src/views/apps/chat/components/settings.js index 9b1b339367..6250ef7861 100644 --- a/pkg/interface/src/views/apps/chat/components/settings.js +++ b/pkg/interface/src/views/apps/chat/components/settings.js @@ -89,6 +89,8 @@ export class SettingsScreen extends Component { isOwner={isOwner} changeLoading={this.changeLoading} station={station} + association={association} + contacts={contacts} api={api} /> Date: Thu, 27 Aug 2020 16:18:10 +0200 Subject: [PATCH 11/58] lib: take json as argument to server json-response No reason conversion to octs has to happen outside of this function. --- pkg/arvo/app/chat-view.hoon | 1 - pkg/arvo/app/dbug.hoon | 4 +--- pkg/arvo/app/language-server.hoon | 2 +- pkg/arvo/app/lens.hoon | 4 ++-- pkg/arvo/app/publish.hoon | 7 ++----- pkg/arvo/lib/server.hoon | 4 ++-- 6 files changed, 8 insertions(+), 14 deletions(-) diff --git a/pkg/arvo/app/chat-view.hoon b/pkg/arvo/app/chat-view.hoon index 15b7bdf403..5f0bfb18a3 100644 --- a/pkg/arvo/app/chat-view.hoon +++ b/pkg/arvo/app/chat-view.hoon @@ -193,7 +193,6 @@ =/ pax t.t.t.t.site.url =/ envelopes (envelope-scry [(scot %ud start) (scot %ud end) pax]) %- json-response:gen - %- json-to-octs %- update:enjs:store [%messages pax start end envelopes] == diff --git a/pkg/arvo/app/dbug.hoon b/pkg/arvo/app/dbug.hoon index 5b2d517b2a..80c5fc1406 100644 --- a/pkg/arvo/app/dbug.hoon +++ b/pkg/arvo/app/dbug.hoon @@ -148,9 +148,7 @@ :: =; json=(unit json) ?~ json not-found:gen - %- json-response:gen - =, html - (as-octt:mimes (en-json u.json)) + (json-response:gen u.json) =, enjs:format ?+ site ~ :: /apps.json: {appname: running?} diff --git a/pkg/arvo/app/language-server.hoon b/pkg/arvo/app/language-server.hoon index 3ad37f5166..0b2e5c31e4 100644 --- a/pkg/arvo/app/language-server.hoon +++ b/pkg/arvo/app/language-server.hoon @@ -113,7 +113,7 @@ ++ json-response |= [eyre-id=@ta jon=json] ^- (list card) - (give-simple-payload:app eyre-id (json-response:gen (json-to-octs jon))) + (give-simple-payload:app eyre-id (json-response:gen jon)) :: ++ give-rpc-notification |= res=out:notification:lsp-sur diff --git a/pkg/arvo/app/lens.hoon b/pkg/arvo/app/lens.hoon index 73004cb27b..8c86f8f8d6 100644 --- a/pkg/arvo/app/lens.hoon +++ b/pkg/arvo/app/lens.hoon @@ -136,7 +136,7 @@ :: :_ this %+ give-simple-payload:app eyre-id.u.job.state - (json-response:gen (json-to-octs jon)) + (json-response:gen jon) :: ++ take-sole-effect |= fec=sole-effect @@ -186,7 +186,7 @@ %+ give-simple-payload:app eyre-id.u.job.state ?- -.u.out %json - (json-response:gen (json-to-octs json.u.out)) + (json-response:gen json.u.out) :: %mime =/ headers diff --git a/pkg/arvo/app/publish.hoon b/pkg/arvo/app/publish.hoon index 00b5075bfb..9761db7837 100644 --- a/pkg/arvo/app/publish.hoon +++ b/pkg/arvo/app/publish.hoon @@ -2347,7 +2347,6 @@ :: all notebooks, short form [[[~ %json] [%'publish-view' %notebooks ~]] ~] %- json-response:gen - %- json-to-octs (notebooks-map:enjs our.bol books) :: :: notes pagination @@ -2366,7 +2365,6 @@ ?~ length not-found:gen %- json-response:gen - %- json-to-octs :- %o (notes-page:enjs notes.u.book u.start u.length) :: @@ -2390,7 +2388,6 @@ ?~ length not-found:gen %- json-response:gen - %- json-to-octs (comments-page:enjs comments.u.note u.start u.length) :: :: single notebook with initial 50 notes in short form, as json @@ -2409,7 +2406,7 @@ (~(put by p.notebook-json) %subscribers (get-subscribers-json book-name)) =. p.notebook-json (~(put by p.notebook-json) %writers (get-writers-json u.host book-name)) - (json-response:gen (json-to-octs (pairs notebook+notebook-json ~))) + (json-response:gen (pairs notebook+notebook-json ~)) :: :: single note, with initial 50 comments, as json [[[~ %json] [%'publish-view' @ @ @ ~]] ~] @@ -2424,7 +2421,7 @@ ?~ note not-found:gen =/ jon=json o+(note-presentation:enjs u.book note-name u.note) - (json-response:gen (json-to-octs jon)) + (json-response:gen jon) == :: -- diff --git a/pkg/arvo/lib/server.hoon b/pkg/arvo/lib/server.hoon index d51fa12c8d..1f450c3e50 100644 --- a/pkg/arvo/lib/server.hoon +++ b/pkg/arvo/lib/server.hoon @@ -92,9 +92,9 @@ [[200 [['content-type' 'text/javascript'] max-1-da ~]] `octs] :: ++ json-response - |= =octs + |= =json ^- simple-payload:http - [[200 ['content-type' 'application/json']~] `octs] + [[200 ['content-type' 'application/json']~] `(json-to-octs json)] :: ++ css-response |= =octs From 20c94d34feb7d9db58d0f6d6c84b767a3eab921b Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 27 Aug 2020 11:46:46 -0500 Subject: [PATCH 12/58] interface: added graph reducer, store state, and subscription --- .../src/logic/reducers/graph-update.js | 141 ++++++++++++++++++ pkg/interface/src/logic/store/store.ts | 4 + pkg/interface/src/logic/store/type.ts | 2 + .../src/logic/subscription/global.ts | 17 ++- pkg/interface/src/views/apps/links/app.js | 2 + 5 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 pkg/interface/src/logic/reducers/graph-update.js diff --git a/pkg/interface/src/logic/reducers/graph-update.js b/pkg/interface/src/logic/reducers/graph-update.js new file mode 100644 index 0000000000..aef331b816 --- /dev/null +++ b/pkg/interface/src/logic/reducers/graph-update.js @@ -0,0 +1,141 @@ +import _ from 'lodash'; + + +const OrderedMap = (arr = []) => { + let map = new Map(arr); +// map[Symbol.iterator] = function* () { +// yield* [...this.entries()].sort((a, b) => a[1] - b[1]); +// }; + return map; +}; + +export const GraphReducer = (json, state) => { + const data = _.get(json, 'graph-update', false); + if (data) { + keys(data, state); + addGraph(data, state); + addNodes(data, state); + } +}; + +const keys = (json, state) => { + const data = _.get(json, 'keys', false); + if (data) { + state.graphKeys = new Set(data.map((res) => { + return res.ship + '/' + res.name; + })); + } +}; + +const addGraph = (json, state) => { + const data = _.get(json, 'add-graph', false); + if (data) { + if (!('graphs' in state)) { + state.graphs = {}; + } + + let resource = data.resource.ship + '/' + data.resource.name; + if (!(resource in state.graphs)) { + state.graphs[resource] = new OrderedMap(); + } + + for (let i in data.graph) { + let item = data.graph[i]; + let index = item[0].split('/').slice(1).map((ind) => { + return parseInt(ind, 10); + }); + + if (index.length === 0) { break; } + + let node = _processNode(item[1]); + state.graphs[resource].set(index[index.length - 1], node); + } + state.graphKeys.add(resource); + } +}; + +const _processNode = (node) => { + // is empty + if (!node.children) { + node.children = new OrderedMap(); + return node; + } + + // is graph + let converted = new OrderedMap(); + for (let i in node.children) { + let item = node.children[i]; + let index = item[0].split('/').slice(1).map((ind) => { + return parseInt(ind, 10); + }); + + if (index.length === 0) { break; } + + converted.set( + index[index.length - 1], + _processNode(item[1]) + ); + } + node.children = converted; + return node; + } + +const removeGraph = (json, state) => { + const data = _.get(json, 'remove-graph', false); + if (data) { + if (!('graphs' in state)) { + state.graphs = {}; + } + let resource = data.resource.ship + '/' + data.resource.name; + delete state.graphs[resource]; + } +}; + +const addNodes = (json, state) => { + const data = _.get(json, 'add-nodes', false); + if (data) { + if (!('graphs' in state)) { return; } + + let resource = data.resource.ship + '/' + data.resource.name; + if (!(resource in state.graphs)) { return; } + + for (let i in data.nodes) { + let item = data.nodes[i]; + if (item[0].split('/').length === 0) { return; } + + let index = item[0].split('/').slice(1).map((ind) => { + return parseInt(ind, 10); + }); + + if (index.length === 0) { return; } + + // TODO: support adding nodes with children + item[1].children = new Map(); + + state.graphs[resource] = _addNode( + state.graphs[resource], + index, + item[1] + ); + } + } +}; + +const _addNode = (graph, index, node) => { + // set child of graph + if (index.length === 1) { + graph.set(index[0], node); + return graph; + } + + // set parent of graph + let parNode = graph.get(index[0]); + if (!parNode) { + console.error('parent node does not exist, cannot add child'); + return; + } + parNode.children = _addNode(parNode.children, index.slice(1), node); + graph.set(index[0], parNode); + return graph; +}; + diff --git a/pkg/interface/src/logic/store/store.ts b/pkg/interface/src/logic/store/store.ts index 1b9d7aeb00..8926231cc7 100644 --- a/pkg/interface/src/logic/store/store.ts +++ b/pkg/interface/src/logic/store/store.ts @@ -9,6 +9,7 @@ import { Cage } from '~/types/cage'; import ContactReducer from '../reducers/contact-update'; import LinkUpdateReducer from '../reducers/link-update'; import S3Reducer from '../reducers/s3-update'; +import { GraphReducer } from '../reducers/graph-update'; import GroupReducer from '../reducers/group-update'; import PermissionReducer from '../reducers/permission-update'; import PublishUpdateReducer from '../reducers/publish-update'; @@ -64,6 +65,8 @@ export default class GlobalStore extends BaseStore { }, groups: {}, groupKeys: new Set(), + graphs: {}, + graphKeys: new Set(), launch: { firstTime: false, tileOrdering: [], @@ -106,5 +109,6 @@ export default class GlobalStore extends BaseStore { this.launchReducer.reduce(data, this.state); this.linkListenReducer.reduce(data, this.state); this.connReducer.reduce(data, this.state); + GraphReducer(data, this.state); } } diff --git a/pkg/interface/src/logic/store/type.ts b/pkg/interface/src/logic/store/type.ts index 620ea71136..525ec23a23 100644 --- a/pkg/interface/src/logic/store/type.ts +++ b/pkg/interface/src/logic/store/type.ts @@ -35,6 +35,8 @@ export interface StoreState { groupKeys: Set; permissions: Permissions; s3: S3State; + graphs: Object; + graphKeys: Set; // App specific states diff --git a/pkg/interface/src/logic/subscription/global.ts b/pkg/interface/src/logic/subscription/global.ts index 6a3bb37015..8a07dde076 100644 --- a/pkg/interface/src/logic/subscription/global.ts +++ b/pkg/interface/src/logic/subscription/global.ts @@ -27,12 +27,18 @@ const groupSubscriptions: AppSubscription[] = [ ['/synced', 'contact-hook'] ]; -type AppName = 'publish' | 'chat' | 'link' | 'groups'; +const graphSubscriptions: AppSubscription[] = [ + ['/keys', 'graph-store'], + ['/updates', 'graph-store'] +]; + +type AppName = 'publish' | 'chat' | 'link' | 'groups' | 'graph'; const appSubscriptions: Record = { chat: chatSubscriptions, publish: publishSubscriptions, link: linkSubscriptions, - groups: groupSubscriptions + groups: groupSubscriptions, + graph: graphSubscriptions }; export default class GlobalSubscription extends BaseSubscription { @@ -40,8 +46,10 @@ export default class GlobalSubscription extends BaseSubscription { chat: [], publish: [], link: [], - groups: [] + groups: [], + graph: [] }; + start() { this.subscribe('/all', 'invite-store'); this.subscribe('/groups', 'group-store'); @@ -67,7 +75,8 @@ export default class GlobalSubscription extends BaseSubscription { console.log(`${app} already started`); return; } - this.openSubscriptions[app] = appSubscriptions[app].map(([path, agent]) => this.subscribe(path, agent)); + this.openSubscriptions[app] = + appSubscriptions[app].map(([path, agent]) => this.subscribe(path, agent)); } stopApp(app: AppName) { diff --git a/pkg/interface/src/views/apps/links/app.js b/pkg/interface/src/views/apps/links/app.js index 30b4965479..606e4ae05d 100644 --- a/pkg/interface/src/views/apps/links/app.js +++ b/pkg/interface/src/views/apps/links/app.js @@ -31,6 +31,7 @@ export class LinksApp extends Component { this.props.api.links.getPage('', 0); this.props.subscription.startApp('link'); + this.props.subscription.startApp('graph'); if (!this.props.sidebarShown) { this.props.api.local.sidebarToggle(); } @@ -38,6 +39,7 @@ export class LinksApp extends Component { componentWillUnmount() { this.props.subscription.stopApp('link'); + this.props.subscription.stopApp('graph'); } From 3c0dc59747d7889f0396c2c838155d8d236a0147 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Thu, 27 Aug 2020 15:11:03 -0400 Subject: [PATCH 13/58] profile: log out of all sessions This was hidden in urbit-os-v1.0.44 until we could ensure it actually logged you out of all sessions. It requires a hidden input to function, so it's added here. Fixes #2649. --- .../src/views/apps/profile/components/lib/Security.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/interface/src/views/apps/profile/components/lib/Security.tsx b/pkg/interface/src/views/apps/profile/components/lib/Security.tsx index d40ae8aef9..0fdfaac529 100644 --- a/pkg/interface/src/views/apps/profile/components/lib/Security.tsx +++ b/pkg/interface/src/views/apps/profile/components/lib/Security.tsx @@ -24,18 +24,18 @@ export default function SecuritySettings({ api }: SecuritySettingsProps) { - {/* + Log out of all sessions - */} - {/* Restore after testing sending 'all' in POST body + You will be logged out of all browsers that have currently logged into your Urbit.
+
-
*/} + ); } From c08509535fe9ab7a815f1f9aec524c6e0d59b98f Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Thu, 27 Aug 2020 15:35:20 -0400 Subject: [PATCH 14/58] publish: fix unread counts for long titles Fixes #3283. --- .../src/views/apps/publish/components/lib/NotebookItem.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/interface/src/views/apps/publish/components/lib/NotebookItem.tsx b/pkg/interface/src/views/apps/publish/components/lib/NotebookItem.tsx index 621725b41a..4a03475e78 100644 --- a/pkg/interface/src/views/apps/publish/components/lib/NotebookItem.tsx +++ b/pkg/interface/src/views/apps/publish/components/lib/NotebookItem.tsx @@ -18,6 +18,7 @@ function UnreadCount(props: { unread: number }) { fontWeight="700" py={1} borderRadius={1} + flexShrink='0' color="white" bg="lightGray" > @@ -41,7 +42,7 @@ export function NotebookItem(props: NotebookItemProps) { justifyContent="space-between" alignItems="center" > - {props.title} + {props.title} {props.unreadCount > 0 && } From f2eeb7a14f5846d70ba7d298fe86817a36dca6ad Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Thu, 27 Aug 2020 15:49:48 -0400 Subject: [PATCH 15/58] chat: break up inline code Doesn't affect %code messages. Fixes #3358. --- pkg/interface/src/views/apps/chat/css/custom.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/interface/src/views/apps/chat/css/custom.css b/pkg/interface/src/views/apps/chat/css/custom.css index 56babb6232..052fb06282 100644 --- a/pkg/interface/src/views/apps/chat/css/custom.css +++ b/pkg/interface/src/views/apps/chat/css/custom.css @@ -252,6 +252,10 @@ blockquote { font-family: 'Inter'; } +code { + white-space: normal; +} + code, pre.code { background-color: var(--light-gray); } From a4b945b4a3be737717d13119a145bc30c64d9cc4 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Thu, 27 Aug 2020 16:42:02 -0400 Subject: [PATCH 16/58] chat: hideAvatars hides chat input avatar Fixes #3386. --- pkg/interface/src/views/apps/chat/components/chat.tsx | 1 + .../src/views/apps/chat/components/lib/chat-input.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/interface/src/views/apps/chat/components/chat.tsx b/pkg/interface/src/views/apps/chat/components/chat.tsx index b7d9a0e58d..2901e7167d 100644 --- a/pkg/interface/src/views/apps/chat/components/chat.tsx +++ b/pkg/interface/src/views/apps/chat/components/chat.tsx @@ -149,6 +149,7 @@ export class ChatScreen extends Component { deleteMessage={() => this.setState({ messages: this.state.messages.set(props.station, "") })} + hideAvatars={props.hideAvatars} />
); diff --git a/pkg/interface/src/views/apps/chat/components/lib/chat-input.js b/pkg/interface/src/views/apps/chat/components/lib/chat-input.js index 4e49680a12..c4919cefce 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/chat-input.js +++ b/pkg/interface/src/views/apps/chat/components/lib/chat-input.js @@ -201,7 +201,10 @@ export class ChatInput extends Component { const sigilClass = props.ownerContact ? '' : 'mix-blend-diff'; - const avatar = (props.ownerContact && (props.ownerContact.avatar !== null)) + const avatar = ( + props.ownerContact && + ((props.ownerContact.avatar !== null) && !props.hideAvatars) + ) ? : Date: Thu, 27 Aug 2020 17:31:36 -0500 Subject: [PATCH 17/58] graph-store: updated scry interface to return %graph-store marks so as to properly do %json conversion --- pkg/arvo/app/graph-store.hoon | 74 ++++++++++++++++++++++------------- pkg/arvo/lib/graph-store.hoon | 12 ++++-- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index ab9a6b9710..16b18bb632 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -447,16 +447,29 @@ |^ ?> (team:title our.bowl src.bowl) ?+ path (on-peek:def path) - [%x %keys ~] ``noun+!>(~(key by graphs)) - [%x %tags ~] ``noun+!>(~(key by tag-queries)) - [%x %tag-queries ~] ``noun+!>(tag-queries) + [%x %keys ~] + :- ~ :- ~ :- %graph-update + !>(`update:store`[%0 now.bowl [%keys ~(key by graphs)]]) + :: + [%x %tags ~] + :- ~ :- ~ :- %graph-update + !>(`update:store`[%0 now.bowl [%tags ~(key by tag-queries)]]) + :: + [%x %tag-queries ~] + :- ~ :- ~ :- %graph-update + !>(`update:store`[%0 now.bowl [%tag-queries tag-queries]]) + :: [%x %graph @ @ ~] =/ =ship (slav %p i.t.t.path) =/ =term i.t.t.t.path =/ result=(unit marked-graph:store) (~(get by graphs) [ship term]) ?~ result [~ ~] - ``noun+!>(u.result) + :- ~ :- ~ :- %graph-update + !> ^- update:store + :+ %0 + now.bowl + [%add-graph [ship term] `graph:store`p.u.result q.u.result] :: [%x %graph-subset @ @ @ @ ~] =/ =ship (slav %p i.t.t.path) @@ -466,7 +479,16 @@ =/ graph=(unit marked-graph:store) (~(get by graphs) [ship term]) ?~ graph [~ ~] - ``noun+!>(`graph:store`(subset:orm p.u.graph start end)) + :- ~ :- ~ :- %graph-update + !> ^- update:store + :+ %0 now.bowl + :+ %add-nodes + [ship term] + %- ~(gas by *(map index:store node:store)) + %+ turn (tap:orm `graph:store`(subset:orm p.u.graph start end)) + |= [=atom =node:store] + ^- [index:store node:store] + [~[atom] node] :: [%x %node @ @ @ *] =/ =ship (slav %p i.t.t.path) @@ -475,28 +497,13 @@ (turn t.t.t.t.path |=(=cord (slav %ud cord))) =/ node=(unit node:store) (get-node ship term index) ?~ node [~ ~] - ``noun+!>(u.node) - :: - [%x %post @ @ @ *] - =/ =ship (slav %p i.t.t.path) - =/ =term i.t.t.t.path - =/ =index:store - (turn t.t.t.t.path |=(=cord (slav %ud cord))) - =/ node=(unit node:store) (get-node ship term index) - ?~ node [~ ~] - ``noun+!>(post.u.node) - :: - [%x %node-children @ @ @ *] - =/ =ship (slav %p i.t.t.path) - =/ =term i.t.t.t.path - =/ =index:store - (turn t.t.t.t.path |=(=cord (slav %ud cord))) - =/ node=(unit node:store) (get-node ship term index) - ?~ node [~ ~] - ?- -.children.u.node - %empty [~ ~] - %graph ``noun+!>(p.children.u.node) - == + :- ~ :- ~ :- %graph-update + !> ^- update:store + :+ %0 + now.bowl + :+ %add-nodes + [ship term] + (~(gas by *(map index:store node:store)) [index u.node] ~) :: [%x %node-children-subset @ @ @ @ @ *] =/ =ship (slav %p i.t.t.path) @@ -509,7 +516,18 @@ ?~ node [~ ~] ?- -.children.u.node %empty [~ ~] - %graph ``noun+!>(`graph:store`(subset:orm p.children.u.node start end)) + %graph + :- ~ :- ~ :- %graph-update + !> ^- update:store + :+ %0 + now.bowl + :+ %add-nodes + [ship term] + %- ~(gas by *(map index:store node:store)) + %+ turn (tap:orm `graph:store`(subset:orm p.children.u.node start end)) + |= [=atom =node:store] + ^- [index:store node:store] + [(snoc index atom) node] == :: [%x %update-log @ @ ~] diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index bf099c89f6..4ed56c4a72 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -247,20 +247,24 @@ |% ++ decode %- of - :~ [%add-graph add-graph] - [%remove-graph remove-graph] - [%add-nodes add-nodes] + :~ [%add-nodes add-nodes] [%remove-nodes remove-nodes] [%add-signatures add-signatures] [%remove-signatures remove-signatures] + :: + [%add-graph add-graph] + [%remove-graph remove-graph] + :: [%add-tag add-tag] [%remove-tag remove-tag] + :: [%archive-graph archive-graph] [%unarchive-graph unarchive-graph] + [%run-updates run-updates] + :: [%keys keys] [%tags tags] [%tag-queries tag-queries] - [%run-updates run-updates] == :: ++ add-graph From c9bfe272e3967517ef9892b8295ff052e157aebd Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 27 Aug 2020 17:34:46 -0500 Subject: [PATCH 18/58] interface: added graph API and stubbed out graph scries --- pkg/interface/src/logic/api/global.ts | 10 +- pkg/interface/src/logic/api/graph.ts | 149 ++++++++++++++++++++++ pkg/interface/src/views/apps/links/app.js | 8 -- 3 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 pkg/interface/src/logic/api/graph.ts diff --git a/pkg/interface/src/logic/api/global.ts b/pkg/interface/src/logic/api/global.ts index 7adc461662..d724e0073c 100644 --- a/pkg/interface/src/logic/api/global.ts +++ b/pkg/interface/src/logic/api/global.ts @@ -11,6 +11,7 @@ import GroupsApi from './groups'; import LaunchApi from './launch'; import LinksApi from './links'; import PublishApi from './publish'; +import GraphApi from './graph'; import S3Api from './s3'; export default class GlobalApi extends BaseApi { @@ -24,10 +25,15 @@ export default class GlobalApi extends BaseApi { links = new LinksApi(this.ship, this.channel, this.store); publish = new PublishApi(this.ship, this.channel, this.store); s3 = new S3Api(this.ship, this.channel, this.store); + graph = new GraphApi(this.ship, this.channel, this.store); - constructor(public ship: Patp, public channel: any, public store: GlobalStore) { - super(ship,channel,store); + constructor( + public ship: Patp, + public channel: any, + public store: GlobalStore + ) { + super(ship, channel, store); } } diff --git a/pkg/interface/src/logic/api/graph.ts b/pkg/interface/src/logic/api/graph.ts new file mode 100644 index 0000000000..4058e787eb --- /dev/null +++ b/pkg/interface/src/logic/api/graph.ts @@ -0,0 +1,149 @@ +import BaseApi from './base'; +import { StoreState } from '../store/type'; +import { Patp, Path, PatpNoSig } from '~/types/noun'; + + +export const createPost = (contents: Object[], parentIndex: string) => { + return { + author: `~${window.ship}`, + index: parentIndex + '/' + Date.now(), + 'time-sent': Date.now(), + contents, + hash: null, + signatures: [] + }; +}; + +export default class GraphApi extends BaseApi { + + private storeAction(action: any): Promise { + return this.action('graph-store', 'graph-update', action) + } + + addGraph(ship: Patp, name: string, graph: any, mark: any) { + this.storeAction({ + 'add-graph': { + resource: { ship, name }, + graph, + mark + } + }); + } + + removeGraph(ship: Patp, name: string) { + this.storeAction({ + 'remove-graph': { + resource: { ship, name } + } + }); + } + + addPost(ship: Patp, name: string, post: Object) { + let nodes = {}; + nodes[post.index] = { + post, + children: { empty: null } + }; + + this.storeAction({ + 'add-nodes': { + resource: { ship, name }, + nodes + } + }); + } + + addNodes(ship: Patp, name: string, nodes: Object) { + this.storeAction({ + 'add-nodes': { + resource: { ship, name }, + nodes + } + }); + } + + removeNodes(ship: Patp, name: string, indices: string[]) { + this.storeAction({ + 'remove-nodes': { + resource: { ship, name }, + indices + } + }); + } + + getKeys() { + this.scry('graph-store', '/keys') + .then((keys) => { + console.log(keys); + }); + } + + getTags() { + this.scry('graph-store', '/tags') + .then((tags) => { + console.log(tags); + }); + } + + getTagQueries() { + this.scry('graph-store', '/tag-queries') + .then((tagQueries) => { + console.log(tagQueries); + }); + } + + getGraph(ship: string, resource: string) { + this.scry('graph-store', `/graph/${ship}/${resource}`) + .then((graph) => { + console.log(graph); + }); + } + + getGraphSubset(ship: string, resource: string, start: string, end: start) { + this.scry( + 'graph-store', + `/graph-subset/${ship}/${resource}/${start}/${end}` + ).then((subset) => { + console.log(subset); + }); + } + + getNode(ship: string, resource: string, index: string) { + this.scry( + 'graph-store', + `/node/${ship}/${resource}/${index}` + ).then((node) => { + console.log(node); + }); + } + + getPost(ship: string, resource: string, index: string) { + this.scry( + 'graph-store', + `/post/${ship}/${resource}/${index}` + ).then((post) => { + console.log(post); + }); + } + + getNodeChildren(ship: string, resource: string, index: string) { + this.scry( + 'graph-store', + `/node-children/${ship}/${resource}/${index}` + ).then((children) => { + console.log(children); + }); + } + + getNodeChildrenSubset(ship: string, resource: string, + start: string, end: string, index: string) { + this.scry( + 'graph-store', + `/node-children-subset/${ship}/${resource}/${start}/${end}/${index}` + ).then((subset) => { + console.log(subset); + }); + } + +} + diff --git a/pkg/interface/src/views/apps/links/app.js b/pkg/interface/src/views/apps/links/app.js index 606e4ae05d..99fae44aa9 100644 --- a/pkg/interface/src/views/apps/links/app.js +++ b/pkg/interface/src/views/apps/links/app.js @@ -42,20 +42,14 @@ export class LinksApp extends Component { this.props.subscription.stopApp('graph'); } - render() { const { props } = this; - const contacts = props.contacts ? props.contacts : {}; - const groups = props.groups ? props.groups : {}; - const associations = props.associations ? props.associations : { link: {}, contacts: {} }; const links = props.links ? props.links : {}; const comments = props.linkComments ? props.linkComments : {}; - const seen = props.linksSeen ? props.linksSeen : {}; - const totalUnseen = _.reduce( links, (acc, collection) => acc + collection.unseenCount, @@ -65,9 +59,7 @@ export class LinksApp extends Component { const invites = props.invites ? props.invites : {}; - const listening = props.linkListening; - const { api, sidebarShown, hideAvatars, hideNicknames } = this.props; return ( From b51046d258d783f46d403eecdb50f4ff74086513 Mon Sep 17 00:00:00 2001 From: Tyler Brown Cifu Shuster Date: Thu, 27 Aug 2020 16:17:25 -0700 Subject: [PATCH 19/58] chat: only show other participant in dms --- .../src/views/apps/chat/components/lib/group-item.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/components/lib/group-item.js b/pkg/interface/src/views/apps/chat/components/lib/group-item.js index 1f0e200b96..495e16812d 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/group-item.js +++ b/pkg/interface/src/views/apps/chat/components/lib/group-item.js @@ -1,11 +1,13 @@ import React, { Component } from 'react'; import { Link } from 'react-router-dom'; import { ChannelItem } from './channel-item'; +import { deSig } from "~/logic/lib/util"; export class GroupItem extends Component { render() { const { props } = this; const association = props.association ? props.association : {}; + const DEFAULT_TITLE_REGEX = new RegExp(`(( <-> )?~${deSig(window.ship)}( <-> )?)`); let title = association['app-path'] ? association['app-path'] : 'Direct Messages'; if (association.metadata && association.metadata.title) { @@ -47,9 +49,13 @@ export class GroupItem extends Component { each in props.chatMetadata && props.chatMetadata[each].metadata ) { - title = props.chatMetadata[each].metadata.title - ? props.chatMetadata[each].metadata.title - : each.substr(1); + if (props.chatMetadata[each].metadata.title) { + title = props.chatMetadata[each].metadata.title + } + } + + if (DEFAULT_TITLE_REGEX.test(title) && props.index === "dm") { + title = title.replace(DEFAULT_TITLE_REGEX, ''); } const selected = props.station === each; From 4c758372d6db823e5bd1ad07848592568521c93e Mon Sep 17 00:00:00 2001 From: Philip Monk Date: Thu, 27 Aug 2020 21:14:47 -0700 Subject: [PATCH 20/58] clay: minimal -diff thread Barebones 2-way diff thread. Further development should include: - recognize at least %txt and %hoon diff types as (urge:clay cord) and print them prettily - check if they're directories and recurse through them, noting files that exist in one or the other and diffing ones that exist in both - support 3-way diffs. Since we know the desks they're on, we can find a mergebase (see how +trouble gets the base-hash in #3378) and do a 3-way diff. - extend the above to support all the useful diffs, including diff3(a,b), diff2(mergebase(a,b),a) and any other useful ones. --- pkg/arvo/ted/diff.hoon | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 pkg/arvo/ted/diff.hoon diff --git a/pkg/arvo/ted/diff.hoon b/pkg/arvo/ted/diff.hoon new file mode 100644 index 0000000000..cd9cdc796a --- /dev/null +++ b/pkg/arvo/ted/diff.hoon @@ -0,0 +1,30 @@ +/- spider +/+ strandio +=, strand=strand:spider +^- thread:spider +|= arg=vase +=/ m (strand ,vase) +^- form:m +|^ +=+ !<([=a=path =b=path ~] arg) +=/ a-mark=mark -:(flop a-path) +=/ b-mark=mark -:(flop b-path) +?. =(a-mark b-mark) + (strand-fail:strandio %files-not-same-type ~) +=/ a-beam (need (de-beam:format a-path)) +;< =a=cage bind:m (get-file a-path) +;< =b=cage bind:m (get-file b-path) +;< =dais:clay bind:m (build-mark:strandio -.a-beam a-mark) +(pure:m (~(diff dais q.a-cage) q.b-cage)) +:: +++ get-file + |= =path + =/ m (strand ,cage) + ^- form:m + =/ beam (need (de-beam:format path)) + ;< =riot:clay bind:m + (warp:strandio p.beam q.beam ~ %sing %x r.beam (flop s.beam)) + ?~ riot + (strand-fail:strandio %file-not-found >path< ~) + (pure:m r.u.riot) +-- From 90a6282b4ee8f45f066525c35a6cdf2fee6e3648 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 28 Aug 2020 13:40:17 -0500 Subject: [PATCH 21/58] interface: integrated and tested all scries with reducer --- pkg/interface/src/logic/api/graph.ts | 57 +++++++------------ .../src/logic/reducers/graph-update.js | 12 ++-- pkg/interface/src/views/apps/links/app.js | 1 + 3 files changed, 29 insertions(+), 41 deletions(-) diff --git a/pkg/interface/src/logic/api/graph.ts b/pkg/interface/src/logic/api/graph.ts index 4058e787eb..d583322021 100644 --- a/pkg/interface/src/logic/api/graph.ts +++ b/pkg/interface/src/logic/api/graph.ts @@ -3,7 +3,7 @@ import { StoreState } from '../store/type'; import { Patp, Path, PatpNoSig } from '~/types/noun'; -export const createPost = (contents: Object[], parentIndex: string) => { +export const createPost = (contents: Object[], parentIndex: string = '') => { return { author: `~${window.ship}`, index: parentIndex + '/' + Date.now(), @@ -74,37 +74,47 @@ export default class GraphApi extends BaseApi { getKeys() { this.scry('graph-store', '/keys') .then((keys) => { - console.log(keys); + this.store.handleEvent({ + data: keys + }); }); } getTags() { this.scry('graph-store', '/tags') .then((tags) => { - console.log(tags); + this.store.handleEvent({ + data: tags + }); }); } getTagQueries() { this.scry('graph-store', '/tag-queries') .then((tagQueries) => { - console.log(tagQueries); + this.store.handleEvent({ + data: tagQueries + }); }); } getGraph(ship: string, resource: string) { this.scry('graph-store', `/graph/${ship}/${resource}`) .then((graph) => { - console.log(graph); + this.store.handleEvent({ + data: graph + }); }); } getGraphSubset(ship: string, resource: string, start: string, end: start) { this.scry( 'graph-store', - `/graph-subset/${ship}/${resource}/${start}/${end}` + `/graph-subset/${ship}/${resource}/${end}/${start}` ).then((subset) => { - console.log(subset); + this.store.handleEvent({ + data: subset + }); }); } @@ -113,37 +123,10 @@ export default class GraphApi extends BaseApi { 'graph-store', `/node/${ship}/${resource}/${index}` ).then((node) => { - console.log(node); + this.store.handleEvent({ + data: node + }); }); } - - getPost(ship: string, resource: string, index: string) { - this.scry( - 'graph-store', - `/post/${ship}/${resource}/${index}` - ).then((post) => { - console.log(post); - }); - } - - getNodeChildren(ship: string, resource: string, index: string) { - this.scry( - 'graph-store', - `/node-children/${ship}/${resource}/${index}` - ).then((children) => { - console.log(children); - }); - } - - getNodeChildrenSubset(ship: string, resource: string, - start: string, end: string, index: string) { - this.scry( - 'graph-store', - `/node-children-subset/${ship}/${resource}/${start}/${end}/${index}` - ).then((subset) => { - console.log(subset); - }); - } - } diff --git a/pkg/interface/src/logic/reducers/graph-update.js b/pkg/interface/src/logic/reducers/graph-update.js index aef331b816..5b8dbcb5cd 100644 --- a/pkg/interface/src/logic/reducers/graph-update.js +++ b/pkg/interface/src/logic/reducers/graph-update.js @@ -22,7 +22,13 @@ const keys = (json, state) => { const data = _.get(json, 'keys', false); if (data) { state.graphKeys = new Set(data.map((res) => { - return res.ship + '/' + res.name; + let resource = res.ship + '/' + res.name; + + if (!(resource in state.graphs)) { + state.graphs[resource] = new OrderedMap(); + } + + return resource; })); } }; @@ -35,9 +41,7 @@ const addGraph = (json, state) => { } let resource = data.resource.ship + '/' + data.resource.name; - if (!(resource in state.graphs)) { - state.graphs[resource] = new OrderedMap(); - } + state.graphs[resource] = new OrderedMap(); for (let i in data.graph) { let item = data.graph[i]; diff --git a/pkg/interface/src/views/apps/links/app.js b/pkg/interface/src/views/apps/links/app.js index 99fae44aa9..5b8cc3d8ce 100644 --- a/pkg/interface/src/views/apps/links/app.js +++ b/pkg/interface/src/views/apps/links/app.js @@ -13,6 +13,7 @@ import { SettingsScreen } from './components/settings'; import { MessageScreen } from './components/lib/message-screen'; import { Links } from './components/links-list'; import { LinkDetail } from './components/link'; + import { makeRoutePath, amOwnerOfGroup, From 7519838cd205e3d3887dfc8b4181750c2d6f5b5e Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Sep 2020 00:38:11 +1000 Subject: [PATCH 22/58] interface: update title eagerly --- pkg/interface/src/views/apps/chat/app.tsx | 2 +- pkg/interface/src/views/apps/links/app.js | 2 +- pkg/interface/src/views/apps/publish/app.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/app.tsx b/pkg/interface/src/views/apps/chat/app.tsx index 2a3a761757..cadf3e265e 100644 --- a/pkg/interface/src/views/apps/chat/app.tsx +++ b/pkg/interface/src/views/apps/chat/app.tsx @@ -108,7 +108,7 @@ export default class ChatApp extends React.Component { return ( <> - + {totalUnreads > 0 ? `(${totalUnreads}) ` : ''}OS1 - Chat diff --git a/pkg/interface/src/views/apps/links/app.js b/pkg/interface/src/views/apps/links/app.js index 30b4965479..a8e6deeb8c 100644 --- a/pkg/interface/src/views/apps/links/app.js +++ b/pkg/interface/src/views/apps/links/app.js @@ -70,7 +70,7 @@ export class LinksApp extends Component { return ( <> - + {totalUnseen > 0 ? `(${totalUnseen}) ` : ''}OS1 - Links diff --git a/pkg/interface/src/views/apps/publish/app.tsx b/pkg/interface/src/views/apps/publish/app.tsx index 2dc2055875..59aafff85e 100644 --- a/pkg/interface/src/views/apps/publish/app.tsx +++ b/pkg/interface/src/views/apps/publish/app.tsx @@ -71,7 +71,7 @@ export default function PublishApp(props: PublishAppProps) { return ( <> - + {unreadTotal > 0 ? `(${unreadTotal}) ` : ""}OS1 - Publish Date: Tue, 1 Sep 2020 01:13:33 +1000 Subject: [PATCH 23/58] publish: check roles correctly for tags --- .../publish/components/lib/Subscribers.tsx | 25 +++++++++++-------- pkg/interface/src/views/components/Group.tsx | 4 +-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/pkg/interface/src/views/apps/publish/components/lib/Subscribers.tsx b/pkg/interface/src/views/apps/publish/components/lib/Subscribers.tsx index 4ff86c82bf..069e851f33 100644 --- a/pkg/interface/src/views/apps/publish/components/lib/Subscribers.tsx +++ b/pkg/interface/src/views/apps/publish/components/lib/Subscribers.tsx @@ -1,11 +1,12 @@ import React, { Component } from 'react'; import { GroupView } from '~/views/components/Group'; -import { resourceFromPath } from '~/logic/lib/group'; +import { resourceFromPath, roleForShip } from '~/logic/lib/group'; import {Notebook} from '~/types/publish-update'; import GlobalApi from '~/logic/api/global'; import {Groups} from '~/types/group-update'; import {Associations} from '~/types/metadata-update'; import {Rolodex} from '~/types/contact-update'; +import {Box, Button} from '@tlon/indigo-react'; interface SubscribersProps { notebook: Notebook; @@ -71,16 +72,20 @@ export class Subscribers extends Component { addDesc: 'Allow user to write to this notebook' }, ]; - + + if(!group) { + return null; + } + + const role = roleForShip(group, window.ship) return ( -
- + + { role === 'admin' && ( + + )} { associations={this.props.associations} api={this.props.api} /> -
+ ); } } diff --git a/pkg/interface/src/views/components/Group.tsx b/pkg/interface/src/views/components/Group.tsx index e364c0aeb4..0b8dc9bf31 100644 --- a/pkg/interface/src/views/components/Group.tsx +++ b/pkg/interface/src/views/components/Group.tsx @@ -143,10 +143,8 @@ export class GroupView extends Component< } isAdmin(): boolean { - const us = `~${window.ship}`; const role = roleForShip(this.props.group, window.ship); - const resource = resourceFromPath(this.props.resourcePath); - return resource.ship == us || role === 'admin'; + return role === 'admin'; } optionsForShip(ship: Patp, missing: GroupViewAppTag[]) { From 149ffd32e64569cfa63a13fb15b96bbe03ff29a2 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Sep 2020 01:25:51 +1000 Subject: [PATCH 24/58] publish: make input form expand to screen --- .../src/views/apps/publish/components/lib/MarkdownField.tsx | 2 +- .../src/views/apps/publish/components/lib/NoteForm.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/interface/src/views/apps/publish/components/lib/MarkdownField.tsx b/pkg/interface/src/views/apps/publish/components/lib/MarkdownField.tsx index efd4f0e475..b60af6a5cf 100644 --- a/pkg/interface/src/views/apps/publish/components/lib/MarkdownField.tsx +++ b/pkg/interface/src/views/apps/publish/components/lib/MarkdownField.tsx @@ -12,7 +12,7 @@ export const MarkdownField = ({ id, ...rest }: { id: string; } & Parameters + setTouched(true)} onBlur={() => setTouched(false)} diff --git a/pkg/interface/src/views/apps/publish/components/lib/NoteForm.tsx b/pkg/interface/src/views/apps/publish/components/lib/NoteForm.tsx index cc83d248d9..e4cc1f8ae6 100644 --- a/pkg/interface/src/views/apps/publish/components/lib/NoteForm.tsx +++ b/pkg/interface/src/views/apps/publish/components/lib/NoteForm.tsx @@ -31,10 +31,11 @@ export function PostForm(props: PostFormProps) { return ( Date: Tue, 1 Sep 2020 02:17:47 +1000 Subject: [PATCH 25/58] chat: cite patps in DM title --- pkg/interface/src/views/apps/chat/components/new-dm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/components/new-dm.js b/pkg/interface/src/views/apps/chat/components/new-dm.js index 5e69eaa6f7..3f2798b16b 100644 --- a/pkg/interface/src/views/apps/chat/components/new-dm.js +++ b/pkg/interface/src/views/apps/chat/components/new-dm.js @@ -3,7 +3,7 @@ import { Spinner } from '~/views/components/Spinner'; import { Link } from 'react-router-dom'; import { InviteSearch } from '~/views/components/InviteSearch'; import urbitOb from 'urbit-ob'; -import { deSig } from '~/logic/lib/util'; +import { deSig, cite } from '~/logic/lib/util'; export class NewDmScreen extends Component { constructor(props) { @@ -91,7 +91,7 @@ export class NewDmScreen extends Component { const aud = state.ship !== window.ship ? [`~${state.ships[0]}`] : []; - let title = `~${window.ship} <-> ~${state.ships[0]}`; + let title = `${cite(window.ship)} <-> ${cite(state.ships[0])}`; if (state.title !== '') { title = state.title; From b5df4e1d71579ac5138f6a070f62faa9e3fda846 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Mon, 31 Aug 2020 15:45:52 -0500 Subject: [PATCH 26/58] interface: added remove operations to graph reducer --- .../src/logic/reducers/graph-update.js | 117 ++++++++++-------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/pkg/interface/src/logic/reducers/graph-update.js b/pkg/interface/src/logic/reducers/graph-update.js index 5b8dbcb5cd..c8253f229c 100644 --- a/pkg/interface/src/logic/reducers/graph-update.js +++ b/pkg/interface/src/logic/reducers/graph-update.js @@ -1,20 +1,14 @@ import _ from 'lodash'; -const OrderedMap = (arr = []) => { - let map = new Map(arr); -// map[Symbol.iterator] = function* () { -// yield* [...this.entries()].sort((a, b) => a[1] - b[1]); -// }; - return map; -}; - export const GraphReducer = (json, state) => { const data = _.get(json, 'graph-update', false); if (data) { keys(data, state); addGraph(data, state); + removeGraph(data, state); addNodes(data, state); + removeNodes(data, state); } }; @@ -25,7 +19,7 @@ const keys = (json, state) => { let resource = res.ship + '/' + res.name; if (!(resource in state.graphs)) { - state.graphs[resource] = new OrderedMap(); + state.graphs[resource] = new Map(); } return resource; @@ -34,39 +28,16 @@ const keys = (json, state) => { }; const addGraph = (json, state) => { - const data = _.get(json, 'add-graph', false); - if (data) { - if (!('graphs' in state)) { - state.graphs = {}; - } - let resource = data.resource.ship + '/' + data.resource.name; - state.graphs[resource] = new OrderedMap(); - - for (let i in data.graph) { - let item = data.graph[i]; - let index = item[0].split('/').slice(1).map((ind) => { - return parseInt(ind, 10); - }); - - if (index.length === 0) { break; } - - let node = _processNode(item[1]); - state.graphs[resource].set(index[index.length - 1], node); - } - state.graphKeys.add(resource); - } -}; - -const _processNode = (node) => { + const _processNode = (node) => { // is empty if (!node.children) { - node.children = new OrderedMap(); + node.children = new Map(); return node; } // is graph - let converted = new OrderedMap(); + let converted = new Map(); for (let i in node.children) { let item = node.children[i]; let index = item[0].split('/').slice(1).map((ind) => { @@ -82,8 +53,33 @@ const _processNode = (node) => { } node.children = converted; return node; + }; + + const data = _.get(json, 'add-graph', false); + if (data) { + if (!('graphs' in state)) { + state.graphs = {}; + } + + let resource = data.resource.ship + '/' + data.resource.name; + state.graphs[resource] = new Map(); + + for (let i in data.graph) { + let item = data.graph[i]; + let index = item[0].split('/').slice(1).map((ind) => { + return parseInt(ind, 10); + }); + + if (index.length === 0) { break; } + + let node = _processNode(item[1]); + state.graphs[resource].set(index[index.length - 1], node); + } + state.graphKeys.add(resource); } +}; + const removeGraph = (json, state) => { const data = _.get(json, 'remove-graph', false); if (data) { @@ -96,6 +92,24 @@ const removeGraph = (json, state) => { }; const addNodes = (json, state) => { + const _addNode = (graph, index, node) => { + // set child of graph + if (index.length === 1) { + graph.set(index[0], node); + return graph; + } + + // set parent of graph + let parNode = graph.get(index[0]); + if (!parNode) { + console.error('parent node does not exist, cannot add child'); + return; + } + parNode.children = _addNode(parNode.children, index.slice(1), node); + graph.set(index[0], parNode); + return graph; + }; + const data = _.get(json, 'add-nodes', false); if (data) { if (!('graphs' in state)) { return; } @@ -125,21 +139,26 @@ const addNodes = (json, state) => { } }; -const _addNode = (graph, index, node) => { - // set child of graph - if (index.length === 1) { - graph.set(index[0], node); - return graph; - } +const removeNodes = (json, state) => { + const data = _.get(json, 'remove-nodes', false); + if (data) { + console.log(data); + if (!(data.resource in state.graphs)) { return; } - // set parent of graph - let parNode = graph.get(index[0]); - if (!parNode) { - console.error('parent node does not exist, cannot add child'); - return; + data.indices.forEach((index) => { + console.log(index); + if (index.split('/').length === 0) { return; } + let indexArr = index.split('/').slice(1).map((ind) => { + return parseInt(ind, 10); + }); + + if (indexArr.length === 1) { + state.graphs[data.resource].delete(indexArr[0]); + } else { + // TODO: recursive + } + + }); } - parNode.children = _addNode(parNode.children, index.slice(1), node); - graph.set(index[0], parNode); - return graph; }; From 97e84f96f24c52793c2502d8b2d9c43d91c5e4ec Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Tue, 1 Sep 2020 14:43:05 -0400 Subject: [PATCH 27/58] leap: move leap to its own subfolder --- pkg/interface/src/views/App.js | 11 +++++------ .../src/views/components/{ => leap}/Omnibox.js | 0 .../src/views/components/{ => leap}/OmniboxInput.js | 0 .../src/views/components/{ => leap}/OmniboxResult.js | 0 4 files changed, 5 insertions(+), 6 deletions(-) rename pkg/interface/src/views/components/{ => leap}/Omnibox.js (100%) rename pkg/interface/src/views/components/{ => leap}/OmniboxInput.js (100%) rename pkg/interface/src/views/components/{ => leap}/OmniboxResult.js (100%) diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index 497c5677b9..e72d0b1d16 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -1,7 +1,7 @@ import { hot } from 'react-hot-loader/root'; import 'react-hot-loader'; import * as React from 'react'; -import { BrowserRouter as Router, Route, withRouter, Switch } from 'react-router-dom'; +import { BrowserRouter as Router, withRouter } from 'react-router-dom'; import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; import { sigil as sigiljs, stringRenderer } from 'urbit-sigil-js'; import Helmet from 'react-helmet'; @@ -16,8 +16,7 @@ import dark from './themes/old-dark'; import { Content } from './components/Content'; import StatusBar from './components/StatusBar'; -import Omnibox from './components/Omnibox'; -import ErrorComponent from './components/Error'; +import Omnibox from './components/leap/Omnibox'; import GlobalStore from '~/logic/store/store'; import GlobalSubscription from '~/logic/subscription/global'; @@ -36,7 +35,7 @@ const Root = styled.div` background-size: cover; ` : p.background?.type === 'color' ? ` background-color: ${p.background.color}; - ` : `` + ` : '' } display: flex; flex-flow: column nowrap; @@ -135,7 +134,8 @@ class App extends React.Component { ship={this.ship} api={this.api} subscription={this.subscription} - {...state} /> + {...state} + /> @@ -143,6 +143,5 @@ class App extends React.Component { } } - export default process.env.NODE_ENV === 'production' ? App : hot(App); diff --git a/pkg/interface/src/views/components/Omnibox.js b/pkg/interface/src/views/components/leap/Omnibox.js similarity index 100% rename from pkg/interface/src/views/components/Omnibox.js rename to pkg/interface/src/views/components/leap/Omnibox.js diff --git a/pkg/interface/src/views/components/OmniboxInput.js b/pkg/interface/src/views/components/leap/OmniboxInput.js similarity index 100% rename from pkg/interface/src/views/components/OmniboxInput.js rename to pkg/interface/src/views/components/leap/OmniboxInput.js diff --git a/pkg/interface/src/views/components/OmniboxResult.js b/pkg/interface/src/views/components/leap/OmniboxResult.js similarity index 100% rename from pkg/interface/src/views/components/OmniboxResult.js rename to pkg/interface/src/views/components/leap/OmniboxResult.js From 37786327f473ff9e9240ed5c74d30cc1088c8363 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Tue, 1 Sep 2020 16:01:29 -0400 Subject: [PATCH 28/58] leap: add "other" actions, prepopulate results --- pkg/interface/src/logic/lib/omnibox.js | 17 ++++- .../src/views/components/leap/Omnibox.js | 32 +++++++-- .../views/components/leap/OmniboxResult.js | 70 +++++++++++++------ 3 files changed, 86 insertions(+), 33 deletions(-) diff --git a/pkg/interface/src/logic/lib/omnibox.js b/pkg/interface/src/logic/lib/omnibox.js index 60dc95c01f..49bf777261 100644 --- a/pkg/interface/src/logic/lib/omnibox.js +++ b/pkg/interface/src/logic/lib/omnibox.js @@ -4,7 +4,8 @@ import defaultApps from './default-apps'; ['commands', []], ['subscriptions', []], ['groups', []], - ['apps', []] + ['apps', []], + ['other', []] ]); // result schematic @@ -41,8 +42,6 @@ const commandIndex = function () { } }); - commands.push(result('Profile', '/~profile', 'profile', null)); - return commands; }; @@ -54,6 +53,9 @@ const appIndex = function (apps) { .filter((e) => { return apps[e]?.type?.basic; }) + .sort((a,b) => { + return a.localeCompare(b); + }) .map((e) => { const obj = result( apps[e].type.basic.title, @@ -70,6 +72,14 @@ const appIndex = function (apps) { return applications; }; +const otherIndex = function() { + const other = []; + other.push(result('Profile and Settings', '/~profile/identity', 'profile', null)); + other.push(result('Log Out', '/~/logout', 'logout', null)); + + return other; +}; + export default function index(associations, apps) { // all metadata from all apps is indexed // into subscriptions and groups @@ -118,6 +128,7 @@ export default function index(associations, apps) { indexes.set('subscriptions', subscriptions); indexes.set('groups', groups); indexes.set('apps', appIndex(apps)); + indexes.set('other', otherIndex()); return indexes; }; diff --git a/pkg/interface/src/views/components/leap/Omnibox.js b/pkg/interface/src/views/components/leap/Omnibox.js index 624229d20a..190220f961 100644 --- a/pkg/interface/src/views/components/leap/Omnibox.js +++ b/pkg/interface/src/views/components/leap/Omnibox.js @@ -26,11 +26,15 @@ export class Omnibox extends Component { this.renderResults = this.renderResults.bind(this); } - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps, prevState) { if (prevProps !== this.props) { this.setState({ index: index(this.props.associations, this.props.apps.tiles) }); } + if (prevProps && (prevProps.apps !== this.props.apps) && (this.state.query === '')) { + this.setState({ results: this.initialResults() }); + } + if (prevProps && this.props.show && prevProps.show !== this.props.show) { Mousetrap.bind('escape', () => this.props.api.local.setOmnibox()); document.addEventListener('mousedown', this.handleClickOutside); @@ -48,7 +52,7 @@ export class Omnibox extends Component { } getSearchedCategories() { - return ['apps', 'commands', 'groups', 'subscriptions']; + return ['apps', 'commands', 'groups', 'subscriptions', 'other']; } control(evt) { @@ -91,7 +95,18 @@ export class Omnibox extends Component { } initialResults() { - return new Map(this.getSearchedCategories().map(category => [category, []])); + return new Map(this.getSearchedCategories().map((category) => { + if (!this.state) { + return [category, []]; + } + if (category === 'apps') { + return ['apps', this.state.index.get('apps')]; + } + if (category === 'other') { + return ['other', this.state.index.get('other')]; + } + return [category, []]; + })); } navigate(link) { @@ -202,10 +217,12 @@ export class Omnibox extends Component { {this.getSearchedCategories() .map(category => Object({ category, categoryResults: state.results.get(category) })) .filter(category => category.categoryResults.length > 0) - .map(({ category, categoryResults }, i) => ( - + .map(({ category, categoryResults }, i) => { + const categoryTitle = (category === 'other') + ? null : {category.charAt(0).toUpperCase() + category.slice(1)}; + return ( - {category.charAt(0).toUpperCase() + category.slice(1)} + {categoryTitle} {categoryResults.map((result, i2) => ( ))} - )) + ); + }) } ; } diff --git a/pkg/interface/src/views/components/leap/OmniboxResult.js b/pkg/interface/src/views/components/leap/OmniboxResult.js index 589ab12b75..c8ccda3ed3 100644 --- a/pkg/interface/src/views/components/leap/OmniboxResult.js +++ b/pkg/interface/src/views/components/leap/OmniboxResult.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { Row, Icon, Text } from '@tlon/indigo-react'; import defaultApps from '~/logic/lib/default-apps'; +import Sigil from '~/logic/lib/sigil'; export class OmniboxResult extends Component { constructor(props) { @@ -24,35 +25,58 @@ export class OmniboxResult extends Component { } } - setHover(boolean) { - this.setState({ hovered: boolean }); - } - render() { - const { icon, text, subtext, link, navigate, selected, dark } = this.props; - - let invertGraphic = {}; + getIcon(icon, dark, selected, link) { + // graphicStyle is only necessary for pngs + // + //TODO can be removed after indigo-react 1.2 + //which includes icons for apps + let graphicStyle = {}; if (icon.toLowerCase() !== 'dojo') { - invertGraphic = (!dark && this.state.hovered) || - selected === link || - (dark && !(this.state.hovered || selected === link)) - ? { filter: 'invert(1)', paddingTop: 2 } - : { filter: 'invert(0)', paddingTop: 2 }; - } else { - invertGraphic = - (!dark && this.state.hovered) || + graphicStyle = (!dark && this.state.hovered) || selected === link || (dark && !(this.state.hovered || selected === link)) - ? { filter: 'invert(0)', paddingTop: 2 } - : { filter: 'invert(1)', paddingTop: 2 }; + ? { filter: 'invert(1)' } + : { filter: 'invert(0)' }; + } else { + graphicStyle = + (!dark && this.state.hovered) || + selected === link || + (dark && !(this.state.hovered || selected === link)) + ? { filter: 'invert(0)' } + : { filter: 'invert(1)' }; } + const iconFill = this.state.hovered || selected === link ? 'white' : 'black'; + const sigilFill = this.state.hovered || selected === link ? '#3a8ff7' : '#ffffff'; + let graphic =
; if (defaultApps.includes(icon.toLowerCase()) || icon.toLowerCase() === 'links') { - graphic = ; + graphic = + ; + } else if (icon === 'logout') { + graphic = ; + } else if (icon === 'profile') { + graphic = ; } else { - graphic = ; + graphic = ; } + + return graphic; + } + + setHover(boolean) { + this.setState({ hovered: boolean }); + } + + render() { + const { icon, text, subtext, link, navigate, selected, dark } = this.props; + + const graphic = this.getIcon(icon, dark, selected, link); + return ( {graphic} - + {text} - + {subtext} ) : ( <> {graphic} - {text} - + {text} + {subtext} From e2df23eca65731982e59d26ca045ff77b1615a51 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Tue, 1 Sep 2020 16:08:50 -0400 Subject: [PATCH 29/58] leap: show group's name, not the host ship --- pkg/interface/src/logic/lib/omnibox.js | 5 +++-- pkg/interface/src/views/components/leap/Omnibox.js | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/interface/src/logic/lib/omnibox.js b/pkg/interface/src/logic/lib/omnibox.js index 49bf777261..ee616ddc93 100644 --- a/pkg/interface/src/logic/lib/omnibox.js +++ b/pkg/interface/src/logic/lib/omnibox.js @@ -1,4 +1,5 @@ import defaultApps from './default-apps'; +import { cite } from '~/logic/lib/util'; const indexes = new Map([ ['commands', []], @@ -109,7 +110,7 @@ export default function index(associations, apps) { title, `/~${app}${each['app-path']}`, app.charAt(0).toUpperCase() + app.slice(1), - shipStart.slice(0, shipStart.indexOf('/')) + cite(shipStart.slice(0, shipStart.indexOf('/'))) ); groups.push(obj); } else { @@ -117,7 +118,7 @@ export default function index(associations, apps) { title, `/~${each['app-name']}/join${each['app-path']}`, app.charAt(0).toUpperCase() + app.slice(1), - shipStart.slice(0, shipStart.indexOf('/')) + (associations?.contacts?.[each['group-path']]?.metadata?.title || null) ); subscriptions.push(obj); } diff --git a/pkg/interface/src/views/components/leap/Omnibox.js b/pkg/interface/src/views/components/leap/Omnibox.js index 190220f961..4a4b484ace 100644 --- a/pkg/interface/src/views/components/leap/Omnibox.js +++ b/pkg/interface/src/views/components/leap/Omnibox.js @@ -6,8 +6,6 @@ import Mousetrap from 'mousetrap'; import OmniboxInput from './OmniboxInput'; import OmniboxResult from './OmniboxResult'; -import { cite } from '~/logic/lib/util'; - export class Omnibox extends Component { constructor(props) { super(props); @@ -228,7 +226,7 @@ export class Omnibox extends Component { key={i2} icon={result.app} text={result.title} - subtext={cite(result.host)} + subtext={result.host} link={result.link} navigate={() => this.navigate(result.link)} selected={this.state.selected} From 24753dd0c89c083820ba437da6d7f0f8dc986437 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Tue, 1 Sep 2020 16:23:42 -0400 Subject: [PATCH 30/58] leap: better compensate for long titles --- .../views/components/leap/OmniboxResult.js | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/pkg/interface/src/views/components/leap/OmniboxResult.js b/pkg/interface/src/views/components/leap/OmniboxResult.js index c8ccda3ed3..89dde65f1f 100644 --- a/pkg/interface/src/views/components/leap/OmniboxResult.js +++ b/pkg/interface/src/views/components/leap/OmniboxResult.js @@ -96,18 +96,45 @@ export class OmniboxResult extends Component { {this.state.hovered || selected === link ? ( <> {graphic} - + {text} - + {subtext} ) : ( <> {graphic} - {text} - + + {text} + + {subtext} From baf2226e3dc5e81bff991e02c509307883ae32e8 Mon Sep 17 00:00:00 2001 From: Tyler Brown Cifu Shuster Date: Tue, 1 Sep 2020 17:17:28 -0700 Subject: [PATCH 31/58] chat: break up inline code while maintaining multiline codeblocks --- pkg/interface/src/views/apps/chat/css/custom.css | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/css/custom.css b/pkg/interface/src/views/apps/chat/css/custom.css index 052fb06282..6294427bd0 100644 --- a/pkg/interface/src/views/apps/chat/css/custom.css +++ b/pkg/interface/src/views/apps/chat/css/custom.css @@ -252,12 +252,13 @@ blockquote { font-family: 'Inter'; } -code { - white-space: normal; +pre, code { + background-color: var(--light-gray); } -code, pre.code { - background-color: var(--light-gray); +pre code { + background-color: transparent; + white-space: pre-wrap; } code, .code, .chat.code .react-codemirror2 .CodeMirror * { From 630b79ad372fe0dcd183a00550265eca11bcca71 Mon Sep 17 00:00:00 2001 From: Tyler Brown Cifu Shuster Date: Sun, 23 Aug 2020 21:40:31 -0700 Subject: [PATCH 32/58] links: added s3 integration --- pkg/interface/src/logic/store/links.js | 4 + .../apps/chat/components/lib/chat-input.js | 52 +++++---- .../apps/chat/components/lib/s3-upload.js | 105 ------------------ .../groups/components/lib/contact-card.js | 12 +- pkg/interface/src/views/apps/links/app.js | 3 +- .../apps/links/components/lib/link-submit.js | 103 ++++++++++------- .../views/apps/links/components/links-list.js | 2 +- .../src/views/apps/links/components/new.js | 5 +- pkg/interface/src/views/components/Spinner.js | 2 +- .../lib => components}/s3-upload.js | 72 +++++++----- 10 files changed, 159 insertions(+), 201 deletions(-) delete mode 100644 pkg/interface/src/views/apps/chat/components/lib/s3-upload.js rename pkg/interface/src/views/{apps/groups/components/lib => components}/s3-upload.js (54%) diff --git a/pkg/interface/src/logic/store/links.js b/pkg/interface/src/logic/store/links.js index d8d7fd7dd4..eb395603fa 100644 --- a/pkg/interface/src/logic/store/links.js +++ b/pkg/interface/src/logic/store/links.js @@ -6,6 +6,7 @@ import InviteReducer from '../reducers/invite-update'; import LinkReducer from '../reducers/link-update'; import ListenReducer from '../reducers/listen-update'; import LocalReducer from '../reducers/local'; +import S3Reducer from '../reducers/s3-update'; import BaseStore from './base'; @@ -21,6 +22,7 @@ export default class LinksStore extends BaseStore { this.localReducer = new LocalReducer(); this.linkReducer = new LinkReducer(); this.listenReducer = new ListenReducer(); + this.s3Reducer = new S3Reducer(); } initialState() { @@ -37,6 +39,7 @@ export default class LinksStore extends BaseStore { comments: {}, seen: {}, permissions: {}, + s3: {}, sidebarShown: true }; } @@ -50,6 +53,7 @@ export default class LinksStore extends BaseStore { this.localReducer.reduce(data, this.state); this.linkReducer.reduce(data, this.state); this.listenReducer.reduce(data, this.state); + this.s3Reducer.reduce(data, this.state); } } diff --git a/pkg/interface/src/views/apps/chat/components/lib/chat-input.js b/pkg/interface/src/views/apps/chat/components/lib/chat-input.js index c4919cefce..1cc8990422 100644 --- a/pkg/interface/src/views/apps/chat/components/lib/chat-input.js +++ b/pkg/interface/src/views/apps/chat/components/lib/chat-input.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import ChatEditor from './chat-editor'; -import { S3Upload } from './s3-upload' +import { S3Upload } from '~/views/components/s3-upload' ; import { uxToHex } from '~/logic/lib/util'; import { Sigil } from '~/logic/lib/sigil'; @@ -221,10 +221,10 @@ export class ChatInput extends Component { style={{ flexGrow: 1 }}>
+ marginTop: 6, + flexBasis: 24, + height: 24 + }}> {avatar}
+ height: '16px', + width: '16px', + flexBasis: 16, + marginTop: 10 + }}> + accept="image/*" + > + +
+ filter: state.inCodeMode && 'invert(100%)', + height: '14px', + width: '14px', + }} + onClick={this.toggleCode} + src="/~chat/img/CodeEval.png" + className="contrast-10-d bg-white bg-none-d ba b--gray1-d br1" />
); diff --git a/pkg/interface/src/views/apps/chat/components/lib/s3-upload.js b/pkg/interface/src/views/apps/chat/components/lib/s3-upload.js deleted file mode 100644 index b497413cfd..0000000000 --- a/pkg/interface/src/views/apps/chat/components/lib/s3-upload.js +++ /dev/null @@ -1,105 +0,0 @@ -import React, { Component } from 'react'; -import S3Client from '~/logic/lib/s3'; - -export class S3Upload extends Component { - constructor(props) { - super(props); - this.s3 = new S3Client(); - this.setCredentials(props.credentials, props.configuration); - this.inputRef = React.createRef(); - } - - isReady(creds, config) { - return ( - Boolean(creds) && - 'endpoint' in creds && - 'accessKeyId' in creds && - 'secretAccessKey' in creds && - creds.endpoint !== '' && - creds.accessKeyId !== '' && - creds.secretAccessKey !== '' && - Boolean(config) && - 'currentBucket' in config && - config.currentBucket !== '' - ); - } - - componentDidUpdate(prevProps) { - const { props } = this; - this.setCredentials(props.credentials, props.configuration); - } - - setCredentials(credentials, configuration) { - if (!this.isReady(credentials, configuration)) { - return; -} - this.s3.setCredentials( - credentials.endpoint, - credentials.accessKeyId, - credentials.secretAccessKey - ); - } - - getFileUrl(endpoint, filename) { - return endpoint + '/' + filename; - } - - onChange() { - const { props } = this; - if (!this.inputRef.current) { - return; -} - const files = this.inputRef.current.files; - if (files.length <= 0) { - return; -} - - const file = files.item(0); - const bucket = props.configuration.currentBucket; - - this.s3.upload(bucket, file.name, file).then((data) => { - if (!data || !('Location' in data)) { - return; - } - this.props.uploadSuccess(data.Location); - }).catch((err) => { - console.error(err); - this.props.uploadError(err); - }); - } - - onClick() { - if (!this.inputRef.current) { - return; - } - this.inputRef.current.click(); - } - - render() { - const { props } = this; - if (!this.isReady(props.credentials, props.configuration)) { - return
; - } else { - const classes = props.className ? - 'pointer ' + props.className : 'pointer'; - return ( -
- - -
- ); - } - } -} - diff --git a/pkg/interface/src/views/apps/groups/components/lib/contact-card.js b/pkg/interface/src/views/apps/groups/components/lib/contact-card.js index 572f2f2f06..40d44ae690 100644 --- a/pkg/interface/src/views/apps/groups/components/lib/contact-card.js +++ b/pkg/interface/src/views/apps/groups/components/lib/contact-card.js @@ -5,7 +5,7 @@ import { Link } from 'react-router-dom'; import { EditElement } from './edit-element'; import { Spinner } from '~/views/components/Spinner'; import { uxToHex } from '~/logic/lib/util'; -import { S3Upload } from './s3-upload'; +import { S3Upload } from '~/views/components/s3-upload'; export class ContactCard extends Component { constructor(props) { @@ -492,7 +492,15 @@ export class ContactCard extends Component { credentials={props.s3.credentials} uploadSuccess={this.uploadSuccess.bind(this)} uploadError={this.uploadError.bind(this)} - /> + accept="image/*" + > + + @@ -256,6 +256,7 @@ export class LinksApp extends Component { api={api} hideNicknames={hideNicknames} hideAvatars={hideAvatars} + s3={s3} /> ); diff --git a/pkg/interface/src/views/apps/links/components/lib/link-submit.js b/pkg/interface/src/views/apps/links/components/lib/link-submit.js index 780df3d88e..042ce804e5 100644 --- a/pkg/interface/src/views/apps/links/components/lib/link-submit.js +++ b/pkg/interface/src/views/apps/links/components/lib/link-submit.js @@ -1,5 +1,8 @@ import React, { Component } from 'react'; + +import { S3Upload } from '~/views/components/s3-upload'; import { Spinner } from '~/views/components/Spinner'; +import { Icon } from "@tlon/indigo-react"; export class LinkSubmit extends Component { constructor() { @@ -60,23 +63,29 @@ export class LinkSubmit extends Component { this.setState({ linkTitle: event.target.value }); } + uploadSuccess(url) { + this.setState({ linkValue: url }); + this.setLinkValid(url); + } + + uploadError(error) { + // no-op for now + } + render() { + console.log('s3', this.props.s3); const activeClasses = (this.state.linkValid && !this.state.disabled) ? 'green2 pointer' : 'gray2'; const focus = (this.state.submitFocus) ? 'b--black b--white-d' : 'b--gray4 b--gray2-d'; - + return (
-