From 30b551323bf334a61de9f733b638308fd2d9fa1e Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 12 Jan 2021 09:05:22 +1000 Subject: [PATCH 01/61] lib/agentio: add helper library for constructing cards --- pkg/arvo/lib/agentio.hoon | 103 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 pkg/arvo/lib/agentio.hoon diff --git a/pkg/arvo/lib/agentio.hoon b/pkg/arvo/lib/agentio.hoon new file mode 100644 index 000000000..14e0c8cd8 --- /dev/null +++ b/pkg/arvo/lib/agentio.hoon @@ -0,0 +1,103 @@ +=> + |% + ++ card card:agent:gall + -- +:: +|_ =bowl:gall +++ scry + |* [desk=@tas =path] + ?> ?=(^ path) + ?> ?=(^ t.path) + %+ weld + /(scot %p our.bowl)/[desk]/(scot %da now.bowl) + t.t.path +:: +++ pass + |_ =wire + ++ poke + |= [=dock =cage] + [%pass wire %agent dock %poke cage] + :: + ++ poke-our + |= [app=term =cage] + ^- card + (poke [our.bowl app] cage) + :: + ++ arvo + |= =note-arvo + ^- card + [%pass wire %arvo note-arvo] + :: + ++ watch + |= [=dock =path] + [%pass (watch-wire path) %agent dock %watch path] + :: + ++ watch-our + |= [app=term =path] + (watch [our.bowl app] path) + :: + ++ watch-wire + |= =path + ^+ wire + ?. ?=(~ wire) + wire + agentio-watch+path + :: + ++ leave + |= =dock + [%pass wire %agent dock %leave ~] + :: + ++ leave-our + |= app=term + (leave our.bowl app) + :: + ++ leave-path + |= [=dock =path] + =. wire + (watch-wire path) + (leave dock) + :: + ++ wait + |= p=@da + (arvo %b %wait p) + :: + ++ rest + |= p=@da + (arvo %b %wait p) + :: + ++ warp + |= [wer=ship =riff:clay] + (arvo %c %warp wer riff) + :: + ++ warp-our + |= =riff:clay + (warp our.bowl riff) + :: + :: right here, right now + ++ warp-slim + |= [genre=?(%sing %next) =care:clay =path] + =/ =mood:clay + [care r.byk.bowl path] + =/ =rave:clay + ?:(?=(%sing genre) [genre mood] [genre mood]) + (warp-our q.byk.bowl `rave) + -- +:: +++ fact-curry + |* [=mark =mold] + |= [paths=(list path) fac=mold] + (fact mark^!>(fac) paths) +:: +++ fact + |= [=cage paths=(list path)] + ^- card + [%give %fact paths cage] +:: +++ kick + |= paths=(list path) + [%give %kick paths ~] +:: +++ kick-only + |= [=ship paths=(list path)] + [%give %kick paths `ship] +-- From 5a24de979a7be0011b4b5e57ea5968dac823eccb Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 12 Jan 2021 09:05:39 +1000 Subject: [PATCH 02/61] graph-view: first draft --- pkg/arvo/app/graph-view.hoon | 226 +++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 pkg/arvo/app/graph-view.hoon diff --git a/pkg/arvo/app/graph-view.hoon b/pkg/arvo/app/graph-view.hoon new file mode 100644 index 000000000..eb281e7ae --- /dev/null +++ b/pkg/arvo/app/graph-view.hoon @@ -0,0 +1,226 @@ +/- view-sur=graph-view, group-store, *group, *metadata-store +/+ default-agent, agentio, mdl=metadata, resource, dbug +|% +++ card card:agent:gall ++$ state-zero + $: %0 + joining=(map @uv [rid=resource =ship]) + == +-- +=| state-zero +=* state - +:: +%- agent:dbug +^- agent:gall +=< +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) + gc ~(. +> bowl) + io ~(. agentio bowl) +++ on-init + `this +++ on-save + !>(state) +:: +++ on-load + |= =vase + `this +:: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + ?. ?=(%graph-view-action mark) + (on-poke:def mark vase) + =+ !<(=action:view-sur vase) + =^ cards state + ?+ -.action `state + %join + (jn-start:join:gc +.action) + == + [cards this] +:: +++ on-watch + |= =path + `this +:: +++ on-peek + |= =path + [~ ~] +:: +++ on-agent + |= [=wire =sign:agent:gall] + =^ cards state + ?+ wire `state + [%join @ *] + =/ uid=@uv + (slav %uv i.t.wire) + (jn-agent:(jn-abed:join:gc uid) t.t.wire sign) + == + [cards this] +:: +++ on-arvo + |= [=wire =sign-arvo] + `this +:: +++ on-leave + |= =path + `this +:: +++ on-fail + |= [=term =tang] + `this +-- +|_ =bowl:gall +++ met ~(. mdl bowl) +++ io ~(. agentio bowl) +:: +++ tx-fact + |= [kind=@tas uid=@uv fact=@tas] + (fact:io graph-view-update+!>([kind uid fact]) /all /tx/(scot %uv uid) ~) +:: +++ join + |_ [uid=@uv rid=resource =ship] + ++ jn-core . + ++ jn-pass-io + |= =path + ~(. pass:io (weld /join/(scot %uv uid) path)) + :: + ++ jn-abed + |= uid=@uv + =/ [r=resource s=^ship] + (~(got by joining) uid) + jn-core(uid uid, rid r, ship s) + :: + ++ jn-start + |= [rid=resource =^ship] + ^- (quip card _state) + =/ uid=@uv + (shaf %join eny.bowl) + =. jn-core + jn-core(uid uid, rid rid, ship ship) + =/ maybe-group + (group-from-app-resource:met %contacts rid) + :_ state(joining (~(put by joining) uid [rid ship])) + :_ ~ + ?^ maybe-group + %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook + pull-hook-action+!>([%add rid ship]) + %+ poke:(jn-pass-io /add) + [ship %group-push-hook] + group-update+!>([%add-members rid (silt our.bowl ~)]) + :: + ++ jn-agent + |= [=wire =sign:agent:gall] + ^- (quip card _state) + |^ + ?+ -.wire ~|("bad %join wire" !!) + %add :: join group + ?> ?=(%poke-ack -.sign) + ?^ p.sign + join-failed + joined + :: + %pull-groups + ?> ?=(%poke-ack -.sign) + ?~ p.sign + :: do nothing, wait for update from store + `state + :: shouldn't ever fail + weird-failure + :: + %groups + ?+ -.sign !! + %fact (groups-fact +.sign) + %watch-ack (ack +.sign) + %kick groups-kick + == + :: + %pull-md + ?> ?=(%poke-ack -.sign) + ?~ p.sign `state + weird-failure + :: + %md + ?+ -.sign !! + %fact (md-fact +.sign) + %watch-ack (ack +.sign) + %kick md-kick + == + :: + %pull-graph + ?> ?=(%poke-ack -.sign) + ?^ p.sign + weird-failure + :_ state(joining (~(del by joining) uid)) + (tx-fact %join uid %done)^~ + == + ++ groups-fact + |= =cage + ?. ?=(%group-update p.cage) + `state + =+ !<(=update:group-store q.cage) + ?. ?=(%initial-group -.update) + `state + ?. =(rid resource.update) + `state + :_ state + :~ + (leave-our:(jn-pass-io /groups) %group-store) + :: + %+ poke-our:(jn-pass-io /pull-md) %metadata-hook + metadata-hook-action+!>([%add-synced ship (en-path:resource rid)]) + == + :: + ++ md-fact + |= [=mark =vase] + :_ state + ?. ?=(%metadata-update mark) ~ + =+ !<(upd=metadata-update vase) + ?. ?=(%add -.upd) ~ + ?. =(group-path.upd (en-path:resource rid)) ~ + :~ + (leave-our:(jn-pass-io /md) %metadata-store) + %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook + pull-hook-action+!>([%add ship rid]) + == + ++ watch-md + (watch-our:(jn-pass-io /md) %metadata-store /updates) + :: + ++ watch-groups + (watch-our:(jn-pass-io /groups) %group-store /groups) + :: + ++ groups-kick + :_ state + watch-groups^~ + :: + ++ md-kick + :_ state + watch-md^~ + :: + ++ ack + |= err=(unit tang) + ?~ err `state + weird-failure + :: + ++ join-failed + :: failed do not continue + :_ state(joining (~(del by joining) uid)) + (tx-fact %join uid %no-perms)^~ + :: + ++ joined + :_ state + :~ + watch-groups + :: + %+ poke-our:(jn-pass-io /pull-group) %group-pull-hook + pull-hook-action+!>([%add ship rid]) + == + :: + ++ weird-failure + ~& >>> "Weird failure joining {}, please report" + :_ state(joining (~(del by joining) uid)) + (tx-fact %join uid %strange)^~ + -- + -- +-- From 1f7f86f682584dcbd1caeb7ed1008685fc92c2a9 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 7 Jan 2021 16:49:24 -0600 Subject: [PATCH 03/61] contact-store: first approach at rewrite --- pkg/arvo/app/contact-hook.hoon | 580 +------------------------- pkg/arvo/app/contact-store.hoon | 393 ++++++----------- pkg/arvo/app/contact-view.hoon | 349 +--------------- pkg/arvo/app/group-store.hoon | 14 +- pkg/arvo/app/invite-store.hoon | 63 ++- pkg/arvo/lib/contact-json.hoon | 265 ------------ pkg/arvo/lib/contact-store.hoon | 123 ++++++ pkg/arvo/mar/contact/action.hoon | 15 - pkg/arvo/mar/contact/hook-update.hoon | 15 - pkg/arvo/mar/contact/initial.hoon | 16 - pkg/arvo/mar/contact/update.hoon | 11 +- pkg/arvo/mar/contact/view-action.hoon | 12 - pkg/arvo/sur/contact-hook.hoon | 18 - pkg/arvo/sur/contact-store.hoon | 29 +- pkg/arvo/sur/contact-view.hoon | 27 -- 15 files changed, 337 insertions(+), 1593 deletions(-) delete mode 100644 pkg/arvo/lib/contact-json.hoon create mode 100644 pkg/arvo/lib/contact-store.hoon delete mode 100644 pkg/arvo/mar/contact/action.hoon delete mode 100644 pkg/arvo/mar/contact/hook-update.hoon delete mode 100644 pkg/arvo/mar/contact/initial.hoon delete mode 100644 pkg/arvo/mar/contact/view-action.hoon delete mode 100644 pkg/arvo/sur/contact-hook.hoon delete mode 100644 pkg/arvo/sur/contact-view.hoon diff --git a/pkg/arvo/app/contact-hook.hoon b/pkg/arvo/app/contact-hook.hoon index 56311fa51..fc77f2b1d 100644 --- a/pkg/arvo/app/contact-hook.hoon +++ b/pkg/arvo/app/contact-hook.hoon @@ -1,571 +1,27 @@ -:: contact-hook [landscape] +:: contact-hook [landscape]: deprecated :: -:: -/- *contact-hook, - *contact-view, - inv=invite-store, - *metadata-hook, - *metadata-store, - *group -/+ *contact-json, - default-agent, - dbug, - group-store, - verb, - resource, - grpl=group, - *migrate -~% %contact-hook-top ..part ~ +/+ default-agent |% +$ card card:agent:gall -:: -+$ versioned-state - $% state-zero - state-one - state-two - state-three - == -:: -+$ state-zero [%0 state-base] -+$ state-one [%1 state-base] -+$ state-two [%2 state-base] -+$ state-three [%3 state-base] -+$ state-base - $: =synced - invite-created=_| - == -- -=| state-three -=* state - -%- agent:dbug -%+ verb | +:: ^- agent:gall -=< - |_ bol=bowl:gall - +* this . - contact-core +> - cc ~(. contact-core bol) - def ~(. (default-agent this %|) bol) - :: - ++ on-init - ^- (quip card _this) - :_ this(invite-created %.y) - :~ (invite-poke:cc [%create %contacts]) - [%pass /inv %agent [our.bol %invite-store] %watch /invitatory/contacts] - [%pass /group %agent [our.bol %group-store] %watch /groups] - == - ++ on-save !>(state) - ++ on-load - |= old-vase=vase - ^- (quip card _this) - =/ old !<(versioned-state old-vase) - =| cards=(list card) - |^ - |- ^- (quip card _this) - ?: ?=(%3 -.old) - [cards this(state old)] - ?: ?=(%2 -.old) - %_ $ - old [%3 +.old] - :: - cards - %+ welp - cards - %- zing - %+ turn - ~(tap by synced.old) - |= [=path =ship] - ^- (list card) - ?. =(ship our.bol) - ~ - ?> ?=([%ship *] path) - :~ (pass-store contacts+t.path %leave ~) - (pass-store contacts+path %watch contacts+path) - == - == - ?: ?=(%1 -.old) - %_ $ - -.old %2 - :: - synced.old - %- malt - %+ turn - ~(tap by synced.old) - |= [=path =ship] - [ship+path ship] - :: - cards - ^- (list card) - ;: welp - :~ [%pass /group %agent [our.bol %group-store] %leave ~] - [%pass /group %agent [our.bol %group-store] %watch /groups] - == - kick-old-subs - cards - == - == - %_ $ - -.old %1 - :: - cards - :_ cards - [%pass /group %agent [our.bol %group-store] %watch /updates] - == - ++ kick-old-subs - =/ paths - %+ turn - ~(val by sup.bol) - |=([=ship =path] path) - ?~ paths ~ - [%give %kick paths ~]~ - :: - ++ pass-store - |= [=wire =task:agent:gall] - ^- card - [%pass wire %agent [our.bol %contact-store] task] - -- - :: - ++ on-poke - |= [=mark =vase] - ^- (quip card _this) - =^ cards state - ?+ mark (on-poke:def mark vase) - %json - (poke-json:cc !<(json vase)) - :: - %contact-action - (poke-contact-action:cc !<(contact-action vase)) - :: - %contact-hook-action - (poke-hook-action:cc !<(contact-hook-action vase)) - :: - %import - ?> (team:title our.bol src.bol) - (poke-import:cc q.vase) - == - [cards this] - :: - ++ on-watch - |= =path - ^- (quip card _this) - ?+ path (on-watch:def path) - [%contacts *] [(watch-contacts:cc t.path) this] - [%synced *] [(watch-synced:cc t.path) this] - == - :: - ++ on-agent - |= [=wire =sign:agent:gall] - ^- (quip card _this) - ?+ -.sign (on-agent:def wire sign) - %kick [(kick:cc wire) this] - %watch-ack - =^ cards state - (watch-ack:cc wire p.sign) - [cards this] - :: - %fact - ?+ p.cage.sign (on-agent:def wire sign) - %contact-update - =^ cards state - (fact-contact-update:cc wire !<(contact-update q.cage.sign)) - [cards this] - :: - %group-update - =^ cards state - (fact-group-update:cc wire !<(update:group-store q.cage.sign)) - [cards this] - :: - %invite-update [~ this] - == - == - :: - ++ on-leave on-leave:def - ++ on-peek - |= =path - ^- (unit (unit cage)) - ?+ path (on-peek:def path) - [%x %export ~] - ``noun+!>(state) - [%x %synced ~] - ``noun+!>(~(key by synced)) - == - ++ on-arvo - |= [=wire =sign-arvo] - ^- (quip card _this) - ?. ?=([%try-rejoin @ @ *] wire) - (on-arvo:def wire sign-arvo) - =/ nack-count=@ud (slav %ud i.t.wire) - =/ who=@p (slav %p i.t.t.wire) - =/ pax t.t.t.wire - ?> ?=([%behn %wake *] sign-arvo) - ~? ?=(^ error.sign-arvo) - "behn errored in backoff timers, continuing anyway" - :_ this - [(try-rejoin:cc who pax +(nack-count))]~ - :: - ++ on-fail on-fail:def - -- -:: |_ bol=bowl:gall -++ grp ~(. grpl bol) ++* this . + def ~(. (default-agent this %|) bol) :: -++ poke-json - |= jon=json - ^- (quip card _state) - (poke-contact-action (json-to-action jon)) +++ on-init on-init:def +++ on-poke on-poke:def +++ on-watch on-watch:def +++ on-agent on-agent:def +++ on-arvo on-arvo:def +++ on-save !>(~) +++ on-load + |= old-vase=vase + ^- (quip card _this) + [~ this] :: -++ poke-contact-action - |= act=contact-action - ^- (quip card _state) - :_ state - ?+ -.act !! - %edit (handle-contact-action path.act ship.act act) - %add (handle-contact-action path.act ship.act act) - %remove (handle-contact-action path.act ship.act act) - == -:: -++ handle-contact-action - |= [=path =ship act=contact-action] - ^- (list card) - :: local - ?: (team:title our.bol src.bol) - ?. |(=(path /~/default) (~(has by synced) path)) ~ - =/ shp ?:(=(path /~/default) our.bol (~(got by synced) path)) - =/ appl ?:(=(shp our.bol) %contact-store %contact-hook) - [%pass / %agent [shp appl] %poke %contact-action !>(act)]~ - :: foreign - =/ shp (~(got by synced) path) - ?. |(=(shp our.bol) =(src.bol ship)) ~ - :: scry group to check if ship is a member - =/ =group (need (group-scry path)) - ?. (~(has in members.group) shp) ~ - [%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)]~ -:: -++ poke-hook-action - |= act=contact-hook-action - ^- (quip card _state) - ?- -.act - %add-owned - ?> (team:title our.bol src.bol) - =/ contact-path [%contacts path.act] - ?: (~(has by synced) path.act) - [~ state] - =. synced (~(put by synced) path.act our.bol) - :_ state - :~ [%pass contact-path %agent [our.bol %contact-store] %watch contact-path] - [%give %fact [/synced]~ %contact-hook-update !>([%initial synced])] - == - :: - %add-synced - ?> (team:title our.bol src.bol) - ?: (~(has by synced) path.act) [~ state] - =. synced (~(put by synced) path.act ship.act) - =/ contact-path [%contacts path.act] - :_ state - :~ [%pass contact-path %agent [ship.act %contact-hook] %watch contact-path] - [%give %fact [/synced]~ %contact-hook-update !>([%initial synced])] - == - :: - %remove - =/ ship (~(get by synced) path.act) - ?~ ship [~ state] - ?: &(=(u.ship our.bol) (team:title our.bol src.bol)) - :: delete one of our.bol own paths - :_ state(synced (~(del by synced) path.act)) - %- zing - :~ (pull-wire [%contacts path.act]) - [%give %kick ~[[%contacts path.act]] ~]~ - [%give %fact [/synced]~ %contact-hook-update !>([%initial synced])]~ - == - ?. |(=(u.ship src.bol) (team:title our.bol src.bol)) - :: if neither ship = source or source = us, do nothing - [~ state] - :: delete a foreign ship's path - =/ cards - (handle-contact-action path.act our.bol [%remove path.act our.bol]) - :_ state(synced (~(del by synced) path.act)) - %- zing - :~ (pull-wire [%contacts path.act]) - [%give %fact [/synced]~ %contact-hook-update !>([%initial synced])]~ - cards - == - == -:: -++ poke-import - |= arc=* - ^- (quip card _state) - =/ sty=state-three - [%3 (remake-map ;;((tree [path ship]) +<.arc)) ;;(? +>.arc)] - :_ sty - %+ turn ~(tap by synced.sty) - |= [=path =ship] - ^- card - =/ contact-path [%contacts path] - ?: =(our.bol ship) - [%pass contact-path %agent [our.bol %contact-store] %watch contact-path] - (try-rejoin ship contact-path 0) -:: -++ try-rejoin - |= [who=@p pax=path nack-count=@ud] - ^- card - =/ =wire - [%try-rejoin (scot %ud nack-count) (scot %p who) pax] - [%pass wire %agent [who %contact-hook] %watch pax] -:: -++ watch-contacts - |= pax=path - ^- (list card) - ?> ?=(^ pax) - ?> (~(has by synced) pax) - :: scry groups to check if ship is a member - =/ =group (need (group-scry pax)) - ?> (~(has in members.group) src.bol) - =/ contacts (need (contacts-scry pax)) - [%give %fact ~ %contact-update !>([%contacts pax contacts])]~ -:: -++ watch-synced - |= pax=path - ^- (list card) - ?> (team:title our.bol src.bol) - [%give %fact ~ %contact-hook-update !>([%initial synced])]~ -:: -++ watch-ack - |= [wir=wire saw=(unit tang)] - ^- (quip card _state) - ?~ saw - [~ state] - ?: ?=([%try-rejoin @ *] wir) - =/ nack-count=@ud (slav %ud i.t.wir) - =/ wakeup=@da - (add now.bol (mul ~s1 (bex (min 19 nack-count)))) - :_ state - [%pass wir %arvo %b %wait wakeup]~ - :: - ?> ?=(^ wir) - [~ state(synced (~(del by synced) t.wir))] -:: -++ migrate - |= wir=wire - ^- wire - ?> ?=([%contacts @ @ *] wir) - [%contacts %ship t.wir] -:: -++ kick - |= wir=wire - ^- (list card) - ?+ wir !! - [%try-rejoin @ @ *] - $(wir t.t.t.wir) - :: - [%inv ~] - [%pass /inv %agent [our.bol %invite-store] %watch /invitatory/contacts]~ - :: - [%group ~] - [%pass /group %agent [our.bol %group-store] %watch /groups]~ - :: - [%contacts @ *] - =/ wir - ?: =(%ship i.t.wir) - wir - (migrate wir) - ?> ?=([%contacts @ @ *] wir) - ?. (~(has by synced) t.wir) ~ - =/ =ship (~(got by synced) t.wir) - ?: =(ship our.bol) - [%pass wir %agent [our.bol %contact-store] %watch wir]~ - [%pass wir %agent [ship %contact-hook] %watch wir]~ - == -:: -++ fact-contact-update - |= [wir=wire fact=contact-update] - ^- (quip card _state) - |^ - ?: (team:title our.bol src.bol) - (local fact) - :_ state - (foreign fact) - :: - ++ give-fact - |= [=path update=contact-update] - ^- (list card) - [%give %fact ~[[%contacts path]] %contact-update !>(update)]~ - :: - ++ local - |= fact=contact-update - ^- (quip card _state) - ?+ -.fact [~ state] - %add - :_ state - (give-fact path.fact [%add path.fact ship.fact contact.fact]) - :: - %edit - :_ state - (give-fact path.fact [%edit path.fact ship.fact edit-field.fact]) - :: - %delete - =. synced (~(del by synced) path.fact) - `state - == - :: - ++ foreign - |= fact=contact-update - ^- (list card) - ?+ -.fact ~ - %contacts - =/ owner (~(got by synced) path.fact) - ?> =(owner src.bol) - =/ have-contacts=(unit contacts) - (contacts-scry path.fact) - ?~ have-contacts - :: if we don't have any contacts yet, - :: create the entry, and %add every contact - :: - :- (contact-poke [%create path.fact]) - %+ turn ~(tap by contacts.fact) - |= [=ship =contact] - (contact-poke [%add path.fact ship contact]) - :: if we already have some, decide between %add, %remove and recreate - :: on a per-contact basis - :: - %- zing - %+ turn - %~ tap in - %- ~(uni in ~(key by contacts.fact)) - ~(key by u.have-contacts) - |= =ship - ^- (list card) - =/ have=(unit contact) (~(get by u.have-contacts) ship) - =/ want=(unit contact) (~(get by contacts.fact) ship) - ?~ have - [(contact-poke %add path.fact ship (need want))]~ - ?~ want - [(contact-poke %remove path.fact ship)]~ - ?: =(u.want u.have) ~ - ::TODO probably want an %all edit-field that resolves to more granular - :: updates within the contact-store? - :~ (contact-poke %remove path.fact ship) - (contact-poke %add path.fact ship u.want) - == - :: - %add - =/ owner (~(get by synced) path.fact) - ?~ owner ~ - ?> |(=(u.owner src.bol) =(src.bol ship.fact)) - ~[(contact-poke [%add path.fact ship.fact contact.fact])] - :: - %remove - =/ owner (~(get by synced) path.fact) - ?~ owner ~ - ?> |(=(u.owner src.bol) =(src.bol ship.fact)) - ~[(contact-poke [%remove path.fact ship.fact])] - :: - %edit - =/ owner (~(got by synced) path.fact) - ?> |(=(owner src.bol) =(src.bol ship.fact)) - ~[(contact-poke [%edit path.fact ship.fact edit-field.fact])] - == - -- -:: -++ fact-group-update - |= [wir=wire fact=update:group-store] - ^- (quip card _state) - ?: ?=(%initial -.fact) - [~ state] - =/ group=(unit group) - (scry-group:grp resource.fact) - |^ - ?+ -.fact [~ state] - %initial-group (initial-group +.fact) - %remove-members (remove +.fact) - %remove-group (unbundle +.fact) - == - :: - ++ initial-group - |= [rid=resource =^group] - ^- (quip card _state) - ?: hidden.group [~ state] - =/ =path - (en-path:resource rid) - ?: (~(has by synced) path) - [~ state] - (poke-hook-action %add-synced entity.rid path) - :: - ++ unbundle - |= [rid=resource ~] - ^- (quip card _state) - =/ =path - (en-path:resource rid) - ?. (~(has by synced) path) - ?~ (contacts-scry path) - [~ state] - :_ state - [(contact-poke [%delete path])]~ - :_ state(synced (~(del by synced) path)) - :~ [%pass [%contacts path] %agent [our.bol %contact-store] %leave ~] - [(contact-poke [%delete path])] - == - :: - ++ remove - |= [rid=resource ships=(set ship)] - ^- (quip card _state) - :: if pax is synced, remove member from contacts and kick their sub - ?~ group - [~ state] - ?: hidden.u.group [~ state] - =/ =path - (en-path:resource rid) - =/ owner=(unit ship) (~(get by synced) path) - ?~ owner - :_ state - %+ turn ~(tap in ships) - |= =ship - (contact-poke [%remove path ship]) - :_ state - %- zing - %+ turn ~(tap in ships) - |= =ship - :~ [%give %kick ~[[%contacts path]] `ship] - ?: =(ship our.bol) - (contact-poke [%delete path]) - (contact-poke [%remove path ship]) - == - -- -:: -++ invite-poke - |= act=action:inv - ^- card - [%pass / %agent [our.bol %invite-store] %poke %invite-action !>(act)] -:: -++ contact-poke - |= act=contact-action - ^- card - [%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)] -:: -++ contacts-scry - |= pax=path - ^- (unit contacts) - =. pax - ;: weld - /(scot %p our.bol)/contact-store/(scot %da now.bol)/contacts - pax - /noun - == - .^((unit contacts) %gx pax) -:: -++ group-scry - |= pax=path - .^ (unit group) - %gx - ;:(weld /(scot %p our.bol)/group-store/(scot %da now.bol) /groups pax /noun) - == -:: -++ pull-wire - |= pax=path - ^- (list card) - ?> ?=(^ pax) - =/ shp (~(get by synced) t.pax) - ?~ shp ~ - ?: =(u.shp our.bol) - [%pass pax %agent [our.bol %contact-store] %leave ~]~ - [%pass pax %agent [u.shp %contact-hook] %leave ~]~ +++ on-leave on-leave:def +++ on-peek on-peek:def +++ on-fail on-fail:def -- diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index 7f4323a64..0b748ef0a 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -1,279 +1,154 @@ :: contact-store [landscape]: :: -:: data store that holds group-based contact data +:: data store that holds individual contact data :: -/+ *contact-json, default-agent, dbug, *migrate +/- store=contact-store +/+ default-agent, dbug, *migrate |% +$ card card:agent:gall ++$ state-4 [%4 =rolodex:store] +$ versioned-state - $% state-zero - state-one - state-two - state-three - == -:: -+$ rolodex-0 (map path contacts-0) -+$ contacts-0 (map ship contact-0) -+$ avatar-0 [content-type=@t octs=[p=@ud q=@t]] -+$ contact-0 - $: nickname=@t - email=@t - phone=@t - website=@t - notes=@t - color=@ux - avatar=(unit avatar-0) - == -:: -+$ state-zero - $: %0 - rolodex=rolodex-0 - == -+$ state-one - $: %1 - =rolodex - == -+$ state-two - $: %2 - =rolodex - == -+$ state-three - $: %3 - =rolodex + $% [%0 *] + [%1 *] + [%2 *] + [%3 *] + state-4 == -- :: -=| state-three +=| state-4 =* state - %- agent:dbug ^- agent:gall -=< - |_ =bowl:gall - +* this . - contact-core +> - cc ~(. contact-core bowl) - def ~(. (default-agent this %|) bowl) - :: - ++ on-init on-init:def - ++ on-save !>(state) - ++ on-load - |= old-vase=vase - =/ old !<(versioned-state old-vase) - =| cards=(list card) - |- - ?: ?=(%3 -.old) - [cards this(state old)] - ?: ?=(%2 -.old) - %_ $ - -.old %3 - :: - rolodex.old - =/ def - (~(get by rolodex.old) /ship/~/default) - ?~ def - rolodex.old - =. rolodex.old - (~(del by rolodex.old) /ship/~/default) - =. rolodex.old - (~(put by rolodex.old) /~/default u.def) - rolodex.old - == - ?: ?=(%1 -.old) - =/ new-rolodex=^rolodex - %- malt - %+ turn - ~(tap by rolodex.old) - |= [=path =contacts] - [ship+path contacts] - %_ $ - old [%2 new-rolodex] - :: - cards - =/ paths - %+ turn - ~(val by sup.bol) - |=([=ship =path] path) - ?~ paths cards - :_ cards - [%give %kick paths ~] - == - - =/ new-rolodex=^rolodex - %- ~(run by rolodex.old) - |= cons=contacts-0 - ^- contacts - %- ~(run by cons) - |= con=contact-0 - ^- contact - :* nickname.con - email.con - phone.con - website.con - notes.con - color.con - ~ - == - $(old [%1 new-rolodex]) - :: - ++ on-poke - |= [=mark =vase] - ^- (quip card _this) - ?> (team:title our.bowl src.bowl) - =^ cards state - ?+ mark (on-poke:def mark vase) - ::%json (poke-json:cc !<(json vase)) - %contact-action - (poke-contact-action:cc !<(contact-action vase)) - :: - %import - (poke-import:cc q.vase) - == - [cards this] - :: - ++ on-watch - |= =path - ^- (quip card _this) - ?> (team:title our.bowl src.bowl) - |^ - =/ cards=(list card) - ?+ path (on-watch:def path) - [%all ~] (give %contact-update !>([%initial rolodex])) - [%updates ~] ~ - [%contacts @ *] - %+ give %contact-update - !>([%contacts t.path (~(got by rolodex) t.path)]) - == - [cards this] - :: - ++ give - |= =cage - ^- (list card) - [%give %fact ~ cage]~ - -- - :: - ++ on-leave on-leave:def - ++ on-peek - |= =path - ^- (unit (unit cage)) - ?+ path (on-peek:def path) - [%x %all ~] ``noun+!>(rolodex) - [%x %contacts *] - ?~ t.t.path - ~ - ``noun+!>((~(get by rolodex) t.t.path)) - :: - [%x %contact *] - :: /:path/:ship - =/ pax `^path`(flop t.t.path) - ?~ pax ~ - =/ =ship (slav %p i.pax) - ?~ t.pax ~ - => .(pax `(list @ta)`(flop t.pax)) - =/ contacts=(unit contacts) (~(get by rolodex) pax) - ?~ contacts - ~ - ``noun+!>((~(get by u.contacts) ship)) - :: - [%x %export ~] - ``noun+!>(state) +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) +:: +++ on-init on-init:def +++ on-save !>(state) +++ on-load + |= old-vase=vase + ^- (quip card _this) + =/ old !<(versioned-state old-vase) + ?- -.old + %4 [~ this(state old)] + %3 [~ this] + %2 [~ this] + %1 [~ this] + %0 [~ this] + == +:: +++ on-watch + |= =path + ^- (quip card _this) + ?> (team:title our.bowl src.bowl) + |^ + =/ cards=(list card) + ?+ path (on-watch:def path) + [%updates ~] ~ == + [cards this] :: - ++ on-agent on-agent:def - ++ on-arvo on-arvo:def - ++ on-fail on-fail:def + ++ give + |= =cage + ^- (list card) + [%give %fact ~ cage]~ -- :: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + ?> (team:title our.bowl src.bowl) + |^ + =^ cards state + ?+ mark (on-poke:def mark vase) + %contact-update (update !<(update:store vase)) + %import (import q.vase) + == + [cards this] + :: + ++ update + |= =update:store + ^- (quip card _state) + |^ + ?- -.update + %initial (handle-initial +.update) + %add (handle-add +.update) + %remove (handle-remove +.update) + %edit (handle-edit +.update) + == + :: + ++ handle-initial + |= rolo=rolodex:store + ^- (quip card _state) + =. rolodex (~(uni by rolodex) rolo) + :_ state(rolodex rolodex) + (send-diff [%initial rolodex]) + :: + ++ handle-add + |= [=ship =contact:store] + ^- (quip card _state) + ?< (~(has by rolodex) ship) + :- (send-diff [%add ship contact]) + state(rolodex (~(put by rolodex) ship contact)) + :: + ++ handle-remove + |= =ship + ^- (quip card _state) + ?> (~(has by rolodex) ship) + :- (send-diff [%remove ship]) + state(rolodex (~(del by rolodex) ship)) + :: + ++ handle-edit + |= [=ship =edit-field:store] + ^- (quip card _state) + =/ contact (~(got by rolodex) ship) + =. contact (edit-contact contact edit-field) + :- (send-diff [%edit ship edit-field]) + state(rolodex (~(put by rolodex) ship contact)) + :: + ++ edit-contact + |= [=contact:store edit=edit-field:store] + ^- contact:store + ?- -.edit + %nickname contact(nickname nickname.edit) + %email contact(email email.edit) + %phone contact(phone phone.edit) + %website contact(website website.edit) + %color contact(color color.edit) + %avatar contact(avatar avatar.edit) + == + :: + ++ send-diff + |= =update:store + ^- (list card) + [%give %fact ~[/updates] %contact-update !>(update)]~ + -- + :: + ++ import + |= arc=* + ^- (quip card _state) + [~ *state-4] + -- :: -|_ bol=bowl:gall -:: -::++ poke-json -:: |= =json -:: ^- (quip move _this) -:: ?> (team:title our.bol src.bol) -:: (poke-contact-action (json-to-action json)) -:: -++ poke-contact-action - |= action=contact-action - ^- (quip card _state) - ?> (team:title our.bol src.bol) - ?- -.action - %create (handle-create +.action) - %delete (handle-delete +.action) - %add (handle-add +.action) - %remove (handle-remove +.action) - %edit (handle-edit +.action) +++ on-peek + |= =path + ^- (unit (unit cage)) + ?+ path (on-peek:def path) + [%x %all ~] ``noun+!>(rolodex) + [%x %export ~] ``noun+!>(state) + :: + [%x %contact @ ~] + =/ =ship (slav %p i.t.t.path) + =/ contact=(unit contact:store) (~(get by rolodex) ship) + ?~ contact ~ + :- ~ :- ~ :- %contact-update + !> ^- update:store + [%add ship u.contact] == :: -++ poke-import - |= arc=* - ^- (quip card _state) - =/ sty=state-three - :- %3 - %- remake-map-of-map - ;;((tree [path (tree [ship contact])]) +.arc) - [~ sty] -:: -++ handle-create - |= =path - ^- (quip card _state) - ?< (~(has by rolodex) path) - :- (send-diff path [%create path]) - state(rolodex (~(put by rolodex) path *contacts)) -:: -++ handle-delete - |= =path - ^- (quip card _state) - ?. (~(has by rolodex) path) [~ state] - :- (send-diff path [%delete path]) - state(rolodex (~(del by rolodex) path)) -:: -++ handle-add - |= [=path =ship =contact] - ^- (quip card _state) - =/ contacts (~(got by rolodex) path) - ?< (~(has by contacts) ship) - =. contacts (~(put by contacts) ship contact) - :- (send-diff path [%add path ship contact]) - state(rolodex (~(put by rolodex) path contacts)) -:: -++ handle-remove - |= [=path =ship] - ^- (quip card _state) - =/ contacts (~(got by rolodex) path) - ?. (~(has by contacts) ship) [~ state] - =. contacts (~(del by contacts) ship) - :- (send-diff path [%remove path ship]) - state(rolodex (~(put by rolodex) path contacts)) -:: -++ handle-edit - |= [=path =ship =edit-field] - ^- (quip card _state) - =/ contacts (~(got by rolodex) path) - =/ contact (~(got by contacts) ship) - =. contact (edit-contact contact edit-field) - =. contacts (~(put by contacts) ship contact) - :- (send-diff path [%edit path ship edit-field]) - state(rolodex (~(put by rolodex) path contacts)) -:: -++ edit-contact - |= [con=contact edit=edit-field] - ^- contact - ?- -.edit - %nickname con(nickname nickname.edit) - %email con(email email.edit) - %phone con(phone phone.edit) - %website con(website website.edit) - %notes con(notes notes.edit) - %color con(color color.edit) - %avatar con(avatar avatar.edit) - == -:: -++ send-diff - |= [pax=path upd=contact-update] - ^- (list card) - :~ :* - %give %fact - ~[/all /updates [%contacts pax]] - %contact-update !>(upd) - == == +++ on-leave on-leave:def +++ on-agent on-agent:def +++ on-arvo on-arvo:def +++ on-fail on-fail:def -- diff --git a/pkg/arvo/app/contact-view.hoon b/pkg/arvo/app/contact-view.hoon index 8b0a0d22c..68694b708 100644 --- a/pkg/arvo/app/contact-view.hoon +++ b/pkg/arvo/app/contact-view.hoon @@ -1,342 +1,27 @@ -:: contact-view [landscape]: -:: -:: sets up contact JS client and combines commands -:: into semantic actions for the UI -:: -/- - inv=invite-store, - *contact-hook, - *metadata-store, - *metadata-hook, - pull-hook, - push-hook -/+ *server, *contact-json, default-agent, dbug, verb, - grpl=group, mdl=metadata, resource, - group-store +:: contact-view [landscape]: deprecated :: +/+ default-agent |% -+$ versioned-state - $% state-0 - == -:: -+$ state-0 - $: %0 - ~ - == -:: +$ card card:agent:gall -- -=| state-0 -=* state - :: -%- agent:dbug -%+ verb | ^- agent:gall -=< - |_ =bowl:gall - +* this . - contact-core +> - cc ~(. contact-core bowl) - def ~(. (default-agent this %|) bowl) - :: - ++ on-init - ^- (quip card _this) - :_ this - :~ [%pass /updates %agent [our.bowl %contact-store] %watch /updates] - (contact-poke:cc [%create /~/default]) - (contact-poke:cc [%add /~/default our.bowl *contact]) - :* %pass /srv %agent [our.bol %file-server] - %poke %file-server-action - !>([%serve-dir /'~groups' /app/landscape %.n %.y]) - == - == - :: - ++ on-save !>(state) - ++ on-load - |= old-vase=vase - ^- (quip card _this) - =/ old ((soft state-0) q.old-vase) - ?^ old [~ this] - :_ this(state [%0 ~]) - :~ [%pass / %arvo %e %disconnect [~ /'~groups']] - [%pass / %arvo %e %connect [~ /'contact-view'] %contact-view] - :* %pass /srv %agent [our.bol %file-server] - %poke %file-server-action - !>([%serve-dir /'~groups' /app/landscape %.n %.y]) - == - == - :: - ++ on-poke - |= [=mark =vase] - ^- (quip card _this) - ?> (team:title our.bowl src.bowl) - ?+ mark (on-poke:def mark vase) - %json [(poke-json:cc !<(json vase)) this] - %contact-view-action - [(poke-contact-view-action:cc !<(contact-view-action vase)) this] - :: - %handle-http-request - =+ !<([eyre-id=@ta =inbound-request:eyre] vase) - :_ this - %+ give-simple-payload:app eyre-id - %+ require-authorization:app inbound-request - poke-handle-http-request:cc - == - :: - ++ on-watch - |= =path - ^- (quip card _this) - ?> (team:title our.bowl src.bowl) - ?: ?=([%http-response *] path) [~ this] - ?. =(/primary path) (on-watch:def path) - [[%give %fact ~ %json !>((update-to-json [%initial all-scry:cc]))]~ this] - :: - ++ on-agent - |= [=wire =sign:agent:gall] - ^- (quip card _this) - ?+ -.sign (on-agent:def wire sign) - %poke-ack - ?. ?=([%join-group %ship @ @ ~] wire) - (on-agent:def wire sign) - ?^ p.sign - (on-agent:def wire sign) - :_ this - (joined-group:cc t.wire) - :: - %kick - [[%pass / %agent [our.bol %contact-store] %watch /updates]~ this] - :: - %fact - ?+ p.cage.sign (on-agent:def wire sign) - %contact-update - =/ update=json (update-to-json !<(contact-update q.cage.sign)) - [[%give %fact ~[/primary] %json !>(update)]~ this] - == - == - :: - ++ on-arvo - |= [=wire =sign-arvo] - ^- (quip card _this) - ?. ?=(%bound +<.sign-arvo) - (on-arvo:def wire sign-arvo) - [~ this] - :: - ++ on-leave on-leave:def - ++ on-peek on-peek:def - ++ on-fail on-fail:def - -- -:: |_ bol=bowl:gall -++ grp ~(. grpl bol) -++ md ~(. mdl bol) -++ poke-json - |= jon=json - ^- (list card) - ?> (team:title our.bol src.bol) - (poke-contact-view-action (json-to-view-action jon)) ++* this . + def ~(. (default-agent this %|) bol) :: -++ poke-contact-view-action - |= act=contact-view-action - ^- (list card) - ?> (team:title our.bol src.bol) - ?- -.act - %create - =/ rid=resource - [our.bol name.act] - =/ =path - (en-path:resource rid) - ;: weld - :~ (group-poke [%add-group rid policy.act %.n]) - (group-poke [%add-members rid (sy our.bol ~)]) - (group-push-poke %add rid) - (contact-poke [%create path]) - (contact-hook-poke [%add-owned path]) - == - (create-metadata path title.act description.act) - ?. ?=(%invite -.policy.act) - ~ - %+ turn - ~(tap in pending.policy.act) - |= =ship - (send-invite our.bol %contacts rid ship '') - == - :: - %join - =/ =cage - :- %group-update - !> ^- update:group-store - [%add-members resource.act (sy our.bol ~)] - =/ =wire - [%join-group (en-path:resource resource.act)] - [%pass wire %agent [entity.resource.act %group-push-hook] %poke cage]~ - :: - %invite - =* rid resource.act - =/ =group (need (scry-group:grp rid)) - :- (send-invite entity.rid %contacts rid ship.act text.act) - ?. ?=(%invite -.policy.group) ~ - ~[(add-pending rid ship.act)] - :: - %delete - ~ - :: - %remove - =/ rid=resource - (de-path:resource path.act) - :~ (group-poke %remove-members rid (sy ship.act ~)) - (contact-poke [%remove path.act ship.act]) - == - :: - %share - :: determine whether to send to our contact-hook or foreign - :: send contact-action to contact-hook with %add action - [(share-poke recipient.act [%add path.act ship.act contact.act])]~ - :: - %groupify - =/ =path - (en-path:resource resource.act) - %+ weld - :~ (group-poke %expose resource.act ~) - (contact-poke [%create path]) - (contact-hook-poke [%add-owned path]) - == - (create-metadata path title.act description.act) - == -++ poke-handle-http-request - |= =inbound-request:eyre - ^- simple-payload:http - =+ url=(parse-request-line url.request.inbound-request) - =/ name=@t - =+ back-path=(flop site.url) - ?~ back-path - '' - i.back-path - ?+ site.url not-found:gen - [%'contact-view' @ *] - =/ =path (flop t.t.site.url) - ?~ path not-found:gen - =/ contact (contact-scry `^path`(snoc (flop t.path) name)) - ?~ contact not-found:gen - ?~ avatar.u.contact not-found:gen - ?- -.u.avatar.u.contact - %url [[307 ['location' url.u.avatar.u.contact]~] ~] - %octt - =/ max-3-days ['cache-control' 'max-age=259200'] - =/ content-type ['content-type' content-type.u.avatar.u.contact] - [[200 [content-type max-3-days ~]] `octs.u.avatar.u.contact] - == - == +++ on-init on-init:def +++ on-poke on-poke:def +++ on-watch on-watch:def +++ on-agent on-agent:def +++ on-arvo on-arvo:def +++ on-save !>(~) +++ on-load + |= old-vase=vase + ^- (quip card _this) + [~ this] :: -++ joined-group - |= =path - ^- (list card) - =/ rid=resource - (de-path:resource path) - :~ (group-pull-poke [%add entity.rid rid]) - (contact-hook-poke [%add-synced entity.rid path]) - (sync-metadata entity.rid path) - == -:: -:: +utilities -:: -++ add-pending - |= [rid=resource =ship] - ^- card - =/ app=term - ?: =(our.bol entity.rid) - %group-store - %group-push-hook - =/ =cage - :- %group-update - !> ^- action:group-store - [%change-policy rid %invite %add-invites (sy ship ~)] - [%pass / %agent [entity.rid app] %poke cage] -:: -++ send-invite - |= =invite:inv - ^- card - =/ =cage - :- %invite-action - !> ^- action:inv - [%invite %contacts (shaf %invite-uid eny.bol) invite] - [%pass / %agent [recipient.invite %invite-hook] %poke cage] -:: -++ contact-poke - |= act=contact-action - ^- card - [%pass / %agent [our.bol %contact-store] %poke %contact-action !>(act)] -:: -++ contact-hook-poke - |= act=contact-hook-action - ^- card - [%pass / %agent [our.bol %contact-hook] %poke %contact-hook-action !>(act)] -:: -++ share-poke - |= [=ship act=contact-action] - ^- card - [%pass / %agent [ship %contact-hook] %poke %contact-action !>(act)] -:: -++ group-poke - |= act=action:group-store - ^- card - [%pass / %agent [our.bol %group-store] %poke %group-action !>(act)] -:: -++ group-push-poke - |= act=action:push-hook - ^- card - [%pass / %agent [our.bol %group-push-hook] %poke %push-hook-action !>(act)] -:: -++ group-proxy-poke - |= act=action:group-store - ^- card - [%pass / %agent [entity.resource.act %group-push-hook] %poke %group-update !>(act)] -:: -++ group-pull-poke - |= act=action:pull-hook - ^- card - [%pass / %agent [our.bol %group-pull-hook] %poke %pull-hook-action !>(act)] -:: -++ metadata-poke - |= act=metadata-action - ^- card - [%pass / %agent [our.bol %metadata-store] %poke %metadata-action !>(act)] -:: -++ metadata-hook-poke - |= act=metadata-hook-action - ^- card - [%pass / %agent [our.bol %metadata-hook] %poke %metadata-hook-action !>(act)] -:: -++ sync-metadata - |= [=ship =path] - ^- card - (metadata-hook-poke %add-synced ship path) -:: -++ create-metadata - |= [=path title=@t description=@t] - ^- (list card) - =/ =metadata - %* . *metadata - title title - description description - date-created now.bol - creator our.bol - == - :~ (metadata-poke [%add path [%contacts path] metadata]) - (metadata-hook-poke [%add-owned path]) - == -:: -++ all-scry - ^- rolodex - .^(rolodex %gx /(scot %p our.bol)/contact-store/(scot %da now.bol)/all/noun) -:: -++ contact-scry - |= pax=path - ^- (unit contact) - =. pax - ;: weld - /(scot %p our.bol)/contact-store/(scot %da now.bol)/contact - pax - /noun - == - .^((unit contact) %gx pax) +++ on-leave on-leave:def +++ on-peek on-peek:def +++ on-fail on-fail:def -- diff --git a/pkg/arvo/app/group-store.hoon b/pkg/arvo/app/group-store.hoon index 43bcb67f0..c85a0ad63 100644 --- a/pkg/arvo/app/group-store.hoon +++ b/pkg/arvo/app/group-store.hoon @@ -29,7 +29,7 @@ :: Modify the group. Further documented in /sur/group-store.hoon :: :: -/- *group, *contact-view +/- *group /+ store=group-store, default-agent, verb, dbug, resource, *migrate |% +$ card card:agent:gall @@ -284,11 +284,8 @@ |= [recipient=@p out=(list card)] ?: =(recipient our.bol) out - :_ out - %- poke-contact - :* %invite rid recipient - (crip "Rejoin disconnected group {}/{}") - == + :: TODO: figure out contacts integration + out :_ out (try-rejoin rid 0) :: @@ -610,11 +607,6 @@ |= =action:store ^- card [%pass / %agent [our.bol %group-store] %poke %group-action !>(action)] -:: -++ poke-contact - |= act=contact-view-action - ^- card - [%pass / %agent [our.bol %contact-view] %poke %contact-view-action !>(act)] :: +send-diff: update subscribers of new state :: :: We only allow subscriptions on /groups diff --git a/pkg/arvo/app/invite-store.hoon b/pkg/arvo/app/invite-store.hoon index ae74a4e5f..47de74ba8 100644 --- a/pkg/arvo/app/invite-store.hoon +++ b/pkg/arvo/app/invite-store.hoon @@ -6,6 +6,7 @@ +$ versioned-state $% state-0 state-1 + state-2 == :: +$ invitatory-0 (map serial:store invite-0) @@ -19,9 +20,10 @@ :: +$ state-0 [%0 invites=(map path invitatory-0)] +$ state-1 [%1 =invites:store] ++$ state-2 [%2 =invites:store] -- :: -=| state-1 +=| state-2 =* state - %- agent:dbug ^- agent:gall @@ -43,37 +45,22 @@ ++ on-load |= old-vase=vase =/ old !<(versioned-state old-vase) + =| cards=(list card) + |- + ?: ?=(%2 -.old) + [cards this(state old)] ?: ?=(%1 -.old) - `this(state old) - :- =- [%pass / %agent [our.bowl %invite-store] %poke %invite-action -]~ - !> ^- action:store - [%create %graph] - %= this - state - :- %1 - %- ~(gas by *invites:store) - %+ murn ~(tap by invites.old) - |= [=path =invitatory-0] - ^- (unit [term invitatory:store]) - ?. ?=([@ ~] path) ~ - :- ~ - :- i.path - %- ~(gas by *invitatory:store) - %+ murn ~(tap by invitatory-0) - |= [=serial:store =invite-0] - ^- (unit [serial:store invite:store]) - =/ resource=(unit resource:res) (de-path-soft:res path.invite-0) - ?~ resource ~ - :- ~ - :- serial - ^- invite:store - :* ship.invite-0 - app.invite-0 - u.resource - recipient.invite-0 - text.invite-0 - == - == + =. cards + :~ =- [%pass / %agent [our.bowl %invite-store] %poke %invite-action -] + !> ^- action:store + [%create %groups] + :: + =- [%pass / %agent [our.bowl %invite-store] %poke %invite-action -] + !> ^- action:store + [%delete %contacts] + == + $(-.old %2) + $(old [%1 (~(gas by *invites:store) [%graph *invitatory:store]~)]) :: ++ on-agent on-agent:def ++ on-arvo on-arvo:def @@ -109,11 +96,19 @@ ++ poke-import |= arc=* ^- (quip card _state) - =/ sty=state-1 - :- %1 + =/ sty=state-2 + :- %2 %- remake-map-of-map ;;((tree [term (tree [serial:store invite:store])]) +.arc) - [~ sty] + :_ sty + :~ =- [%pass / %agent [our.bowl %invite-store] %poke %invite-action -] + !> ^- action:store + [%create %groups] + :: + =- [%pass / %agent [our.bowl %invite-store] %poke %invite-action -] + !> ^- action:store + [%delete %contacts] + == :: ++ poke-invite-action |= =action:store diff --git a/pkg/arvo/lib/contact-json.hoon b/pkg/arvo/lib/contact-json.hoon deleted file mode 100644 index 5485ef4c4..000000000 --- a/pkg/arvo/lib/contact-json.hoon +++ /dev/null @@ -1,265 +0,0 @@ -/- *contact-view, *contact-hook -/+ group-store, resource -|% -++ nu :: parse number as hex - |= jon=json - ?> ?=([%s *] jon) - (rash p.jon hex) -:: -++ hook-update-to-json - |= upd=contact-hook-update - =, enjs:format - ^- json - %+ frond %contact-hook-update - %- pairs - %+ turn ~(tap by synced.upd) - |= [pax=^path shp=^ship] - ^- [cord json] - [(spat pax) s+(scot %p shp)] -:: -++ rolodex-to-json - |= rolo=rolodex - =, enjs:format - ^- json - %- pairs - %+ turn ~(tap by rolo) - |= [pax=^path =contacts] - ^- [cord json] - :- (spat pax) - (contacts-to-json pax contacts) -:: -++ contacts-to-json - |= [=path con=contacts] - ^- json - %- pairs:enjs:format - %+ turn ~(tap by con) - |= [=ship =contact] - ^- [cord json] - [(crip (slag 1 (scow %p ship))) (contact-to-json path ship contact)] -:: -++ contact-to-json - |= [=path =ship con=contact] - ^- json - %- pairs:enjs:format - :~ [%nickname s+nickname.con] - [%email s+email.con] - [%phone s+phone.con] - [%website s+website.con] - [%notes s+notes.con] - [%color s+(scot %ux color.con)] - [%avatar (avatar-to-json path ship avatar.con)] - == -:: -++ edit-to-json - |= [=path =ship edit=edit-field] - ^- json - %+ frond:enjs:format -.edit - ?- -.edit - %nickname s+nickname.edit - %email s+email.edit - %phone s+phone.edit - %website s+website.edit - %notes s+notes.edit - %color s+(scot %ux color.edit) - %avatar (avatar-to-json path ship avatar.edit) - == -:: -++ avatar-to-json - |= [=path =ship avat=(unit avatar)] - ^- json - ?~ avat ~ - ?- -.u.avat - %octt - :- %s - %- crip - %- zing - :~ "/contact-view" - (trip (spat path)) - "/" - (trip (scot %p ship)) - == - :: - %url s+url.u.avat - == -:: -++ update-to-json - |= upd=contact-update - =, enjs:format - ^- json - %+ frond %contact-update - %- pairs - :~ - ?: ?=(%initial -.upd) - [%initial (rolodex-to-json rolodex.upd)] - ?: ?=(%create -.upd) - [%create (pairs [%path (path path.upd)]~)] - ?: ?=(%delete -.upd) - [%delete (pairs [%path (path path.upd)]~)] - ?: ?=(%add -.upd) - :- %add - %- pairs - :~ [%path (path path.upd)] - [%ship (ship ship.upd)] - [%contact (contact-to-json path.upd ship.upd contact.upd)] - == - ?: ?=(%remove -.upd) - :- %remove - %- pairs - :~ [%path (path path.upd)] - [%ship (ship ship.upd)] - == - ?: ?=(%edit -.upd) - :- %edit - %- pairs - :~ [%path (path path.upd)] - [%ship (ship ship.upd)] - [%edit-field (edit-to-json path.upd ship.upd edit-field.upd)] - == - [*@t *^json] - == -:: -++ json-to-view-action - |= jon=json - ^- contact-view-action - =, dejs:format - =< (parse-json jon) - |% - ++ parse-json - %- of - :~ [%create create] - [%delete delete] - [%join dejs:resource] - [%invite invite] - [%remove remove] - [%share share] - == - :: - ++ create - %- ot - :~ [%name so] - [%policy policy:dejs:group-store] - [%title so] - [%description so] - == - :: - ++ invite - %- ot - :~ [%resource dejs:resource] - [%ship (su ;~(pfix sig fed:ag))] - [%text so] - == - :: - ++ delete (ot [%path pa]~) - :: - ++ remove - %- ot - :~ [%path pa] - [%ship (su ;~(pfix sig fed:ag))] - == - :: - ++ share - %- ot - :~ [%recipient (su ;~(pfix sig fed:ag))] - [%path pa] - [%ship (su ;~(pfix sig fed:ag))] - [%contact cont] - == - -- -:: -++ json-to-action - |= jon=json - ^- contact-action - =, dejs:format - =< (parse-json jon) - |% - ++ parse-json - %- of - :~ [%create create] - [%delete delete] - [%add add] - [%remove remove] - [%edit edit] - == - :: - ++ create - (ot [%path pa]~) - :: - ++ delete - (ot [%path pa]~) - :: - ++ add - %- ot - :~ [%path pa] - [%ship (su ;~(pfix sig fed:ag))] - [%contact cont] - == - :: - ++ remove - %- ot - :~ [%path pa] - [%ship (su ;~(pfix sig fed:ag))] - == - :: - ++ edit - %- ot - :~ [%path pa] - [%ship (su ;~(pfix sig fed:ag))] - [%edit-field edit-fi] - == - -- -:: -++ octet - %- ot:dejs:format - :~ [%p ni:dejs:format] - [%q so:dejs:format] - == -:: -++ avat - |= jon=json - ^- avatar - |^ - =/ =avatar (parse-json jon) - ?- -.avatar - %url avatar - %octt - =. octs.avatar (need (de:base64:mimes:html q.octs.avatar)) - avatar - == - :: - ++ parse-json - %- of:dejs:format - :~ [%octt octt] - [%url url] - == - :: - ++ octt - %- ot:dejs:format - :~ [%content-type so:dejs:format] - [%octs octet] - == - :: - ++ url so:dejs:format - -- -:: -++ cont - %- ot:dejs:format - :~ [%nickname so:dejs:format] - [%email so:dejs:format] - [%phone so:dejs:format] - [%website so:dejs:format] - [%notes so:dejs:format] - [%color nu] - [%avatar (mu:dejs:format avat)] - == -:: -++ edit-fi - %- of:dejs:format - :~ [%nickname so:dejs:format] - [%email so:dejs:format] - [%phone so:dejs:format] - [%website so:dejs:format] - [%notes so:dejs:format] - [%color nu] - [%avatar (mu:dejs:format avat)] - == --- diff --git a/pkg/arvo/lib/contact-store.hoon b/pkg/arvo/lib/contact-store.hoon new file mode 100644 index 000000000..f12d2392a --- /dev/null +++ b/pkg/arvo/lib/contact-store.hoon @@ -0,0 +1,123 @@ +/- sur=contact-store +=< [sur .] +=, sur +|% +++ nu :: parse number as hex + |= jon=json + ?> ?=([%s *] jon) + (rash p.jon hex) +:: +++ enjs + =, enjs:format + |% + ++ update + |= upd=^update + ^- json + |^ (frond %contact-update (pairs ~[(encode upd)])) + :: + ++ encode + |= upd=update-0 + ^- [cord json] + ?- -.upd + %initial + :: TODO: initial + :- %initial + *json + %add + :- %add + %- pairs + :~ [%path (path path.upd)] + [%ship (ship ship.upd)] + [%contact (contact-to-json path.upd ship.upd contact.upd)] + == + :: + %remove + :- %remove + %- pairs + :~ [%path (path path.upd)] + [%ship (ship ship.upd)] + == + :: + %edit + :- %edit + %- pairs + :~ [%path (path path.upd)] + [%ship (ship ship.upd)] + [%edit-field (edit-to-json edit-field.upd)] + == + == + -- + :: + ++ rolodex-to-json + |= rol=rolodex:store + ^- json + %- pairs:enjs:format + %+ turn ~(tap by rol) + |= [=ship =contact:store] + ^- [cord json] + [(crip (slag 1 (scow %p ship))) (contact-to-json contact)] + :: + ++ contact-to-json + |= con=contact:store + ^- json + %- pairs:enjs:format + :~ [%nickname s+nickname.con] + [%email s+email.con] + [%phone s+phone.con] + [%website s+website.con] + [%color s+(scot %ux color.con)] + [%avatar ?~(avatar.edit ~ s+u.avatar.con)] + == + :: + ++ edit-to-json + |= edit=edit-field + ^- json + %+ frond:enjs:format -.edit + ?- -.edit + %nickname s+nickname.edit + %email s+email.edit + %phone s+phone.edit + %website s+website.edit + %color s+(scot %ux color.edit) + %avatar ?~(avatar.edit ~ s+u.avatar.edit) + == + -- +:: +++ dej + =, dejs:formats + |% + ++ update + |= jon=json + ^- ^update + =< (decode jon) + |% + ++ decode + %- of + :~ [%initial initial] + [%add add-contact] + [%remove remove-contact] + [%edit edit-contact] + == + :: + ++ cont + %- ot + :~ [%nickname so] + [%email so] + [%phone so] + [%website so] + [%color nu] + [%avatar (mu so)] + == + :: + ++ edit-fi + %- of + :~ [%nickname so] + [%email so] + [%phone so] + [%website so] + [%color nu] + [%avatar (mu so)] + == + -- + -- +-- diff --git a/pkg/arvo/mar/contact/action.hoon b/pkg/arvo/mar/contact/action.hoon deleted file mode 100644 index a756fb810..000000000 --- a/pkg/arvo/mar/contact/action.hoon +++ /dev/null @@ -1,15 +0,0 @@ -/+ *contact-json -|_ act=contact-action -++ grad %noun -++ grow - |% - ++ noun act - -- -++ grab - |% - ++ noun contact-action - ++ json - |= jon=^json - (json-to-action jon) - -- --- diff --git a/pkg/arvo/mar/contact/hook-update.hoon b/pkg/arvo/mar/contact/hook-update.hoon deleted file mode 100644 index 481582282..000000000 --- a/pkg/arvo/mar/contact/hook-update.hoon +++ /dev/null @@ -1,15 +0,0 @@ -/+ *contact-json -|_ upd=contact-hook-update -++ grad %noun -++ grow - |% - ++ noun upd - ++ json (hook-update-to-json upd) - -- -:: -++ grab - |% - ++ noun contact-hook-update - -- -:: --- diff --git a/pkg/arvo/mar/contact/initial.hoon b/pkg/arvo/mar/contact/initial.hoon deleted file mode 100644 index 0bf1d3e8d..000000000 --- a/pkg/arvo/mar/contact/initial.hoon +++ /dev/null @@ -1,16 +0,0 @@ -/+ *contact-json -|_ rolo=rolodex -:: -++ grad %noun -++ grow - |% - ++ noun +<.grow - ++ json (rolodex-to-json rolo) - -- -:: -++ grab - |% - ++ noun rolodex - -- -:: --- diff --git a/pkg/arvo/mar/contact/update.hoon b/pkg/arvo/mar/contact/update.hoon index 75e593125..733d30f48 100644 --- a/pkg/arvo/mar/contact/update.hoon +++ b/pkg/arvo/mar/contact/update.hoon @@ -1,15 +1,16 @@ -/+ *contact-json -|_ upd=contact-update +/+ *contact-store +:: +|_ upd=update ++ grad %noun ++ grow |% ++ noun upd - ++ json (update-to-json upd) + ++ json (update:enjs upd) -- :: ++ grab |% - ++ noun contact-update + ++ noun update + ++ json update:dejs -- -:: -- diff --git a/pkg/arvo/mar/contact/view-action.hoon b/pkg/arvo/mar/contact/view-action.hoon deleted file mode 100644 index bd386555d..000000000 --- a/pkg/arvo/mar/contact/view-action.hoon +++ /dev/null @@ -1,12 +0,0 @@ -/- *contact-view -|_ act=contact-view-action -++ grad %noun -++ grow - |% - ++ noun act - -- -++ grab - |% - ++ noun contact-view-action - -- --- diff --git a/pkg/arvo/sur/contact-hook.hoon b/pkg/arvo/sur/contact-hook.hoon deleted file mode 100644 index 5926ec5a5..000000000 --- a/pkg/arvo/sur/contact-hook.hoon +++ /dev/null @@ -1,18 +0,0 @@ -|% -+$ contact-hook-action - $% :: %add-owned: make a contacts list accessible to foreign ships - :: who are members of that list - :: - [%add-owned =path] - :: %add-synced: mirror a foreign contacts list to our contact-store - :: - [%add-synced =ship =path] - :: %remove: stop mirroring a foreign contacts list or stop allowing - :: a local contacts list to be mirrored - :: - [%remove =path] - == -:: -+$ synced (map path ship) -+$ contact-hook-update [%initial =synced] --- diff --git a/pkg/arvo/sur/contact-store.hoon b/pkg/arvo/sur/contact-store.hoon index 7bd642b7b..6c7db48a3 100644 --- a/pkg/arvo/sur/contact-store.hoon +++ b/pkg/arvo/sur/contact-store.hoon @@ -1,20 +1,13 @@ /- *identity |% -+$ rolodex (map path contacts) -+$ contacts (map ship contact) -+$ avatar - $% [%octt content-type=@t octs=[p=@ud q=@t]] - [%url url=@t] - == -:: ++$ rolodex (map ship contact) +$ contact $: nickname=@t email=@t phone=@t website=@t - notes=@t color=@ux - avatar=(unit avatar) + avatar=(unit @t) == :: +$ edit-field @@ -22,22 +15,14 @@ [%email email=@t] [%phone phone=@t] [%website website=@t] - [%notes notes=@t] [%color color=@ux] - [%avatar avatar=(unit avatar)] + [%avatar avatar=(unit @t)] == :: -+$ contact-action - $% [%create =path] - [%delete =path] - [%add =path =ship =contact] - [%remove =path =ship] - [%edit =path =ship =edit-field] - == -:: -+$ contact-update ++$ update $% [%initial =rolodex] - [%contacts =path =contacts] - contact-action + [%add =ship =contact] + [%remove =ship] + [%edit =ship =edit-field] == -- diff --git a/pkg/arvo/sur/contact-view.hoon b/pkg/arvo/sur/contact-view.hoon deleted file mode 100644 index f02a5d3b7..000000000 --- a/pkg/arvo/sur/contact-view.hoon +++ /dev/null @@ -1,27 +0,0 @@ -/- *contact-store, *group, *resource -:: -|% -+$ contact-view-action - $% :: %create: create in both groups and contacts - :: - [%create name=term =policy title=@t description=@t] - :: %join: join open group in both groups and contacts - :: - [%join =resource] - :: %invite: invite to invite-only group and contacts - :: - [%invite =resource =ship text=cord] - :: %remove: remove from both groups and contacts - :: - [%remove =path =ship] - :: %delete: delete in both groups and contacts - :: - [%delete =path] - :: %share: send %add contact-action to to recipient's contact-hook - :: - [%share recipient=ship =path =ship =contact] - :: %groupify: create contacts object for a preexisting group - :: - [%groupify =resource title=@t description=@t] - == --- From 1eb99bfdcd3e84531b9f491f24d88cae4a160817 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Mon, 11 Jan 2021 13:39:36 -0600 Subject: [PATCH 04/61] contact-store: wrote out all the JSON conversions and store compiles --- pkg/arvo/app/contact-store.hoon | 9 +- pkg/arvo/lib/contact-store.hoon | 139 ++++++++++++++++--------------- pkg/arvo/sur/contact-store.hoon | 1 - pkg/arvo/ted/group/on-leave.hoon | 17 +--- 4 files changed, 78 insertions(+), 88 deletions(-) diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index 0b748ef0a..ffa066b8e 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -30,12 +30,8 @@ |= old-vase=vase ^- (quip card _this) =/ old !<(versioned-state old-vase) - ?- -.old - %4 [~ this(state old)] - %3 [~ this] - %2 [~ this] - %1 [~ this] - %0 [~ this] + ?+ -.old [~ this] + %4 [~ this(state old)] == :: ++ on-watch @@ -128,6 +124,7 @@ ++ import |= arc=* ^- (quip card _state) + :: note: we are purposefully wiping all state before state-4 [~ *state-4] -- :: diff --git a/pkg/arvo/lib/contact-store.hoon b/pkg/arvo/lib/contact-store.hoon index f12d2392a..719886ca1 100644 --- a/pkg/arvo/lib/contact-store.hoon +++ b/pkg/arvo/lib/contact-store.hoon @@ -13,78 +13,71 @@ ++ update |= upd=^update ^- json - |^ (frond %contact-update (pairs ~[(encode upd)])) - :: - ++ encode - |= upd=update-0 - ^- [cord json] - ?- -.upd - %initial - :: TODO: initial - :- %initial - *json - %add - :- %add - %- pairs - :~ [%path (path path.upd)] - [%ship (ship ship.upd)] - [%contact (contact-to-json path.upd ship.upd contact.upd)] - == - :: - %remove - :- %remove - %- pairs - :~ [%path (path path.upd)] - [%ship (ship ship.upd)] - == - :: - %edit - :- %edit - %- pairs - :~ [%path (path path.upd)] - [%ship (ship ship.upd)] - [%edit-field (edit-to-json edit-field.upd)] - == - == - -- - :: - ++ rolodex-to-json - |= rol=rolodex:store - ^- json - %- pairs:enjs:format - %+ turn ~(tap by rol) - |= [=ship =contact:store] + %+ frond %contact-update + %- pairs + :_ ~ ^- [cord json] - [(crip (slag 1 (scow %p ship))) (contact-to-json contact)] - :: - ++ contact-to-json - |= con=contact:store - ^- json - %- pairs:enjs:format - :~ [%nickname s+nickname.con] - [%email s+email.con] - [%phone s+phone.con] - [%website s+website.con] - [%color s+(scot %ux color.con)] - [%avatar ?~(avatar.edit ~ s+u.avatar.con)] + ?- -.upd + %initial + :- %initial + (pairs [%rolodex (rolo rolodex.upd)]~) + :: + %add + :- %add + %- pairs + :~ [%ship (ship ship.upd)] + [%contact (cont contact.upd)] + == + :: + %remove + :- %remove + (pairs [%ship (ship ship.upd)]~) + :: + %edit + :- %edit + %- pairs + :~ [%ship (ship ship.upd)] + [%edit-field (edit edit-field.upd)] + == == :: - ++ edit-to-json - |= edit=edit-field + ++ rolo + |= =rolodex ^- json - %+ frond:enjs:format -.edit - ?- -.edit - %nickname s+nickname.edit - %email s+email.edit - %phone s+phone.edit - %website s+website.edit - %color s+(scot %ux color.edit) - %avatar ?~(avatar.edit ~ s+u.avatar.edit) + %- pairs + %+ turn ~(tap by rolodex) + |= [=^ship =contact] + ^- [cord json] + [(scot %p ship) (cont contact)] + :: + ++ cont + |= =contact + ^- json + %- pairs + :~ [%nickname s+nickname.contact] + [%email s+email.contact] + [%phone s+phone.contact] + [%website s+website.contact] + [%color s+(scot %ux color.contact)] + [%avatar ?~(avatar.contact ~ s+u.avatar.contact)] + == + :: + ++ edit + |= field=edit-field + ^- json + %+ frond -.field + ?- -.field + %nickname s+nickname.field + %email s+email.field + %phone s+phone.field + %website s+website.field + %color s+(scot %ux color.field) + %avatar ?~(avatar.field ~ s+u.avatar.field) == -- :: ++ dej - =, dejs:formats + =, dejs:format |% ++ update |= jon=json @@ -99,6 +92,22 @@ [%edit edit-contact] == :: + ++ initial (op ;~(pfix sig fed:ag) cont) + :: + ++ add-contact + %- ot + :~ [%ship (su ;~(pfix sig fed:ag))] + [%contact cont] + == + :: + ++ remove-contact (ot [%ship (su ;~(pfix sig fed:ag))]~) + :: + ++ edit-contact + %- ot + :~ [%ship (su ;~(pfix sig fed:ag))] + [%edit-field edit] + == + :: ++ cont %- ot :~ [%nickname so] @@ -109,7 +118,7 @@ [%avatar (mu so)] == :: - ++ edit-fi + ++ edit %- of :~ [%nickname so] [%email so] diff --git a/pkg/arvo/sur/contact-store.hoon b/pkg/arvo/sur/contact-store.hoon index 6c7db48a3..ea118a2e0 100644 --- a/pkg/arvo/sur/contact-store.hoon +++ b/pkg/arvo/sur/contact-store.hoon @@ -1,4 +1,3 @@ -/- *identity |% +$ rolodex (map ship contact) +$ contact diff --git a/pkg/arvo/ted/group/on-leave.hoon b/pkg/arvo/ted/group/on-leave.hoon index b3e02ef35..ed26d6ccc 100644 --- a/pkg/arvo/ted/group/on-leave.hoon +++ b/pkg/arvo/ted/group/on-leave.hoon @@ -1,4 +1,4 @@ -/- spider, grp=group-store, gra=graph-store, met=metadata-store, con=contact-store +/- spider, grp=group-store, gra=graph-store, met=metadata-store /+ strandio, res=resource :: =* strand strand:spider @@ -33,21 +33,6 @@ [our.bowl %group-pull-hook] :- %pull-hook-action !>([%remove resource.update]) -:: stop serving or syncing contacts associated with group -:: -;< ~ bind:m - %+ raw-poke - [our.bowl %contact-hook] - :- %contact-hook-action - !>([%remove (en-path:res resource.update)]) -:: remove contact data associated with group -:: -;< ~ bind:m - %+ raw-poke - [our.bowl %contact-store] - :- %contact-action - !> ^- contact-action:con - [%delete (en-path:res resource.update)] :: stop serving or syncing metadata associated with group :: ;< ~ bind:m From dca2c9ae586809f258a267ec3e52a7e4b700a75d Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Mon, 11 Jan 2021 13:40:40 -0600 Subject: [PATCH 05/61] interface: updated api/logic in reducer and api to reflect new %contact-store --- pkg/interface/src/logic/api/contacts.ts | 59 ++++--------------- .../src/logic/reducers/contact-update.ts | 34 ++--------- .../src/logic/subscription/global.ts | 4 +- 3 files changed, 20 insertions(+), 77 deletions(-) diff --git a/pkg/interface/src/logic/api/contacts.ts b/pkg/interface/src/logic/api/contacts.ts index 3049442f5..2874ba0ef 100644 --- a/pkg/interface/src/logic/api/contacts.ts +++ b/pkg/interface/src/logic/api/contacts.ts @@ -5,74 +5,41 @@ import { Contact, ContactEdit } from '~/types/contact-update'; import { GroupPolicy, Resource } from '~/types/group-update'; export default class ContactsApi extends BaseApi { - create( - name: string, - policy: Enc, - title: string, - description: string - ) { - return this.viewAction({ - create: { - name, - policy, - title, - description, - }, - }); + add(ship: Patp, contact: any) { + return this.storeAction({ add: { ship, contact } }); } - share(recipient: Patp, path: Patp, ship: Patp, contact: Contact) { - return this.viewAction({ - share: { - recipient, - path, - ship, - contact, - }, - }); + remove(ship: Patp) { + return this.storeAction({ remove: { ship } }); } - remove(path: Path, ship: Patp) { - return this.viewAction({ remove: { path, ship } }); - } - - edit(path: Path, ship: Patp, editField: ContactEdit) { + edit(ship: Patp, editField: ContactEdit) { /* editField can be... {nickname: ''} {email: ''} {phone: ''} {website: ''} - {notes: ''} {color: 'fff'} // with no 0x prefix {avatar: null} - {avatar: {url: ''}} + {avatar: ''} */ - return this.hookAction({ + return this.storeAction({ edit: { - path, ship, 'edit-field': editField, }, }); } - invite(resource: Resource, ship: Patp, text = '') { - return this.viewAction({ - invite: { resource, ship, text }, - }); + private storeAction(action: any): Promise { + return this.action('contact-store', 'contact-update', action) } - join(resource: Resource) { - return this.viewAction({ - join: resource, - }); + private viewAction(threadName: string, action: any) { + return this.spider('contact-view-action', 'json', threadName, action); } - private hookAction(data) { - return this.action('contact-hook', 'contact-action', data); - } - - private viewAction(data) { - return this.action('contact-view', 'json', data); + private hookAction(ship: Patp, action: any): Promise { + return this.action('contact-push-hook', 'contact-update', action); } } diff --git a/pkg/interface/src/logic/reducers/contact-update.ts b/pkg/interface/src/logic/reducers/contact-update.ts index 88a527ed1..2ba1da1d0 100644 --- a/pkg/interface/src/logic/reducers/contact-update.ts +++ b/pkg/interface/src/logic/reducers/contact-update.ts @@ -10,8 +10,6 @@ export default class ContactReducer { const data = _.get(json, 'contact-update', false); if (data) { this.initial(data, state); - this.create(data, state); - this.delete(data, state); this.add(data, state); this.remove(data, state); this.edit(data, state); @@ -25,27 +23,10 @@ export default class ContactReducer { } } - create(json: ContactUpdate, state: S) { - const data = _.get(json, 'create', false); - if (data) { - state.contacts[data.path] = {}; - } - } - - delete(json: ContactUpdate, state: S) { - const data = _.get(json, 'delete', false); - if (data) { - delete state.contacts[data.path]; - } - } - add(json: ContactUpdate, state: S) { const data = _.get(json, 'add', false); - if ( - data && - (data.path in state.contacts) - ) { - state.contacts[data.path][data.ship] = data.contact; + if (data) { + state.contacts[data.ship] = data.contact; } } @@ -53,10 +34,9 @@ export default class ContactReducer { const data = _.get(json, 'remove', false); if ( data && - (data.path in state.contacts) && - (data.ship in state.contacts[data.path]) + (data.ship in state.contacts) ) { - delete state.contacts[data.path][data.ship]; + delete state.contacts[data.ship]; } } @@ -64,15 +44,13 @@ export default class ContactReducer { const data = _.get(json, 'edit', false); if ( data && - (data.path in state.contacts) && - (data.ship in state.contacts[data.path]) + (data.ship in state.contacts) ) { const edit = Object.keys(data['edit-field']); if (edit.length !== 1) { return; } - state.contacts[data.path][data.ship][edit[0]] = - data['edit-field'][edit[0]]; + state.contacts[data.ship][edit[0]] = data['edit-field'][edit[0]]; } } } diff --git a/pkg/interface/src/logic/subscription/global.ts b/pkg/interface/src/logic/subscription/global.ts index ed4a2c94c..d6af89428 100644 --- a/pkg/interface/src/logic/subscription/global.ts +++ b/pkg/interface/src/logic/subscription/global.ts @@ -10,7 +10,6 @@ import _ from 'lodash'; type AppSubscription = [Path, string]; const groupSubscriptions: AppSubscription[] = [ - ['/synced', 'contact-hook'] ]; const graphSubscriptions: AppSubscription[] = [ @@ -37,8 +36,7 @@ export default class GlobalSubscription extends BaseSubscription { this.subscribe('/groups', 'group-store'); this.clearQueue(); - - this.subscribe('/primary', 'contact-view'); + this.subscribe('/updates', 'contact-store'); this.subscribe('/all', 's3-store'); this.subscribe('/keys', 'graph-store'); this.subscribe('/updates', 'hark-store'); From cdb91291ed393b8fed63783491b2f211aa00981d Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Mon, 11 Jan 2021 15:09:41 -0600 Subject: [PATCH 06/61] contact-store: %allow/%disallow support --- pkg/arvo/app/contact-store.hoon | 67 +++++++++++++++++++++++---------- pkg/arvo/lib/contact-store.hoon | 30 +++++++++++++-- pkg/arvo/sur/contact-store.hoon | 8 ++++ 3 files changed, 82 insertions(+), 23 deletions(-) diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index ffa066b8e..bcb2897de 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -2,11 +2,16 @@ :: :: data store that holds individual contact data :: -/- store=contact-store +/- store=contact-store, *resource /+ default-agent, dbug, *migrate |% +$ card card:agent:gall -+$ state-4 [%4 =rolodex:store] ++$ state-4 + $: %4 + =rolodex:store + allowed-groups=(set resource) + allowed-ships=(set ship) + == +$ versioned-state $% [%0 *] [%1 *] @@ -41,14 +46,15 @@ |^ =/ cards=(list card) ?+ path (on-watch:def path) + [%all ~] (give [%initial rolodex]) [%updates ~] ~ == [cards this] :: ++ give - |= =cage + |= =update:store ^- (list card) - [%give %fact ~ cage]~ + [%give %fact ~ [%contact-update !>(update)]]~ -- :: ++ on-poke @@ -68,10 +74,12 @@ ^- (quip card _state) |^ ?- -.update - %initial (handle-initial +.update) - %add (handle-add +.update) - %remove (handle-remove +.update) - %edit (handle-edit +.update) + %initial (handle-initial +.update) + %add (handle-add +.update) + %remove (handle-remove +.update) + %edit (handle-edit +.update) + %allow (handle-allow +.update) + %disallow (handle-disallow +.update) == :: ++ handle-initial @@ -97,22 +105,42 @@ :: ++ handle-edit |= [=ship =edit-field:store] + |^ ^- (quip card _state) =/ contact (~(got by rolodex) ship) =. contact (edit-contact contact edit-field) :- (send-diff [%edit ship edit-field]) state(rolodex (~(put by rolodex) ship contact)) + :: + ++ edit-contact + |= [=contact:store edit=edit-field:store] + ^- contact:store + ?- -.edit + %nickname contact(nickname nickname.edit) + %email contact(email email.edit) + %phone contact(phone phone.edit) + %website contact(website website.edit) + %color contact(color color.edit) + %avatar contact(avatar avatar.edit) + == + -- :: - ++ edit-contact - |= [=contact:store edit=edit-field:store] - ^- contact:store - ?- -.edit - %nickname contact(nickname nickname.edit) - %email contact(email email.edit) - %phone contact(phone phone.edit) - %website contact(website website.edit) - %color contact(color color.edit) - %avatar contact(avatar avatar.edit) + ++ handle-allow + |= =beings:store + ^- (quip card _state) + :- (send-diff [%allow beings]) + ?- -.beings + %group state(allowed-groups (~(put in allowed-groups) resource.beings)) + %ships state(allowed-ships (~(uni in allowed-ships) ships.beings)) + == + :: + ++ handle-disallow + |= =beings:store + ^- (quip card _state) + :- (send-diff [%disallow beings]) + ?- -.beings + %group state(allowed-groups (~(del in allowed-groups) resource.beings)) + %ships state(allowed-ships (~(dif in allowed-ships) ships.beings)) == :: ++ send-diff @@ -133,12 +161,11 @@ ^- (unit (unit cage)) ?+ path (on-peek:def path) [%x %all ~] ``noun+!>(rolodex) - [%x %export ~] ``noun+!>(state) :: [%x %contact @ ~] =/ =ship (slav %p i.t.t.path) =/ contact=(unit contact:store) (~(get by rolodex) ship) - ?~ contact ~ + ?~ contact [~ ~] :- ~ :- ~ :- %contact-update !> ^- update:store [%add ship u.contact] diff --git a/pkg/arvo/lib/contact-store.hoon b/pkg/arvo/lib/contact-store.hoon index 719886ca1..78e9c39ca 100644 --- a/pkg/arvo/lib/contact-store.hoon +++ b/pkg/arvo/lib/contact-store.hoon @@ -1,4 +1,5 @@ /- sur=contact-store +/+ res=resource =< [sur .] =, sur |% @@ -19,8 +20,7 @@ ^- [cord json] ?- -.upd %initial - :- %initial - (pairs [%rolodex (rolo rolodex.upd)]~) + [%initial (rolo rolodex.upd)] :: %add :- %add @@ -39,6 +39,14 @@ :~ [%ship (ship ship.upd)] [%edit-field (edit edit-field.upd)] == + :: + %allow + :- %allow + (pairs [%beings (beng beings.upd)]~) + :: + %disallow + :- %disallow + (pairs [%beings (beng beings.upd)]~) == :: ++ rolo @@ -74,9 +82,17 @@ %color s+(scot %ux color.field) %avatar ?~(avatar.field ~ s+u.avatar.field) == + :: + ++ beng + |= =beings + ^- json + ?- -.beings + %ships [%a (turn ~(tap in ships.beings) |=(s=^ship s+(scot %p s)))] + %group (enjs:res resource.beings) + == -- :: -++ dej +++ dejs =, dejs:format |% ++ update @@ -90,6 +106,8 @@ [%add add-contact] [%remove remove-contact] [%edit edit-contact] + [%allow beings] + [%disallow beings] == :: ++ initial (op ;~(pfix sig fed:ag) cont) @@ -108,6 +126,12 @@ [%edit-field edit] == :: + ++ beings + %- of + :~ [%ships (as (su ;~(pfix sig fed:ag)))] + [%group dejs:res] + == + :: ++ cont %- ot :~ [%nickname so] diff --git a/pkg/arvo/sur/contact-store.hoon b/pkg/arvo/sur/contact-store.hoon index ea118a2e0..ad6765bca 100644 --- a/pkg/arvo/sur/contact-store.hoon +++ b/pkg/arvo/sur/contact-store.hoon @@ -1,3 +1,4 @@ +/- *resource |% +$ rolodex (map ship contact) +$ contact @@ -18,10 +19,17 @@ [%avatar avatar=(unit @t)] == :: ++$ beings + $% [%ships ships=(set ship)] + [%group =resource] + == +:: +$ update $% [%initial =rolodex] [%add =ship =contact] [%remove =ship] [%edit =ship =edit-field] + [%allow =beings] + [%disallow =beings] == -- From 6d95cc76a4d20c9ac8fcb2b5d80fe73ed220a360 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 19 Jan 2021 13:56:17 -0600 Subject: [PATCH 07/61] interface: basic new contact-store support --- .../src/logic/reducers/contact-update.ts | 78 +++++++++---------- pkg/interface/src/logic/store/store.ts | 7 +- .../src/logic/subscription/global.ts | 3 +- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/pkg/interface/src/logic/reducers/contact-update.ts b/pkg/interface/src/logic/reducers/contact-update.ts index 2ba1da1d0..0f03c1292 100644 --- a/pkg/interface/src/logic/reducers/contact-update.ts +++ b/pkg/interface/src/logic/reducers/contact-update.ts @@ -5,52 +5,52 @@ import { ContactUpdate } from '~/types/contact-update'; type ContactState = Pick; -export default class ContactReducer { - reduce(json: Cage, state: S) { - const data = _.get(json, 'contact-update', false); - if (data) { - this.initial(data, state); - this.add(data, state); - this.remove(data, state); - this.edit(data, state); - } +export const ContactReducer = (json, state) => { + const data = _.get(json, 'contact-update', false); + if (data) { + console.log(data); + initial(data, state); + add(data, state); + remove(data, state); + edit(data, state); + console.log(state); } +}; - initial(json: ContactUpdate, state: S) { - const data = _.get(json, 'initial', false); - if (data) { - state.contacts = data; - } +const initial = (json: ContactUpdate, state: S) => { + const data = _.get(json, 'initial', false); + if (data) { + state.contacts = data; } +}; - add(json: ContactUpdate, state: S) { - const data = _.get(json, 'add', false); - if (data) { - state.contacts[data.ship] = data.contact; - } +const add = (json: ContactUpdate, state: S) => { + const data = _.get(json, 'add', false); + if (data) { + state.contacts[data.ship] = data.contact; } +}; - remove(json: ContactUpdate, state: S) { - const data = _.get(json, 'remove', false); - if ( - data && - (data.ship in state.contacts) - ) { - delete state.contacts[data.ship]; - } +const remove = (json: ContactUpdate, state: S) => { + const data = _.get(json, 'remove', false); + if ( + data && + (data.ship in state.contacts) + ) { + delete state.contacts[data.ship]; } +}; - edit(json: ContactUpdate, state: S) { - const data = _.get(json, 'edit', false); - if ( - data && - (data.ship in state.contacts) - ) { - const edit = Object.keys(data['edit-field']); - if (edit.length !== 1) { - return; - } - state.contacts[data.ship][edit[0]] = data['edit-field'][edit[0]]; +const edit = (json: ContactUpdate, state: S) => { + const data = _.get(json, 'edit', false); + if ( + data && + (data.ship in state.contacts) + ) { + const edit = Object.keys(data['edit-field']); + if (edit.length !== 1) { + return; } + state.contacts[data.ship][edit[0]] = data['edit-field'][edit[0]]; } -} +}; diff --git a/pkg/interface/src/logic/store/store.ts b/pkg/interface/src/logic/store/store.ts index 56720d4d9..1229bf0b8 100644 --- a/pkg/interface/src/logic/store/store.ts +++ b/pkg/interface/src/logic/store/store.ts @@ -6,10 +6,10 @@ import LocalReducer from '../reducers/local'; import { StoreState } from './type'; import { Timebox } from '~/types'; import { Cage } from '~/types/cage'; -import ContactReducer from '../reducers/contact-update'; import S3Reducer from '../reducers/s3-update'; import { GraphReducer } from '../reducers/graph-update'; import { HarkReducer } from '../reducers/hark-update'; +import { ContactReducer } from '../reducers/contact-update'; import GroupReducer from '../reducers/group-update'; import LaunchReducer from '../reducers/launch-update'; import ConnectionReducer from '../reducers/connection'; @@ -34,7 +34,6 @@ export default class GlobalStore extends BaseStore { inviteReducer = new InviteReducer(); metadataReducer = new MetadataReducer(); localReducer = new LocalReducer(); - contactReducer = new ContactReducer(); s3Reducer = new S3Reducer(); groupReducer = new GroupReducer(); launchReducer = new LaunchReducer(); @@ -54,7 +53,7 @@ export default class GlobalStore extends BaseStore { baseHash: null, invites: {}, associations: { - contacts: {}, + groups: {}, graph: {}, }, groups: {}, @@ -97,12 +96,12 @@ export default class GlobalStore extends BaseStore { this.inviteReducer.reduce(data, this.state); this.metadataReducer.reduce(data, this.state); this.localReducer.reduce(data, this.state); - this.contactReducer.reduce(data, this.state); this.s3Reducer.reduce(data, this.state); this.groupReducer.reduce(data, this.state); this.launchReducer.reduce(data, this.state); this.connReducer.reduce(data, this.state); GraphReducer(data, this.state); HarkReducer(data, this.state); + ContactReducer(data, this.state); } } diff --git a/pkg/interface/src/logic/subscription/global.ts b/pkg/interface/src/logic/subscription/global.ts index d6af89428..655e66e4e 100644 --- a/pkg/interface/src/logic/subscription/global.ts +++ b/pkg/interface/src/logic/subscription/global.ts @@ -36,7 +36,8 @@ export default class GlobalSubscription extends BaseSubscription { this.subscribe('/groups', 'group-store'); this.clearQueue(); - this.subscribe('/updates', 'contact-store'); + // TODO: update to get /updates + this.subscribe('/all', 'contact-store'); this.subscribe('/all', 's3-store'); this.subscribe('/keys', 'graph-store'); this.subscribe('/updates', 'hark-store'); From 54b64f56821a80db77b2d6056607ac65f6544f63 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 19 Jan 2021 15:07:11 -0600 Subject: [PATCH 08/61] contacts: write hooks and use permisssioning system --- pkg/arvo/app/contact-pull-hook.hoon | 45 ++++++++++++++++ pkg/arvo/app/contact-push-hook.hoon | 81 +++++++++++++++++++++++++++++ pkg/arvo/app/contact-store.hoon | 36 +++++++++---- pkg/arvo/lib/contact.hoon | 34 ++++++++++++ 4 files changed, 187 insertions(+), 9 deletions(-) create mode 100644 pkg/arvo/app/contact-pull-hook.hoon create mode 100644 pkg/arvo/app/contact-push-hook.hoon create mode 100644 pkg/arvo/lib/contact.hoon diff --git a/pkg/arvo/app/contact-pull-hook.hoon b/pkg/arvo/app/contact-pull-hook.hoon new file mode 100644 index 000000000..9d66a20c1 --- /dev/null +++ b/pkg/arvo/app/contact-pull-hook.hoon @@ -0,0 +1,45 @@ +/- *resource +/+ store=contact-store, contact, default-agent, verb, dbug, pull-hook +~% %contact-pull-hook-top ..part ~ +|% ++$ card card:agent:gall +++ config + ^- config:pull-hook + :* %contact-store + update:store + %contact-update + %contact-push-hook + == +-- +:: +%- agent:dbug +^- agent:gall +%- (agent:pull-hook config) +^- (pull-hook:pull-hook config) +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) + dep ~(. (default:pull-hook this config) bowl) + con ~(. contact bowl) +:: +++ on-init on-init:def +++ on-save !>(~) +++ on-load on-load:def +++ on-poke on-poke:def +++ on-peek on-peek:def +++ on-arvo on-arvo:def +++ on-fail on-fail:def +++ on-agent on-agent:def +++ on-watch on-watch:def +++ on-leave on-leave:def +++ on-pull-nack + |= [=resource =tang] + ^- (quip card _this) + :_ this + ?~ (get-contact:con entity.resource) ~ + =- [%pass /pl-nack %agent [our.bowl %contact-store] %poke %contact-update -]~ + !> ^- update:store + [%remove entity.resource] +:: +++ on-pull-kick |=(=resource `/) +-- diff --git a/pkg/arvo/app/contact-push-hook.hoon b/pkg/arvo/app/contact-push-hook.hoon new file mode 100644 index 000000000..12b665e61 --- /dev/null +++ b/pkg/arvo/app/contact-push-hook.hoon @@ -0,0 +1,81 @@ +/+ store=contact-store, res=resource, contact, default-agent, dbug, push-hook +~% %contact-push-hook-top ..part ~ +|% ++$ card card:agent:gall +++ config + ^- config:push-hook + :* %contact-store + /our + update:store + %contact-update + %graph-pull-hook + == +:: ++$ agent (push-hook:push-hook config) +-- +:: +%- agent:dbug +^- agent:gall +%- (agent:push-hook config) +^- agent +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) + con ~(. contact bowl) +:: +++ on-init on-init:def +++ on-save !>(~) +++ on-load on-load:def +++ on-poke on-poke:def +++ on-agent on-agent:def +++ on-watch on-watch:def +++ on-leave on-leave:def +++ on-peek on-peek:def +++ on-arvo on-arvo:def +++ on-fail on-fail:def +:: +++ should-proxy-update + |= =vase + ^- ? + =/ =update:store !<(update:store vase) + ?- -.update + %initial %.n + %add %.y + %remove %.y + %edit %.y + %allow %.n + %disallow %.n + == +:: +++ resource-for-update + |= =vase + ^- (unit resource:res) + =/ =update:store !<(update:store vase) + ?- -.update + %initial ~ + %add `[our.bowl %our] + %remove `[our.bowl %our] + %edit `[our.bowl %our] + %allow ~ + %disallow `[our.bowl %our] + == +:: +++ initial-watch + |= [=path =resource:res] + ^- vase + ?> (is-allowed:con src.bowl) + !> ^- update:store + =/ contact=(unit contact:store) (get-contact:con our.bowl) + :+ %add + our.bowl + ?^ contact u.contact + *contact:store +:: +++ take-update + |= =vase + ^- [(list card) agent] + =/ =update:store !<(update:store vase) + ?. ?=(%disallow -.update) [~ this] + :_ this + [%give %kick ~[resource+(en-path:res [our.bowl %our])] ~]~ +-- diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index bcb2897de..c1d7734b0 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -48,6 +48,14 @@ ?+ path (on-watch:def path) [%all ~] (give [%initial rolodex]) [%updates ~] ~ + :: + [%our ~] + %- give + :+ %add + our.bowl + =/ contact=(unit contact:store) (~(get by rolodex) our.bowl) + ?~ contact *contact:store + u.contact == [cards this] :: @@ -87,20 +95,19 @@ ^- (quip card _state) =. rolodex (~(uni by rolodex) rolo) :_ state(rolodex rolodex) - (send-diff [%initial rolodex]) + (send-diff [%initial rolodex] %.n) :: ++ handle-add |= [=ship =contact:store] ^- (quip card _state) - ?< (~(has by rolodex) ship) - :- (send-diff [%add ship contact]) + :- (send-diff [%add ship contact] =(ship our.bowl)) state(rolodex (~(put by rolodex) ship contact)) :: ++ handle-remove |= =ship ^- (quip card _state) ?> (~(has by rolodex) ship) - :- (send-diff [%remove ship]) + :- (send-diff [%remove ship] =(ship our.bowl)) state(rolodex (~(del by rolodex) ship)) :: ++ handle-edit @@ -109,7 +116,7 @@ ^- (quip card _state) =/ contact (~(got by rolodex) ship) =. contact (edit-contact contact edit-field) - :- (send-diff [%edit ship edit-field]) + :- (send-diff [%edit ship edit-field] =(ship our.bowl)) state(rolodex (~(put by rolodex) ship contact)) :: ++ edit-contact @@ -128,7 +135,7 @@ ++ handle-allow |= =beings:store ^- (quip card _state) - :- (send-diff [%allow beings]) + :- (send-diff [%allow beings] %.n) ?- -.beings %group state(allowed-groups (~(put in allowed-groups) resource.beings)) %ships state(allowed-ships (~(uni in allowed-ships) ships.beings)) @@ -137,16 +144,20 @@ ++ handle-disallow |= =beings:store ^- (quip card _state) - :- (send-diff [%disallow beings]) + :- (send-diff [%disallow beings] %.y) ?- -.beings %group state(allowed-groups (~(del in allowed-groups) resource.beings)) %ships state(allowed-ships (~(dif in allowed-ships) ships.beings)) == :: ++ send-diff - |= =update:store + |= [=update:store our=?] ^- (list card) - [%give %fact ~[/updates] %contact-update !>(update)]~ + =/ paths=(list path) + ?: our + `(list path)`[/updates /our]~ + ~[/updates] + [%give %fact paths %contact-update !>(update)]~ -- :: ++ import @@ -169,6 +180,13 @@ :- ~ :- ~ :- %contact-update !> ^- update:store [%add ship u.contact] + :: + [%x %allowed-ship @ ~] + =/ =ship (slav %p i.t.t.path) + ``noun+!>((~(has in allowed-ships) ship)) + :: + [%x %allowed-groups ~] + ``noun+!>(allowed-groups) == :: ++ on-leave on-leave:def diff --git a/pkg/arvo/lib/contact.hoon b/pkg/arvo/lib/contact.hoon new file mode 100644 index 000000000..8a86715d5 --- /dev/null +++ b/pkg/arvo/lib/contact.hoon @@ -0,0 +1,34 @@ +/- store=contact-store +/+ group +|_ =bowl:gall +++ scry-for + |* [=mold =path] + .^ mold + %gx + (scot %p our.bowl) + %contact-store + (scot %da now.bowl) + (snoc `^path`path %noun) + == +:: +++ get-contact + |= =ship + ^- (unit contact:store) + =/ upd (scry-for (unit update:store) /contact/(scot %p ship)) + ?~ upd ~ + ?> ?=(%add -.u.upd) + `contact.u.upd +:: +++ is-allowed + |= =ship + ^- ? + =/ shp (scry-for ? /allowed-ship/(scot %p ship)) + ?: shp %.y + =/ allowed-groups ~(tap in (scry-for (set resource) /allowed-groups)) + =/ grp ~(. group bowl) + |- + ?~ allowed-groups %.n + ?: ~(has in (members:grp i.allowed-groups) ship) + %.y + $(allowed-groups t.allowed-groups) +-- From 7ffce92c377c4273e098220f34e051704f2e8f33 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 19 Jan 2021 15:09:30 -0600 Subject: [PATCH 09/61] hood: start %contact-push/pull-hooks --- pkg/arvo/app/contact-store.hoon | 2 +- pkg/arvo/app/hood.hoon | 3 ++- pkg/arvo/lib/contact.hoon | 4 ++-- pkg/arvo/lib/hood/drum.hoon | 5 +++++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index c1d7734b0..0276821b1 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -155,7 +155,7 @@ ^- (list card) =/ paths=(list path) ?: our - `(list path)`[/updates /our]~ + [/updates /our ~] ~[/updates] [%give %fact paths %contact-update !>(update)]~ -- diff --git a/pkg/arvo/app/hood.hoon b/pkg/arvo/app/hood.hoon index 1b62fd165..24a9e524c 100644 --- a/pkg/arvo/app/hood.hoon +++ b/pkg/arvo/app/hood.hoon @@ -2,7 +2,7 @@ /+ drum=hood-drum, helm=hood-helm, kiln=hood-kiln |% +$ state - $: %11 + $: %12 drum=state:drum helm=state:helm kiln=state:kiln @@ -14,6 +14,7 @@ [%8 drum=state:drum helm=state:helm kiln=state:kiln] [%9 drum=state:drum helm=state:helm kiln=state:kiln] [%10 drum=state:drum helm=state:helm kiln=state:kiln] + [%11 drum=state:drum helm=state:helm kiln=state:kiln] == +$ any-state-tuple $: drum=any-state:drum diff --git a/pkg/arvo/lib/contact.hoon b/pkg/arvo/lib/contact.hoon index 8a86715d5..449478e12 100644 --- a/pkg/arvo/lib/contact.hoon +++ b/pkg/arvo/lib/contact.hoon @@ -1,4 +1,4 @@ -/- store=contact-store +/- store=contact-store, *resource /+ group |_ =bowl:gall ++ scry-for @@ -28,7 +28,7 @@ =/ grp ~(. group bowl) |- ?~ allowed-groups %.n - ?: ~(has in (members:grp i.allowed-groups) ship) + ?: (~(has in (members:grp i.allowed-groups)) ship) %.y $(allowed-groups t.allowed-groups) -- diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index e3c33eda9..f7676bfdd 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -91,6 +91,8 @@ %herm %contact-store %contact-hook + %contact-push-hook + %contact-pull-hook %contact-view %metadata-store %metadata-hook @@ -248,6 +250,9 @@ => (se-born | %home %hark-store) => (se-born | %home %observe-hook) (se-born | %home %herm) + =? ..on-load (lte hood-version %12) + => (se-born | %home %contact-push-hook) + (se-born | %home %contact-pull-hook) ..on-load :: ++ reap-phat :: ack connect From 058bd69cf146ae1fb478f47e182c3780e4c17ad5 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 19 Jan 2021 16:07:34 -0600 Subject: [PATCH 10/61] interface: broke apart settings and profile, updated StatusBar UI --- .../src/logic/reducers/contact-update.ts | 2 +- pkg/interface/src/views/App.js | 3 + .../profile}/components/ContactCard.tsx | 1 + .../src/views/apps/profile/profile.tsx | 115 +++--------------- .../components/lib/BackgroundPicker.tsx | 0 .../components/lib/BucketList.tsx | 0 .../components/lib/DisplayForm.tsx | 0 .../components/lib/RemoteContent.tsx | 0 .../components/lib/S3Form.tsx | 0 .../components/lib/Security.tsx | 0 .../components/settings.tsx | 0 .../src/views/apps/settings/settings.tsx | 48 ++++++++ .../src/views/components/StatusBar.js | 9 +- .../src/views/landscape/components/Content.js | 9 ++ .../landscape/components/PopoverRoutes.tsx | 10 -- 15 files changed, 82 insertions(+), 115 deletions(-) rename pkg/interface/src/views/{landscape => apps/profile}/components/ContactCard.tsx (99%) rename pkg/interface/src/views/apps/{profile => settings}/components/lib/BackgroundPicker.tsx (100%) rename pkg/interface/src/views/apps/{profile => settings}/components/lib/BucketList.tsx (100%) rename pkg/interface/src/views/apps/{profile => settings}/components/lib/DisplayForm.tsx (100%) rename pkg/interface/src/views/apps/{profile => settings}/components/lib/RemoteContent.tsx (100%) rename pkg/interface/src/views/apps/{profile => settings}/components/lib/S3Form.tsx (100%) rename pkg/interface/src/views/apps/{profile => settings}/components/lib/Security.tsx (100%) rename pkg/interface/src/views/apps/{profile => settings}/components/settings.tsx (100%) create mode 100644 pkg/interface/src/views/apps/settings/settings.tsx diff --git a/pkg/interface/src/logic/reducers/contact-update.ts b/pkg/interface/src/logic/reducers/contact-update.ts index 0f03c1292..2de64b6dd 100644 --- a/pkg/interface/src/logic/reducers/contact-update.ts +++ b/pkg/interface/src/logic/reducers/contact-update.ts @@ -13,7 +13,7 @@ export const ContactReducer = (json, state) => { add(data, state); remove(data, state); edit(data, state); - console.log(state); + console.log(state.contacts); } }; diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index 27b32293e..f40f633b4 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -137,6 +137,8 @@ class App extends React.Component { const notificationsCount = state.notificationsCount || 0; const doNotDisturb = state.doNotDisturb || false; + const ourContact = this.state.contacts[this.ship] || null; + console.log(ourContact, this.state.contacts, this.ship); const showBanner = localStorage.getItem("2020BreachBanner") || "flex"; let banner = null; @@ -155,6 +157,7 @@ class App extends React.Component { props={this.props} associations={associations} invites={this.state.invites} + ourContact={ourContact} api={this.api} connection={this.state.connection} subscription={this.subscription} diff --git a/pkg/interface/src/views/landscape/components/ContactCard.tsx b/pkg/interface/src/views/apps/profile/components/ContactCard.tsx similarity index 99% rename from pkg/interface/src/views/landscape/components/ContactCard.tsx rename to pkg/interface/src/views/apps/profile/components/ContactCard.tsx index 3738428eb..b7fe89e29 100644 --- a/pkg/interface/src/views/landscape/components/ContactCard.tsx +++ b/pkg/interface/src/views/apps/profile/components/ContactCard.tsx @@ -135,6 +135,7 @@ export function ContactCard(props: ContactCardProps) { gridTemplateColumns="100%" gridRowGap="5" maxWidth="400px" + width="100%" > { - const selected = current === view; - const icon = (view) => { - switch(view) { - case 'identity': - return 'Smiley'; - case 'settings': - return 'Adjust'; - default: - return 'Circle' - } - } - return ( - - - - - {children} - - - - ); -}; - export default function ProfileScreen(props: any) { const { ship, dark } = props; const hideAvatars = useLocalState(state => state.hideAvatars); @@ -49,101 +18,45 @@ export default function ProfileScreen(props: any) { OS1 - Profile - { - const { view } = match.params; - const contact = props.contacts?.["/~/default"]?.[window.ship]; + const contact = props.contacts?.[window.ship]; const sigilColor = contact?.color ? `#${uxToHex(contact.color)}` : dark ? "#FFFFFF" : "#000000"; + if(!contact) { return null; } - if (!view && !MOBILE_BROWSER_REGEX.test(window.navigator.userAgent)) { - history.replace("/~profile/identity"); - } - - const image = (!hideAvatars && contact?.avatar) - ? - : ; return ( - - - - {image} - - - - - Your Identity - - - Ship Settings - - - - - {"<- Back"} - - {view === "settings" && } - - {view === "identity" && ( - <> - Your identity provides the default information you can optionally share with groups in the group settings panel. - - - )} + ); }} - > - + /> ); } diff --git a/pkg/interface/src/views/apps/profile/components/lib/BackgroundPicker.tsx b/pkg/interface/src/views/apps/settings/components/lib/BackgroundPicker.tsx similarity index 100% rename from pkg/interface/src/views/apps/profile/components/lib/BackgroundPicker.tsx rename to pkg/interface/src/views/apps/settings/components/lib/BackgroundPicker.tsx diff --git a/pkg/interface/src/views/apps/profile/components/lib/BucketList.tsx b/pkg/interface/src/views/apps/settings/components/lib/BucketList.tsx similarity index 100% rename from pkg/interface/src/views/apps/profile/components/lib/BucketList.tsx rename to pkg/interface/src/views/apps/settings/components/lib/BucketList.tsx diff --git a/pkg/interface/src/views/apps/profile/components/lib/DisplayForm.tsx b/pkg/interface/src/views/apps/settings/components/lib/DisplayForm.tsx similarity index 100% rename from pkg/interface/src/views/apps/profile/components/lib/DisplayForm.tsx rename to pkg/interface/src/views/apps/settings/components/lib/DisplayForm.tsx diff --git a/pkg/interface/src/views/apps/profile/components/lib/RemoteContent.tsx b/pkg/interface/src/views/apps/settings/components/lib/RemoteContent.tsx similarity index 100% rename from pkg/interface/src/views/apps/profile/components/lib/RemoteContent.tsx rename to pkg/interface/src/views/apps/settings/components/lib/RemoteContent.tsx diff --git a/pkg/interface/src/views/apps/profile/components/lib/S3Form.tsx b/pkg/interface/src/views/apps/settings/components/lib/S3Form.tsx similarity index 100% rename from pkg/interface/src/views/apps/profile/components/lib/S3Form.tsx rename to pkg/interface/src/views/apps/settings/components/lib/S3Form.tsx diff --git a/pkg/interface/src/views/apps/profile/components/lib/Security.tsx b/pkg/interface/src/views/apps/settings/components/lib/Security.tsx similarity index 100% rename from pkg/interface/src/views/apps/profile/components/lib/Security.tsx rename to pkg/interface/src/views/apps/settings/components/lib/Security.tsx diff --git a/pkg/interface/src/views/apps/profile/components/settings.tsx b/pkg/interface/src/views/apps/settings/components/settings.tsx similarity index 100% rename from pkg/interface/src/views/apps/profile/components/settings.tsx rename to pkg/interface/src/views/apps/settings/components/settings.tsx diff --git a/pkg/interface/src/views/apps/settings/settings.tsx b/pkg/interface/src/views/apps/settings/settings.tsx new file mode 100644 index 000000000..bfe331ecd --- /dev/null +++ b/pkg/interface/src/views/apps/settings/settings.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import { Route, Link, Switch } from "react-router-dom"; +import Helmet from 'react-helmet'; + +import { Box, Text, Row, Col, Icon, BaseImage } from "@tlon/indigo-react"; + +import Settings from "./components/settings"; +import useLocalState from "~/logic/state/local"; + +export default function SettingsScreen(props: any) { + const { ship, dark } = props; + const hideAvatars = useLocalState(state => state.hideAvatars); + return ( + <> + + Landscape - Settings + + { + return ( + + + + + + ); + }} + /> + + ); +} diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 6b32bd4eb..2f2c5cb74 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -10,6 +10,8 @@ const StatusBar = (props) => { const invites = [].concat(...Object.values(props.invites).map(obj => Object.values(obj))); const metaKey = (window.navigator.platform.includes('Mac')) ? '⌘' : 'Ctrl+'; const toggleOmnibox = useLocalState(state => state.toggleOmnibox); + + const color = !!props.ourContact ? props.ourContact.color : 'black'; return ( { - toggleOmnibox()}> { !props.doNotDisturb && (props.notificationsCount > 0 || invites.length > 0) && ( @@ -59,9 +60,11 @@ const StatusBar = (props) => { > Submit an issue + props.history.push('/~settings')}> + + props.history.push('/~profile')}> - - ~{props.ship} + diff --git a/pkg/interface/src/views/landscape/components/Content.js b/pkg/interface/src/views/landscape/components/Content.js index 3d14f6f1d..a507e4f3b 100644 --- a/pkg/interface/src/views/landscape/components/Content.js +++ b/pkg/interface/src/views/landscape/components/Content.js @@ -7,6 +7,7 @@ import LaunchApp from '~/views/apps/launch/app'; import TermApp from '~/views/apps/term/app'; import Landscape from '~/views/landscape/index'; import Profile from '~/views/apps/profile/profile'; +import Settings from '~/views/apps/settings/settings'; import ErrorComponent from '~/views/components/Error'; import Notifications from '~/views/apps/notifications/notifications'; import GraphApp from '../../apps/graph/app'; @@ -63,6 +64,14 @@ export const Content = (props) => { /> )} /> + ( + + )} + /> ( diff --git a/pkg/interface/src/views/landscape/components/PopoverRoutes.tsx b/pkg/interface/src/views/landscape/components/PopoverRoutes.tsx index 5b42228ff..4a50a5d44 100644 --- a/pkg/interface/src/views/landscape/components/PopoverRoutes.tsx +++ b/pkg/interface/src/views/landscape/components/PopoverRoutes.tsx @@ -9,7 +9,6 @@ import { Association } from "~/types/metadata-update"; import GlobalApi from "~/logic/api/global"; import {GroupNotificationsConfig, S3State} from "~/types"; -import { ContactCard } from "./ContactCard"; import { GroupSettings } from "./GroupSettings/GroupSettings"; import { Participants } from "./Participants"; @@ -135,15 +134,6 @@ export function PopoverRoutes( api={props.api} /> )} - {view === "profile" && ( - - )} From 7bb76ba39c2fdddc9d9f333f404bd8fc31694e88 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 21 Jan 2021 11:36:48 -0600 Subject: [PATCH 11/61] contact-store: change fields in to reflect new profile --- pkg/arvo/app/contact-store.hoon | 8 +++++--- pkg/arvo/lib/contact-store.hoon | 26 ++++++++++++++------------ pkg/arvo/sur/contact-store.hoon | 13 +++++++------ 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index 0276821b1..8216ee148 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -100,6 +100,7 @@ ++ handle-add |= [=ship =contact:store] ^- (quip card _state) + =. last-updated.contact now.bowl :- (send-diff [%add ship contact] =(ship our.bowl)) state(rolodex (~(put by rolodex) ship contact)) :: @@ -116,6 +117,7 @@ ^- (quip card _state) =/ contact (~(got by rolodex) ship) =. contact (edit-contact contact edit-field) + =. last-updated.contact now.bowl :- (send-diff [%edit ship edit-field] =(ship our.bowl)) state(rolodex (~(put by rolodex) ship contact)) :: @@ -124,11 +126,11 @@ ^- contact:store ?- -.edit %nickname contact(nickname nickname.edit) - %email contact(email email.edit) - %phone contact(phone phone.edit) - %website contact(website website.edit) + %bio contact(bio bio.edit) + %status contact(status status.edit) %color contact(color color.edit) %avatar contact(avatar avatar.edit) + %cover contact(cover cover.edit) == -- :: diff --git a/pkg/arvo/lib/contact-store.hoon b/pkg/arvo/lib/contact-store.hoon index 78e9c39ca..67c7ed9e5 100644 --- a/pkg/arvo/lib/contact-store.hoon +++ b/pkg/arvo/lib/contact-store.hoon @@ -63,11 +63,12 @@ ^- json %- pairs :~ [%nickname s+nickname.contact] - [%email s+email.contact] - [%phone s+phone.contact] - [%website s+website.contact] + [%bio s+bio.contact] + [%status s+status.contact] [%color s+(scot %ux color.contact)] [%avatar ?~(avatar.contact ~ s+u.avatar.contact)] + [%cover ?~(cover.contact ~ s+u.cover.contact)] + [%last-updated (time last-updated.contact)] == :: ++ edit @@ -76,11 +77,11 @@ %+ frond -.field ?- -.field %nickname s+nickname.field - %email s+email.field - %phone s+phone.field - %website s+website.field + %bio s+bio.field + %status s+status.field %color s+(scot %ux color.field) %avatar ?~(avatar.field ~ s+u.avatar.field) + %cover ?~(cover.field ~ s+u.cover.field) == :: ++ beng @@ -135,21 +136,22 @@ ++ cont %- ot :~ [%nickname so] - [%email so] - [%phone so] - [%website so] + [%bio so] + [%status so] [%color nu] [%avatar (mu so)] + [%cover (mu so)] + [%last-updated di] == :: ++ edit %- of :~ [%nickname so] - [%email so] - [%phone so] - [%website so] + [%bio so] + [%status so] [%color nu] [%avatar (mu so)] + [%cover (mu so)] == -- -- diff --git a/pkg/arvo/sur/contact-store.hoon b/pkg/arvo/sur/contact-store.hoon index ad6765bca..8424c04c5 100644 --- a/pkg/arvo/sur/contact-store.hoon +++ b/pkg/arvo/sur/contact-store.hoon @@ -3,20 +3,21 @@ +$ rolodex (map ship contact) +$ contact $: nickname=@t - email=@t - phone=@t - website=@t + bio=@t + status=@t color=@ux avatar=(unit @t) + cover=(unit @t) + last-updated=@da == :: +$ edit-field $% [%nickname nickname=@t] - [%email email=@t] - [%phone phone=@t] - [%website website=@t] + [%bio bio=@t] + [%status status=@t] [%color color=@ux] [%avatar avatar=(unit @t)] + [%cover cover=(unit @t)] == :: +$ beings From 8f5efe46be90d101c2576d01dd00c8e124e54776 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 21 Jan 2021 11:37:30 -0600 Subject: [PATCH 12/61] interface: add blank profile --- .../views/apps/profile/components/Profile.tsx | 76 +++++++++++++++++++ .../src/views/apps/profile/profile.tsx | 20 ++--- .../src/views/components/StatusBar.js | 5 +- 3 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 pkg/interface/src/views/apps/profile/components/Profile.tsx diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx new file mode 100644 index 000000000..9df092bfa --- /dev/null +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -0,0 +1,76 @@ +import React from "react"; +import { Sigil } from "~/logic/lib/sigil"; + +import { uxToHex } from "~/logic/lib/util"; +import { + Center, + Col, + Box, + Text, + Row, + BaseImage, +} from "@tlon/indigo-react"; +import { AsyncButton } from "~/views/components/AsyncButton"; +import GlobalApi from "~/logic/api/global"; +import useLocalState from "~/logic/state/local"; + + +const emptyContact = { + nickname: '', + bio: '', + status: '', + avatar: null, + cover: null, + 'last-updated': 0 +}; + +export function Profile(props: any) { + const { hideAvatars, hideNicknames } = useLocalState(({ hideAvatars, hideNicknames }) => ({ + hideAvatars, hideNicknames + })); + if (!props.ship) { + return null; + } + const { contact } = props; + const hexColor = contact?.color ? `#${uxToHex(contact.color)}` : "#000000"; + const cover = (contact?.cover) + ? + : ; + + const image = (!hideAvatars && contact?.avatar) + ? + : ; + + const nickname = + (!hideNicknames && contact?.nickname) ? contact.nickname : ""; + + return ( +
+ + + {cover} + + +
+ + {image} + +
+ + {nickname} + +
+
+
+ ); +} diff --git a/pkg/interface/src/views/apps/profile/profile.tsx b/pkg/interface/src/views/apps/profile/profile.tsx index a4efb103a..48f3141ab 100644 --- a/pkg/interface/src/views/apps/profile/profile.tsx +++ b/pkg/interface/src/views/apps/profile/profile.tsx @@ -4,14 +4,13 @@ import Helmet from 'react-helmet'; import { Box, Text, Row, Col, Icon, BaseImage } from "@tlon/indigo-react"; -import { Sigil } from "~/logic/lib/sigil"; import { uxToHex } from "~/logic/lib/util"; -import { ContactCard } from "./components/ContactCard"; +import { Profile } from "./components/Profile"; import useLocalState from "~/logic/state/local"; export default function ProfileScreen(props: any) { - const { ship, dark } = props; + const { dark } = props; const hideAvatars = useLocalState(state => state.hideAvatars); return ( <> @@ -19,35 +18,30 @@ export default function ProfileScreen(props: any) { OS1 - Profile { - const contact = props.contacts?.[window.ship]; + const ship = match.params.ship; + const contact = props.contacts?.[ship]; const sigilColor = contact?.color ? `#${uxToHex(contact.color)}` : dark ? "#FFFFFF" : "#000000"; - if(!contact) { - return null; - } return ( - diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 2f2c5cb74..55f73d50c 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -63,7 +63,10 @@ const StatusBar = (props) => { props.history.push('/~settings')}> - props.history.push('/~profile')}> + props.history.push('/~profile/' + window.ship)}> From 288302a406063afc2e3289e395f612cc31f872ac Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 21 Jan 2021 11:58:59 -0600 Subject: [PATCH 13/61] wip --- pkg/interface/src/views/App.js | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index f40f633b4..19f4ffc8c 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -138,7 +138,6 @@ class App extends React.Component { const notificationsCount = state.notificationsCount || 0; const doNotDisturb = state.doNotDisturb || false; const ourContact = this.state.contacts[this.ship] || null; - console.log(ourContact, this.state.contacts, this.ship); const showBanner = localStorage.getItem("2020BreachBanner") || "flex"; let banner = null; From 2ad33fe6a389d444368572acb004473d5877757b Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 21 Jan 2021 13:39:43 -0600 Subject: [PATCH 14/61] interface: built out profile view screen --- .../views/apps/profile/components/Profile.tsx | 72 ++++++++++++++++--- .../src/views/apps/profile/profile.tsx | 4 +- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 9df092bfa..65cb87bf9 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -4,15 +4,17 @@ import { Sigil } from "~/logic/lib/sigil"; import { uxToHex } from "~/logic/lib/util"; import { Center, - Col, Box, Text, Row, BaseImage, + Button, } from "@tlon/indigo-react"; import { AsyncButton } from "~/views/components/AsyncButton"; +import RichText from "~/views/components/RichText"; import GlobalApi from "~/logic/api/global"; import useLocalState from "~/logic/state/local"; +import { useHistory } from "react-router-dom"; const emptyContact = { @@ -25,13 +27,14 @@ const emptyContact = { }; export function Profile(props: any) { + const history = useHistory(); const { hideAvatars, hideNicknames } = useLocalState(({ hideAvatars, hideNicknames }) => ({ hideAvatars, hideNicknames })); if (!props.ship) { return null; } - const { contact } = props; + const { contact, isEdit} = props; const hexColor = contact?.color ? `#${uxToHex(contact.color)}` : "#000000"; const cover = (contact?.cover) ? @@ -41,9 +44,6 @@ export function Profile(props: any) { ? : ; - const nickname = - (!hideNicknames && contact?.nickname) ? contact.nickname : ""; - return (
@@ -66,10 +66,64 @@ export function Profile(props: any) { {image}
- - {nickname} - + +
+ + {(contact?.nickname ? contact.nickname : "")} + +
+
+ +
+ + {`~${ship}`} + +
+
+ +
+ + {(contact?.bio ? contact.bio : "")} + +
+
+ { (ship === window.ship && !isEdit) ? ( + +
+ +
+
+ ) : null + } + +
+ {`~${ship} `} + remains private +
+
); diff --git a/pkg/interface/src/views/apps/profile/profile.tsx b/pkg/interface/src/views/apps/profile/profile.tsx index 48f3141ab..0c2a7f69d 100644 --- a/pkg/interface/src/views/apps/profile/profile.tsx +++ b/pkg/interface/src/views/apps/profile/profile.tsx @@ -18,9 +18,10 @@ export default function ProfileScreen(props: any) { OS1 - Profile { const ship = match.params.ship; + const isEdit = match.url.includes('edit'); const contact = props.contacts?.[ship]; const sigilColor = contact?.color ? `#${uxToHex(contact.color)}` @@ -44,6 +45,7 @@ export default function ProfileScreen(props: any) { contact={contact} api={props.api} s3={props.s3} + isEdit={isEdit} />
From 316b86e7fbebb5ac931fa2e7a3bc8465acee198f Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 26 Jan 2021 15:22:33 -0600 Subject: [PATCH 15/61] contact-store: update to add public groups and force us to always keep our own contact --- pkg/arvo/app/contact-store.hoon | 25 ++++++++++++++++++------- pkg/arvo/lib/contact-store.hoon | 18 ++++++++++++------ pkg/arvo/sur/contact-store.hoon | 3 +++ 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index 8216ee148..902ac4916 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -35,7 +35,10 @@ |= old-vase=vase ^- (quip card _this) =/ old !<(versioned-state old-vase) - ?+ -.old [~ this] + ?+ -.old + =. rolodex (~(put by rolodex) our.bowl *contact:store) + [~ this(state state)] + :: %4 [~ this(state old)] == :: @@ -109,6 +112,8 @@ ^- (quip card _state) ?> (~(has by rolodex) ship) :- (send-diff [%remove ship] =(ship our.bowl)) + ?: =(ship our.bowl) + state(rolodex (~(put by rolodex) *contact:store)) state(rolodex (~(del by rolodex) ship)) :: ++ handle-edit @@ -125,12 +130,18 @@ |= [=contact:store edit=edit-field:store] ^- contact:store ?- -.edit - %nickname contact(nickname nickname.edit) - %bio contact(bio bio.edit) - %status contact(status status.edit) - %color contact(color color.edit) - %avatar contact(avatar avatar.edit) - %cover contact(cover cover.edit) + %nickname contact(nickname nickname.edit) + %bio contact(bio bio.edit) + %status contact(status status.edit) + %color contact(color color.edit) + %avatar contact(avatar avatar.edit) + %cover contact(cover cover.edit) + :: + %add-group + contact(groups (~(put in groups.contact) resource.edit)) + :: + %remove-group + contact(groups (~(del in groups.contact) resource.edit)) == -- :: diff --git a/pkg/arvo/lib/contact-store.hoon b/pkg/arvo/lib/contact-store.hoon index 67c7ed9e5..722b779e9 100644 --- a/pkg/arvo/lib/contact-store.hoon +++ b/pkg/arvo/lib/contact-store.hoon @@ -68,6 +68,7 @@ [%color s+(scot %ux color.contact)] [%avatar ?~(avatar.contact ~ s+u.avatar.contact)] [%cover ?~(cover.contact ~ s+u.cover.contact)] + [%groups a+(turn ~(tap in groups.contact) |=(r=resource (enjs:res r)))] [%last-updated (time last-updated.contact)] == :: @@ -76,12 +77,14 @@ ^- json %+ frond -.field ?- -.field - %nickname s+nickname.field - %bio s+bio.field - %status s+status.field - %color s+(scot %ux color.field) - %avatar ?~(avatar.field ~ s+u.avatar.field) - %cover ?~(cover.field ~ s+u.cover.field) + %nickname s+nickname.field + %bio s+bio.field + %status s+status.field + %color s+(scot %ux color.field) + %avatar ?~(avatar.field ~ s+u.avatar.field) + %cover ?~(cover.field ~ s+u.cover.field) + %add-group (enjs:res resource.field) + %remove-group (enjs:res resource.field) == :: ++ beng @@ -141,6 +144,7 @@ [%color nu] [%avatar (mu so)] [%cover (mu so)] + [%groups (as dejs:res)] [%last-updated di] == :: @@ -152,6 +156,8 @@ [%color nu] [%avatar (mu so)] [%cover (mu so)] + [%add-group dejs:res] + [%remove-group dejs:res] == -- -- diff --git a/pkg/arvo/sur/contact-store.hoon b/pkg/arvo/sur/contact-store.hoon index 8424c04c5..37f3af140 100644 --- a/pkg/arvo/sur/contact-store.hoon +++ b/pkg/arvo/sur/contact-store.hoon @@ -8,6 +8,7 @@ color=@ux avatar=(unit @t) cover=(unit @t) + groups=(set resource) last-updated=@da == :: @@ -17,6 +18,8 @@ [%status status=@t] [%color color=@ux] [%avatar avatar=(unit @t)] + [%add-group =resource] + [%remove-group =resource] [%cover cover=(unit @t)] == :: From e577edfc32ca2045694824c873baaf0a5b6ee2bc Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 26 Jan 2021 15:23:01 -0600 Subject: [PATCH 16/61] interface: split profile into multiple components, beginning Formik work --- .../apps/profile/components/EditProfile.tsx | 127 ++++++++++++++++++ .../views/apps/profile/components/Profile.tsx | 85 ++---------- .../apps/profile/components/ViewProfile.tsx | 82 +++++++++++ .../src/views/components/StatusBar.js | 42 ++++-- 4 files changed, 253 insertions(+), 83 deletions(-) create mode 100644 pkg/interface/src/views/apps/profile/components/EditProfile.tsx create mode 100644 pkg/interface/src/views/apps/profile/components/ViewProfile.tsx diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx new file mode 100644 index 000000000..f7216397a --- /dev/null +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -0,0 +1,127 @@ +import React from "react"; +import * as Yup from "yup"; + +import { + Center, + Box, + Text, + Row, + Button, +} from "@tlon/indigo-react"; +import { Formik, FormikHelpers } from "formik"; +import { useHistory } from "react-router-dom"; + +import GlobalApi from "~/logic/api/global"; +import { Sigil } from "~/logic/lib/sigil"; +import { AsyncButton } from "~/views/components/AsyncButton"; +import { ColorInput } from "~/views/components/ColorInput"; +import { ImageInput } from "~/views/components/ImageInput"; + + +const formSchema = Yup.object({ + nickname: Yup.string(), + bio: Yup.string(), + color: Yup.string() +}); + +const emptyContact = { + nickname: '', + bio: '', + status: '', + color: '0', + avatar: null, + cover: null, + groups: [], + 'last-updated': 0 +}; + + +export function EditProfile(props: any) { + const { contact, ship } = props; + if (ship !== window.ship) { + return null; + } + const history = useHistory(); + + const onSubmit = async (values: any, actions: FormikHelpers) => { + try { + if(!contact) { + const [,,ship] = props.path.split('/'); + values.color = uxToHex(values.color); + const sharedValues = Object.assign({}, values); + sharedValues.avatar = !!values.avatar ? values.avatar : null; + console.log(values); + await props.api.contacts.share(ship, props.path, us, sharedValues); + actions.setStatus({ success: null }); + return; + } + + await Object.keys(values).reduce((acc, key) => { + const newValue = key !== "color" ? values[key] : uxToHex(values[key]); + if (newValue !== contact[key]) { + if (key === "avatar") { + return acc.then(() => + props.api.contacts.edit(props.path, us, { + avatar: { url: newValue }, + } as any) + ); + } + + return acc.then(() => + props.api.contacts.edit(props.path, us, { + [key]: newValue, + } as any) + ); + } + return acc; + }, Promise.resolve()); + actions.setStatus({ success: null }); + } catch (e) { + console.error(e); + actions.setStatus({ error: e.message }); + } + }; + + + + return ( + +
+ + + {image} + + + {nickname} + + + + + + + + + + + {(contact) ? "Save" : "Share Contact"} + + +
+ ); +} diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 65cb87bf9..1fe217bf9 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -1,40 +1,27 @@ import React from "react"; import { Sigil } from "~/logic/lib/sigil"; +import { ViewProfile } from './ViewProfile'; +import { EditProfile } from './EditProfile'; import { uxToHex } from "~/logic/lib/util"; import { Center, Box, - Text, Row, BaseImage, - Button, } from "@tlon/indigo-react"; -import { AsyncButton } from "~/views/components/AsyncButton"; -import RichText from "~/views/components/RichText"; -import GlobalApi from "~/logic/api/global"; import useLocalState from "~/logic/state/local"; import { useHistory } from "react-router-dom"; -const emptyContact = { - nickname: '', - bio: '', - status: '', - avatar: null, - cover: null, - 'last-updated': 0 -}; - export function Profile(props: any) { - const history = useHistory(); - const { hideAvatars, hideNicknames } = useLocalState(({ hideAvatars, hideNicknames }) => ({ - hideAvatars, hideNicknames + const { hideAvatars } = useLocalState(({ hideAvatars }) => ({ + hideAvatars })); if (!props.ship) { return null; } - const { contact, isEdit} = props; + const { contact, isEdit, ship } = props; const hexColor = contact?.color ? `#${uxToHex(contact.color)}` : "#000000"; const cover = (contact?.cover) ? @@ -67,63 +54,11 @@ export function Profile(props: any) {
- -
- - {(contact?.nickname ? contact.nickname : "")} - -
-
- -
- - {`~${ship}`} - -
-
- -
- - {(contact?.bio ? contact.bio : "")} - -
-
- { (ship === window.ship && !isEdit) ? ( - -
- -
-
- ) : null - } - -
- {`~${ship} `} - remains private -
-
+ { isEdit ? ( + + ) : ( + + ) } ); diff --git a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx new file mode 100644 index 000000000..2d766be2c --- /dev/null +++ b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx @@ -0,0 +1,82 @@ +import React from "react"; +import { Sigil } from "~/logic/lib/sigil"; + +import { + Center, + Box, + Text, + Row, + Button, +} from "@tlon/indigo-react"; +import { AsyncButton } from "~/views/components/AsyncButton"; +import RichText from "~/views/components/RichText"; +import { useHistory } from "react-router-dom"; + + +export function ViewProfile(props: any) { + const history = useHistory(); + const { contact, ship } = props; + + return ( + <> + +
+ + {(contact?.nickname ? contact.nickname : "")} + +
+
+ +
+ + {`~${ship}`} + +
+
+ +
+ + {(contact?.bio ? contact.bio : "")} + +
+
+ { (ship === window.ship) ? ( + +
+ +
+
+ ) : null + } + +
+ {`~${ship} `} + remains private +
+
+ + ); +} + diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 55f73d50c..da85eb23a 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -1,7 +1,8 @@ import React from 'react'; -import { Row, Box, Text, Icon, Button } from '@tlon/indigo-react'; +import { Col, Row, Box, Text, Icon, Button } from '@tlon/indigo-react'; import ReconnectButton from './ReconnectButton'; +import { Dropdown } from './Dropdown'; import { StatusBarItem } from './StatusBarItem'; import { Sigil } from '~/logic/lib/sigil'; import useLocalState from '~/logic/state/local'; @@ -11,7 +12,7 @@ const StatusBar = (props) => { const metaKey = (window.navigator.platform.includes('Mac')) ? '⌘' : 'Ctrl+'; const toggleOmnibox = useLocalState(state => state.toggleOmnibox); - const color = !!props.ourContact ? props.ourContact.color : 'black'; + const color = !!props.ourContact ? props.ourContact.color : '#000'; return ( { props.history.push('/~settings')}> - props.history.push('/~profile/' + window.ship)}> - - + + props.history.push('/~profile/' + window.ship)}> + View Profile + + props.history.push('/~profile/' + window.ship)}> + Set Status + + props.history.push('/~profile/' + window.ship)}> + System Settings + + + }> + + + + ); From 683df1b9a40b6df6a138347b74119684111573aa Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 26 Jan 2021 15:41:34 -0600 Subject: [PATCH 17/61] contact-store: fix crash --- pkg/arvo/app/contact-store.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index 902ac4916..7f5b9389b 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -113,7 +113,7 @@ ?> (~(has by rolodex) ship) :- (send-diff [%remove ship] =(ship our.bowl)) ?: =(ship our.bowl) - state(rolodex (~(put by rolodex) *contact:store)) + state(rolodex (~(put by rolodex) our.bowl *contact:store)) state(rolodex (~(del by rolodex) ship)) :: ++ handle-edit From f5e623b04abb7490436cdb7fc69bea45a86b38ea Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 26 Jan 2021 15:41:50 -0600 Subject: [PATCH 18/61] interface: get edit closer --- .../apps/profile/components/EditProfile.tsx | 58 ++++++------------- .../views/apps/profile/components/Profile.tsx | 2 +- 2 files changed, 19 insertions(+), 41 deletions(-) diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx index f7216397a..e78684076 100644 --- a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -2,7 +2,10 @@ import React from "react"; import * as Yup from "yup"; import { + ManagedForm as Form, + ManagedTextInputField as Input, Center, + Col, Box, Text, Row, @@ -21,7 +24,8 @@ import { ImageInput } from "~/views/components/ImageInput"; const formSchema = Yup.object({ nickname: Yup.string(), bio: Yup.string(), - color: Yup.string() + color: Yup.string(), + avatar: Yup.string().nullable() }); const emptyContact = { @@ -58,19 +62,10 @@ export function EditProfile(props: any) { await Object.keys(values).reduce((acc, key) => { const newValue = key !== "color" ? values[key] : uxToHex(values[key]); - if (newValue !== contact[key]) { - if (key === "avatar") { - return acc.then(() => - props.api.contacts.edit(props.path, us, { - avatar: { url: newValue }, - } as any) - ); - } + if (newValue !== contact[key]) { return acc.then(() => - props.api.contacts.edit(props.path, us, { - [key]: newValue, - } as any) + props.api.contacts.edit(ship, { [key]: newValue }) ); } return acc; @@ -90,36 +85,19 @@ export function EditProfile(props: any) { initialValues={contact || emptyContact} onSubmit={onSubmit} > -
- - - {image} - - - {nickname} - + + + + + + + + + + - - - - - - - - {(contact) ? "Save" : "Share Contact"} + Submit diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 1fe217bf9..8dc409edb 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -55,7 +55,7 @@ export function Profile(props: any) {
{ isEdit ? ( - + ) : ( ) } From 95d2d6eb088b2eded5b2b01208366b1ebd2155fc Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Tue, 26 Jan 2021 17:13:00 -0500 Subject: [PATCH 19/61] statusbar: style dropdown --- pkg/interface/src/views/components/StatusBar.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index fdfcfcb30..0da0de027 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -6,7 +6,6 @@ import { Dropdown } from './Dropdown'; import { StatusBarItem } from './StatusBarItem'; import { Sigil } from '~/logic/lib/sigil'; import useLocalState from '~/logic/state/local'; -import { cite } from '~/logic/lib/util'; const StatusBar = (props) => { const invites = [].concat(...Object.values(props.invites).map(obj => Object.values(obj))); @@ -66,28 +65,34 @@ const StatusBar = (props) => { + props.history.push('/~profile/' + window.ship)}> View Profile props.history.push('/~profile/' + window.ship)}> Set Status props.history.push('/~profile/' + window.ship)}> System Settings - + }> Date: Tue, 26 Jan 2021 16:17:41 -0600 Subject: [PATCH 20/61] interface: profile updates work --- pkg/interface/src/logic/api/contacts.ts | 1 + .../src/logic/reducers/contact-update.ts | 5 ++- .../apps/profile/components/EditProfile.tsx | 38 ++++++++----------- .../views/apps/profile/components/Profile.tsx | 2 +- .../src/views/apps/profile/profile.tsx | 3 +- 5 files changed, 22 insertions(+), 27 deletions(-) diff --git a/pkg/interface/src/logic/api/contacts.ts b/pkg/interface/src/logic/api/contacts.ts index 2874ba0ef..cd9f1cd76 100644 --- a/pkg/interface/src/logic/api/contacts.ts +++ b/pkg/interface/src/logic/api/contacts.ts @@ -23,6 +23,7 @@ export default class ContactsApi extends BaseApi { {avatar: null} {avatar: ''} */ + console.log(ship, editField); return this.storeAction({ edit: { ship, diff --git a/pkg/interface/src/logic/reducers/contact-update.ts b/pkg/interface/src/logic/reducers/contact-update.ts index 2de64b6dd..ef3031d33 100644 --- a/pkg/interface/src/logic/reducers/contact-update.ts +++ b/pkg/interface/src/logic/reducers/contact-update.ts @@ -43,14 +43,15 @@ const remove = (json: ContactUpdate, state: S) => { const edit = (json: ContactUpdate, state: S) => { const data = _.get(json, 'edit', false); + const ship = `~${data.ship}`; if ( data && - (data.ship in state.contacts) + (ship in state.contacts) ) { const edit = Object.keys(data['edit-field']); if (edit.length !== 1) { return; } - state.contacts[data.ship][edit[0]] = data['edit-field'][edit[0]]; + state.contacts[ship][edit[0]] = data['edit-field'][edit[0]]; } }; diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx index e78684076..f7c7b4feb 100644 --- a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -14,7 +14,7 @@ import { import { Formik, FormikHelpers } from "formik"; import { useHistory } from "react-router-dom"; -import GlobalApi from "~/logic/api/global"; +import { uxToHex } from "~/logic/lib/util"; import { Sigil } from "~/logic/lib/sigil"; import { AsyncButton } from "~/views/components/AsyncButton"; import { ColorInput } from "~/views/components/ColorInput"; @@ -41,31 +41,23 @@ const emptyContact = { export function EditProfile(props: any) { - const { contact, ship } = props; + const { contact, ship, api } = props; if (ship !== window.ship) { return null; } + console.log(contact); const history = useHistory(); - const onSubmit = async (values: any, actions: FormikHelpers) => { + const onSubmit = async (values: any, actions: any) => { + console.log(values); try { - if(!contact) { - const [,,ship] = props.path.split('/'); - values.color = uxToHex(values.color); - const sharedValues = Object.assign({}, values); - sharedValues.avatar = !!values.avatar ? values.avatar : null; - console.log(values); - await props.api.contacts.share(ship, props.path, us, sharedValues); - actions.setStatus({ success: null }); - return; - } - await Object.keys(values).reduce((acc, key) => { + console.log(key); const newValue = key !== "color" ? values[key] : uxToHex(values[key]); - if (newValue !== contact[key]) { + if (newValue !== contact[key] && key !== "groups" && key !== "last-updated") { return acc.then(() => - props.api.contacts.edit(ship, { [key]: newValue }) + api.contacts.edit(`~${ship}`, { [key]: newValue }) ); } return acc; @@ -77,14 +69,13 @@ export function EditProfile(props: any) { } }; - - return ( - + +
@@ -101,5 +92,6 @@ export function EditProfile(props: any) {
+
); } diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 8dc409edb..9cac884b2 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -55,7 +55,7 @@ export function Profile(props: any) { { isEdit ? ( - + ) : ( ) } diff --git a/pkg/interface/src/views/apps/profile/profile.tsx b/pkg/interface/src/views/apps/profile/profile.tsx index 0c2a7f69d..d271f9f9f 100644 --- a/pkg/interface/src/views/apps/profile/profile.tsx +++ b/pkg/interface/src/views/apps/profile/profile.tsx @@ -22,7 +22,8 @@ export default function ProfileScreen(props: any) { render={({ match, history }) => { const ship = match.params.ship; const isEdit = match.url.includes('edit'); - const contact = props.contacts?.[ship]; + const contact = props.contacts?.[`~${ship}`]; + console.log(props.contacts); const sigilColor = contact?.color ? `#${uxToHex(contact.color)}` : dark From 090946e3289bac186b20131632df0c6d6303da76 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Tue, 26 Jan 2021 16:18:01 -0600 Subject: [PATCH 21/61] contact-store: updates sent to /all path as well --- pkg/arvo/app/contact-store.hoon | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index 7f5b9389b..ccaa10561 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -29,7 +29,10 @@ +* this . def ~(. (default-agent this %|) bowl) :: -++ on-init on-init:def +++ on-init + =. rolodex (~(put by rolodex) our.bowl *contact:store) + [~ this(state state)] +:: ++ on-save !>(state) ++ on-load |= old-vase=vase @@ -168,8 +171,8 @@ ^- (list card) =/ paths=(list path) ?: our - [/updates /our ~] - ~[/updates] + [/updates /our /all ~] + [/updates /all ~] [%give %fact paths %contact-update !>(update)]~ -- :: From d85214040391e4a429355b51da3cb95d9a0e1b1d Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Tue, 26 Jan 2021 18:42:54 -0500 Subject: [PATCH 22/61] leap: add contacts searching --- pkg/interface/src/logic/lib/omnibox.js | 12 +++++++++- pkg/interface/src/views/App.js | 4 +--- .../src/views/components/leap/Omnibox.js | 5 +++-- .../views/components/leap/OmniboxResult.js | 22 ++++++++++--------- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/pkg/interface/src/logic/lib/omnibox.js b/pkg/interface/src/logic/lib/omnibox.js index 1bc38a4e2..e636d3d6d 100644 --- a/pkg/interface/src/logic/lib/omnibox.js +++ b/pkg/interface/src/logic/lib/omnibox.js @@ -1,6 +1,7 @@ import { cite } from '~/logic/lib/util'; const indexes = new Map([ + ['ships', []], ['commands', []], ['subscriptions', []], ['groups', []], @@ -18,6 +19,14 @@ const result = function(title, link, app, host) { }; }; +const shipIndex = function(contacts) { + const ships = []; + Object.keys(contacts).map((e) => { + return ships.push(result(e, `/~profile/${e}`, 'profile', contacts[e]?.status)); + }); + return ships; +}; + const commandIndex = function (currentGroup) { // commands are special cased for default suite const commands = []; @@ -62,7 +71,8 @@ const otherIndex = function() { return other; }; -export default function index(associations, apps, currentGroup, groups) { +export default function index(contacts, associations, apps, currentGroup, groups) { + indexes.set('ships', shipIndex(contacts)); // all metadata from all apps is indexed // into subscriptions and landscape const subscriptions = []; diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index 04a7a37eb..0e70bce4f 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -139,9 +139,6 @@ class App extends React.Component { const doNotDisturb = state.doNotDisturb || false; const ourContact = this.state.contacts[this.ship] || null; - const showBanner = localStorage.getItem("2020BreachBanner") || "flex"; - let banner = null; - return ( @@ -170,6 +167,7 @@ class App extends React.Component { associations={state.associations} apps={state.launch} api={this.api} + contacts={state.contacts} notifications={state.notificationsCount} invites={state.invites} groups={state.groups} diff --git a/pkg/interface/src/views/components/leap/Omnibox.js b/pkg/interface/src/views/components/leap/Omnibox.js index 70304381e..f11eb444d 100644 --- a/pkg/interface/src/views/components/leap/Omnibox.js +++ b/pkg/interface/src/views/components/leap/Omnibox.js @@ -32,7 +32,7 @@ export class Omnibox extends Component { const { pathname } = this.props.location; const selectedGroup = pathname.startsWith('/~landscape/ship/') ? '/' + pathname.split('/').slice(2,5).join('/') : null; - this.setState({ index: index(this.props.associations, this.props.apps.tiles, selectedGroup, this.props.groups) }); + this.setState({ index: index(this.props.contacts, this.props.associations, this.props.apps.tiles, selectedGroup, this.props.groups) }); } if (prevProps && (prevProps.apps !== this.props.apps) && (this.state.query === '')) { @@ -56,7 +56,7 @@ export class Omnibox extends Component { } getSearchedCategories() { - return ['other', 'commands', 'groups', 'subscriptions', 'apps']; + return ['ships', 'other', 'commands', 'groups', 'subscriptions', 'apps']; } control(evt) { @@ -249,6 +249,7 @@ export class Omnibox extends Component { selected={selected} invites={props.invites} notifications={props.notifications} + contacts={props.contacts} /> ))} diff --git a/pkg/interface/src/views/components/leap/OmniboxResult.js b/pkg/interface/src/views/components/leap/OmniboxResult.js index 9ed37a955..3dd41aba4 100644 --- a/pkg/interface/src/views/components/leap/OmniboxResult.js +++ b/pkg/interface/src/views/components/leap/OmniboxResult.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import { Box, Row, Icon, Text } from '@tlon/indigo-react'; import defaultApps from '~/logic/lib/default-apps'; import Sigil from '~/logic/lib/sigil'; +import { uxToHex } from '~/logic/lib/util'; export class OmniboxResult extends Component { constructor(props) { @@ -25,9 +26,8 @@ export class OmniboxResult extends Component { } } - getIcon(icon, selected, link, invites, notifications) { + getIcon(icon, selected, link, invites, notifications, text, color) { const iconFill = (this.state.hovered || (selected === link)) ? 'white' : 'black'; - const sigilFill = (this.state.hovered || (selected === link)) ? '#3a8ff7' : '#ffffff'; const bulletFill = (this.state.hovered || (selected === link)) ? 'white' : 'blue'; const inviteCount = [].concat(...Object.values(invites).map(obj => Object.values(obj))); @@ -39,22 +39,23 @@ export class OmniboxResult extends Component { { icon = (icon === 'Link') ? 'Collection' : (icon === 'Terminal') ? 'Dojo' : icon; - graphic = ; + graphic = ; } else if (icon === 'inbox') { graphic = - + {(notifications > 0 || inviteCount.length > 0) && ( )} ; } else if (icon === 'logout') { - graphic = ; + graphic = ; } else if (icon === 'profile') { - graphic = ; + text = text.startsWith('Profile') ? window.ship : text; + graphic = ; } else if (icon === 'home') { - graphic = ; + graphic = ; } else if (icon === 'notifications') { - graphic = ; + graphic = ; } else { graphic = ; } @@ -67,9 +68,10 @@ export class OmniboxResult extends Component { } render() { - const { icon, text, subtext, link, navigate, selected, invites, notifications } = this.props; + const { icon, text, subtext, link, navigate, selected, invites, notifications, contacts } = this.props; - const graphic = this.getIcon(icon, selected, link, invites, notifications); + const color = contacts?.[text] ? `#${uxToHex(contacts[text].color)}` : "#000000"; + const graphic = this.getIcon(icon, selected, link, invites, notifications, text, color); return ( Date: Tue, 26 Jan 2021 18:46:31 -0500 Subject: [PATCH 23/61] profile: assume sig is prepended Our contacts object uses ~patp format. We're prefixing sigs on top of this, causing the profile page to break unless the sig is provided, and then showing patp info with two sigs. This just prefixes sigs in the route and removes the sigs prepended in user-facing strings. --- pkg/interface/src/views/apps/profile/components/Profile.tsx | 2 +- .../src/views/apps/profile/components/ViewProfile.tsx | 6 +++--- pkg/interface/src/views/components/StatusBar.js | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 8dc409edb..ae444420b 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -29,7 +29,7 @@ export function Profile(props: any) { const image = (!hideAvatars && contact?.avatar) ? - : ; + : ; return (
- {`~${ship}`} + {`${ship}`}
@@ -63,7 +63,7 @@ export function ViewProfile(props: any) {
- ) : null + ) : null }
- {`~${ship} `} + {`${ship} `} remains private
diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 0da0de027..0667ce1fd 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -75,21 +75,21 @@ const StatusBar = (props) => { p={1} color='black' fontSize={0} - onClick={() => props.history.push('/~profile/' + window.ship)}> + onClick={() => props.history.push('/~profile/~' + window.ship)}> View Profile props.history.push('/~profile/' + window.ship)}> + onClick={() => props.history.push('/~profile/~' + window.ship)}> Set Status props.history.push('/~profile/' + window.ship)}> + onClick={() => props.history.push('/~profile/~' + window.ship)}> System Settings From 3c4a62accfcafb0b046026555c6307a5d8092ac0 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Tue, 26 Jan 2021 18:47:44 -0500 Subject: [PATCH 24/61] statusbar: dropdown uses cursor: pointer --- pkg/interface/src/views/components/StatusBar.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 0667ce1fd..05c33a656 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -74,6 +74,7 @@ const StatusBar = (props) => { props.history.push('/~profile/~' + window.ship)}> View Profile @@ -81,6 +82,7 @@ const StatusBar = (props) => { props.history.push('/~profile/~' + window.ship)}> Set Status @@ -88,6 +90,7 @@ const StatusBar = (props) => { props.history.push('/~profile/~' + window.ship)}> System Settings From cab2a76004b081c92d6bb507b4c95bab4ed1c3fb Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Wed, 27 Jan 2021 16:13:52 -0500 Subject: [PATCH 25/61] leap: mono for ship names --- pkg/interface/src/views/components/leap/OmniboxResult.js | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/interface/src/views/components/leap/OmniboxResult.js b/pkg/interface/src/views/components/leap/OmniboxResult.js index 3dd41aba4..1f3ca309b 100644 --- a/pkg/interface/src/views/components/leap/OmniboxResult.js +++ b/pkg/interface/src/views/components/leap/OmniboxResult.js @@ -91,6 +91,7 @@ export class OmniboxResult extends Component { Date: Wed, 27 Jan 2021 17:20:58 -0500 Subject: [PATCH 26/61] chat: weave flattened contacts prop --- pkg/interface/src/views/apps/chat/ChatResource.tsx | 4 ++-- .../src/views/apps/chat/components/ChatMessage.tsx | 2 +- pkg/interface/src/views/components/StatusBar.js | 10 +++++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/ChatResource.tsx b/pkg/interface/src/views/apps/chat/ChatResource.tsx index 9e18ccad6..4c724f248 100644 --- a/pkg/interface/src/views/apps/chat/ChatResource.tsx +++ b/pkg/interface/src/views/apps/chat/ChatResource.tsx @@ -24,7 +24,7 @@ export function ChatResource(props: ChatResourceProps) { const station = props.association['app-path']; const groupPath = props.association['group-path']; const group = props.groups[groupPath]; - const contacts = props.contacts[groupPath] || {}; + const contacts = props.contacts; const graph = props.graphs[station.slice(7)]; @@ -33,7 +33,7 @@ export function ChatResource(props: ChatResourceProps) { const unreadCount = props.unreads.graph?.[station]?.['/']?.unreads || 0; const [,, owner, name] = station.split('/'); - const ourContact = contacts?.[window.ship]; + const ourContact = contacts?.[`~${window.ship}`]; const chatInput = useRef(); diff --git a/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx b/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx index 30ed1c2c1..675b54e85 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx @@ -178,7 +178,7 @@ export const MessageWithSigil = (props) => { const dark = useLocalState(state => state.dark); const datestamp = moment.unix(msg['time-sent'] / 1000).format(DATESTAMP_FORMAT); - const contact = msg.author in contacts ? contacts[msg.author] : false; + const contact = `~${msg.author}` in contacts ? contacts[`~${msg.author}`] : false; const showNickname = useShowNickname(contact); const name = showNickname ? contact.nickname : cite(msg.author); const color = contact ? `#${uxToHex(contact.color)}` : dark ? '#000000' :'#FFFFFF' diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 05c33a656..c836c8fe6 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -70,7 +70,15 @@ const StatusBar = (props) => { alignY="top" alignX="right" options={ - + Date: Wed, 27 Jan 2021 17:22:38 -0500 Subject: [PATCH 27/61] profileOverlay: new profile style --- .../src/views/components/ProfileOverlay.tsx | 64 ++++++++----------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/pkg/interface/src/views/components/ProfileOverlay.tsx b/pkg/interface/src/views/components/ProfileOverlay.tsx index 0b1ee7f0a..873abfe48 100644 --- a/pkg/interface/src/views/components/ProfileOverlay.tsx +++ b/pkg/interface/src/views/components/ProfileOverlay.tsx @@ -4,7 +4,7 @@ import { Contact, Group } from '~/types'; import { cite, useShowNickname } from '~/logic/lib/util'; import { Sigil } from '~/logic/lib/sigil'; -import { Box, Col, Button, Text, BaseImage, ColProps } from '@tlon/indigo-react'; +import { Box, Col, Row, Button, Text, BaseImage, ColProps, Icon } from '@tlon/indigo-react'; import { withLocalState } from '~/logic/state/local'; export const OVERLAY_HEIGHT = 250; @@ -60,7 +60,6 @@ class ProfileOverlay extends PureComponent { color, topSpace, bottomSpace, - group = false, hideAvatars, hideNicknames, history, @@ -78,75 +77,68 @@ class ProfileOverlay extends PureComponent { if (!(top || bottom)) { bottom = `-${Math.round(OVERLAY_HEIGHT / 2)}px`; } - const containerStyle = { top, bottom, left: '100%', maxWidth: '160px' }; + const containerStyle = { top, bottom, left: '100%' }; const isOwn = window.ship === ship; const img = contact?.avatar && !hideAvatars - ? + ? : ; const showNickname = useShowNickname(contact, hideNicknames); - // TODO: we need to rethink this "top-level profile view" of other ships - /* if (!group.hidden) { - }*/ - - const isHidden = group ? group.hidden : false; - const rootSettings = history.location.pathname.slice(0, history.location.pathname.indexOf("/resource")); return ( - + + + {(!isOwn) && ( + history.push(`/~landscape/dm/${ship}`)}/> + )} + + {img} - - {showNickname && ( + - {contact.nickname} + {showNickname ? contact.nickname : cite(ship)} - )} - {cite(`~${ship}`)} - {!isOwn && ( - - )} - {(isOwn) ? ( - - ) :
} - + {contact?.status && ({contact.status})} + ); } } -export default withLocalState(ProfileOverlay, ['hideAvatars', 'hideNicknames']); \ No newline at end of file +export default withLocalState(ProfileOverlay, ['hideAvatars', 'hideNicknames']); From 95a773df2a4da746f214031fa6ebbda1ecb5200e Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Wed, 27 Jan 2021 17:41:15 -0500 Subject: [PATCH 28/61] profileOverlay: add stubbed status setting logic Just needs the API call filled in. --- pkg/interface/src/views/components/OverlaySigil.tsx | 1 - pkg/interface/src/views/components/ProfileOverlay.tsx | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/interface/src/views/components/OverlaySigil.tsx b/pkg/interface/src/views/components/OverlaySigil.tsx index b2567596d..929a8f260 100644 --- a/pkg/interface/src/views/components/OverlaySigil.tsx +++ b/pkg/interface/src/views/components/OverlaySigil.tsx @@ -110,7 +110,6 @@ class OverlaySigil extends PureComponent { return ( { > {showNickname ? contact.nickname : cite(ship)} - {contact?.status && ({contact.status})} + api.contacts.edit()...} + > + {(!contact?.status && isOwn) ? "Set a status" : contact.status} + ); From 4ce5aafd4f5526b10167a771fe5d2b93b3229706 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Wed, 27 Jan 2021 18:08:41 -0500 Subject: [PATCH 29/61] profileOverlay: add dropdown options --- .../src/views/components/ProfileOverlay.tsx | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/pkg/interface/src/views/components/ProfileOverlay.tsx b/pkg/interface/src/views/components/ProfileOverlay.tsx index 6238ca8e9..011f58a63 100644 --- a/pkg/interface/src/views/components/ProfileOverlay.tsx +++ b/pkg/interface/src/views/components/ProfileOverlay.tsx @@ -4,7 +4,8 @@ import { Contact, Group } from '~/types'; import { cite, useShowNickname } from '~/logic/lib/util'; import { Sigil } from '~/logic/lib/sigil'; -import { Box, Col, Row, Button, Text, BaseImage, ColProps, Icon } from '@tlon/indigo-react'; +import { Box, Col, Row, Text, BaseImage, ColProps, Icon } from '@tlon/indigo-react'; +import { Dropdown } from './Dropdown'; import { withLocalState } from '~/logic/state/local'; export const OVERLAY_HEIGHT = 250; @@ -114,7 +115,44 @@ class ProfileOverlay extends PureComponent { {...rest} > - + + history.push('/~profile/' + window.ship)}> + View Profile + + {(!isOwn) && ( + history.push(`/~landscape/dm/${ship}`)} + > + Send Message + + )} + + }> + + {(!isOwn) && ( history.push(`/~landscape/dm/${ship}`)}/> )} From cb21979d94d0c13841a8014345f975d66391311b Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Wed, 27 Jan 2021 17:20:42 -0600 Subject: [PATCH 30/61] contacts: added %set-public update type --- pkg/arvo/app/contact-push-hook.hoon | 30 ++++++++------------------- pkg/arvo/app/contact-store.hoon | 20 ++++++++++++------ pkg/arvo/lib/contact-store.hoon | 4 ++++ pkg/arvo/mar/contact-hook-action.hoon | 10 --------- pkg/arvo/mar/contact/update.hoon | 16 ++++++++++++++ pkg/arvo/sur/contact-store.hoon | 1 + 6 files changed, 44 insertions(+), 37 deletions(-) delete mode 100644 pkg/arvo/mar/contact-hook-action.hoon diff --git a/pkg/arvo/app/contact-push-hook.hoon b/pkg/arvo/app/contact-push-hook.hoon index 12b665e61..716d33e8b 100644 --- a/pkg/arvo/app/contact-push-hook.hoon +++ b/pkg/arvo/app/contact-push-hook.hoon @@ -5,10 +5,10 @@ ++ config ^- config:push-hook :* %contact-store - /our + /updates update:store %contact-update - %graph-pull-hook + %contact-pull-hook == :: +$ agent (push-hook:push-hook config) @@ -39,25 +39,13 @@ ^- ? =/ =update:store !<(update:store vase) ?- -.update - %initial %.n - %add %.y - %remove %.y - %edit %.y - %allow %.n - %disallow %.n - == -:: -++ resource-for-update - |= =vase - ^- (unit resource:res) - =/ =update:store !<(update:store vase) - ?- -.update - %initial ~ - %add `[our.bowl %our] - %remove `[our.bowl %our] - %edit `[our.bowl %our] - %allow ~ - %disallow `[our.bowl %our] + %initial %.n + %add %.y + %remove %.y + %edit %.y + %allow %.n + %disallow %.n + %set-public %.n == :: ++ initial-watch diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index ccaa10561..7c10835a6 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -11,6 +11,7 @@ =rolodex:store allowed-groups=(set resource) allowed-ships=(set ship) + is-public=_| == +$ versioned-state $% [%0 *] @@ -88,12 +89,13 @@ ^- (quip card _state) |^ ?- -.update - %initial (handle-initial +.update) - %add (handle-add +.update) - %remove (handle-remove +.update) - %edit (handle-edit +.update) - %allow (handle-allow +.update) - %disallow (handle-disallow +.update) + %initial (handle-initial +.update) + %add (handle-add +.update) + %remove (handle-remove +.update) + %edit (handle-edit +.update) + %allow (handle-allow +.update) + %disallow (handle-disallow +.update) + %set-public (handle-set-public +.update) == :: ++ handle-initial @@ -166,6 +168,12 @@ %ships state(allowed-ships (~(dif in allowed-ships) ships.beings)) == :: + ++ handle-set-public + |= public=? + ^- (quip card _state) + :_ state(is-public public) + (send-diff [%set-public public] %.n) + :: ++ send-diff |= [=update:store our=?] ^- (list card) diff --git a/pkg/arvo/lib/contact-store.hoon b/pkg/arvo/lib/contact-store.hoon index 722b779e9..731d8a9cd 100644 --- a/pkg/arvo/lib/contact-store.hoon +++ b/pkg/arvo/lib/contact-store.hoon @@ -47,6 +47,9 @@ %disallow :- %disallow (pairs [%beings (beng beings.upd)]~) + :: + %set-public + [%set-public b+public.upd] == :: ++ rolo @@ -112,6 +115,7 @@ [%edit edit-contact] [%allow beings] [%disallow beings] + [%set-public bo] == :: ++ initial (op ;~(pfix sig fed:ag) cont) diff --git a/pkg/arvo/mar/contact-hook-action.hoon b/pkg/arvo/mar/contact-hook-action.hoon deleted file mode 100644 index c6f27976f..000000000 --- a/pkg/arvo/mar/contact-hook-action.hoon +++ /dev/null @@ -1,10 +0,0 @@ -/- *contact-hook -|_ act=contact-hook-action -++ grab |% - ++ noun contact-hook-action - -- -++ grow |% - ++ noun act - -- -++ grad %noun --- diff --git a/pkg/arvo/mar/contact/update.hoon b/pkg/arvo/mar/contact/update.hoon index 733d30f48..87d3f18a5 100644 --- a/pkg/arvo/mar/contact/update.hoon +++ b/pkg/arvo/mar/contact/update.hoon @@ -6,6 +6,22 @@ |% ++ noun upd ++ json (update:enjs upd) + ++ resource + |^ + ?- -.upd + %initial [nobody %contacts] + %add [nobody %contacts] + %remove [nobody %contacts] + %edit [nobody %contacts] + %allow !! + %disallow !! + %set-public !! + == + :: + ++ nobody + ^- @p + (bex 128) + -- -- :: ++ grab diff --git a/pkg/arvo/sur/contact-store.hoon b/pkg/arvo/sur/contact-store.hoon index 37f3af140..d9a5109c5 100644 --- a/pkg/arvo/sur/contact-store.hoon +++ b/pkg/arvo/sur/contact-store.hoon @@ -35,5 +35,6 @@ [%edit =ship =edit-field] [%allow =beings] [%disallow =beings] + [%set-public public=?] == -- From d3c0d92c3a326891312819612441df1b291b7db7 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Wed, 27 Jan 2021 17:21:15 -0600 Subject: [PATCH 31/61] interface: cleaning up integration of profile with mp's branch --- .../src/views/apps/profile/components/EditProfile.tsx | 6 +----- .../src/views/apps/profile/components/Profile.tsx | 2 +- .../src/views/apps/profile/components/ViewProfile.tsx | 8 +++----- pkg/interface/src/views/apps/profile/profile.tsx | 3 +-- pkg/interface/src/views/components/StatusBar.js | 7 ++----- 5 files changed, 8 insertions(+), 18 deletions(-) diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx index f7c7b4feb..69e350a39 100644 --- a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -42,10 +42,6 @@ const emptyContact = { export function EditProfile(props: any) { const { contact, ship, api } = props; - if (ship !== window.ship) { - return null; - } - console.log(contact); const history = useHistory(); const onSubmit = async (values: any, actions: any) => { @@ -57,7 +53,7 @@ export function EditProfile(props: any) { if (newValue !== contact[key] && key !== "groups" && key !== "last-updated") { return acc.then(() => - api.contacts.edit(`~${ship}`, { [key]: newValue }) + api.contacts.edit(ship, { [key]: newValue }) ); } return acc; diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index cb46b3514..0dc07f8d1 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -29,7 +29,7 @@ export function Profile(props: any) { const image = (!hideAvatars && contact?.avatar) ? - : ; + : ; return (
- - {`${ship}`} - + {ship}
- { (ship === window.ship) ? ( + { (ship === `~${window.ship}`) ? (
- {`${ship} `} + {ship} remains private
diff --git a/pkg/interface/src/views/apps/profile/profile.tsx b/pkg/interface/src/views/apps/profile/profile.tsx index 7baa1724d..2b663ca94 100644 --- a/pkg/interface/src/views/apps/profile/profile.tsx +++ b/pkg/interface/src/views/apps/profile/profile.tsx @@ -22,8 +22,7 @@ export default function ProfileScreen(props: any) { render={({ match, history }) => { const ship = match.params.ship; const isEdit = match.url.includes('edit'); - const contact = props.contacts?.[`~${ship}`]; - console.log(props.contacts); + const contact = props.contacts?.[ship]; const sigilColor = contact?.color ? `#${uxToHex(contact.color)}` : dark diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 05c33a656..1d86233dd 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -61,9 +61,6 @@ const StatusBar = (props) => { > Submit an issue - props.history.push('/~settings')}> - - { color='black' cursor='pointer' fontSize={0} - onClick={() => props.history.push('/~profile/~' + window.ship)}> + onClick={() => console.log('TODO, show a modal')}> Set Status { color='black' cursor='pointer' fontSize={0} - onClick={() => props.history.push('/~profile/~' + window.ship)}> + onClick={() => props.history.push('/~settings')}> System Settings From 520a7c2d7c4f2da5358af1869525337b79b9a7ba Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 28 Jan 2021 13:24:07 -0600 Subject: [PATCH 32/61] interface: fully support profile images in statusbar --- pkg/interface/src/views/App.js | 2 +- .../apps/profile/components/EditProfile.tsx | 6 ++- .../src/views/components/StatusBar.js | 37 ++++++++++++++++--- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index 0e70bce4f..684f29486 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -137,7 +137,7 @@ class App extends React.Component { const notificationsCount = state.notificationsCount || 0; const doNotDisturb = state.doNotDisturb || false; - const ourContact = this.state.contacts[this.ship] || null; + const ourContact = this.state.contacts[`~${this.ship}`] || null; return ( diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx index 69e350a39..b34129496 100644 --- a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -19,6 +19,7 @@ import { Sigil } from "~/logic/lib/sigil"; import { AsyncButton } from "~/views/components/AsyncButton"; import { ColorInput } from "~/views/components/ColorInput"; import { ImageInput } from "~/views/components/ImageInput"; +import { MarkdownField } from "~/views/apps/publish/components/MarkdownField"; const formSchema = Yup.object({ @@ -74,7 +75,10 @@ export function EditProfile(props: any) { >
- + + Description + + diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 32dbd7547..9a0e906f3 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -1,18 +1,43 @@ import React from 'react'; -import { Col, Row, Box, Text, Icon, Button } from '@tlon/indigo-react'; +import { + Col, + Row, + Box, + Text, + Icon, + Button, + BaseImage +} from '@tlon/indigo-react'; import ReconnectButton from './ReconnectButton'; import { Dropdown } from './Dropdown'; import { StatusBarItem } from './StatusBarItem'; import { Sigil } from '~/logic/lib/sigil'; +import { uxToHex } from "~/logic/lib/util"; + import useLocalState from '~/logic/state/local'; const StatusBar = (props) => { + const { ourContact } = props; const invites = [].concat(...Object.values(props.invites).map(obj => Object.values(obj))); const metaKey = (window.navigator.platform.includes('Mac')) ? '⌘' : 'Ctrl+'; - const toggleOmnibox = useLocalState(state => state.toggleOmnibox); + const { toggleOmnibox, hideAvatars } = + useLocalState(({ toggleOmnibox, hideAvatars }) => + ({ toggleOmnibox, hideAvatars }) + ); + + const color = !!ourContact ? `#${uxToHex(props.ourContact.color)}` : '#000'; + const xPadding = (!hideAvatars && ourContact?.avatar) ? '0' : '2'; + const bgColor = (!hideAvatars && ourContact?.avatar) ? '' : color; + const profileImage = (!hideAvatars && ourContact?.avatar) ? ( + + ) : ; - const color = !!props.ourContact ? props.ourContact.color : '#000'; return ( { }> - + backgroundColor={bgColor}> + {profileImage} From 8ac1a9768d67ce95ca759dcac04409d30e149de6 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 28 Jan 2021 14:45:28 -0600 Subject: [PATCH 33/61] contacts + interface: hooked up isPublic to interface --- pkg/arvo/app/contact-store.hoon | 8 ++-- pkg/arvo/lib/contact-store.hoon | 12 +++++- pkg/arvo/sur/contact-store.hoon | 2 +- pkg/interface/src/logic/api/contacts.ts | 6 +++ .../src/logic/reducers/contact-update.ts | 11 ++++- pkg/interface/src/logic/store/store.ts | 1 + .../apps/profile/components/EditProfile.tsx | 40 ++++++++++++++----- .../views/apps/profile/components/Profile.tsx | 11 +++-- .../apps/profile/components/ViewProfile.tsx | 27 +++++++------ .../src/views/apps/profile/profile.tsx | 2 + 10 files changed, 86 insertions(+), 34 deletions(-) diff --git a/pkg/arvo/app/contact-store.hoon b/pkg/arvo/app/contact-store.hoon index 7c10835a6..c58b73d02 100644 --- a/pkg/arvo/app/contact-store.hoon +++ b/pkg/arvo/app/contact-store.hoon @@ -53,7 +53,7 @@ |^ =/ cards=(list card) ?+ path (on-watch:def path) - [%all ~] (give [%initial rolodex]) + [%all ~] (give [%initial rolodex is-public]) [%updates ~] ~ :: [%our ~] @@ -99,11 +99,11 @@ == :: ++ handle-initial - |= rolo=rolodex:store + |= [rolo=rolodex:store is-public=?] ^- (quip card _state) =. rolodex (~(uni by rolodex) rolo) - :_ state(rolodex rolodex) - (send-diff [%initial rolodex] %.n) + :_ state(rolodex rolodex, is-public is-public) + (send-diff [%initial rolodex is-public] %.n) :: ++ handle-add |= [=ship =contact:store] diff --git a/pkg/arvo/lib/contact-store.hoon b/pkg/arvo/lib/contact-store.hoon index 731d8a9cd..8356d69aa 100644 --- a/pkg/arvo/lib/contact-store.hoon +++ b/pkg/arvo/lib/contact-store.hoon @@ -20,7 +20,11 @@ ^- [cord json] ?- -.upd %initial - [%initial (rolo rolodex.upd)] + :- %initial + %- pairs + :~ [%rolodex (rolo rolodex.upd)] + [%is-public b+is-public.upd] + == :: %add :- %add @@ -118,7 +122,11 @@ [%set-public bo] == :: - ++ initial (op ;~(pfix sig fed:ag) cont) + ++ initial + %- ot + :~ [%rolodex (op ;~(pfix sig fed:ag) cont)] + [%is-public bo] + == :: ++ add-contact %- ot diff --git a/pkg/arvo/sur/contact-store.hoon b/pkg/arvo/sur/contact-store.hoon index d9a5109c5..fb6e85330 100644 --- a/pkg/arvo/sur/contact-store.hoon +++ b/pkg/arvo/sur/contact-store.hoon @@ -29,7 +29,7 @@ == :: +$ update - $% [%initial =rolodex] + $% [%initial =rolodex is-public=?] [%add =ship =contact] [%remove =ship] [%edit =ship =edit-field] diff --git a/pkg/interface/src/logic/api/contacts.ts b/pkg/interface/src/logic/api/contacts.ts index cd9f1cd76..34db3c773 100644 --- a/pkg/interface/src/logic/api/contacts.ts +++ b/pkg/interface/src/logic/api/contacts.ts @@ -32,6 +32,12 @@ export default class ContactsApi extends BaseApi { }); } + setPublic(setPublic: any) { + return this.storeAction({ + 'set-public': setPublic + }); + } + private storeAction(action: any): Promise { return this.action('contact-store', 'contact-update', action) } diff --git a/pkg/interface/src/logic/reducers/contact-update.ts b/pkg/interface/src/logic/reducers/contact-update.ts index ef3031d33..87aaf02c4 100644 --- a/pkg/interface/src/logic/reducers/contact-update.ts +++ b/pkg/interface/src/logic/reducers/contact-update.ts @@ -13,6 +13,7 @@ export const ContactReducer = (json, state) => { add(data, state); remove(data, state); edit(data, state); + setPublic(data, state); console.log(state.contacts); } }; @@ -20,7 +21,8 @@ export const ContactReducer = (json, state) => { const initial = (json: ContactUpdate, state: S) => { const data = _.get(json, 'initial', false); if (data) { - state.contacts = data; + state.contacts = data.rolodex; + state.isContactPublic = data['is-public']; } }; @@ -55,3 +57,10 @@ const edit = (json: ContactUpdate, state: S) => { state.contacts[ship][edit[0]] = data['edit-field'][edit[0]]; } }; + +const setPublic = (json: ContactUpdate, state: S) => { + const data = _.get(json, 'set-public', false); + state.isContactPublic = data; +}; + + diff --git a/pkg/interface/src/logic/store/store.ts b/pkg/interface/src/logic/store/store.ts index 1229bf0b8..362489a7e 100644 --- a/pkg/interface/src/logic/store/store.ts +++ b/pkg/interface/src/logic/store/store.ts @@ -74,6 +74,7 @@ export default class GlobalStore extends BaseStore { }, credentials: null }, + isContactPublic: false, contacts: {}, notifications: new BigIntOrderedMap(), archivedNotifications: new BigIntOrderedMap(), diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx index b34129496..cfc820414 100644 --- a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -4,6 +4,7 @@ import * as Yup from "yup"; import { ManagedForm as Form, ManagedTextInputField as Input, + ManagedCheckboxField as Checkbox, Center, Col, Box, @@ -37,13 +38,17 @@ const emptyContact = { avatar: null, cover: null, groups: [], - 'last-updated': 0 + 'last-updated': 0, + isPublic: false }; export function EditProfile(props: any) { - const { contact, ship, api } = props; + const { contact, ship, api, isPublic } = props; const history = useHistory(); + if (contact) { + contact.isPublic = isPublic; + } const onSubmit = async (values: any, actions: any) => { console.log(values); @@ -52,14 +57,25 @@ export function EditProfile(props: any) { console.log(key); const newValue = key !== "color" ? values[key] : uxToHex(values[key]); - if (newValue !== contact[key] && key !== "groups" && key !== "last-updated") { - return acc.then(() => - api.contacts.edit(ship, { [key]: newValue }) - ); + if (newValue !== contact[key]) { + if (key === "isPublic") { + return acc.then(() => + api.contacts.setPublic(newValue) + ); + } else if ( + key !== "groups" && + key !== "last-updated" && + key !== "isPublic" + ) { + return acc.then(() => + api.contacts.edit(ship, { [key]: newValue }) + ); + } } return acc; }, Promise.resolve()); - actions.setStatus({ success: null }); + //actions.setStatus({ success: null }); + history.push(`/~profile/${ship}`); } catch (e) { console.error(e); actions.setStatus({ error: e.message }); @@ -79,14 +95,16 @@ export function EditProfile(props: any) { Description + - - + + - - + + + Submit diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 0dc07f8d1..0e076b4d0 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -21,7 +21,7 @@ export function Profile(props: any) { if (!props.ship) { return null; } - const { contact, isEdit, ship } = props; + const { contact, isPublic, isEdit, ship } = props; const hexColor = contact?.color ? `#${uxToHex(contact.color)}` : "#000000"; const cover = (contact?.cover) ? @@ -55,9 +55,14 @@ export function Profile(props: any) { { isEdit ? ( - + ) : ( - + ) } diff --git a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx index efb8f37b9..a84fab799 100644 --- a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx @@ -15,7 +15,7 @@ import { useHistory } from "react-router-dom"; export function ViewProfile(props: any) { const history = useHistory(); - const { contact, ship } = props; + const { contact, isPublic, ship } = props; return ( <> @@ -63,17 +63,20 @@ export function ViewProfile(props: any) { ) : null } - -
- {ship} - remains private -
-
+ { !isPublic && ship === `~${window.ship}` ? ( + +
+ {ship} + remains private +
+
+ ) : null + } ); } diff --git a/pkg/interface/src/views/apps/profile/profile.tsx b/pkg/interface/src/views/apps/profile/profile.tsx index 2b663ca94..c4335ea67 100644 --- a/pkg/interface/src/views/apps/profile/profile.tsx +++ b/pkg/interface/src/views/apps/profile/profile.tsx @@ -22,6 +22,7 @@ export default function ProfileScreen(props: any) { render={({ match, history }) => { const ship = match.params.ship; const isEdit = match.url.includes('edit'); + const isPublic = props.isContactPublic; const contact = props.contacts?.[ship]; const sigilColor = contact?.color ? `#${uxToHex(contact.color)}` @@ -46,6 +47,7 @@ export default function ProfileScreen(props: any) { api={props.api} s3={props.s3} isEdit={isEdit} + isPublic={isPublic} /> From 38f2022690b043e70feaa34fe21e7ed712540535 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Thu, 28 Jan 2021 17:09:31 -0600 Subject: [PATCH 34/61] interface: added ability to set status for profile --- .../apps/profile/components/EditProfile.tsx | 6 +- .../views/apps/profile/components/Profile.tsx | 10 +++- .../apps/profile/components/SetStatus.tsx | 57 +++++++++++++++++++ .../src/views/apps/profile/profile.tsx | 4 +- 4 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 pkg/interface/src/views/apps/profile/components/SetStatus.tsx diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx index cfc820414..70b94096d 100644 --- a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -83,13 +83,13 @@ export function EditProfile(props: any) { }; return ( - + <> - + Description @@ -110,6 +110,6 @@ export function EditProfile(props: any) { - + ); } diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 0e076b4d0..5c3cf67d7 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -2,6 +2,7 @@ import React from "react"; import { Sigil } from "~/logic/lib/sigil"; import { ViewProfile } from './ViewProfile'; import { EditProfile } from './EditProfile'; +import { SetStatus } from './SetStatus'; import { uxToHex } from "~/logic/lib/util"; import { @@ -9,6 +10,8 @@ import { Box, Row, BaseImage, + StatelessTextInput as Input, + Button } from "@tlon/indigo-react"; import useLocalState from "~/logic/state/local"; import { useHistory } from "react-router-dom"; @@ -35,11 +38,14 @@ export function Profile(props: any) {
+ width="100%"> + { ship === `~${window.ship}` ? ( + + ) : null + } {cover} diff --git a/pkg/interface/src/views/apps/profile/components/SetStatus.tsx b/pkg/interface/src/views/apps/profile/components/SetStatus.tsx new file mode 100644 index 000000000..a89511f30 --- /dev/null +++ b/pkg/interface/src/views/apps/profile/components/SetStatus.tsx @@ -0,0 +1,57 @@ +import React, { + useState, + useCallback, + useEffect, + ChangeEvent +} from "react"; + +import { + Row, + Button, + StatelessTextInput as Input, +} from "@tlon/indigo-react"; + + +export function SetStatus(props: any) { + const { contact, ship, api } = props; + const [_status, setStatus] = useState(''); + const onStatusChange = useCallback( + (e: ChangeEvent) => { + setStatus(e.target.value); + }, + [setStatus] + ); + + useEffect(() => { + setStatus(!!contact ? contact.status : ''); + }, [contact]); + + const editStatus = () => { + api.contacts.edit(ship, {status: _status}); + }; + + return ( + + { + if (evt.key === 'Enter') { + editStatus(); + } + }} + /> + + + ); +} diff --git a/pkg/interface/src/views/apps/profile/profile.tsx b/pkg/interface/src/views/apps/profile/profile.tsx index c4335ea67..e2fdfed4d 100644 --- a/pkg/interface/src/views/apps/profile/profile.tsx +++ b/pkg/interface/src/views/apps/profile/profile.tsx @@ -39,8 +39,10 @@ export default function ProfileScreen(props: any) { bg="white" border={1} borderColor="washedGray" + overflowY="auto" + flexGrow > - + Date: Thu, 28 Jan 2021 17:22:59 -0600 Subject: [PATCH 35/61] interface: set-public bug fixed --- pkg/interface/src/logic/reducers/contact-update.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/interface/src/logic/reducers/contact-update.ts b/pkg/interface/src/logic/reducers/contact-update.ts index 87aaf02c4..ac96ae36c 100644 --- a/pkg/interface/src/logic/reducers/contact-update.ts +++ b/pkg/interface/src/logic/reducers/contact-update.ts @@ -8,13 +8,11 @@ type ContactState = Pick; export const ContactReducer = (json, state) => { const data = _.get(json, 'contact-update', false); if (data) { - console.log(data); initial(data, state); add(data, state); remove(data, state); edit(data, state); setPublic(data, state); - console.log(state.contacts); } }; @@ -59,7 +57,7 @@ const edit = (json: ContactUpdate, state: S) => { }; const setPublic = (json: ContactUpdate, state: S) => { - const data = _.get(json, 'set-public', false); + const data = _.get(json, 'set-public', state.isContactPublic); state.isContactPublic = data; }; From 53d416cf167b0a0a98c3706ba0f11964f7fc094d Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Thu, 28 Jan 2021 18:33:50 -0500 Subject: [PATCH 36/61] profile: allow line breaks in description --- .../views/apps/profile/components/ViewProfile.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx index a84fab799..4875d7da1 100644 --- a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx @@ -7,6 +7,7 @@ import { Text, Row, Button, + Col } from "@tlon/indigo-react"; import { AsyncButton } from "~/views/components/AsyncButton"; import RichText from "~/views/components/RichText"; @@ -37,16 +38,17 @@ export function ViewProfile(props: any) { {ship}
- -
- +
+ {(contact?.bio ? contact.bio : "")} -
- +
+ { (ship === `~${window.ship}`) ? ( Date: Thu, 28 Jan 2021 19:04:41 -0500 Subject: [PATCH 37/61] profileOverlay: fix dismiss clobbering dropdown --- pkg/interface/src/views/components/ProfileOverlay.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/interface/src/views/components/ProfileOverlay.tsx b/pkg/interface/src/views/components/ProfileOverlay.tsx index 011f58a63..620123efd 100644 --- a/pkg/interface/src/views/components/ProfileOverlay.tsx +++ b/pkg/interface/src/views/components/ProfileOverlay.tsx @@ -26,11 +26,13 @@ type ProfileOverlayProps = ColProps & { class ProfileOverlay extends PureComponent { public popoverRef: React.Ref; + public dropdownRef: React.Ref; constructor(props) { super(props); this.popoverRef = React.createRef(); + this.dropdownRef = React.createRef(); this.onDocumentClick = this.onDocumentClick.bind(this); } @@ -45,9 +47,9 @@ class ProfileOverlay extends PureComponent { } onDocumentClick(event) { - const { popoverRef } = this; + const { popoverRef, dropdownRef } = this; // Do nothing if clicking ref's element or descendent elements - if (!popoverRef.current || popoverRef.current.contains(event.target)) { + if (!popoverRef.current || dropdownRef.current.contains(event.target) || popoverRef.current.contains(event.target)) { return; } @@ -129,13 +131,14 @@ class ProfileOverlay extends PureComponent { border={1} borderRadius={2} borderColor="lightGray" + ref={this.dropdownRef} boxShadow="0px 0px 0px 3px"> history.push('/~profile/' + window.ship)}> + onClick={() => history.push('/~profile/~' + window.ship)}> View Profile {(!isOwn) && ( From 977dc628826e03168a8f9050d5bbebfef5468bc6 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 29 Jan 2021 12:38:33 +1000 Subject: [PATCH 38/61] graph-view: cleanup subscription handling --- pkg/arvo/app/graph-view.hoon | 80 +++++++++++++++++------------------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/pkg/arvo/app/graph-view.hoon b/pkg/arvo/app/graph-view.hoon index eb281e7ae..c19f7d95f 100644 --- a/pkg/arvo/app/graph-view.hoon +++ b/pkg/arvo/app/graph-view.hoon @@ -30,7 +30,7 @@ ++ on-poke |= [=mark =vase] ^- (quip card _this) - ?. ?=(%graph-view-action mark) + ?. ?=(?(%graph-view-action %noun) mark) (on-poke:def mark vase) =+ !<(=action:view-sur vase) =^ cards state @@ -42,7 +42,9 @@ :: ++ on-watch |= =path - `this + ?: ?=(?([%all ~] [%join @ ~]) path) + `this + (on-watch:def path) :: ++ on-peek |= =path @@ -82,6 +84,12 @@ ++ join |_ [uid=@uv rid=resource =ship] ++ jn-core . + ++ watch-md + (watch-our:(jn-pass-io /md) %metadata-store /updates) + :: + ++ watch-groups + (watch-our:(jn-pass-io /groups) %group-store /groups) + :: ++ jn-pass-io |= =path ~(. pass:io (weld /join/(scot %uv uid) path)) @@ -102,13 +110,17 @@ =/ maybe-group (group-from-app-resource:met %contacts rid) :_ state(joining (~(put by joining) uid [rid ship])) - :_ ~ ?^ maybe-group + :_ ~ %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook pull-hook-action+!>([%add rid ship]) - %+ poke:(jn-pass-io /add) - [ship %group-push-hook] - group-update+!>([%add-members rid (silt our.bowl ~)]) + :~ %+ poke:(jn-pass-io /add) + [ship %group-push-hook] + group-update+!>([%add-members rid (silt our.bowl ~)]) + :: + watch-md + watch-groups + == :: ++ jn-agent |= [=wire =sign:agent:gall] @@ -127,7 +139,7 @@ :: do nothing, wait for update from store `state :: shouldn't ever fail - weird-failure + (cleanup %strange) :: %groups ?+ -.sign !! @@ -139,7 +151,7 @@ %pull-md ?> ?=(%poke-ack -.sign) ?~ p.sign `state - weird-failure + (cleanup %strange) :: %md ?+ -.sign !! @@ -150,10 +162,8 @@ :: %pull-graph ?> ?=(%poke-ack -.sign) - ?^ p.sign - weird-failure - :_ state(joining (~(del by joining) uid)) - (tx-fact %join uid %done)^~ + %- cleanup + ?^(p.sign %strange %done) == ++ groups-fact |= =cage @@ -165,12 +175,9 @@ ?. =(rid resource.update) `state :_ state - :~ - (leave-our:(jn-pass-io /groups) %group-store) - :: - %+ poke-our:(jn-pass-io /pull-md) %metadata-hook - metadata-hook-action+!>([%add-synced ship (en-path:resource rid)]) - == + :_ ~ + %+ poke-our:(jn-pass-io /pull-md) %metadata-hook + metadata-hook-action+!>([%add-synced ship (en-path:resource rid)]) :: ++ md-fact |= [=mark =vase] @@ -179,16 +186,9 @@ =+ !<(upd=metadata-update vase) ?. ?=(%add -.upd) ~ ?. =(group-path.upd (en-path:resource rid)) ~ - :~ - (leave-our:(jn-pass-io /md) %metadata-store) - %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook - pull-hook-action+!>([%add ship rid]) - == - ++ watch-md - (watch-our:(jn-pass-io /md) %metadata-store /updates) - :: - ++ watch-groups - (watch-our:(jn-pass-io /groups) %group-store /groups) + :_ ~ + %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook + pull-hook-action+!>([%add ship rid]) :: ++ groups-kick :_ state @@ -201,26 +201,22 @@ ++ ack |= err=(unit tang) ?~ err `state - weird-failure + (cleanup %strange) :: - ++ join-failed - :: failed do not continue + ++ cleanup + |= fact=@t :_ state(joining (~(del by joining) uid)) - (tx-fact %join uid %no-perms)^~ + :~ (leave-our:(jn-pass-io /groups) %group-store) + (leave-our:(jn-pass-io /md) %metadata-store) + (tx-fact %join uid %no-perms) + == :: ++ joined :_ state - :~ - watch-groups - :: - %+ poke-our:(jn-pass-io /pull-group) %group-pull-hook - pull-hook-action+!>([%add ship rid]) - == + :_ ~ + %+ poke-our:(jn-pass-io /pull-group) %group-pull-hook + pull-hook-action+!>([%add ship rid]) :: - ++ weird-failure - ~& >>> "Weird failure joining {}, please report" - :_ state(joining (~(del by joining) uid)) - (tx-fact %join uid %strange)^~ -- -- -- From 911cade5e5ccfd098be29e8d8bd00ba7d124e228 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 29 Jan 2021 12:39:38 +1000 Subject: [PATCH 39/61] graph-view: rename to group-view --- pkg/arvo/app/{graph-view.hoon => group-view.hoon} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pkg/arvo/app/{graph-view.hoon => group-view.hoon} (100%) diff --git a/pkg/arvo/app/graph-view.hoon b/pkg/arvo/app/group-view.hoon similarity index 100% rename from pkg/arvo/app/graph-view.hoon rename to pkg/arvo/app/group-view.hoon From f013508853eae67da94126d4614313263212d7d4 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 29 Jan 2021 14:21:13 +1000 Subject: [PATCH 40/61] group-view: implicitly join graphs if group is hidden --- pkg/arvo/app/group-view.hoon | 117 +++++++++++++++------------- pkg/arvo/mar/group/view-action.hoon | 12 +++ pkg/arvo/mar/group/view-update.hoon | 12 +++ pkg/arvo/sur/group-view.hoon | 15 ++++ 4 files changed, 102 insertions(+), 54 deletions(-) create mode 100644 pkg/arvo/mar/group/view-action.hoon create mode 100644 pkg/arvo/mar/group/view-update.hoon create mode 100644 pkg/arvo/sur/group-view.hoon diff --git a/pkg/arvo/app/group-view.hoon b/pkg/arvo/app/group-view.hoon index c19f7d95f..c03b02845 100644 --- a/pkg/arvo/app/group-view.hoon +++ b/pkg/arvo/app/group-view.hoon @@ -1,16 +1,18 @@ -/- view-sur=graph-view, group-store, *group, *metadata-store -/+ default-agent, agentio, mdl=metadata, resource, dbug +/- view-sur=group-view, group-store, *group, *metadata-store +/+ default-agent, agentio, mdl=metadata, resource, dbug, grpl=group, verb |% ++ card card:agent:gall +$ state-zero $: %0 - joining=(map @uv [rid=resource =ship]) + joining=(map rid=resource =ship) == +++ view view-sur -- =| state-zero =* state - :: %- agent:dbug +%+ verb & ^- agent:gall =< |_ =bowl:gall @@ -30,21 +32,20 @@ ++ on-poke |= [=mark =vase] ^- (quip card _this) - ?. ?=(?(%graph-view-action %noun) mark) + ?. ?=(?(%group-view-action %noun) mark) (on-poke:def mark vase) - =+ !<(=action:view-sur vase) + =+ !<(=action:view vase) =^ cards state - ?+ -.action `state - %join - (jn-start:join:gc +.action) - == + (jn-start:join:gc +.action) [cards this] :: ++ on-watch |= =path - ?: ?=(?([%all ~] [%join @ ~]) path) - `this - (on-watch:def path) + ?+ path (on-watch:def path) + [%all ~] + :_ this + (fact:io group-view-update+!>([%initial ~(key by joining)]) ~)^~ + == :: ++ on-peek |= =path @@ -54,10 +55,11 @@ |= [=wire =sign:agent:gall] =^ cards state ?+ wire `state - [%join @ *] - =/ uid=@uv - (slav %uv i.t.wire) - (jn-agent:(jn-abed:join:gc uid) t.t.wire sign) + [%join %ship @ @ *] + =/ rid + (de-path:resource t.wire) + ?. (~(has by joining) rid) `state + (jn-agent:(jn-abed:join:gc rid) t.t.t.t.wire sign) == [cards this] :: @@ -69,21 +71,25 @@ |= =path `this :: -++ on-fail - |= [=term =tang] - `this +++ on-fail on-fail:def -- |_ =bowl:gall ++ met ~(. mdl bowl) +++ grp ~(. grpl bowl) ++ io ~(. agentio bowl) :: -++ tx-fact - |= [kind=@tas uid=@uv fact=@tas] - (fact:io graph-view-update+!>([kind uid fact]) /all /tx/(scot %uv uid) ~) :: ++ join - |_ [uid=@uv rid=resource =ship] + |_ [rid=resource =ship] ++ jn-core . + :: + ++ tx-fact + |= =progress:view + ~& +< + =; cage + (fact:io cage /all tx+(en-path:resource rid) ~) + group-view-update+!>([%progress rid progress]) + :: ++ watch-md (watch-our:(jn-pass-io /md) %metadata-store /updates) :: @@ -91,29 +97,28 @@ (watch-our:(jn-pass-io /groups) %group-store /groups) :: ++ jn-pass-io - |= =path - ~(. pass:io (weld /join/(scot %uv uid) path)) + |= pax=path + ~(. pass:io (welp join+(en-path:resource rid) pax)) :: ++ jn-abed - |= uid=@uv - =/ [r=resource s=^ship] - (~(got by joining) uid) - jn-core(uid uid, rid r, ship s) + |= r=resource + =/ s=^ship + (~(got by joining) r) + jn-core(rid r, ship s) :: ++ jn-start |= [rid=resource =^ship] ^- (quip card _state) - =/ uid=@uv - (shaf %join eny.bowl) + ?< (~(has by joining) rid) + =. joining + (~(put by joining) rid ship) =. jn-core - jn-core(uid uid, rid rid, ship ship) + (jn-abed rid) =/ maybe-group (group-from-app-resource:met %contacts rid) - :_ state(joining (~(put by joining) uid [rid ship])) ?^ maybe-group - :_ ~ - %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook - pull-hook-action+!>([%add rid ship]) + ~|("already joined group {}" !!) + :_ state :~ %+ poke:(jn-pass-io /add) [ship %group-push-hook] group-update+!>([%add-members rid (silt our.bowl ~)]) @@ -130,8 +135,11 @@ %add :: join group ?> ?=(%poke-ack -.sign) ?^ p.sign - join-failed - joined + (cleanup %no-perms) + :_ state + :_ ~ + %+ poke-our:(jn-pass-io /pull-groups) %group-pull-hook + pull-hook-action+!>([%add ship rid]) :: %pull-groups ?> ?=(%poke-ack -.sign) @@ -160,7 +168,7 @@ %kick md-kick == :: - %pull-graph + %pull-graphs ?> ?=(%poke-ack -.sign) %- cleanup ?^(p.sign %strange %done) @@ -181,14 +189,21 @@ :: ++ md-fact |= [=mark =vase] - :_ state - ?. ?=(%metadata-update mark) ~ + ?. ?=(%metadata-update mark) `state =+ !<(upd=metadata-update vase) - ?. ?=(%add -.upd) ~ - ?. =(group-path.upd (en-path:resource rid)) ~ + ~& upd + ?. ?=(%add -.upd) `state + ?. =(group-path.upd (en-path:resource rid)) `state + =^ cards state + (cleanup %done) + :_ state + %+ welp cards + ?. hidden:(need (scry-group:grp rid)) ~ + =/ app-rid=resource + (de-path:resource app-path.resource.upd) :_ ~ %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook - pull-hook-action+!>([%add ship rid]) + pull-hook-action+!>([%add [entity .]:rid]) :: ++ groups-kick :_ state @@ -204,19 +219,13 @@ (cleanup %strange) :: ++ cleanup - |= fact=@t - :_ state(joining (~(del by joining) uid)) + |= =progress:view + ^- (quip card _state) + :_ state(joining (~(del by joining) rid)) :~ (leave-our:(jn-pass-io /groups) %group-store) (leave-our:(jn-pass-io /md) %metadata-store) - (tx-fact %join uid %no-perms) + (tx-fact progress) == - :: - ++ joined - :_ state - :_ ~ - %+ poke-our:(jn-pass-io /pull-group) %group-pull-hook - pull-hook-action+!>([%add ship rid]) - :: -- -- -- diff --git a/pkg/arvo/mar/group/view-action.hoon b/pkg/arvo/mar/group/view-action.hoon new file mode 100644 index 000000000..f901a13fa --- /dev/null +++ b/pkg/arvo/mar/group/view-action.hoon @@ -0,0 +1,12 @@ +/- view=group-view +|_ =action:view +++ grad %noun +++ grow + |% + ++ noun action + -- +++ grab + |% + ++ noun action:view + -- +-- diff --git a/pkg/arvo/mar/group/view-update.hoon b/pkg/arvo/mar/group/view-update.hoon new file mode 100644 index 000000000..22d5fa36f --- /dev/null +++ b/pkg/arvo/mar/group/view-update.hoon @@ -0,0 +1,12 @@ +/- view=group-view +|_ =update:view +++ grad %noun +++ grow + |% + ++ noun update + -- +++ grab + |% + ++ noun update:view + -- +-- diff --git a/pkg/arvo/sur/group-view.hoon b/pkg/arvo/sur/group-view.hoon new file mode 100644 index 000000000..c028dbaf2 --- /dev/null +++ b/pkg/arvo/sur/group-view.hoon @@ -0,0 +1,15 @@ +/- *resource +^? +|% +:: ++$ action + [%join =resource =ship] +:: ++$ progress + ?(%no-perms %strange %done) +:: ++$ update + $% [%initial =resources] + [%progress =resource =progress] + == +-- From ee34819cd2b806c7648bee51d2c4f7c558449081 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 29 Jan 2021 14:52:36 +1000 Subject: [PATCH 41/61] group-view: fix breakage from merge --- pkg/arvo/app/group-view.hoon | 26 +++++++++++++------------- pkg/arvo/app/metadata-store.hoon | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/arvo/app/group-view.hoon b/pkg/arvo/app/group-view.hoon index c03b02845..56888731c 100644 --- a/pkg/arvo/app/group-view.hoon +++ b/pkg/arvo/app/group-view.hoon @@ -1,4 +1,4 @@ -/- view-sur=group-view, group-store, *group, *metadata-store +/- view-sur=group-view, group-store, *group, metadata=metadata-store /+ default-agent, agentio, mdl=metadata, resource, dbug, grpl=group, verb |% ++ card card:agent:gall @@ -85,8 +85,7 @@ :: ++ tx-fact |= =progress:view - ~& +< - =; cage + =; =cage (fact:io cage /all tx+(en-path:resource rid) ~) group-view-update+!>([%progress rid progress]) :: @@ -115,7 +114,7 @@ =. jn-core (jn-abed rid) =/ maybe-group - (group-from-app-resource:met %contacts rid) + (peek-group:met %contacts rid) ?^ maybe-group ~|("already joined group {}" !!) :_ state @@ -184,24 +183,25 @@ `state :_ state :_ ~ - %+ poke-our:(jn-pass-io /pull-md) %metadata-hook - metadata-hook-action+!>([%add-synced ship (en-path:resource rid)]) + %+ poke-our:(jn-pass-io /pull-md) %metadata-push-hook + pull-hook-action+!>([%add [entity .]:rid]) :: ++ md-fact |= [=mark =vase] ?. ?=(%metadata-update mark) `state - =+ !<(upd=metadata-update vase) - ~& upd - ?. ?=(%add -.upd) `state - ?. =(group-path.upd (en-path:resource rid)) `state + =+ !<(=update:metadata vase) + ?. ?=(%initial-group -.update) `state + ?. =(group.update rid) `state =^ cards state (cleanup %done) :_ state %+ welp cards ?. hidden:(need (scry-group:grp rid)) ~ - =/ app-rid=resource - (de-path:resource app-path.resource.upd) - :_ ~ + %+ murn ~(tap by associations.update) + |= [=md-resource:metadata =association:metadata] + ?. =(app-name.md-resource %graph) ~ + =* rid resource.md-resource + :- ~ %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook pull-hook-action+!>([%add [entity .]:rid]) :: diff --git a/pkg/arvo/app/metadata-store.hoon b/pkg/arvo/app/metadata-store.hoon index ce832247f..fe8e8aa89 100644 --- a/pkg/arvo/app/metadata-store.hoon +++ b/pkg/arvo/app/metadata-store.hoon @@ -24,7 +24,7 @@ :: /group/%path associations for group :: /- store=metadata-store -/+ *metadata-json, default-agent, verb, dbug, resource, *migrate +/+ default-agent, verb, dbug, resource, *migrate |% +$ card card:agent:gall +$ base-state-0 From 5580190e5af60f4981ebba0a0ed3e93d32968a35 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 29 Jan 2021 14:52:56 +1000 Subject: [PATCH 42/61] group-view: add JSON conversion --- pkg/arvo/lib/group-view.hoon | 46 +++++++++++++++++++++++++++++ pkg/arvo/mar/group/view-action.hoon | 3 +- pkg/arvo/mar/group/view-update.hoon | 3 +- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 pkg/arvo/lib/group-view.hoon diff --git a/pkg/arvo/lib/group-view.hoon b/pkg/arvo/lib/group-view.hoon new file mode 100644 index 000000000..2c73e5823 --- /dev/null +++ b/pkg/arvo/lib/group-view.hoon @@ -0,0 +1,46 @@ +/- sur=group-view +/+ resource +^? +=< [. sur] +=, sur +|% +++ dejs + =, dejs:format + |% + ++ action + %- of + :~ join+join + == + :: + ++ join + %- ot + :~ resource+dejs:resource + ship+ship + == + -- +:: +++ enjs + =, enjs:format + |% + ++ update + |= upd=^update + %+ frond %group-view-update + %+ frond -.upd + ?- -.upd + %initial (initial +.upd) + %progress (progress +.upd) + == + :: + ++ progress + |= [rid=resource prog=^progress] + %- pairs + :~ resource+s+(enjs-path:resource rid) + progress+s+prog + == + :: + ++ initial + |= resources=(set resource) + ^- json + a+(turn ~(tap in resources) (cork enjs-path:resource (lead %s))) + -- +-- diff --git a/pkg/arvo/mar/group/view-action.hoon b/pkg/arvo/mar/group/view-action.hoon index f901a13fa..c1f2abdae 100644 --- a/pkg/arvo/mar/group/view-action.hoon +++ b/pkg/arvo/mar/group/view-action.hoon @@ -1,4 +1,4 @@ -/- view=group-view +/+ view=group-view |_ =action:view ++ grad %noun ++ grow @@ -8,5 +8,6 @@ ++ grab |% ++ noun action:view + ++ json action:dejs:view -- -- diff --git a/pkg/arvo/mar/group/view-update.hoon b/pkg/arvo/mar/group/view-update.hoon index 22d5fa36f..c7f822511 100644 --- a/pkg/arvo/mar/group/view-update.hoon +++ b/pkg/arvo/mar/group/view-update.hoon @@ -1,9 +1,10 @@ -/- view=group-view +/+ view=group-view |_ =update:view ++ grad %noun ++ grow |% ++ noun update + ++ json (update:enjs:view update) -- ++ grab |% From d41ea872c57d158bf4e2e5f9ca6c4fa6c9a9b229 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 29 Jan 2021 15:12:50 +1000 Subject: [PATCH 43/61] group-view: add to interface state --- pkg/arvo/app/group-view.hoon | 25 +- pkg/arvo/sur/group-view.hoon | 3 + pkg/interface/package-lock.json | 1296 ----------------- .../src/logic/reducers/group-view.ts | 30 + pkg/interface/src/logic/store/store.ts | 2 + .../src/logic/subscription/global.ts | 1 + 6 files changed, 47 insertions(+), 1310 deletions(-) create mode 100644 pkg/interface/src/logic/reducers/group-view.ts diff --git a/pkg/arvo/app/group-view.hoon b/pkg/arvo/app/group-view.hoon index 56888731c..970d0d4da 100644 --- a/pkg/arvo/app/group-view.hoon +++ b/pkg/arvo/app/group-view.hoon @@ -12,7 +12,7 @@ =* state - :: %- agent:dbug -%+ verb & +%+ verb | ^- agent:gall =< |_ =bowl:gall @@ -27,7 +27,8 @@ :: ++ on-load |= =vase - `this + =+ !<(old=state-zero vase) + `this(state old) :: ++ on-poke |= [=mark =vase] @@ -47,9 +48,7 @@ (fact:io group-view-update+!>([%initial ~(key by joining)]) ~)^~ == :: -++ on-peek - |= =path - [~ ~] +++ on-peek on-peek:def :: ++ on-agent |= [=wire =sign:agent:gall] @@ -63,13 +62,9 @@ == [cards this] :: -++ on-arvo - |= [=wire =sign-arvo] - `this +++ on-arvo on-arvo:def :: -++ on-leave - |= =path - `this +++ on-leave on-leave:def :: ++ on-fail on-fail:def -- @@ -122,6 +117,7 @@ [ship %group-push-hook] group-update+!>([%add-members rid (silt our.bowl ~)]) :: + (tx-fact %start) watch-md watch-groups == @@ -136,9 +132,10 @@ ?^ p.sign (cleanup %no-perms) :_ state - :_ ~ - %+ poke-our:(jn-pass-io /pull-groups) %group-pull-hook - pull-hook-action+!>([%add ship rid]) + :~ (tx-fact %added) + %+ poke-our:(jn-pass-io /pull-groups) %group-pull-hook + pull-hook-action+!>([%add ship rid]) + == :: %pull-groups ?> ?=(%poke-ack -.sign) diff --git a/pkg/arvo/sur/group-view.hoon b/pkg/arvo/sur/group-view.hoon index c028dbaf2..be275136c 100644 --- a/pkg/arvo/sur/group-view.hoon +++ b/pkg/arvo/sur/group-view.hoon @@ -6,6 +6,9 @@ [%join =resource =ship] :: +$ progress + ?(%start %added final) +:: ++$ final ?(%no-perms %strange %done) :: +$ update diff --git a/pkg/interface/package-lock.json b/pkg/interface/package-lock.json index 24a6e024a..cdadefa5f 100644 --- a/pkg/interface/package-lock.json +++ b/pkg/interface/package-lock.json @@ -11769,563 +11769,6 @@ "path-dirname": "^1.0.0" }, "dependencies": { -<<<<<<< HEAD - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "3.2.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "0.5.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.14.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - } - }, - "nopt": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.7.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.1", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { -======= "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", @@ -12333,7 +11776,6 @@ "dev": true, "optional": true, "requires": { ->>>>>>> origin/release/next-userspace "is-extglob": "^2.1.0" } } @@ -12511,37 +11953,6 @@ "which": "^1.2.9" } }, -<<<<<<< HEAD - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, -======= ->>>>>>> origin/release/next-userspace "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -12569,15 +11980,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, -<<<<<<< HEAD - "v8-compile-cache": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", - "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", - "dev": true - }, -======= ->>>>>>> origin/release/next-userspace "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -12590,15 +11992,9 @@ } }, "webpack-dev-middleware": { -<<<<<<< HEAD - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", - "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", -======= "version": "3.7.3", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", ->>>>>>> origin/release/next-userspace "dev": true, "requires": { "memory-fs": "^0.4.1", @@ -12609,29 +12005,17 @@ }, "dependencies": { "mime": { -<<<<<<< HEAD - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", - "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==", -======= "version": "2.5.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.0.tgz", "integrity": "sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag==", ->>>>>>> origin/release/next-userspace "dev": true } } }, "webpack-dev-server": { -<<<<<<< HEAD - "version": "3.10.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz", - "integrity": "sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ==", -======= "version": "3.11.2", "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz", "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", ->>>>>>> origin/release/next-userspace "dev": true, "requires": { "ansi-html": "0.0.7", @@ -12642,30 +12026,13 @@ "debug": "^4.1.1", "del": "^4.1.1", "express": "^4.17.1", -<<<<<<< HEAD - "html-entities": "^1.2.1", -======= "html-entities": "^1.3.1", ->>>>>>> origin/release/next-userspace "http-proxy-middleware": "0.19.1", "import-local": "^2.0.0", "internal-ip": "^4.3.0", "ip": "^1.1.5", "is-absolute-url": "^3.0.3", "killable": "^1.0.1", -<<<<<<< HEAD - "loglevel": "^1.6.6", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.25", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.7", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "0.3.19", - "sockjs-client": "1.4.0", - "spdy": "^4.0.1", -======= "loglevel": "^1.6.8", "opn": "^5.5.0", "p-retry": "^3.0.1", @@ -12677,18 +12044,13 @@ "sockjs": "^0.3.21", "sockjs-client": "^1.5.0", "spdy": "^4.0.2", ->>>>>>> origin/release/next-userspace "strip-ansi": "^3.0.1", "supports-color": "^6.1.0", "url": "^0.11.0", "webpack-dev-middleware": "^3.7.2", "webpack-log": "^2.0.0", "ws": "^6.2.1", -<<<<<<< HEAD - "yargs": "12.0.5" -======= "yargs": "^13.3.2" ->>>>>>> origin/release/next-userspace }, "dependencies": { "ansi-regex": { @@ -12711,7 +12073,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", -<<<<<<< HEAD "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -12763,663 +12124,6 @@ "upath": "^1.1.1" } }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "fsevents": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", - "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1", - "node-pre-gyp": "*" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "3.2.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "0.5.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.14.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - } - }, - "nopt": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.7.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.1", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, -======= ->>>>>>> origin/release/next-userspace - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } -<<<<<<< HEAD - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "optional": true -======= ->>>>>>> origin/release/next-userspace - } - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", diff --git a/pkg/interface/src/logic/reducers/group-view.ts b/pkg/interface/src/logic/reducers/group-view.ts new file mode 100644 index 000000000..3f5e536ad --- /dev/null +++ b/pkg/interface/src/logic/reducers/group-view.ts @@ -0,0 +1,30 @@ +import { resourceAsPath } from "~/logic/lib/util"; + + +const initial = (json: any, state: any) => { + const data = json.initial; + if(data) { + state.pendingJoin = new Set(data); + } +} + +const progress = (json: any, state: any) => { + const data = json.progress; + if(data) { + const res = resourceAsPath(data.resource); + const { progress } = data; + if(progress === 'start') { + state.pendingJoin.add(res); + } else if (progress !== 'added') { + state.pendingJoin.delete(res); + } + } +} + +export const GroupViewReducer = (json: any, state: any) => { + const data = json['group-view-update']; + if(data) { + progress(data, state); + initial(data, state); + } +} diff --git a/pkg/interface/src/logic/store/store.ts b/pkg/interface/src/logic/store/store.ts index fd1d0914c..837d3925c 100644 --- a/pkg/interface/src/logic/store/store.ts +++ b/pkg/interface/src/logic/store/store.ts @@ -16,6 +16,7 @@ import ConnectionReducer from '../reducers/connection'; import SettingsReducer from '../reducers/settings-update'; import {OrderedMap} from '../lib/OrderedMap'; import { BigIntOrderedMap } from '../lib/BigIntOrderedMap'; +import {GroupViewReducer} from '../reducers/group-view'; export default class GlobalStore extends BaseStore { @@ -95,5 +96,6 @@ export default class GlobalStore extends BaseStore { GraphReducer(data, this.state); HarkReducer(data, this.state); this.settingsReducer.reduce(data, this.state); + GroupViewReducer(data, this.state); } } diff --git a/pkg/interface/src/logic/subscription/global.ts b/pkg/interface/src/logic/subscription/global.ts index 5c88e0f8a..7e457f79a 100644 --- a/pkg/interface/src/logic/subscription/global.ts +++ b/pkg/interface/src/logic/subscription/global.ts @@ -45,6 +45,7 @@ export default class GlobalSubscription extends BaseSubscription { this.subscribe('/updates', 'hark-graph-hook'); this.subscribe('/updates', 'hark-group-hook'); this.subscribe('/all', 'settings-store'); + this.subscribe('/all', 'group-view'); } restart() { From 8d39763f43d582c280eaa9c1923ce8e3d12d35e1 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 29 Jan 2021 14:24:57 -0600 Subject: [PATCH 44/61] interface: set status modal works --- .../apps/profile/components/SetStatus.tsx | 6 +- .../src/views/components/SetStatusBarModal.js | 88 +++++++++++++++++++ .../src/views/components/StatusBar.js | 23 ++--- 3 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 pkg/interface/src/views/components/SetStatusBarModal.js diff --git a/pkg/interface/src/views/apps/profile/components/SetStatus.tsx b/pkg/interface/src/views/apps/profile/components/SetStatus.tsx index a89511f30..4674f315c 100644 --- a/pkg/interface/src/views/apps/profile/components/SetStatus.tsx +++ b/pkg/interface/src/views/apps/profile/components/SetStatus.tsx @@ -13,7 +13,7 @@ import { export function SetStatus(props: any) { - const { contact, ship, api } = props; + const { contact, ship, api, callback } = props; const [_status, setStatus] = useState(''); const onStatusChange = useCallback( (e: ChangeEvent) => { @@ -28,6 +28,10 @@ export function SetStatus(props: any) { const editStatus = () => { api.contacts.edit(ship, {status: _status}); + + if (callback) { + callback(); + } }; return ( diff --git a/pkg/interface/src/views/components/SetStatusBarModal.js b/pkg/interface/src/views/components/SetStatusBarModal.js new file mode 100644 index 000000000..baa0286e5 --- /dev/null +++ b/pkg/interface/src/views/components/SetStatusBarModal.js @@ -0,0 +1,88 @@ +import React, { + useState, + useEffect +} from 'react'; + +import { + Row, + Box +} from '@tlon/indigo-react'; + +import { SetStatus } from '~/views/apps/profile/components/SetStatus'; + + +export const SetStatusBarModal = (props) => { + const { + ship, + contact, + api, + ...rest + } = props; + const [modalShown, setModalShown] = useState(false); + + const handleKeyDown = (event) => { + if (event.key === 'Escape') { + setModalShown(false); + } + } + + useEffect(() => { + window.addEventListener('keydown', handleKeyDown); + + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; + }, [modalShown]); + + return ( + <> + {modalShown && ( + setModalShown(false)} + > + e.stopPropagation()} + display="flex" + alignItems="stretch" + flexDirection="column" + > + + { + setModalShown(false); + }} /> + + + + )} + setModalShown(true)}> + Set Status + + + ); +} + diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index 9a0e906f3..ca6cd9da6 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -1,4 +1,7 @@ -import React from 'react'; +import React, { + useState, + useEffect +} from 'react'; import { Col, @@ -14,11 +17,13 @@ import { Dropdown } from './Dropdown'; import { StatusBarItem } from './StatusBarItem'; import { Sigil } from '~/logic/lib/sigil'; import { uxToHex } from "~/logic/lib/util"; +import { SetStatusBarModal } from './SetStatusBarModal'; import useLocalState from '~/logic/state/local'; + const StatusBar = (props) => { - const { ourContact } = props; + const { ourContact, api, ship } = props; const invites = [].concat(...Object.values(props.invites).map(obj => Object.values(obj))); const metaKey = (window.navigator.platform.includes('Mac')) ? '⌘' : 'Ctrl+'; const { toggleOmnibox, hideAvatars } = @@ -106,17 +111,13 @@ const StatusBar = (props) => { color='black' cursor='pointer' fontSize={0} - onClick={() => props.history.push('/~profile/~' + window.ship)}> + onClick={() => props.history.push(`/~profile/~${ship}`)}> View Profile - console.log('TODO, show a modal')}> - Set Status - + Date: Fri, 29 Jan 2021 17:28:48 -0500 Subject: [PATCH 45/61] landscape: "contacts" -> "groups" in associations --- pkg/interface/src/logic/api/contacts.ts | 2 ++ pkg/interface/src/logic/lib/omnibox.js | 2 +- pkg/interface/src/logic/lib/workspace.ts | 2 +- pkg/interface/src/types/noun.ts | 2 +- .../src/views/apps/launch/components/Groups.tsx | 10 +++++----- pkg/interface/src/views/apps/notifications/header.tsx | 2 +- pkg/interface/src/views/apps/notifications/invites.tsx | 2 +- .../src/views/apps/notifications/notifications.tsx | 2 +- .../src/views/landscape/components/GroupSwitcher.tsx | 6 +++--- .../src/views/landscape/components/GroupsPane.tsx | 4 ++-- .../src/views/landscape/components/NewGroup.tsx | 2 +- .../src/views/landscape/components/Resource.tsx | 4 ++-- .../views/landscape/components/Sidebar/SidebarList.tsx | 2 +- 13 files changed, 22 insertions(+), 20 deletions(-) diff --git a/pkg/interface/src/logic/api/contacts.ts b/pkg/interface/src/logic/api/contacts.ts index 34db3c773..fab1ed90a 100644 --- a/pkg/interface/src/logic/api/contacts.ts +++ b/pkg/interface/src/logic/api/contacts.ts @@ -22,6 +22,8 @@ export default class ContactsApi extends BaseApi { {color: 'fff'} // with no 0x prefix {avatar: null} {avatar: ''} + {add-group: {ship, name}} + {remove-group: {ship, name}} */ console.log(ship, editField); return this.storeAction({ diff --git a/pkg/interface/src/logic/lib/omnibox.js b/pkg/interface/src/logic/lib/omnibox.js index 6473d86ce..0c2e27c3e 100644 --- a/pkg/interface/src/logic/lib/omnibox.js +++ b/pkg/interface/src/logic/lib/omnibox.js @@ -116,7 +116,7 @@ export default function index(contacts, associations, apps, currentGroup, groups title, `/~landscape${group}/join/${app}${each.resource}`, app.charAt(0).toUpperCase() + app.slice(1), - (associations?.contacts?.[each.group]?.metadata?.title || null) + (associations?.groups?.[each.group]?.metadata?.title || null) ); subscriptions.push(obj); } diff --git a/pkg/interface/src/logic/lib/workspace.ts b/pkg/interface/src/logic/lib/workspace.ts index 2ab8ce65b..7532bac6e 100644 --- a/pkg/interface/src/logic/lib/workspace.ts +++ b/pkg/interface/src/logic/lib/workspace.ts @@ -8,7 +8,7 @@ export function getTitleFromWorkspace( case "home": return "DMs + Drafts"; case "group": - const association = associations.contacts[workspace.group]; + const association = associations.groups[workspace.group]; return association?.metadata?.title || ""; } } diff --git a/pkg/interface/src/types/noun.ts b/pkg/interface/src/types/noun.ts index 95dedea82..f566f0240 100644 --- a/pkg/interface/src/types/noun.ts +++ b/pkg/interface/src/types/noun.ts @@ -18,7 +18,7 @@ export type Serial = string; export type Jug = Map>; // name of app -export type AppName = 'chat' | 'link' | 'contacts' | 'publish' | 'graph'; +export type AppName = 'contacts' | 'groups' | 'graph'; export function getTagFromFrond(frond: O): keyof O { const tags = Object.keys(frond) as Array; diff --git a/pkg/interface/src/views/apps/launch/components/Groups.tsx b/pkg/interface/src/views/apps/launch/components/Groups.tsx index 42eab90c6..8a23536d2 100644 --- a/pkg/interface/src/views/apps/launch/components/Groups.tsx +++ b/pkg/interface/src/views/apps/launch/components/Groups.tsx @@ -16,7 +16,7 @@ const sortGroupsAlph = (a: Association, b: Association) => alphabeticalOrder(a.metadata.title, b.metadata.title); -const getGraphUnreads = (associations: Associations, unreads: Unreads) => (path: string) => +const getGraphUnreads = (associations: Associations, unreads: Unreads) => (path: string) => f.flow( f.pickBy((a: Association) => a.group === path), f.map('resource'), @@ -24,7 +24,7 @@ const getGraphUnreads = (associations: Associations, unreads: Unreads) => (path: f.reduce(f.add, 0) )(associations.graph); -const getGraphNotifications = (associations: Associations, unreads: Unreads) => (path: string) => +const getGraphNotifications = (associations: Associations, unreads: Unreads) => (path: string) => f.flow( f.pickBy((a: Association) => a.group === path), f.map('resource'), @@ -36,7 +36,7 @@ const getGraphNotifications = (associations: Associations, unreads: Unreads) => export default function Groups(props: GroupsProps & Parameters[0]) { const { associations, unreads, inbox, ...boxProps } = props; - const groups = Object.values(associations?.contacts || {}) + const groups = Object.values(associations?.groups || {}) .filter((e) => e?.group in props.groups) .sort(sortGroupsAlph); const graphUnreads = getGraphUnreads(associations || {}, unreads); @@ -78,10 +78,10 @@ function Group(props: GroupProps) { {title} - {unreads > 0 && + {unreads > 0 && ({unreads} unread{unreads !== 1 && 's'} ) } - {updates > 0 && + {updates > 0 && ({updates} update{updates !== 1 && 's'} ) } diff --git a/pkg/interface/src/views/apps/notifications/header.tsx b/pkg/interface/src/views/apps/notifications/header.tsx index b987a0693..e27a4ef31 100644 --- a/pkg/interface/src/views/apps/notifications/header.tsx +++ b/pkg/interface/src/views/apps/notifications/header.tsx @@ -63,7 +63,7 @@ export function Header(props: { const time = moment(props.time).format("HH:mm"); const groupTitle = - props.associations.contacts?.[props.group]?.metadata?.title; + props.associations.groups?.[props.group]?.metadata?.title; const app = props.chat ? 'chat' : 'graph'; const channelTitle = diff --git a/pkg/interface/src/views/apps/notifications/invites.tsx b/pkg/interface/src/views/apps/notifications/invites.tsx index 5b77fa212..b01f6ff04 100644 --- a/pkg/interface/src/views/apps/notifications/invites.tsx +++ b/pkg/interface/src/views/apps/notifications/invites.tsx @@ -31,7 +31,7 @@ export function Invites(props: InvitesProps) { const resourcePath = resourceAsPath(invite.resource); if (app === "contacts") { await api.contacts.join(resource); - await waiter((p) => resourcePath in p.associations?.contacts); + await waiter((p) => resourcePath in p.associations?.groups); await api.invite.accept(app, uid); history.push(`/~landscape${resourcePath}`); } else if (app === "graph") { diff --git a/pkg/interface/src/views/apps/notifications/notifications.tsx b/pkg/interface/src/views/apps/notifications/notifications.tsx index c4567cc09..16f2658b2 100644 --- a/pkg/interface/src/views/apps/notifications/notifications.tsx +++ b/pkg/interface/src/views/apps/notifications/notifications.tsx @@ -44,7 +44,7 @@ export default function NotificationsScreen(props: any) { filter.groups.length === 0 ? "All" : filter.groups - .map((g) => props.associations?.contacts?.[g]?.metadata?.title) + .map((g) => props.associations?.groups?.[g]?.metadata?.title) .join(", "); return ( diff --git a/pkg/interface/src/views/landscape/components/GroupSwitcher.tsx b/pkg/interface/src/views/landscape/components/GroupSwitcher.tsx index 1a78f0299..e98448f90 100644 --- a/pkg/interface/src/views/landscape/components/GroupSwitcher.tsx +++ b/pkg/interface/src/views/landscape/components/GroupSwitcher.tsx @@ -42,9 +42,9 @@ function RecentGroups(props: { recent: string[]; associations: Associations }) { Recent Groups {props.recent.filter((e) => { - return (e in associations?.contacts); + return (e in associations?.groups); }).slice(1, 5).map((g) => { - const assoc = associations.contacts[g]; + const assoc = associations.groups[g]; const color = uxToHex(assoc?.metadata?.color || '0x0'); return ( @@ -78,7 +78,7 @@ export function GroupSwitcher(props: { }) { const { associations, workspace, isAdmin } = props; const title = getTitleFromWorkspace(associations, workspace); - const metadata = workspace.type === 'home' ? undefined : associations.contacts[workspace.group].metadata; + const metadata = workspace.type === 'home' ? undefined : associations.groups[workspace.group].metadata; const navTo = (to: string) => `${props.baseUrl}${to}`; return ( diff --git a/pkg/interface/src/views/landscape/components/GroupsPane.tsx b/pkg/interface/src/views/landscape/components/GroupsPane.tsx index be8344c17..b1e5b08eb 100644 --- a/pkg/interface/src/views/landscape/components/GroupsPane.tsx +++ b/pkg/interface/src/views/landscape/components/GroupsPane.tsx @@ -43,7 +43,7 @@ export function GroupsPane(props: GroupsPaneProps) { const groupContacts = (groupPath && contacts[groupPath]) || undefined; const rootIdentity = contacts?.["/~/default"]?.[window.ship]; const groupAssociation = - (groupPath && associations.contacts[groupPath]) || undefined; + (groupPath && associations.groups[groupPath]) || undefined; const group = (groupPath && groups[groupPath]) || undefined; const [recentGroups, setRecentGroups] = useLocalStorageState( "recent-groups", @@ -196,7 +196,7 @@ export function GroupsPane(props: GroupsPaneProps) { let summary: ReactNode; if(groupAssociation?.group) { const memberCount = props.groups[groupAssociation.group].members.size; - summary = { - return path in contacts && path in groups && path in associations.contacts; + return path in contacts && path in groups && path in associations.groups; }); actions.setStatus({ success: null }); diff --git a/pkg/interface/src/views/landscape/components/Resource.tsx b/pkg/interface/src/views/landscape/components/Resource.tsx index ddfd316c5..8c3cd7d7c 100644 --- a/pkg/interface/src/views/landscape/components/Resource.tsx +++ b/pkg/interface/src/views/landscape/components/Resource.tsx @@ -37,8 +37,8 @@ export function Resource(props: ResourceProps) { const skelProps = { api, association }; let title = props.association.metadata.title; if ('workspace' in props) { - if ('group' in props.workspace && props.workspace.group in props.associations.contacts) { - title = `${props.associations.contacts[props.workspace.group].metadata.title} - ${props.association.metadata.title}`; + if ('group' in props.workspace && props.workspace.group in props.associations.groups) { + title = `${props.associations.groups[props.workspace.group].metadata.title} - ${props.association.metadata.title}`; } } return ( diff --git a/pkg/interface/src/views/landscape/components/Sidebar/SidebarList.tsx b/pkg/interface/src/views/landscape/components/Sidebar/SidebarList.tsx index ee5893996..a3d155fd8 100644 --- a/pkg/interface/src/views/landscape/components/Sidebar/SidebarList.tsx +++ b/pkg/interface/src/views/landscape/components/Sidebar/SidebarList.tsx @@ -57,7 +57,7 @@ export function SidebarList(props: { const assoc = associations[a]; return group ? assoc.group === group - : !(assoc.group in props.associations.contacts); + : !(assoc.group in props.associations.groups); }) .sort(sidebarSort(associations, props.apps)[config.sortBy]); From 81bd17a1f291bf3f47e6385d25d1f3d5cc67bb84 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Fri, 29 Jan 2021 17:29:18 -0500 Subject: [PATCH 46/61] groupSearch: stub in multi-group search --- .../src/views/components/GroupSearch.tsx | 95 +++++++++++-------- .../src/views/components/ShipSearch.tsx | 2 +- .../landscape/components/GroupifyForm.tsx | 5 +- 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/pkg/interface/src/views/components/GroupSearch.tsx b/pkg/interface/src/views/components/GroupSearch.tsx index 0c963a00c..012d38262 100644 --- a/pkg/interface/src/views/components/GroupSearch.tsx +++ b/pkg/interface/src/views/components/GroupSearch.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useCallback } from "react"; +import React, { useMemo, useCallback, useState, useEffect } from 'react'; import { Box, Text, @@ -6,17 +6,17 @@ import { Row, Col, Icon, - ErrorLabel, -} from "@tlon/indigo-react"; -import _ from "lodash"; -import { useField } from "formik"; -import styled from "styled-components"; + ErrorLabel +} from '@tlon/indigo-react'; +import _ from 'lodash'; +import { useField } from 'formik'; +import styled from 'styled-components'; -import { roleForShip } from "~/logic/lib/group"; +import { roleForShip } from '~/logic/lib/group'; -import { DropdownSearch } from "./DropdownSearch"; -import { Groups } from "~/types"; -import { Associations, Association } from "~/types/metadata-update"; +import { DropdownSearch } from './DropdownSearch'; +import { Groups } from '~/types'; +import { Associations, Association } from '~/types/metadata-update'; interface InviteSearchProps { disabled?: boolean; @@ -26,11 +26,12 @@ interface InviteSearchProps { label: string; caption?: string; id: string; + maxLength?: number; } const CandidateBox = styled(Box)<{ selected: boolean }>` &:hover { - background-color: ${(p) => p.theme.colors.washedGray}; + background-color: ${p => p.theme.colors.washedGray}; } `; @@ -64,38 +65,45 @@ function renderCandidate( export function GroupSearch(props: InviteSearchProps) { const { id, caption, label } = props; + const [selected, setSelected] = useState([] as string[]); const groups: Association[] = useMemo(() => { return props.adminOnly ? Object.values( - Object.keys(props.associations?.contacts) + Object.keys(props.associations?.groups) .filter( - (e) => roleForShip(props.groups[e], window.ship) === "admin" + e => roleForShip(props.groups[e], window.ship) === 'admin' ) .reduce((obj, key) => { - obj[key] = props.associations?.contacts[key]; + obj[key] = props.associations?.groups[key]; return obj; }, {}) || {} ) - : Object.values(props.associations?.contacts || {}); - }, [props.associations?.contacts]); + : Object.values(props.associations?.groups || {}); + }, [props.associations?.groups]); const [{ value }, meta, { setValue, setTouched }] = useField(props.id); + useEffect(() => { + setValue(selected); + }, [selected]) + const { title: groupTitle } = - props.associations.contacts?.[value]?.metadata || {}; + props.associations.groups?.[value]?.metadata || {}; const onSelect = useCallback( - (a: Association) => { - setValue(a.group); + (s: string) => { setTouched(true); + setSelected(v => _.uniq([...v, s])); }, - [setValue] + [setTouched, setSelected] ); - const onUnselect = useCallback(() => { - setValue(undefined); - setTouched(true); - }, [setValue]); + const onRemove = useCallback( + (s: string) => { + setSelected(groups => groups.filter(group => group !== s)) + }, + [setSelected] + ); return ( @@ -105,25 +113,11 @@ export function GroupSearch(props: InviteSearchProps) { {caption} )} - {value && ( - - {groupTitle || value} - - - )} - {!value && ( mt="2" candidates={groups} + placeholder="Search for groups..." + disabled={props.maxLength ? selected.length >= props.maxLength : false} renderCandidate={renderCandidate} search={(s: string, a: Association) => a.metadata.title.toLowerCase().startsWith(s.toLowerCase()) @@ -131,8 +125,27 @@ export function GroupSearch(props: InviteSearchProps) { getKey={(a: Association) => a.group} onSelect={onSelect} /> + {value?.length > 0 && ( + value.map((e) => { + return ( + + {groupTitle || e} + + + ); + }) )} - + {meta.error} diff --git a/pkg/interface/src/views/components/ShipSearch.tsx b/pkg/interface/src/views/components/ShipSearch.tsx index f26ed4253..6c9db1760 100644 --- a/pkg/interface/src/views/components/ShipSearch.tsx +++ b/pkg/interface/src/views/components/ShipSearch.tsx @@ -173,7 +173,7 @@ export function ShipSearch(props: InviteSearchProps) { const result = ob.isValidPatp(ship); return result ? deSig(s) ?? undefined : undefined; }} - placeholder="Search for ships" + placeholder="Search for ships..." candidates={peers} renderCandidate={renderCandidate} disabled={props.maxLength ? selected.length >= props.maxLength : false} diff --git a/pkg/interface/src/views/landscape/components/GroupifyForm.tsx b/pkg/interface/src/views/landscape/components/GroupifyForm.tsx index e8ba57af2..6e8424a2b 100644 --- a/pkg/interface/src/views/landscape/components/GroupifyForm.tsx +++ b/pkg/interface/src/views/landscape/components/GroupifyForm.tsx @@ -14,7 +14,7 @@ const formSchema = Yup.object({ }); interface FormSchema { - group: string | null; + group: string[] | null; } interface GroupifyFormProps { @@ -37,7 +37,7 @@ export function GroupifyForm(props: GroupifyFormProps) { await props.api.graph.groupifyGraph( ship, name, - values.group || undefined + values.group?.toString() || undefined ); const mod = association.metadata.module || association['app-name']; const newGroup = values.group || association.group; @@ -79,6 +79,7 @@ export function GroupifyForm(props: GroupifyFormProps) { groups={props.groups} associations={props.associations} adminOnly + maxLength={1} /> Groupify From 9e3d5b7a33c67690972879e28ac6fb56238c316d Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Fri, 29 Jan 2021 17:29:41 -0500 Subject: [PATCH 47/61] landscape: add group search to profile --- .../apps/profile/components/EditProfile.tsx | 16 +++++++++++++--- .../views/apps/profile/components/Profile.tsx | 2 ++ pkg/interface/src/views/apps/profile/profile.tsx | 2 ++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx index 70b94096d..35e3a135f 100644 --- a/pkg/interface/src/views/apps/profile/components/EditProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/EditProfile.tsx @@ -21,6 +21,8 @@ import { AsyncButton } from "~/views/components/AsyncButton"; import { ColorInput } from "~/views/components/ColorInput"; import { ImageInput } from "~/views/components/ImageInput"; import { MarkdownField } from "~/views/apps/publish/components/MarkdownField"; +import { resourceFromPath } from "~/logic/lib/group"; +import GroupSearch from "~/views/components/GroupSearch"; const formSchema = Yup.object({ @@ -62,8 +64,15 @@ export function EditProfile(props: any) { return acc.then(() => api.contacts.setPublic(newValue) ); + } else if (key === 'groups') { + newValue.map((e) => { + if (!contact['groups']?.[e]) { + return acc.then(() => { + api.contacts.edit(ship, { 'add-group': resourceFromPath(e) }); + }); + } + }) } else if ( - key !== "groups" && key !== "last-updated" && key !== "isPublic" ) { @@ -93,7 +102,7 @@ export function EditProfile(props: any) { Description - + @@ -105,7 +114,8 @@ export function EditProfile(props: any) { - + + Submit diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 5c3cf67d7..64e1ec0e8 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -66,6 +66,8 @@ export function Profile(props: any) { contact={contact} s3={props.s3} api={props.api} + groups={props.groups} + associations={props.associations} isPublic={isPublic}/> ) : ( diff --git a/pkg/interface/src/views/apps/profile/profile.tsx b/pkg/interface/src/views/apps/profile/profile.tsx index e2fdfed4d..eb7853f26 100644 --- a/pkg/interface/src/views/apps/profile/profile.tsx +++ b/pkg/interface/src/views/apps/profile/profile.tsx @@ -45,6 +45,8 @@ export default function ProfileScreen(props: any) { Date: Fri, 29 Jan 2021 16:38:32 -0600 Subject: [PATCH 48/61] metadata-store: compiles --- pkg/arvo/app/metadata-store.hoon | 2 +- pkg/arvo/ted/group/on-leave.hoon | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/app/metadata-store.hoon b/pkg/arvo/app/metadata-store.hoon index ce832247f..fe8e8aa89 100644 --- a/pkg/arvo/app/metadata-store.hoon +++ b/pkg/arvo/app/metadata-store.hoon @@ -24,7 +24,7 @@ :: /group/%path associations for group :: /- store=metadata-store -/+ *metadata-json, default-agent, verb, dbug, resource, *migrate +/+ default-agent, verb, dbug, resource, *migrate |% +$ card card:agent:gall +$ base-state-0 diff --git a/pkg/arvo/ted/group/on-leave.hoon b/pkg/arvo/ted/group/on-leave.hoon index 3e9d00ec3..e308b7d6d 100644 --- a/pkg/arvo/ted/group/on-leave.hoon +++ b/pkg/arvo/ted/group/on-leave.hoon @@ -50,7 +50,7 @@ (en-path:res resource.update) /noun == -=/ entries=(list [m=md-resource:met g=resource:res =metadata:met]) +=/ entries=(list [m=md-resource:met g=resource:res *]) ~(tap by associations) |- ^- form:m =* loop $ @@ -62,7 +62,7 @@ %+ raw-poke [our.bowl %metadata-store] :- %metadata-action - !> ^- metadata-action:met + !> ^- action:met [%remove g.i.entries m.i.entries] :: archive graph associated with group :: From 13bad6b16cd86cab0ef30d6edb36f91cc388c763 Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 29 Jan 2021 16:52:04 -0600 Subject: [PATCH 49/61] graph-create thread: fix metadata to metadatum rename --- pkg/arvo/ted/graph/create.hoon | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/arvo/ted/graph/create.hoon b/pkg/arvo/ted/graph/create.hoon index a883d822c..745020ef7 100644 --- a/pkg/arvo/ted/graph/create.hoon +++ b/pkg/arvo/ted/graph/create.hoon @@ -1,6 +1,6 @@ /- spider, graph=graph-store, - *metadata-store, + met=metadata-store, *group, group-store, inv=invite-store @@ -57,18 +57,18 @@ :: :: Setup metadata :: -=/ =metadata - %* . *metadata +=/ =metadatum:met + %* . *metadatum:met title title.action description description.action date-created now.bowl creator our.bowl module module.action == -=/ =metadata-action - [%add group graph+rid.action metadata] +=/ met-action=action:met + [%add group graph+rid.action metadatum] ;< ~ bind:m - (poke-our %metadata-store %metadata-action !>(metadata-action)) + (poke-our %metadata-store %metadata-action !>(met-action)) ;< ~ bind:m (poke-our %metadata-push-hook %push-hook-action !>([%add group])) :: From 7b82c55b597192f6a1d13437ad4b802ef894d6fd Mon Sep 17 00:00:00 2001 From: Logan Allen Date: Fri, 29 Jan 2021 16:58:44 -0600 Subject: [PATCH 50/61] graph-delete thread: fix %metadata-store scry and %hook reference to %push-hook --- pkg/arvo/ted/graph/delete.hoon | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/pkg/arvo/ted/graph/delete.hoon b/pkg/arvo/ted/graph/delete.hoon index f98ddf075..d921e4723 100644 --- a/pkg/arvo/ted/graph/delete.hoon +++ b/pkg/arvo/ted/graph/delete.hoon @@ -1,4 +1,4 @@ -/- spider, graph-view, graph=graph-store, *metadata-store, *group +/- spider, graph-view, graph=graph-store, met=metadata-store, *group /+ strandio, resource => |% @@ -9,16 +9,14 @@ ++ scry-metadata |= rid=resource =/ m (strand ,(unit resource)) - ;< paxs=(unit (set path)) bind:m - %+ scry:strandio ,(unit (set path)) + ;< group=(unit resource) bind:m + %+ scry:strandio ,(unit resource) ;: weld /gx/metadata-store/resource/graph (en-path:resource rid) /noun == - ?~ paxs (pure:m ~) - ?~ u.paxs (pure:m ~) - (pure:m `(de-path:resource n.u.paxs)) + (pure:m group) :: ++ scry-group |= rid=resource @@ -42,11 +40,7 @@ ;< ~ bind:m (poke-our %graph-push-hook %push-hook-action !>([%remove rid])) ;< ~ bind:m - %+ poke-our %metadata-hook - :- %metadata-action - !> :+ %remove - (en-path:resource group-rid) - [%graph (en-path:resource rid)] + (poke-our %metadata-push-hook %push-hook-action !>([%remove rid])) (pure:m ~) -- :: @@ -74,6 +68,5 @@ (poke-our %group-push-hook %push-hook-action !>([%remove rid.action])) ;< ~ bind:m (delete-graph u.ugroup-rid rid.action) ;< ~ bind:m - %+ poke-our %metadata-hook - metadata-hook-action+!>([%remove (en-path:resource u.ugroup-rid)]) + (poke-our %metadata-push-hook %push-hook-action !>([%remove rid.action])) (pure:m !>(~)) From 0bad34b04449f628a511db91fac0f17e11fff6d5 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 11:57:56 +1000 Subject: [PATCH 51/61] group-view: refactor to surface UI state --- pkg/arvo/app/group-view.hoon | 130 +++++++++++++++---------------- pkg/arvo/app/metadata-store.hoon | 15 ++-- pkg/arvo/lib/group-view.hoon | 11 ++- pkg/arvo/sur/group-view.hoon | 2 +- 4 files changed, 79 insertions(+), 79 deletions(-) diff --git a/pkg/arvo/app/group-view.hoon b/pkg/arvo/app/group-view.hoon index 970d0d4da..cdb17577c 100644 --- a/pkg/arvo/app/group-view.hoon +++ b/pkg/arvo/app/group-view.hoon @@ -4,7 +4,7 @@ ++ card card:agent:gall +$ state-zero $: %0 - joining=(map rid=resource =ship) + joining=(map rid=resource [=ship =progress:view]) == ++ view view-sur -- @@ -37,7 +37,7 @@ (on-poke:def mark vase) =+ !<(=action:view vase) =^ cards state - (jn-start:join:gc +.action) + jn-abet:(jn-start:join:gc +.action) [cards this] :: ++ on-watch @@ -45,7 +45,12 @@ ?+ path (on-watch:def path) [%all ~] :_ this - (fact:io group-view-update+!>([%initial ~(key by joining)]) ~)^~ + :_ ~ + %+ fact:io + :- %group-view-update + !> ^- update:view + [%initial (~(run by joining) |=([=ship =progress:view] progress))] + ~ == :: ++ on-peek on-peek:def @@ -58,7 +63,7 @@ =/ rid (de-path:resource t.wire) ?. (~(has by joining) rid) `state - (jn-agent:(jn-abed:join:gc rid) t.t.t.t.wire sign) + jn-abet:(jn-agent:(jn-abed:join:gc rid) t.t.t.t.wire sign) == [cards this] :: @@ -75,20 +80,28 @@ :: :: ++ join - |_ [rid=resource =ship] + |_ [rid=resource =ship cards=(list card)] ++ jn-core . + ++ emit-many + |= crds=(list card) + jn-core(cards (weld (flop crds) cards)) + ++ emit + |= =card + jn-core(cards [card cards]) :: - ++ tx-fact + ++ tx-progress |= =progress:view + =. joining + (~(put by joining) rid [ship progress]) =; =cage - (fact:io cage /all tx+(en-path:resource rid) ~) + (emit (fact:io cage /all tx+(en-path:resource rid) ~)) group-view-update+!>([%progress rid progress]) :: ++ watch-md - (watch-our:(jn-pass-io /md) %metadata-store /updates) + (emit (watch-our:(jn-pass-io /md) %metadata-store /updates)) :: ++ watch-groups - (watch-our:(jn-pass-io /groups) %group-store /groups) + (emit (watch-our:(jn-pass-io /groups) %group-store /groups)) :: ++ jn-pass-io |= pax=path @@ -96,72 +109,69 @@ :: ++ jn-abed |= r=resource - =/ s=^ship + =/ [s=^ship =progress:view] (~(got by joining) r) jn-core(rid r, ship s) :: + ++ jn-abet + ^- (quip card _state) + [(flop cards) state] + :: ++ jn-start |= [rid=resource =^ship] - ^- (quip card _state) + ^+ jn-core ?< (~(has by joining) rid) =. joining - (~(put by joining) rid ship) + (~(put by joining) rid [ship %start]) =. jn-core (jn-abed rid) =/ maybe-group (peek-group:met %contacts rid) ?^ maybe-group ~|("already joined group {}" !!) - :_ state - :~ %+ poke:(jn-pass-io /add) - [ship %group-push-hook] - group-update+!>([%add-members rid (silt our.bowl ~)]) - :: - (tx-fact %start) - watch-md - watch-groups - == + =. jn-core + %- emit + %+ poke:(jn-pass-io /add) + [ship %group-push-hook] + group-update+!>([%add-members rid (silt our.bowl ~)]) + =. jn-core (tx-progress %start) + => watch-md + watch-groups :: ++ jn-agent |= [=wire =sign:agent:gall] - ^- (quip card _state) + ^+ jn-core |^ ?+ -.wire ~|("bad %join wire" !!) %add :: join group ?> ?=(%poke-ack -.sign) ?^ p.sign (cleanup %no-perms) - :_ state - :~ (tx-fact %added) + => %- emit %+ poke-our:(jn-pass-io /pull-groups) %group-pull-hook pull-hook-action+!>([%add ship rid]) - == + (tx-progress %added) :: %pull-groups ?> ?=(%poke-ack -.sign) - ?~ p.sign - :: do nothing, wait for update from store - `state - :: shouldn't ever fail - (cleanup %strange) + (ack +.sign) :: %groups ?+ -.sign !! %fact (groups-fact +.sign) %watch-ack (ack +.sign) - %kick groups-kick + %kick watch-groups == :: %pull-md ?> ?=(%poke-ack -.sign) - ?~ p.sign `state - (cleanup %strange) + (ack +.sign) :: %md ?+ -.sign !! %fact (md-fact +.sign) %watch-ack (ack +.sign) - %kick md-kick + %kick watch-md == :: %pull-graphs @@ -171,58 +181,46 @@ == ++ groups-fact |= =cage - ?. ?=(%group-update p.cage) - `state + ?. ?=(%group-update p.cage) jn-core =+ !<(=update:group-store q.cage) - ?. ?=(%initial-group -.update) - `state - ?. =(rid resource.update) - `state - :_ state - :_ ~ - %+ poke-our:(jn-pass-io /pull-md) %metadata-push-hook + ?. ?=(%initial-group -.update) jn-core + ?. =(rid resource.update) jn-core + %- emit + %+ poke-our:(jn-pass-io /pull-md) %metadata-pull-hook pull-hook-action+!>([%add [entity .]:rid]) :: ++ md-fact |= [=mark =vase] - ?. ?=(%metadata-update mark) `state + ?. ?=(%metadata-update mark) jn-core =+ !<(=update:metadata vase) - ?. ?=(%initial-group -.update) `state - ?. =(group.update rid) `state - =^ cards state - (cleanup %done) - :_ state - %+ welp cards - ?. hidden:(need (scry-group:grp rid)) ~ + ?. ?=(%initial-group -.update) jn-core + ?. =(group.update rid) jn-core + =. jn-core (cleanup %done) + ?. hidden:(need (scry-group:grp rid)) jn-core + %- emit-many %+ murn ~(tap by associations.update) |= [=md-resource:metadata =association:metadata] + ^- (unit card) ?. =(app-name.md-resource %graph) ~ =* rid resource.md-resource :- ~ %+ poke-our:(jn-pass-io /pull-graph) %graph-pull-hook pull-hook-action+!>([%add [entity .]:rid]) :: - ++ groups-kick - :_ state - watch-groups^~ - :: - ++ md-kick - :_ state - watch-md^~ - :: ++ ack |= err=(unit tang) - ?~ err `state + ?~ err jn-core + %- (slog u.err) (cleanup %strange) :: ++ cleanup |= =progress:view - ^- (quip card _state) - :_ state(joining (~(del by joining) rid)) - :~ (leave-our:(jn-pass-io /groups) %group-store) - (leave-our:(jn-pass-io /md) %metadata-store) - (tx-fact progress) - == + =. jn-core + (tx-progress progress) + =. joining (~(del by joining) rid) + =. jn-core + (emit (leave-our:(jn-pass-io /groups) %group-store)) + (emit (leave-our:(jn-pass-io /md) %metadata-store)) -- -- -- diff --git a/pkg/arvo/app/metadata-store.hoon b/pkg/arvo/app/metadata-store.hoon index fe8e8aa89..0f41e1695 100644 --- a/pkg/arvo/app/metadata-store.hoon +++ b/pkg/arvo/app/metadata-store.hoon @@ -353,7 +353,7 @@ ++ handle-add |= [group=resource =md-resource:store =metadatum:store] ^- (quip card _state) - :- %+ send-diff app-name.md-resource + :- %- send-diff [%add group md-resource metadatum] %= state associations @@ -374,7 +374,7 @@ ++ handle-remove |= [group=resource =md-resource:store] ^- (quip card _state) - :- (send-diff app-name.md-resource [%remove group md-resource]) + :- (send-diff [%remove group md-resource]) %= state associations (~(del by associations) md-resource) @@ -395,15 +395,15 @@ |= [group=resource =associations:store] =/ assocs=(list [=md-resource:store grp=resource =metadatum:store]) ~(tap by associations) - =| cards=(list card) + :- (send-diff %initial-group group associations) |- ?~ assocs - [cards state] + state =, assocs ?> =(group grp.i) - =^ new-cards state + =^ cards state (handle-add group [md-resource metadatum]:i) - $(cards (weld cards new-cards), assocs t) + $(assocs t) :: ++ metadata-for-app |= =app-name:store @@ -428,13 +428,12 @@ (~(put by out) md-resource [group metadatum]) :: ++ send-diff - |= [=app-name:store =update:store] + |= =update:store ^- (list card) |^ %- zing :~ (update-subscribers /all update) (update-subscribers /updates update) - (update-subscribers [%app-name app-name ~] update) == :: ++ update-subscribers diff --git a/pkg/arvo/lib/group-view.hoon b/pkg/arvo/lib/group-view.hoon index 2c73e5823..f3b1bf44b 100644 --- a/pkg/arvo/lib/group-view.hoon +++ b/pkg/arvo/lib/group-view.hoon @@ -15,7 +15,7 @@ ++ join %- ot :~ resource+dejs:resource - ship+ship + ship+(su ;~(pfix sig fed:ag)) == -- :: @@ -39,8 +39,11 @@ == :: ++ initial - |= resources=(set resource) - ^- json - a+(turn ~(tap in resources) (cork enjs-path:resource (lead %s))) + |= init=(map resource ^progress) + %- pairs + %+ turn ~(tap by init) + |= [rid=resource prog=^progress] + :_ s+prog + (enjs-path:resource rid) -- -- diff --git a/pkg/arvo/sur/group-view.hoon b/pkg/arvo/sur/group-view.hoon index be275136c..587430094 100644 --- a/pkg/arvo/sur/group-view.hoon +++ b/pkg/arvo/sur/group-view.hoon @@ -12,7 +12,7 @@ ?(%no-perms %strange %done) :: +$ update - $% [%initial =resources] + $% [%initial initial=(map resource progress)] [%progress =resource =progress] == -- From 4827dbccbbdbc66dffcfe41b9e3cbc0580d1699c Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 12:00:24 +1000 Subject: [PATCH 52/61] group-view: surface joining status in the interface --- pkg/interface/src/logic/api/groups.ts | 13 +++- pkg/interface/src/logic/api/metadata.ts | 2 +- .../src/logic/reducers/group-view.ts | 14 ++-- pkg/interface/src/logic/store/type.ts | 5 +- pkg/interface/src/types/group-view.ts | 11 ++++ pkg/interface/src/types/index.ts | 3 +- .../src/views/apps/notifications/inbox.tsx | 29 ++++++++- .../src/views/apps/notifications/joining.tsx | 49 ++++++++++++++ .../views/landscape/components/JoinGroup.tsx | 64 +++++++++++++------ 9 files changed, 154 insertions(+), 36 deletions(-) create mode 100644 pkg/interface/src/types/group-view.ts create mode 100644 pkg/interface/src/views/apps/notifications/joining.tsx diff --git a/pkg/interface/src/logic/api/groups.ts b/pkg/interface/src/logic/api/groups.ts index 3901149fd..8ceb83175 100644 --- a/pkg/interface/src/logic/api/groups.ts +++ b/pkg/interface/src/logic/api/groups.ts @@ -8,6 +8,7 @@ import { Tag, GroupPolicyDiff, } from '~/types/group-update'; +import {makeResource} from '../lib/group'; export default class GroupsApi extends BaseApi { remove(resource: Resource, ships: Patp[]) { @@ -34,12 +35,22 @@ export default class GroupsApi extends BaseApi { return this.proxyAction({ changePolicy: { resource, diff } }); } + join(ship: string, name: string) { + const resource = makeResource(ship, name); + + return this.viewAction({ join: { resource, ship }}); + } + private proxyAction(action: GroupAction) { return this.action('group-push-hook', 'group-update', action); } private storeAction(action: GroupAction) { - console.log(action); return this.action('group-store', 'group-update', action); } + + private viewAction(action: any) { + return this.action('group-view', 'group-view-action', action); + + } } diff --git a/pkg/interface/src/logic/api/metadata.ts b/pkg/interface/src/logic/api/metadata.ts index 464e2f205..b17e681d8 100644 --- a/pkg/interface/src/logic/api/metadata.ts +++ b/pkg/interface/src/logic/api/metadata.ts @@ -70,7 +70,7 @@ export default class MetadataApi extends BaseApi { done = true; tempChannel.delete(); reject(new Error("offline")) - }, 30000); + }, 15000); tempChannel.subscribe(window.ship, "metadata-pull-hook", `/preview${group}`, (err) => { diff --git a/pkg/interface/src/logic/reducers/group-view.ts b/pkg/interface/src/logic/reducers/group-view.ts index 3f5e536ad..92be7c0f5 100644 --- a/pkg/interface/src/logic/reducers/group-view.ts +++ b/pkg/interface/src/logic/reducers/group-view.ts @@ -4,19 +4,19 @@ import { resourceAsPath } from "~/logic/lib/util"; const initial = (json: any, state: any) => { const data = json.initial; if(data) { - state.pendingJoin = new Set(data); + state.pendingJoin = data; } } const progress = (json: any, state: any) => { const data = json.progress; if(data) { - const res = resourceAsPath(data.resource); - const { progress } = data; - if(progress === 'start') { - state.pendingJoin.add(res); - } else if (progress !== 'added') { - state.pendingJoin.delete(res); + const { progress, resource } = data; + state.pendingJoin = {...state.pendingJoin, [resource]: progress }; + if(progress === 'done') { + setTimeout(() => { + delete state.pendingJoin[resource]; + }, 10000); } } } diff --git a/pkg/interface/src/logic/store/type.ts b/pkg/interface/src/logic/store/type.ts index b1180ee02..d261a9385 100644 --- a/pkg/interface/src/logic/store/type.ts +++ b/pkg/interface/src/logic/store/type.ts @@ -11,7 +11,8 @@ import { Notifications, NotificationGraphConfig, GroupNotificationsConfig, - Unreads + Unreads, + JoinRequests } from "~/types"; export interface StoreState { @@ -46,5 +47,5 @@ export interface StoreState { notificationsCount: number, unreads: Unreads; doNotDisturb: boolean; - unreads: Unreads; + pendingJoin: JoinRequests; } diff --git a/pkg/interface/src/types/group-view.ts b/pkg/interface/src/types/group-view.ts new file mode 100644 index 000000000..635a2954a --- /dev/null +++ b/pkg/interface/src/types/group-view.ts @@ -0,0 +1,11 @@ +export const joinError = ['no-perms', 'strange'] as const; +export type JoinError = typeof joinError[number]; +export const joinResult = ['done', ...joinError] as const; +export type JoinResult = typeof joinResult[number]; + +export const joinProgress = ['start', 'added', ...joinResult] as const; +export type JoinProgress = typeof joinProgress[number]; + +export interface JoinRequests { + [rid: string]: JoinProgress; +} diff --git a/pkg/interface/src/types/index.ts b/pkg/interface/src/types/index.ts index 684763c57..549159261 100644 --- a/pkg/interface/src/types/index.ts +++ b/pkg/interface/src/types/index.ts @@ -1,10 +1,9 @@ export * from './cage'; -export * from './chat-hook-update'; -export * from './chat-update'; export * from './connection'; export * from './contact-update'; export * from './global'; export * from './group-update'; +export * from './group-view'; export * from './graph-update'; export * from './hark-update'; export * from './invite-update'; diff --git a/pkg/interface/src/views/apps/notifications/inbox.tsx b/pkg/interface/src/views/apps/notifications/inbox.tsx index bc1bdcd7e..0efffdcf1 100644 --- a/pkg/interface/src/views/apps/notifications/inbox.tsx +++ b/pkg/interface/src/views/apps/notifications/inbox.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useCallback, useState, useMemo } from "react"; import f from "lodash/fp"; import _ from "lodash"; -import { Icon, Col, Row, Box, Text, Anchor, Rule } from "@tlon/indigo-react"; +import { Icon, Col, Row, Box, Text, Anchor, Rule, SegmentedProgressBar } from "@tlon/indigo-react"; import moment from "moment"; -import { Notifications, Rolodex, Timebox, IndexedNotification, Groups } from "~/types"; -import { MOMENT_CALENDAR_DATE, daToUnix, resourceAsPath } from "~/logic/lib/util"; +import { Notifications, Rolodex, Timebox, IndexedNotification, Groups, joinProgress, JoinRequests } from "~/types"; +import { MOMENT_CALENDAR_DATE, daToUnix, resourceAsPath, clamp } from "~/logic/lib/util"; import { BigInteger } from "big-integer"; import GlobalApi from "~/logic/api/global"; import { Notification } from "./notification"; @@ -15,6 +15,7 @@ import { useWaitForProps } from "~/logic/lib/useWaitForProps"; import { useHistory } from "react-router-dom"; import {useModal} from "~/logic/lib/useModal"; import {JoinGroup} from "~/views/landscape/components/JoinGroup"; +import {JoiningStatus} from "./joining"; type DatedTimebox = [BigInteger, Timebox]; @@ -44,6 +45,7 @@ export default function Inbox(props: { contacts: Rolodex; filter: string[]; invites: any; + pendingJoin: JoinRequests; }) { const { api, associations, invites } = props; const waiter = useWaitForProps(props) @@ -164,10 +166,31 @@ export default function Inbox(props: { return returned; }; + const joinRequests = (requests) => { + if(Object.keys(requests).length === 0) { + return null; + } + return ( + + { Object + .keys(requests) + .map(resource => ( + + )) + } + + ); + }; + return ( {modal} + {joinRequests(props.pendingJoin)} {inviteItems(invites, api)} {[...notificationsByDay.keys()].map((day, index) => { diff --git a/pkg/interface/src/views/apps/notifications/joining.tsx b/pkg/interface/src/views/apps/notifications/joining.tsx new file mode 100644 index 000000000..d820c20b2 --- /dev/null +++ b/pkg/interface/src/views/apps/notifications/joining.tsx @@ -0,0 +1,49 @@ +import React, { useState, useEffect } from "react"; +import { Col, Text, SegmentedProgressBar } from "@tlon/indigo-react"; +import GlobalApi from "~/logic/api/global"; +import { JoinProgress, joinProgress, MetadataUpdatePreview, joinError } from "~/types"; +import { clamp } from "~/logic/lib/util"; + +interface JoiningStatusProps { + resource: string; + api: GlobalApi; + status: JoinProgress; +} + +const description: string[] = + ["Attempting to contact group host", + "Retrieving group data", + "Finished join", + "Unable to join group, you do not have the correct permissions", + "Internal error, please file an issue" + ]; + + + +export function JoiningStatus(props: JoiningStatusProps) { + const { resource, status, api } = props; + + const [preview, setPreview] = useState(null); + + useEffect(() => { + (async () => { + const prev = await api.metadata.preview(resource); + setPreview(prev) + })(); + return () => { + setPreview(null); + } + }, [resource]) + + const current = joinProgress.indexOf(status); + const desc = description?.[current] || ""; + const title = preview?.metadata?.title ?? resource; + const isError = joinError.indexOf(status as any) !== -1; + return ( + + {isError ? "Failed to join " : "Joining "} {title} + {desc} + + + ); +} diff --git a/pkg/interface/src/views/landscape/components/JoinGroup.tsx b/pkg/interface/src/views/landscape/components/JoinGroup.tsx index 904f30302..623ea4198 100644 --- a/pkg/interface/src/views/landscape/components/JoinGroup.tsx +++ b/pkg/interface/src/views/landscape/components/JoinGroup.tsx @@ -1,4 +1,5 @@ import React, { useState, useCallback, useEffect } from "react"; +import _ from 'lodash'; import { Body } from "~/views/components/Body"; import { Col, @@ -11,7 +12,7 @@ import { import { Formik, Form, FormikHelpers, useFormikContext } from "formik"; import { AsyncButton } from "~/views/components/AsyncButton"; import * as Yup from "yup"; -import { Groups, Rolodex } from "~/types"; +import { Groups, Rolodex, MetadataUpdatePreview, Associations } from "~/types"; import { useWaitForProps } from "~/logic/lib/useWaitForProps"; import GlobalApi from "~/logic/api/global"; import { RouteComponentProps, useHistory } from "react-router-dom"; @@ -42,6 +43,7 @@ interface FormSchema { interface JoinGroupProps { groups: Groups; contacts: Rolodex; + associations: Associations; api: GlobalApi; autojoin?: string; inviteUid?: string; @@ -60,38 +62,53 @@ function Autojoin(props: { autojoin: string | null }) { } export function JoinGroup(props: JoinGroupProps) { - const { api, autojoin } = props; + const { api, autojoin, associations, groups } = props; const history = useHistory(); const initialValues: FormSchema = { group: autojoin || "", }; + const [preview, setPreview] = useState< + MetadataUpdatePreview | string | null + >(null); - const waiter = useWaitForProps(props); - const [preview, setPreview] = useState(null); + + const waiter = useWaitForProps(props, _.isString(preview) ? 1 : 5000); const onConfirm = useCallback(async () => { - const { group } = preview; - await api.contacts.join(resourceFromPath(group)); + const group = _.isString(preview) ? preview : preview?.group!; + const [,,ship,name] = group.split('/'); + await api.groups.join(ship, name); if (props.inviteUid) { api.invite.accept("contacts", props.inviteUid); } - await waiter(({ contacts, groups }) => { - return group in contacts && group in groups; - }); - history.push(`/~landscape${group}`); - }, [api, preview, waiter]); + try { + await waiter((p: JoinGroupProps) => { + return group in p.groups && + (group in p.associations.graph + || group in p.associations.contacts) + }); + if(props.groups?.[group]?.hidden) { + const { metadata } = associations.graph[group]; + history.push(`/~landscape/home/resource/${metadata.module}${group}`); + return; + } else { + history.push(`/~landscape${group}`); + } + } catch (e) { + // drop them into inbox to show join request still pending + history.push('/~notifications'); + } + }, [api, preview, waiter, history, associations, groups]); const onSubmit = useCallback( async (values: FormSchema, actions: FormikHelpers) => { + const [ship, name] = values.group.split("/"); + const path = `/ship/${ship}/${name}`; try { - const [ship, name] = values.group.split("/"); - const path = `/ship/${ship}/${name}`; - const prev = await api.metadata.preview(path); actions.setStatus({ success: null }); setPreview(prev); } catch (e) { - console.log(e); if (!(e instanceof Error)) { actions.setStatus({ error: "Unknown error" }); } else if (e.message === "no-permissions") { @@ -100,9 +117,7 @@ export function JoinGroup(props: JoinGroupProps) { "Unable to join group, you do not have the correct permissions", }); } else if (e.message === "offline") { - actions.setStatus({ - error: "Group host is offline, please try again later", - }); + setPreview(path); } } }, @@ -117,13 +132,21 @@ export function JoinGroup(props: JoinGroupProps) { Join a Group - {preview ? ( + {_.isString(preview) ? ( + + The host appears to be offline. Join anyway? + + Join anyway + + + ) : preview ? ( - 0 && ( + ))} + )} Join {preview.metadata.title} From a6e145939598b4e1817bd7671f4aab97c459c492 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 13:25:00 +1000 Subject: [PATCH 53/61] group-view: add %create thread --- pkg/arvo/sur/group-view.hoon | 13 +++++++-- pkg/arvo/ted/group/create.hoon | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 pkg/arvo/ted/group/create.hoon diff --git a/pkg/arvo/sur/group-view.hoon b/pkg/arvo/sur/group-view.hoon index 587430094..940381eb5 100644 --- a/pkg/arvo/sur/group-view.hoon +++ b/pkg/arvo/sur/group-view.hoon @@ -1,9 +1,18 @@ -/- *resource +/- *resource, *group ^? |% :: +$ action - [%join =resource =ship] + $% :: host side + [%create name=term =policy title=@t description=@t] + [%remove =resource] + :: client side + [%join =resource =ship] + [%leave =resource] + :: + [%groupify =resource title=@t description=@t] + == + :: +$ progress ?(%start %added final) diff --git a/pkg/arvo/ted/group/create.hoon b/pkg/arvo/ted/group/create.hoon new file mode 100644 index 000000000..b379520c9 --- /dev/null +++ b/pkg/arvo/ted/group/create.hoon @@ -0,0 +1,50 @@ +/- spider, + metadata=metadata-store, + *group, + inv=invite-store, + store=group-store, + push-hook +/+ strandio, resource, view=group-view +=> +|% +++ strand strand:spider +++ poke poke:strandio +++ poke-our poke-our:strandio +-- +^- thread:spider +|= arg=vase +=/ m (strand ,vase) +^- form:m +=+ !<([~ =action:view] arg) +?> ?=(%create -.action) +?> ((sane %tas) name.action) +;< =bowl:spider bind:m get-bowl:strandio +:: Add graph to graph-store +:: +=/ rid=resource + [our.bowl name.action] +=/ group-act=action:store + [%add-group rid policy.action &] +;< ~ bind:m (poke-our %group-store %group-action !>(action)) +;< =bowl:spider bind:m get-bowl:strandio +;< ~ bind:m (poke-our %group-store %group-action !>([%add-members rid (sy our.bowl ~)])) +=/ push-hook-act=cage + :- %push-hook-action + !> ^- action:push-hook + [%add rid] +;< ~ bind:m + (poke-our %group-push-hook push-hook-act) +=/ =metadatum:metadata + %* . *metadatum:metadata + title title.action + description description.action + date-created now.bowl + creator our.bowl + == +=/ met-action=action:metadata + [%add rid groups+rid metadatum] +;< ~ bind:m (poke-our %metadata-store %metadata-action !>(met-action)) +;< ~ bind:m (poke-our %metadata-push-hook push-hook-act) +(pure:m !>(~)) + + From d5bfe028e8a425648a1af0a6f1dcf30707ed84de Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 13:43:40 +1000 Subject: [PATCH 54/61] group-view: add leave, delete threads --- pkg/arvo/lib/group-view.hoon | 22 ++++++++++++++-- pkg/arvo/ted/group/delete.hoon | 46 ++++++++++++++++++++++++++++++++++ pkg/arvo/ted/group/leave.hoon | 30 ++++++++++++++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 pkg/arvo/ted/group/delete.hoon create mode 100644 pkg/arvo/ted/group/leave.hoon diff --git a/pkg/arvo/lib/group-view.hoon b/pkg/arvo/lib/group-view.hoon index f3b1bf44b..9a5fb0fa7 100644 --- a/pkg/arvo/lib/group-view.hoon +++ b/pkg/arvo/lib/group-view.hoon @@ -1,5 +1,5 @@ -/- sur=group-view -/+ resource +/- sur=group-view, spider +/+ resource, strandio, metadata=metadata-store ^? =< [. sur] =, sur @@ -46,4 +46,22 @@ :_ s+prog (enjs-path:resource rid) -- +++ cleanup-md + |= rid=resource + =/ m (strand:spider ,~) + ^- form:m + ;< =associations:metadata bind:m + %+ scry:strandio associations:metadata + %+ weld /metadata-store/group + (snoc (en-path:resource rid) %noun) + =/ assocs=(list [=md-resource:metadata association:metadata]) + ~(tap by associations) + |- + =* loop $ + ?~ assocs + (pure:m ~) + ;< ~ bind:m + %+ poke-our:strandio %metadata-store + metadata-action+!>([%remove rid md-resource.i.assocs]) + loop(assocs t.assocs) -- diff --git a/pkg/arvo/ted/group/delete.hoon b/pkg/arvo/ted/group/delete.hoon new file mode 100644 index 000000000..3aec0f52a --- /dev/null +++ b/pkg/arvo/ted/group/delete.hoon @@ -0,0 +1,46 @@ +/- spider, + metadata=metadata-store, + *group, + inv=invite-store, + store=group-store, + push-hook +/+ strandio, resource, view=group-view +=> +|% +++ strand strand:spider +++ poke poke:strandio +++ poke-our poke-our:strandio +++ cleanup-md + |= rid=resouce + =/ m (strand ,~) + ^- form:m + ;< =associations:metadata bind:m + %+ scry:strandio associations:metadata + %+ weld /metadata-store/group + (snoc (en-path:resource rid) %noun) + =/ assocs=(list [=md-resource:metadata association:metadata]) + ~(tap by associations) + |- + =* loop $ + ?~ assocs + (pure:m ~) + ;< ~ bind:m + (poke-our %metadata-store metadata-action+!>([%remove rid md-resource.i.assocs])) + loop(assocs t.assocs) +-- +^- thread:spider +|= arg=vase +=/ m (strand ,vase) +=+ !<([~ =action:view] arg) +?> ?=(%remove -.action) +;< =bowl:spider bind:m get-bowl:strandio +?> =(our.bowl entity.resource.action) +=/ push-hook-act=cage + :- %push-hook-action + !> ^- action:push-hook + [%remove resource.action] +;< ~ bind:m (cleanup-md:view rid) +;< ~ bind:m (poke-our %group-store %group-update !>([%remove-group rid ~])) +;< ~ bind:m (poke-our %metadata-push-hook push-hook-act) +;< ~ bind:m (poke-our %group-push-hook push-hook-act) +(pure:m !>(~)) diff --git a/pkg/arvo/ted/group/leave.hoon b/pkg/arvo/ted/group/leave.hoon new file mode 100644 index 000000000..5e5834880 --- /dev/null +++ b/pkg/arvo/ted/group/leave.hoon @@ -0,0 +1,30 @@ +/- spider, + metadata=metadata-store, + *group, + inv=invite-store, + store=group-store, + pull-hook +/+ strandio, resource, view=group-view +=> +|% +++ strand strand:spider +++ poke poke:strandio +++ poke-our poke-our:strandio +-- +^- thread:spider +|= arg=vase +=/ m (strand ,vase) +=+ !<([~ =action:view] arg) +?> ?=(%leave -.action) +;< =bowl:spider bind:m get-bowl:strandio +?> =(our.bowl entity.resource.action) +=* rid resource.action +=/ pull-hook-act=cage + :- %pull-hook-action + !> ^- action:pull-hook + [%remove rid] +;< ~ bind:m (cleanup-md:view rid) +;< ~ bind:m (poke-our %group-store %group-update !>([%remove-group rid ~])) +;< ~ bind:m (poke-our %metadata-pull-hook pull-hook-act) +;< ~ bind:m (poke-our %group-pull-hook pull-hook-act) +(pure:m !>(~)) From e7b404ee4e3641000d28fa02917d3ec154dd5415 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 13:48:49 +1000 Subject: [PATCH 55/61] group-view: add JSON decoders for new actions --- pkg/arvo/lib/group-view.hoon | 20 ++++++++++++++++++-- pkg/arvo/sur/group-view.hoon | 2 -- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/lib/group-view.hoon b/pkg/arvo/lib/group-view.hoon index 9a5fb0fa7..51e9314c3 100644 --- a/pkg/arvo/lib/group-view.hoon +++ b/pkg/arvo/lib/group-view.hoon @@ -1,5 +1,5 @@ /- sur=group-view, spider -/+ resource, strandio, metadata=metadata-store +/+ resource, strandio, metadata=metadata-store, store=group-store ^? =< [. sur] =, sur @@ -8,10 +8,26 @@ =, dejs:format |% ++ action + ^- $-(json ^action) %- of - :~ join+join + :~ create+create + remove+remove + join+join + leave+leave == :: + ++ create + %- ot + :~ name+so + policy+policy:dejs:store + title+so + description+so + == + :: + ++ remove dejs:resource + :: + ++ leave dejs:resource + :: ++ join %- ot :~ resource+dejs:resource diff --git a/pkg/arvo/sur/group-view.hoon b/pkg/arvo/sur/group-view.hoon index 940381eb5..4ffbcfc8a 100644 --- a/pkg/arvo/sur/group-view.hoon +++ b/pkg/arvo/sur/group-view.hoon @@ -9,8 +9,6 @@ :: client side [%join =resource =ship] [%leave =resource] - :: - [%groupify =resource title=@t description=@t] == :: From 2730eb6c09cd73b7bd7daea15c25d4cfcc71fc73 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 14:07:39 +1000 Subject: [PATCH 56/61] graph-view: refactor threads to call into %group-view --- pkg/arvo/ted/graph/create.hoon | 25 +++++-------- pkg/arvo/ted/graph/delete.hoon | 15 +++----- pkg/arvo/ted/graph/join.hoon | 66 +++------------------------------- pkg/arvo/ted/graph/leave.hoon | 24 +++---------- 4 files changed, 23 insertions(+), 107 deletions(-) diff --git a/pkg/arvo/ted/graph/create.hoon b/pkg/arvo/ted/graph/create.hoon index a883d822c..64cff6555 100644 --- a/pkg/arvo/ted/graph/create.hoon +++ b/pkg/arvo/ted/graph/create.hoon @@ -1,6 +1,6 @@ /- spider, graph=graph-store, - *metadata-store, + metadata=metadata-store, *group, group-store, inv=invite-store @@ -16,13 +16,8 @@ =/ m (strand ,resource) ?: ?=(%group -.associated) (pure:m rid.associated) - =/ =action:group-store - [%add-group rid policy.associated %&] - ;< ~ bind:m (poke-our %group-store %group-action !>(action)) - ;< =bowl:spider bind:m get-bowl:strandio - ;< ~ bind:m (poke-our %group-store %group-action !>([%add-members rid (sy our.bowl ~)])) - ;< ~ bind:m - (poke-our %group-push-hook %push-hook-action !>([%add rid])) + ;< ~ bind:m + (poke-our %metadata-push-hook %push-hook-action !>([%add rid])) (pure:m rid) -- :: @@ -52,25 +47,21 @@ :: ;< group=resource bind:m (handle-group rid.action associated.action) -=/ group-path=path - (en-path:resource group) :: :: Setup metadata :: -=/ =metadata - %* . *metadata +=/ =metadatum:metadata + %* . *metadatum:metadata title title.action description description.action date-created now.bowl creator our.bowl module module.action == -=/ =metadata-action - [%add group graph+rid.action metadata] +=/ met-action=action:metadata + [%add group graph+rid.action metadatum] ;< ~ bind:m - (poke-our %metadata-store %metadata-action !>(metadata-action)) -;< ~ bind:m - (poke-our %metadata-push-hook %push-hook-action !>([%add group])) + (poke-our %metadata-push-hook metadata-update+!>(met-action)) :: :: Send invites :: diff --git a/pkg/arvo/ted/graph/delete.hoon b/pkg/arvo/ted/graph/delete.hoon index f98ddf075..29daa734f 100644 --- a/pkg/arvo/ted/graph/delete.hoon +++ b/pkg/arvo/ted/graph/delete.hoon @@ -64,16 +64,11 @@ ?~ ugroup-rid !! ;< =group bind:m (scry-group u.ugroup-rid) +;< ~ bind:m + (delete-graph u.ugroup-rid rid.action) ?. hidden.group - ;< ~ bind:m - (delete-graph u.ugroup-rid rid.action) (pure:m !>(~)) -;< ~ bind:m - (poke-our %group-store %group-action !>([%remove-group rid.action ~])) -;< ~ bind:m - (poke-our %group-push-hook %push-hook-action !>([%remove rid.action])) -;< ~ bind:m (delete-graph u.ugroup-rid rid.action) -;< ~ bind:m - %+ poke-our %metadata-hook - metadata-hook-action+!>([%remove (en-path:resource u.ugroup-rid)]) +;< =thread-result:strandio bind:m + (await-thread:strandio %group-delete !>([%delete rid.action])) (pure:m !>(~)) + diff --git a/pkg/arvo/ted/graph/join.hoon b/pkg/arvo/ted/graph/join.hoon index 96f3677db..c68d25978 100644 --- a/pkg/arvo/ted/graph/join.hoon +++ b/pkg/arvo/ted/graph/join.hoon @@ -19,42 +19,6 @@ /noun == (pure:m res) - :: -++ wait-for-group-join - |= rid=resource - =/ m (strand ,~) - ^- form:m - =/ pax - (en-path:resource rid) - =/ hold=@dr ~s0..8000 - |- ^- form:m - ?> (lte hold ~m5) - =* loop $ - ;< u-group=(unit group) bind:m - (scry:strandio ,(unit group) (weld /gx/group-store/groups (snoc pax %noun))) - ?^ u-group - (pure:m ~) - ;< ~ bind:m (sleep:strandio hold) - =. hold (mul hold 2) - loop -:: -++ wait-for-md - |= rid=resource - =/ m (strand ,~) - ^- form:m - =/ pax - (en-path:resource rid) - =/ hold=@dr ~s0..8000 - |- ^- form:m - ?> (lte hold ~m5) - =* loop $ - ;< groups=(jug path md-resource) bind:m - (scry:strandio ,(jug path md-resource) /gy/metadata-store/group-indices) - ?: (~(has by groups) pax) - (pure:m ~) - ;< ~ bind:m (sleep:strandio hold) - =. hold (mul hold 2) - loop -- :: ^- thread:spider @@ -67,30 +31,10 @@ ?: =(our.bowl entity.rid.action) (fail %bad-request ~) ;< group=(unit resource) bind:m (scry-metadata rid.action) -?^ group - :: We have group, graph is managed - ;< ~ bind:m - %+ poke-our %graph-pull-hook - pull-hook-action+!>([%add ship.action rid.action]) - (pure:m !>(~)) -:: Else, add group then join +?> ?=(^ group) +:: We have group, graph is managed ;< ~ bind:m - %+ (map-err:strandio ,~) |=(* [%forbidden ~]) - %+ poke - [ship.action %group-push-hook] - group-update+!>([%add-members rid.action (sy our.bowl ~)]) -:: -;< ~ bind:m - %+ poke-our %group-pull-hook - pull-hook-action+!>([%add ship.action rid.action]) -;< ~ bind:m (wait-for-group-join rid.action) -:: -;< ~ bind:m - %+ poke-our %metadata-pull-hook - pull-hook-action+!>([%add ship.action rid.action]):: -;< ~ bind:m (wait-for-md rid.action) -:: -;< ~ bind:m - %+ poke-our %graph-pull-hook - pull-hook-action+!>([%add ship.action rid.action]) + %+ poke-our %graph-pull-hook + pull-hook-action+!>([%add ship.action rid.action]) (pure:m !>(~)) + diff --git a/pkg/arvo/ted/graph/leave.hoon b/pkg/arvo/ted/graph/leave.hoon index 131d1f8eb..001955a26 100644 --- a/pkg/arvo/ted/graph/leave.hoon +++ b/pkg/arvo/ted/graph/leave.hoon @@ -10,16 +10,14 @@ |= rid=resource =/ m (strand ,resource) ^- form:m - ;< pax=(unit (set path)) bind:m - %+ scry:strandio ,(unit (set path)) + ;< group=(unit resource) bind:m + %+ scry:strandio ,(unit resource) ;: weld /gx/metadata-store/resource/graph (en-path:resource rid) /noun == - ?> ?=(^ pax) - ?> ?=(^ u.pax) - (pure:m (de-path:resource n.u.pax)) + (pure:m (need group)) :: ++ scry-group |= rid=resource @@ -59,18 +57,6 @@ ?. hidden.g ;< ~ bind:m (delete-graph now.bowl rid.action) (pure:m !>(~)) -;< ~ bind:m - %+ poke-our %metadata-hook - metadata-hook-action+!>([%remove (en-path:resource rid.action)]) -;< ~ bind:m - %+ poke-our %metadata-store - :- %metadata-action - !> :+ %remove - (en-path:resource rid.action) - [%graph (en-path:resource rid.action)] -;< ~ bind:m - (poke-our %group-store %group-action !>([%remove-group rid.action ~])) -;< ~ bind:m - (poke-our %group-pull-hook %pull-hook-action !>([%remove rid.action])) -;< ~ bind:m (delete-graph now.bowl rid.action) +;< =thread-result:strandio bind:m + (await-thread:strandio %group-leave !>([%leave rid.action])) (pure:m !>(~)) From e6d66b205a8cec4d65a0ef1082cb9b545433ae64 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 16:27:38 +1000 Subject: [PATCH 57/61] group,graph-view: fixup calling convention for awaiting threads --- pkg/arvo/app/group-view.hoon | 1 + pkg/arvo/app/metadata-push-hook.hoon | 4 +++- pkg/arvo/lib/group-view.hoon | 3 ++- pkg/arvo/lib/metadata-store.hoon | 13 +++++++++++- pkg/arvo/ted/graph/create.hoon | 20 +++++++++++++++++-- pkg/arvo/ted/graph/delete.hoon | 30 ++++++++++++---------------- pkg/arvo/ted/graph/leave.hoon | 4 ++-- pkg/arvo/ted/group/delete.hoon | 20 ++----------------- pkg/arvo/ted/group/leave.hoon | 5 ++--- 9 files changed, 55 insertions(+), 45 deletions(-) diff --git a/pkg/arvo/app/group-view.hoon b/pkg/arvo/app/group-view.hoon index cdb17577c..0ae264ba0 100644 --- a/pkg/arvo/app/group-view.hoon +++ b/pkg/arvo/app/group-view.hoon @@ -36,6 +36,7 @@ ?. ?=(?(%group-view-action %noun) mark) (on-poke:def mark vase) =+ !<(=action:view vase) + ?> ?=(%join -.action) =^ cards state jn-abet:(jn-start:join:gc +.action) [cards this] diff --git a/pkg/arvo/app/metadata-push-hook.hoon b/pkg/arvo/app/metadata-push-hook.hoon index fee4b9b93..daa5f7a8e 100644 --- a/pkg/arvo/app/metadata-push-hook.hoon +++ b/pkg/arvo/app/metadata-push-hook.hoon @@ -49,7 +49,9 @@ =/ members ~(wyt in (members:grp rid)) =/ =metadatum:store - (need (peek-metadatum:met %contacts rid)) + %- need + %+ mate (peek-metadatum:met %contacts rid) + (peek-metadatum:met %graph rid) :_ this =; =cage [%pass / %agent [src.bowl %metadata-pull-hook] %poke cage]~ diff --git a/pkg/arvo/lib/group-view.hoon b/pkg/arvo/lib/group-view.hoon index 51e9314c3..483b97a86 100644 --- a/pkg/arvo/lib/group-view.hoon +++ b/pkg/arvo/lib/group-view.hoon @@ -68,8 +68,9 @@ ^- form:m ;< =associations:metadata bind:m %+ scry:strandio associations:metadata - %+ weld /metadata-store/group + %+ weld /gx/metadata-store/group (snoc (en-path:resource rid) %noun) + ~& associations =/ assocs=(list [=md-resource:metadata association:metadata]) ~(tap by associations) |- diff --git a/pkg/arvo/lib/metadata-store.hoon b/pkg/arvo/lib/metadata-store.hoon index 7288a7582..ec57f7d42 100644 --- a/pkg/arvo/lib/metadata-store.hoon +++ b/pkg/arvo/lib/metadata-store.hoon @@ -7,6 +7,14 @@ ++ enjs =, enjs:format |% + :: + ++ initial-group + |= [group=resource assocs=^associations] + %- pairs + :~ group+s+(enjs-path:resource group) + associations+(associations assocs) + == + :: ++ associations |= =^associations =, enjs:format @@ -49,7 +57,7 @@ ^- json %+ frond %metadata-update %- pairs - :~ ?+ -.upd *[cord json] + :~ ?- -.upd %add :- %add %- pairs @@ -77,6 +85,9 @@ :: %associations [%associations (associations associations.upd)] + :: + %initial-group + [%initial-group (initial-group +.upd)] :: == == :: diff --git a/pkg/arvo/ted/graph/create.hoon b/pkg/arvo/ted/graph/create.hoon index 64cff6555..96f1d5ec6 100644 --- a/pkg/arvo/ted/graph/create.hoon +++ b/pkg/arvo/ted/graph/create.hoon @@ -3,7 +3,8 @@ metadata=metadata-store, *group, group-store, - inv=invite-store + inv=invite-store, + push-hook /+ strandio, resource, graph-view => |% @@ -16,8 +17,22 @@ =/ m (strand ,resource) ?: ?=(%group -.associated) (pure:m rid.associated) + =/ push-hook-act=cage + :- %push-hook-action + !> ^- action:push-hook + [%add rid] ;< ~ bind:m - (poke-our %metadata-push-hook %push-hook-action !>([%add rid])) + (poke-our %metadata-push-hook push-hook-act) + ;< ~ bind:m + %+ poke-our %group-store + :- %group-update + !> ^- update:group-store + [%add-group rid policy.associated %.y] + ;< =bowl:spider bind:m get-bowl:strandio + ;< ~ bind:m + (poke-our %group-store group-update+!>([%add-members rid (sy our.bowl ~)])) + ;< ~ bind:m + (poke-our %group-push-hook push-hook-act) (pure:m rid) -- :: @@ -57,6 +72,7 @@ date-created now.bowl creator our.bowl module module.action + preview %.n == =/ met-action=action:metadata [%add group graph+rid.action metadatum] diff --git a/pkg/arvo/ted/graph/delete.hoon b/pkg/arvo/ted/graph/delete.hoon index 29daa734f..cc3bdcdbd 100644 --- a/pkg/arvo/ted/graph/delete.hoon +++ b/pkg/arvo/ted/graph/delete.hoon @@ -1,4 +1,4 @@ -/- spider, graph-view, graph=graph-store, *metadata-store, *group +/- spider, graph-view, graph=graph-store, metadata=metadata-store, *group /+ strandio, resource => |% @@ -8,17 +8,15 @@ :: ++ scry-metadata |= rid=resource - =/ m (strand ,(unit resource)) - ;< paxs=(unit (set path)) bind:m - %+ scry:strandio ,(unit (set path)) + =/ m (strand ,resource) + ;< group=(unit resource) bind:m + %+ scry:strandio ,(unit resource) ;: weld /gx/metadata-store/resource/graph (en-path:resource rid) /noun == - ?~ paxs (pure:m ~) - ?~ u.paxs (pure:m ~) - (pure:m `(de-path:resource n.u.paxs)) + (pure:m (need group)) :: ++ scry-group |= rid=resource @@ -42,11 +40,10 @@ ;< ~ bind:m (poke-our %graph-push-hook %push-hook-action !>([%remove rid])) ;< ~ bind:m - %+ poke-our %metadata-hook - :- %metadata-action - !> :+ %remove - (en-path:resource group-rid) - [%graph (en-path:resource rid)] + %+ poke-our %metadata-push-hook + :- %metadata-update + !> ^- action:metadata + [%remove group-rid [%graph rid]] (pure:m ~) -- :: @@ -59,16 +56,15 @@ ;< =bowl:spider bind:m get-bowl:strandio ?. =(our.bowl entity.rid.action) (strand-fail:strandio %bad-request ~) -;< ugroup-rid=(unit resource) bind:m +;< group-rid=resource bind:m (scry-metadata rid.action) -?~ ugroup-rid !! ;< =group bind:m - (scry-group u.ugroup-rid) + (scry-group group-rid) ;< ~ bind:m - (delete-graph u.ugroup-rid rid.action) + (delete-graph group-rid rid.action) ?. hidden.group (pure:m !>(~)) ;< =thread-result:strandio bind:m - (await-thread:strandio %group-delete !>([%delete rid.action])) + (await-thread:strandio %group-delete !>(`[%remove rid.action])) (pure:m !>(~)) diff --git a/pkg/arvo/ted/graph/leave.hoon b/pkg/arvo/ted/graph/leave.hoon index 001955a26..1ff9a915f 100644 --- a/pkg/arvo/ted/graph/leave.hoon +++ b/pkg/arvo/ted/graph/leave.hoon @@ -54,9 +54,9 @@ (strand-fail:strandio %bad-request ~) ;< group-rid=resource bind:m (scry-metadata rid.action) ;< g=group bind:m (scry-group group-rid) +;< ~ bind:m (delete-graph now.bowl rid.action) ?. hidden.g - ;< ~ bind:m (delete-graph now.bowl rid.action) (pure:m !>(~)) ;< =thread-result:strandio bind:m - (await-thread:strandio %group-leave !>([%leave rid.action])) + (await-thread:strandio %group-leave !>([~ [%leave rid.action]])) (pure:m !>(~)) diff --git a/pkg/arvo/ted/group/delete.hoon b/pkg/arvo/ted/group/delete.hoon index 3aec0f52a..3c9d1e924 100644 --- a/pkg/arvo/ted/group/delete.hoon +++ b/pkg/arvo/ted/group/delete.hoon @@ -10,31 +10,15 @@ ++ strand strand:spider ++ poke poke:strandio ++ poke-our poke-our:strandio -++ cleanup-md - |= rid=resouce - =/ m (strand ,~) - ^- form:m - ;< =associations:metadata bind:m - %+ scry:strandio associations:metadata - %+ weld /metadata-store/group - (snoc (en-path:resource rid) %noun) - =/ assocs=(list [=md-resource:metadata association:metadata]) - ~(tap by associations) - |- - =* loop $ - ?~ assocs - (pure:m ~) - ;< ~ bind:m - (poke-our %metadata-store metadata-action+!>([%remove rid md-resource.i.assocs])) - loop(assocs t.assocs) -- ^- thread:spider |= arg=vase =/ m (strand ,vase) =+ !<([~ =action:view] arg) ?> ?=(%remove -.action) +=* rid resource.action ;< =bowl:spider bind:m get-bowl:strandio -?> =(our.bowl entity.resource.action) +?> =(our.bowl entity.rid) =/ push-hook-act=cage :- %push-hook-action !> ^- action:push-hook diff --git a/pkg/arvo/ted/group/leave.hoon b/pkg/arvo/ted/group/leave.hoon index 5e5834880..ec4da0555 100644 --- a/pkg/arvo/ted/group/leave.hoon +++ b/pkg/arvo/ted/group/leave.hoon @@ -17,14 +17,13 @@ =+ !<([~ =action:view] arg) ?> ?=(%leave -.action) ;< =bowl:spider bind:m get-bowl:strandio -?> =(our.bowl entity.resource.action) =* rid resource.action =/ pull-hook-act=cage :- %pull-hook-action !> ^- action:pull-hook [%remove rid] -;< ~ bind:m (cleanup-md:view rid) -;< ~ bind:m (poke-our %group-store %group-update !>([%remove-group rid ~])) ;< ~ bind:m (poke-our %metadata-pull-hook pull-hook-act) ;< ~ bind:m (poke-our %group-pull-hook pull-hook-act) +;< ~ bind:m (poke-our %group-store %group-update !>([%remove-group rid ~])) +;< ~ bind:m (cleanup-md:view rid) (pure:m !>(~)) From b95d2b3848697c734b8fcdc4df06a3da5904c42d Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 16:28:43 +1000 Subject: [PATCH 58/61] inbox: fix invite dismissal on join --- .../src/logic/reducers/metadata-update.ts | 9 +++ pkg/interface/src/logic/store/store.ts | 3 +- .../src/views/apps/notifications/inbox.tsx | 73 +------------------ .../src/views/apps/notifications/invites.tsx | 42 ++++++----- .../views/landscape/components/JoinGroup.tsx | 12 +-- 5 files changed, 43 insertions(+), 96 deletions(-) diff --git a/pkg/interface/src/logic/reducers/metadata-update.ts b/pkg/interface/src/logic/reducers/metadata-update.ts index cc639a856..00070b87e 100644 --- a/pkg/interface/src/logic/reducers/metadata-update.ts +++ b/pkg/interface/src/logic/reducers/metadata-update.ts @@ -16,6 +16,15 @@ export default class MetadataReducer { this.add(data, state); this.update(data, state); this.remove(data, state); + this.groupInitial(data, state); + } + } + + groupInitial(json: MetadataUpdate, state: S) { + const data = _.get(json, 'initial-group', false); + console.log(data); + if(data) { + this.associations(data, state); } } diff --git a/pkg/interface/src/logic/store/store.ts b/pkg/interface/src/logic/store/store.ts index ff492677c..0d50e246c 100644 --- a/pkg/interface/src/logic/store/store.ts +++ b/pkg/interface/src/logic/store/store.ts @@ -94,7 +94,8 @@ export default class GlobalStore extends BaseStore { group: {} }, notificationsCount: 0, - settings: {} + settings: {}, + pendingJoin: {}, }; } diff --git a/pkg/interface/src/views/apps/notifications/inbox.tsx b/pkg/interface/src/views/apps/notifications/inbox.tsx index c0aff3143..8d3258a96 100644 --- a/pkg/interface/src/views/apps/notifications/inbox.tsx +++ b/pkg/interface/src/views/apps/notifications/inbox.tsx @@ -100,76 +100,6 @@ export default function Inbox(props: { const scrollRef = useRef(null); - const [joining, setJoining] = useState<[string, string] | null>(null); - - const { modal, showModal } = useModal( - { modal: useCallback( - (dismiss) => ( - - ), - [props.contacts, props.groups, props.api, joining] - )}) - - const joinGroup = useCallback((group: string, uid: string) => { - setJoining([group, uid]); - showModal(); - }, [setJoining, showModal]); - - const acceptInvite = (app: string, uid: string) => async (invite) => { - const resource = { - ship: `~${invite.resource.ship}`, - name: invite.resource.name - }; - - const resourcePath = resourceAsPath(invite.resource); - if(app === 'contacts') { - joinGroup(resourcePath, uid); - } else if ( app === 'chat') { - await api.invite.accept(app, uid); - history.push(`/~landscape/home/resource/chat${resourcePath.slice(5)}`); - } else if ( app === 'graph') { - await api.invite.accept(app, uid); - history.push(`/~graph/join${resourcePath}`); - } - }; - - - - - const inviteItems = (invites, api) => { - const returned = []; - Object.keys(invites).map((appKey) => { - const app = invites[appKey]; - Object.keys(app).map((uid) => { - const invite = app[uid]; - const inviteItem = - api.invite.decline(appKey, uid)} - />; - returned.push(inviteItem); - }); - }); - return returned; - }; - - const joinRequests = (requests) => { - if(Object.keys(requests).length === 0) { - return null; - } - return ( - - - ); - }; const loadMore = useCallback(async () => { return api.hark.getMore(); }, [api]); @@ -179,8 +109,7 @@ export default function Inbox(props: { return ( - {modal} - + {[...notificationsByDayMap.keys()].sort().reverse().map((day, index) => { const timeboxes = notificationsByDayMap.get(day)!; return timeboxes.length > 0 && ( diff --git a/pkg/interface/src/views/apps/notifications/invites.tsx b/pkg/interface/src/views/apps/notifications/invites.tsx index 82681d730..b7c772524 100644 --- a/pkg/interface/src/views/apps/notifications/invites.tsx +++ b/pkg/interface/src/views/apps/notifications/invites.tsx @@ -1,22 +1,26 @@ -import React, { useCallback } from "react"; +import React, { useCallback, useState } from "react"; import { Box, Row, Col } from "@tlon/indigo-react"; import GlobalApi from "~/logic/api/global"; -import { Invites as IInvites, Associations, Invite, JoinRequests } from "~/types"; +import { Invites as IInvites, Associations, Invite, JoinRequests, Groups } from "~/types"; import { resourceAsPath } from "~/logic/lib/util"; import { useHistory } from "react-router-dom"; import { useWaitForProps } from "~/logic/lib/useWaitForProps"; import InviteItem from "~/views/components/Invite"; import {JoiningStatus} from "./joining"; +import {useModal} from "~/logic/lib/useModal"; +import {JoinGroup} from "~/views/landscape/components/JoinGroup"; interface InvitesProps { api: GlobalApi; invites: IInvites; + groups: Groups; associations: Associations; pendingJoin: JoinRequests; } export function Invites(props: InvitesProps) { const { api, invites, pendingJoin } = props; + const [selected, setSelected] = useState<[string, string, Invite] | undefined>() const history = useHistory(); const waiter = useWaitForProps(props); @@ -25,21 +29,8 @@ export function Invites(props: InvitesProps) { uid: string, invite: Invite ) => async () => { - const resource = { - ship: `~${invite.resource.ship}`, - name: invite.resource.name, - }; - - const resourcePath = resourceAsPath(invite.resource); - if (app === "contacts") { - await api.contacts.join(resource); - await waiter((p) => resourcePath in p.associations?.contacts); - await api.invite.accept(app, uid); - history.push(`/~landscape${resourcePath}`); - } else if (app === "graph") { - await api.invite.accept(app, uid); - history.push(`/~graph/join${resourcePath}`); - } + setSelected([app, uid, invite]); + showModal(); }; const declineInvite = useCallback( @@ -47,6 +38,22 @@ export function Invites(props: InvitesProps) { [api] ); + const { modal, showModal } = useModal({ modal: () => { + const [app, uid, invite] = selected!; + const autojoin = `~${invite.resource.ship}/${invite.resource.name}`; + return ( + + )}}); + + + return ( + {modal} { Object .keys(props.pendingJoin) .map(resource => ( diff --git a/pkg/interface/src/views/landscape/components/JoinGroup.tsx b/pkg/interface/src/views/landscape/components/JoinGroup.tsx index 623ea4198..cef007956 100644 --- a/pkg/interface/src/views/landscape/components/JoinGroup.tsx +++ b/pkg/interface/src/views/landscape/components/JoinGroup.tsx @@ -42,11 +42,11 @@ interface FormSchema { interface JoinGroupProps { groups: Groups; - contacts: Rolodex; associations: Associations; api: GlobalApi; autojoin?: string; inviteUid?: string; + inviteApp?: string; } function Autojoin(props: { autojoin: string | null }) { @@ -78,14 +78,14 @@ export function JoinGroup(props: JoinGroupProps) { const group = _.isString(preview) ? preview : preview?.group!; const [,,ship,name] = group.split('/'); await api.groups.join(ship, name); - if (props.inviteUid) { - api.invite.accept("contacts", props.inviteUid); + if (props.inviteUid && props.inviteApp) { + api.invite.accept(props.inviteApp, props.inviteUid); } try { await waiter((p: JoinGroupProps) => { return group in p.groups && - (group in p.associations.graph - || group in p.associations.contacts) + (group in (p.associations?.graph ?? {}) + || group in (p.associations?.contacts ?? {})) }); if(props.groups?.[group]?.hidden) { const { metadata } = associations.graph[group]; @@ -181,7 +181,7 @@ export function JoinGroup(props: JoinGroupProps) { onSubmit={onSubmit} >
- + Date: Mon, 1 Feb 2021 17:54:37 +1000 Subject: [PATCH 59/61] metadata, groups: update for %groups metadata --- pkg/arvo/app/group-view.hoon | 2 +- pkg/arvo/app/metadata-pull-hook.hoon | 1 - pkg/arvo/app/metadata-push-hook.hoon | 2 +- pkg/arvo/lib/metadata-store.hoon | 2 +- pkg/arvo/lib/push-hook.hoon | 27 ++++++++++++++------------- pkg/arvo/ted/group/create.hoon | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pkg/arvo/app/group-view.hoon b/pkg/arvo/app/group-view.hoon index 0ae264ba0..2cebb3eb5 100644 --- a/pkg/arvo/app/group-view.hoon +++ b/pkg/arvo/app/group-view.hoon @@ -127,7 +127,7 @@ =. jn-core (jn-abed rid) =/ maybe-group - (peek-group:met %contacts rid) + (peek-group:met %groups rid) ?^ maybe-group ~|("already joined group {}" !!) =. jn-core diff --git a/pkg/arvo/app/metadata-pull-hook.hoon b/pkg/arvo/app/metadata-pull-hook.hoon index 8098fb49c..227a84dbf 100644 --- a/pkg/arvo/app/metadata-pull-hook.hoon +++ b/pkg/arvo/app/metadata-pull-hook.hoon @@ -55,7 +55,6 @@ =+ !<(=update:invite-store q.cage.sign) :_ state ?. ?=(%invite -.update) ~ - ?. =(%contacts term.update) ~ (get-preview resource.invite.update)^~ :: %kick [watch-invites^~ state] diff --git a/pkg/arvo/app/metadata-push-hook.hoon b/pkg/arvo/app/metadata-push-hook.hoon index daa5f7a8e..63a726c49 100644 --- a/pkg/arvo/app/metadata-push-hook.hoon +++ b/pkg/arvo/app/metadata-push-hook.hoon @@ -50,7 +50,7 @@ ~(wyt in (members:grp rid)) =/ =metadatum:store %- need - %+ mate (peek-metadatum:met %contacts rid) + %+ mate (peek-metadatum:met %groups rid) (peek-metadatum:met %graph rid) :_ this =; =cage diff --git a/pkg/arvo/lib/metadata-store.hoon b/pkg/arvo/lib/metadata-store.hoon index ec57f7d42..72ff4b6d6 100644 --- a/pkg/arvo/lib/metadata-store.hoon +++ b/pkg/arvo/lib/metadata-store.hoon @@ -121,7 +121,7 @@ :: ++ initial-group |= json - [%initial-group *resource *associations] + [*resource *associations] :: ++ add %- ot diff --git a/pkg/arvo/lib/push-hook.hoon b/pkg/arvo/lib/push-hook.hoon index 7a77e0736..b36fc5284 100644 --- a/pkg/arvo/lib/push-hook.hoon +++ b/pkg/arvo/lib/push-hook.hoon @@ -386,18 +386,17 @@ [%give %fact paths update-mark.config vase]~ :: ++ forward-update - |= =vase + |= update=vase ^- (list card:agent:gall) - =/ rid=(unit resource) - (resource-for-update vase) - ?~ rid ~ + =/ rid=resource + (need (resource-for-update update)) =/ =path - resource+(en-path:resource u.rid) + resource+(en-path:resource rid) =/ =wire - (make-wire resource+(en-path:resource u.rid)) + (make-wire resource+(en-path:resource rid)) =/ dap=term - ?:(=(our.bowl entity.u.rid) store-name.config dap.bowl) - [%pass wire %agent [entity.u.rid dap] %poke update-mark.config vase]~ + ?:(=(our.bowl entity.rid) store-name.config dap.bowl) + [%pass wire %agent [entity.rid dap] %poke update-mark.config update]~ :: ++ get-conversion .^ tube:clay @@ -407,11 +406,13 @@ :: ++ resource-for-update |= update=vase - =/ =tube:clay - get-conversion - %+ bind - (mole |.((tube update))) - |=(=vase !<(resource vase)) + ^- (unit resource) + =/ converted=(each vase (list tank)) + (mule |.((get-conversion update))) + ?: ?=(%| -.converted) + %- (slog p.converted) + ~ + [~ !<(resource p.converted)] :: ++ build-mark |= rav=?(%sing %next) diff --git a/pkg/arvo/ted/group/create.hoon b/pkg/arvo/ted/group/create.hoon index b379520c9..4185eeb38 100644 --- a/pkg/arvo/ted/group/create.hoon +++ b/pkg/arvo/ted/group/create.hoon @@ -24,8 +24,8 @@ =/ rid=resource [our.bowl name.action] =/ group-act=action:store - [%add-group rid policy.action &] -;< ~ bind:m (poke-our %group-store %group-action !>(action)) + [%add-group rid policy.action %.n] +;< ~ bind:m (poke-our %group-store %group-action !>(group-act)) ;< =bowl:spider bind:m get-bowl:strandio ;< ~ bind:m (poke-our %group-store %group-action !>([%add-members rid (sy our.bowl ~)])) =/ push-hook-act=cage From 988515aefaceaabb061d82f65d097747df7524a3 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 18:08:42 +1000 Subject: [PATCH 60/61] group-view: update interface to use threads --- pkg/interface/src/logic/api/groups.ts | 30 ++++++++++++++++ .../landscape/components/DeleteGroup.tsx | 35 +++++++++++-------- .../views/landscape/components/GroupsPane.tsx | 2 +- .../views/landscape/components/NewGroup.tsx | 6 ++-- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/pkg/interface/src/logic/api/groups.ts b/pkg/interface/src/logic/api/groups.ts index 8ceb83175..4e5182abe 100644 --- a/pkg/interface/src/logic/api/groups.ts +++ b/pkg/interface/src/logic/api/groups.ts @@ -41,6 +41,32 @@ export default class GroupsApi extends BaseApi { return this.viewAction({ join: { resource, ship }}); } + create(name: string, policy: Enc, title: string, description: string) { + return this.viewThread('group-create', { + create: { + name, + policy, + title, + description + } + }); + } + + deleteGroup(ship: string, name: string) { + const resource = makeResource(ship, name); + + return this.viewThread('group-delete', { + remove: resource + }); + } + + leaveGroup(ship: string, name: string) { + const resource = makeResource(ship, name); + return this.viewThread('group-leave', { + leave: resource + }); + } + private proxyAction(action: GroupAction) { return this.action('group-push-hook', 'group-update', action); } @@ -49,6 +75,10 @@ export default class GroupsApi extends BaseApi { return this.action('group-store', 'group-update', action); } + private viewThread(thread: string, action: any) { + return this.spider('group-view-action', 'json', thread, action); + } + private viewAction(action: any) { return this.action('group-view', 'group-view-action', action); diff --git a/pkg/interface/src/views/landscape/components/DeleteGroup.tsx b/pkg/interface/src/views/landscape/components/DeleteGroup.tsx index cac10fe7d..e539c7c8c 100644 --- a/pkg/interface/src/views/landscape/components/DeleteGroup.tsx +++ b/pkg/interface/src/views/landscape/components/DeleteGroup.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Col, Label, Row, Button } from "@tlon/indigo-react"; +import { Icon, Text, Col, Label, Row, Button, Action } from "@tlon/indigo-react"; import { useHistory } from "react-router-dom"; import GlobalApi from "~/logic/api/global"; @@ -7,6 +7,8 @@ import { Association } from "~/types"; import { resourceFromPath } from "~/logic/lib/group"; import { StatelessAsyncButton } from "~/views/components/StatelessAsyncButton"; import ModalButton from "~/views/apps/launch/components/ModalButton"; +import {useModal} from "~/logic/lib/useModal"; +import {SidebarItem} from "./Sidebar/SidebarItem"; export function DeleteGroup(props: { owner: boolean; @@ -15,14 +17,17 @@ export function DeleteGroup(props: { }) { const history = useHistory(); const onDelete = async () => { - const name = props.association.group.split("/").pop(); + const { ship, name } = resourceFromPath(props.association.group); if (props.owner) { const shouldDelete = prompt(`To confirm deleting this group, type ${name}`) === name; if (!shouldDelete) return; } - const resource = resourceFromPath(props.association.group); - await props.api.groups.removeGroup(resource); + if(props.owner) { + await props.api.groups.deleteGroup(ship, name); + } else { + await props.api.groups.leaveGroup(ship, name); + } history.push("/"); }; @@ -32,15 +37,8 @@ export function DeleteGroup(props: { : "You can rejoin if it is an open group, or if you are reinvited"; const icon = props.owner ? "X" : "SignOut"; - return ( - - {(dismiss: () => void) => ( + const { modal, showModal } = useModal({ modal: + (dismiss: () => void) => ( + )}); + return ( + + {modal} + + + {action} group + + ); } diff --git a/pkg/interface/src/views/landscape/components/GroupsPane.tsx b/pkg/interface/src/views/landscape/components/GroupsPane.tsx index b1e5b08eb..e860f1ec5 100644 --- a/pkg/interface/src/views/landscape/components/GroupsPane.tsx +++ b/pkg/interface/src/views/landscape/components/GroupsPane.tsx @@ -57,7 +57,7 @@ export function GroupsPane(props: GroupsPaneProps) { setRecentGroups((gs) => _.uniq([workspace.group, ...gs])); }, [workspace]); - if (!associations) { + if (!(associations && (groupPath ? groupPath in groups : true))) { return null; } diff --git a/pkg/interface/src/views/landscape/components/NewGroup.tsx b/pkg/interface/src/views/landscape/components/NewGroup.tsx index ea02ac049..b7a45bfde 100644 --- a/pkg/interface/src/views/landscape/components/NewGroup.tsx +++ b/pkg/interface/src/views/landscape/components/NewGroup.tsx @@ -62,10 +62,10 @@ export function NewGroup(props: NewGroupProps & RouteComponentProps) { banned: [], }, }; - await api.contacts.create(name, policy, title, description); + await api.groups.create(name, policy, title, description); const path = `/ship/~${window.ship}/${name}`; - await waiter(({ contacts, groups, associations }) => { - return path in contacts && path in groups && path in associations.groups; + await waiter(({ groups, associations }) => { + return path in groups && path in associations.groups; }); actions.setStatus({ success: null }); From 3f8f3bd3a4a57d94f9756cac66abd1e10c71b487 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 1 Feb 2021 18:18:50 +1000 Subject: [PATCH 61/61] GroupSearch: fix type of value --- pkg/interface/src/views/components/GroupSearch.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interface/src/views/components/GroupSearch.tsx b/pkg/interface/src/views/components/GroupSearch.tsx index 012d38262..4fc833983 100644 --- a/pkg/interface/src/views/components/GroupSearch.tsx +++ b/pkg/interface/src/views/components/GroupSearch.tsx @@ -91,9 +91,9 @@ export function GroupSearch(props: InviteSearchProps) { props.associations.groups?.[value]?.metadata || {}; const onSelect = useCallback( - (s: string) => { + (a: Association) => { setTouched(true); - setSelected(v => _.uniq([...v, s])); + setSelected(v => _.uniq([...v, a.group])); }, [setTouched, setSelected] );