diff --git a/pkg/arvo/app/chat-cli.hoon b/pkg/arvo/app/chat-cli.hoon index 6ff7667a5..d5cef8823 100644 --- a/pkg/arvo/app/chat-cli.hoon +++ b/pkg/arvo/app/chat-cli.hoon @@ -10,7 +10,7 @@ :: and trust it to take care of the rest. :: /- view=chat-view, hook=chat-hook, *group, - *permission-store, *group-store, *invite-store, + *permission-store, *group-store, inv=invite-store, sole /+ shoe, default-agent, verb, dbug, store=chat-store, group-store, grpl=group, resource @@ -27,7 +27,7 @@ +$ state-2 $: %2 grams=(list mail) :: all messages - known=(set [target serial]) :: known message lookup + known=(set [target serial:store]) :: known message lookup count=@ud :: (lent grams) bound=(map target glyph) :: bound circle glyphs binds=(jug glyph target) :: circle glyph lookup @@ -54,7 +54,7 @@ :: +$ state-0 $: grams=(list [[=ship =path] envelope:store]) :: all messages - known=(set [[=ship =path] serial]) :: known message lookup + known=(set [[=ship =path] serial:store]) :: known message lookup count=@ud :: (lent grams) bound=(map [=ship =path] glyph) :: bound circle glyphs binds=(jug glyph [=ship =path]) :: circle glyph lookup @@ -161,7 +161,7 @@ %fact ?+ p.cage.sign ~|([%chat-cli-bad-sub-mark wire p.cage.sign] !!) %chat-update (diff-chat-update:tc wire !<(update:store q.cage.sign)) - %invite-update (handle-invite-update:tc !<(invite-update q.cage.sign)) + %invite-update (handle-invite-update:tc !<(update:inv q.cage.sign)) == == [cards this] @@ -224,9 +224,9 @@ grams ~ ::NOTE this only impacts historic message lookup in chat-cli :: known - ^- (set [target serial]) + ^- (set [target serial:store]) %- ~(run in known.u.old) - |= [t=[ship path] s=serial] + |= [t=[ship path] s=serial:store] [`target`[| t] s] :: bound @@ -324,7 +324,7 @@ :: +handle-invite-update: get new invites :: ++ handle-invite-update - |= upd=invite-update + |= upd=update:inv ^- (quip card _state) ?+ -.upd [~ state] %invite [[(show-invite:sh-out invite.upd) ~] state] @@ -534,10 +534,10 @@ :: ;~(pfix ace ;~(plug i.opt $(opt t.opt))) :: -- :: - ++ group ;~((glue net) ship sym) + ++ group ;~((glue fas) ship sym) ++ tag |*(a=@tas (cold a (jest a))) ::TODO into stdlib ++ ship ;~(pfix sig fed:ag) - ++ path ;~(pfix net ;~(plug urs:ab (easy ~))) ::NOTE short only, tmp + ++ path ;~(pfix fas ;~(plug urs:ab (easy ~))) ::NOTE short only, tmp :: +mang: un/managed indicator prefix :: :: deprecated, as sig prefix is no longer used @@ -619,7 +619,7 @@ ++ letter ;~ pose (stag %url turl) - (stag %me ;~(pfix vat text)) + (stag %me ;~(pfix pat text)) (stag %text ;~(less mic hax text)) == :: +turl: url parser @@ -722,12 +722,11 @@ %poke %invite-action :: - !> - ^- invite-action - :^ %invite /chat + !> ^- action:inv + :^ %invite %chat (shax (jam [our-self where] who)) - ^- invite - [our-self %chat-hook where who ''] + ^- invite:inv + [our-self %chat-hook (de-path:resource where) who ''] == :: +set-target: set audience, update prompt :: @@ -865,7 +864,7 @@ |= =letter:store ^- (quip card _state) ~! bowl - =/ =serial (shaf %msg-uid eny.bowl) + =/ =serial:store (shaf %msg-uid eny.bowl) :_ state ^- (list card) %+ turn ~(tap in audience) @@ -1132,11 +1131,9 @@ :: +show-invite: print incoming invite notification :: ++ show-invite - |= invite + |= invite:inv ^- card - %- note - %+ weld "invited to: " - ~(phat tr (path-to-target path)) + (note "invited to: {(scow %p entity.resource)} {(trip name.resource)}") -- :: :: +tr: render targets diff --git a/pkg/arvo/app/chat-hook.hoon b/pkg/arvo/app/chat-hook.hoon index 3dff6c5d6..340d1e6c1 100644 --- a/pkg/arvo/app/chat-hook.hoon +++ b/pkg/arvo/app/chat-hook.hoon @@ -2,7 +2,7 @@ :: mirror chat data from foreign to local based on read permissions :: allow sending chat messages to foreign paths based on write perms :: -/- *permission-store, *invite-store, *metadata-store, +/- *permission-store, inv=invite-store, *metadata-store, *permission-hook, *group-store, *permission-group-hook, ::TMP for upgrade hook=chat-hook, view=chat-view, @@ -52,7 +52,7 @@ +$ poke $% [%chat-action action:store] [%permission-action permission-action] - [%invite-action invite-action] + [%invite-action action:inv] [%chat-view-action action:view] == :: @@ -77,7 +77,7 @@ ++ on-init ^- (quip card _this) :_ this(invite-created %.y) - :~ (invite-poke:cc [%create /chat]) + :~ (invite-poke:cc [%create %chat]) [%pass /invites %agent [our.bol %invite-store] %watch /invitatory/chat] watch-groups:cc == @@ -406,7 +406,7 @@ :: %invite-update =^ cards state - (fact-invite-update:cc wire !<(invite-update q.cage.sign)) + (fact-invite-update:cc wire !<(update:inv q.cage.sign)) [cards this] :: %group-update @@ -719,15 +719,18 @@ == :: ++ fact-invite-update - |= [wir=wire fact=invite-update] + |= [wir=wire fact=update:inv] ^- (quip card _state) :_ state ?+ -.fact ~ %accepted - =/ ask-history ?~((chat-scry path.invite.fact) %.y %.n) - =* shp ship.invite.fact - =* app-path path.invite.fact - ~[(chat-view-poke [%join shp app-path ask-history])] + =* resource resource.invite.fact + =/ =path [(scot %p entity.resource) name.resource ~] + :_ ~ + %- chat-view-poke + :^ %join ship.invite.fact + path + ?=(~ (chat-scry path)) == :: ++ fact-group-update @@ -919,9 +922,9 @@ [%pass / %agent [our.bol %chat-view] %poke %chat-view-action !>(act)] :: ++ invite-poke - |= act=invite-action + |= =action:inv ^- card - [%pass / %agent [our.bol %invite-store] %poke %invite-action !>(act)] + [%pass / %agent [our.bol %invite-store] %poke %invite-action !>(action)] :: ++ sec-to-perm |= [pax=path =kind] @@ -936,9 +939,9 @@ [%mailbox pax] :: ++ invite-scry - |= uid=serial - ^- (unit invite) - %^ scry (unit invite) + |= uid=serial:inv + ^- (unit invite:inv) + %^ scry (unit invite:inv) %invite-store /invite/chat/(scot %uv uid) :: diff --git a/pkg/arvo/app/chat-view.hoon b/pkg/arvo/app/chat-view.hoon index f12a64edb..648f42082 100644 --- a/pkg/arvo/app/chat-view.hoon +++ b/pkg/arvo/app/chat-view.hoon @@ -6,7 +6,7 @@ /- *permission-store, *permission-hook, *group, - *invite-store, + inv=invite-store, *metadata-store, group-hook, *permission-group-hook, @@ -220,8 +220,7 @@ ~& %chat-already-exists ~ %- zing - :~ (create-chat app-path.act allow-history.act) - %- create-group + :~ %- create-group :* group-path.act app-path.act policy.act @@ -231,6 +230,7 @@ managed.act == (create-metadata title.act description.act group-path.act app-path.act) + (create-chat app-path.act allow-history.act) == :: %delete @@ -407,13 +407,14 @@ ^- card =/ managed=? !=(ship+app-path group-path) - =/ =invite + =/ =invite:inv :* our.bol ?:(managed %contact-hook %chat-hook) - ?:(managed group-path app-path) + (de-path:resource ?:(managed group-path ship+app-path)) ship '' == - =/ act=invite-action [%invite ?:(managed /contacts /chat) (shaf %msg-uid eny.bol) invite] + =/ act=action:inv + [%invite ?:(managed %contacts %chat) (shaf %msg-uid eny.bol) invite] [%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)] :: ++ chat-scry @@ -487,8 +488,8 @@ (en-path:resource rid) ?> ?=(^ path) :~ (group-pull-hook-poke %add ship rid) - (chat-hook-poke %add-synced ship t.path ask-history) (metadata-hook-poke %add-synced ship path) + (chat-hook-poke %add-synced ship t.path ask-history) == :: ++ diff-chat-update diff --git a/pkg/arvo/app/contact-hook.hoon b/pkg/arvo/app/contact-hook.hoon index ccdb41010..087120183 100644 --- a/pkg/arvo/app/contact-hook.hoon +++ b/pkg/arvo/app/contact-hook.hoon @@ -4,7 +4,7 @@ /- group-hook, *contact-hook, *contact-view, - *invite-store, + inv=invite-store, *metadata-hook, *metadata-store, *group @@ -44,7 +44,7 @@ ++ on-init ^- (quip card _this) :_ this(invite-created %.y) - :~ (invite-poke:cc [%create /contacts]) + :~ (invite-poke:cc [%create %contacts]) [%pass /inv %agent [our.bol %invite-store] %watch /invitatory/contacts] [%pass /group %agent [our.bol %group-store] %watch /groups] == @@ -467,20 +467,10 @@ (contact-poke [%delete path]) (contact-poke [%remove path ship]) == - :: - ++ send-invite-poke - |= [=path =ship] - ^- card - =/ =invite - :* our.bol %contact-hook - path ship '' - == - =/ act=invite-action [%invite /contacts (shaf %msg-uid eny.bol) invite] - [%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)] -- :: ++ invite-poke - |= act=invite-action + |= act=action:inv ^- card [%pass / %agent [our.bol %invite-store] %poke %invite-action !>(act)] :: diff --git a/pkg/arvo/app/contact-view.hoon b/pkg/arvo/app/contact-view.hoon index 9fab4648c..2abbbb0f6 100644 --- a/pkg/arvo/app/contact-view.hoon +++ b/pkg/arvo/app/contact-view.hoon @@ -5,7 +5,7 @@ :: /- group-hook, - *invite-store, + inv=invite-store, *contact-hook, *metadata-store, *metadata-hook, @@ -161,27 +161,22 @@ %+ turn ~(tap in pending.policy.act) |= =ship - (send-invite our.bol %contacts path ship '') + (send-invite our.bol %contacts rid ship '') == :: %join - =/ =path - (en-path:resource resource.act) =/ =cage :- %group-update !> ^- update:group-store [%add-members resource.act (sy our.bol ~)] =/ =wire - [%join-group path] + [%join-group (en-path:resource resource.act)] [%pass wire %agent [entity.resource.act %group-push-hook] %poke cage]~ :: %invite =* rid resource.act - =/ =path - (en-path:resource rid) - =/ =group - (need (scry-group:grp rid)) - :- (send-invite entity.rid %contacts path ship.act text.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)] :: @@ -276,12 +271,12 @@ [%pass / %agent [entity.rid app] %poke cage] :: ++ send-invite - |= =invite + |= =invite:inv ^- card =/ =cage :- %invite-action - !> ^- invite-action - [%invite /contacts (shaf %invite-uid eny.bol) invite] + !> ^- action:inv + [%invite %contacts (shaf %invite-uid eny.bol) invite] [%pass / %agent [recipient.invite %invite-hook] %poke cage] :: ++ contact-poke diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index d225ef9e0..5e54034a7 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -165,7 +165,7 @@ == == :: - ;~ pfix net + ;~ pfix fas ;~ pose (parse-variable (cold %sur hep) ;~(pfix gap parse-cables)) (parse-variable (cold %lib lus) ;~(pfix gap parse-cables)) @@ -179,8 +179,8 @@ ++ parse-sink ;~ pose ;~(plug (cold %file tar) parse-beam) - ;~(plug (cold %flat vat) (most net sym)) - ;~(plug (cold %pill dot) (most net sym)) + ;~(plug (cold %flat pat) (most fas sym)) + ;~(plug (cold %pill dot) (most fas sym)) ;~(plug (cold %http lus) (stag %post parse-url)) ;~(plug (cold %http hep) (stag %put parse-url)) (stag %show (cook $?($1 $2 $3 $4 $5) (cook lent (stun [1 5] wut)))) @@ -218,6 +218,7 @@ ;~(plug (cold %ur lus) parse-url) ;~(plug (cold %ge lus) parse-model) ;~(plug (cold %te hep) sym (star ;~(pfix ace parse-source))) + ;~(plug (cold %as pam) sym ;~(pfix ace parse-source)) ;~(plug (cold %do cab) parse-hoon ;~(pfix ace parse-source)) parse-value == @@ -227,7 +228,7 @@ ;~ pose ;~ plug ;~(pfix sig fed:ag) - ;~(pose ;~(pfix net sym) (easy default-app)) + ;~(pose ;~(pfix fas sym) (easy default-app)) == %+ stag our ;~(pose sym (easy default-app)) @@ -262,7 +263,7 @@ auri:de-purl:html :: ++ parse-model ;~(plug parse-server parse-config) - ++ parse-server (stag 0 (most net sym)) + ++ parse-server (stag 0 (most fas sym)) ++ parse-hoon tall:hoon-parser :: ++ parse-rood @@ -283,10 +284,10 @@ == ++ parse-value ;~ pose - ;~(plug (cold %as pad) sym ;~(pfix ace parse-source)) - (stag %sa ;~(pfix tar pad sym)) + ;~(plug (cold %as pam) sym ;~(pfix ace parse-source)) + (stag %sa ;~(pfix tar pam sym)) (stag %ex parse-hoon) - (stag %tu (ifix [lac rac] (most ace parse-source))) + (stag %tu (ifix [sel ser] (most ace parse-source))) == :: ++ parse-config diff --git a/pkg/arvo/app/glob.hoon b/pkg/arvo/app/glob.hoon index c031faa9b..472f93833 100644 --- a/pkg/arvo/app/glob.hoon +++ b/pkg/arvo/app/glob.hoon @@ -5,7 +5,7 @@ /- glob /+ default-agent, verb, dbug |% -++ hash 0v2.1vtfh.0l23v.30s7f.n57l9.dpjvi +++ hash 0v4.fpa4r.s6dtc.h8tps.62jv0.qn0fj +$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))] +$ all-states $% state-0 @@ -89,7 +89,7 @@ =+ .^(=map=tube:clay %cc (weld home /map/mime)) =+ .^(arch %cy (weld home /app/landscape/js/bundle)) =/ bundle-hash=@t - %- need + %- need ^- (unit @t) %- ~(rep by dir) |= [[file=@t ~] out=(unit @t)] diff --git a/pkg/arvo/app/graph-pull-hook.hoon b/pkg/arvo/app/graph-pull-hook.hoon index 5971ef948..70ed3e22e 100644 --- a/pkg/arvo/app/graph-pull-hook.hoon +++ b/pkg/arvo/app/graph-pull-hook.hoon @@ -20,6 +20,7 @@ +* this . def ~(. (default-agent this %|) bowl) dep ~(. (default:pull-hook this config) bowl) + gra ~(. graph bowl) :: ++ on-init on-init:def ++ on-save !>(~) @@ -35,6 +36,7 @@ |= [=resource =tang] ^- (quip card _this) :_ this + ?. (~(has in get-keys:gra) resource) ~ =- [%pass /pull-nack %agent [our.bowl %graph-store] %poke %graph-update -]~ !> ^- update:store [%0 now.bowl [%archive-graph resource]] @@ -42,7 +44,7 @@ ++ on-pull-kick |= =resource ^- (unit path) - =/ maybe-time (peek-update-log:graph resource) + =/ maybe-time (peek-update-log:gra resource) ?~ maybe-time `/ `/(scot %da u.maybe-time) -- diff --git a/pkg/arvo/app/graph-push-hook.hoon b/pkg/arvo/app/graph-push-hook.hoon index 5b4ea54b3..e4d409754 100644 --- a/pkg/arvo/app/graph-push-hook.hoon +++ b/pkg/arvo/app/graph-push-hook.hoon @@ -32,6 +32,22 @@ ?| (is-member:grp src.bowl i.group-paths) (is-admin:grp src.bowl i.group-paths) == +:: +++ is-allowed-remove + |= [=resource:res indices=(set index:store) =bowl:gall] + ^- ? + =/ gra ~(. graph bowl) + ?. (is-allowed resource bowl %.n) + %.n + %+ levy + ~(tap in indices) + |= =index:store + ^- ? + =/ =node:store + (got-node:gra resource index) + ?| =(author.post.node src.bowl) + (is-allowed resource bowl %.y) + == -- :: %- agent:dbug @@ -63,7 +79,7 @@ %add-graph (is-allowed resource.q.update bowl %.y) %remove-graph (is-allowed resource.q.update bowl %.y) %add-nodes (is-allowed resource.q.update bowl %.n) - %remove-nodes (is-allowed resource.q.update bowl %.y) + %remove-nodes (is-allowed-remove resource.q.update indices.q.update bowl) %add-signatures (is-allowed resource.uid.q.update bowl %.n) %remove-signatures (is-allowed resource.uid.q.update bowl %.y) %archive-graph (is-allowed resource.q.update bowl %.y) @@ -108,6 +124,8 @@ (get-graph:gra resource) :: resubscribe :: + ?~ (get-update-log:gra resource) + (get-graph:gra resource) =/ =time (slav %da i.path) =/ =update-log:store (get-update-log-subset:gra resource time) [%0 now.bowl [%run-updates resource update-log]] diff --git a/pkg/arvo/app/graph-store.hoon b/pkg/arvo/app/graph-store.hoon index 34f4d9040..ae47b6158 100644 --- a/pkg/arvo/app/graph-store.hoon +++ b/pkg/arvo/app/graph-store.hoon @@ -7,14 +7,20 @@ +$ card card:agent:gall +$ versioned-state $% state-0 + state-1 + state-2 == :: +$ state-0 [%0 network:store] ++$ state-1 [%1 network:store] ++$ state-2 [%2 network:store] +:: ++ orm orm:store ++ orm-log orm-log:store ++$ debug-input [%validate-graph =resource:store] -- :: -=| state-0 +=| state-2 =* state - :: %- agent:dbug @@ -27,9 +33,160 @@ ++ on-init [~ this] ++ on-save !>(state) ++ on-load - |= old=vase + |= =old=vase ^- (quip card _this) - [~ this(state !<(state-0 old))] + =+ !<(old=versioned-state old-vase) + =| cards=(list card) + |^ + ?- -.old + %0 + %_ $ + -.old %1 + :: + validators.old + (~(put in validators.old) %graph-validator-link) + :: + cards + %+ weld cards + %+ turn + ~(tap in (~(put in validators.old) %graph-validator-link)) + |= validator=@t + ^- card + =/ =wire /validator/[validator] + =/ =rave:clay [%sing %b [%da now.bowl] /[validator]] + [%pass wire %arvo %c %warp our.bowl [%home `rave]] + :: + graphs.old + %- ~(run by graphs.old) + |= [=graph:store q=(unit mark)] + ^- [graph:store (unit mark)] + :- (convert-unix-timestamped-graph graph) + ?^ q q + `%graph-validator-link + :: + update-logs.old + %- ~(run by update-logs.old) + |=(a=* *update-log:store) + == + :: + %1 + %_ $ + -.old %2 + graphs.old (~(run by graphs.old) change-revision-graph) + :: + update-logs.old + %- ~(run by update-logs.old) + |=(a=* *update-log:store) + == + :: + %2 [cards this(state old)] + == + :: + ++ change-revision-graph + |= [=graph:store q=(unit mark)] + ^- [graph:store (unit mark)] + |^ + :_ q + ?+ q graph + [~ %graph-validator-link] convert-links + [~ %graph-validator-publish] convert-publish + == + :: + ++ convert-links + %+ gas:orm *graph:store + %+ turn (tap:orm graph) + |= [=atom =node:store] + ^- [^atom node:store] + :: top-level + :: + :+ atom post.node + ?: ?=(%empty -.children.node) + [%empty ~] + :- %graph + %+ gas:orm *graph:store + %+ turn (tap:orm p.children.node) + |= [=^atom =node:store] + ^- [^^atom node:store] + :: existing comments get turned into containers for revisions + :: + :^ atom + post.node(contents ~, hash ~) + %graph + %+ gas:orm *graph:store + :_ ~ :- %1 + :_ [%empty ~] + post.node(index (snoc index.post.node atom), hash ~) + :: + ++ convert-publish + %+ gas:orm *graph:store + %+ turn (tap:orm graph) + |= [=atom =node:store] + ^- [^atom node:store] + :: top-level + :: + :+ atom post.node + ?: ?=(%empty -.children.node) + [%empty ~] + :- %graph + %+ gas:orm *graph:store + %+ turn (tap:orm p.children.node) + |= [=^atom =node:store] + ^- [^^atom node:store] + :: existing container for publish note revisions + :: + ?+ atom !! + %1 [atom node] + %2 + :+ atom post.node + ?: ?=(%empty -.children.node) + [%empty ~] + :- %graph + %+ gas:orm *graph:store + %+ turn (tap:orm p.children.node) + |= [=^^atom =node:store] + ^- [^^^atom node:store] + :+ atom post.node(contents ~, hash ~) + :- %graph + %+ gas:orm *graph:store + :_ ~ :- %1 + :_ [%empty ~] + post.node(index (snoc index.post.node atom), hash ~) + == + -- + :: + ++ maybe-unix-to-da + |= =atom + ^- @ + :: (bex 127) is roughly 226AD + ?. (lte atom (bex 127)) + atom + (add ~1970.1.1 (div (mul ~s1 atom) 1.000)) + :: + ++ convert-unix-timestamped-node + |= =node:store + ^- node:store + =. index.post.node + (convert-unix-timestamped-index index.post.node) + ?. ?=(%graph -.children.node) + node + :+ post.node + %graph + (convert-unix-timestamped-graph p.children.node) + :: + ++ convert-unix-timestamped-index + |= =index:store + (turn index maybe-unix-to-da) + :: + ++ convert-unix-timestamped-graph + |= =graph:store + %+ gas:orm *graph:store + %+ turn + (tap:orm graph) + |= [=atom =node:store] + ^- [^atom node:store] + :- (maybe-unix-to-da atom) + (convert-unix-timestamped-node node) + -- :: ++ on-watch ~/ %graph-store-watch @@ -60,6 +217,7 @@ =^ cards state ?+ mark (on-poke:def mark vase) %graph-update (graph-update !<(update:store vase)) + %noun (debug !<(debug-input vase)) == [cards this] :: @@ -68,6 +226,7 @@ ^- (quip card _state) |^ ?> ?=(%0 -.update) + =? p.update =(p.update *time) now.bowl ?- -.q.update %add-graph (add-graph +.q.update) %remove-graph (remove-graph +.q.update) @@ -86,23 +245,30 @@ == :: ++ add-graph - |= [=resource:store =graph:store mark=(unit mark:store)] + |= $: =resource:store + =graph:store + mark=(unit mark:store) + overwrite=? + == ^- (quip card _state) - ?< (~(has by archive) resource) - ?< (~(has by graphs) resource) + ?> ?| overwrite + ?& !(~(has by archive) resource) + !(~(has by graphs) resource) + == == ?> (validate-graph graph mark) :_ %_ state graphs (~(put by graphs) resource [graph mark]) update-logs (~(put by update-logs) resource (gas:orm-log ~ ~)) + archive (~(del by archive) resource) validators ?~ mark validators (~(put in validators) u.mark) == %- zing - :~ (give [/updates /keys ~] [%add-graph resource graph mark]) + :~ (give [/updates /keys ~] [%add-graph resource graph mark overwrite]) ?~ mark ~ ?: (~(has in validators) u.mark) ~ - =/ wire (weld /graph (en-path:res resource)) + =/ wire /validator/[u.mark] =/ =rave:clay [%sing %b [%da now.bowl] /[u.mark]] [%pass wire %arvo %c %warp our.bowl [%home `rave]]~ == @@ -395,52 +561,57 @@ ^- (quip card _state) ?< (~(has by archive) resource) ?> (~(has by graphs) resource) - :_ state - %+ turn (tap:orm-log update-log) - |= [=time update=logged-update:store] - ^- card - ?> ?=(%0 -.update) - :* %pass - /run-updates/(scot %da time) - %agent - [our.bowl %graph-store] - %poke - :- %graph-update - !> - ^- update:store - ?- -.q.update - %add-nodes update(resource.q resource) - %remove-nodes update(resource.q resource) - %add-signatures update(resource.uid.q resource) - %remove-signatures update(resource.uid.q resource) - == - == - :: - ++ validate-graph - |= [=graph:store mark=(unit mark:store)] - ^- ? - ?~ mark %.y - ?~ graph %.y - =/ =dais:clay - .^ =dais:clay - %cb - /(scot %p our.bowl)/[q.byk.bowl]/(scot %da now.bowl)/[u.mark] + =/ updates=(list [=time upd=logged-update:store]) + (tap:orm-log update-log) + =| cards=(list card) + |- ^- (quip card _state) + ?~ updates + [cards state] + =* update upd.i.updates + =^ crds state + %- graph-update + ^- update:store + ?- -.q.update + %add-nodes update(resource.q resource) + %remove-nodes update(resource.q resource) + %add-signatures update(resource.uid.q resource) + %remove-signatures update(resource.uid.q resource) == - %+ roll (tap:orm graph) - |= [[=atom =node:store] out=?] - ?& out - =(%& -:(mule |.((vale:dais [atom post.node])))) - ?- -.children.node - %empty %.y - %graph ^$(graph p.children.node) - == - == + $(cards (weld cards crds), updates t.updates) :: ++ give |= [paths=(list path) update=update-0:store] ^- (list card) [%give %fact paths [%graph-update !>([%0 now.bowl update])]]~ -- + :: + ++ debug + |= =debug-input + ^- (quip card _state) + =/ [=graph:store mark=(unit mark:store)] + (~(got by graphs) resource.debug-input) + ?> (validate-graph graph mark) + [~ state] + :: + ++ validate-graph + |= [=graph:store mark=(unit mark:store)] + ^- ? + ?~ mark %.y + ?~ graph %.y + =/ =dais:clay + .^ =dais:clay + %cb + /(scot %p our.bowl)/[q.byk.bowl]/(scot %da now.bowl)/[u.mark] + == + %+ roll (tap:orm graph) + |= [[=atom =node:store] out=?] + ?& out + =(%& -:(mule |.((vale:dais [atom post.node])))) + ?- -.children.node + %empty %.y + %graph ^$(graph p.children.node) + == + == -- :: ++ on-peek @@ -450,6 +621,14 @@ |^ ?> (team:title our.bowl src.bowl) ?+ path (on-peek:def path) + [%x %graph-mark @ @ ~] + =/ =ship (slav %p i.t.t.path) + =/ =term i.t.t.t.path + =/ result=(unit marked-graph:store) + (~(get by graphs) [ship term]) + ?~ result [~ ~] + ``noun+!>(q.u.result) + :: [%x %keys ~] :- ~ :- ~ :- %graph-update !>(`update:store`[%0 now.bowl [%keys ~(key by graphs)]]) @@ -472,7 +651,7 @@ !> ^- update:store :+ %0 now.bowl - [%add-graph [ship term] `graph:store`p.u.result q.u.result] + [%add-graph [ship term] `graph:store`p.u.result q.u.result %.y] :: :: note: near-duplicate of /x/graph :: @@ -488,7 +667,7 @@ !> ^- update:store :+ %0 now.bowl - [%add-graph [ship term] `graph:store`p.u.result q.u.result] + [%add-graph [ship term] `graph:store`p.u.result q.u.result %.y] :: [%x %graph-subset @ @ @ @ ~] =/ =ship (slav %p i.t.t.path) @@ -513,7 +692,7 @@ =/ =ship (slav %p i.t.t.path) =/ =term i.t.t.t.path =/ =index:store - (turn t.t.t.t.path |=(=cord (slav %ud cord))) + (turn t.t.t.t.path (cury slav %ud)) =/ node=(unit node:store) (get-node ship term index) ?~ node [~ ~] :- ~ :- ~ :- %graph-update @@ -543,7 +722,7 @@ :+ %add-nodes [ship term] %- ~(gas by *(map index:store node:store)) - %+ turn (tap:orm `graph:store`(subset:orm p.children.u.node start end)) + %+ turn (tap:orm `graph:store`(subset:orm p.children.u.node end start)) |= [=atom =node:store] ^- [index:store node:store] [(snoc index atom) node] @@ -556,7 +735,8 @@ =/ end=(unit time) (slaw %da i.t.t.t.t.t.path) =/ update-log=(unit update-log:store) (~(get by update-logs) [ship term]) ?~ update-log [~ ~] - ``noun+!>((subset:orm-log u.update-log start end)) + :: orm-log is ordered backwards, so swap start and end + ``noun+!>((subset:orm-log u.update-log end start)) :: [%x %update-log @ @ ~] =/ =ship (slav %p i.t.t.path) @@ -600,15 +780,15 @@ ++ on-arvo |= [=wire =sign-arvo] ^- (quip card _this) - ?+ -.sign-arvo (on-arvo:def wire sign-arvo) - %c + ?+ wire (on-arvo:def wire sign-arvo) + :: + :: old wire, do nothing + [%graph *] [~ this] + :: + [%validator @ ~] :_ this - ?> ?=([%graph @ *] wire) - =/ =resource:store (de-path:res t.wire) - =/ gra=(unit marked-graph:store) (~(get by graphs) resource) - ?~ gra ~ - ?~ q.u.gra ~ - =/ =rave:clay [%next %b [%da now.bowl] /[u.q.u.gra]] + =* validator i.t.wire + =/ =rave:clay [%next %b [%da now.bowl] /[validator]] [%pass wire %arvo %c %warp our.bowl [%home `rave]]~ == :: diff --git a/pkg/arvo/app/hark-chat-hook.hoon b/pkg/arvo/app/hark-chat-hook.hoon new file mode 100644 index 000000000..dcd1449ab --- /dev/null +++ b/pkg/arvo/app/hark-chat-hook.hoon @@ -0,0 +1,214 @@ +:: hark-chat-hook: notifications for chat-store [landscape] +:: +/- store=hark-store, post, group-store, metadata-store, hook=hark-chat-hook +/+ resource, metadata, default-agent, dbug, chat-store, grpl=group +:: +~% %hark-chat-hook-top ..is ~ +|% ++$ card card:agent:gall ++$ versioned-state + $% state-0 + == +:: ++$ state-0 + $: %0 + watching=(set path) + mentions=_& + == +:: +-- +:: +=| state-0 +=* state - +:: +=> + |_ =bowl:gall + :: + ++ give + |= [paths=(list path) =update:hook] + ^- (list card) + [%give %fact paths hark-chat-hook-update+!>(update)]~ + :: + ++ watch-chat + ^- card + [%pass /chat %agent [our.bowl %chat-store] %watch /all] + -- +%- agent:dbug +^- agent:gall +~% %hark-chat-hook-agent ..card ~ +|_ =bowl:gall ++* this . + ha ~(. +> bowl) + def ~(. (default-agent this %|) bowl) + met ~(. metadata bowl) + grp ~(. grpl bowl) +:: +++ on-init + :_ this + ~[watch-chat:ha] +:: +++ on-save !>(state) +++ on-load + |= old=vase + ^- (quip card _this) + :_ this(state !<(state-0 old)) + ?: (~(has by wex.bowl) [/chat our.bowl %chat-store]) + ~ + ~[watch-chat:ha] +:: +++ on-watch + |= =path + ^- (quip card _this) + =^ cards state + ?+ path (on-watch:def path) + :: + [%updates ~] + :_ state + %+ give:ha ~ + :* %initial + watching + == + == + [cards this] +:: +++ on-poke + ~/ %hark-chat-hook-poke + |= [=mark =vase] + ^- (quip card _this) + |^ + ?> (team:title our.bowl src.bowl) + =^ cards state + ?+ mark (on-poke:def mark vase) + %hark-chat-hook-action + (hark-chat-hook-action !<(action:hook vase)) + == + [cards this] + :: + ++ hark-chat-hook-action + |= =action:hook + ^- (quip card _state) + |^ + :- (give:ha ~[/updates] action) + ?- -.action + %listen (listen +.action) + %ignore (ignore +.action) + %set-mentions (set-mentions +.action) + == + ++ listen + |= chat=path + ^+ state + state(watching (~(put in watching) chat)) + :: + ++ ignore + |= chat=path + ^+ state + state(watching (~(del in watching) chat)) + :: + ++ set-mentions + |= ment=? + ^+ state + state(mentions ment) + -- + -- +:: +++ on-agent + ~/ %hark-chat-hook-agent + |= [=wire =sign:agent:gall] + ^- (quip card _this) + |^ + ?+ -.sign (on-agent:def wire sign) + %kick + :_ this + ?. ?=([%chat ~] wire) + ~ + ~[watch-chat:ha] + :: + %fact + ?. ?=(%chat-update p.cage.sign) + (on-agent:def wire sign) + =^ cards state + (chat-update !<(update:chat-store q.cage.sign)) + [cards this] + == + :: + ++ chat-update + |= =update:chat-store + ^- (quip card _state) + ?+ -.update `state + %initial (process-initial +.update) + %create (process-new +.update) + :: + %message + :_ state + (process-envelope path.update envelope.update) + :: + %messages + :_ state + %- zing + (turn envelopes.update (cury process-envelope path.update)) + == + ++ process-initial + |= =inbox:chat-store + ^- (quip card _state) + =/ keys=(list path) + ~(tap in ~(key by inbox)) + =| cards=(list card) + |- + ?~ keys + [cards state] + =* path i.keys + =^ cs state + (process-new path) + $(cards (weld cards cs), keys t.keys) + :: + ++ process-new + |= chat=path + ^- (quip card _state) + =/ groups=(list path) + (groups-from-resource:met %chat chat) + ?~ groups + `state + ?: (is-managed-path:grp i.groups) + `state + `state(watching (~(put in watching) chat)) + :: + ++ is-mention + |= =envelope:chat-store + ?. ?=(%text -.letter.envelope) %.n + ?& mentions + ?= ^ + (find (scow %p our.bowl) (trip text.letter.envelope)) + == + :: + ++ is-notification + |= [=path =envelope:chat-store] + ?& (~(has in watching) path) + !=(author.envelope our.bowl) + == + :: + ++ process-envelope + |= [=path =envelope:chat-store] + ^- (list card) + =/ mention=? + (is-mention envelope) + ?. ?|(mention (is-notification path envelope)) + ~ + =/ =index:store + [%chat path mention] + =/ =contents:store + [%chat ~[envelope]] + ~[(poke-store %add index when.envelope %.n contents)] + :: + ++ poke-store + |= =action:store + ^- card + =- [%pass /store %agent [our.bowl %hark-store] %poke -] + hark-action+!>(action) + -- +:: +++ on-peek on-peek:def +:: +++ on-leave on-leave:def +++ on-arvo on-arvo:def +++ on-fail on-fail:def +-- diff --git a/pkg/arvo/app/hark-graph-hook.hoon b/pkg/arvo/app/hark-graph-hook.hoon new file mode 100644 index 000000000..edf87a6f8 --- /dev/null +++ b/pkg/arvo/app/hark-graph-hook.hoon @@ -0,0 +1,267 @@ +:: hark-graph-hook: notifications for graph-store [landscape] +:: +/- store=hark-store, post, group-store, metadata-store, hook=hark-graph-hook +/+ resource, metadata, default-agent, dbug, graph-store +:: +~% %hark-graph-hook-top ..is ~ +|% ++$ card card:agent:gall ++$ versioned-state + $% state-0 + == +:: ++$ state-0 + $: %0 + watching=(set [resource index:post]) + mentions=_& + watch-on-self=_& + == +:: +-- +:: +=| state-0 +=* state - +:: +=> + |_ =bowl:gall + :: + ++ scry + |* [=mold p=path] + ?> ?=(^ p) + ?> ?=(^ t.p) + .^(mold i.p (scot %p our.bowl) i.t.p (scot %da now.bowl) t.t.p) + :: + ++ give + |= [paths=(list path) =update:hook] + ^- (list card) + [%give %fact paths hark-graph-hook-update+!>(update)]~ + :: + ++ watch-graph + ^- card + [%pass /graph %agent [our.bowl %graph-store] %watch /updates] + -- +%- agent:dbug +^- agent:gall +~% %hark-graph-hook-agent ..card ~ +|_ =bowl:gall ++* this . + ha ~(. +> bowl) + def ~(. (default-agent this %|) bowl) + met ~(. metadata bowl) +:: +++ on-init + :_ this + ~[watch-graph:ha] +:: +++ on-save !>(state) +++ on-load + |= old=vase + ^- (quip card _this) + `this(state !<(state-0 old)) +:: +++ on-watch + |= =path + ^- (quip card _this) + =^ cards state + ?+ path (on-watch:def path) + :: + [%updates ~] + :_ state + %+ give:ha ~ + :* %initial + watching + mentions + watch-on-self + == + == + [cards this] +:: +++ on-poke + ~/ %hark-graph-hook-poke + |= [=mark =vase] + ^- (quip card _this) + |^ + ?> (team:title our.bowl src.bowl) + =^ cards state + ?+ mark (on-poke:def mark vase) + %hark-graph-hook-action + (hark-graph-hook-action !<(action:hook vase)) + == + [cards this] + :: + ++ hark-graph-hook-action + |= =action:hook + ^- (quip card _state) + |^ + :- (give:ha ~[/updates] action) + ?- -.action + %listen (listen +.action) + %ignore (ignore +.action) + %set-mentions (set-mentions +.action) + %set-watch-on-self (set-watch-on-self +.action) + == + ++ listen + |= [graph=resource =index:post] + ^+ state + state(watching (~(put in watching) [graph index])) + :: + ++ ignore + |= [graph=resource =index:post] + ^+ state + state(watching (~(del in watching) [graph index])) + :: + ++ set-mentions + |= ment=? + ^+ state + state(mentions ment) + :: + ++ set-watch-on-self + |= self=? + ^+ state + state(watch-on-self self) + -- + -- +:: +++ on-agent + ~/ %hark-graph-hook-agent + |= [=wire =sign:agent:gall] + ^- (quip card _this) + |^ + ?+ -.sign (on-agent:def wire sign) + %kick + :_ this + ?. ?=([%graph ~] wire) + ~ + ~[watch-graph:ha] + :: + %fact + ?. ?=(%graph-update p.cage.sign) + (on-agent:def wire sign) + =^ cards state + (graph-update !<(update:graph-store q.cage.sign)) + [cards this] + == + ++ add-graph + |= rid=resource + ^- (quip card _state) + ?. &(watch-on-self =(our.bowl entity.rid)) + [~ state] + `state(watching (~(put in watching) [rid ~])) + :: + ++ graph-update + |= =update:graph-store + ^- (quip card _state) + ?: ?=(%add-graph -.q.update) + (add-graph resource.q.update) + ?. ?=(%add-nodes -.q.update) + [~ state] + =/ group=resource + (need (group-from-app-resource:met %graph resource.q.update)) + =/ =metadata:metadata-store + (need (peek-metadata:met %graph group resource.q.update)) + =* rid resource.q.update + =+ %+ scry:ha + ,mark=(unit mark) + /gx/graph-store/graph-mark/(scot %p entity.rid)/[name.rid]/noun + =+ %+ scry:ha + ,=tube:clay + /cc/[q.byk.bowl]/[(fall mark %graph-validator-link)]/notification-kind + =/ nodes=(list [p=index:graph-store q=node:graph-store]) + ~(tap by nodes.q.update) + =| cards=(list card) + |^ + ?~ nodes + [cards state] + =* index p.i.nodes + =* node q.i.nodes + =^ node-cards state + (check-node node tube) + %_ $ + nodes t.nodes + cards (weld node-cards cards) + == + :: + ++ check-node-children + |= [=node:graph-store =tube:clay] + ^- (quip card _state) + ?: ?=(%empty -.children.node) + [~ state] + =/ children=(list [=atom =node:graph-store]) + (tap:orm:graph-store p.children.node) + =| cards=(list card) + |- ^- (quip card _state) + ?~ children + [cards state] + =^ new-cards state + (check-node node.i.children tube) + %_ $ + cards (weld cards new-cards) + children t.children + == + :: + ++ check-node + |= [=node:graph-store =tube:clay] + ^- (quip card _state) + =^ child-cards state + (check-node-children node tube) + ?: =(our.bowl author.post.node) + =^ self-cards state + (self-post node) + :_ state + (weld child-cards self-cards) + =+ !< notif-kind=(unit [name=@t parent-lent=@ud]) + (tube !>([0 post.node])) + ?~ notif-kind + [child-cards state] + =/ desc=@t + ?: (is-mention contents.post.node) + %mention + name.u.notif-kind + =/ parent=index:post + (scag parent-lent.u.notif-kind index.post.node) + ?. ?| =(desc %mention) + (~(has in watching) [rid parent]) + == + [child-cards state] + =/ notif-index=index:store + [%graph group rid module.metadata desc] + =/ =contents:store + [%graph (limo post.node ~)] + :_ state + %+ snoc child-cards + (add-unread notif-index [time-sent.post.node %.n contents]) + :: + ++ is-mention + |= contents=(list content:post) + ^- ? + ?. mentions %.n + ?~ contents %.n + ?. ?=(%mention -.i.contents) + $(contents t.contents) + ?: =(our.bowl ship.i.contents) + %.y + $(contents t.contents) + :: + ++ self-post + |= =node:graph-store + ^- (quip card _state) + ?. ?=(%.y watch-on-self) + [~ state] + `state(watching (~(put in watching) [rid index.post.node])) + :: + ++ add-unread + |= [=index:store =notification:store] + ^- card + =- [%pass / %agent [our.bowl %hark-store] %poke -] + hark-action+!>([%add index notification]) + :: + -- + -- +:: +++ on-peek on-peek:def +:: +++ on-leave on-leave:def +++ on-arvo on-arvo:def +++ on-fail on-fail:def +-- + diff --git a/pkg/arvo/app/hark-group-hook.hoon b/pkg/arvo/app/hark-group-hook.hoon new file mode 100644 index 000000000..4b685c938 --- /dev/null +++ b/pkg/arvo/app/hark-group-hook.hoon @@ -0,0 +1,169 @@ +:: hark-group-hook: notifications for groups [landscape] +:: +/- store=hark-store, post, group-store, metadata-store, hook=hark-group-hook +/+ resource, metadata, default-agent, dbug, graph-store +:: +~% %hark-group-hook-top ..is ~ +|% ++$ card card:agent:gall ++$ versioned-state + $% state-0 + == +:: ++$ state-0 + $: %0 + watching=(set resource) + == +:: +-- +:: +=| state-0 +=* state - +:: +=< +%- agent:dbug +^- agent:gall +~% %hark-group-hook-agent ..card ~ +|_ =bowl:gall ++* this . + ha ~(. +> bowl) + def ~(. (default-agent this %|) bowl) + met ~(. metadata bowl) +:: +++ on-init + :_ this + :~ watch-metadata:ha + watch-groups:ha + == +:: +++ on-save !>(state) +++ on-load + |= old=vase + ^- (quip card _this) + `this(state !<(state-0 old)) +:: +++ on-watch + |= =path + ?. ?=([%updates ~] path) + (on-watch:def path) + :_ this + =; =cage + [%give %fact ~ cage]~ + :- %hark-group-hook-update + !> ^- update:hook + [%initial watching] +:: +++ on-poke + ~/ %hark-group-hook-poke + |= [=mark =vase] + ^- (quip card _this) + |^ + ?> (team:title our.bowl src.bowl) + =^ cards state + ?+ mark (on-poke:def mark vase) + %hark-group-hook-action + (hark-group-hook-action !<(action:hook vase)) + == + [cards this] + :: + ++ hark-group-hook-action + |= =action:hook + ^- (quip card _state) + |^ + ?- -.action + %listen (listen +.action) + %ignore (ignore +.action) + == + ++ listen + |= group=resource + ^- (quip card _state) + :- (give %listen group) + state(watching (~(put in watching) group)) + :: + ++ ignore + |= group=resource + ^- (quip card _state) + :- (give %ignore group) + state(watching (~(del in watching) group)) + :: + ++ give + |= =update:hook + ^- (list card) + [%give %fact ~[/updates] %hark-group-hook-update !>(update)]~ + -- + -- +:: +++ on-agent + ~/ %hark-group-hook-agent + |= [=wire =sign:agent:gall] + ^- (quip card _this) + |^ + ?+ -.sign (on-agent:def wire sign) + %kick + :_ this + ?+ wire ~ + [%group ~] ~[watch-groups:ha] + [%metadata ~] ~[watch-metadata:ha] + == + :: + %fact + ?+ p.cage.sign (on-agent:def wire sign) + %group-update + =^ cards state + (group-update !<(update:group-store q.cage.sign)) + [cards this] + :: + %metadata-update + =^ cards state + (metadata-update !<(metadata-update:metadata-store q.cage.sign)) + [cards this] + == + == + :: + ++ group-update + |= =update:group-store + ^- (quip card _state) + ?. ?=(?(%add-members %remove-members) -.update) + [~ state] + ?. (~(has in watching) resource.update) + [~ state] + =/ =contents:store + [%group ~[update]] + =/ =notification:store [now.bowl %.n contents] + =/ =index:store + [%group resource.update -.update] + :_ state + ~[(add-unread index notification)] + :: +metadata-update is stubbed for now, for the following reasons + :: - There's no semantic difference in metadata-store between + :: adding and editing a channel + :: - We have no way of retrieving old metadata to e.g. get a + :: channel's old name when it is renamed + ++ metadata-update + |= update=metadata-update:metadata-store + ^- (quip card _state) + [~ state] + :: + ++ add-unread + |= [=index:store =notification:store] + ^- card + =- [%pass / %agent [our.bowl %hark-store] %poke -] + hark-action+!>([%add index notification]) + -- +:: +++ on-peek on-peek:def +++ on-leave on-leave:def +++ on-arvo on-arvo:def +++ on-fail on-fail:def +-- +|_ =bowl:gall ++* met ~(. metadata bowl) +:: +++ watch-groups + ^- card + [%pass /group %agent [our.bowl %group-store] %watch /groups] +:: +++ watch-metadata + ^- card + [%pass /metadata %agent [our.bowl %metadata-store] %watch /updates] +-- diff --git a/pkg/arvo/app/hark-store.hoon b/pkg/arvo/app/hark-store.hoon new file mode 100644 index 000000000..476ea8d92 --- /dev/null +++ b/pkg/arvo/app/hark-store.hoon @@ -0,0 +1,363 @@ +:: hark-store: notifications [landscape] +:: +/- store=hark-store, post, group-store, metadata-store +/+ resource, metadata, default-agent, dbug, graph-store +:: +~% %hark-store-top ..is ~ +|% ++$ card card:agent:gall ++$ versioned-state + $% state-0 + == +:: ++$ state-0 + $: %0 + =notifications:store + archive=notifications:store + last-seen=@da + dnd=_| + == ++$ inflated-state + $: state-0 + cache + == +:: $cache: useful to have precalculated, but can be derived from state +:: albeit expensively ++$ cache + $: unread-count=@ud + by-index=(jug index:store @da) + ~ + == +:: +++ orm ((ordered-map @da timebox:store) gth) +-- +:: +=| inflated-state +=* state - +:: +=< +%- agent:dbug +^- agent:gall +~% %hark-store-agent ..card ~ +|_ =bowl:gall ++* this . + ha ~(. +> bowl) + def ~(. (default-agent this %|) bowl) + met ~(. metadata bowl) +:: +++ on-init + :_ this + ~[autoseen-timer] +:: +++ on-save !>(-.state) +++ on-load + |= =old=vase + ^- (quip card _this) + =/ old + !<(state-0 old-vase) + =. notifications.old + (gas:orm *notifications:store (tap:orm notifications.old)) + =. archive.old + (gas:orm *notifications:store (tap:orm archive.old)) + `this(-.state old, +.state (inflate-cache old)) +:: +++ on-watch + |= =path + ^- (quip card _this) + |^ + ?+ path (on-watch:def path) + :: + [%updates ~] + :_ this + [%give %fact ~ hark-update+!>(initial-updates)]~ + == + :: + ++ initial-updates + ^- update:store + :- %more + ^- (list update:store) + :- unreads + :+ [%set-dnd dnd] + [%count unread-count] + %+ weld + %+ turn + %+ scag 3 + (tap-nonempty:ha archive) + (timebox-update &) + %+ turn + %+ scag 3 + (tap-nonempty:ha notifications) + (timebox-update |) + :: + ++ unreads + ^- update:store + :- %unreads + ^- (list [index:store @ud]) + %+ turn + ~(tap by by-index) + |=([=index:store =(set @da)] [index ~(wyt in set)]) + :: + ++ timebox-update + |= archived=? + |= [time=@da =timebox:store] + ^- update:store + [%timebox time archived ~(tap by timebox)] + -- +:: +++ on-peek + |= =path + ^- (unit (unit cage)) + ?+ path (on-peek:def path) + :: + [%x %recent ?(%archive %inbox) @ @ ~] + =/ is-archive + =(%archive i.t.t.path) + =/ offset=@ud + (slav %ud i.t.t.t.path) + =/ length=@ud + (slav %ud i.t.t.t.t.path) + :^ ~ ~ %hark-update + !> ^- update:store + :- %more + %+ turn + %+ scag length + %+ slag offset + %- tap-nonempty:ha + ?:(is-archive archive notifications) + |= [time=@da =timebox:store] + ^- update:store + :^ %timebox time is-archive + ~(tap by timebox) + == +:: +++ on-poke + ~/ %hark-store-poke + |= [=mark =vase] + ^- (quip card _this) + |^ + ?> (team:title our.bowl src.bowl) + =^ cards state + ?+ mark (on-poke:def mark vase) + %hark-action (hark-action !<(action:store vase)) + == + [cards this] + :: + ++ hark-action + |= =action:store + ^- (quip card _state) + |^ + ?- -.action + %add (add +.action) + %archive (do-archive +.action) + %seen seen + %read (read +.action) + %read-index (read-index +.action) + %unread (unread +.action) + %set-dnd (set-dnd +.action) + == + ++ add + |= [=index:store =notification:store] + ^- (quip card _state) + =/ =timebox:store + (gut-orm:ha notifications last-seen) + =/ existing-notif + (~(get by timebox) index) + =/ new=notification:store + ?~ existing-notif + notification + (merge-notification:ha u.existing-notif notification) + =/ new-timebox=timebox:store + (~(put by timebox) index new) + :- (give:ha [/updates]~ %added last-seen index new) + %_ state + + ?~(existing-notif (upd-unreads:ha index last-seen %.n) +.state) + notifications (put:orm notifications last-seen new-timebox) + == + ++ read-index + |= =index:store + ^- (quip card _state) + =/ times=(list @da) + ~(tap in (~(gut by by-index) index ~)) + =| cards=(list card) + |- + ?~ times + [cards state] + =* time i.times + =^ crds state + (read time index) + $(cards (weld cards crds), times t.times) + :: + ++ do-archive + |= [time=@da =index:store] + ^- (quip card _state) + =/ =timebox:store + (gut-orm:ha notifications time) + =/ =notification:store + (~(got by timebox) index) + =/ new-timebox=timebox:store + (~(del by timebox) index) + :- (give:ha [/updates]~ %archive time index) + %_ state + + ?.(read.notification (upd-unreads:ha index time %.y) +.state) + :: + notifications + (put:orm notifications time new-timebox) + :: + archive + %^ jub-orm:ha archive time + |= archive-box=timebox:store + ^- timebox:store + (~(put by archive-box) index notification(read %.y)) + == + :: + ++ read + |= [time=@da =index:store] + ^- (quip card _state) + :- (give:ha [/updates]~ %read time index) + %_ state + + (upd-unreads:ha index time %.y) + unread-count (dec unread-count) + notifications (change-read-status:ha time index %.y) + == + :: + ++ unread + |= [time=@da =index:store] + ^- (quip card _state) + :- (give:ha [/updates]~ %unread time index) + %_ state + + (upd-unreads:ha index time %.n) + unread-count +(unread-count) + notifications (change-read-status:ha time index %.n) + == + :: + ++ seen + ^- (quip card _state) + :_ state(last-seen now.bowl) + :~ cancel-autoseen:ha + autoseen-timer:ha + == + :: + ++ set-dnd + |= d=? + ^- (quip card _state) + :_ state(dnd d) + (give:ha [/updates]~ %set-dnd d) + -- + -- +:: +++ on-agent on-agent:def +:: +++ on-leave on-leave:def +++ on-arvo + |= [=wire =sign-arvo] + ^- (quip card _this) + ?. ?=([%autoseen ~] wire) + (on-arvo:def wire sign-arvo) + ?> ?=([%b %wake *] sign-arvo) + :_ this(last-seen now.bowl) + ~[autoseen-timer:ha] +:: +++ on-fail on-fail:def +-- +|_ =bowl:gall ++* met ~(. metadata bowl) +:: +++ tap-nonempty + |= =notifications:store + ^- (list [@da timebox:store]) + %+ skip (tap:orm notifications) + |=([@da =timebox:store] =(0 ~(wyt by timebox))) +:: +++ merge-notification + |= [existing=notification:store new=notification:store] + ^- notification:store + ?- -.contents.existing + :: + %chat + ?> ?=(%chat -.contents.new) + existing(list.contents (weld list.contents.existing list.contents.new)) + :: + %graph + ?> ?=(%graph -.contents.new) + existing(list.contents (weld list.contents.existing list.contents.new)) + :: + %group + ?> ?=(%group -.contents.new) + existing(list.contents (weld list.contents.existing list.contents.new)) + == +:: +++ change-read-status + |= [time=@da =index:store read=?] + ^+ notifications + %^ jub-orm notifications time + |= =timebox:store + %+ ~(jab by timebox) index + |= =notification:store + ?> !=(read read.notification) + notification(read read) +:: +key-orm: +key:by for ordered maps +++ key-orm + |= =notifications:store + ^- (list @da) + (turn (tap:orm notifications) |=([key=@da =timebox:store] key)) +:: +jub-orm: combo +jab/+gut for ordered maps +:: TODO: move to zuse.hoon +++ jub-orm + |= [=notifications:store time=@da fun=$-(timebox:store timebox:store)] + ^- notifications:store + =/ =timebox:store + (fun (gut-orm notifications time)) + (put:orm notifications time timebox) +:: +gut-orm: +gut:by for ordered maps +:: TODO: move to zuse.hoon +++ gut-orm + |= [=notifications:store time=@da] + ^- timebox:store + (fall (get:orm notifications time) ~) +:: +++ autoseen-interval ~h3 +++ cancel-autoseen + ^- card + [%pass /autoseen %arvo %b %rest (add last-seen autoseen-interval)] +:: +++ autoseen-timer + ^- card + [%pass /autoseen %arvo %b %wait (add now.bowl autoseen-interval)] +:: +++ give + |= [paths=(list path) update=update:store] + ^- (list card) + [%give %fact paths [%hark-update !>(update)]]~ +:: +++ upd-unreads + |= [=index:store time=@da read=?] + ^+ +.state + %_ +.state + :: + by-index + %. [index time] + ?: read + ~(del ju by-index) + ~(put ju by-index) + == +:: +++ inflate-cache + |= state-0 + ^+ +.state + =/ nots=(list [p=@da =timebox:store]) + (tap:orm notifications) + |- =* outer $ + ?~ nots + +.state + =/ unreads ~(tap by timebox.i.nots) + |- =* inner $ + ?~ unreads + outer(nots t.nots) + =* notification q.i.unreads + =* index p.i.unreads + ?: read.notification + inner(unreads t.unreads) + =. +.state + (upd-unreads index p.i.nots %.n) + inner(unreads t.unreads) +-- diff --git a/pkg/arvo/app/herm.hoon b/pkg/arvo/app/herm.hoon new file mode 100644 index 000000000..4434685c3 --- /dev/null +++ b/pkg/arvo/app/herm.hoon @@ -0,0 +1,101 @@ +:: herm: stand-in for term.c with http interface +:: +/+ default-agent, dbug, verb +=, able:jael +|% ++$ state-0 [%0 ~] +-- +:: +=| state-0 +=* state - +%+ verb | +%- agent:dbug +^- agent:gall +=> |% + ++ request-tube + |= [bowl:gall from=mark to=mark next=?] + ^- card:agent:gall + :* %pass /tube/[from]/[to] + %arvo %c %warp + our q.byk ~ + :: + ?: next + [%next %c da+now /[from]/[to]] + [%sing %c da+now /[from]/[to]] + == + -- +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) +:: +++ on-init + ^- (quip card:agent:gall _this) + :_ this + :: set up dill session subscription, + :: and ensure the tubes we use are in cache + :: + :~ [%pass [%view %$ ~] %arvo %d %view ~] + (request-tube bowl %blit %json |) + (request-tube bowl %json %belt |) + == +:: +++ on-save !>([%0 ~]) +++ on-load + |= old=vase + ^- (quip card:agent:gall _this) + [~ this(state [%0 ~])] +:: +++ on-watch + |= =path + ^- (quip card:agent:gall _this) + ?> ?=([%session @ ~] path) + :_ this + :: scry prompt and cursor position out of dill for initial response + :: + =/ base=^path + /dx/(scot %p our.bowl)//(scot %da now.bowl)/sessions + :~ [%give %fact ~ %blit !>(.^(blit:dill (weld base //line)))] + [%give %fact ~ %blit !>(`blit:dill`hop+.^(@ud (weld base //cursor)))] + == +:: +++ on-arvo + |= [=wire =sign-arvo] + ^- (quip card:agent:gall _this) + ?+ wire !! + :: pass on dill blits for the session + :: + [%view %$ ~] + ?. ?=([%d %blit *] sign-arvo) + ~| [%unexpected-sign [- +<]:sign-arvo] + !! + :_ this + %+ turn p.sign-arvo + |= =blit:dill + [%give %fact [%session %$ ~]~ %blit !>(blit)] + :: + :: ensure the tubes we need remain in cache + :: + [%tube @ @ ~] + =* from i.t.wire + =* to i.t.t.wire + ?. ?=([%c %writ *] sign-arvo) + ~| [%unexpected-sign [- +<]:sign-arvo] + !! + :_ this + [(request-tube bowl from to &)]~ + == +:: +++ on-poke + |= [=mark =vase] + ^- (quip card:agent:gall _this) + ?. ?=(%belt mark) + ~| [%unexpected-mark mark] + !! + :_ this + [%pass [%belt %$ ~] %arvo %d %belt !<(belt:dill vase)]~ +:: +++ on-leave on-leave:def +++ on-peek on-peek:def +++ on-agent on-agent:def +++ on-fail on-fail:def +-- diff --git a/pkg/arvo/app/hood.hoon b/pkg/arvo/app/hood.hoon index 433ccb2e4..7ea33fe6b 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 - $: %10 + $: %11 drum=state:drum helm=state:helm kiln=state:kiln @@ -13,6 +13,7 @@ [%7 drum=state:drum helm=state:helm kiln=state:kiln] [%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] == +$ any-state-tuple $: drum=any-state:drum diff --git a/pkg/arvo/app/invite-hook.hoon b/pkg/arvo/app/invite-hook.hoon index 0e7b93d97..8cde26eb6 100644 --- a/pkg/arvo/app/invite-hook.hoon +++ b/pkg/arvo/app/invite-hook.hoon @@ -1,123 +1,121 @@ -:: invite-hook [landscape]: +:: invite-hook [landscape]: receive invites from any source :: -:: receive invites from any source +:: only handles %invite actions: +:: - can be poked by the host team to send an invite out to someone. +:: - can be poked by foreign ships to send an invite to us. :: -:: only handles %invite actions. accepts json, but only from the host team. -:: can be poked by the host team to send an invite out to someone. -:: can be poked by foreign ships to send an invite to us. -:: -/+ *invite-json, default-agent, verb, dbug +/- *invite-store +/+ default-agent, dbug :: |% +$ state-0 [%0 ~] -:: +$ card card:agent:gall -- :: =| state-0 =* state - -:: -%+ verb | %- agent:dbug ^- agent:gall -=< - |_ =bowl:gall - +* this . - do ~(. +> bowl) - def ~(. (default-agent this %|) bowl) - :: - ++ on-init - ^- (quip card _this) - [~ this] - :: - ++ on-save !>(state) - ++ on-load - |= old=vase - ^- (quip card _this) - [~ this(state !<(state-0 old))] - :: - ++ on-poke - |= [=mark =vase] - ^- (quip card _this) - :_ this - ?+ mark (on-poke:def mark vase) - %json - :: only accept json from ourselves. +:: +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) +:: +++ on-init [~ this] +++ on-save !>(state) +++ on-load + |= old=vase + ^- (quip card _this) + [~ this(state !<(state-0 old))] +:: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + |^ + :_ this + ?+ mark (on-poke:def mark vase) + %invite-action + =/ act=action !<(action vase) + ?+ -.act ~ + %invites + ?. (team:title [our src]:bowl) ~ + :: outgoing. we must be inviting other ships. send them each an invite :: - ?> (team:title our.bowl src.bowl) - =/ act (json-to-action !<(json vase)) - ?> ?=(%invite -.act) - [(invite-hook-poke:do recipient.invite.act act)]~ + %+ turn ~(tap in recipients.invites.act) + |= recipient=ship + ^- card + ?< (team:title our.bowl recipient) + %+ invite-hook-poke recipient + :^ %invite term.act uid.act + ^- invite + :* ship.invites.act + app.invites.act + resource.invites.act + recipient + text.invites.act + == :: - %invite-action - =/ act=invite-action !<(invite-action vase) - ?. ?=(%invite -.act) ~ - ?: (team:title our.bowl src.bowl) + %invite + ?: (team:title [our src]:bowl) :: outgoing. we must be inviting another ship. send them the invite. :: ?< (team:title our.bowl recipient.invite.act) - [(invite-hook-poke:do recipient.invite.act act)]~ + [(invite-hook-poke recipient.invite.act act)]~ :: else incoming. ensure invitatory exists and invite is not a duplicate. :: - ?> ?=(^ (invitatory-scry:do path.act)) - ?> ?=(~ (invite-scry:do path.act uid.act)) - [(invite-poke:do path.act act)]~ + ?> ?=(^ (invitatory-scry term.act)) + ?> ?=(~ (invite-scry term.act uid.act)) + [(invite-poke term.act act)]~ + == + == + :: + ++ invite-hook-poke + |= [=ship =action] + ^- card + :* %pass + /invite-hook + %agent + [ship %invite-hook] + %poke + %invite-action + !>(action) == :: - ++ on-peek on-peek:def - ++ on-watch on-watch:def - ++ on-leave on-leave:def - ++ on-agent on-agent:def - ++ on-arvo on-arvo:def - ++ on-fail on-fail:def + ++ invite-poke + |= [=term =action] + ^- card + :* %pass + /[term] + %agent + [our.bowl %invite-store] + %poke + %invite-action + !>(action) + == + :: + ++ invitatory-scry + |= =term + .^ (unit invitatory) + %gx + %+ weld + /(scot %p our.bowl)/invite-store/(scot %da now.bowl)/invitatory + /[term]/noun + == + :: + ++ invite-scry + |= [=term uid=serial] + .^ (unit invite) + %gx + %+ weld + /(scot %p our.bowl)/invite-store/(scot %da now.bowl)/invite + /[term]/(scot %uv uid)/noun + == -- :: -|_ =bowl:gall -:: -++ invite-hook-poke - |= [=ship action=invite-action] - ^- card - :* %pass - /invite-hook - %agent - [ship %invite-hook] - %poke - %invite-action - !>(action) - == -:: -++ invite-poke - |= [=path action=invite-action] - ^- card - :* %pass - path - %agent - [our.bowl %invite-store] - %poke - %invite-action - !>(action) - == -:: -++ invitatory-scry - |= pax=path - ^- (unit invitatory) - =. pax - ;: weld - /(scot %p our.bowl)/invite-store/(scot %da now.bowl)/invitatory - pax - /noun - == - .^((unit invitatory) %gx pax) -:: -++ invite-scry - |= [pax=path uid=serial] - ^- (unit invite) - =. pax - ;: weld - /(scot %p our.bowl)/invite-store/(scot %da now.bowl)/invite - pax - /(scot %uv uid)/noun - == - .^((unit invite) %gx pax) +++ on-peek on-peek:def +++ on-watch on-watch:def +++ 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/invite-store.hoon b/pkg/arvo/app/invite-store.hoon index c09bd4cba..258f61a4c 100644 --- a/pkg/arvo/app/invite-store.hoon +++ b/pkg/arvo/app/invite-store.hoon @@ -1,184 +1,209 @@ :: invite-store [landscape] -/+ *invite-json, default-agent, dbug +/- store=invite-store +/+ res=resource, default-agent, dbug |% +$ card card:agent:gall -:: +$ versioned-state - $% state-zero + $% state-0 + state-1 == :: -+$ state-zero - $: %0 - =invites ++$ invitatory-0 (map serial:store invite-0) ++$ invite-0 + $: =ship :: ship to subscribe to upon accepting invite + app=@tas :: app to subscribe to upon accepting invite + =path :: path to subscribe to upon accepting invite + recipient=ship :: recipient to receive invite + text=cord :: text to describe the invite == +:: ++$ state-0 [%0 invites=(map path invitatory-0)] ++$ state-1 [%1 =invites:store] -- :: -=| state-zero +=| state-1 =* state - %- agent:dbug ^- agent:gall -=< - |_ bol=bowl:gall - +* this . - inv-core +> - ic ~(. inv-core bol) - def ~(. (default-agent this %|) bol) - ++ on-init on-init:def - ++ on-save !>(state) - ++ on-load - |= old=vase - `this(state !<(state-zero old)) +:: +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) +:: +++ on-init + ^- (quip card _this) + :- ~ + %_ this + invites.state + %- ~(gas by *invites:store) + [%graph *invitatory:store]~ + == +:: +++ on-save !>(state) +++ on-load + |= old-vase=vase + =/ old !<(versioned-state old-vase) + ?: ?=(%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 + == + == +:: +++ on-agent on-agent:def +++ on-arvo on-arvo:def +++ on-leave on-leave:def +++ on-fail on-fail:def +:: +++ on-watch + |= =path + ^- (quip card _this) + ?> (team:title our.bowl src.bowl) + =/ cards=(list card) + ?+ path (on-watch:def path) + [%all ~] [%give %fact ~ %invite-update !>([%initial invites])]~ + [%updates ~] ~ + [%invitatory @ ~] + =/ inv=invitatory:store (~(got by invites) i.t.path) + [%give %fact ~ %invite-update !>([%invitatory inv])]~ + == + [cards this] +:: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + |^ + ?> (team:title our.bowl src.bowl) + =^ cards state + ?+ mark (on-poke:def mark vase) + %invite-action (poke-invite-action !<(action:store vase)) + == + [cards this] :: - ++ on-poke - |= [=mark =vase] - ^- (quip card _this) - ?> (team:title our.bol src.bol) - =^ cards state - ?+ mark (on-poke:def mark vase) - %json (poke-invite-action:ic (json-to-action !<(json vase))) - %invite-action (poke-invite-action:ic !<(invite-action vase)) - == - [cards this] - :: - ++ on-watch - |= =path - ^- (quip card _this) - =/ cards=(list card) - ?+ path (on-watch:def path) - [%all ~] [%give %fact ~ %invite-update !>([%initial invites])]~ - [%updates ~] ~ - [%invitatory *] - =/ inv=invitatory (~(got by invites) t.path) - [%give %fact ~ %invite-update !>([%invitatory inv])]~ - == - [cards this] - :: - ++ on-leave on-leave:def - ++ on-peek - |= =path - ^- (unit (unit cage)) - ?+ path (on-peek:def path) - [%x %all ~] (peek-x-all:ic t.t.path) - [%x %invitatory *] (peek-x-invitatory:ic t.t.path) - [%x %invite *] (peek-x-invite:ic t.t.path) + ++ poke-invite-action + |= =action:store + ^- (quip card _state) + ?- -.action + %create (handle-create +.action) + %delete (handle-delete +.action) + %invite (handle-invite +.action) + %accept (handle-accept +.action) + %decline (handle-decline +.action) + %invites ~|('only send this to %invite-hook' !!) == :: - ++ on-agent on-agent:def - ++ on-arvo on-arvo:def - ++ on-fail on-fail:def + ++ handle-create + |= =term + ^- (quip card _state) + ?: (~(has by invites) term) + [~ state] + :- (send-diff term [%create term]) + state(invites (~(put by invites) term *invitatory:store)) + :: + ++ handle-delete + |= =term + ^- (quip card _state) + ?. (~(has by invites) term) + [~ state] + :- (send-diff term [%delete term]) + state(invites (~(del by invites) term)) + :: + ++ handle-invite + |= [=term =serial:store =invite:store] + ^- (quip card _state) + ?. (~(has by invites) term) + [~ state] + =/ container (~(got by invites) term) + =. serial (sham eny.bowl) + =. container (~(put by container) serial invite) + :- (send-diff term [%invite term serial invite]) + state(invites (~(put by invites) term container)) + :: + ++ handle-accept + |= [=term =serial:store] + ^- (quip card _state) + ?. (~(has by invites) term) + [~ state] + =/ container (~(got by invites) term) + =/ invite (~(get by container) serial) + ?~ invite + [~ state] + =. container (~(del by container) serial) + :- (send-diff term [%accepted term serial u.invite]) + state(invites (~(put by invites) term container)) + :: + ++ handle-decline + |= [=term =serial:store] + ^- (quip card _state) + ?. (~(has by invites) term) + [~ state] + =/ container (~(got by invites) term) + =/ invite (~(get by container) serial) + ?~ invite + [~ state] + =. container (~(del by container) serial) + :- (send-diff term [%decline term serial]) + state(invites (~(put by invites) term container)) + :: + ++ update-subscribers + |= [=path =update:store] + ^- card + [%give %fact ~[path] %invite-update !>(update)] + :: + ++ send-diff + |= [=term =update:store] + ^- (list card) + :~ (update-subscribers /all update) + (update-subscribers /updates update) + (update-subscribers /invitatory/[term] update) + == -- :: -|_ bol=bowl:gall -:: -++ peek-x-all - |= pax=path +++ on-peek + |= =path ^- (unit (unit cage)) - [~ ~ %noun !>(invites)] -:: -++ peek-x-invitatory - |= pax=path - ^- (unit (unit cage)) - ?~ pax - ~ - =/ invitatory=(unit invitatory) (~(get by invites) pax) - [~ ~ %noun !>(invitatory)] -:: -++ peek-x-invite - |= pax=path - ^- (unit (unit cage)) - :: /:path/:uid - =/ pas (flop pax) - ?~ pas - ~ - =/ uid=serial (slav %uv i.pas) - =. pax (scag (dec (lent pax)) `(list @ta)`pax) - =/ invitatory=(unit invitatory) (~(get by invites) pax) - ?~ invitatory - ~ - =/ invite=(unit invite) (~(get by u.invitatory) uid) - [~ ~ %noun !>(invite)] -:: -++ poke-invite-action - |= action=invite-action - ^- (quip card _state) - ?> (team:title our.bol src.bol) - ?- -.action - %create (handle-create action) - %delete (handle-delete action) - %invite (handle-invite action) - %accept (handle-accept action) - %decline (handle-decline action) + ?+ path (on-peek:def path) + [%x %all ~] + ``noun+!>(invites) + :: + [%x %invitatory @ ~] + :^ ~ ~ %noun + !> ^- (unit invitatory:store) + (~(get by invites) i.t.t.path) + :: + [%x %invite @ @ ~] + =* term i.t.t.path + =/ =serial:store (slav %uv i.t.t.t.path) + ?. (~(has by invites) term) + ~ + =/ =invitatory:store (~(got by invites) term) + :^ ~ ~ %noun + !> ^- (unit invite:store) + (~(get by invitatory) serial) == -:: -++ handle-create - |= act=invite-action - ^- (quip card _state) - ?> ?=(%create -.act) - ?: (~(has by invites) path.act) - [~ state] - :- (send-diff path.act act) - state(invites (~(put by invites) path.act *invitatory)) -:: -++ handle-delete - |= act=invite-action - ^- (quip card _state) - ?> ?=(%delete -.act) - ?. (~(has by invites) path.act) - [~ state] - :- (send-diff path.act act) - state(invites (~(del by invites) path.act)) -:: -++ handle-invite - |= act=invite-action - ^- (quip card _state) - ?> ?=(%invite -.act) - ?. (~(has by invites) path.act) - [~ state] - =/ container (~(got by invites) path.act) - =. uid.act (sham eny.bol) - =. container (~(put by container) uid.act invite.act) - :- (send-diff path.act act) - state(invites (~(put by invites) path.act container)) -:: -++ handle-accept - |= act=invite-action - ^- (quip card _state) - ?> ?=(%accept -.act) - ?. (~(has by invites) path.act) - [~ state] - =/ container (~(got by invites) path.act) - =/ invite (~(get by container) uid.act) - ?~ invite - [~ state] - =. container (~(del by container) uid.act) - :- (send-diff path.act [%accepted path.act uid.act u.invite]) - state(invites (~(put by invites) path.act container)) -:: -++ handle-decline - |= act=invite-action - ^- (quip card _state) - ?> ?=(%decline -.act) - ?. (~(has by invites) path.act) - [~ state] - =/ container (~(got by invites) path.act) - =/ invite (~(get by container) uid.act) - ?~ invite - [~ state] - =. container (~(del by container) uid.act) - :- (send-diff path.act act) - state(invites (~(put by invites) path.act container)) -:: -++ update-subscribers - |= [pax=path upd=invite-update] - ^- card - [%give %fact ~[pax] %invite-update !>(upd)] -:: -++ send-diff - |= [pax=path upd=invite-update] - ^- (list card) - :~ (update-subscribers /all upd) - (update-subscribers /updates upd) - (update-subscribers [%invitatory pax] upd) - == -:: -- diff --git a/pkg/arvo/app/landscape/img/chat.png b/pkg/arvo/app/landscape/img/chat.png deleted file mode 100644 index 58223a5d6..000000000 Binary files a/pkg/arvo/app/landscape/img/chat.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/chatswitcherclosed.png b/pkg/arvo/app/landscape/img/chatswitcherclosed.png deleted file mode 100644 index 2009b319b..000000000 Binary files a/pkg/arvo/app/landscape/img/chatswitcherclosed.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/chatswitcherlink.png b/pkg/arvo/app/landscape/img/chatswitcherlink.png deleted file mode 100644 index 9b47164dd..000000000 Binary files a/pkg/arvo/app/landscape/img/chatswitcherlink.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/chevron.png b/pkg/arvo/app/landscape/img/chevron.png deleted file mode 100644 index 79eada831..000000000 Binary files a/pkg/arvo/app/landscape/img/chevron.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/codeeval.png b/pkg/arvo/app/landscape/img/codeeval.png deleted file mode 100644 index 8bcb81ca6..000000000 Binary files a/pkg/arvo/app/landscape/img/codeeval.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/dojo.png b/pkg/arvo/app/landscape/img/dojo.png deleted file mode 100644 index d6b651bc5..000000000 Binary files a/pkg/arvo/app/landscape/img/dojo.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/link.png b/pkg/arvo/app/landscape/img/link.png deleted file mode 100644 index d83bb877c..000000000 Binary files a/pkg/arvo/app/landscape/img/link.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/links.png b/pkg/arvo/app/landscape/img/links.png deleted file mode 100644 index d83bb877c..000000000 Binary files a/pkg/arvo/app/landscape/img/links.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/popout.png b/pkg/arvo/app/landscape/img/popout.png deleted file mode 100644 index 712c2ab2f..000000000 Binary files a/pkg/arvo/app/landscape/img/popout.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/publish.png b/pkg/arvo/app/landscape/img/publish.png deleted file mode 100644 index df16b2647..000000000 Binary files a/pkg/arvo/app/landscape/img/publish.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/search.png b/pkg/arvo/app/landscape/img/search.png deleted file mode 100644 index 7ac218304..000000000 Binary files a/pkg/arvo/app/landscape/img/search.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/send.png b/pkg/arvo/app/landscape/img/send.png deleted file mode 100644 index 6c13772b9..000000000 Binary files a/pkg/arvo/app/landscape/img/send.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/img/spinner.png b/pkg/arvo/app/landscape/img/spinner.png deleted file mode 100644 index 8fddc7895..000000000 Binary files a/pkg/arvo/app/landscape/img/spinner.png and /dev/null differ diff --git a/pkg/arvo/app/landscape/index.html b/pkg/arvo/app/landscape/index.html index cab16a450..a2a06dea1 100644 --- a/pkg/arvo/app/landscape/index.html +++ b/pkg/arvo/app/landscape/index.html @@ -24,6 +24,6 @@
- + diff --git a/pkg/arvo/app/launch.hoon b/pkg/arvo/app/launch.hoon index eddf976c5..16997bfc0 100644 --- a/pkg/arvo/app/launch.hoon +++ b/pkg/arvo/app/launch.hoon @@ -12,6 +12,7 @@ [%3 *] [%4 state-zero] [%5 state-zero] + [%6 state-zero] == :: +$ state-zero @@ -21,7 +22,7 @@ == -- :: -=| [%5 state-zero] +=| [%6 state-zero] =* state - %- agent:dbug ^- agent:gall @@ -36,27 +37,42 @@ %_ new-state tiles %- ~(gas by *tiles:store) - %+ turn `(list term)`[%weather %clock %dojo ~] + %+ turn `(list term)`[%weather %clock %term ~] |= =term :- term ^- tile:store - ?+ term [[%custom ~] %.y] - %dojo [[%basic 'Dojo' '/~landscape/img/Dojo.png' '/~dojo'] %.y] + ?+ term [[%custom ~] %.y] + %term [[%basic 'Terminal' '/~landscape/img/term.png' '/~term'] %.y] == - tile-ordering [%weather %clock %dojo ~] + tile-ordering [%weather %clock %term ~] == - [~ this(state [%5 new-state])] + [~ this(state [%6 new-state])] :: ++ on-save !>(state) ++ on-load |= old=vase ^- (quip card _this) =/ old-state !<(versioned-state old) - |- + =| cards=(list card) + |- ^- (quip card _this) + ?: ?=(%6 -.old-state) + [cards this(state old-state)] ?: ?=(%5 -.old-state) - `this(state old-state) + :: replace %dojo with %term + :: + =. tiles.old-state + %+ ~(put by (~(del by tiles.old-state) %dojo)) + %term + :_ is-shown:(~(gut by tiles.old-state) %dojo *tile:store) + [%basic 'Terminal' '/~landscape/img/term.png' '/~term'] + =. tile-ordering.old-state + %+ turn tile-ordering.old-state + |=(t=term ?:(=(%dojo t) %term t)) + $(old-state [%6 +.old-state]) ?: ?=(%4 -.old-state) - :- [%pass / %arvo %e %disconnect [~ /]]~ + =. cards + %+ snoc cards + [%pass / %arvo %e %disconnect [~ /]] =. tiles.old-state (~(del by tiles.old-state) %chat) =. tiles.old-state @@ -65,7 +81,7 @@ (~(del by tiles.old-state) %links) =. tile-ordering.old-state (skip tile-ordering.old-state |=(=term ?=(?(%links %chat %publish) term))) - this(state [%5 +.old-state]) + $(old-state [%5 +.old-state]) =/ new-state *state-zero =. new-state %_ new-state @@ -80,18 +96,22 @@ == tile-ordering [%weather %clock %dojo ~] == - :_ this(state [%5 new-state]) - %+ welp - :~ [%pass / %arvo %e %disconnect [~ /]] - :* %pass /srv %agent [our.bowl %file-server] - %poke %file-server-action - !>([%serve-dir / /app/landscape %.n %.y]) - == - == - %+ turn ~(tap by wex.bowl) - |= [[=wire =ship =term] *] - ^- card - [%pass wire %agent [ship term] %leave ~] + %_ $ + old-state [%5 new-state] + :: + cards + %+ welp + :~ [%pass / %arvo %e %disconnect [~ /]] + :* %pass /srv %agent [our.bowl %file-server] + %poke %file-server-action + !>([%serve-dir / /app/landscape %.n %.y]) + == + == + %+ turn ~(tap by wex.bowl) + |= [[=wire =ship =term] *] + ^- card + [%pass wire %agent [ship term] %leave ~] + == :: ++ on-poke |= [=mark =vase] diff --git a/pkg/arvo/app/link-store.hoon b/pkg/arvo/app/link-store.hoon index 0d8f472cf..d653e7748 100644 --- a/pkg/arvo/app/link-store.hoon +++ b/pkg/arvo/app/link-store.hoon @@ -116,7 +116,7 @@ |= [=resource =graph:gra] ^- card %- poke-graph-store - [%0 now.bowl %add-graph resource graph `%graph-validator-link] + [%0 now.bowl %add-graph resource graph `%graph-validator-link %.y] :: ++ archive-graph |= =resource diff --git a/pkg/arvo/app/metadata-store.hoon b/pkg/arvo/app/metadata-store.hoon index 78f5dd04a..ec32cf818 100644 --- a/pkg/arvo/app/metadata-store.hoon +++ b/pkg/arvo/app/metadata-store.hoon @@ -10,7 +10,7 @@ :: encode group-path and app-path using (scot %t (spat group-path)) :: :: +watch paths: -:: /all assocations + updates +:: /all associations + updates :: /updates just updates :: /app-name/%app-name specific app's associations + updates :: @@ -57,6 +57,7 @@ +$ state-3 [%3 base-state-1] +$ state-4 [%4 base-state-1] +$ state-5 [%5 base-state-1] ++$ state-6 [%6 base-state-1] +$ versioned-state $% state-0 state-1 @@ -64,10 +65,11 @@ state-3 state-4 state-5 + state-6 == -- :: -=| state-5 +=| state-6 =* state - %+ verb | %- agent:dbug @@ -86,29 +88,37 @@ =/ old !<(versioned-state vase) =| cards=(list card) |^ - ?: ?=(%5 -.old) + ?: ?=(%6 -.old) [cards this(state old)] - ?: ?=(%4 -.old) - %_ $ - -.old %5 - :: - group-indices.old - %- ~(gas ju *(jug group-path md-resource)) - ~(tap in ~(key by associations.old)) - :: - app-indices.old - %- ~(gas ju *(jug app-name [group-path app-path])) - %+ turn ~(tap in ~(key by associations.old)) - |= [g=group-path r=md-resource] - ^- [app-name [group-path app-path]] - [app-name.r [g app-path.r]] + ?: ?=(%5 -.old) + =/ =^associations + (migrate-app-to-graph-store %publish associations.old) + %_ $ + -.old %6 + associations.old associations :: resource-indices.old - %- ~(gas ju *(jug md-resource group-path)) - %+ turn ~(tap in ~(key by associations.old)) - |= [g=group-path r=md-resource] - ^- [md-resource group-path] - [r g] + (rebuild-resource-indices associations) + :: + app-indices.old + (rebuild-app-indices associations) + :: + group-indices.old + (rebuild-group-indices associations) + == + + ?: ?=(%4 -.old) + %_ $ + -.old %5 + :: + resource-indices.old + (rebuild-resource-indices associations.old) + :: + app-indices.old + (rebuild-app-indices associations.old) + :: + group-indices.old + (rebuild-group-indices associations.old) == ?: ?=(%3 -.old) $(old [%4 +.old]) @@ -147,6 +157,43 @@ == $(old new-state-1) :: + ++ rebuild-resource-indices + |= =^associations + %- ~(gas ju *(jug md-resource group-path)) + %+ turn ~(tap in ~(key by associations)) + |= [g=group-path r=md-resource] + ^- [md-resource group-path] + [r g] + :: + ++ rebuild-group-indices + |= =^associations + %- ~(gas ju *(jug group-path md-resource)) + ~(tap in ~(key by associations)) + :: + ++ rebuild-app-indices + |= =^associations + %- ~(gas ju *(jug app-name [group-path app-path])) + %+ turn ~(tap in ~(key by associations)) + |= [g=group-path r=md-resource] + ^- [app-name [group-path app-path]] + [app-name.r [g app-path.r]] + + :: + ++ migrate-app-to-graph-store + |= [app=@tas =^associations] + ^+ associations + %- malt + %+ turn ~(tap by associations) + |= [[=group-path =md-resource] m=metadata] + ^- [[^group-path ^md-resource] metadata] + ?. =(app-name.md-resource app) + [[group-path md-resource] m] + =/ new-app-path=path + ?. ?=([@ @ ~] app-path.md-resource) + app-path.md-resource + ship+app-path.md-resource + [[group-path [%graph new-app-path]] m(module app)] + :: ++ poke-md-hook |= act=metadata-hook-action ^- card diff --git a/pkg/arvo/app/observe-hook.hoon b/pkg/arvo/app/observe-hook.hoon new file mode 100644 index 000000000..174b90b13 --- /dev/null +++ b/pkg/arvo/app/observe-hook.hoon @@ -0,0 +1,222 @@ +:: observe-hook: +:: +:: helper that observes an app at a particular path and forwards all facts +:: to a particular thread. kills the subscription if the thread crashes +:: +/- sur=observe-hook +/+ default-agent, dbug +:: +|% ++$ card card:agent:gall ++$ versioned-state + $% state-0 + == +:: ++$ serial @uv ++$ state-0 [%0 observers=(map serial observer:sur)] +++ got-by-val + |= [a=(map serial observer:sur) b=observer:sur] + ^- serial + %- need + %+ roll ~(tap by a) + |= [[key=serial val=observer:sur] output=(unit serial)] + ?:(=(val b) `key output) +-- +:: +%- agent:dbug +=| state-0 +=* state - +:: +^- agent:gall +|_ =bowl:gall ++* this . + def ~(. (default-agent this %|) bowl) +:: +++ on-init + |^ ^- (quip card _this) + :_ this + :_ ~ + (act /inv-gra [%watch %invite-store /invitatory/graph %invite-accepted-graph]) + :: + ++ act + |= [=wire =action:sur] + ^- card + :* %pass + wire + %agent + [our.bowl %observe-hook] + %poke + %observe-action + !> ^- action:sur + action + == + -- +:: +++ on-save !>(state) +++ on-load + |= old-vase=vase + ^- (quip card _this) + `this(state !<(state-0 old-vase)) +:: +++ on-poke + |= [=mark =vase] + ^- (quip card _this) + ?> (team:title our.bowl src.bowl) + ?. ?=(%observe-action mark) + (on-poke:def mark vase) + =/ =action:sur !<(action:sur vase) + =* observer observer.action + =/ vals (silt ~(val by observers)) + ?- -.action + %watch + ?: ?|(=(app.observer %spider) =(app.observer %observe-hook)) + ~|('we avoid infinite loops' !!) + ?: (~(has in vals) observer) + ~|('duplicate observer' !!) + :_ this(observers (~(put by observers) (sham eny.bowl) observer)) + :_ ~ + :* %pass + /observer/(scot %uv (sham eny.bowl)) + %agent + [our.bowl app.observer] + %watch + path.observer + == + :: + %ignore + ?. (~(has in vals) observer) + ~|('cannot remove nonexistent observer' !!) + =/ key (got-by-val observers observer) + :_ this(observers (~(del by observers) key)) + :_ ~ + :* %pass + /observer/(scot %uv key) + %agent + [our.bowl app.observer] + %leave + ~ + == + == +:: +++ on-agent + |= [=wire =sign:agent:gall] + ^- (quip card _this) + |^ + ?+ wire (on-agent:def wire sign) + [%observer @ ~] on-observer + [%thread-result @ ~] on-thread-result + [%thread-start @ @ ~] on-thread-start + == + :: + ++ on-observer + ?> ?=([%observer @ ~] wire) + ?+ -.sign (on-agent:def wire sign) + %watch-ack + ?~ p.sign [~ this] + =/ =serial (slav %uv i.t.wire) + ~& watch-ack-deleting-observer+(~(got by observers) serial) + [~ this(observers (~(del by observers) serial))] + :: + %kick + =/ =serial (slav %uv i.t.wire) + =/ =observer:sur (~(got by observers) serial) + :_ this + :_ ~ + :* %pass + wire + %agent + [our.bowl app.observer] + %watch + path.observer + == + :: + %fact + =/ =serial (slav %uv i.t.wire) + =/ =observer:sur (~(got by observers) serial) + =/ tid (scot %uv (sham eny.bowl)) + :_ this + :~ :* %pass + [%thread-result i.t.wire ~] + %agent + [our.bowl %spider] + %watch + [%thread-result tid ~] + == + :* %pass + [%thread-start i.t.wire tid ~] + %agent + [our.bowl %spider] + %poke + %spider-start + !>([~ `tid thread.observer (slop q.cage.sign !>(~))]) + == == + == + :: + ++ on-thread-result + ?> ?=([%thread-result @ ~] wire) + ?+ -.sign (on-agent:def wire sign) + %kick [~ this] + %watch-ack [~ this] + :: + %fact + ?. =(p.cage.sign %thread-fail) + :_ this + :_ ~ + :* %pass + wire + %agent + [our.bowl %spider] + %leave + ~ + == + =/ =serial (slav %uv i.t.wire) + =/ =observer:sur (~(got by observers) serial) + ~& observer-failed+observer + :_ this(observers (~(del by observers) serial)) + :~ :* %pass + [%observer i.t.wire ~] + %agent + [our.bowl app.observer] + %leave + ~ + == + :* %pass + wire + %agent + [our.bowl %spider] + %leave + ~ + == + == + == + :: + ++ on-thread-start + ?> ?=([%thread-start @ @ ~] wire) + ?. ?=(%poke-ack -.sign) (on-agent:def wire sign) + ?~ p.sign [~ this] + =/ =serial (slav %uv i.t.wire) + =/ =observer:sur (~(got by observers) serial) + ~& added-invalid-observer+observer + :_ this(observers (~(del by observers) serial)) + :~ :* %pass + [%observer i.t.wire ~] + %agent + [our.bowl app.observer] + %leave + ~ + == + :* %pass + wire + %agent + [our.bowl app.observer] + %leave + ~ + == == + -- +:: +++ 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 +-- diff --git a/pkg/arvo/app/publish.hoon b/pkg/arvo/app/publish.hoon index cf0654df8..2588be433 100644 --- a/pkg/arvo/app/publish.hoon +++ b/pkg/arvo/app/publish.hoon @@ -8,7 +8,7 @@ /- *permission-hook /- *permission-group-hook /- *permission-store -/- *invite-store +/- inv=invite-store /- *metadata-store /- *metadata-hook /- contact-view @@ -22,6 +22,7 @@ /+ verb /+ grpl=group /+ group-store +/+ graph-store /+ resource :: ~% %publish ..is ~ @@ -52,6 +53,15 @@ == == :: ++$ state-four + [state-three migrate=migration-state] +:: +:: $migration-state: resources that are unavailable because their host +:: has not processed the ota, and number of times we've tried to reach +:: the host ++$ migration-state + (map resource @ud) +:: +$ versioned-state $% [%1 state-two] [%2 state-two] @@ -59,6 +69,7 @@ [%4 state-three] [%5 state-three] [%6 state-three] + [%7 state-four] == :: +$ metadata-delta @@ -74,7 +85,7 @@ == -- :: -=| [%6 state-three] +=| [%7 state-four] =* state - %- agent:dbug %+ verb | @@ -87,23 +98,7 @@ :: ++ on-init ^- (quip card _this) - =/ rav [%sing %t [%da now.bol] /app/publish/notebooks] - :_ this - :~ [%pass /view-bind %arvo %e %connect [~ /'publish-view'] %publish] - [%pass /read/paths %arvo %c %warp our.bol q.byk.bol `rav] - (invite-poke:main [%create /publish]) - :* %pass /invites %agent [our.bol %invite-store] %watch - /invitatory/publish - == - :* %pass / %agent [our.bol %invite-store] %poke %invite-action - !>([%create /publish]) - == - :* %pass /srv %agent [our.bol %file-server] - %poke %file-server-action - !>([%serve-dir /'~publish' /app/landscape %.n %.y]) - == - [%pass /groups %agent [our.bol %group-store] %watch /groups] - == + `this :: ++ on-save !>(state) :: @@ -122,7 +117,7 @@ :* %pass /permissions %agent [our.bol %permission-store] %watch /updates == - (invite-poke:main [%create /publish]) + (invite-poke:main [%create %publish]) :* %pass /invites %agent [our.bol %invite-store] %watch /invitatory/publish == @@ -136,10 +131,10 @@ =+ ^- [kick-cards=(list card) old-subs=(jug @tas @p)] kick-subs =/ inv-scry-pax /(scot %p our.bol)/invite-store/(scot %da now.bol)/invitatory/publish/noun - =/ inv=(unit invitatory) .^((unit invitatory) %gx inv-scry-pax) + =/ invi=(unit invitatory:inv) .^((unit invitatory:inv) %gx inv-scry-pax) =| new-state=state-two - =? tile-num.new-state ?=(^ inv) - ~(wyt by u.inv) + =? tile-num.new-state ?=(^ invi) + ~(wyt by u.invi) %= $ old-state [%& %2 new-state] :: @@ -242,8 +237,152 @@ == :: %6 + =/ [ours=(set [rid=resource nb=notebook]) theirs=(set resource)] + %+ roll ~(tap by books.p.old-state) + |= [[[who=@p book=@tas] nb=notebook] [ours=(set [resource notebook]) theirs=(set resource)]] + ^- [(set [resource notebook]) (set resource)] + =/ =resource + [who book] + ?. =(who our.bol) + ours^(~(put in theirs) resource) + :_ theirs + (~(put in ours) [resource nb]) + :: + %_ $ + p.old-state + :+ %7 +.p.old-state + %- ~(gas by *(map resource @ud)) + (turn ~(tap in theirs) (late 0)) + :: + cards + ;: weld + cards + :: move our books to graph-store + ^- (list card) + %- zing + %+ turn ~(tap in ours) + |= [rid=resource nb=notebook] + ^- (list card) + =/ =graph:graph-store + (notebook-to-graph nb) + :~ + %- poke-graph-store + :* %0 date-created.nb %add-graph + rid + graph + `%graph-validator-publish + %.y + == + (poke-graph-push %add rid) + == + :: for their books, subscribe to graph-pull-hook, to see if host has migrated + ^- (list card) + (turn ~(tap in theirs) check-host-migrate:main) + :: leave all subscriptions + ^- (list card) + %+ turn ~(tap in ~(key by wex.bol)) + |= [=wire =ship app=term] + ^- card + [%pass wire %agent [ship app] %leave ~] + == + == + :: + %7 [cards this(state p.old-state)] == + ++ blank-note-node + |= =note + %* . *node:graph-store + author.post author.note + time-sent.post date-created.note + == + :: + ++ notebook-to-graph + |= =notebook + ^- graph:graph-store + %+ gas:orm:graph-store *graph:graph-store + %+ turn ~(tap by notes.notebook) + |= [@ta =note] + ^- [atom node:graph-store] + :- date-created.note + %* . (blank-note-node note) + index.post ~[date-created.note] + :: + children + :- %graph + (note-to-revision-container notebook note) + == + :: + ++ note-to-revision-container + |= [=notebook =note] + ^- graph:graph-store + %+ gas:orm:graph-store *graph:graph-store + :~ + :- %1 + %* . (blank-note-node note) + index.post ~[date-created.note %1] + children graph+(note-to-revisions note) + == + :: + :- %2 + %* . (blank-note-node note) + index.post ~[date-created.note %2] + children (comments-to-internal-graph note) + == + == + :: + ++ note-to-revisions + |= =note + ^- graph:graph-store + %^ put:orm:graph-store + *graph:graph-store %1 + =/ body=@t + =/ file + (trip file.note) + =/ idx + (find ";>" file) + ?~ idx + file.note + %- crip + (slag (add 2 u.idx) (trip file.note)) + %* . (blank-note-node note) + index.post ~[date-created.note %1 %1] + contents.post ~[text+title.note text+body] + == + :: + ++ comments-to-internal-graph + |= =note + ^- internal-graph:graph-store + ?: =(~ comments.note) + [%empty ~] + :- %graph + %+ gas:orm:graph-store *graph:graph-store + %+ turn ~(tap by comments.note) + |= [when=@da =comment] + ^- [atom node:graph-store] + :- when + %* . *node:graph-store + author.post author.comment + index.post ~[date-created.note %2 when] + time-sent.post when + contents.post [%text content.comment]~ + == + :: + ++ poke-our + |= [app=term =cage] + [%pass / %agent [our.bol app] %poke cage] + :: + ++ poke-graph-pull + |= =action:pull-hook + (poke-our %graph-pull-hook pull-hook-action+!>(action)) + :: + ++ poke-graph-store + |= =update:graph-store + (poke-our %graph-store graph-update+!>(update)) + :: + ++ poke-graph-push + |= =action:push-hook + (poke-our %graph-push-hook push-hook-action+!>(action)) ++ convert-notebook-3-4 |= prev=notebook-3 ^- notebook-3 @@ -312,12 +451,12 @@ |= who=@p ^- card =/ uid (sham %publish who book eny.bol) - =/ inv=invite - :* our.bol %publish /notebook/[book] who + =/ =invite:inv + :* our.bol %publish [our.bol book] who (crip "invite for notebook {}/{(trip book)}") == - =/ act=invite-action [%invite /publish uid inv] - [%pass /invite %agent [who %invite-hook] %poke %invite-action !>(act)] + =/ =action:inv [%invite %publish uid invite] + [%pass /invite %agent [who %invite-hook] %poke %invite-action !>(action)] :: ++ move-files |= old-subs=(jug @tas @p) @@ -373,227 +512,49 @@ [[%pass /move-files %arvo %c %info q.byk.bol %& sob] cards] -- :: - ++ on-poke - |= [mar=mark vas=vase] - ^- (quip card _this) - ?+ mar (on-poke:def mar vas) - :: - %noun - ?+ q.vas - [~ this] - :: - %flush-limbo [~ this(limbo [~ ~])] - :: - %reset-warp - =/ rav [%sing %t [%da now.bol] /app/publish/notebooks] - :_ this - [%pass /read/paths %arvo %c %warp our.bol q.byk.bol `rav]~ - == - :: - %handle-http-request - =+ !<([id=@ta req=inbound-request:eyre] vas) - :_ this - %+ give-simple-payload:app id - %+ require-authorization:app req - handle-http-request:main - :: - %publish-action - =^ cards state - (poke-publish-action:main !<(action vas)) - [cards this] - == - :: - ++ on-watch - |= pax=path - ^- (quip card _this) - ?+ pax (on-watch:def pax) - [%http-response *] [~ this] - [%primary ~] [~ this] - [%notebook @ ~] - =^ cards state - (watch-notebook:main pax) - [cards this] - == - :: + ++ on-poke on-poke:def + ++ on-watch on-watch:def ++ on-leave on-leave:def - ++ on-peek - |= pax=path - ^- (unit (unit cage)) - ?+ pax (on-peek:def pax) - [%t %limbo ~] - :^ ~ ~ %noun - !> ^- (list path) - %+ weld - %+ turn ~(tap by notes.limbo) - |= [[who=@p book=@tas note=@tas] *] - ^- path - /(scot %p who)/[book]/[note] - %+ turn ~(tap by comments.limbo) - |= [[who=@p book=@tas note=@tas comment=@da] *] - ^- path - /(scot %p who)/[book]/[note]/(scot %ds comment) - :: - [%x %limbo @ @ @ ~] - =/ host=(unit @p) (slaw %p i.t.t.pax) - ?~ host [~ ~] - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ note (~(get by notes.limbo) u.host book-name note-name) - ?~ note ~ - ``noun+!>(u.note) - :: - [%x %limbo @ @ @ @ ~] - =/ host=(unit @p) (slaw %p i.t.t.pax) - =/ comment-date=(unit @da) (slaw %da i.t.t.t.t.t.pax) - ?~ host [~ ~] - ?~ comment-date [~ ~] - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ comment - (~(get by comments.limbo) u.host book-name note-name u.comment-date) - ?~ comment ~ - ``noun+!>(u.comment) - :: - [%x %book @ @ ~] - =/ host=(unit @p) (slaw %p i.t.t.pax) - =/ book-name i.t.t.t.pax - ?~ host [~ ~] - =/ book (~(get by books) u.host book-name) - ?~ book ~ - ``noun+!>(u.book) - == - :: - ++ on-agent - |= [wir=wire sin=sign:agent:gall] + ++ on-peek on-peek:def + ++ on-agent + |= [=wire =sign:agent:gall] ^- (quip card _this) - ?- -.sin - %poke-ack - ?: ?=([%join-group @ @ ~] wir) - ?^ p.sin - (on-agent:def wir sin) - =/ =ship - (slav %p i.t.wir) - =^ cards state - (subscribe-notebook ship i.t.t.wir) - [cards this] - ?~ p.sin - [~ this] - =^ cards state - (handle-poke-fail:main wir) - [cards this] - :: If our subscribe failed, delete notebook associated with subscription if - :: it exists - :: - %watch-ack - ?. ?=([%subscribe @ @ ~] wir) - (on-agent:def wir sin) - ?~ p.sin - [~ this] - =/ who=@p (slav %p i.t.wir) - =/ book=@tas i.t.t.wir - =/ del [%del-book who book] - :_ this(books (~(del by books) who book)) - [%give %fact [/primary]~ %publish-primary-delta !>(del)]~ - :: Resubscribe to any subscription we get kicked from. The case of actually - :: getting banned from a notebook is handled by %watch-ack - :: - %kick - ?+ wir - [~ this] - :: - [%subscribe @ @ ~] - =/ who=@p (slav %p i.t.wir) - =/ book=@tas i.t.t.wir - =/ wen=(unit @da) (get-last-update:main who book) - =/ pax=path - ?~ wen - /notebook/[book] - /notebook/[book]/(scot %da u.wen) - :_ this - [%pass wir %agent [who %publish] %watch pax]~ - :: - [%permissions ~] - :_ this - [%pass /permissions %agent [our.bol %permission-store] %watch /updates]~ - :: - [%groups ~] - :_ this - [%pass /groups %agent [our.bol %group-store] %watch /groups]~ - :: - [%invites ~] - :_ this - :_ ~ - :* %pass /invites %agent [our.bol %invite-store] %watch - /invitatory/publish - == - == - :: - %fact - ?+ wir (on-agent:def wir sin) - [%subscribe @ @ ~] - =/ who=@p (slav %p i.t.wir) - =/ book-name i.t.t.wir - ?> ?=(%publish-notebook-delta p.cage.sin) - =^ cards state - (handle-notebook-delta:main !<(notebook-delta q.cage.sin) state) - [cards this] - :: - [%groups ~] - =^ cards state - (handle-group-update:main !<(update:group-store q.cage.sin)) - [cards this] - :: - [%invites ~] - =^ cards state - (handle-invite-update:main !<(invite-update q.cage.sin)) - [cards this] - :: - [%collection *] - [~ this] - == - == - :: + ?. ?=([%graph-migrate *] wire) + (on-agent:def wire sign) + =/ rid=resource + (de-path:resource t.wire) + ?. ?=(%watch-ack -.sign) + ~| "Expected error, please ignore" + (on-agent:def wire sign) + ?~ p.sign + :: if watch acked successfully, then host has completed OTA, and + :: we are safe to add it to the pull-hook + :_ this(migrate (~(del by migrate) rid)) + ~[(poke-graph-pull:main %add entity.rid rid)] + :: if nacked, then set a exponential backoff and retry + =/ nack-count=@ud + +((~(gut by migrate) rid 0)) + ?: (gte nack-count 24) + ~& >>> "failed to migrate notebook {} to graph-store" + [~ this] + :_ this(migrate (~(put by migrate) rid nack-count)) + :: (bex 19) is roughly 6 days + =/ wakeup=@da + (add now.bol (mul ~s1 (bex (min 19 nack-count)))) + [%pass wire %arvo %b %wait wakeup]~ + :: ++ on-arvo - |= [wir=wire sin=sign-arvo] + |= [=wire =sign-arvo] ^- (quip card _this) - ?+ wir - (on-arvo:def wir sin) - :: - [%read %paths ~] - ?> ?=([?(%b %c) %writ *] sin) - =/ rot=riot:clay +>.sin - ?> ?=(^ rot) - =^ cards state - (read-paths:main u.rot) - [cards this] - :: - [%read %info *] - ?> ?=([?(%b %c) %writ *] sin) - =/ rot=riot:clay +>.sin - =^ cards state - (read-info:main t.t.wir rot) - [cards this] - :: - [%read %note *] - ?> ?=([?(%b %c) %writ *] sin) - =/ rot=riot:clay +>.sin - =^ cards state - (read-note:main t.t.wir rot) - [cards this] - :: - [%read %comment *] - ?> ?=([?(%b %c) %writ *] sin) - =/ rot=riot:clay +>.sin - =^ cards state - (read-comment:main t.t.wir rot) - [cards this] - :: - [%bind ~] - [~ this] - :: - [%view-bind ~] - [~ this] - == + ?. ?=([%graph-migrate *] wire) + (on-arvo:def wire sign-arvo) + =/ rid=resource + (de-path:resource t.wire) + ?> ?=([%b %wake *] sign-arvo) + ~? ?=(^ error.sign-arvo) + "behn errored in backoff timers, continuing anyway" + :_ this + ~[(check-host-migrate:main rid)] :: ++ on-fail on-fail:def -- @@ -601,624 +562,8 @@ |_ bol=bowl:gall ++ grup ~(. grpl bol) :: -++ metadata-store-poke - |= act=metadata-action - ^- card - [%pass / %agent [our.bol %metadata-store] %poke %metadata-action !>(act)] - :: -:: -++ get-last-update - |= [host=@p book-name=@tas] - ^- (unit @da) - =/ book (~(get by books) host book-name) - ?~ book ~ - =/ wen date-created.u.book - %- some - %- ~(rep by notes.u.book) - |= [[@tas =note] out=_wen] - ^- @da - %+ max out - %+ max last-edit.note - %- ~(rep by comments.note) - |= [[@da =comment] out=_out] - (max date-created.comment out) -:: -++ get-notebook-from-date - |= [host=@p book-name=@tas wen=@da] - ^- notebook - =/ book (~(got by books) host book-name) - %= book - notes - %- ~(rep by notes.book) - |= [[nom=@tas not=note] out=(map @tas note)] - ^- (map @tas note) - ?: (gth last-edit.not wen) - (~(put by out) nom not) - =. comments.not - %- ~(rep by comments.not) - |= [[nam=@da com=comment] out=(map @da comment)] - ?: (gth date-created.com wen) - (~(put by out) nam com) - out - ?~ comments.not - out - (~(put by out) nom not) - == -:: -++ merge-notebooks - |= [base=notebook diff=notebook] - ^- notebook - %= diff - notes - %- ~(rep by notes.diff) - |= [[nom=@tas not=note] out=_notes.base] - =/ base-note=(unit note) (~(get by out) nom) - ?~ base-note - (~(put by out) nom not) - =. comments.u.base-note - (~(uni by comments.u.base-note) comments.not) - (~(put by out) nom u.base-note) - == -:: -++ read-paths - |= ran=rant:clay - ^- (quip card _state) - =/ rav [%next %t [%da now.bol] /app/publish/notebooks] - =/ new (filter-and-sort-paths !<((list path) q.r.ran)) - =/ dif (diff-paths our-paths new) - =^ del-moves state (del-paths del.dif) - =^ add-moves state (add-paths add.dif) - :: - =/ cards=(list card) - ;: weld - [%pass /read/paths %arvo %c %warp our.bol q.byk.bol `rav]~ - del-moves - add-moves - == - [cards state(our-paths new)] -:: -++ read-info - |= [pax=path rot=riot:clay] - ^- (quip card _state) - ?> ?=([%app %publish %notebooks @ %publish-info ~] pax) - =/ book-name i.t.t.t.pax - ?~ rot - [~ state] - =/ info=notebook-info !<(notebook-info q.r.u.rot) - =/ new-book=notebook - :* title.info - description.info - comments.info - writers.info - subscribers.info - now.bol - ~ ~ ~ - == - =/ rif=riff:clay [q.byk.bol `[%next %x [%da now.bol] pax]] - =/ delta=notebook-delta - [%edit-book our.bol book-name new-book] - =^ cards state - (handle-notebook-delta delta state) - :_ state - :* [%pass (welp /read/info pax) %arvo %c %warp our.bol rif] - cards - == -:: -++ read-note - |= [pax=path rot=riot:clay] - ^- (quip card _state) - ?> ?=([%app %publish %notebooks @ @ %udon ~] pax) - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ book (~(get by books) our.bol book-name) - ?~ book - [~ state] - =/ old-note (~(get by notes.u.book) note-name) - ?~ old-note - [~ state] - ?~ rot - [~ state] - =/ udon !<(@t q.r.u.rot) - =/ new-note=note (form-note note-name udon) - =/ rif=riff:clay [q.byk.bol `[%next %x [%da now.bol] pax]] - =/ delta=notebook-delta - [%edit-note our.bol book-name note-name new-note] - =^ cards state - (handle-notebook-delta delta state) - :_ state - :* [%pass (welp /read/note pax) %arvo %c %warp our.bol rif] - cards - == -:: -++ read-comment - |= [pax=path rot=riot:clay] - ^- (quip card _state) - ?> ?=([%app %publish %notebooks @ @ @ %publish-comment ~] pax) - ?~ rot - [~ state] - =/ comment-date (slaw %da i.t.t.t.t.t.pax) - ?~ comment-date - [~ state] - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ com-2-3 !<(?(comment-2 comment-3) q.r.u.rot) - =/ new-comment=comment-3 - ?: ?=(comment-2 com-2-3) - [author.com-2-3 date-created.com-2-3 content.com-2-3 %.n] - com-2-3 - =/ rif=riff:clay [q.byk.bol `[%next %x [%da now.bol] pax]] - =/ delta=notebook-delta - [%edit-comment our.bol book-name note-name u.comment-date new-comment] - =^ cards state - (handle-notebook-delta delta state) - :_ state - :* [%pass (welp /read/comment pax) %arvo %c %warp our.bol rif] - cards - == -:: -++ filter-and-sort-paths - |= paths=(list path) - ^- (list path) - %+ sort - %+ skim paths - |= pax=path - ?| ?=([%app %publish %notebooks @ %publish-info ~] pax) - ?=([%app %publish %notebooks @ @ %udon ~] pax) - ?=([%app %publish %notebooks @ @ @ %publish-comment ~] pax) - == - |= [a=path b=path] - ^- ? - (lte (lent a) (lent b)) -:: -++ diff-paths - |= [old=(list path) new=(list path)] - ^- [del=(list path) add=(list path)] - =/ del=(list path) (skim old |=(p=path ?=(~ (find [p]~ new)))) - =/ add=(list path) (skim new |=(p=path ?=(~ (find [p]~ old)))) - [del add] -:: -++ del-paths - |= paths=(list path) - ^- (quip card _state) - %+ roll paths - |= [pax=path cad=(list card) sty=_state] - ?+ pax !! - [%app %publish %notebooks @ %publish-info ~] - =/ book-name i.t.t.t.pax - =/ delta=notebook-delta [%del-book our.bol book-name] - =^ cards sty (handle-notebook-delta delta sty) - [(weld cards cad) sty] - :: - [%app %publish %notebooks @ @ %udon ~] - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ book (~(get by books.sty) our.bol book-name) - ?~ book - [cad sty] - =. notes.u.book (~(del by notes.u.book) note-name) - =/ delta=notebook-delta [%del-note our.bol book-name note-name] - =^ cards sty (handle-notebook-delta delta sty) - [(weld cards cad) sty] - :: - [%app %publish %notebooks @ @ @ %publish-comment ~] - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ comment-date (slaw %da i.t.t.t.t.t.pax) - ?~ comment-date - [cad sty] - =/ delta=notebook-delta - [%del-comment our.bol book-name note-name u.comment-date] - =^ cards sty (handle-notebook-delta delta sty) - [(weld cards cad) sty] - == -:: -++ add-paths - |= paths=(list path) - ^- (quip card _state) - %+ roll paths - |= [pax=path cad=(list card) sty=_state] - ^- (quip card _state) - ?+ pax !! - [%app %publish %notebooks @ %publish-info ~] - =/ book-name i.t.t.t.pax - =/ info=notebook-info .^(notebook-info %cx (welp our-beak pax)) - =* title title.info - =* description description.info - =/ new-book=notebook - :* title - description - comments.info - writers.info - subscribers.info - now.bol - ~ ~ ~ - == - =+ ^- [grp-car=(list card) write-pax=path read-pax=path] - ?: =(writers.new-book /) - =/ group-path /~/(scot %p our.bol)/[book-name] - (make-groups book-name [group-path ~ %.n %.n] title description) - [~ writers.info subscribers.info] - =. writers.new-book write-pax - =. subscribers.new-book read-pax - =+ ^- [read-cards=(list card) notes=(map @tas note)] - (watch-notes /app/publish/notebooks/[book-name]) - =. notes.new-book notes - =/ delta=notebook-delta [%add-book our.bol book-name new-book] - =/ rif=riff:clay [q.byk.bol `[%next %x [%da now.bol] pax]] - =^ update-cards sty (handle-notebook-delta delta sty) - :_ sty - ;: weld - grp-car - [%pass (welp /read/info pax) %arvo %c %warp our.bol rif]~ - read-cards - update-cards - cad - == - :: - [%app %publish %notebooks @ @ %udon ~] - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ new-note=note (scry-note pax) - =+ ^- [read-cards=(list card) comments=(map @da comment)] - (watch-comments /app/publish/notebooks/[book-name]/[note-name]) - =. comments.new-note comments - =/ rif=riff:clay [q.byk.bol `[%next %x [%da now.bol] pax]] - =/ delta=notebook-delta - [%add-note our.bol book-name note-name new-note] - =^ update-cards sty (handle-notebook-delta delta sty) - :_ sty - ;: weld - [%pass (welp /read/note pax) %arvo %c %warp our.bol rif]~ - read-cards - update-cards - cad - == - :: - [%app %publish %notebooks @ @ @ %publish-comment ~] - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ comment-name (slaw %da i.t.t.t.t.t.pax) - ?~ comment-name - [~ sty] - =/ com-2-3 .^(?(comment-2 comment-3) %cx (welp our-beak pax)) - =/ new-com=comment-3 - ?: ?=(comment-2 com-2-3) - [author.com-2-3 date-created.com-2-3 content.com-2-3 %.n] - com-2-3 - =/ rif=riff:clay [q.byk.bol `[%next %x [%da now.bol] pax]] - :: - =/ delta=notebook-delta - [%add-comment our.bol book-name note-name u.comment-name new-com] - =^ update-cards sty (handle-notebook-delta delta sty) - :_ sty - ;: weld - [%pass (welp /read/comment pax) %arvo %c %warp our.bol rif]~ - update-cards - cad - == - == -:: -++ watch-notes - |= pax=path - ^- [(list card) (map @tas note)] - =/ paths .^((list path) %ct (weld our-beak pax)) - %+ roll paths - |= [pax=path cards=(list card) notes=(map @tas note)] - ?. ?=([%app %publish %notebooks @ @ %udon ~] pax) - [cards notes] - =/ book-name i.t.t.t.pax - =/ note-name i.t.t.t.t.pax - =/ new-note (scry-note pax) - =^ comment-cards comments.new-note - (watch-comments /app/publish/notebooks/[book-name]/[note-name]) - =/ rif=riff:clay [q.byk.bol `[%next %x [%da now.bol] pax]] - :_ (~(put by notes) note-name new-note) - ;: weld - [%pass (welp /read/note pax) %arvo %c %warp our.bol rif]~ - comment-cards - cards - == -:: -++ watch-comments - |= pax=path - ^- [(list card) (map @da comment)] - =/ paths .^((list path) %ct (weld our-beak pax)) - %+ roll paths - |= [pax=path cards=(list card) comments=(map @da comment)] - ?. ?=([%app %publish %notebooks @ @ @ %publish-comment ~] pax) - [cards comments] - =/ comment-name (slaw %da i.t.t.t.t.t.pax) - ?~ comment-name - [cards comments] - =/ new-com .^(comment %cx (welp our-beak pax)) - =/ rif=riff:clay [q.byk.bol `[%next %x [%da now.bol] pax]] - :_ (~(put by comments) u.comment-name new-com) - [[%pass (welp /read/comment pax) %arvo %c %warp our.bol rif] cards] -:: -++ scry-note - |= pax=path - ^- note - ?> ?=([%app %publish %notebooks @ @ %udon ~] pax) - =/ note-name i.t.t.t.t.pax - =/ udon=@t .^(@t %cx (welp our-beak pax)) - (form-note note-name udon) -:: -++ form-snippet - |= file=@t - ^- @t - =/ front-idx (add 3 (need (find ";>" (trip file)))) - =/ front-matter (cat 3 (end 3 front-idx file) 'dummy text\0a') - =/ body (cut 3 [front-idx (met 3 file)] file) - (of-wain:format (scag 1 (to-wain:format body))) -:: -++ form-note - |= [note-name=@tas file=@t] - ^- note - =/ snippet=@t (form-snippet file) - =/ front-idx (add 3 (need (find ";>" (trip file)))) - =/ front-matter (cat 3 (end 3 front-idx file) 'dummy text\0a') - =/ meta=(each (map term knot) tang) - %- mule |. - %- ~(run by inf:(static:cram (ream front-matter))) - |= a=dime ^- cord - ?+ (end 3 1 p.a) (scot a) - %t q.a - == - :: - =/ author=@p our.bol - =? author ?=(%.y -.meta) - %+ fall - (biff (~(get by p.meta) %author) (slat %p)) - our.bol - :: - =/ title=@t note-name - =? title ?=(%.y -.meta) - (fall (~(get by p.meta) %title) note-name) - :: - =/ date-created=@da now.bol - =? date-created ?=(%.y -.meta) - %+ fall - (biff (~(get by p.meta) %date-created) (slat %da)) - now.bol - :: - =/ last-modified=@da now.bol - =? last-modified ?=(%.y -.meta) - %+ fall - (biff (~(get by p.meta) %last-modified) (slat %da)) - now.bol - :: - :* author - title - note-name - date-created - last-modified - %.y - file - snippet - ~ - %.n - == -:: -++ handle-group-update - |= =update:group-store - ^- (quip card _state) - ?. ?=(?(%remove-members %add-members) -.update) - [~ state] - =* ships ships.update - =/ =path - (en-path:resource resource.update) - =/ book=(unit @tas) - %+ roll ~(tap by books) - |= [[[who=@p nom=@tas] book=notebook] out=(unit @tas)] - ?. =(who our.bol) - out - ?. =(path subscribers.book) - out - `nom - ?~ book - [~ state] - :_ state - %- zing - :- ^- (list card) - %+ roll ~(tap by books) - |= [[[who=@p book=@tas] nb=notebook] out=(list card)] - ^- (list card) - ?. =(who our.bol) - out - ?. =(writers.nb path) - out - =/ rid (de-path:resource writers.nb) - =/ grp=(unit group) (scry-group:grup rid) - ?~ grp out - ?: hidden.u.grp - out - =/ =tag [%publish (cat 3 'writers-' book)] - :_ out - (group-proxy-poke entity.rid %add-tag rid tag members.u.grp) - %+ turn ~(tap in ships) - |= who=@p - ?. (allowed who %read u.book) - [%give %kick [/notebook/[u.book]]~ `who]~ - ?: ?|(?=(%remove-members -.update) (is-managed-path:grup path)) - ~ - =/ uid (sham %publish who u.book eny.bol) - =/ inv=invite - :* our.bol %publish /notebook/[u.book] who - (crip "invite for notebook {}/{(trip u.book)}") - == - =/ act=invite-action [%invite /publish uid inv] - [%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)]~ -:: -++ handle-invite-update - |= upd=invite-update - ^- (quip card _state) - ?+ -.upd - [~ state] - :: - %delete - [~ state] - :: - %invite - [~ state] - :: - %decline - [~ state] - :: - %accepted - ?> ?=([@ @ *] path.invite.upd) - =/ book i.t.path.invite.upd - =/ group - (group-from-book notebook+book^~) - ?^ group - (subscribe-notebook ship.invite.upd book) - =/ rid=resource - (de-path:resource ship+path.invite.upd) - =/ join-wire=wire - /join-group/[(scot %p ship.invite.upd)]/[book] - =/ =cage - :- %group-update - !> ^- action:group-store - [%add-members rid (sy our.bol ~)] - :_ state - [%pass join-wire %agent [entity.rid %group-push-hook] %poke cage]~ - == -:: -++ subscribe-notebook - |= [=ship book=@tas] - ^- (quip card _state) - =/ pax=path /notebook/[book] - =/ wir=wire /subscribe/[(scot %p ship)]/[book] - =? tile-num (gth tile-num 0) - (dec tile-num) - =/ jon=json (frond:enjs:format %notifications (numb:enjs:format tile-num)) - :_ state - :~ [%pass wir %agent [ship %publish] %watch pax] - [%give %fact [/publishtile]~ %json !>(jon)] - == -:: -++ watch-notebook - |= pax=path - ?> ?=([%notebook @ *] pax) - =/ book-name i.t.pax - ?. (allowed src.bol %read book-name) - ~|("not permitted" !!) - =/ book - ?: ?=([%notebook @ @ ~] pax) - =/ wen=@da (slav %da i.t.t.pax) - (get-notebook-from-date our.bol book-name wen) - (~(got by books) our.bol book-name) - =/ delta=notebook-delta - [%add-book our.bol book-name book] - :_ state - [%give %fact ~ %publish-notebook-delta !>(delta)]~ -:: ++ our-beak /(scot %p our.bol)/[q.byk.bol]/(scot %da now.bol) :: -++ book-writers - |= [host=@p book=@tas] - ^- (set ship) - =/ =notebook (~(got by books) host book) - =/ rid=resource - (de-path:resource writers.notebook) - %- ~(uni in (fall (scry-tag:grup rid %admin) ~)) - %+ fall - (scry-tag:grup rid `tag`[%publish (cat 3 %writers- book)]) - ~ -:: -++ allowed - |= [who=@p mod=?(%read %write) book=@tas] - ^- ? - =/ =notebook (~(got by books) our.bol book) - =/ rid=resource - (de-path:resource writers.notebook) - ?: ?=(%read mod) - (~(has in (members:grup rid)) who) - (~(has in (book-writers our.bol book)) who) -:: -++ write-file - |= [pax=path cay=cage] - ^- card - =. pax (weld our-beak pax) - [%pass (weld /write pax) %arvo %c %info (foal:space:userlib pax cay)] -:: -++ delete-file - |= pax=path - ^- card - =. pax (weld our-beak pax) - [%pass (weld /delete pax) %arvo %c %info (fray:space:userlib pax)] -:: -++ delete-dir - |= pax=path - ^- card - =/ nor=nori:clay - :- %& - %+ turn .^((list path) %ct (weld our-beak pax)) - |= pax=path - ^- [path miso:clay] - [pax %del ~] - [%pass (weld /delete pax) %arvo %c %info q.byk.bol nor] -:: -++ add-front-matter - |= [fro=(map knot cord) udon=@t] - ^- @t - %- of-wain:format - =/ tum (trip udon) - =/ id (find ";>" tum) - ?~ id - %+ weld (front-to-wain fro) - (to-wain:format (crip :(weld ";>\0a" tum))) - %+ weld (front-to-wain fro) - (to-wain:format (crip (slag u.id tum))) -:: -++ front-to-wain - |= a=(map knot cord) - ^- wain - =/ entries=wain - %+ turn ~(tap by a) - |= b=[knot cord] - =/ c=[term cord] (,[term cord] b) - (crip " [{<-.c>} {<+.c>}]") - :: - ?~ entries ~ - ;: weld - [':- :~' ~] - entries - [' ==' ~] - == -:: -++ give-primary-delta - |= del=primary-delta - ^- card - [%give %fact [/primary]~ %publish-primary-delta !>(del)] -:: -++ group-poke - |= act=action:group-store - ^- card - [%pass / %agent [our.bol %group-store] %poke %group-action !>(act)] -:: -++ group-proxy-poke - |= [who=ship act=action:group-store] - ^- card - [%pass / %agent [who %group-push-hook] %poke %group-update !>(act)] -:: -++ group-pull-hook-poke - |= act=action:pull-hook - ^- card - [%pass / %agent [our.bol %group-pull-hook] %poke %pull-hook-action !>(act)] -:: -++ contact-view-poke - |= act=contact-view-action:contact-view - ^- card - [%pass / %agent [our.bol %contact-view] %poke %contact-view-action !>(act)] -:: -++ contact-view-create - |= [=path ships=(set ship) =policy title=@t description=@t] - =/ rid=resource - (de-path:resource path) - =/ act=contact-view-action:contact-view - [%create name.rid policy title description] - (contact-view-poke act) -:: ++ perm-hook-poke |= act=permission-hook-action ^- card @@ -1232,7 +577,7 @@ == :: ++ invite-poke - |= act=invite-action + |= act=action:inv ^- card [%pass / %agent [our.bol %invite-store] %poke %invite-action !>(act)] :: @@ -1254,11 +599,11 @@ %+ turn ~(tap in invitees) |= who=ship =/ uid (sham %publish who book eny.bol) - =/ inv=invite - :* our.bol %publish /(scot %p our.bol)/[book] who + =/ =invite:inv + :* our.bol %publish [our.bol book] who (crip "invite for notebook {}/{(trip book)}") == - =/ act=invite-action [%invite /publish uid inv] + =/ act=action:inv [%invite %publish uid invite] [%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)] :: ++ make-groups @@ -1297,1135 +642,50 @@ :- (group-poke %add-group rid policy %.y) (generate-invites book (~(del in invitees.group) our.bol)) :: -++ handle-poke-fail - |= wir=wire - ^- (quip card _state) - ?+ wir - [~ state] - :: new note failed, stash it in limbo - :: - [%forward %new-note @ @ @ ~] - =/ host=@p (slav %p i.t.t.wir) - =/ book-name i.t.t.t.wir - =/ note-name i.t.t.t.t.wir - =/ book (~(get by books) [host book-name]) - ?~ book - [~ state] - =/ note (~(get by notes.u.book) note-name) - ?~ note - [~ state] - =. notes.limbo (~(put by notes.limbo) [host book-name note-name] u.note) - =. notes.u.book (~(del by notes.u.book) note-name) - =/ del [%del-note host book-name note-name] - :- [(give-primary-delta del)]~ - state(books (~(put by books) [host book-name] u.book)) - :: new comment failed, stash it in limbo - :: - [%forward %new-comment @ @ @ @ ~] - =/ host=@p (slav %p i.t.t.wir) - =/ book-name i.t.t.t.wir - =/ note-name i.t.t.t.t.wir - =/ comment-date=@da (slav %da i.t.t.t.t.t.wir) - =/ book (~(get by books) [host book-name]) - ?~ book - [~ state] - =/ note (~(get by notes.u.book) note-name) - ?~ note - [~ state] - =/ comment (~(get by comments.u.note) comment-date) - ?~ comment - [~ state] - =. comments.limbo - %+ ~(put by comments.limbo) - [host book-name note-name comment-date] - u.comment - =. comments.u.note (~(del by comments.u.note) comment-date) - =. notes.u.book (~(put by notes.u.book) note-name u.note) - =/ del [%del-comment host book-name note-name comment-date] - :- [(give-primary-delta del)]~ - state(books (~(put by books) [host book-name] u.book)) - :: edit note failed, restore old version - :: - [%forward %edit-note @ @ @ ~] - =/ host=@p (slav %p i.t.t.wir) - =/ book-name i.t.t.t.wir - =/ note-name i.t.t.t.t.wir - =/ book (~(get by books) [host book-name]) - ?~ book - [~ state] - =/ note (~(get by notes.limbo) host book-name note-name) - ?~ note - [~ state] - =. notes.u.book (~(put by notes.u.book) note-name u.note) - =/ del [%edit-note host book-name note-name u.note] - :- [(give-primary-delta del)]~ - %= state - books (~(put by books) [host book-name] u.book) - notes.limbo (~(del by notes.limbo) host book-name note-name) - == - :: edit comment failed, restore old version - :: - [%forward %new-comment @ @ @ @ ~] - =/ host=@p (slav %p i.t.t.wir) - =/ book-name i.t.t.t.wir - =/ note-name i.t.t.t.t.wir - =/ comment-date=@da (slav %da i.t.t.t.t.t.wir) - =/ book (~(get by books) [host book-name]) - ?~ book - [~ state] - =/ note (~(get by notes.u.book) note-name) - ?~ note - [~ state] - =/ comment - (~(get by comments.limbo) host book-name note-name comment-date) - ?~ comment - [~ state] - =. comments.u.note (~(put by comments.u.note) comment-date u.comment) - =. notes.u.book (~(put by notes.u.book) note-name u.note) - =/ del [%edit-comment host book-name note-name comment-date u.comment] - :- [(give-primary-delta del)]~ - %= state - books (~(put by books) [host book-name] u.book) - :: - comments.limbo - %+ ~(del by comments.limbo) - [host book-name note-name comment-date] - u.comment - == - :: delete note failed, restore old version - :: - [%forward %del-note @ @ @ ~] - =/ host=@p (slav %p i.t.t.wir) - =/ book-name i.t.t.t.wir - =/ note-name i.t.t.t.t.wir - =/ book (~(get by books) [host book-name]) - ?~ book - [~ state] - =/ note (~(get by notes.limbo) host book-name note-name) - ?~ note - [~ state] - =. notes.u.book (~(put by notes.u.book) note-name u.note) - =/ del [%add-note host book-name note-name u.note] - :- [(give-primary-delta del)]~ - %= state - books (~(put by books) [host book-name] u.book) - notes.limbo (~(del by notes.limbo) host book-name note-name) - == - :: delete comment failed, restore old version - :: - [%forward %del-comment @ @ @ @ ~] - =/ host=@p (slav %p i.t.t.wir) - =/ book-name i.t.t.t.wir - =/ note-name i.t.t.t.t.wir - =/ comment-date=@da (slav %da i.t.t.t.t.t.wir) - =/ book (~(get by books) [host book-name]) - ?~ book - [~ state] - =/ note (~(get by notes.u.book) note-name) - ?~ note - [~ state] - =/ comment - (~(get by comments.limbo) host book-name note-name comment-date) - ?~ comment - [~ state] - =. comments.u.note (~(put by comments.u.note) comment-date u.comment) - =. notes.u.book (~(put by notes.u.book) note-name u.note) - =/ del [%add-comment host book-name note-name comment-date u.comment] - :- [(give-primary-delta del)]~ - %= state - books (~(put by books) [host book-name] u.book) - :: - comments.limbo - %+ ~(del by comments.limbo) - [host book-name note-name comment-date] - u.comment - == - == -:: -++ poke-publish-action - |= act=action - ^- (quip card _state) - ?- -.act - :: %new-book: Make groups and save publish info file. - :: - %new-book - ?. (team:title our.bol src.bol) - ~|("action not permitted" !!) - ?: (~(has by books) our.bol book.act) - ~|("notebook already exists: {}" !!) - =+ ^- [cards=(list card) write-pax=path read-pax=path] - (make-groups book.act group.act title.act about.act) - =/ new-book=notebook-info - :* title.act - about.act - coms.act - write-pax - read-pax - == - =/ pax=path /app/publish/notebooks/[book.act]/publish-info - :_ state - [(write-file pax %publish-info !>(new-book)) cards] - :: %new-note: - :: If poke is from us, eagerly store new note in books. If poke is to us, - :: save file, otherwise forward the poke. If forwarded poke fails, note is - :: removed from books and stored in limbo. - :: - %new-note - =/ book=(unit notebook) (~(get by books) who.act book.act) - ?~ book - ~|("nonexistent notebook {}" !!) - ?: (~(has by notes.u.book) note.act) - ~|("note already exists: {}" !!) - =/ front=(map knot cord) - %- my - :~ title+title.act - author+(scot %p src.bol) - date-created+(scot %da now.bol) - last-modified+(scot %da now.bol) - == - =/ file=@t (add-front-matter front body.act) - :: - =^ cards books - ?. =(src.bol our.bol) - [~ books] - =/ new-note=note - :* src.bol - title.act - note.act - now.bol - now.bol - %.y - file - (form-snippet file) - ~ - %.y - == - =/ del=primary-delta [%add-note who.act book.act note.act new-note] - :- [(give-primary-delta del)]~ - %+ ~(put by books) - [who.act book.act] - u.book(notes (~(put by notes.u.book) note.act new-note)) - :: - :_ state - ?. =(who.act our.bol) - =/ poke-wir=wire - /forward/new-note/(scot %p who.act)/[book.act]/[note.act] - :_ cards - [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] - ?. ?| (team:title our.bol src.bol) - (allowed src.bol %write book.act) - == - ~|("action not permitted" !!) - =/ pax=path /app/publish/notebooks/[book.act]/[note.act]/udon - :_ cards - [(write-file pax %udon !>(file))] - :: %new-comment - :: If poke is from us, eagerly store new comment in books. If poke is to - :: us, save file, otherwise forward the poke. If forwarded poke fails, - :: comment is removed from books and stored in limbo. - :: - %new-comment - =/ book=(unit notebook) (~(get by books) who.act book.act) - ?~ book - ~|("nonexistent notebook {}" !!) - =/ note=(unit note) (~(get by notes.u.book) note.act) - ?~ note - ~|("nonexistent note {}" !!) - =/ new-comment=comment - :* author=src.bol - date-created=now.bol - content=body.act - %.y - == - :: - =^ cards books - ?. =(src.bol our.bol) - [~ books] - =/ new-note - %= u.note - comments (~(put by comments.u.note) now.bol new-comment) - == - =/ del=primary-delta - [%add-comment who.act book.act note.act now.bol new-comment] - :- [(give-primary-delta del)]~ - %+ ~(put by books) - [who.act book.act] - u.book(notes (~(put by notes.u.book) note.act new-note)) - :_ state - ?. =(who.act our.bol) - =/ poke-wir=wire - :~ %forward - %new-comment - (scot %p who.act) - book.act - note.act - (scot %da now.bol) - == - :_ cards - [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] - ?. ?& ?| (team:title our.bol src.bol) - (allowed src.bol %read book.act) - == - comments.u.book - == - ~|("action not permitted" !!) - =/ pax=path - %+ weld /app/publish/notebooks - /[book.act]/[note.act]/(scot %da now.bol)/publish-comment - [(write-file pax %publish-comment !>(new-comment(pending %.n)))]~ - :: %edit-book: Make groups and save publish-info file - :: - %edit-book - ?. (team:title our.bol src.bol) - ~|("action not permitted" !!) - =/ book (~(get by books) our.bol book.act) - ?~ book - ~|("nonexistent notebook" !!) - =+ ^- [cards=(list card) write-pax=path read-pax=path] - ?~ group.act - [~ writers.u.book subscribers.u.book] - (make-groups book.act u.group.act title.act about.act) - =/ new-info=notebook-info - :* title.act - about.act - coms.act - write-pax - read-pax - == - =/ pax=path /app/publish/notebooks/[book.act]/publish-info - :_ state - [(write-file pax %publish-info !>(new-info)) cards] - :: %edit-note: - :: If poke is from us, eagerly store new note in books, and place the old - :: note in limbo. If poke is to us, save file, otherwise forward the poke. - :: If forwarded poke fails, old note is restored from limbo. - :: - %edit-note - =/ book=(unit notebook) (~(get by books) who.act book.act) - ?~ book - ~|("nonexistent notebook {}" !!) - =/ note=(unit note) (~(get by notes.u.book) note.act) - ?~ note - ~|("nonexistent note: {}" !!) - =/ front=(map knot cord) - %- my - :~ title+title.act - author+(scot %p src.bol) - date-created+(scot %da date-created.u.note) - last-modified+(scot %da now.bol) - == - =/ file=@t (add-front-matter front body.act) - :: - =^ cards state - ?. =(src.bol our.bol) - [~ state] - =/ new-note - %= u.note - author src.bol - title title.act - last-edit now.bol - file file - snippet (form-snippet file) - pending %.y - == - =/ del=primary-delta [%edit-note who.act book.act note.act new-note] - :- [(give-primary-delta del)]~ - %= state - notes.limbo - (~(put by notes.limbo) [who.act book.act note.act] u.note) - :: - books - %+ ~(put by books) - [who.act book.act] - u.book(notes (~(put by notes.u.book) note.act new-note)) - == - :: - :_ state - ?. =(who.act our.bol) - =/ poke-wir=wire - /forward/edit-note/(scot %p who.act)/[book.act]/[note.act] - :_ cards - [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] - ?. ?| (team:title our.bol src.bol) - ?& =(author.u.note src.bol) - (allowed src.bol %write book.act) - == - == - ~|("action not permitted" !!) - =/ pax=path /app/publish/notebooks/[book.act]/[note.act]/udon - [(write-file pax %udon !>(file))]~ - :: %edit-comment: - :: If poke is from us, eagerly store new comment in books, and place the - :: old note in limbo. If poke is to us, save file, otherwise forward the - :: poke. If forwarded poke fails, old comment is restored from limbo. - :: - %edit-comment - =/ book=(unit notebook) (~(get by books) who.act book.act) - ?~ book - ~|("nonexistent notebook {}" !!) - =/ note=(unit note) (~(get by notes.u.book) note.act) - ?~ note - ~|("nonexistent note {}" !!) - =/ comment-date (slav %da comment.act) - =/ comment=(unit comment) (~(get by comments.u.note) comment-date) - ?~ comment - ~|("nonexistent comment {}" !!) - =/ new-comment - u.comment(content body.act, pending %.y) - :: - =^ cards state - ?. =(src.bol our.bol) - [~ state] - =/ new-note - %= u.note - comments - (~(put by comments.u.note) comment-date new-comment) - == - =/ del=primary-delta - [%edit-comment who.act book.act note.act comment-date new-comment] - :- [(give-primary-delta del)]~ - %= state - books - %+ ~(put by books) - [who.act book.act] - u.book(notes (~(put by notes.u.book) note.act new-note)) - :: - comments.limbo - %+ ~(put by comments.limbo) - [who.act book.act note.act comment-date] - u.comment - == - :: - :_ state - ?. =(who.act our.bol) - =/ poke-wir - :~ %forward - %edit-comment - (scot %p who.act) - book.act - note.act - comment.act - == - :_ cards - [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] - ?. ?| (team:title our.bol src.bol) - ?& =(author.u.comment src.bol) - (allowed src.bol %read book.act) - == - == - ~|("action not permitted" !!) - =/ pax=path - %+ weld /app/publish/notebooks - /[book.act]/[note.act]/[comment.act]/publish-comment - [(write-file pax %publish-comment !>(new-comment(pending %.n)))]~ - :: %del-book: Delete whole notebook directory, delete groups and permissions - :: - %del-book - ?. (team:title our.bol src.bol) - ~|("action not permitted" !!) - =/ book=(unit notebook) (~(get by books) our.bol book.act) - ?~ book - ~|("nonexistent notebook {}" !!) - =/ pax=path /app/publish/notebooks/[book.act] - ?> ?=(^ writers.u.book) - ?> ?=(^ subscribers.u.book) - =/ cards=(list card) - ~[(delete-dir pax)] - =/ rid=resource - (de-path:resource writers.u.book) - =? cards !(is-managed:grup rid) - [(group-poke %remove-group rid ~) cards] - [cards state] - :: %del-note: - :: If poke is from us, eagerly remove note from books, and place the - :: old note in limbo. If poke is to us, save file, otherwise forward the - :: poke. If forwarded poke fails, old note is restored from limbo. - :: - %del-note - =/ book=(unit notebook) (~(get by books) who.act book.act) - ?~ book - ~|("nonexistent notebook {}" !!) - =/ note=(unit note) (~(get by notes.u.book) note.act) - ?~ note - ~|("nonexistent note: {}" !!) - :: - =^ cards state - ?. =(src.bol our.bol) - [~ state] - =/ del=primary-delta [%del-note who.act book.act note.act] - =. notes.u.book (~(del by notes.u.book) note.act) - :- [(give-primary-delta del)]~ - %= state - books (~(put by books) [who.act book.act] u.book) - notes.limbo (~(put by notes.limbo) [who.act book.act note.act] u.note) - == - :: - :_ state - ?. =(who.act our.bol) - =/ poke-wir=wire - /forward/del-note/(scot %p who.act)/[book.act]/[note.act] - :_ cards - [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] - ?. ?| (team:title our.bol src.bol) - ?& =(author.u.note src.bol) - (allowed src.bol %write book.act) - == - == - ~|("action not permitted" !!) - =/ pax=path /app/publish/notebooks/[book.act]/[note.act]/udon - [(delete-file pax)]~ - :: %del-comment: - :: If poke is from us, eagerly remove comment from books, and place the - :: old note in limbo. If poke is to us, save file, otherwise forward the - :: poke. If forwarded poke fails, old comment is restored from limbo. - :: - %del-comment - =/ book=(unit notebook) (~(get by books) who.act book.act) - ?~ book - ~|("nonexistent notebook {}" !!) - =/ note=(unit note) (~(get by notes.u.book) note.act) - ?~ note - ~|("nonexistent note {}" !!) - =/ comment-date (slav %da comment.act) - =/ comment=(unit comment) (~(get by comments.u.note) comment-date) - ?~ comment - ~|("nonexistent comment {}" !!) - :: - =^ cards state - ?. =(src.bol our.bol) - [~ state] - =/ del=primary-delta - [%del-comment who.act book.act note.act comment-date] - =. comments.u.note (~(del by comments.u.note) comment-date) - =. notes.u.book (~(put by notes.u.book) note.act u.note) - :- [(give-primary-delta del)]~ - %= state - books - (~(put by books) [who.act book.act] u.book) - :: - comments.limbo - %+ ~(put by comments.limbo) - [who.act book.act note.act comment-date] - u.comment - == - :: - :_ state - ?. =(who.act our.bol) - =/ poke-wir=wire - :~ %forward - %del-comment - (scot %p who.act) - book.act - note.act - comment.act - == - :_ cards - [%pass poke-wir %agent [who.act %publish] %poke %publish-action !>(act)] - ?. ?| (team:title our.bol src.bol) - ?& =(author.u.comment src.bol) - (allowed src.bol %read book.act) - == - == - ~|("action not permitted" !!) - =/ pax=path - %+ weld /app/publish/notebooks - /[book.act]/[note.act]/[comment.act]/publish-comment - [(delete-file pax)]~ - :: %subscribe - :: - %subscribe - ?> (team:title our.bol src.bol) - ?: =(our.bol who.act) - [~ state] - =/ join-wire=wire - /join-group/[(scot %p who.act)]/[book.act] - =/ meta=(unit (set path)) - (metadata-resource-scry %publish /(scot %p who.act)/[book.act]) - ?^ meta - (subscribe-notebook who.act book.act) - =/ rid=resource - [who.act book.act] - =/ =cage - :- %group-update - !> ^- action:group-store - [%add-members rid (sy our.bol ~)] - :_ state - [%pass join-wire %agent [who.act %group-push-hook] %poke cage]~ - :: %unsubscribe - :: - %unsubscribe - ?> (team:title our.bol src.bol) - =/ wir=wire /subscribe/(scot %p who.act)/[book.act] - =/ del=primary-delta [%del-book who.act book.act] - =/ book=notebook - (~(got by books) who.act book.act) - =/ rid=resource - (de-path:resource writers.book) - =/ =group - (need (scry-group:grup rid)) - =/ cards=(list card) - :~ [%pass wir %agent [who.act %publish] %leave ~] - [%give %fact [/primary]~ %publish-primary-delta !>(del)] - == - =? cards hidden.group - %+ weld cards - :~ (group-proxy-poke who.act %remove-members rid (sy our.bol ~)) - (group-poke %remove-group rid ~) - == - [cards state(books (~(del by books) who.act book.act))] - :: %read - :: - %read - ?> (team:title our.bol src.bol) - =/ book=(unit notebook) - (~(get by books) who.act book.act) - ?~ book - ~|("nonexistent notebook: {}" !!) - =/ not=(unit note) (~(get by notes.u.book) note.act) - ?~ not - ~|("nonexistent note: {}" !!) - =? tile-num &(!read.u.not (gth tile-num 0)) - (dec tile-num) - =. read.u.not %.y - =. notes.u.book (~(put by notes.u.book) note.act u.not) - =. books (~(put by books) [who.act book.act] u.book) - :_ state - [%give %fact [/primary]~ %publish-primary-delta !>(act)]~ - :: %groupify - :: - %groupify - ?. (team:title our.bol src.bol) - ~|("action not permitted" !!) - =/ book (~(get by books) our.bol book.act) - ?~ book - ~|("nonexistent notebook: {}" !!) - :: - =* old-group-path writers.u.book - =/ app-path /[(scot %p our.bol)]/[book.act] - =/ =metadata - (need (metadata-scry old-group-path app-path)) - =/ old-rid=resource - (de-path:resource old-group-path) - ?< (is-managed:grup old-rid) - ?~ target.act - :: just create contacts object for group - :_ state - ~[(contact-view-poke %groupify old-rid title.metadata description.metadata)] - :: change associations - =* group-path u.target.act - =/ rid=resource - (de-path:resource group-path) - =/ old-group=group - (need (scry-group:grup old-rid)) - =/ =group - (need (scry-group:grup rid)) - =/ ships=(set ship) - (~(dif in members.old-group) members.group) - =. subscribers.u.book - group-path - =. writers.u.book - group-path - =. books - (~(put by books) [our.bol book.act] u.book) - =/ del - [%edit-book our.bol book.act u.book] - :_ state - :* [%give %fact [/primary]~ %publish-primary-delta !>(del)] - [%give %fact [/notebook/[book.act]]~ %publish-notebook-delta !>(del)] - (metadata-store-poke %remove app-path %publish app-path) - (metadata-store-poke %add group-path [%publish app-path] metadata) - (group-poke %remove-group old-rid ~) - ?. inclusive.act - ~ - :- (group-poke %add-members rid ships) - %+ turn - ~(tap in ships) - |= =ship - =/ =invite - :* our.bol - %contact-hook - group-path - ship '' - == - =/ act=invite-action [%invite /contacts (shaf %msg-uid eny.bol) invite] - [%pass / %agent [our.bol %invite-hook] %poke %invite-action !>(act)] - == - == -:: -++ get-subscribers - |= book=@tas - ^- (set @p) - %+ roll ~(val by sup.bol) - |= [[who=@p pax=path] out=(set @p)] - ^- (set @p) - ?. ?=([%notebook @ ~] pax) out - ?. =(book i.t.pax) out - (~(put in out) who) -:: -++ get-notebook - |= [host=@p book-name=@tas sty=_state] - ^- (unit notebook) - (~(get by books.sty) host book-name) -:: -++ get-unread - |= book=notebook - ^- @ud - %+ roll ~(tap by notes.book) - |= [[nom=@tas not=note] out=@ud] - ?: read.not - out - +(out) -:: -++ emit-updates-and-state - |= [host=@p book-name=@tas book=notebook del=notebook-delta sty=_state] - ^- (quip card _state) - :_ sty(books (~(put by books.sty) [host book-name] book)) - ?: =(our.bol host) - :~ [%give %fact [/notebook/[book-name]]~ %publish-notebook-delta !>(del)] - [%give %fact [/primary]~ %publish-primary-delta !>(del)] - == - [%give %fact [/primary]~ %publish-primary-delta !>(del)]~ -:: -++ metadata-poke - |= act=metadata-action - ^- card - [%pass / %agent [our.bol %metadata-hook] %poke %metadata-action !>(act)] -:: -:: -++ metadata-scry - |= [group-path=path app-path=path] - ^- (unit metadata) - ?. .^(? %gu (scot %p our.bol) %metadata-store (scot %da now.bol) ~) ~ - .^ (unit metadata) - %gx - (scot %p our.bol) - %metadata-store - (scot %da now.bol) - %metadata - (scot %t (spat group-path)) - %publish - (scot %t (spat app-path)) - /noun - == -:: -++ metadata-resource-scry - |= [app=@tas app-path=path] - ^- (unit (set path)) - ?. .^(? %gu (scot %p our.bol) %metadata-store (scot %da now.bol) ~) ~ - .^ (unit (set path)) - %gx - ;: weld - /(scot %p our.bol)/metadata-store/(scot %da now.bol)/resource/[app] - app-path - /noun - == - == -:: -++ emit-metadata - |= del=metadata-delta - ^- (list card) - |^ - ?- -.del - %add - =/ preexisting (metadata-scry group-path.del app-path.del) - =/ meta=metadata - %* . *metadata - title title.del - description desc.del - date-created created.del - creator author.del - == - ?~ preexisting - (add group-path.del app-path.del meta) - =. color.meta color.u.preexisting - (add group-path.del app-path.del meta) - :: - %remove - =/ app-path [(scot %p author.del) /[book.del]] - =/ group-path=(unit path) (group-from-book app-path) - ?~ group-path ~ - [(metadata-poke [%remove u.group-path [%publish app-path]])]~ - == - :: - ++ add - |= [group-path=path app-path=path =metadata] - ^- (list card) - [(metadata-poke [%add group-path [%publish app-path] metadata])]~ - -- -:: -++ group-from-book - |= app-path=path - ^- (unit path) - ?. .^(? %gu (scot %p our.bol) %metadata-store (scot %da now.bol) ~) - ?: ?=([@ ^] app-path) - ~& [%assuming-ported-legacy-publish app-path] - `[%'~' app-path] - ~&([%weird-publish app-path] ~) - =/ resource-indices - .^ (jug md-resource group-path) - %gy - (scot %p our.bol) - %metadata-store - (scot %da now.bol) - /resource-indices - == - =/ groups=(unit (set path)) - (~(get by resource-indices) [%publish app-path]) - ?~ groups ~ - =/ group-paths ~(tap in u.groups) - ?~ group-paths ~ - `i.group-paths -:: -++ metadata-hook-poke - |= act=metadata-hook-action - ^- card - :* %pass / %agent - [our.bol %metadata-hook] - %poke %metadata-hook-action - !>(act) - == -:: -++ handle-notebook-delta - |= [del=notebook-delta sty=_state] - ^- (quip card _state) - ?- -.del - %add-book - ?: =(our.bol host.del) - =^ cards state - (emit-updates-and-state host.del book.del data.del del sty) - :_ state - %- zing - :~ cards - [(metadata-hook-poke [%add-owned writers.data.del])]~ - %- emit-metadata - :* %add - writers.data.del - [(scot %p host.del) /[book.del]] - title.data.del - description.data.del - host.del - date-created.data.del - == - == - =? data.del (~(has by books) host.del book.del) - (merge-notebooks (~(got by books) host.del book.del) data.del) - =^ cards state - (emit-updates-and-state host.del book.del data.del del sty) - =/ rid=resource - (de-path:resource writers.data.del) - =? cards !=(our.bol entity.rid) - :_ cards - (group-pull-hook-poke [%add host.del rid]) - :_ state - :* (metadata-hook-poke [%add-synced host.del writers.data.del]) - cards - == - :: - %add-note - =/ book=(unit notebook) - (get-notebook host.del book.del sty) - ?~ book - [~ sty] - =. read.data.del =(our.bol author.data.del) - =. notes.u.book (~(put by notes.u.book) note.del data.del) - (emit-updates-and-state host.del book.del u.book del sty) - :: - %add-comment - =/ book=(unit notebook) - (get-notebook host.del book.del sty) - ?~ book - [~ sty] - =/ note (~(get by notes.u.book) note.del) - ?~ note - [~ sty] - =/ limbo-comment=(unit @da) - %- ~(rep by comments.u.note) - |= [[date=@da com=comment] out=(unit @da)] - ?: ?& =(author.com author.data.del) - =(content.com content.data.del) - =(%.y pending.com) - == - `date - out - =? comments.u.note ?=(^ limbo-comment) - (~(del by comments.u.note) u.limbo-comment) - =. comments.u.note (~(put by comments.u.note) comment-date.del data.del) - =. notes.u.book (~(put by notes.u.book) note.del u.note) - (emit-updates-and-state host.del book.del u.book del sty) - :: - %edit-book - =/ old-book=(unit notebook) - (get-notebook host.del book.del sty) - ?~ old-book - [~ sty] - =/ new-book=notebook - %= data.del - date-created date-created.u.old-book - notes notes.u.old-book - order order.u.old-book - == - =^ cards state - (emit-updates-and-state host.del book.del new-book del sty) - :_ state - %+ weld cards - %- emit-metadata - :* %add - writers.new-book - [(scot %p host.del) /[book.del]] - title.new-book - description.new-book - host.del - date-created.new-book - == - :: - %edit-note - =. notes.limbo.sty (~(del by notes.limbo.sty) host.del book.del note.del) - =/ book=(unit notebook) - (get-notebook host.del book.del sty) - ?~ book - [~ sty] - =/ old-note (~(get by notes.u.book) note.del) - ?~ old-note - [~ sty] - ?: =(our.bol author.u.old-note) - [~ sty] - =/ new-note=note - %= data.del - date-created date-created.u.old-note - comments comments.u.old-note - read read.u.old-note - == - =. notes.u.book (~(put by notes.u.book) note.del new-note) - (emit-updates-and-state host.del book.del u.book del sty) - :: - %edit-comment - =. comments.limbo.sty - %- ~(del by comments.limbo.sty) - [host.del book.del note.del comment-date.del] - =/ book=(unit notebook) - (get-notebook host.del book.del sty) - ?~ book - [~ sty] - =/ note (~(get by notes.u.book) note.del) - ?~ note - [~ sty] - =/ old-comment (~(get by comments.u.note) comment-date.del) - ?~ old-comment - [~ sty] - =. comments.u.note (~(put by comments.u.note) comment-date.del data.del) - =. notes.u.book (~(put by notes.u.book) note.del u.note) - (emit-updates-and-state host.del book.del u.book del sty) - :: - %del-book - =/ book=(unit notebook) - (get-notebook host.del book.del sty) - ?~ book [~ sty] - :_ sty(books (~(del by books.sty) host.del book.del)) - ?. =(our.bol host.del) - %+ welp - [%give %fact [/primary]~ %publish-primary-delta !>(del)]~ - ?: (is-managed writers.u.book) ~ - [(metadata-hook-poke [%remove writers.u.book])]~ - %- zing - :~ [%give %fact [/notebook/[book.del]]~ %publish-notebook-delta !>(del)]~ - [%give %fact [/primary]~ %publish-primary-delta !>(del)]~ - (emit-metadata %remove host.del book.del) - :: - ?: (is-managed writers.u.book) ~ - [(metadata-hook-poke [%remove writers.u.book])]~ - == - :: - %del-note - =. notes.limbo.sty (~(del by notes.limbo.sty) host.del book.del note.del) - =/ book=(unit notebook) - (get-notebook host.del book.del sty) - ?~ book - [~ sty] - =/ not=(unit note) (~(get by notes.u.book) note.del) - ?~ not - [~ sty] - =. notes.u.book (~(del by notes.u.book) note.del) - (emit-updates-and-state host.del book.del u.book del sty) - :: - %del-comment - =. comments.limbo.sty - %- ~(del by comments.limbo.sty) - [host.del book.del note.del comment.del] - =/ book=(unit notebook) - (get-notebook host.del book.del sty) - ?~ book - [~ sty] - =/ note (~(get by notes.u.book) note.del) - ?~ note - [~ sty] - =. comments.u.note (~(del by comments.u.note) comment.del) - =. notes.u.book (~(put by notes.u.book) note.del u.note) - (emit-updates-and-state host.del book.del u.book del sty) - == -:: -++ get-subscribers-json - |= book=@tas - ^- json - :- %a - %+ roll ~(val by sup.bol) - |= [[who=@p pax=path] out=(list json)] - ^- (list json) - ?. ?=([%notebook @ ~] pax) out - ?. =(book i.t.pax) out - [[%s (scot %p who)] out] -:: -++ get-writers-json - |= [host=@p book=@tas] - =/ =tag - [%publish (cat 3 %writers- book)] - ^- json - =/ writers=(list ship) - ~(tap in (book-writers host book)) - :- %a - %+ turn writers - |= who=@p - ^- json - [%s (scot %p who)] -:: -++ get-notebook-json - |= [host=@p book-name=@tas] - ^- (unit json) - =, enjs:format - =/ book=(unit notebook) (~(get by books) host book-name) - ?~ book - ~ - =/ notebook-json (notebook-full:enjs host book-name u.book) - ?> ?=(%o -.notebook-json) - =. p.notebook-json - (~(uni by p.notebook-json) (notes-page:enjs notes.u.book 0 50)) - =. p.notebook-json - (~(put by p.notebook-json) %subscribers (get-subscribers-json book-name)) - =/ notebooks-json (notebooks-map:enjs our.bol books) - =. p.notebook-json - (~(put by p.notebook-json) %writers (get-writers-json host book-name)) - ?> ?=(%o -.notebooks-json) - =/ host-books-json (~(got by p.notebooks-json) (scot %p host)) - ?> ?=(%o -.host-books-json) - =. p.host-books-json (~(put by p.host-books-json) book-name notebook-json) - =. p.notebooks-json - (~(put by p.notebooks-json) (scot %p host) host-books-json) - `(pairs notebooks+notebooks-json ~) -:: -++ get-note-json - |= [host=@p book-name=@tas note-name=@tas] - ^- (unit json) - =, enjs:format - =/ book=(unit notebook) (~(get by books) host book-name) - ?~ book - ~ - =/ note=(unit note) (~(get by notes.u.book) note-name) - ?~ note - ~ - =/ notebook-json (notebook-full:enjs host book-name u.book) - ?> ?=(%o -.notebook-json) - =/ note-json (note-presentation:enjs u.book note-name u.note) - =. p.notebook-json (~(uni by p.notebook-json) note-json) - =/ notebooks-json (notebooks-map:enjs our.bol books) - ?> ?=(%o -.notebooks-json) - =/ host-books-json (~(got by p.notebooks-json) (scot %p host)) - ?> ?=(%o -.host-books-json) - =. p.host-books-json (~(put by p.host-books-json) book-name notebook-json) - =. p.notebooks-json - (~(put by p.notebooks-json) (scot %p host) host-books-json) - `(pairs notebooks+notebooks-json ~) -:: ++ is-managed |= =path ^- ? ?> ?=(^ path) !=(i.path '~') :: -++ handle-http-request - |= req=inbound-request:eyre - ^- simple-payload:http - =/ url (parse-request-line url.request.req) - ?+ url not-found:gen - :: - :: pagination endpoints - :: - :: all notebooks, short form - [[[~ %json] [%'publish-view' %notebooks ~]] ~] - %- json-response:gen - (notebooks-map:enjs our.bol books) - :: - :: notes pagination - [[[~ %json] [%'publish-view' %notes @ @ @ @ ~]] ~] - =/ host=(unit @p) (slaw %p i.t.t.site.url) - ?~ host - not-found:gen - =/ book-name i.t.t.t.site.url - =/ book=(unit notebook) (~(get by books) u.host book-name) - ?~ book - not-found:gen - =/ start (rush i.t.t.t.t.site.url dem) - ?~ start - not-found:gen - =/ length (rush i.t.t.t.t.t.site.url dem) - ?~ length - not-found:gen - %- json-response:gen - :- %o - (notes-page:enjs notes.u.book u.start u.length) - :: - :: comments pagination - [[[~ %json] [%'publish-view' %comments @ @ @ @ @ ~]] ~] - =/ host=(unit @p) (slaw %p i.t.t.site.url) - ?~ host - not-found:gen - =/ book-name i.t.t.t.site.url - =/ book=(unit notebook) (~(get by books) u.host book-name) - ?~ book - not-found:gen - =/ note-name i.t.t.t.t.site.url - =/ note=(unit note) (~(get by notes.u.book) note-name) - ?~ note - not-found:gen - =/ start (rush i.t.t.t.t.t.site.url dem) - ?~ start - not-found:gen - =/ length (rush i.t.t.t.t.t.t.site.url dem) - ?~ length - not-found:gen - %- json-response:gen - (comments-page:enjs comments.u.note u.start u.length) - :: - :: single notebook with initial 50 notes in short form, as json - [[[~ %json] [%'publish-view' @ @ ~]] ~] - =, enjs:format - =/ host=(unit @p) (slaw %p i.t.site.url) - ?~ host not-found:gen - =/ book-name i.t.t.site.url - =/ book=(unit notebook) (~(get by books) u.host book-name) - ?~ book not-found:gen - =/ notebook-json (notebook-full:enjs u.host book-name u.book) - ?> ?=(%o -.notebook-json) - =. p.notebook-json - (~(uni by p.notebook-json) (notes-page:enjs notes.u.book 0 50)) - =. p.notebook-json - (~(put by p.notebook-json) %subscribers (get-subscribers-json book-name)) - =. p.notebook-json - (~(put by p.notebook-json) %writers (get-writers-json u.host book-name)) - (json-response:gen (pairs notebook+notebook-json ~)) - :: - :: single note, with initial 50 comments, as json - [[[~ %json] [%'publish-view' @ @ @ ~]] ~] - =, enjs:format - =/ host=(unit @p) (slaw %p i.t.site.url) - ?~ host not-found:gen - =/ book-name i.t.t.site.url - =/ book=(unit notebook) (~(get by books) u.host book-name) - ?~ book not-found:gen - =/ note-name i.t.t.t.site.url - =/ note=(unit note) (~(get by notes.u.book) note-name) - ?~ note not-found:gen - =/ jon=json - o+(note-presentation:enjs u.book note-name u.note) - (json-response:gen jon) - == +++ group-poke + |= =update:group-store + ^- card + [%pass / %agent [our.bol %group-store] %poke %group-update !>(update)] +:: +++ group-proxy-poke + |= [=ship =update:group-store] + ^- card + [%pass / %agent [ship %group-push-hook] %poke %group-update !>(update)] +++ contact-view-poke + |= act=contact-view-action:contact-view + ^- card + [%pass / %agent [our.bol %contact-view] %poke %contact-view-action !>(act)] +:: +++ contact-view-create + |= [=path ships=(set ship) =policy title=@t description=@t] + =/ rid=resource + (de-path:resource path) + =/ act=contact-view-action:contact-view + [%create name.rid policy title description] + (contact-view-poke act) +:: +++ check-host-migrate + |= rid=resource + ^- card + =/ res-path + (en-path:resource rid) + =- [%pass graph-migrate+res-path %agent -] + [[entity.rid %graph-push-hook] %watch resource+res-path] +:: + +:: +++ poke-our + |= [app=term =cage] + [%pass / %agent [our.bol app] %poke cage] +:: +++ poke-graph-pull + |= =action:pull-hook + (poke-our %graph-pull-hook pull-hook-action+!>(action)) :: -- diff --git a/pkg/arvo/app/soto.hoon b/pkg/arvo/app/soto.hoon index 2ca0c2620..29d9a7a94 100644 --- a/pkg/arvo/app/soto.hoon +++ b/pkg/arvo/app/soto.hoon @@ -1,74 +1,4 @@ +:: soto [tombstone]: former dojo relay for urbit's landscape interface :: -:: soto [landscape]: A Dojo relay for Urbit's Landscape interface -:: -:: Relays sole-effects to subscribers and forwards sole-action pokes -:: -/- sole -/+ *soto, default-agent -|% -+$ card card:agent:gall -:: -+$ versioned-state - $@ state-null - state-zero -:: -+$ state-null ~ -:: -+$ state-zero [%0 ~] --- -=| state-zero -=* state - -^- agent:gall -|_ bol=bowl:gall -+* this . - soto-core +> - sc ~(. soto-core bol) - def ~(. (default-agent this %|) bol) -:: -++ on-init - :_ this - :_ ~ - :* %pass /srv %agent [our.bol %file-server] - %poke %file-server-action - !>([%serve-dir /'~dojo' /app/landscape %.n %.y]) - == -++ on-save !>(state) -:: -++ on-load - |= old-vase=vase - =/ old - !<(versioned-state old-vase) - ?^ old - [~ this(state old)] - :_ this(state [%0 ~]) - :~ [%pass /bind/soto %arvo %e %disconnect [~ /'~dojo']] - :* %pass /srv %agent [our.bol %file-server] - %poke %file-server-action - !>([%serve-dir /'~dojo' /app/landscape %.n %.y]) - == - == -:: -++ on-poke on-poke:def -++ on-watch - |= pax=path - ^- (quip card _this) - ?+ pax (on-watch:def pax) - [%sototile ~] - :_ this - [%give %fact ~ %json !>(~)]~ - == -:: -++ on-agent on-agent:def -:: -++ on-arvo - |= [wir=wire sin=sign-arvo] - ^- (quip card _this) - ?: ?=(%bound +<.sin) - [~ this] - (on-arvo:def wir sin) -:: -++ on-fail on-fail:def -++ on-leave on-leave:def -++ on-peek on-peek:def -:: --- +/+ default-agent +(default-agent *agent:gall %|) diff --git a/pkg/arvo/app/spider.hoon b/pkg/arvo/app/spider.hoon index 1d4230c68..a328e0d47 100644 --- a/pkg/arvo/app/spider.hoon +++ b/pkg/arvo/app/spider.hoon @@ -1,5 +1,5 @@ /- spider -/+ libstrand=strand, default-agent, verb, server +/+ libstrand=strand, default-agent, verb, server =, strand=strand:libstrand |% +$ card card:agent:gall diff --git a/pkg/arvo/gen/graph-store/add-graph.hoon b/pkg/arvo/gen/graph-store/add-graph.hoon index a95468928..0192ede89 100644 --- a/pkg/arvo/gen/graph-store/add-graph.hoon +++ b/pkg/arvo/gen/graph-store/add-graph.hoon @@ -3,8 +3,8 @@ /+ *graph-store :- %say |= $: [now=@da eny=@uvJ =beak] - [[=resource mark=(unit mark) ~] ~] + [[=resource mark=(unit mark) overwrite=? ~] ~] == :- %graph-update ^- update -[%0 now [%add-graph resource (gas:orm ~ ~) mark]] +[%0 now [%add-graph resource (gas:orm ~ ~) mark overwrite]] diff --git a/pkg/arvo/lib/base64.hoon b/pkg/arvo/lib/base64.hoon index 6843f8be8..aa5887419 100644 --- a/pkg/arvo/lib/base64.hoon +++ b/pkg/arvo/lib/base64.hoon @@ -3,6 +3,7 @@ :: pad: include padding when encoding, require when decoding :: url: use url-safe characters '-' for '+' and '_' for '/' :: +:: =+ [pad=& url=|] |% :: diff --git a/pkg/arvo/lib/bip32.hoon b/pkg/arvo/lib/bip32.hoon index 1d4722d4e..90ec0a07b 100644 --- a/pkg/arvo/lib/bip32.hoon +++ b/pkg/arvo/lib/bip32.hoon @@ -81,11 +81,11 @@ ++ derivation-path ;~ pfix ;~(pose (jest 'm/') (easy ~)) - %+ most net + %+ most fas ;~ pose %+ cook |=(i=@ (add i (bex 31))) - ;~(sfix dem say) + ;~(sfix dem soq) :: dem == == diff --git a/pkg/arvo/lib/graph-store.hoon b/pkg/arvo/lib/graph-store.hoon index 4ed56c4a7..a6055bb10 100644 --- a/pkg/arvo/lib/graph-store.hoon +++ b/pkg/arvo/lib/graph-store.hoon @@ -34,6 +34,79 @@ ++ enjs =, enjs:format |% + :: + ++ signatures + |= s=^signatures + ^- json + [%a (turn ~(tap in s) signature)] + :: + ++ signature + |= s=^signature + ^- json + %- pairs + :~ [%signature s+(scot %ux p.s)] + [%ship (ship q.s)] + [%life (numb r.s)] + == + :: + ++ index + |= i=^index + ^- json + ?: =(~ i) s+'/' + =/ j=^tape "" + |- + ?~ i [%s (crip j)] + =/ k=json (numb i.i) + ?> ?=(%n -.k) + %_ $ + i t.i + j (weld j (weld "/" (trip +.k))) + == + :: + ++ uid + |= u=^uid + ^- json + %- pairs + :~ [%resource (enjs:res resource.u)] + [%index (index index.u)] + == + :: + ++ content + |= c=^content + ^- json + ?- -.c + %mention (frond %mention (ship ship.c)) + %text (frond %text s+text.c) + %url (frond %url s+url.c) + %reference (frond %reference (uid uid.c)) + %code + %+ frond %code + %- pairs + :- [%expression s+expression.c] + :_ ~ + :- %output + :: virtualize output rendering, +tank:enjs:format might crash + :: + =/ result=(each (list json) tang) + (mule |.((turn output.c tank))) + ?- -.result + %& a+p.result + %| a+[a+[%s '[[output rendering error]]']~]~ + == + == + :: + ++ post + |= p=^post + ^- json + %- pairs + :~ [%author (ship author.p)] + [%index (index index.p)] + [%time-sent (time time-sent.p)] + [%contents [%a (turn contents.p content)]] + [%hash ?~(hash.p ~ s+(scot %ux u.hash.p))] + [%signatures (signatures signatures.p)] + == + :: ++ update |= upd=^update ^- json @@ -50,6 +123,7 @@ :~ [%resource (enjs:res resource.upd)] [%graph (graph graph.upd)] [%mark ?~(mark.upd ~ s+u.mark.upd)] + [%overwrite b+overwrite.upd] == :: %remove-graph @@ -132,20 +206,6 @@ :~ (index [a]~) (node n) == - :: - ++ index - |= i=^index - ^- json - =/ j=^tape "" - |- - ?~ i [%s (crip j)] - =/ k=json (numb i.i) - ?> ?=(%n -.k) - %_ $ - i t.i - j (weld j (weld "/" (trip +.k))) - == - :: ++ node |= n=^node ^- json @@ -158,41 +218,7 @@ == == :: - ++ post - |= p=^post - ^- json - %- pairs - :~ [%author (ship author.p)] - [%index (index index.p)] - [%time-sent (time time-sent.p)] - [%contents [%a (turn contents.p content)]] - [%hash ?~(hash.p ~ s+(scot %ux u.hash.p))] - [%signatures (signatures signatures.p)] - == - :: - ++ content - |= c=^content - ^- json - ?- -.c - %text (frond %text s+text.c) - %url (frond %url s+url.c) - %reference (frond %reference (uid uid.c)) - %code - %+ frond %code - %- pairs - :- [%expression s+expression.c] - :_ ~ - :- %output - :: virtualize output rendering, +tank:enjs:format might crash - :: - =/ result=(each (list json) tang) - (mule |.((turn output.c tank))) - ?- -.result - %& a+p.result - %| a+[a+[%s '[[output rendering error]]']~]~ - == - == - :: + :: ++ nodes |= m=(map ^index ^node) ^- json @@ -210,27 +236,6 @@ ^- json [%a (turn ~(tap in i) index)] :: - ++ uid - |= u=^uid - ^- json - %- pairs - :~ [%resource (enjs:res resource.u)] - [%index (index index.u)] - == - :: - ++ signatures - |= s=^signatures - ^- json - [%a (turn ~(tap in s) signature)] - :: - ++ signature - |= s=^signature - ^- json - %- pairs - :~ [%signature s+(scot %ux p.s)] - [%ship (ship q.s)] - [%life (numb r.s)] - == -- -- :: @@ -272,6 +277,7 @@ :~ [%resource dejs:res] [%graph graph] [%mark (mu so)] + [%overwrite bo] == :: ++ graph @@ -295,14 +301,19 @@ [%nodes nodes] == :: - ++ nodes (op ;~(pfix net (more net dem)) node) + ++ nodes (op ;~(pfix fas (more fas dem)) node) :: ++ node %- ot :~ [%post post] - :: TODO: support adding nodes with children by supporting the - :: graph key - [%children (of [%empty ul]~)] + [%children internal-graph] + == + :: + ++ internal-graph + ^- $-(json ^internal-graph) + %- of + :~ [%empty ul] + [%graph graph] == :: ++ post @@ -317,7 +328,8 @@ :: ++ content %- of - :~ [%text so] + :~ [%mention (su ;~(pfix sig fed:ag))] + [%text so] [%url so] [%reference uid] [%code eval] @@ -366,7 +378,7 @@ [%index index] == :: - ++ index (su ;~(pfix net (more net dem))) + ++ index (su ;~(pfix fas (more fas dem))) :: ++ add-tag %- ot diff --git a/pkg/arvo/lib/graph.hoon b/pkg/arvo/lib/graph.hoon index 2e2bcdf1e..2d2046801 100644 --- a/pkg/arvo/lib/graph.hoon +++ b/pkg/arvo/lib/graph.hoon @@ -17,6 +17,18 @@ %+ scry-for update:store /graph/(scot %p entity.res)/[name.res] :: +++ got-node + |= [res=resource =index:store] + ^- node:store + =+ %+ scry-for ,=update:store + %+ weld + /node/(scot %p entity.res)/[name.res] + (turn index (cury scot %ud)) + ?> ?=(%0 -.update) + ?> ?=(%add-nodes -.q.update) + ?> ?=(^ nodes.q.update) + q.n.nodes.q.update +:: ++ get-update-log |= rid=resource ^- update-log:store @@ -33,4 +45,12 @@ ^- update-log:store %+ scry-for update-log:store /update-log-subset/(scot %p entity.res)/[name.res]/(scot %da start)/'~' +:: +++ get-keys + ^- resources + =+ %+ scry-for ,=update:store + /keys + ?> ?=(%0 -.update) + ?> ?=(%keys -.q.update) + resources.q.update -- diff --git a/pkg/arvo/lib/hark/chat-hook.hoon b/pkg/arvo/lib/hark/chat-hook.hoon new file mode 100644 index 000000000..1bdd167f5 --- /dev/null +++ b/pkg/arvo/lib/hark/chat-hook.hoon @@ -0,0 +1,30 @@ +/- sur=hark-chat-hook +^? +=< [. sur] +=, sur +|% +++ dejs + =, dejs:format + |% + ++ action + %- of + :~ listen+pa + ignore+pa + set-mentions+bo + == + -- +:: +++ enjs + =, enjs:format + |% + ++ update + |= upd=^update + %+ frond -.upd + ?- -.upd + ?(%listen %ignore) (path chat.upd) + %set-mentions b+mentions.upd + %initial a+(turn ~(tap in watching.upd) path) + == + -- +-- + diff --git a/pkg/arvo/lib/hark/graph-hook.hoon b/pkg/arvo/lib/hark/graph-hook.hoon new file mode 100644 index 000000000..d379236ff --- /dev/null +++ b/pkg/arvo/lib/hark/graph-hook.hoon @@ -0,0 +1,66 @@ +/- sur=hark-graph-hook, post +/+ graph-store, resource +^? +=< [. sur] +=, sur +|% +++ dejs + =, dejs:format + |% + :: + ++ index + ^- $-(json index:graph-store) + (su ;~(pfix net (more net dem))) + :: + ++ graph-index + %- ot + :~ graph+dejs-path:resource + index+index + == + :: + ++ action + %- of + :~ listen+graph-index + ignore+graph-index + set-mentions+bo + set-watch-on-self+bo + == + -- +:: +++ enjs + =, enjs:format + |% + :: + ++ graph-index + |= [graph=resource =index:post] + %- pairs + :~ graph+s+(enjs-path:resource graph) + index+(index:enjs:graph-store index) + == + :: + ++ action + |= act=^action + ^- json + %+ frond -.act + ?- -.act + %set-watch-on-self b+watch-on-self.act + %set-mentions b+mentions.act + ?(%listen %ignore) (graph-index graph.act index.act) + == + :: + :: + :: + ++ update + |= upd=^update + ^- json + ?. ?=(%initial -.upd) + (action upd) + %+ frond -.upd + %- pairs + :~ 'watchOnSelf'^b+watch-on-self.upd + 'mentions'^b+mentions.upd + :+ %watching %a + (turn ~(tap in watching.upd) graph-index) + == + -- +-- diff --git a/pkg/arvo/lib/hark/group-hook.hoon b/pkg/arvo/lib/hark/group-hook.hoon new file mode 100644 index 000000000..e32ee8bd7 --- /dev/null +++ b/pkg/arvo/lib/hark/group-hook.hoon @@ -0,0 +1,34 @@ +/- sur=hark-group-hook +/+ resource +^? +=< [. sur] +=, sur +|% +++ dejs + =, dejs:format + |% + ++ action + %- of + :~ listen+dejs-path:resource + ignore+dejs-path:resource + == + -- +:: +++ enjs + =, enjs:format + |% + ++ res + (cork enjs-path:resource (lead %s)) + :: + ++ update + |= upd=^update + %+ frond -.upd + ?- -.upd + ?(%listen %ignore) (res group.upd) + :: + %initial + :- %a + (turn ~(tap in watching.upd) res) + == + -- +-- diff --git a/pkg/arvo/lib/hark/store.hoon b/pkg/arvo/lib/hark/store.hoon new file mode 100644 index 000000000..f9448f1e8 --- /dev/null +++ b/pkg/arvo/lib/hark/store.hoon @@ -0,0 +1,226 @@ +/- sur=hark-store, post +/+ resource, graph-store, group-store, chat-store +^? +=< [. sur] +=, sur +|% +++ dejs + =, dejs:format + |% + ++ index + %- of + :~ graph+graph-index + group+group-index + chat+chat-index + == + :: + ++ chat-index + %- ot + :~ chat+pa + mention+bo + == + :: + ++ group-index + %- ot + :~ group+dejs-path:resource + description+so + == + :: + ++ graph-index + %- ot + :~ group+dejs-path:resource + graph+dejs-path:resource + module+so + description+so + == + :: parse date as @ud + :: TODO: move to zuse + ++ sd + |= jon=json + ^- @da + ?> ?=(%s -.jon) + `@da`(rash p.jon dem:ag) + + :: + ++ notif-ref + ^- $-(json [@da ^index]) + %- ot + :~ time+sd + index+index + == + :: + ++ add + |= jon=json + [*^index *notification] + :: + ++ action + ^- $-(json ^action) + %- of + :~ seen+ul + archive+notif-ref + unread+notif-ref + read+notif-ref + add+add + set-dnd+bo + read-index+index + == + -- +:: +++ enjs + =, enjs:format + |% + ++ update + |= upd=^update + ^- json + |^ + %+ frond -.upd + ?+ -.upd a+~ + %added (added +.upd) + %timebox (timebox +.upd) + %set-dnd b+dnd.upd + %count (numb count.upd) + %unreads (unreads unreads.upd) + %more (more +.upd) + :: + ?(%archive %read %unread) + (notif-ref +.upd) + == + :: + ++ unreads + |= l=(list [^index @ud]) + ^- json + :- %a + ^- (list json) + %+ turn l + |= [idx=^index unread=@ud] + %- pairs + :~ unread+(numb unread) + index+(index idx) + == + :: + ++ added + |= [tim=@da idx=^index not=^notification] + ^- json + %- pairs + :~ time+s+(scot %ud tim) + index+(index idx) + notification+(notification not) + == + :: + ++ notif-ref + |= [tim=@da idx=^index] + ^- json + %- pairs + :~ time+s+(scot %ud tim) + index+(index idx) + == + :: + ++ more + |= upds=(list ^update) + ^- json + a+(turn upds update) + :: + ++ index + |= =^index + %+ frond -.index + |^ + ?- -.index + %graph (graph-index +.index) + %group (group-index +.index) + %chat (chat-index +.index) + == + :: + ++ chat-index + |= [chat=^path mention=?] + ^- json + %- pairs + :~ chat+(path chat) + mention+b+mention + == + :: + ++ graph-index + |= [group=resource graph=resource module=@t description=@t] + ^- json + %- pairs + :~ group+s+(enjs-path:resource group) + graph+s+(enjs-path:resource graph) + module+s+module + description+s+description + == + :: + ++ group-index + |= [group=resource description=@t] + ^- json + %- pairs + :~ group+s+(enjs-path:resource group) + description+s+description + == + -- + :: + ++ notification + |= ^notification + ^- json + %- pairs + :~ time+(time date) + read+b+read + contents+(^contents contents) + == + :: + ++ contents + |= =^contents + ^- json + %+ frond -.contents + |^ + ?- -.contents + %graph (graph-contents +.contents) + %group (group-contents +.contents) + %chat (chat-contents +.contents) + == + :: + ++ chat-contents + |= =(list envelope:chat-store) + ^- json + :- %a + (turn list envelope:enjs:chat-store) + :: + ++ graph-contents + |= =(list post:post) + ^- json + :- %a + (turn list post:enjs:graph-store) + :: + ++ group-contents + |= =(list ^group-contents) + ^- json + :- %a + %+ murn list + |= =^group-contents + ?. ?=(?(%add-members %remove-members) -.group-contents) + ~ + `(update:enjs:group-store group-contents) + -- + :: + ++ indexed-notification + |= [=^index =^notification] + %- pairs + :~ index+(^index index) + notification+(^notification notification) + == + :: + ++ timebox + |= [tim=@da arch=? l=(list [^index ^notification])] + ^- json + %- pairs + :~ time+s+(scot %ud tim) + archive+b+arch + :- %notifications + ^- json + :- %a + %+ turn l + |= [=^index =^notification] + ^- json + (indexed-notification index notification) + == + -- + -- +-- diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 0388ab894..84ddfa0f7 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -91,7 +91,7 @@ %chat-hook %chat-view %chat-cli - %soto + %herm %contact-store %contact-hook %contact-view @@ -107,6 +107,11 @@ %graph-store %graph-pull-hook %graph-push-hook + %hark-store + %hark-graph-hook + %hark-group-hook + %hark-chat-hook + %observe-hook == :: ++ deft-fish :: default connects @@ -209,7 +214,7 @@ == :: ++ on-load - |= [hood-version=?(%1 %2 %3 %4 %5 %6 %7 %8 %9 %10) old=any-state] + |= [hood-version=@ud old=any-state] =< se-abet =< se-view =. sat old =. dev (~(gut by bin) ost *source) @@ -237,10 +242,17 @@ => (se-born | %home %group-push-hook) (se-born | %home %group-pull-hook) =? ..on-load (lte hood-version %9) - (se-born | %home %graph-store) + (se-born | %home %graph-store) =? ..on-load (lte hood-version %10) => (se-born | %home %graph-push-hook) (se-born | %home %graph-pull-hook) + =? ..on-load (lte hood-version %11) + => (se-born | %home %hark-graph-hook) + => (se-born | %home %hark-group-hook) + => (se-born | %home %hark-chat-hook) + => (se-born | %home %hark-store) + => (se-born | %home %observe-hook) + (se-born | %home %herm) ..on-load :: ++ reap-phat :: ack connect @@ -556,7 +568,6 @@ ++ se-show :: show buffer, raw |= lin/(pair @ud stub) ^+ +> - =. p.lin (add p.lin (lent-stye:klr q.lin)) ?: =(mir lin) +> =. +> ?:(=(p.mir p.lin) +> (se-blit %hop p.lin)) =. +> ?:(=(q.mir q.lin) +> (se-blit %pom q.lin)) @@ -1120,25 +1131,10 @@ (fall p.q.a p.q.b) (fall q.q.a q.q.b) :: - ++ lent-stye - |= a/stub ^- @ - (roll (lnts-stye a) add) - :: ++ lent-char |= a/stub ^- @ (roll (lnts-char a) add) :: - ++ lnts-stye :: stub pair head lengths - |= a/stub ^- (list @) - %+ turn a - |= a/(pair stye (list @c)) - ;: add :: presumes impl of cvrt:ansi in %dill - (mul 5 2) :: bg - (mul 5 2) :: fg - =+ b=~(wyt in p.p.a) :: effect - ?:(=(0 b) 0 (mul 4 +(b))) - == - :: ++ lnts-char :: stub pair tail lengths |= a/stub ^- (list @) %+ turn a diff --git a/pkg/arvo/lib/invite-json.hoon b/pkg/arvo/lib/invite-json.hoon index c28cd16c8..7faac97d0 100644 --- a/pkg/arvo/lib/invite-json.hoon +++ b/pkg/arvo/lib/invite-json.hoon @@ -1,4 +1,5 @@ /- *invite-store +/+ resource |% ++ slan |=(mod/@tas |=(txt/@ta (need (slaw mod txt)))) :: @@ -12,9 +13,9 @@ ^- json %- pairs:enjs:format %+ turn ~(tap by inv) - |= [=path =invitatory] + |= [=term =invitatory] ^- [cord json] - [(spat path) (invitatory-to-json invitatory)] + [term (invitatory-to-json invitatory)] :: ++ invitatory-to-json |= =invitatory @@ -33,13 +34,13 @@ %- pairs :~ [%ship (ship ship.invite)] [%app [%s app.invite]] - [%path (path path.invite)] + [%resource (enjs:resource resource.invite)] [%recipient (ship recipient.invite)] [%text [%s text.invite]] == :: ++ update-to-json - |= upd=invite-update + |= upd=update =, enjs:format ^- json %+ frond %invite-update @@ -50,15 +51,15 @@ [%initial (invites-to-json invites.upd)] ?: =(%create -.upd) ?> ?=(%create -.upd) - [%create (pairs [%path (path path.upd)]~)] + [%create (pairs [%term s+term.upd]~)] ?: =(%delete -.upd) ?> ?=(%delete -.upd) - [%delete (pairs [%path (path path.upd)]~)] + [%delete (pairs [%term s+term.upd]~)] ?: =(%accepted -.upd) ?> ?=(%accepted -.upd) :- %accepted %- pairs - :~ [%path (path path.upd)] + :~ [%term s+term.upd] [%uid s+(scot %uv uid.upd)] [%invite (invite-to-json invite.upd)] == @@ -66,14 +67,14 @@ ?> ?=(%decline -.upd) :- %decline %- pairs - :~ [%path (path path.upd)] + :~ [%term s+term.upd] [%uid s+(scot %uv uid.upd)] == ?: =(%invite -.upd) ?> ?=(%invite -.upd) :- %invite %- pairs - :~ [%path (path path.upd)] + :~ [%term s+term.upd] [%uid s+(scot %uv uid.upd)] [%invite (invite-to-json invite.upd)] == @@ -88,53 +89,45 @@ :: ++ json-to-action |= jon=json - ^- invite-action + ^- action =, dejs:format =< (parse-json jon) |% ++ parse-json %- of - :~ [%create create] - [%delete delete] + :~ [%create so] + [%delete so] [%invite invite] [%accept accept] [%decline decline] == :: - ++ create - (ot [%path pa]~) - :: - ++ delete - (ot [%path pa]~) - :: - ++ invite %- ot - :~ [%path pa] + :~ [%term so] [%uid seri] [%invite invi] == :: ++ accept %- ot - :~ [%path pa] + :~ [%term so] [%uid seri] == :: ++ decline %- ot - :~ [%path pa] + :~ [%term so] [%uid seri] == :: ++ invi %- ot :~ [%ship (su ;~(pfix sig fed:ag))] - [%app (se %tas)] - [%path pa] + [%app so] + [%resource dejs:resource] [%recipient (su ;~(pfix sig fed:ag))] [%text so] == -- -- - diff --git a/pkg/arvo/lib/language-server/build.hoon b/pkg/arvo/lib/language-server/build.hoon index 9c6e3dfd6..015f37b88 100644 --- a/pkg/arvo/lib/language-server/build.hoon +++ b/pkg/arvo/lib/language-server/build.hoon @@ -7,13 +7,13 @@ =/ parse-pair %+ cook |=([row=@ud col=@ud] [(dec row) col]) - (ifix [lac rac] ;~((glue ace) dem dem)) + (ifix [sel ser] ;~((glue ace) dem dem)) =/ parse-path %+ cook |=(p=path (slag 3 p)) - (ifix [net (jest '::')] (more net urs:ab)) + (ifix [fas (jest '::')] (more fas urs:ab)) =/ parse-full - ;~(plug parse-path ;~(sfix ;~((glue dot) parse-pair parse-pair) ban)) + ;~(plug parse-path ;~(sfix ;~((glue dot) parse-pair parse-pair) gar)) (rust tape parse-full) :: ++ get-errors-from-tang diff --git a/pkg/arvo/lib/language-server/parser.hoon b/pkg/arvo/lib/language-server/parser.hoon index 4564c22f0..339d31972 100644 --- a/pkg/arvo/lib/language-server/parser.hoon +++ b/pkg/arvo/lib/language-server/parser.hoon @@ -11,7 +11,7 @@ :: parse optional /? and ignore :: ;~ pose - (cold ~ ;~(plug net wut gap dem gap)) + (cold ~ ;~(plug fas wut gap dem gap)) (easy ~) == :: @@ -20,7 +20,7 @@ ;~ sfix %+ cook |=((list (list taut)) (zing +<)) %+ more gap - ;~ pfix ;~(plug net hep gap) + ;~ pfix ;~(plug fas hep gap) (most ;~(plug com gaw) taut-rule) == gap @@ -32,7 +32,7 @@ ;~ sfix %+ cook |=((list (list taut)) (zing +<)) %+ more gap - ;~ pfix ;~(plug net lus gap) + ;~ pfix ;~(plug fas lus gap) (most ;~(plug com gaw) taut-rule) == gap @@ -44,9 +44,9 @@ ;~ sfix %+ cook |=((list [face=term =path]) +<) %+ more gap - ;~ pfix ;~(plug net tis gap) + ;~ pfix ;~(plug fas tis gap) %+ cook |=([term path] +<) - ;~(plug sym ;~(pfix ;~(plug gap net) (more net urs:ab))) + ;~(plug sym ;~(pfix ;~(plug gap fas) (more fas urs:ab))) == gap == @@ -57,12 +57,12 @@ ;~ sfix %+ cook |=((list [face=term =mark =path]) +<) %+ more gap - ;~ pfix ;~(plug net tar gap) + ;~ pfix ;~(plug fas tar gap) %+ cook |=([term mark path] +<) ;~ plug sym ;~(pfix ;~(plug gap cen) sym) - ;~(pfix ;~(plug gap net) (more net urs:ab)) + ;~(pfix ;~(plug gap fas) (more fas urs:ab)) == == gap diff --git a/pkg/arvo/lib/metadata.hoon b/pkg/arvo/lib/metadata.hoon index 32d5bf4a6..71c894b20 100644 --- a/pkg/arvo/lib/metadata.hoon +++ b/pkg/arvo/lib/metadata.hoon @@ -1,6 +1,7 @@ :: metadata: helpers for getting data from the metadata-store :: /- *metadata-store +/+ res=resource :: |_ =bowl:gall ++ app-paths-from-group @@ -21,6 +22,27 @@ ?. =(app-name.md-resource app-name) ~ `app-path.md-resource :: +++ peek-metadata + |= [app-name=term =group=resource:res =app=resource:res] + ^- (unit metadata) + =/ group-cord=cord (scot %t (spat (en-path:res group-resource))) + =/ app-cord=cord (scot %t (spat (en-path:res app-resource))) + =/ our=cord (scot %p our.bowl) + =/ now=cord (scot %da now.bowl) + .^ (unit metadata) + %gx (scot %p our.bowl) %metadata-store (scot %da now.bowl) + %metadata group-cord app-name app-cord /noun + == +:: +++ group-from-app-resource + |= [app=term =app=resource:res] + ^- (unit resource:res) + =/ app-path (en-path:res app-resource) + =/ group-paths (groups-from-resource app app-path) + ?~ group-paths + ~ + `(de-path:res i.group-paths) +:: ++ groups-from-resource |= =md-resource ^- (list group-path) diff --git a/pkg/arvo/lib/publish.hoon b/pkg/arvo/lib/publish.hoon index 2a035aad5..2db1066ad 100644 --- a/pkg/arvo/lib/publish.hoon +++ b/pkg/arvo/lib/publish.hoon @@ -1,240 +1,4 @@ /- sur=publish /+ elem-to-react-json ^? -=< [. sur] -=, sur -|% -:: -++ enjs - =, enjs:format - |% - :: - ++ tang - |= tan=^tang - %- wall - %- zing - %+ turn tan - |= a=^tank - (wash [0 80] a) - :: - ++ note-build - |= build=(each manx ^tang) - ^- json - ?: ?=(%.y -.build) - %- pairs - :~ success+b+%.y - result+(elem-to-react-json p.build) - == - %- pairs - :~ success+b+%.n - result+(tang p.build) - == - :: - ++ notebooks-list - |= [our=@p books=(map @tas notebook) subs=(map [@p @tas] notebook)] - ^- json - :- %a - %+ weld - %+ turn ~(tap by books) - |= [name=@tas book=notebook] - (notebook-short book) - %+ turn ~(tap by subs) - |= [[host=@p name=@tas] book=notebook] - (notebook-short book) - :: - ++ notebooks-map - |= [our=@p books=(map [@p @tas] notebook)] - ^- json - =/ notebooks-map=json - %- ~(rep by books) - |= [[[host=@p book-name=@tas] book=notebook] out=json] - ^- json - =/ host-ta (scot %p host) - ?~ out - (frond host-ta (frond book-name (notebook-short book))) - ?> ?=(%o -.out) - =/ books (~(get by p.out) host-ta) - ?~ books - :- %o - (~(put by p.out) host-ta (frond book-name (notebook-short book))) - ?> ?=(%o -.u.books) - =. p.u.books (~(put by p.u.books) book-name (notebook-short book)) - :- %o - (~(put by p.out) host-ta u.books) - =? notebooks-map ?=(~ notebooks-map) - [%o ~] - notebooks-map - :: - ++ notebook-short - |= book=notebook - ^- json - %- pairs - :~ title+s+title.book - date-created+(time date-created.book) - about+s+description.book - num-notes+(numb ~(wyt by notes.book)) - num-unread+(numb (count-unread notes.book)) - comments+b+comments.book - writers-group-path+s+(spat writers.book) - subscribers-group-path+s+(spat subscribers.book) - == - :: - ++ notebook-full - |= [host=@p book-name=@tas book=notebook] - ^- json - %- pairs - :~ title+s+title.book - about+s+description.book - date-created+(time date-created.book) - num-notes+(numb ~(wyt by notes.book)) - num-unread+(numb (count-unread notes.book)) - notes-by-date+(notes-by-date notes.book) - comments+b+comments.book - writers-group-path+s+(spat writers.book) - subscribers-group-path+s+(spat subscribers.book) - == - :: - ++ note-presentation - |= [book=notebook note-name=@tas not=note] - ^- (map @t json) - =/ notes-list=(list [@tas note]) - %+ sort ~(tap by notes.book) - |= [[@tas n1=note] [@tas n2=note]] - (gte date-created.n1 date-created.n2) - =/ idx=@ (need (find [note-name not]~ notes-list)) - =/ next=(unit [name=@tas not=note]) - ?: =(idx 0) ~ - `(snag (dec idx) notes-list) - =/ prev=(unit [name=@tas not=note]) - ?: =(+(idx) (lent notes-list)) ~ - `(snag +(idx) notes-list) - =/ current=json (note-full note-name not) - ?> ?=(%o -.current) - =. p.current (~(put by p.current) %prev-note ?~(prev ~ s+name.u.prev)) - =. p.current (~(put by p.current) %next-note ?~(next ~ s+name.u.next)) - =/ notes=(list [@t json]) [note-name current]~ - =? notes ?=(^ prev) - [[name.u.prev (note-short name.u.prev not.u.prev)] notes] - =? notes ?=(^ next) - [[name.u.next (note-short name.u.next not.u.next)] notes] - %- my - :~ notes+(pairs notes) - notes-by-date+a+(turn notes-list |=([name=@tas *] s+name)) - == - :: - ++ note-full - |= [note-name=@tas =note] - ^- json - %- pairs - :~ note-id+s+note-name - author+s+(scot %p author.note) - title+s+title.note - date-created+(time date-created.note) - snippet+s+snippet.note - file+s+file.note - num-comments+(numb ~(wyt by comments.note)) - comments+(comments-page:enjs comments.note 0 50) - read+b+read.note - pending+b+pending.note - == - :: - ++ notes-by-date - |= notes=(map @tas note) - ^- json - =/ notes-list=(list [@tas note]) - %+ sort ~(tap by notes) - |= [[@tas n1=note] [@tas n2=note]] - (gte date-created.n1 date-created.n2) - :- %a - %+ turn notes-list - |= [name=@tas note] - ^- json - [%s name] - :: - ++ note-short - |= [note-name=@tas =note] - ^- json - %- pairs - :~ note-id+s+note-name - author+s+(scot %p author.note) - title+s+title.note - date-created+(time date-created.note) - num-comments+(numb ~(wyt by comments.note)) - read+b+read.note - snippet+s+snippet.note - pending+b+pending.note - == - :: - ++ notes-page - |= [notes=(map @tas note) start=@ud length=@ud] - ^- (map @t json) - =/ notes-list=(list [@tas note]) - %+ sort ~(tap by notes) - |= [[@tas n1=note] [@tas n2=note]] - (gte date-created.n1 date-created.n2) - %- my - :~ notes-by-date+a+(turn notes-list |=([name=@tas *] s+name)) - notes+o+(^notes-list (scag length (slag start notes-list))) - == - :: - ++ notes-list - |= notes=(list [@tas note]) - ^- (map @t json) - %+ roll notes - |= [[name=@tas not=note] out-map=(map @t json)] - ^- (map @t json) - (~(put by out-map) name (note-short name not)) - :: - ++ comments-page - |= [comments=(map @da ^comment) start=@ud end=@ud] - ^- json - =/ coms=(list [@da ^comment]) - %+ sort ~(tap by comments) - |= [[d1=@da ^comment] [d2=@da ^comment]] - (gte d1 d2) - %- comments-list - (scag end (slag start coms)) - :: - ++ comments-list - |= comments=(list [@da ^comment]) - ^- json - :- %a - (turn comments comment) - :: - ++ comment - |= [date=@da com=^comment] - ^- json - %+ frond - (scot %da date) - %- pairs - :~ author+s+(scot %p author.com) - date-created+(time date-created.com) - content+s+content.com - pending+b+pending.com - == - -- -:: -++ string-to-symbol - |= tap=tape - ^- @tas - %- crip - %+ turn tap - |= a=@ - ?: ?| &((gte a 'a') (lte a 'z')) - &((gte a '0') (lte a '9')) - == - a - ?: &((gte a 'A') (lte a 'Z')) - (add 32 a) - '-' -:: -++ count-unread - |= notes=(map @tas note) - ^- @ud - %- ~(rep by notes) - |= [[key=@tas val=note] count=@ud] - ?: read.val - count - +(count) -:: --- +sur diff --git a/pkg/arvo/lib/pull-hook.hoon b/pkg/arvo/lib/pull-hook.hoon index ce4954bb6..cb3b5e6f7 100644 --- a/pkg/arvo/lib/pull-hook.hoon +++ b/pkg/arvo/lib/pull-hook.hoon @@ -38,16 +38,24 @@ push-hook-name=term == :: -:: $state-0: state for the pull hook +:: $base-state-0: state for the pull hook :: :: .tracking: a map of resources we are pulling, and the ships that :: we are pulling them from. :: .inner-state: state given to internal door :: -+$ state-0 - $: %0 - tracking=(map resource ship) - inner-state=vase ++$ base-state-0 + $: tracking=(map resource ship) + inner-state=vase + == +:: ++$ state-0 [%0 base-state-0] +:: ++$ state-1 [%1 base-state-0] +:: ++$ versioned-state + $% state-0 + state-1 == :: ++ default @@ -133,7 +141,7 @@ ++ agent |* =config |= =(pull-hook config) - =| state-0 + =| state-1 =* state - ^- agent:gall =< @@ -149,12 +157,40 @@ [cards this] ++ on-load |= =old=vase - ^- [(list card:agent:gall) agent:gall] =/ old - !<(state-0 old-vase) - =^ cards pull-hook - (on-load:og inner-state.old) - [cards this(state old)] + !<(versioned-state old-vase) + =| cards=(list card:agent:gall) + |^ + ?- -.old + %1 + =^ og-cards pull-hook + (on-load:og inner-state.old) + [(weld cards og-cards) this(state old)] + :: + %0 + %_ $ + -.old %1 + :: + cards + (weld cards (missing-subscriptions tracking.old)) + == + == + ++ missing-subscriptions + |= tracking=(map resource ship) + ^- (list card:agent:gall) + %+ murn + ~(tap by tracking) + |= [rid=resource =ship] + ^- (unit card:agent:gall) + =/ =path + resource+(en-path:resource rid) + =/ =wire + (make-wire pull+path) + ?: (~(has by wex.bowl) [wire ship push-hook-name.config]) + ~ + `[%pass wire %agent [ship push-hook-name.config] %watch path] + -- + :: ++ on-save ^- vase =. inner-state diff --git a/pkg/arvo/lib/push-hook.hoon b/pkg/arvo/lib/push-hook.hoon index 9f9e2af3a..9553745eb 100644 --- a/pkg/arvo/lib/push-hook.hoon +++ b/pkg/arvo/lib/push-hook.hoon @@ -45,17 +45,24 @@ pull-hook-name=term == :: -:: $state-0: state for the push hook +:: $base-state-0: state for the push hook :: :: .sharing: resources that the push hook is proxying :: .inner-state: state given to internal door :: -+$ state-0 - $: %0 - sharing=(set resource) - inner-state=vase ++$ base-state-0 + $: sharing=(set resource) + inner-state=vase == :: ++$ state-0 [%0 base-state-0] +:: ++$ state-1 [%1 base-state-0] +:: ++$ versioned-state + $% state-0 + state-1 + == ++ push-hook |* =config $_ ^| @@ -144,7 +151,7 @@ ++ agent |* =config |= =(push-hook config) - =| state-0 + =| state-1 =* state - ^- agent:gall =< @@ -163,10 +170,39 @@ ++ on-load |= =old=vase =/ old - !<(state-0 old-vase) - =^ cards push-hook - (on-load:og inner-state.old) - `this(state old) + !<(versioned-state old-vase) + =| cards=(list card:agent:gall) + |^ + ?- -.old + %1 + =^ og-cards push-hook + (on-load:og inner-state.old) + [(weld cards og-cards) this(state old)] + :: + %0 + %_ $ + -.old %1 + :: + cards + =/ paths=(list path) + kicked-watches + ?~ paths cards + :_ cards + [%give %kick paths ~] + == + == + :: + ++ kicked-watches + ^- (list path) + %~ tap in + %+ roll + ~(val by sup.bowl) + |= [[=ship =path] out=(set path)] + ?~ path out + ?. (lth 4 (lent path)) + out + (~(put in out) path) + -- :: ++ on-save =. inner-state @@ -282,14 +318,15 @@ |= rid=resource =/ pax=path [%resource (en-path:resource rid)] - =/ paths=(list path) + =/ paths=(set path) + %- sy %+ turn (incoming-subscriptions pax) - |=([ship pox=path] pax) + |=([ship pox=path] pox) =. sharing (~(del in sharing) rid) :_ state - [%give %kick ~[pax] ~]~ + [%give %kick ~(tap in paths) ~]~ :: ++ revoke |= [ships=(set ship) rid=resource] @@ -334,9 +371,14 @@ =/ rid=(unit resource) (resource-for-update:og vase) ?~ rid ~ - =/ =path + =/ prefix=path resource+(en-path:resource u.rid) - [%give %fact ~[path] update-mark.config vase]~ + =/ paths=(list path) + %+ turn + (incoming-subscriptions prefix) + |=([ship pax=path] pax) + ?~ paths ~ + [%give %fact paths update-mark.config vase]~ :: ++ forward-update |= =vase diff --git a/pkg/arvo/lib/resource.hoon b/pkg/arvo/lib/resource.hoon index 07931f5a4..f84acb0b8 100644 --- a/pkg/arvo/lib/resource.hoon +++ b/pkg/arvo/lib/resource.hoon @@ -37,6 +37,13 @@ %- spat (en-path resource) :: +++ dejs-path + %- su:dejs:format + ;~ pfix + (jest '/ship/') + ;~((glue fas) ;~(pfix sig fed:ag) urs:ab) + == +:: ++ dejs =, dejs:format ^- $-(json resource) diff --git a/pkg/arvo/lib/verb.hoon b/pkg/arvo/lib/verb.hoon index ead541ef9..2737addfc 100644 --- a/pkg/arvo/lib/verb.hoon +++ b/pkg/arvo/lib/verb.hoon @@ -12,26 +12,26 @@ :: ++ on-init ^- (quip card:agent:gall agent:gall) - %- (print bowl "{}: on-init") + %- (print bowl |.("{}: on-init")) =^ cards agent on-init:ag [[(emit-event %on-init ~) cards] this] :: ++ on-save ^- vase - %- (print bowl "{}: on-save") + %- (print bowl |.("{}: on-save")) on-save:ag :: ++ on-load |= old-state=vase ^- (quip card:agent:gall agent:gall) - %- (print bowl "{}: on-load") + %- (print bowl |.("{}: on-load")) =^ cards agent (on-load:ag old-state) [[(emit-event %on-load ~) cards] this] :: ++ on-poke |= [=mark =vase] ^- (quip card:agent:gall agent:gall) - %- (print bowl "{}: on-poke with mark {}") + %- (print bowl |.("{}: on-poke with mark {}")) ?: ?=(%verb mark) ?- !<(?(%loud %bowl) vase) %loud `this(loud !loud) @@ -43,7 +43,7 @@ ++ on-watch |= =path ^- (quip card:agent:gall agent:gall) - %- (print bowl "{}: on-watch on path {}") + %- (print bowl |.("{}: on-watch on path {}")) =^ cards agent ?: ?=([%verb %events ~] path) [~ agent] @@ -53,7 +53,7 @@ ++ on-leave |= =path ^- (quip card:agent:gall agent:gall) - %- (print bowl "{}: on-leave on path {}") + %- (print bowl |.("{}: on-leave on path {}")) ?: ?=([%verb %event ~] path) [~ this] =^ cards agent (on-leave:ag path) @@ -62,39 +62,40 @@ ++ on-peek |= =path ^- (unit (unit cage)) - %- (print bowl "{}: on-peek on path {}") + %- (print bowl |.("{}: on-peek on path {}")) (on-peek:ag path) :: ++ on-agent |= [=wire =sign:agent:gall] ^- (quip card:agent:gall agent:gall) - %- (print bowl "{}: on-agent on wire {}, {<-.sign>}") + %- (print bowl |.("{}: on-agent on wire {}, {<-.sign>}")) =^ cards agent (on-agent:ag wire sign) [[(emit-event %on-agent wire -.sign) cards] this] :: ++ on-arvo |= [=wire =sign-arvo] ^- (quip card:agent:gall agent:gall) - %- (print bowl "{}: on-arvo on wire {}, {<[- +<]:sign-arvo>}") + %- %+ print bowl |. + "{}: on-arvo on wire {}, {<[- +<]:sign-arvo>}" =^ cards agent (on-arvo:ag wire sign-arvo) [[(emit-event %on-arvo wire [- +<]:sign-arvo) cards] this] :: ++ on-fail |= [=term =tang] ^- (quip card:agent:gall agent:gall) - %- (print bowl "{}: on-fail with term {}") + %- (print bowl |.("{}: on-fail with term {}")) =^ cards agent (on-fail:ag term tang) [[(emit-event %on-fail term) cards] this] -- :: ++ print - |= [=bowl:gall =tape] + |= [=bowl:gall render=(trap tape)] ^+ same =? . bowl-print %- (slog >bowl< ~) . ?. loud same - %- (slog leaf+tape ~) + %- (slog [%leaf $:render] ~) same :: ++ emit-event diff --git a/pkg/arvo/mar/belt.hoon b/pkg/arvo/mar/belt.hoon new file mode 100644 index 000000000..1c5a6e1ea --- /dev/null +++ b/pkg/arvo/mar/belt.hoon @@ -0,0 +1,29 @@ +:: belt: runtime belt structure +:: +|_ =belt:dill +++ grad %noun +:: +grab: convert from +:: +++ grab + |% + ++ noun belt:dill + ++ json + ^- $-(^json belt:dill) + =, dejs:format + %- of + :~ aro+(su (perk %d %l %r %u ~)) + bac+ul + ctl+(cu taft so) + del+ul + met+(cu taft so) + ret+ul + txt+(ar (cu taft so)) + == + -- +:: +grow: convert to +:: +++ grow + |% + ++ noun belt + -- +-- diff --git a/pkg/arvo/mar/blit.hoon b/pkg/arvo/mar/blit.hoon new file mode 100644 index 000000000..242678ea3 --- /dev/null +++ b/pkg/arvo/mar/blit.hoon @@ -0,0 +1,58 @@ +:: blit: runtime blit structure +:: +/+ base64 +:: +|_ =blit:dill +++ grad %noun +:: +grab: convert from +:: +++ grab + |% + ++ noun blit:dill + -- +:: +grow: convert to +:: +++ grow + |% + ++ noun blit + ++ json + ^- ^json + =, enjs:format + %+ frond -.blit + ?- -.blit + %bel b+& + %clr b+& + %hop (numb p.blit) + %lin a+(turn p.blit |=(c=@c s+(tuft c))) + %mor b+& + %url s+p.blit + :: + %sag + %- pairs + :~ 'path'^(path p.blit) + 'file'^s+(en:base64 (as-octs:mimes:html (jam q.blit))) + == + :: + %sav + %- pairs + :~ 'path'^(path p.blit) + 'file'^s+(en:base64 (as-octs:mimes:html q.blit)) + == + :: + %klr + :- %a + %+ turn p.blit + |= [=stye text=(list @c)] + %- pairs + :~ 'text'^a+(turn text |=(c=@c s+(tuft c))) + :: + :- 'stye' + %- pairs + :~ 'back'^[?~(. ~ s+.)]:p.q.stye + 'fore'^[?~(. ~ s+.)]:q.q.stye + 'deco'^a+(turn ~(tap in p.stye) |=(d=deco ?~(d ~ s+d))) + == + == + == + -- +-- diff --git a/pkg/arvo/mar/graph/validator/link.hoon b/pkg/arvo/mar/graph/validator/link.hoon index 02de528df..a860b2015 100644 --- a/pkg/arvo/mar/graph/validator/link.hoon +++ b/pkg/arvo/mar/graph/validator/link.hoon @@ -3,6 +3,11 @@ ++ grow |% ++ noun i + ++ notification-kind + ?+ index.p.i ~ + [@ ~] `[%link 0] + [@ @ @ ~] `[%comment 1] + == -- ++ grab |% @@ -16,10 +21,16 @@ ?> ?=([[%text @] [%url @] ~] contents.p.ip) ip :: - :: comment on link post; comment text + :: comment on link post; container structure :: [@ @ ~] - ?> ?=([[%text @] ~] contents.p.ip) + ?> ?=(~ contents.p.ip) + ip + :: + :: comment on link post; comment text + :: + [@ @ @ ~] + ?> ?=(^ contents.p.ip) ip == -- diff --git a/pkg/arvo/mar/graph/validator/publish.hoon b/pkg/arvo/mar/graph/validator/publish.hoon new file mode 100644 index 000000000..cddf69073 --- /dev/null +++ b/pkg/arvo/mar/graph/validator/publish.hoon @@ -0,0 +1,59 @@ +/- *post +|_ i=indexed-post +++ grow + |% + ++ noun i + :: +notification-kind + :: Ignore all containers, only notify on content + :: + ++ notification-kind + ?+ index.p.i ~ + [@ %1 @ ~] `[%note 0] + [@ %2 @ @ ~] `[%comment 1] + == + -- +++ grab + |% + :: +noun: Validate publish post + :: + ++ noun + |= p=* + =/ ip ;;(indexed-post p) + ?+ index.p.ip !! + :: top level post must have no content + [@ ~] + ?> ?=(~ contents.p.ip) + ip + :: container for revisions + :: + [@ %1 ~] + ?> ?=(~ contents.p.ip) + ip + :: specific revision + :: first content is the title + :: revisions are numbered by the revision count + :: starting at one + [@ %1 @ ~] + ?> ?=([* * *] contents.p.ip) + ?> ?=(%text -.i.contents.p.ip) + ip + :: container for comments + :: + [@ %2 ~] + ?> ?=(~ contents.p.ip) + ip + :: container for comment revisions + :: + [@ %2 @ ~] + ?> ?=(~ contents.p.ip) + ip + :: specific comment revision + :: + [@ %2 @ @ ~] + ?> ?=(^ contents.p.ip) + ip + == + -- +:: +++ grad %noun +-- diff --git a/pkg/arvo/mar/hark/action.hoon b/pkg/arvo/mar/hark/action.hoon new file mode 100644 index 000000000..608f7f318 --- /dev/null +++ b/pkg/arvo/mar/hark/action.hoon @@ -0,0 +1,13 @@ +/+ *hark-store +|_ act=action +++ grad %noun +++ grow + |% + ++ noun act + -- +++ grab + |% + ++ noun action + ++ json action:dejs + -- +-- diff --git a/pkg/arvo/mar/hark/chat-hook-action.hoon b/pkg/arvo/mar/hark/chat-hook-action.hoon new file mode 100644 index 000000000..37987c956 --- /dev/null +++ b/pkg/arvo/mar/hark/chat-hook-action.hoon @@ -0,0 +1,13 @@ +/+ *hark-chat-hook +|_ act=action +++ grad %noun +++ grow + |% + ++ noun act + -- +++ grab + |% + ++ noun action + ++ json action:dejs + -- +-- diff --git a/pkg/arvo/mar/hark/chat-hook-update.hoon b/pkg/arvo/mar/hark/chat-hook-update.hoon new file mode 100644 index 000000000..b76de0bb5 --- /dev/null +++ b/pkg/arvo/mar/hark/chat-hook-update.hoon @@ -0,0 +1,16 @@ +/+ *hark-chat-hook +|_ upd=update +++ grad %noun +++ grow + |% + ++ noun upd + ++ json + %+ frond:enjs:format + %hark-chat-hook-update + (update:enjs upd) + -- +++ grab + |% + ++ noun update + -- +-- diff --git a/pkg/arvo/mar/hark/graph-hook-action.hoon b/pkg/arvo/mar/hark/graph-hook-action.hoon new file mode 100644 index 000000000..1dbc05a09 --- /dev/null +++ b/pkg/arvo/mar/hark/graph-hook-action.hoon @@ -0,0 +1,13 @@ +/+ *hark-graph-hook +|_ act=action +++ grad %noun +++ grow + |% + ++ noun act + -- +++ grab + |% + ++ noun action + ++ json action:dejs + -- +-- diff --git a/pkg/arvo/mar/hark/graph-hook-update.hoon b/pkg/arvo/mar/hark/graph-hook-update.hoon new file mode 100644 index 000000000..61c77dcd6 --- /dev/null +++ b/pkg/arvo/mar/hark/graph-hook-update.hoon @@ -0,0 +1,17 @@ +/+ *hark-graph-hook +|_ upd=update +++ grad %noun +++ grow + |% + ++ noun upd + ++ json + %+ frond:enjs:format + %hark-graph-hook-update + (update:enjs upd) + -- +++ grab + |% + ++ noun update + ++ json update:dejs + -- +-- diff --git a/pkg/arvo/mar/hark/group-hook-action.hoon b/pkg/arvo/mar/hark/group-hook-action.hoon new file mode 100644 index 000000000..05b9d15eb --- /dev/null +++ b/pkg/arvo/mar/hark/group-hook-action.hoon @@ -0,0 +1,13 @@ +/+ *hark-group-hook +|_ act=action +++ grad %noun +++ grow + |% + ++ noun act + -- +++ grab + |% + ++ noun action + ++ json action:dejs + -- +-- diff --git a/pkg/arvo/mar/hark/group-hook-update.hoon b/pkg/arvo/mar/hark/group-hook-update.hoon new file mode 100644 index 000000000..95063a5a0 --- /dev/null +++ b/pkg/arvo/mar/hark/group-hook-update.hoon @@ -0,0 +1,16 @@ +/+ *hark-group-hook +|_ upd=update +++ grad %noun +++ grow + |% + ++ noun upd + ++ json + %+ frond:enjs:format + %hark-group-hook-update + (update:enjs upd) + -- +++ grab + |% + ++ noun update + -- +-- diff --git a/pkg/arvo/mar/hark/update.hoon b/pkg/arvo/mar/hark/update.hoon new file mode 100644 index 000000000..8aeff8f5a --- /dev/null +++ b/pkg/arvo/mar/hark/update.hoon @@ -0,0 +1,15 @@ +/+ *hark-store +|_ upd=update +++ grad %noun +++ grow + |% + ++ noun upd + ++ json + %+ frond:enjs:format 'harkUpdate' + (update:enjs upd) + -- +++ grab + |% + ++ noun update + -- +-- diff --git a/pkg/arvo/mar/invite/action.hoon b/pkg/arvo/mar/invite/action.hoon index a0baf8b6d..90a6d0c5c 100644 --- a/pkg/arvo/mar/invite/action.hoon +++ b/pkg/arvo/mar/invite/action.hoon @@ -1,6 +1,6 @@ /+ *invite-json =, dejs:format -|_ act=invite-action +|_ act=action ++ grad %noun ++ grow |% @@ -8,7 +8,7 @@ -- ++ grab |% - ++ noun invite-action + ++ noun action ++ json |= jon=^json (json-to-action jon) diff --git a/pkg/arvo/mar/invite/update.hoon b/pkg/arvo/mar/invite/update.hoon index 534e304d8..af0abca82 100644 --- a/pkg/arvo/mar/invite/update.hoon +++ b/pkg/arvo/mar/invite/update.hoon @@ -1,15 +1,15 @@ +/- store=invite-store /+ *invite-json -|_ upd=invite-update +|_ =update:store ++ grad %noun ++ grow |% - ++ noun upd - ++ json (update-to-json upd) + ++ noun update + ++ json (update-to-json update) -- :: ++ grab |% - ++ noun invite-update + ++ noun update:store -- -:: -- diff --git a/pkg/arvo/mar/lens/command.hoon b/pkg/arvo/mar/lens/command.hoon index bd8a88cc9..3f29fc833 100644 --- a/pkg/arvo/mar/lens/command.hoon +++ b/pkg/arvo/mar/lens/command.hoon @@ -37,7 +37,7 @@ %- su ;~ plug sym - ;~(pfix col (more net (cook crip (star ;~(less net prn))))) + ;~(pfix col (more fas (cook crip (star ;~(less fas prn))))) == listen-api+(su ;~(plug sym ;~(pfix col sym))) export+so @@ -61,7 +61,7 @@ %- su ;~ plug sym - ;~(pfix col (more net (cook crip (star ;~(less net prn))))) + ;~(pfix col (more fas (cook crip (star ;~(less fas prn))))) == command+so app+(su sym) diff --git a/pkg/arvo/mar/observe/action.hoon b/pkg/arvo/mar/observe/action.hoon new file mode 100644 index 000000000..466debd69 --- /dev/null +++ b/pkg/arvo/mar/observe/action.hoon @@ -0,0 +1,13 @@ +/- sur=observe-hook +|_ =action:sur +++ grad %noun +++ grow + |% + ++ noun action + -- +:: +++ grab + |% + ++ noun action:sur + -- +-- diff --git a/pkg/arvo/mar/publish/action.hoon b/pkg/arvo/mar/publish/action.hoon index 2e5c1ce3c..f346ed816 100644 --- a/pkg/arvo/mar/publish/action.hoon +++ b/pkg/arvo/mar/publish/action.hoon @@ -1,6 +1,6 @@ :: :::: /hoon/action/publish/mar - :: + :: tombstoned, now unused /- *publish =, format :: @@ -16,121 +16,5 @@ ++ grab |% ++ noun action - ++ json - |= jon=^json - =, dejs:format - ;; action - |^ %. jon - %- of - :~ new-book+new-book - new-note+new-note - new-comment+new-comment - edit-book+edit-book - edit-note+edit-note - edit-comment+edit-comment - del-book+del-book - del-note+del-note - del-comment+del-comment - subscribe+subscribe - unsubscribe+unsubscribe - read+read - groupify+groupify - == - :: - ++ new-book - %- ot - :~ book+so - title+so - about+so - coms+bo - group+group-info - == - :: - ++ new-note - %- ot - :~ who+(su fed:ag) - book+so - note+so - title+so - body+so - == - :: - ++ new-comment - %- ot - :~ who+(su fed:ag) - book+so - note+so - body+so - == - :: - ++ edit-book - %- ot - :~ book+so - title+so - about+so - coms+bo - group+(mu group-info) - == - :: - ++ edit-note - %- ot - :~ who+(su fed:ag) - book+so - note+so - title+so - body+so - == - :: - ++ edit-comment - %- ot - :~ who+(su fed:ag) - book+so - note+so - comment+so - body+so - == - :: - ++ del-book (ot book+so ~) - :: - ++ del-note (ot who+(su fed:ag) book+so note+so ~) - :: - ++ del-comment - %- ot - :~ who+(su fed:ag) - book+so - note+so - comment+so - == - ++ subscribe - %- ot - :~ who+(su fed:ag) - book+so - == - ++ unsubscribe - %- ot - :~ who+(su fed:ag) - book+so - == - ++ read - %- ot - :~ who+(su fed:ag) - book+so - note+so - == - ++ groupify - %- ot - :~ book+so - target+(mu pa) - inclusive+bo - == - ++ group-info - %- ot - :~ group-path+pa - invitees+set-ship - use-preexisting+bo - make-managed+bo - == - ++ set-ship (as (su fed:ag)) - -- -- -- diff --git a/pkg/arvo/mar/publish/info.hoon b/pkg/arvo/mar/publish/info.hoon index eb8d7cbcc..288c3609d 100644 --- a/pkg/arvo/mar/publish/info.hoon +++ b/pkg/arvo/mar/publish/info.hoon @@ -1,25 +1,12 @@ :: :::: /hoon/info/publish/mar + :: tombstoned, now unused :: /- *publish !: |_ info=notebook-info :: :: -++ grow - |% - ++ mime - :- /text/x-publish-info - (as-octs:mimes:html (of-wain:format txt)) - ++ txt - ^- wain - :~ (cat 3 'title: ' title.info) - (cat 3 'description: ' description.info) - (cat 3 'comments: ' ?:(comments.info 'on' 'off')) - (cat 3 'writers: ' (spat writers.info)) - (cat 3 'subscribers: ' (spat subscribers.info)) - == - -- ++ grab |% ++ mime @@ -49,10 +36,10 @@ (key-val (jest 'description: ') (cook crip (star prn))) %+ key-val (jest 'comments: ') (cook |=(a=@ =(%on a)) ;~(pose (jest %on) (jest %off))) - (key-val (jest 'writers: ') ;~(pfix net (more net urs:ab))) + (key-val (jest 'writers: ') ;~(pfix fas (more fas urs:ab))) ;~ pose - (key-val (jest 'subscribers: ') ;~(pfix net (more net urs:ab))) - ;~(pfix (jest 'subscribers: ') ;~(pfix net (more net urs:ab))) + (key-val (jest 'subscribers: ') ;~(pfix fas (more fas urs:ab))) + ;~(pfix (jest 'subscribers: ') ;~(pfix fas (more fas urs:ab))) == == ++ both-parser diff --git a/pkg/arvo/mar/publish/primary-delta.hoon b/pkg/arvo/mar/publish/primary-delta.hoon index d2b01052d..41b331c08 100644 --- a/pkg/arvo/mar/publish/primary-delta.hoon +++ b/pkg/arvo/mar/publish/primary-delta.hoon @@ -13,73 +13,5 @@ ++ grow |% ++ noun del - ++ json - %+ frond:enjs:format %publish-update - %+ frond:enjs:format -.del - ?- -.del - %add-book - %+ frond:enjs:format (scot %p host.del) - %+ frond:enjs:format book.del - (notebook-short:enjs data.del) - :: - %add-note - %+ frond:enjs:format (scot %p host.del) - %+ frond:enjs:format book.del - (note-full:enjs note.del data.del) - :: - %add-comment - %- pairs:enjs:format - :~ host+s+(scot %p host.del) - book+s+book.del - note+s+note.del - comment+(comment:enjs comment-date.del data.del) - == - :: - %edit-book - %+ frond:enjs:format (scot %p host.del) - %+ frond:enjs:format book.del - (notebook-short:enjs data.del) - :: - %edit-note - %+ frond:enjs:format (scot %p host.del) - %+ frond:enjs:format book.del - (note-full:enjs note.del data.del) - :: - %edit-comment - %- pairs:enjs:format - :~ host+s+(scot %p host.del) - book+s+book.del - note+s+note.del - comment+(comment:enjs comment-date.del data.del) - == - :: - %del-book - %- pairs:enjs:format - :~ host+s+(scot %p host.del) - book+s+book.del - == - :: - %del-note - %- pairs:enjs:format - :~ host+s+(scot %p host.del) - book+s+book.del - note+s+note.del - == - :: - %del-comment - %- pairs:enjs:format - :~ host+s+(scot %p host.del) - book+s+book.del - note+s+note.del - comment+s+(scot %da comment.del) - == - :: - %read - %- pairs:enjs:format - :~ host+s+(scot %p who.del) - book+s+book.del - note+s+note.del - == - == -- -- diff --git a/pkg/arvo/ren/publish/comments.hoon b/pkg/arvo/ren/publish/comments.hoon deleted file mode 100644 index a793df78c..000000000 --- a/pkg/arvo/ren/publish/comments.hoon +++ /dev/null @@ -1,14 +0,0 @@ -/- publish -/+ publish -/= result - /^ (list comment:publish) - /; - |= comments=(map knot comment:publish) - ^- (list [comment-info:publish @t]) - %+ sort ~(val by comments) - |= [a=comment:publish b=comment:publish] - ^- ? - (gte date-created.info.a date-created.info.b) -:: - /_ /publish-comment/ -result diff --git a/pkg/arvo/ren/publish/post.hoon b/pkg/arvo/ren/publish/post.hoon deleted file mode 100644 index 717facddc..000000000 --- a/pkg/arvo/ren/publish/post.hoon +++ /dev/null @@ -1,20 +0,0 @@ -/- publish -/+ publish, cram, elem-to-react-json -/= args /$ ,[beam *] -/= result - /^ [post-info:publish manx @t] - /; - |= $: post-front=(map knot cord) - post-content=manx - post-raw=wain - ~ - == - :+ (front-to-post-info:publish post-front) - post-content - (of-wain:format (slag 11 post-raw)) -:: - /. /&front&/udon/ - /&elem&/udon/ - /&txt&/udon/ - == -result diff --git a/pkg/arvo/ren/run.hoon b/pkg/arvo/ren/run.hoon deleted file mode 100644 index 104669204..000000000 --- a/pkg/arvo/ren/run.hoon +++ /dev/null @@ -1,10 +0,0 @@ -:: For testing purposes -:: -:::: /hoon/run/ren - :: -/? 310 -/, /ren/run /~ ~|(%loop !!) - / /!noun/ -== -~& run+-.- -~ diff --git a/pkg/arvo/ren/test-gen.hoon b/pkg/arvo/ren/test-gen.hoon deleted file mode 100644 index ebe10ffa6..000000000 --- a/pkg/arvo/ren/test-gen.hoon +++ /dev/null @@ -1,4 +0,0 @@ -/+ test-runner -/= test-core /!noun/ -:: -(get-test-arms:test-runner !>(test-core)) diff --git a/pkg/arvo/sur/graph-store.hoon b/pkg/arvo/sur/graph-store.hoon index edcfb4135..e2570fed8 100644 --- a/pkg/arvo/sur/graph-store.hoon +++ b/pkg/arvo/sur/graph-store.hoon @@ -42,7 +42,7 @@ :: +$ update-0 $% logged-update-0 - [%add-graph =resource =graph mark=(unit mark)] + [%add-graph =resource =graph mark=(unit mark) overwrite=?] [%remove-graph =resource] :: [%add-tag =term =resource] diff --git a/pkg/arvo/sur/hark-chat-hook.hoon b/pkg/arvo/sur/hark-chat-hook.hoon new file mode 100644 index 000000000..a5e9bf875 --- /dev/null +++ b/pkg/arvo/sur/hark-chat-hook.hoon @@ -0,0 +1,15 @@ +^? +|% ++$ action + $% [?(%listen %ignore) chat=path] + [%set-mentions mentions=?] + == +:: ++$ update + $% + action + $: %initial + watching=(set path) + == + == +-- diff --git a/pkg/arvo/sur/hark-graph-hook.hoon b/pkg/arvo/sur/hark-graph-hook.hoon new file mode 100644 index 000000000..58f42b3ac --- /dev/null +++ b/pkg/arvo/sur/hark-graph-hook.hoon @@ -0,0 +1,20 @@ +/- *resource, graph-store, post +^? +|% ++$ action + $% + [?(%listen %ignore) graph=resource =index:post] + [%set-mentions mentions=?] + [%set-watch-on-self watch-on-self=?] + == +:: ++$ update + $% + action + $: %initial + watching=(set [resource index:post]) + mentions=_& + watch-on-self=_& + == + == +-- diff --git a/pkg/arvo/sur/hark-group-hook.hoon b/pkg/arvo/sur/hark-group-hook.hoon new file mode 100644 index 000000000..f44ed63bc --- /dev/null +++ b/pkg/arvo/sur/hark-group-hook.hoon @@ -0,0 +1,11 @@ +/- *resource +^? +|% ++$ action + [?(%listen %ignore) group=resource] +:: ++$ update + $% action + [%initial watching=(set resource)] + == +-- diff --git a/pkg/arvo/sur/hark-store.hoon b/pkg/arvo/sur/hark-store.hoon new file mode 100644 index 000000000..6d2783709 --- /dev/null +++ b/pkg/arvo/sur/hark-store.hoon @@ -0,0 +1,52 @@ +/- *resource, graph-store, post, group-store, metadata-store, chat-store +^? +|% ++$ index + $% [%graph group=resource graph=resource module=@t description=@t] + [%group group=resource description=@t] + [%chat chat=path mention=?] + == +:: ++$ group-contents + $~ [%add-members *resource ~] + $% $>(?(%add-members %remove-members) update:group-store) + metadata-action:metadata-store + == +:: ++$ notification + [date=@da read=? =contents] +:: ++$ contents + $% [%graph =(list post:post)] + [%group =(list group-contents)] + [%chat =(list envelope:chat-store)] + == +:: ++$ timebox + (map index notification) +:: ++$ notifications + ((mop @da timebox) gth) +:: ++$ action + $% [%add =index =notification] + [%archive time=@da index] + [%read time=@da index] + [%read-index index] + [%unread time=@da index] + [%set-dnd dnd=?] + [%seen ~] + == +:: +++ indexed-notification + [index notification] +:: ++$ update + $% action + [%more more=(list update)] + [%added time=@da =index =notification] + [%timebox time=@da archived=? =(list [index notification])] + [%count count=@ud] + [%unreads unreads=(list [index @ud])] + == +-- diff --git a/pkg/arvo/sur/invite-store.hoon b/pkg/arvo/sur/invite-store.hoon index ff8aa46d6..2d2d1e8e9 100644 --- a/pkg/arvo/sur/invite-store.hoon +++ b/pkg/arvo/sur/invite-store.hoon @@ -1,45 +1,49 @@ +/- *resource |% ++ serial @uvH :: +$ invite $: =ship :: ship to subscribe to upon accepting invite app=@tas :: app to subscribe to upon accepting invite - =path :: path to subscribe to upon accepting invite + =resource :: resource to subscribe to upon accepting invite recipient=ship :: recipient to receive invite text=cord :: text to describe the invite == :: -:: +invites: each application using invites creates its own path that ++$ multi-invite + $: =ship :: ship to subscribe to upon accepting invite + app=@tas :: app to subscribe to upon accepting invite + =resource :: resource to subscribe to upon accepting invite + recipients=(set ship) :: recipient to receive invite + text=cord :: text to describe the invite + == +:: +:: +invites: each application using invites creates its own resource that :: contains a map of serial to invite. this allows it to only receive :: invites that it is concerned with :: -+$ invites (map path invitatory) :: main data structure ++$ invites (map term invitatory) :: main data structure :: +$ invitatory (map serial invite) :: containing or conveying an invitation :: -:: +$ invite-base - $% [%create =path] :: create a path - [%delete =path] :: delete a path - [%invite =path uid=serial =invite] :: receive an invite at path/uid - [%decline =path uid=serial] :: decline an invite at path/uid + $% [%create =term] :: create a resource + [%delete =term] :: delete a resource + [%invite =term uid=serial =invite] :: receive an invite at term/uid + [%decline =term uid=serial] :: decline an invite at term/uid == :: -+$ invite-action ++$ action $% invite-base - [%accept =path uid=serial] :: accept an invite at path/uid + [%accept =term uid=serial] :: accept an invite at term/uid + [%invites =term uid=serial invites=multi-invite] == :: -+$ invite-update ++$ update $% invite-base [%initial =invites] - [%invitatory =invitatory] :: receive invitatory - [%accepted =path uid=serial =invite] :: an invite has been accepted - == -:: -+$ invite-diff - $% [%invite-initial invites] - [%invite-update invite-update] + [%invitatory =invitatory] :: receive invitatory + [%accepted =term uid=serial =invite] :: an invite has been accepted == -- diff --git a/pkg/arvo/sur/observe-hook.hoon b/pkg/arvo/sur/observe-hook.hoon new file mode 100644 index 000000000..a424c9622 --- /dev/null +++ b/pkg/arvo/sur/observe-hook.hoon @@ -0,0 +1,7 @@ +|% ++$ observer [app=term =path thread=term] ++$ action + $% [%watch =observer] + [%ignore =observer] + == +-- diff --git a/pkg/arvo/sur/post.hoon b/pkg/arvo/sur/post.hoon index c5c354615..4855a3a68 100644 --- a/pkg/arvo/sur/post.hoon +++ b/pkg/arvo/sur/post.hoon @@ -28,6 +28,7 @@ :: +$ content $% [%text text=cord] + [%mention =ship] [%url url=cord] [%code expression=cord output=(list tank)] [%reference =uid] diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index b3602bfd4..8d1d39275 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -5595,47 +5595,59 @@ :: :::: 4h: parsing (ascii glyphs) :: -++ ace (just ' ') -++ ban (just '>') -++ bar (just '|') -++ bas (just '\\') :: XX deprecated -++ bat (just '\\') -++ buc (just '$') :: XX deprecated -++ bus (just '$') -++ cab (just '_') -++ cen (just '%') -++ col (just ':') -++ com (just ',') -++ dot (just '.') -++ fas (just '/') :: XX deprecated? -++ gal (just '<') :: XX deprecated -++ gar (just '>') :: XX deprecated -++ vat (just '@') :: pronounced "at" -++ hax (just '#') -++ hep (just '-') :: pronounced "ep" -++ ket (just '^') -++ leb (just '{') -++ led (just '<') -++ lob (just '{') -++ lit (just '(') -++ lac (just '[') -++ lus (just '+') -++ mic (just ';') :: pronounced "mick" -++ net (just '/') -++ pad (just '&') -++ rac (just ']') -++ reb (just '}') -++ rob (just '}') -++ rit (just ')') -++ say (just '\'') -++ sig (just '~') -++ tar (just '*') -++ tec (just '`') -++ tis (just '=') :: pronounced "is" -++ toc (just '"') :: XX deprecated -++ yel (just '"') -++ wut (just '?') -++ zap (just '!') +++ ace (just ' ') :: spACE +++ bar (just '|') :: vertical BAR +++ bas (just '\\') :: Back Slash (escaped) +++ buc (just '$') :: dollars BUCks +++ cab (just '_') :: CABoose +++ cen (just '%') :: perCENt +++ col (just ':') :: COLon +++ com (just ',') :: COMma +++ doq (just '"') :: Double Quote +++ dot (just '.') :: dot dot dot ... +++ fas (just '/') :: Forward Slash +++ gal (just '<') :: Greater Left +++ gar (just '>') :: Greater Right +++ hax (just '#') :: Hash +++ hep (just '-') :: HyPhen +++ kel (just '{') :: Curly Left +++ ker (just '}') :: Curly Right +++ ket (just '^') :: CareT +++ lus (just '+') :: pLUS +++ mic (just ';') :: seMIColon +++ pal (just '(') :: Paren Left +++ pam (just '&') :: AMPersand pampersand +++ par (just ')') :: Paren Right +++ pat (just '@') :: AT pat +++ sel (just '[') :: Square Left +++ ser (just ']') :: Square Right +++ sig (just '~') :: SIGnature squiggle +++ soq (just '\'') :: Single Quote +++ tar (just '*') :: sTAR +++ tic (just '`') :: backTiCk +++ tis (just '=') :: 'tis tis, it is +++ wut (just '?') :: wut, what? +++ zap (just '!') :: zap! bang! crash!! +:: +++ ban (just '>') :: XX deprecated, use gar +++ bat (just '\\') :: XX deprecated, use bas +++ bus (just '$') :: XX deprecated, use buc +++ lac (just '[') :: XX deprecated, use sel +++ leb (just '{') :: XX deprecated, use kel +++ led (just '<') :: XX deprecated, use gal +++ lit (just '(') :: XX deprecated, use pal +++ lob (just '{') :: XX deprecated, use kel +++ net (just '/') :: XX deprecated, use fas +++ pad (just '&') :: XX deprecated, use pam +++ rac (just ']') :: XX deprecated, use ser +++ reb (just '}') :: XX deprecated, use ker +++ rit (just ')') :: XX deprecated, use par +++ rob (just '}') :: XX deprecated, use ker +++ say (just '\'') :: XX deprecated, use soq +++ tec (just '`') :: XX deprecated, use tic +++ toc (just '"') :: XX deprecated, use doq +++ vat (just '@') :: XX deprecated, use pat +++ yel (just '"') :: XX deprecated, use doq :: :::: 4i: parsing (useful idioms) :: @@ -5662,8 +5674,8 @@ == ++ gaw (cold ~ (star ;~(pose vul gah))) :: classic white ++ gay ;~(pose gap (easy ~)) :: -++ gon ;~(pose ;~(plug bat gay net) (easy ~)) :: long numbers \ / -++ gul ;~(pose (cold 2 led) (cold 3 ban)) :: axis syntax < > +++ gon ;~(pose ;~(plug bas gay fas) (easy ~)) :: long numbers \ / +++ gul ;~(pose (cold 2 gal) (cold 3 gar)) :: axis syntax < > ++ hex (bass 16 (most gon hit)) :: hex to atom ++ hig (shim 'A' 'Z') :: uppercase ++ hit ;~ pose :: hex digits @@ -5703,13 +5715,13 @@ ;~(less ;~(plug (just `@`10) soz) (just `@`10)) == ++ qit ;~ pose :: chars in a cord - ;~(less bat say prn) - ;~(pfix bat ;~(pose bat say mes)) :: escape chars + ;~(less bas soq prn) + ;~(pfix bas ;~(pose bas soq mes)) :: escape chars == -++ qut ;~ simu say :: cord +++ qut ;~ simu soq :: cord ;~ pose ;~ less soz - (ifix [say say] (boss 256 (more gon qit))) + (ifix [soq soq] (boss 256 (more gon qit))) == =+ hed=;~(pose ;~(plug (plus ace) vul) (just '\0a')) %- iny %+ ifix @@ -5718,7 +5730,7 @@ (boss 256 (star qat)) == == -++ soz ;~(plug say say say) :: delimiting ''' +++ soz ;~(plug soq soq soq) :: delimiting ''' ++ sym :: symbol %+ cook |=(a/tape (rap 3 ^-((list @) a))) @@ -5819,7 +5831,7 @@ (cook tuft (ifix [sig dot] hex)) ;~(pfix sig ;~(pose sig dot)) == - ++ voy ;~(pfix bat ;~(pose bat say bix)) + ++ voy ;~(pfix bas ;~(pose bas soq bix)) -- ++ ag |% @@ -6356,7 +6368,7 @@ ++ spat |=(pax/path (crip (spud pax))) :: render path to cord ++ spud |=(pax/path ~(ram re (smyt pax))) :: render path to tape ++ stab :: parse cord to path - =+ fel=;~(pfix net (more net urs:ab)) + =+ fel=;~(pfix fas (more fas urs:ab)) |=(zep/@t `path`(rash zep fel)) :: :::: 4n: virtualization @@ -9754,18 +9766,7 @@ ^- (pair type type) (~(mull et hyp rig) gol dox) :: - ++ felt - ~/ %felt - |= lap/opal - ^- type - ?- -.lap - %& p.lap - %| %- fork - %+ turn ~(tap in q.lap) - |= [a=type *] - ?> ?=([%core *] a) - [%core q.q.a q.a] - == + ++ felt !! :: :: ++ feel :: detect existence |= rot/(list wing) @@ -9814,7 +9815,12 @@ == :: %& - =. sut (felt q.p.mor) + =. sut + =* lap q.p.mor + ?- -.lap + %& p.lap + %| (fork (turn ~(tap in q.lap) head)) + == => :_ + :* axe=`axis`1 lon=p.p.mor @@ -12176,7 +12182,7 @@ ++ gash %+ cook :: parse path |= a/(list tyke) ^- tyke ?~(a ~ (weld i.a $(a t.a))) - (more net limp) + (more fas limp) ++ gasp ;~ pose :: parse =path= etc. %+ cook |=({a/tyke b/tyke c/tyke} :(weld a b c)) @@ -12189,9 +12195,9 @@ == ++ glam ~+((glue ace)) ++ hasp ;~ pose :: path element - (ifix [lac rac] wide) - (stag %cncl (ifix [lit rit] (most ace wide))) - (stag %sand (stag %tas (cold %$ bus))) + (ifix [sel ser] wide) + (stag %cncl (ifix [pal par] (most ace wide))) + (stag %sand (stag %tas (cold %$ buc))) (stag %sand (stag %t qut)) %+ cook |=(a/coin [%sand ?:(?=({~ $tas *} a) %tas %ta) ~(rent co a)]) @@ -12201,7 +12207,7 @@ |= {a/(list) b/tyke} ?~ a b $(a t.a, b [`[%sand %tas %$] b]) - ;~(plug (star net) gasp) + ;~(plug (star fas) gasp) ++ mota %+ cook |=({a/tape b/tape} (rap 3 (weld a b))) ;~(plug (star low) (star hig)) @@ -12257,7 +12263,7 @@ ++ body ;~ pose ;~ plug :: can duplicate :: - (into ;~(pfix (punt ;~(plug null col ban step)) line)) + (into ;~(pfix (punt ;~(plug null col gar step)) line)) (easy ~) == ;~ plug @@ -12289,11 +12295,11 @@ :: ++ indo |* bod/rule - ;~(pfix col ban ;~(sfix bod (just `@`10) (punt gap))) + ;~(pfix col gar ;~(sfix bod (just `@`10) (punt gap))) :: ++ exit |* bod/rule - ;~(pfix (star ace) col led step bod) + ;~(pfix (star ace) col gal step bod) :: :: fill: full definition :: @@ -12379,7 +12385,7 @@ ++ porc ;~ plug (cook |=(a/(list) (lent a)) (star cen)) - ;~(pfix net gash) + ;~(pfix fas gash) == :: ++ rump @@ -12389,7 +12395,7 @@ ;~(plug rope ;~(pose (stag ~ wede) (easy ~))) :: ++ rood - ;~ pfix net + ;~ pfix fas (stag %clsg poor) == :: @@ -12478,7 +12484,7 @@ ++ wide-attrs :: wide attributes %+ cook |=(a/(unit mart:hoot) (fall a ~)) %- punt - %+ ifix [lit rit] + %+ ifix [pal par] %+ more (jest ', ') ;~((glue ace) a-mane hopefully-quote) :: @@ -12494,7 +12500,7 @@ ++ wide-paren-elems :: wide flow %+ cook |=(a/marl:hoot a) %+ cook join-tops - (ifix [lit rit] (more ace wide-inner-top)) + (ifix [pal par] (more ace wide-inner-top)) :: ::+| :: @@ -12515,7 +12521,7 @@ %+ cook |=(a/marl:hoot a) ;~ pose ;~ less (jest '"""') - (ifix [yel yel] (cook collapse-chars quote-innards)) + (ifix [doq doq] (cook collapse-chars quote-innards)) == :: %- inde @@ -12527,14 +12533,14 @@ %+ cook |=(a/(list $@(@ tuna:hoot)) a) %- star ;~ pose - ;~(pfix bas ;~(pose (mask "-+*%;\{") bas yel bix:ab)) + ;~(pfix bas ;~(pose (mask "-+*%;\{") bas doq bix:ab)) inline-embed - ;~(less bas lob ?:(in-tall-form fail toc) prn) + ;~(less bas kel ?:(in-tall-form fail doq) prn) ?:(lin fail ;~(less (jest '\0a"""') (just '\0a'))) == :: ++ bracketed-elem :: bracketed element - %+ ifix [lob rob] + %+ ifix [kel ker] ;~(plug tag-head wide-elems) :: ++ wrapped-elems :: wrapped tuna @@ -12587,7 +12593,7 @@ ;~ plug (punt ;~(plug (cold %id hax) (cook trip sym))) (cook en-class (star ;~(plug (cold %class dot) sym))) - (punt ;~(plug ;~(pose (cold %href net) (cold %src vat)) soil)) + (punt ;~(plug ;~(pose (cold %href fas) (cold %src pat)) soil)) (easy ~) == :: @@ -12604,7 +12610,7 @@ (stag %& tall-elem) (stag %| wide-quote) (stag %| ;~(pfix tis tall-tail)) - (stag %& ;~(pfix ban gap (stag [%div ~] cram))) + (stag %& ;~(pfix gar gap (stag [%div ~] cram))) (stag %| ;~(plug ;~((glue gap) tuna-mode tall) (easy ~))) (easy %| [;/("\0a")]~) == @@ -13067,20 +13073,20 @@ (cold [%end %stet] duz) :: == end of markdown :: (cold [%one %rule] ;~(plug hep hep hep)) :: --- horizontal ruler - (cold [%one %fens] ;~(plug tec tec tec)) :: ``` code fence + (cold [%one %fens] ;~(plug tic tic tic)) :: ``` code fence (cold [%one %expr] mic) :: ;sail expression :: (cold [%new %head] ;~(plug (star hax) ace)) :: # heading (cold [%new %lint] ;~(plug hep ace)) :: - line item (cold [%new %lite] ;~(plug lus ace)) :: + line item - (cold [%new %bloc] ;~(plug ban ace)) :: > block-quote + (cold [%new %bloc] ;~(plug gar ace)) :: > block-quote :: (easy [%old %text]) :: anything else == == :: :: - ++ calf :: cash but for tec tec + ++ calf :: cash but for tic tic |* tem=rule %- star ;~ pose @@ -13187,17 +13193,17 @@ :: :: "quoted text" :: - (stag %quod (ifix [yel yel] (cool (cash yel) werk))) + (stag %quod (ifix [doq doq] (cool (cash doq) werk))) :: :: `classic markdown quote` :: - (stag %code (ifix [tec tec] (calf tec))) + (stag %code (ifix [tic tic] (calf tic))) :: :: ++arm, +-arm, +$arm, +*arm, ++arm:core, ... :: %+ stag %code ;~ plug - lus ;~(pose lus hep bus tar) + lus ;~(pose lus hep buc tar) low (star ;~(pose nud low hep col)) == :: @@ -13205,8 +13211,8 @@ :: %+ stag %link ;~ (glue (punt whit)) - (ifix [lac rac] (cool (cash rac) werk)) - (ifix [lit rit] (cash rit)) + (ifix [sel ser] (cool (cash ser) werk)) + (ifix [pal par] (cash par)) == :: :: ![alt text](url) @@ -13214,8 +13220,8 @@ %+ stag %mage ;~ pfix zap ;~ (glue (punt whit)) - (ifix [lac rac] (cash rac)) - (ifix [lit rit] (cash rit)) + (ifix [sel ser] (cash ser)) + (ifix [pal par] (cash par)) == == :: @@ -13243,7 +13249,7 @@ tash:so ;~(pfix dot perd:so) ;~(pfix sig ;~(pose twid:so (easy [%$ %n 0]))) - ;~(pfix cen ;~(pose sym bus pad bar qut nuck:so)) + ;~(pfix cen ;~(pose sym buc pam bar qut nuck:so)) == :: ;~(simu whit (easy ~)) @@ -13313,22 +13319,22 @@ %+ cold [[%hr ~] ~]~ ;~(plug (star ace) hep hep hep (star hep) (just '\0a')) :: - ++ tecs - ;~(plug tec tec tec (just '\0a')) + ++ tics + ;~(plug tic tic tic (just '\0a')) :: ++ fens |= col/@u ~+ =/ ind (stun [(dec col) (dec col)] ace) - =/ ind-tecs ;~(plug ind tecs) + =/ ind-tics ;~(plug ind tics) %+ cook |=(txt/tape `tarp`[[%pre ~] ;/(txt) ~]~) :: :: leading outdent is ok since container may :: have already been parsed and consumed - %+ ifix [;~(plug (star ace) tecs) ind-tecs] + %+ ifix [;~(plug (star ace) tics) ind-tics] %^ stir "" |=({a/tape b/tape} "{a}\0a{b}") ;~ pose %+ ifix [ind (just '\0a')] - ;~(less tecs (star prn)) + ;~(less tics (star prn)) :: (cold "" ;~(plug (star ace) (just '\0a'))) == @@ -13396,11 +13402,11 @@ ;~(pfix com (stag %bsmc wide)) :- '$' ;~ pose - ;~ pfix bus + ;~ pfix buc ;~ pose :: XX all three deprecated :: - (stag %leaf (stag %tas (cold %$ bus))) + (stag %leaf (stag %tas (cold %$ buc))) (stag %leaf (stag %t qut)) (stag %leaf (sear |=(a/coin ?:(?=($$ -.a) (some +.a) ~)) nuck:so)) == @@ -13411,8 +13417,8 @@ ;~ pose ;~ pfix cen ;~ pose - (stag %leaf (stag %tas (cold %$ bus))) - (stag %leaf (stag %f (cold & pad))) + (stag %leaf (stag %tas (cold %$ buc))) + (stag %leaf (stag %f (cold & pam))) (stag %leaf (stag %f (cold | bar))) (stag %leaf (stag %t qut)) (stag %leaf (sear |=(a/coin ?:(?=($$ -.a) (some +.a) ~)) nuck:so)) @@ -13422,7 +13428,7 @@ :- '(' %+ cook |=(spec +<) %+ stag %make - %+ ifix [lit rit] + %+ ifix [pal par] ;~ plug wide ;~(pose ;~(pfix ace (most ace wyde)) (easy ~)) @@ -13430,19 +13436,19 @@ :- '{' :: XX deprecated :: - (stag %bscl (ifix [lob rob] (most ace wyde))) + (stag %bscl (ifix [kel ker] (most ace wyde))) :- '[' - (stag %bscl (ifix [lac rac] (most ace wyde))) + (stag %bscl (ifix [sel ser] (most ace wyde))) :- '*' (cold [%base %noun] tar) :- '/' - ;~(pfix net (stag %loop ;~(pose (cold %$ bus) sym))) + ;~(pfix fas (stag %loop ;~(pose (cold %$ buc) sym))) :- '@' - ;~(pfix vat (stag %base (stag %atom mota))) + ;~(pfix pat (stag %base (stag %atom mota))) :- '?' ;~ pose %+ stag %bswt - ;~(pfix wut (ifix [lit rit] (most ace wyde))) + ;~(pfix wut (ifix [pal par] (most ace wyde))) :: (cold [%base %flag] wut) == @@ -13471,7 +13477,7 @@ == :- ['a' 'z'] ;~ pose - (stag %bsts ;~(plug sym ;~(pfix ;~(pose net tis) wyde))) + (stag %bsts ;~(plug sym ;~(pfix ;~(pose fas tis) wyde))) (stag %like (most col rope)) == == @@ -13495,11 +13501,11 @@ ;~(pfix cab (stag %ktcl (stag %bscb wide))) :- '$' ;~ pose - ;~ pfix bus + ;~ pfix buc ;~ pose :: XX: these are all obsolete in hoon 142 :: - (stag %leaf (stag %tas (cold %$ bus))) + (stag %leaf (stag %tas (cold %$ buc))) (stag %leaf (stag %t qut)) (stag %leaf (sear |=(a/coin ?:(?=($$ -.a) (some +.a) ~)) nuck:so)) == @@ -13510,8 +13516,8 @@ ;~ pfix cen ;~ pose (stag %clsg (sear |~({a/@ud b/tyke} (posh ~ ~ a b)) porc)) - (stag %rock (stag %tas (cold %$ bus))) - (stag %rock (stag %f (cold & pad))) + (stag %rock (stag %tas (cold %$ buc))) + (stag %rock (stag %f (cold & pam))) (stag %rock (stag %f (cold | bar))) (stag %rock (stag %t qut)) (cook (jock &) nuck:so) @@ -13521,26 +13527,26 @@ :- '&' ;~ pose (cook |=(a/wing [%cnts a ~]) rope) - (stag %wtpd ;~(pfix pad (ifix [lit rit] (most ace wide)))) - ;~(plug (stag %rock (stag %f (cold & pad))) wede) - (stag %sand (stag %f (cold & pad))) + (stag %wtpd ;~(pfix pam (ifix [pal par] (most ace wide)))) + ;~(plug (stag %rock (stag %f (cold & pam))) wede) + (stag %sand (stag %f (cold & pam))) == :- '\'' (stag %sand (stag %t qut)) :- '(' - (stag %cncl (ifix [lit rit] (most ace wide))) + (stag %cncl (ifix [pal par] (most ace wide))) :- '{' - (stag %ktcl (stag %bscl (ifix [lob rob] (most ace wyde)))) + (stag %ktcl (stag %bscl (ifix [kel ker] (most ace wyde)))) :- '*' ;~ pose (stag %kttr ;~(pfix tar wyde)) (cold [%base %noun] tar) == :- '@' - ;~(pfix vat (stag %base (stag %atom mota))) + ;~(pfix pat (stag %base (stag %atom mota))) :- '+' ;~ pose - (stag %dtls ;~(pfix lus (ifix [lit rit] wide))) + (stag %dtls ;~(pfix lus (ifix [pal par] wide))) :: %+ cook |= a/(list (list woof)) @@ -13574,14 +13580,14 @@ :- ':' ;~ pfix col ;~ pose - (stag %mccl (ifix [lit rit] (most ace wide))) - ;~(pfix net (stag %mcnt wide)) + (stag %mccl (ifix [pal par] (most ace wide))) + ;~(pfix fas (stag %mcnt wide)) == == :- '=' ;~ pfix tis ;~ pose - (stag %dtts (ifix [lit rit] ;~(glam wide wide))) + (stag %dtts (ifix [pal par] ;~(glam wide wide))) :: %+ sear :: mainly used for +skin formation @@ -13596,7 +13602,7 @@ :- '?' ;~ pose %+ stag %ktcl - (stag %bswt ;~(pfix wut (ifix [lit rit] (most ace wyde)))) + (stag %bswt ;~(pfix wut (ifix [pal par] (most ace wyde)))) :: (cold [%base %flag] wut) == @@ -13608,16 +13614,16 @@ (cold [%base %cell] ket) == :- '`' - ;~ pfix tec + ;~ pfix tic ;~ pose %+ cook |=({a/@ta b/hoon} [%ktls [%sand a 0] [%ktls [%sand %$ 0] b]]) - ;~(pfix vat ;~(plug mota ;~(pfix tec wide))) + ;~(pfix pat ;~(plug mota ;~(pfix tic wide))) ;~ pfix tar - (stag %kthp (stag [%base %noun] ;~(pfix tec wide))) + (stag %kthp (stag [%base %noun] ;~(pfix tic wide))) == - (stag %kthp ;~(plug wyde ;~(pfix tec wide))) - (stag %ktls ;~(pfix lus ;~(plug wide ;~(pfix tec wide)))) + (stag %kthp ;~(plug wyde ;~(pfix tic wide))) + (stag %ktls ;~(pfix lus ;~(plug wide ;~(pfix tic wide)))) (cook |=(a/hoon [[%rock %n ~] a]) wide) == == @@ -13631,7 +13637,7 @@ :- '|' ;~ pose (cook |=(a/wing [%cnts a ~]) rope) - (stag %wtbr ;~(pfix bar (ifix [lit rit] (most ace wide)))) + (stag %wtbr ;~(pfix bar (ifix [pal par] (most ace wide)))) ;~(plug (stag %rock (stag %f (cold | bar))) wede) (stag %sand (stag %f (cold | bar))) == @@ -13641,11 +13647,11 @@ :: ;~ pfix sig ;~ pose - (stag %clsg (ifix [lac rac] (most ace wide))) + (stag %clsg (ifix [sel ser] (most ace wide))) :: %+ stag %cnsg %+ ifix - [lit rit] + [pal par] ;~(glam rope wide (most ace wide)) :: (cook (jock |) twid:so) @@ -13657,18 +13663,18 @@ :- '/' rood :- '<' - (ifix [led ban] (stag %tell (most ace wide))) + (ifix [gal gar] (stag %tell (most ace wide))) :- '>' - (ifix [ban led] (stag %yell (most ace wide))) + (ifix [gar gal] (stag %yell (most ace wide))) == ++ soil ;~ pose ;~ less (jest '"""') - %+ ifix [yel yel] + %+ ifix [doq doq] %- star ;~ pose - ;~(pfix bas ;~(pose bas yel lob bix:ab)) - ;~(less yel bas lob prn) + ;~(pfix bas ;~(pose bas doq kel bix:ab)) + ;~(less doq bas kel prn) (stag ~ sump) == == @@ -13677,13 +13683,13 @@ [(jest '"""\0a') (jest '\0a"""')] %- star ;~ pose - ;~(pfix bas ;~(pose bas lob bix:ab)) - ;~(less bas lob prn) + ;~(pfix bas ;~(pose bas kel bix:ab)) + ;~(less bas kel prn) ;~(less (jest '\0a"""') (just `@`10)) (stag ~ sump) == == - ++ sump (ifix [lob rob] (stag %cltr (most ace wide))) + ++ sump (ifix [kel ker] (stag %cltr (most ace wide))) ++ norm :: rune regular form |= tol/? |% @@ -13691,18 +13697,18 @@ %- stew ^. stet ^. limo :~ :- '$' - ;~ pfix bus + ;~ pfix buc %- stew ^. stet ^. limo :~ [':' (rune col %bscl exqs)] ['%' (rune cen %bscn exqs)] - ['<' (rune led %bsld exqb)] - ['>' (rune ban %bsbn exqb)] + ['<' (rune gal %bsld exqb)] + ['>' (rune gar %bsbn exqb)] ['^' (rune ket %bskt exqb)] ['~' (rune sig %bssg exqd)] ['|' (rune bar %bsbr exqc)] - ['&' (rune pad %bspd exqc)] - ['@' (rune vat %bsvt exqb)] + ['&' (rune pam %bspd exqc)] + ['@' (rune pat %bsvt exqb)] ['_' (rune cab %bscb expa)] ['-' (rune hep %bshp exqb)] ['=' (rune tis %bsts exqg)] @@ -13749,7 +13755,7 @@ ^. stet ^. limo :~ ['_' (rune cab %brcb exqr)] ['%' (runo cen %brcn ~ expe)] - ['@' (runo vat %brvt ~ expe)] + ['@' (runo pat %brvt ~ expe)] [':' (rune col %brcl expb)] ['.' (rune dot %brdt expa)] ['-' (rune hep %brhp expa)] @@ -13758,21 +13764,21 @@ ['*' (rune tar %brtr exqc)] ['=' (rune tis %brts exqc)] ['?' (rune wut %brwt expa)] - ['$' (rune bus %brbs exqe)] + ['$' (rune buc %brbs exqe)] == == :- '$' - ;~ pfix bus + ;~ pfix buc %- stew ^. stet ^. limo - :~ ['@' (stag %ktcl (rune vat %bsvt exqb))] + :~ ['@' (stag %ktcl (rune pat %bsvt exqb))] ['_' (stag %ktcl (rune cab %bscb expa))] [':' (stag %ktcl (rune col %bscl exqs))] ['%' (stag %ktcl (rune cen %bscn exqs))] - ['<' (stag %ktcl (rune led %bsld exqb))] - ['>' (stag %ktcl (rune ban %bsbn exqb))] + ['<' (stag %ktcl (rune gal %bsld exqb))] + ['>' (stag %ktcl (rune gar %bsbn exqb))] ['|' (stag %ktcl (rune bar %bsbr exqc))] - ['&' (stag %ktcl (rune pad %bspd exqc))] + ['&' (stag %ktcl (rune pam %bspd exqc))] ['^' (stag %ktcl (rune ket %bskt exqb))] ['~' (stag %ktcl (rune sig %bssg exqd))] ['-' (stag %ktcl (rune hep %bshp exqb))] @@ -13828,7 +13834,7 @@ ['.' (rune dot %ktdt expb)] ['-' (rune hep %kthp exqc)] ['+' (rune lus %ktls expb)] - ['&' (rune pad %ktpd expa)] + ['&' (rune pam %ktpd expa)] ['~' (rune sig %ktsg expa)] ['=' (rune tis %ktts expj)] ['?' (rune wut %ktwt expa)] @@ -13842,14 +13848,14 @@ %- stew ^. stet ^. limo :~ ['|' (rune bar %sgbr expb)] - ['$' (rune bus %sgbs expf)] + ['$' (rune buc %sgbs expf)] ['_' (rune cab %sgcb expb)] ['%' (rune cen %sgcn hind)] - ['/' (rune net %sgnt hine)] - ['<' (rune led %sgld hinb)] - ['>' (rune ban %sgbn hinb)] + ['/' (rune fas %sgnt hine)] + ['<' (rune gal %sgld hinb)] + ['>' (rune gar %sgbn hinb)] ['+' (rune lus %sgls hinc)] - ['&' (rune pad %sgpd hinf)] + ['&' (rune pam %sgpd hinf)] ['?' (rune wut %sgwt hing)] ['=' (rune tis %sgts expb)] ['!' (rune zap %sgzp expb)] @@ -13860,7 +13866,7 @@ %- stew ^. stet ^. limo :~ [':' (rune col %mccl expi)] - ['/' (rune net %mcnt expa)] + ['/' (rune fas %mcnt expa)] ['<' (rune gal %mcgl exp1)] ['~' (rune sig %mcsg expi)] [';' (rune mic %mcmc exqc)] @@ -13875,10 +13881,10 @@ ['?' (rune wut %tswt expw)] ['^' (rune ket %tskt expt)] [':' (rune col %tscl expp)] - ['/' (rune net %tsnt expo)] + ['/' (rune fas %tsnt expo)] [';' (rune mic %tsmc expo)] - ['<' (rune led %tsld expb)] - ['>' (rune ban %tsbn expb)] + ['<' (rune gal %tsld expb)] + ['>' (rune gar %tsbn expb)] ['-' (rune hep %tshp expb)] ['*' (rune tar %tstr expg)] [',' (rune com %tscm expb)] @@ -13893,15 +13899,15 @@ :~ ['|' (rune bar %wtbr exps)] [':' (rune col %wtcl expc)] ['.' (rune dot %wtdt expc)] - ['<' (rune led %wtld expb)] - ['>' (rune ban %wtbn expb)] + ['<' (rune gal %wtld expb)] + ['>' (rune gar %wtbn expb)] ['-' ;~(pfix hep (toad txhp))] ['^' ;~(pfix ket (toad tkkt))] ['=' ;~(pfix tis (toad txts))] ['#' ;~(pfix hax (toad txhx))] ['+' ;~(pfix lus (toad txls))] - ['&' (rune pad %wtpd exps)] - ['@' ;~(pfix vat (toad tkvt))] + ['&' (rune pam %wtpd exps)] + ['@' ;~(pfix pat (toad tkvt))] ['~' ;~(pfix sig (toad tksg))] ['!' (rune zap %wtzp expa)] == @@ -13914,9 +13920,9 @@ ['.' ;~(pfix dot (toad |.(loaf(bug |))))] [',' (rune com %zpcm expb)] [';' (rune mic %zpmc expb)] - ['>' (rune ban %zpbn expa)] - ['<' (rune led %zpld exqc)] - ['@' (rune vat %zpvt expy)] + ['>' (rune gar %zpbn expa)] + ['<' (rune gal %zpld exqc)] + ['@' (rune pat %zpvt expy)] ['=' (rune tis %zpts expa)] ['?' (rune wut %zpwt hinh)] == @@ -13931,7 +13937,7 @@ (jest '+-') :: XX deprecated == ;~ plug - ;~(pfix gap ;~(pose (cold %$ bus) sym)) + ;~(pfix gap ;~(pose (cold %$ buc) sym)) ;~(pfix gap loaf) == == @@ -13965,14 +13971,14 @@ ;~ pfix (jest '+*') ;~ plug ;~(pfix gap sym) - ;~(pfix gap (ifix [lac rac] (most ace sym))) + ;~(pfix gap (ifix [sel ser] (most ace sym))) ;~(pfix gap loan) == == == :: parses a or [a b c] or a b c == ++ lynx - =/ wid (ifix [lac rac] (most ace sym)) + =/ wid (ifix [sel ser] (most ace sym)) =/ tal ;~ sfix (most gap sym) @@ -14052,7 +14058,7 @@ ++ toad :: untrap parser exp =+ har=expa |@ ++ $ - =+ dur=(ifix [lit rit] $:har(tol |)) + =+ dur=(ifix [pal par] $:har(tol |)) ?:(tol ;~(pose ;~(pfix gap $:har(tol &)) dur) dur) -- :: @@ -14203,12 +14209,12 @@ ++ hine |.(;~(gunk bonk loaf)) :: jet-hint and hoon ++ hinf |. :: 0-3 >s, two hoons ;~ pose - ;~(gunk (cook lent (stun [1 3] ban)) loaf loaf) + ;~(gunk (cook lent (stun [1 3] gar)) loaf loaf) (stag 0 ;~(gunk loaf loaf)) == ++ hing |. :: 0-3 >s, three hoons ;~ pose - ;~(gunk (cook lent (stun [1 3] ban)) loaf loaf loaf) + ;~(gunk (cook lent (stun [1 3] gar)) loaf loaf loaf) (stag 0 ;~(gunk loaf loaf loaf)) == ++ bonk :: jet signature @@ -14224,7 +14230,7 @@ ;~ gunk ;~ pose dem - (ifix [lac rac] ;~(plug dem ;~(pfix ace dem))) + (ifix [sel ser] ;~(plug dem ;~(pfix ace dem))) == loaf == @@ -14237,7 +14243,7 @@ ;~ pose (cold ~ sig) %+ ifix - ?:(tol [;~(plug duz gap) ;~(plug gap duz)] [lit rit]) + ?:(tol [;~(plug duz gap) ;~(plug gap duz)] [pal par]) (more mash ;~(gunk ;~(pfix cen sym) loaf)) == -- @@ -14275,7 +14281,7 @@ ;~(plug (cold %ket ket) wide) ;~ plug (easy %lit) - (ifix [lit rit] lobo) + (ifix [pal par] lobo) == == == @@ -14287,7 +14293,7 @@ %+ cook |=(hoon +<) %+ stag %cltr %+ ifix - [;~(plug lac gap) ;~(plug gap rac)] + [;~(plug sel gap) ;~(plug gap ser)] (most gap tall) :: ++ ropa (most col rope) @@ -14300,13 +14306,13 @@ (cold [%| 0 ~] com) %+ cook |=({a/(list) b/term} ?~(a b [%| (lent a) `b])) - ;~(plug (star ket) ;~(pose sym (cold %$ bus))) + ;~(plug (star ket) ;~(pose sym (cold %$ buc))) :: %+ cook |=(a/axis [%& a]) ;~ pose ;~(pfix lus dim:ag) - ;~(pfix pad (cook |=(a/@ ?:(=(0 a) 0 (mul 2 +($(a (dec a)))))) dim:ag)) + ;~(pfix pam (cook |=(a/@ ?:(=(0 a) 0 (mul 2 +($(a (dec a)))))) dim:ag)) ;~(pfix bar (cook |=(a/@ ?:(=(0 a) 1 +((mul 2 $(a (dec a)))))) dim:ag)) ven (cold 1 dot) @@ -14332,9 +14338,7 @@ term [%name term %spec u.unit %base %noun] ;~ plug sym - :: XX: net deprecated - :: - (punt ;~(pfix ;~(pose net tis) wyde)) + (punt ;~(pfix ;~(pose fas tis) wyde)) == :: %+ cook @@ -14352,7 +14356,7 @@ ++ wede :: wide bulb :: XX: lus deprecated :: - ;~(pfix ;~(pose lus net) wide) + ;~(pfix ;~(pose lus fas) wide) ++ wide :: full wide form %+ knee *hoon |.(~+((wart ;~(pose expression:(norm |) long apex:(sail |))))) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 76abd9c19..0ebe2d09c 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -785,23 +785,35 @@ ~ ``noun+!>(u.peer) :: [%forward-lane ~] - :: find lane for u.who, or their galaxy + :: + :: this duplicates the routing hack from +send-blob:event-core + :: so long as neither the peer nor the peer's sponsoring galaxy is us: + :: + :: - no route to the peer: send to the peer's sponsoring galaxy + :: - direct route to the peer: use that + :: - indirect route to the peer: send to both that route and the + :: the peer's sponsoring galaxy :: :^ ~ ~ %noun !> ^- (list lane) - =/ ship-state (~(get by peers.ames-state) u.who) - ?. ?=([~ %known *] ship-state) + ?. ?& ?=([~ %known *] peer) + !=(our u.who) + == ~ - =/ peer-state +.u.ship-state - ?. =(~ route.peer-state) ::NOTE avoid tmi - [lane:(need route.peer-state)]~ - |- ^- (list lane) - ?: ?=(%czar (clan:title sponsor.peer-state)) - [%& sponsor.peer-state]~ - =/ next (~(get by peers.ames-state) sponsor.peer-state) + =; zar=(trap (list lane)) + ?~ route.u.peer $:zar + =* rot u.route.u.peer + ?:(direct.rot [lane.rot ~] [lane.rot $:zar]) + :: + |. ^- (list lane) + ?: ?=(%czar (clan:title sponsor.u.peer)) + ?: =(our sponsor.u.peer) + ~ + [%& sponsor.u.peer]~ + =/ next (~(get by peers.ames-state) sponsor.u.peer) ?. ?=([~ %known *] next) ~ - $(peer-state +.u.next) + $(peer next) == :: [%bones @ ~] @@ -1034,6 +1046,9 @@ ++ on-hear-open |= [=lane =packet ok=?] ^+ event-core + :: assert the comet can't pretend to be a moon or other address + :: + ?> ?=(%pawn (clan:title sndr.packet)) :: if we already know .sndr, ignore duplicate attestation :: =/ ship-state (~(get by peers.ames-state) sndr.packet) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index edc3ca3ff..290a7c4b8 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -561,7 +561,7 @@ ++ vale |= =noun ^+ sam - (slam (slap cor ^~((ream 'noun:grab'))) !>(noun)) + (slam (slap cor !,(*hoon noun:grab)) !>(noun)) ++ volt |= =noun ^+ sam @@ -577,22 +577,23 @@ ^- vase %+ slap (with-faces cor+cor sam+sam new+new ~) - ^~((ream '(diff:~(grad cor sam) new)')) + !, *hoon + (diff:~(grad cor sam) new) ++ form fom ++ join |= [a=vase b=vase] ^- (unit (unit vase)) ?: =(q.a q.b) ~ - =; res `?~(q.res ~ `(slap res ^~((ream '?~(. !! u)')))) - (slam (slap cor ^~((ream 'join:grad'))) (slop a b)) + =; res `?~(q.res ~ `(slap res !,(*hoon ?~(. !! u)))) + (slam (slap cor !,(*hoon join:grad)) (slop a b)) ++ mash |= [a=[=ship =desk diff=vase] b=[=ship =desk diff=vase]] ^- (unit vase) ?: =(q.diff.a q.diff.b) ~ :- ~ - %+ slam (slap cor ^~((ream 'mash:grad'))) + %+ slam (slap cor !,(*hoon mash:grad)) %+ slop :(slop !>(ship.a) !>(desk.a) diff.a) :(slop !>(ship.b) !>(desk.b) diff.b) @@ -601,11 +602,12 @@ ^+ sam %+ slap (with-faces cor+cor sam+sam diff+diff ~) - ^~((ream '(pact:~(grad cor sam) diff)')) + !, *hoon + (pact:~(grad cor sam) diff) ++ vale |= =noun ^+ sam - (slam (slap cor ^~((ream 'noun:grab'))) !>(noun)) + (slam (slap cor !,(*hoon noun:grab)) !>(noun)) ++ volt |= =noun ^+ sam @@ -637,7 +639,7 @@ :: try +grow; is there a +grow core with a .b arm? :: =^ old=vase nub (build-fit %mar a) - ?: =/ ram (mule |.((slap old ^~((ream 'grow'))))) + ?: =/ ram (mule |.((slap old !,(*hoon grow)))) ?: ?=(%| -.ram) %.n =/ lab (mule |.((slob b p.p.ram))) ?: ?=(%| -.lab) %.n @@ -650,22 +652,28 @@ ^- vase %+ slap (with-faces old+old sam+sam ~) - %- ream - ;: (cury cat 3) - '!: ' - '~! old=old ' - '~! sam=sam ' - b ':~(grow old sam)' - == + :+ %sgzp !,(*hoon old=old) + :+ %sgzp !,(*hoon sam=sam) + :+ %tsld [%limb b] + !, *hoon + ~(grow old sam) :: try direct +grab :: =^ new=vase nub (build-fit %mar b) - =/ rab (mule |.((slap new (ream (cat 3 a ':grab'))))) + =/ rab + %- mule |. + %+ slap new + :+ %tsld [%limb a] + [%limb %grab] ?: &(?=(%& -.rab) ?=(^ q.p.rab)) :_(nub |=(sam=vase ~|([%grab a b] (slam p.rab sam)))) :: try +jump :: - =/ jum (mule |.((slap old (ream (cat 3 b ':jump'))))) + =/ jum + %- mule |. + %+ slap old + :+ %tsld [%limb b] + [%limb %jump] ?: ?=(%& -.jum) (compose-casts a !<(mark p.jum) b) :: try indirect +grab @@ -803,7 +811,7 @@ :: parse optional /? and ignore :: ;~ pose - (cold ~ ;~(plug net wut gap dem gap)) + (cold ~ ;~(plug fas wut gap dem gap)) (easy ~) == :: @@ -812,7 +820,7 @@ ;~ sfix %+ cook |=((list (list taut)) (zing +<)) %+ more gap - ;~ pfix ;~(plug net hep gap) + ;~ pfix ;~(plug fas hep gap) (most ;~(plug com gaw) taut-rule) == gap @@ -824,7 +832,7 @@ ;~ sfix %+ cook |=((list (list taut)) (zing +<)) %+ more gap - ;~ pfix ;~(plug net lus gap) + ;~ pfix ;~(plug fas lus gap) (most ;~(plug com gaw) taut-rule) == gap @@ -836,9 +844,9 @@ ;~ sfix %+ cook |=((list [face=term =path]) +<) %+ more gap - ;~ pfix ;~(plug net tis gap) + ;~ pfix ;~(plug fas tis gap) %+ cook |=([term path] +<) - ;~(plug sym ;~(pfix ;~(plug gap net) (more net urs:ab))) + ;~(plug sym ;~(pfix ;~(plug gap fas) (more fas urs:ab))) == gap == @@ -849,12 +857,12 @@ ;~ sfix %+ cook |=((list [face=term =mark =path]) +<) %+ more gap - ;~ pfix ;~(plug net tar gap) + ;~ pfix ;~(plug fas tar gap) %+ cook |=([term mark path] +<) ;~ plug sym ;~(pfix ;~(plug gap cen) sym) - ;~(pfix ;~(plug gap net) (more net urs:ab)) + ;~(pfix ;~(plug gap fas) (more fas urs:ab)) == == gap @@ -1597,7 +1605,7 @@ ~> %mean.%arvo-parse-fail (path-to-hoon data /sys/arvo/hoon) ~> %mean.%arvo-compile-fail - (slap (slap hoon gen) (ream '..is')) + (slap (slap hoon gen) !,(*^hoon ..is)) :: ++ build-zuse |= arvo=vase @@ -4384,7 +4392,7 @@ %+ rain /sys/arvo/hoon (lobe-to-cord (~(got by data) /sys/arvo/hoon)) ~> %mean.%arvo-compile-fail - (slap (slap hoon gen) (ream '..is')) + (slap (slap hoon gen) !,(*^hoon ..is)) :: ++ build-zuse |= arvo=vase diff --git a/pkg/arvo/sys/vane/dill.hoon b/pkg/arvo/sys/vane/dill.hoon index 04f4d0353..58b2b5004 100644 --- a/pkg/arvo/sys/vane/dill.hoon +++ b/pkg/arvo/sys/vane/dill.hoon @@ -8,9 +8,10 @@ -- :: => |% :: console protocol ++ axle :: - $: %3 :: + $: %4 ::TODO replace ducts with session ids :: hey/(unit duct) :: default duct dug/(map duct axon) :: conversations + eye=(jug duct duct) :: outside listeners lit/? :: boot in lite mode $= veb :: vane verbosities $~ (~(put by *(map @tas log-level)) %hole %soft) :: quiet packet crashes @@ -21,7 +22,7 @@ tem/(unit (list dill-belt)) :: pending, reverse wid/_80 :: terminal width pos/@ud :: cursor position - see/(list @c) :: current line + see=$%([%lin (list @c)] [%klr stub]) :: current line == :: +$ log-level ?(%hush %soft %loud) :: none, line, full -- => :: @@ -151,7 +152,11 @@ :: ++ done :: return gift |= git/gift:able - +>(moz :_(moz [hen %give git])) + =- +>.$(moz (weld - moz)) + %+ turn + :- hen + ~(tap in (~(get ju eye.all) hen)) + |=(=duct [duct %give git]) :: ++ deal :: pass to %gall |= [=wire =deal:gall] @@ -161,7 +166,7 @@ |= [=wire =note] +>(moz :_(moz [hen %pass wire note])) :: - ++ from :: receive belt + ++ from :: receive blit |= bit/dill-blit ^+ +> ?: ?=($mor -.bit) @@ -172,86 +177,33 @@ %+ done %blit :~ [%lin p.bit] [%mor ~] - [%lin see] + see [%hop pos] == ?: ?=($klr -.bit) %+ done %blit - :~ [%lin (cvrt:ansi p.bit)] + :~ [%klr p.bit] [%mor ~] - [%lin see] + see [%hop pos] == ?: ?=($pro -.bit) - (done(see p.bit) %blit [[%lin p.bit] [%hop pos] ~]) + =. see [%lin p.bit] + (done %blit [see [%hop pos] ~]) ?: ?=($pom -.bit) - =. see (cvrt:ansi p.bit) - (done %blit [[%lin see] [%hop pos] ~]) + ::NOTE treat "styled prompt" without style as plain prompt, + :: to allow rendering by older runtimes + ::TODO remove me once v0.10.9+ has high/guaranteed adoption + :: + ?: (levy p.bit (cork head |*(s=stye =(*stye s)))) + $(bit [%pro (zing (turn p.bit tail))]) + =. see [%klr p.bit] + (done %blit [see [%hop pos] ~]) ?: ?=($hop -.bit) (done(pos p.bit) %blit [bit ~]) ?: ?=($qit -.bit) (dump %logo ~) (done %blit [bit ~]) - :: - ++ ansi - |% - ++ cvrt :: stub to (list @c) - |= a/stub :: with ANSI codes - ^- (list @c) - %- zing %+ turn a - |= a/(pair stye (list @c)) - ^- (list @c) - ;: weld - ?: =(0 ~(wyt in p.p.a)) ~ - `(list @c)`(zing (turn ~(tap in p.p.a) ef)) - (bg p.q.p.a) - (fg q.q.p.a) - q.a - ?~(p.p.a ~ (ef ~)) - (bg ~) - (fg ~) - == - :: - ++ ef |=(a/^deco (scap (deco a))) :: ANSI effect - :: - ++ fg |=(a/^tint (scap (tint a))) :: ANSI foreground - :: - ++ bg :: ANSI background - |= a/^tint - %- scap - =>((tint a) [+(p) q]) :: (add 10 fg) - :: - ++ scap :: ANSI escape seq - |= a/$@(@ (pair @ @)) - %- (list @c) - :+ 27 '[' :: "\033[{a}m" - ?@(a :~(a 'm') :~(p.a q.a 'm')) - :: - ++ deco :: ANSI effects - |= a/^deco ^- @ - ?- a - ~ '0' - $br '1' - $un '4' - $bl '5' - == - :: - ++ tint :: ANSI colors (fg) - |= a/^tint - ^- (pair @ @) - :- '3' - ?- a - $k '0' - $r '1' - $g '2' - $y '3' - $b '4' - $m '5' - $c '6' - $w '7' - ~ '9' - == - -- :: XX move :: ++ sein @@ -398,7 +350,7 @@ =* duc (need hey.all) =/ app %hood =/ see (tuba "") - =/ zon=axon [app input=[~ ~] width=80 cursor=(lent see) see] + =/ zon=axon [app input=[~ ~] width=80 cursor=(lent see) lin+see] :: =^ moz all abet:(~(into as duc zon) ~) [moz ..^$] @@ -422,7 +374,29 @@ =. veb.all (~(put by veb.all) tag.task level.task) [~ ..^$] :: + ?: ?=(%view -.task) + :: crash on viewing non-existent session + :: + ~| [%no-session session.task] + ?> =(~ session.task) + =/ session (need hey.all) + =/ =axon (~(got by dug.all) session) + :: register the viewer and send them the prompt line + :: + :- [hen %give %blit [see.axon]~]~ + ..^$(eye.all (~(put ju eye.all) session hen)) + :: + ?: ?=(%flee -.task) + :- ~ + ~| [%no-session session.task] + ?> =(~ session.task) + =/ session (need hey.all) + ..^$(eye.all (~(del ju eye.all) session hen)) + :: =/ nus (ax hen) + =? nus &(?=(~ nus) ?=(^ hey.all)) + ::TODO allow specifying target session in task + (ax u.hey.all) ?~ nus :: :hen is an unrecognized duct :: could be before %boot (or %boot failed) @@ -441,7 +415,7 @@ ++ axle-1 $: $1 hey/(unit duct) - dug/(map duct axon) + dug/(map duct axon-3) lit/? $= hef $: a/(unit mass) @@ -457,10 +431,11 @@ $~ (~(put by *(map @tas log-level)) %hole %soft) (map @tas log-level) == + :: ++ axle-2 $: %2 hey/(unit duct) - dug/(map duct axon) + dug/(map duct axon-3) lit/? dog/_| $= hef @@ -478,29 +453,68 @@ (map @tas log-level) == :: - ++ axle-any - $%(axle-1 axle-2 axle) + +$ axle-3 + $: %3 + hey=(unit duct) + dug=(map duct axon-3) + lit=? + $= veb + $~ (~(put by *(map @tas log-level)) %hole %soft) + (map @tas log-level) + == + +$ axon-3 + $: ram=term + tem=(unit (list dill-belt)) + wid=_80 + pos=@ud + see=(list @c) + == + :: + +$ axle-any + $%(axle-1 axle-2 axle-3 axle) -- :: |= old=axle-any ?- -.old %1 $(old [%2 [hey dug lit dog=& hef veb]:old]) %2 $(old [%3 [hey dug lit veb]:old]) - %3 ..^$(all old) + %3 =- $(old [%4 hey.old - ~ lit.old veb.old]) + (~(run by dug.old) |=(a=axon-3 a(see lin+see.a))) + %4 ..^$(all old) == :: ++ scry |= {fur/(unit (set monk)) ren/@tas why/shop syd/desk lot/coin tyl/path} ^- (unit (unit cage)) - ?. ?=(%& -.why) ~ - =* his p.why + ::TODO don't special-case whey scry + :: ?: &(=(ren %$) =(tyl /whey)) =/ maz=(list mass) :~ hey+&+hey.all dug+&+dug.all == ``mass+!>(maz) - [~ ~] + :: only respond for the local identity, %$ desk, current timestamp + :: + ?. ?& =(&+our why) + =([%$ %da now] lot) + =(%$ syd) + == + ~ + :: /dx/sessions//line blit current line (prompt) of default session + :: /dx/sessions//cursor @ud current cursor position of default session + ::TODO support asking for specific sessions once session ids are real + :: + ?. ?=(%x ren) ~ + ?+ tyl ~ + [%sessions %$ *] + ?~ hey.all [~ ~] + ?~ session=(~(get by dug.all) u.hey.all) [~ ~] + ?+ t.t.tyl ~ + [%line ~] ``blit+!>(`blit`see.u.session) + [%cursor ~] ``atom+!>(pos.u.session) + == + == :: ++ stay all :: diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index 8744d142a..758e7d410 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -462,7 +462,7 @@ == ;body ;h1:"Internal Server Error" - ;p:"There was an error while handling the request for {<(trip url)>}." + ;p:"There was an error while handling the request for {(trip url)}." ;* ?: authorized ;= ;code:"*{(render-tang-to-marl 80 t)}" @@ -478,7 +478,7 @@ :: =/ code-as-tape=tape (format-ud-as-integer code) =/ message=tape - ?+ code "{} Error" + ?+ code "{(scow %ud code)} Error" %400 "Bad Request" %403 "Forbidden" %404 "Not Found" @@ -495,7 +495,7 @@ == ;body ;h1:"{message}" - ;p:"There was an error while handling the request for {<(trip url)>}." + ;p:"There was an error while handling the request for {(trip url)}." ;* ?: authorized ;= ;code:"{t}" @@ -590,8 +590,12 @@ =* headers header-list.request :: for requests from localhost, respect the "forwarded" header :: - =? address =([%ipv4 .127.0.0.1] address) - (fall (forwarded-for headers) address) + =/ [secure=? =^address] + =* same [secure address] + ?. =([%ipv4 .127.0.0.1] address) same + ?~ forwards=(forwarded-params headers) same + :- (fall (forwarded-secure u.forwards) secure) + (fall (forwarded-for u.forwards) address) :: =/ host (get-header:http 'host' headers) =/ [=action suburl=@t] @@ -995,7 +999,7 @@ ~ :: is there an urbauth cookie? :: - ?~ urbauth=(get-header:http (crip "urbauth-{}") u.cookies) + ?~ urbauth=(get-header:http (crip "urbauth-{(scow %p our)}") u.cookies) ~ :: if it's formatted like a valid session cookie, produce it :: @@ -1035,7 +1039,7 @@ ^- @t %- crip =; max-age=tape - "urbauth-{}={}; Path=/; Max-Age={max-age}" + "urbauth-{(scow %p our)}={(scow %uv session)}; Path=/; Max-Age={max-age}" %- format-ud-as-integer ?. extend 0 (div (msec:milly session-timeout) 1.000) @@ -1500,6 +1504,16 @@ ?~ channel :_ state :_ ~ [duct %pass /flog %d %flog %crud %eyre-no-channel >id=channel-id< ~] + :: it's possible that this is a sign emitted directly alongside a fact + :: that triggered a clog & closed the subscription. in that case, just + :: drop the sign. + :: poke-acks are not paired with subscriptions, so we can process them + :: regardless. + :: + ?: ?& !?=(%poke-ack -.sign) + !(~(has by subscriptions.u.channel) request-id) + == + [~ state] :: attempt to convert the sign to json. :: if conversion succeeds, we *can* send it. if the client is actually :: connected, we *will* send it immediately. @@ -1535,10 +1549,10 @@ :: update channel's unacked counts, find out if clogged :: =^ clogged unacked.u.channel - :: poke-acks are one-offs, don't apply clog logic to them. + :: only apply clog logic to facts. :: and of course don't count events we can't send as unacked. :: - ?: ?| ?=(%poke-ack -.sign) + ?: ?| !?=(%fact -.sign) ?=(~ json) == [| unacked.u.channel] @@ -1555,6 +1569,10 @@ =* kicking |(clogged ?=(~ json)) =? moves kicking :_ moves + ::NOTE this shouldn't crash because we + :: - never fail to serialize subscriptionless signs (%poke-ack), + :: - only clog on %facts, which have a subscription associated, + :: - and already checked whether we still have that subscription. =+ (~(got by subscriptions.u.channel) request-id) :^ duct %pass (subscription-wire channel-id request-id ship app) @@ -1585,7 +1603,7 @@ == =? next-id kicking +(next-id) :: - :- moves + :- (flop moves) %_ state session.channel-state %+ ~(put by session.channel-state.state) channel-id @@ -2013,29 +2031,39 @@ (cat 3 '.' u.ext.request-line) -- :: -++ forwarded-for +++ forwarded-params |= =header-list:http - ^- (unit address) - =/ forwarded=(unit @t) + ^- (unit (list (map @t @t))) + %+ biff (get-header:http 'forwarded' header-list) - ?~ forwarded ~ - |^ =/ forwards=(unit (list (map @t @t))) - (unpack-header:http u.forwarded) - ?. ?=([~ ^] forwards) ~ - =* forward i.u.forwards - ?~ for=(~(get by forward) 'for') ~ - ::NOTE per rfc7239, non-ip values are also valid. they're not useful - :: for the general case, so we ignore them here. if needed, - :: request handlers are free to inspect the headers themselves. - :: - (rush u.for ip-address) + unpack-header:http +:: +++ forwarded-for + |= forwards=(list (map @t @t)) + ^- (unit address) + ?. ?=(^ forwards) ~ + =* forward i.forwards + ?~ for=(~(get by forward) 'for') ~ + ::NOTE per rfc7239, non-ip values are also valid. they're not useful + :: for the general case, so we ignore them here. if needed, + :: request handlers are free to inspect the headers themselves. :: - ++ ip-address - ;~ sfix - ;~(pose (stag %ipv4 ip4) (stag %ipv6 (ifix [lac rac] ip6))) - ;~(pose ;~(pfix col dim:ag) (easy ~)) - == - -- + %+ rush u.for + ;~ sfix + ;~(pose (stag %ipv4 ip4) (stag %ipv6 (ifix [sel ser] ip6))) + ;~(pose ;~(pfix col dim:ag) (easy ~)) + == +:: +++ forwarded-secure + |= forwards=(list (map @t @t)) + ^- (unit ?) + ?. ?=(^ forwards) ~ + =* forward i.forwards + ?~ proto=(~(get by forward) 'proto') ~ + ?+ u.proto ~ + %http `| + %https `& + == :: ++ parse-request-line |= url=@t @@ -2378,7 +2406,7 @@ =/ handle-gall-error handle-gall-error:(per-server-event event-args) =^ moves server-state.ax - (handle-gall-error leaf+"eyre bad mark {}" ~) + (handle-gall-error leaf+"eyre bad mark {(trip mark)}" ~) [moves http-server-gate] :: =/ =http-event:http diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index 4dc733ca8..9662e1c93 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -367,7 +367,7 @@ ++ pairs %+ cook ~(gas by *(map @t @t)) - %+ more (ifix [. .]:(star ace) mic) + %+ most (ifix [. .]:(star ace) mic) ;~(plug token ;~(pose ;~(pfix tis value) (easy ''))) :: ++ value @@ -378,16 +378,16 @@ ::NOTE this is ptok:de-purl:html, but can't access that here %- plus ;~ pose - aln zap hax bus cen pad say tar lus - hep dot ket cab tec bar sig + aln zap hax buc cen pam soq tar lus + hep dot ket cab tic bar sig == :: ++ quoted-string :: 7230 quoted string %+ cook crip - %+ ifix [. .]:;~(less (jest '\\"') yel) + %+ ifix [. .]:;~(less (jest '\\"') doq) %- star ;~ pose - ;~(pfix bat ;~(pose (just '\09') ace prn)) + ;~(pfix bas ;~(pose (just '\09') ace prn)) ;~(pose (just '\09') ;~(less (mask "\22\5c\7f") (shim 0x20 0xff))) == -- @@ -1120,6 +1120,7 @@ {$boot lit/? p/*} :: weird %dill boot {$crop p/@ud} :: trim kernel state $>(%crud vane-task) :: error with trace + [%flee session=~] :: unwatch session {$flog p/flog} :: wrapped error {$flow p/@tas q/(list gill:gall)} :: terminal config {$hail ~} :: terminal refresh @@ -1134,6 +1135,7 @@ {$talk p/tank} :: {$text p/tape} :: {$veer p/@ta q/path r/@t} :: install vane + [%view session=~] :: watch session blits $>(%trim vane-task) :: trim state $>(%vega vane-task) :: report upgrade {$verb ~} :: verbose mode @@ -1157,6 +1159,7 @@ $% {$bel ~} :: make a noise {$clr ~} :: clear the screen {$hop p/@ud} :: set cursor position + [%klr p=stub] :: set styled line {$lin p/(list @c)} :: set current line {$mor ~} :: newline {$sag p/path q/*} :: save to jamfile @@ -5362,28 +5365,30 @@ :: :::: ++ format ^? |% - :: :: ++to-wain:format - ++ to-wain :: atom to line list - ~% %lore ..is ~ - |= lub/@ - =| tez/(list @t) - |- ^+ tez - =+ ^= wor - =+ [meg=0 i=0] - |- ^- {meg/@ i/@ end/@f} - =+ gam=(cut 3 [i 1] lub) - ?: =(0 gam) - [meg i %.y] - ?: =(10 gam) - [meg i %.n] - $(meg (cat 3 meg gam), i +(i)) - ?: end.wor - (flop ^+(tez [meg.wor tez])) - ?: =(0 lub) (flop tez) - $(lub (rsh 3 +(i.wor) lub), tez [meg.wor tez]) + :: 0 ending a line (invalid @t) is not preserved :: ++to-wain:format + ++ to-wain :: cord to line list + ~% %leer ..is ~ + |= txt=cord + ^- wain + =/ len=@ (met 3 txt) + =/ cut =+(cut -(a 3, c 1, d txt)) + =/ sub sub + =| [i=@ out=wain] + |- ^+ out + =+ |- ^- j=@ + ?: ?| =(i len) + =(10 (cut(b i))) + == + i + $(i +(i)) + =. out :_ out + (cut(b i, c (sub j i))) + ?: =(j len) + (flop out) + $(i +(j)) :: :: ++of-wain:format - ++ of-wain :: line list to atom - |= tez/(list @t) + ++ of-wain :: line list to cord + |= tez=wain ^- cord (rap 3 (join '\0a' tez)) :: :: ++of-wall:format ++ of-wall :: line list to tape @@ -5636,7 +5641,7 @@ [(rash a fel) b] :: :: ++pa:dejs:format ++ pa :: string as path - (su ;~(pfix net (more net urs:ab))) + (su ;~(pfix fas (more fas urs:ab))) :: :: ++pe:dejs:format ++ pe :: prefix |* {pre/* wit/fist} @@ -6198,7 +6203,7 @@ :: :: ++abox:de-json:html ++ abox :: array %+ stag %a - (ifix [lac (wish rac)] (more (wish com) apex)) + (ifix [sel (wish ser)] (more (wish com) apex)) :: :: ++apex:de-json:html ++ apex :: any value %+ knee *json |. ~+ @@ -6230,7 +6235,7 @@ =* wow `(map @t @)`(malt lip) (sear ~(get by wow) low) =* tuf ;~(pfix (just 'u') (cook tuft qix:ab)) - ;~(pose yel net say bas loo tuf) + ;~(pose doq fas soq bas loo tuf) == :: :: ++expo:de-json:html ++ expo :: exponent @@ -6244,7 +6249,7 @@ ;~(plug dot digs) :: :: ++jcha:de-json:html ++ jcha :: string character - ;~(pose ;~(less yel bas prn) esca) + ;~(pose ;~(less doq bas prn) esca) :: :: ++mayb:de-json:html ++ mayb :: optional |*(bus/rule ;~(pose bus (easy ~))) @@ -6261,7 +6266,7 @@ == :: :: ++obje:de-json:html ++ obje :: object list - %+ ifix [(wish leb) (wish reb)] + %+ ifix [(wish kel) (wish ker)] (more (wish com) pear) :: :: ++obox:de-json:html ++ obox :: object @@ -6275,7 +6280,7 @@ (cook |=(a/@ [a ~]) bus) :: :: ++stri:de-json:html ++ stri :: string - (cook crip (ifix [yel yel] (star jcha))) + (cook crip (ifix [doq doq] (star jcha))) :: :: ++tops:de-json:html ++ tops :: strict value ;~(pose abox obox) @@ -6384,14 +6389,14 @@ ;~(pfix (plus whit) name) ;~ pose %+ ifix - :_ yel - ;~(plug (ifix [. .]:(star whit) tis) yel) - (star ;~(less yel escp)) + :_ doq + ;~(plug (ifix [. .]:(star whit) tis) doq) + (star ;~(less doq escp)) :: %+ ifix - :_ say - ;~(plug (ifix [. .]:(star whit) tis) say) - (star ;~(less say escp)) + :_ soq + ;~(plug (ifix [. .]:(star whit) tis) soq) + (star ;~(less soq escp)) :: (easy ~) == @@ -6407,7 +6412,7 @@ :: :: ++chrd:de-xml:html ++ chrd :: character data %+ cook |=(a/tape ^-(mars ;/(a))) - (plus ;~(less yel ;~(pose (just `@`10) escp))) + (plus ;~(less doq ;~(pose (just `@`10) escp))) :: :: ++comt:de-xml:html ++ comt :: comments =- (ifix [(jest '')] (star -)) @@ -6424,10 +6429,10 @@ ;~(less (jest '?>') prn) :: :: ++escp:de-xml:html ++ escp :: - ;~(pose ;~(less led ban pad prn) enty) + ;~(pose ;~(less gal gar pam prn) enty) :: :: ++enty:de-xml:html ++ enty :: entity - %+ ifix pad^mic + %+ ifix pam^mic ;~ pose =+ def=^+(ent (my:nl [%gt '>'] [%lt '<'] [%amp '&'] [%quot '"'] ~)) %+ sear ~(get by (~(uni by def) ent)) @@ -6443,7 +6448,7 @@ ;~(plug ;~(plug name attr) (cold ~ (star whit))) :: :: ++head:de-xml:html ++ head :: opening tag - (ifix [gal ban] ;~(plug name attr)) + (ifix [gal gar] ;~(plug name attr)) :: :: ++many:de-xml:html ++ many :: contents ;~(pfix (star comt) (star ;~(sfix ;~(pose apex chrd cdat) (star comt)))) @@ -6458,7 +6463,7 @@ ;~(pose ;~(plug ;~(sfix chx col) chx) chx) :: :: ++tail:de-xml:html ++ tail :: closing tag - (ifix [(jest ' |=(a/@ ((sand %tas) (crip (flop (trip a))))) - (;~(sfix (sear . sym) dot) [1^1 (flop (trip i.rax))]) + %- ;~ sfix + %+ sear + |=(a/@ ((sand %ta) (crip (flop (trip a))))) + (cook |=(a/tape (rap 3 ^-((list @) a))) (star aln)) + dot + == + [1^1 (flop (trip i.rax))] ?~ q.raf [~ [i.rax ~]] =+ `{ext/term {@ @} fyl/tape}`u.q.raf @@ -6573,7 +6583,7 @@ :: :: ++apat:de-purl:html ++ apat :: 2396 abs_path %+ cook deft - ;~(pfix net (more net smeg)) + ;~(pfix fas (more fas smeg)) :: :: ++aurf:de-purl:html ++ aurf :: 2396 with fragment %+ cook |~(a/purf a) @@ -6594,13 +6604,13 @@ [q.a [[p.a r.a] b]] :: ;~ plug - ;~(plug htts (punt ;~(sfix urt:ab vat)) thor) + ;~(plug htts (punt ;~(sfix urt:ab pat)) thor) ;~(plug ;~(pose apat (easy *pork)) yque) == :: :: ++htts:de-purl:html ++ htts :: scheme %+ sear ~(get by (malt `(list (pair term ?))`[http+| https+& ~])) - ;~(sfix scem ;~(plug col net net)) + ;~(sfix scem ;~(plug col fas fas)) :: :: ++cock:de-purl:html ++ cock :: cookie %+ most ;~(plug mic ace) @@ -6620,10 +6630,10 @@ (cook crip (star pquo)) :: :: ++pcar:de-purl:html ++ pcar :: 2396 path char - ;~(pose pure pesc psub col vat) + ;~(pose pure pesc psub col pat) :: :: ++pcok:de-purl:html ++ pcok :: cookie char - ;~(less bas mic com yel prn) + ;~(less bas mic com doq prn) :: :: ++pesc:de-purl:html ++ pesc :: 2396 escaped ;~(pfix cen mes) @@ -6632,24 +6642,24 @@ (cold ' ' (just '+')) :: :: ++pque:de-purl:html ++ pque :: 3986 query char - ;~(pose pcar net wut) + ;~(pose pcar fas wut) :: :: ++pquo:de-purl:html ++ pquo :: normal query char - ;~(pose pure pesc pold net wut col com) + ;~(pose pure pesc pold fas wut col com) :: :: ++pure:de-purl:html ++ pure :: 2396 unreserved - ;~(pose aln hep cab dot zap sig tar say lit rit) + ;~(pose aln hep cab dot zap sig tar soq pal par) :: :: ++psub:de-purl:html ++ psub :: 3986 sub-delims ;~ pose - zap bus pad say lit rit + zap buc pam soq pal par tar lus com mic tis == :: :: ++ptok:de-purl:html ++ ptok :: 2616 token ;~ pose - aln zap hax bus cen pad say tar lus - hep dot ket cab tec bar sig + aln zap hax buc cen pam soq tar lus + hep dot ket cab tic bar sig == :: :: ++scem:de-purl:html ++ scem :: 2396 scheme @@ -6663,7 +6673,7 @@ (cook crip (plus pcok)) :: :: ++tosk:de-purl:html ++ tosk :: 6265 quoted value - ;~(pose tock (ifix [yel yel] tock)) + ;~(pose tock (ifix [doq doq] tock)) :: :: ++toke:de-purl:html ++ toke :: 2616 token (cook crip (plus ptok)) @@ -6705,7 +6715,7 @@ :: proper query :: %+ more - ;~(pose pad mic) + ;~(pose pam mic) ;~(plug fque ;~(pose ;~(pfix tis fquu) (easy ''))) :: :: funky query @@ -8209,7 +8219,7 @@ :: ++ function |* [tag=@tas fun=@t rul=rule] - ;~(plug (cold tag (jest fun)) (ifix [lit rit] rul)) + ;~(plug (cold tag (jest fun)) (ifix [pal par] rul)) :: ++ shipname ;~(pfix sig fed:ag) @@ -9174,6 +9184,10 @@ |- ^- seed:able:jael =/ cub=acru:ames (pit:nu:crub:crypto 512 eny) =/ who=ship `@`fig:ex:cub + :: disallow 64-bit or smaller addresses + :: + ?. ?=(%pawn (clan:title who)) + $(eny +(eny)) ?: (~(has in stars) (^sein:title who)) [who 1 sec:ex:cub ~] $(eny +(eny)) diff --git a/pkg/arvo/ted/graph/create.hoon b/pkg/arvo/ted/graph/create.hoon index e0938fbc6..e0c544818 100644 --- a/pkg/arvo/ted/graph/create.hoon +++ b/pkg/arvo/ted/graph/create.hoon @@ -1,4 +1,9 @@ -/- spider, graph=graph-store, *metadata-store, *group, group-store +/- spider, + graph=graph-store, + *metadata-store, + *group, + group-store, + inv=invite-store /+ strandio, resource, graph-view => |% @@ -27,22 +32,25 @@ =+ !<([=action:graph-view ~] arg) ?> ?=(%create -.action) ;< =bowl:spider bind:m get-bowl:strandio +:: :: Add graph to graph-store :: ?. =(our.bowl entity.rid.action) (strand-fail:strandio %bad-request ~) =/ =update:graph - [%0 now.bowl %add-graph rid.action *graph:graph mark.action] + [%0 now.bowl %add-graph rid.action *graph:graph mark.action %.n] ;< ~ bind:m (poke-our %graph-store graph-update+!>(update)) ;< ~ bind:m (poke-our %graph-push-hook %push-hook-action !>([%add rid.action])) +:: :: Add group, if graph is unmanaged :: ;< group=resource bind:m (handle-group rid.action associated.action) =/ group-path=path (en-path:resource group) +:: :: Setup metadata :: =/ =metadata @@ -53,9 +61,30 @@ creator our.bowl module module.action == -=/ act=metadata-action +=/ =metadata-action [%add group-path graph+(en-path:resource rid.action) metadata] -;< ~ bind:m (poke-our %metadata-hook %metadata-action !>(act)) +;< ~ bind:m + (poke-our %metadata-hook %metadata-action !>(metadata-action)) ;< ~ bind:m (poke-our %metadata-hook %metadata-hook-action !>([%add-owned group-path])) -(pure:m !>(~)) +:: +:: Send invites +:: +?: ?=(%group -.associated.action) + (pure:m !>(~)) +?- -.policy.associated.action + %open (pure:m !>(~)) + %invite + =/ inv-action=action:inv + :^ %invites %graph (shaf %graph-uid eny.bowl) + ^- multi-invite:inv + :* our.bowl + %graph-push-hook + rid.action + pending.policy.associated.action + description.action + == + ;< ~ bind:m + (poke-our %invite-hook %invite-action !>(inv-action)) + (pure:m !>(~)) +== diff --git a/pkg/arvo/ted/graph/delete.hoon b/pkg/arvo/ted/graph/delete.hoon index 7e95d492b..1ffcdd97d 100644 --- a/pkg/arvo/ted/graph/delete.hoon +++ b/pkg/arvo/ted/graph/delete.hoon @@ -41,6 +41,15 @@ (poke-our %graph-store %graph-update !>([%0 now.bowl %remove-graph rid])) ;< ~ bind:m (poke-our %graph-push-hook %push-hook-action !>([%remove rid])) + ;< ~ bind:m + %+ poke-our %metadata-hook + metadata-hook-action+!>([%remove (en-path:resource rid)]) + ;< ~ bind:m + %+ poke-our %metadata-store + :- %metadata-action + !> :+ %remove + (en-path:resource rid) + [%graph (en-path:resource rid)] (pure:m ~) -- :: diff --git a/pkg/arvo/ted/graph/groupify.hoon b/pkg/arvo/ted/graph/groupify.hoon index 5a3f618fd..58a9ec4a9 100644 --- a/pkg/arvo/ted/graph/groupify.hoon +++ b/pkg/arvo/ted/graph/groupify.hoon @@ -67,5 +67,5 @@ %+ poke-our %metadata-store metadata-action+!>([%remove app-path graph+app-path]) ;< ~ bind:m - (poke-our %group-store %group-update !>([%remove-group rid.action])) + (poke-our %group-store %group-update !>([%remove-group rid.action ~])) (pure:m !>(~)) diff --git a/pkg/arvo/ted/invite/accepted-graph.hoon b/pkg/arvo/ted/invite/accepted-graph.hoon new file mode 100644 index 000000000..bb1227082 --- /dev/null +++ b/pkg/arvo/ted/invite/accepted-graph.hoon @@ -0,0 +1,28 @@ +/- spider, inv=invite-store, graph-view +/+ strandio +:: +=* strand strand:spider +=* fail strand-fail:strand +=* poke-our poke-our:strandio +=* flog-text flog-text:strandio +:: +^- thread:spider +|= arg=vase +=/ m (strand ,vase) +^- form:m +=+ !<([=update:inv ~] arg) +?. ?=(%accepted -.update) + (pure:m !>(~)) +;< =bowl:spider bind:m get-bowl:strandio +=* invite invite.update +?: =(our.bowl entity.resource.invite) + :: do not crash because that will kill the invitatory subscription + (pure:m !>(~)) +;< ~ bind:m + %+ poke-our %spider + =- spider-start+!>([`tid.bowl ~ %graph-join -]) + %+ slop + !> ^- action:graph-view + [%join resource.invite ship.invite] + !>(~) +(pure:m !>(~)) diff --git a/pkg/arvo/ted/ph/lib-hooks.hoon b/pkg/arvo/ted/ph/lib-hooks.hoon new file mode 100644 index 000000000..1f2aa5966 --- /dev/null +++ b/pkg/arvo/ted/ph/lib-hooks.hoon @@ -0,0 +1,65 @@ +/- spider +/+ *ph-io, *strandio +=> +|% +++ strand strand:spider +++ start-agents + |= =ship + =/ m (strand ,~) + ;< ~ bind:m (dojo ship "|start %graph-store") + ;< ~ bind:m (dojo ship "|start %graph-push-hook") + ;< ~ bind:m (dojo ship "|start %graph-pull-hook") + ;< ~ bind:m (dojo ship "|start %group-store") + ;< ~ bind:m (dojo ship "|start %group-push-hook") + ;< ~ bind:m (dojo ship "|start %group-pull-hook") + ;< ~ bind:m (dojo ship "|start %metadata-store") + ;< ~ bind:m (dojo ship "|start %metadata-hook") + ;< ~ bind:m (sleep `@dr`300) + (pure:m ~) +:: +++ make-link + |= [title=@t url=@t] + =/ m (strand ,~) + ;< ~ bind:m (dojo ~bud ":graph-store|add-post [~bud %test] ~[[%text '{(trip title)}'] [%url '{(trip url)}']]") + (pure:m ~) +-- + +^- thread:spider +|= vase +=/ m (strand ,vase) +;< az=tid:spider + bind:m start-azimuth +;< ~ bind:m (spawn az ~bud) +;< ~ bind:m (spawn az ~dev) +;< ~ bind:m (real-ship az ~bud) +;< ~ bind:m (real-ship az ~dev) +;< ~ bind:m (start-agents ~bud) +;< ~ bind:m (start-agents ~dev) +;< ~ bind:m (send-hi ~bud ~dev) +;< ~ bind:m (dojo ~bud "-graph-create [%create [~bud %test] 'test' '' `%graph-validator-link [%policy [%open ~ ~]] 'link']") +;< ~ bind:m (sleep ~s5) +;< ~ bind:m (dojo ~dev "-graph-join [%join [~bud %test] ~bud]") +;< ~ bind:m (sleep ~s5) +;< ~ bind:m (send-hi ~bud ~dev) +;< ~ bind:m (poke-our %aqua noun+!>([%pause-events ~[~dev]])) +;< ~ bind:m (make-link 'one' 'one') +;< ~ bind:m (make-link 'two' 'one') +;< ~ bind:m (make-link 'thre' 'one') +;< ~ bind:m (make-link 'four' 'one') +;< ~ bind:m (make-link 'five' 'one') +;< ~ bind:m (make-link 'six' 'one') +;< ~ bind:m (make-link 'seven' 'one') +;< ~ bind:m (sleep ~s40) +:: five unacked events is sufficent to cause a clog, and by extension a +:: %kick +;< ~ bind:m (poke-our %aqua noun+!>([%unpause-events ~[~dev]])) +;< ~ bind:m (sleep ~s10) +;< ~ bind:m (make-link 'eight' 'one') +;< ~ bind:m (make-link 'nine' 'one') +;< ~ bind:m (sleep ~s10) +;< ~ bind:m (dojo ~dev ":graph-pull-hook +dbug %bowl") +;< ~ bind:m (dojo ~dev ":graph-store +dbug") +;< ~ bind:m (dojo ~bud ":graph-push-hook +dbug %bowl") +;< ~ bind:m (dojo ~bud ":graph-store +dbug") +;< ~ bind:m end-azimuth +(pure:m *vase) diff --git a/pkg/arvo/tests/sys/vane/eyre.hoon b/pkg/arvo/tests/sys/vane/eyre.hoon index b5323038f..dadaafb99 100644 --- a/pkg/arvo/tests/sys/vane/eyre.hoon +++ b/pkg/arvo/tests/sys/vane/eyre.hoon @@ -1849,11 +1849,11 @@ ~ == ^= expected-moves - ~ ::NOTE tested elsewher + ~ ::NOTE tested elsewhere == :: user gets sent multiple subscription results :: - =/ max=@ud (dec clog-threshold:eyre-gate) + =/ max=@ud clog-threshold:eyre-gate =/ cur=@ud 0 |- =* loop-fact $ ?. =(cur max) @@ -1875,7 +1875,7 @@ loop-fact(cur +(cur)) :: the next subscription result should trigger a clog :: - =^ results eyre-gate + =^ results1 eyre-gate %: eyre-take eyre-gate now @@ -1889,40 +1889,58 @@ == ^= moves :~ :* duct=~[/http-get-open] - %give - %response - %continue - :- ~ - %- as-octt:mimes:html - """ - id: {((d-co:co 1) +(clog-threshold:eyre-gate))} - data: \{"id":1,"response":"quit"} - - - """ - complete=%.n - == - :* duct=~[/http-put-request] %pass - /channel/subscription/'0123456789abcdef'/'1'/~nul/two - %g %deal [~nul ~nul] %two %leave ~ - == - :* duct=~[/http-get-open] %give %response %continue :- ~ %- as-octt:mimes:html """ - id: {((d-co:co 1) clog-threshold:eyre-gate)} + id: {((d-co:co 1) +(clog-threshold:eyre-gate))} data: \{"json":[1],"id":1,"response":"diff"} """ complete=%.n == + :* duct=~[/http-put-request] %pass + /channel/subscription/'0123456789abcdef'/'1'/~nul/two + %g %deal [~nul ~nul] %two %leave ~ + == + :* duct=~[/http-get-open] + %give + %response + %continue + :- ~ + %- as-octt:mimes:html + """ + id: {((d-co:co 1) (add 2 clog-threshold:eyre-gate))} + data: \{"id":1,"response":"quit"} + + + """ + complete=%.n + == == == - results + :: subsequent subscription updates, which might have gotten sent out during + :: the same event in which a clog triggered, should be silently ignored + :: + =^ results2 eyre-gate + %: eyre-take + eyre-gate + now + scry=scry-provides-code + ^= take-args + :* wire=/channel/subscription/'0123456789abcdef'/'1'/~nul/two + duct=~[/http-put-request] + ^- (hypo sign:eyre-gate) + :- *type + [%g %unto %fact %json !>(`json`[%a [%n '1'] ~])] + == + ^= moves + ~ + == + (weld results1 results2) :: ++ test-born-sends-pending-cancels :: diff --git a/pkg/interface/package-lock.json b/pkg/interface/package-lock.json index 812ebc329..1adb54bcd 100644 --- a/pkg/interface/package-lock.json +++ b/pkg/interface/package-lock.json @@ -1585,22 +1585,6 @@ } } }, - "@react-dnd/asap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.0.tgz", - "integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ==" - }, - "@react-dnd/invariant": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", - "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" - }, - "@react-dnd/shallowequal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", - "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==", - "dev": true - }, "@styled-system/background": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@styled-system/background/-/background-5.1.2.tgz", @@ -1709,8 +1693,9 @@ "integrity": "sha512-3OPSdf9cejP/TSzWXuBaYbzLtAfBzQnc75SlPLkoPfwpxnv1Bvy9hiWngLY0WnKRR6lMOldnkYQCCuNWeDibYQ==" }, "@tlon/indigo-react": { - "version": "github:urbit/indigo-react#a9ad1e2ca3c318b7455ed942d288340400e2481d", - "from": "github:urbit/indigo-react#lf/1.2.9", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@tlon/indigo-react/-/indigo-react-1.2.13.tgz", + "integrity": "sha512-6qYLjVcGZtDjI+BqS2PRrfAh9mUCDtYwDOHuYuPyV87mdVRAhduBlQ/3tDVlTNWICF9DeAhozeClxalACs5Ipw==", "requires": { "@reach/menu-button": "^0.10.5", "react": "^16.13.1", @@ -1718,9 +1703,9 @@ }, "dependencies": { "tslib": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.2.tgz", - "integrity": "sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" } } }, @@ -2682,6 +2667,11 @@ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, + "big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -3909,21 +3899,6 @@ "randombytes": "^2.0.0" } }, - "dnd-core": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-11.1.3.tgz", - "integrity": "sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==", - "requires": { - "@react-dnd/asap": "^4.0.0", - "@react-dnd/invariant": "^2.0.0", - "redux": "^4.0.4" - } - }, - "dnd-multi-backend": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/dnd-multi-backend/-/dnd-multi-backend-6.0.0.tgz", - "integrity": "sha512-qfUO4V0IACs24xfE9m9OUnwIzoL+SWzSiFbKVIHE0pFddJeZ93BZOdHS1XEYr8X3HNh+CfnfjezXgOMgjvh74g==" - }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -4876,6 +4851,11 @@ } } }, + "file-saver": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz", + "integrity": "sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw==" + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -7872,53 +7852,6 @@ "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-6.0.1.tgz", "integrity": "sha512-rutEKVgvFhWcy/GeVA1hFbqrO89qLqgqdhUr7YhYgIzdyICdlRQv+ztuNvOFQMXrO0fLt0VkaYOdMdYdQgsSUA==" }, - "react-dnd": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-11.1.3.tgz", - "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", - "dev": true, - "requires": { - "@react-dnd/shallowequal": "^2.0.0", - "@types/hoist-non-react-statics": "^3.3.1", - "dnd-core": "^11.1.3", - "hoist-non-react-statics": "^3.3.0" - } - }, - "react-dnd-html5-backend": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz", - "integrity": "sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw==", - "requires": { - "dnd-core": "^11.1.3" - } - }, - "react-dnd-multi-backend": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/react-dnd-multi-backend/-/react-dnd-multi-backend-6.0.2.tgz", - "integrity": "sha512-SwpqRv0HkJYu244FbHf9NbvGzGy14Ir9wIAhm909uvOVaHgsOq6I1THMSWSgpwUI31J3Bo5uS19tuvGpVPjzZw==", - "requires": { - "dnd-multi-backend": "^6.0.0", - "prop-types": "^15.7.2", - "react-dnd-preview": "^6.0.2" - } - }, - "react-dnd-preview": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/react-dnd-preview/-/react-dnd-preview-6.0.2.tgz", - "integrity": "sha512-F2+uK4Be+q+7mZfNh9kaZols7wp1hX6G7UBTVaTpDsBpMhjFvY7/v7odxYSerSFBShh23MJl33a4XOVRFj1zoQ==", - "requires": { - "prop-types": "^15.7.2" - } - }, - "react-dnd-touch-backend": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/react-dnd-touch-backend/-/react-dnd-touch-backend-11.1.3.tgz", - "integrity": "sha512-8lz4fxfYwUuJ6Y2seQYwh8+OfwKcbBX0CIbz7AwXfBYz54Wg2nIDU6CP8Dyybt/Wyx4D3oXmTPEaOMB62uqJvQ==", - "requires": { - "@react-dnd/invariant": "^2.0.0", - "dnd-core": "^11.1.3" - } - }, "react-dom": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", @@ -8095,15 +8028,6 @@ "picomatch": "^2.2.1" } }, - "redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", - "requires": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" - } - }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -9446,11 +9370,6 @@ "xml-reader": "2.4.3" } }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - }, "synchronous-promise": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.13.tgz", diff --git a/pkg/interface/package.json b/pkg/interface/package.json index 619ccae0f..5786f7494 100644 --- a/pkg/interface/package.json +++ b/pkg/interface/package.json @@ -9,12 +9,14 @@ "@reach/menu-button": "^0.10.5", "@reach/tabs": "^0.10.5", "@tlon/indigo-light": "^1.0.3", - "@tlon/indigo-react": "urbit/indigo-react#lf/1.2.9", + "@tlon/indigo-react": "1.2.13", "@tlon/sigil-js": "^1.4.2", "aws-sdk": "^2.726.0", + "big-integer": "^1.6.48", "classnames": "^2.2.6", "codemirror": "^5.55.0", "css-loader": "^3.5.3", + "file-saver": "^2.0.2", "formik": "^2.1.4", "lodash": "^4.17.15", "markdown-to-jsx": "^6.11.4", @@ -26,9 +28,6 @@ "prop-types": "^15.7.2", "react": "^16.5.2", "react-codemirror2": "^6.0.1", - "react-dnd-html5-backend": "^11.1.3", - "react-dnd-multi-backend": "^6.0.2", - "react-dnd-touch-backend": "^11.1.3", "react-dom": "^16.8.6", "react-helmet": "^6.1.0", "react-markdown": "^4.3.1", @@ -73,7 +72,6 @@ "file-loader": "^6.0.0", "html-webpack-plugin": "^4.2.0", "moment-locales-webpack-plugin": "^1.2.0", - "react-dnd": "^11.1.3", "react-hot-loader": "^4.12.21", "sass": "^1.26.5", "sass-loader": "^8.0.2", diff --git a/pkg/interface/src/logic/api/global.ts b/pkg/interface/src/logic/api/global.ts index ac4cc8a50..5388259a2 100644 --- a/pkg/interface/src/logic/api/global.ts +++ b/pkg/interface/src/logic/api/global.ts @@ -9,9 +9,9 @@ import MetadataApi from './metadata'; import ContactsApi from './contacts'; import GroupsApi from './groups'; import LaunchApi from './launch'; -import PublishApi from './publish'; import GraphApi from './graph'; import S3Api from './s3'; +import {HarkApi} from './hark'; export default class GlobalApi extends BaseApi { chat = new ChatApi(this.ship, this.channel, this.store); @@ -21,10 +21,9 @@ export default class GlobalApi extends BaseApi { contacts = new ContactsApi(this.ship, this.channel, this.store); groups = new GroupsApi(this.ship, this.channel, this.store); launch = new LaunchApi(this.ship, this.channel, this.store); - publish = new PublishApi(this.ship, this.channel, this.store); s3 = new S3Api(this.ship, this.channel, this.store); graph = new GraphApi(this.ship, this.channel, this.store); - + hark = new HarkApi(this.ship, this.channel, this.store); constructor( public ship: Patp, diff --git a/pkg/interface/src/logic/api/graph.ts b/pkg/interface/src/logic/api/graph.ts index 98097016e..6f9cec4a2 100644 --- a/pkg/interface/src/logic/api/graph.ts +++ b/pkg/interface/src/logic/api/graph.ts @@ -3,13 +3,56 @@ import { StoreState } from '../store/type'; import { Patp, Path, PatpNoSig } from '~/types/noun'; import _ from 'lodash'; import {makeResource, resourceFromPath} from '../lib/group'; -import {GroupPolicy, Enc, Post} from '~/types'; -import { deSig } from '~/logic/lib/util'; +import {GroupPolicy, Enc, Post, NodeMap, Content} from '~/types'; +import { numToUd, unixToDa } from '~/logic/lib/util'; -export const createPost = (contents: Object[], parentIndex: string = '') => { +export const createBlankNodeWithChildPost = ( + parentIndex: string = '', + childIndex: string = '', + contents: Content[] +) => { + const date = unixToDa(Date.now()).toString(); + const nodeIndex = parentIndex + '/' + date; + + const childGraph = {}; + childGraph[childIndex] = { + post: { + author: `~${window.ship}`, + index: nodeIndex + '/' + childIndex, + 'time-sent': Date.now(), + contents, + hash: null, + signatures: [] + }, + children: { empty: null } + }; + + return { + post: { + author: `~${window.ship}`, + index: nodeIndex, + 'time-sent': Date.now(), + contents: [], + hash: null, + signatures: [] + }, + children: { + graph: childGraph + } + }; +}; + +export const createPost = ( + contents: Content[], + parentIndex: string = '', + childIndex:string = 'DATE_PLACEHOLDER' +) => { + if (childIndex === 'DATE_PLACEHOLDER') { + childIndex = unixToDa(Date.now()).toString(); + } return { author: `~${window.ship}`, - index: parentIndex + '/' + Date.now(), + index: parentIndex + '/' + childIndex, 'time-sent': Date.now(), contents, hash: null, @@ -17,6 +60,16 @@ export const createPost = (contents: Object[], parentIndex: string = '') => { }; }; +function moduleToMark(mod: string): string | undefined { + if(mod === 'link') { + return 'graph-validator-link'; + } + if(mod === 'publish') { + return 'graph-validator-publish'; + } + return undefined; +} + export default class GraphApi extends BaseApi { private storeAction(action: any): Promise { @@ -47,7 +100,8 @@ export default class GraphApi extends BaseApi { title, description, associated, - "module": mod + "module": mod, + mark: moduleToMark(mod) } }); } @@ -67,7 +121,8 @@ export default class GraphApi extends BaseApi { title, description, associated: { policy }, - "module": mod + "module": mod, + mark: moduleToMark(mod) } }); } @@ -138,8 +193,21 @@ export default class GraphApi extends BaseApi { }); } + addNode(ship: Patp, name: string, node: Object) { + let nodes = {}; + const resource = { ship, name }; + nodes[node.post.index] = node; + + return this.hookAction(ship, { + 'add-nodes': { + resource, + nodes + } + }); + } + addNodes(ship: Patp, name: string, nodes: Object) { - this.hookAction(ship, { + return this.hookAction(ship, { 'add-nodes': { resource: { ship, name }, nodes @@ -204,9 +272,10 @@ export default class GraphApi extends BaseApi { } getNode(ship: string, resource: string, index: string) { + const idx = index.split('/').map(numToUd).join('/'); return this.scry( 'graph-store', - `/node/${ship}/${resource}/${index}` + `/node/${ship}/${resource}${idx}` ).then((node) => { this.store.handleEvent({ data: node diff --git a/pkg/interface/src/logic/api/hark.ts b/pkg/interface/src/logic/api/hark.ts new file mode 100644 index 000000000..8f33fc480 --- /dev/null +++ b/pkg/interface/src/logic/api/hark.ts @@ -0,0 +1,180 @@ +import BaseApi from "./base"; +import { StoreState } from "../store/type"; +import { dateToDa, decToUd } from "../lib/util"; +import {NotifIndex, IndexedNotification} from "~/types"; +import { BigInteger } from 'big-integer'; +import {getParentIndex} from "../lib/notification"; + +export class HarkApi extends BaseApi { + private harkAction(action: any): Promise { + return this.action("hark-store", "hark-action", action); + } + + private graphHookAction(action: any) { + return this.action("hark-graph-hook", "hark-graph-hook-action", action); + } + + private groupHookAction(action: any) { + return this.action("hark-group-hook", "hark-group-hook-action", action); + } + + private chatHookAction(action: any) { + return this.action("hark-chat-hook", "hark-chat-hook-action", action); + } + + private actOnNotification(frond: string, intTime: BigInteger, index: NotifIndex) { + const time = decToUd(intTime.toString()); + return this.harkAction({ + [frond]: { + time, + index + } + }); + } + + async setMentions(mentions: boolean) { + await this.graphHookAction({ + 'set-mentions': mentions + }); + return this.chatHookAction({ + 'set-mentions': mentions + }); + } + + setWatchOnSelf(watchSelf: boolean) { + return this.graphHookAction({ + 'set-watch-on-self': watchSelf + }); + } + + setDoNotDisturb(dnd: boolean) { + return this.harkAction({ + 'set-dnd': dnd + }); + } + + archive(time: BigInteger, index: NotifIndex) { + return this.actOnNotification('archive', time, index); + } + + read(time: BigInteger, index: NotifIndex) { + return this.actOnNotification('read', time, index); + } + + readIndex(index: NotifIndex) { + return this.harkAction({ + 'read-index': index + }); + } + + unread(time: BigInteger, index: NotifIndex) { + return this.actOnNotification('unread', time, index); + } + + seen() { + return this.harkAction({ seen: null }); + } + + mute(notif: IndexedNotification) { + if('graph' in notif.index && 'graph' in notif.notification.contents) { + const { index } = notif; + const parentIndex = getParentIndex(index.graph, notif.notification.contents.graph) + if(!parentIndex) { + return Promise.resolve(); + } + return this.ignoreGraph(index.graph.graph, parentIndex); + } + if('group' in notif.index) { + const { group } = notif.index.group; + return this.ignoreGroup(group); + } + if('chat' in notif.index) { + return this.ignoreChat(notif.index.chat.chat); + } + return Promise.resolve(); + } + + unmute(notif: IndexedNotification) { + if('graph' in notif.index && 'graph' in notif.notification.contents) { + const { index } = notif; + const parentIndex = getParentIndex(index.graph, notif.notification.contents.graph) + if(!parentIndex) { + return Promise.resolve(); + } + return this.listenGraph(index.graph.graph, parentIndex); + } + if('group' in notif.index) { + return this.listenGroup(notif.index.group.group); + } + if('chat' in notif.index) { + return this.listenChat(notif.index.chat.chat); + } + return Promise.resolve(); + } + + ignoreGroup(group: string) { + return this.groupHookAction({ + ignore: group + }) + } + + ignoreGraph(graph: string, index: string) { + return this.graphHookAction({ + ignore: { + graph, + index + } + }) + } + + ignoreChat(chat: string) { + return this.chatHookAction({ + ignore: chat + }); + } + + + listenGroup(group: string) { + return this.groupHookAction({ + listen: group + }) + } + + listenGraph(graph: string, index: string) { + return this.graphHookAction({ + listen: { + graph, + index + } + }) + } + + listenChat(chat: string) { + return this.chatHookAction({ + listen: chat + }); + } + + getMore(archive = false) { + const offset = this.store.state[ + archive ? 'archivedNotifications' : 'notifications' + ].size; + const count = 3; + return this.getSubset(offset,count, archive); + } + + async getSubset(offset:number, count:number, isArchive: boolean) { + const where = isArchive ? 'archive' : 'inbox'; + const data = await this.scry("hark-store", `/recent/${where}/${offset}/${count}`); + this.store.handleEvent({ data }); + } + + async getTimeSubset(start?: Date, end?: Date) { + const s = start ? dateToDa(start) : "-"; + const e = end ? dateToDa(end) : "-"; + const result = await this.scry("hark-hook", `/recent/${s}/${e}`); + this.store.handleEvent({ + data: result, + }); + } +} diff --git a/pkg/interface/src/logic/api/invite.ts b/pkg/interface/src/logic/api/invite.ts index 432a266bc..89a730768 100644 --- a/pkg/interface/src/logic/api/invite.ts +++ b/pkg/interface/src/logic/api/invite.ts @@ -3,25 +3,25 @@ import { StoreState } from "../store/type"; import { Serial, Path } from "~/types/noun"; export default class InviteApi extends BaseApi { - accept(app: Path, uid: Serial) { + accept(app: string, uid: Serial) { return this.inviteAction({ accept: { - path: app, + term: app, uid } }); } - decline(app: Path, uid: Serial) { + decline(app: string, uid: Serial) { return this.inviteAction({ decline: { - path: app, + term: app, uid } }); } private inviteAction(action) { - return this.action('invite-store', 'json', action); + return this.action('invite-store', 'invite-action', action); } } diff --git a/pkg/interface/src/logic/api/launch.ts b/pkg/interface/src/logic/api/launch.ts index 30661df83..bbe49db73 100644 --- a/pkg/interface/src/logic/api/launch.ts +++ b/pkg/interface/src/logic/api/launch.ts @@ -1,9 +1,7 @@ import BaseApi from './base'; import { StoreState } from '../store/type'; - export default class LaunchApi extends BaseApi { - add(name: string, tile = { basic : { title: '', linkedUrl: '', iconUrl: '' }}) { return this.launchAction({ add: { name, tile } }); } @@ -12,10 +10,6 @@ export default class LaunchApi extends BaseApi { return this.launchAction({ remove: name }); } - changeOrder(orderedTiles: string[] = []) { - return this.launchAction({ 'change-order': orderedTiles }); - } - changeFirstTime(firstTime = true) { return this.launchAction({ 'change-first-time': firstTime }); } @@ -31,6 +25,5 @@ export default class LaunchApi extends BaseApi { private launchAction(data) { return this.action('launch', 'launch-action', data); } - } diff --git a/pkg/interface/src/logic/api/publish.ts b/pkg/interface/src/logic/api/publish.ts deleted file mode 100644 index 27d4bfdad..000000000 --- a/pkg/interface/src/logic/api/publish.ts +++ /dev/null @@ -1,224 +0,0 @@ -import BaseApi from './base'; - -import { PublishResponse } from '~/types/publish-response'; -import { PatpNoSig, Path } from '~/types/noun'; -import { BookId, NoteId } from '~/types/publish-update'; - -export default class PublishApi extends BaseApi { - handleEvent(data: PublishResponse) { - this.store.handleEvent({ data: { 'publish-response' : data } }); - } - - fetchNotebooks() { - return fetch('/publish-view/notebooks.json') - .then(response => response.json()) - .then((json) => { - this.handleEvent({ - type: 'notebooks', - data: json - }); - }); - } - - fetchNotebook(host: PatpNoSig, book: BookId) { - return fetch(`/publish-view/${host}/${book}.json`) - .then(response => response.json()) - .then((json) => { - this.handleEvent({ - type: 'notebook', - data: json, - host: host, - notebook: book - }); - }); - } - - fetchNote(host: PatpNoSig, book: BookId, note: NoteId) { - return fetch(`/publish-view/${host}/${book}/${note}.json`) - .then(response => response.json()) - .then((json) => { - this.handleEvent({ - type: 'note', - data: json, - host: host, - notebook: book, - note: note - }); - }); - } - - fetchNotesPage(host: PatpNoSig, book: BookId, start: number, length: number) { - return fetch(`/publish-view/notes/${host}/${book}/${start}/${length}.json`) - .then(response => response.json()) - .then((json) => { - this.handleEvent({ - type: 'notes-page', - data: json, - host: host, - notebook: book, - startIndex: start, - length: length - }); - }); - } - - fetchCommentsPage(host: PatpNoSig, book: BookId, note: NoteId, start: number, length: number) { - return fetch(`/publish-view/comments/${host}/${book}/${note}/${start}/${length}.json`) - .then(response => response.json()) - .then((json) => { - this.handleEvent({ - type: 'comments-page', - data: json, - host: host, - notebook: book, - note: note, - startIndex: start, - length: length - }); - }); - } - - subscribeNotebook(who: PatpNoSig, book: BookId) { - return this.publishAction({ - subscribe: { - who, - book - } - }); - } - - unsubscribeNotebook(who: PatpNoSig, book: BookId) { - return this.publishAction({ - unsubscribe: { - who, - book - } - }); - } - - publishAction(act: any) { - return this.action('publish', 'publish-action', act); - } - - groupify(bookId: string, group: Path | null) { - return this.publishAction({ - groupify: { - book: bookId, - target: group, - inclusive: false - } - }); - } - - - newBook(bookId: string, title: string, description: string, group?: Path) { - const groupInfo = group ? { 'group-path': group, - invitees: [], - 'use-preexisting': true, - 'make-managed': true - } : { - 'group-path': `/ship/~${window.ship}/${bookId}`, - invitees: [], - 'use-preexisting': false, - 'make-managed': false - }; - return this.publishAction({ - "new-book": { - book: bookId, - title: title, - about: description, - coms: true, - group: groupInfo - } - }); - } - - editBook(bookId: string, title: string, description: string, coms: boolean) { - return this.publishAction({ - "edit-book": { - book: bookId, - title: title, - about: description, - coms, - group: null - } - }); - } - - delBook(book: string) { - return this.publishAction({ - "del-book": { - book - } - }); - } - - newNote(who: PatpNoSig, book: string, note: string, title: string, body: string) { - return this.publishAction({ - 'new-note': { - who, - book, - note, - title, - body - } - }); - } - - editNote(who: PatpNoSig, book: string, note: string, title: string, body: string) { - return this.publishAction({ - 'edit-note': { - who, - book, - note, - title, - body - } - }); - } - - delNote(who: PatpNoSig, book: string, note: string) { - return this.publishAction({ - 'del-note': { - who, - book, - note - } - }); - } - - readNote(who: PatpNoSig, book: string, note: string) { - return this.publishAction({ - read: { - who, - book, - note - } - }); - } - - updateComment(who: PatpNoSig, book: string, note: string, comment: Path, body: string) { - return this.publishAction({ - 'edit-comment': { - who, - book, - note, - comment, - body - } - }); - } - - deleteComment(who: PatpNoSig, book: string, note: string, comment: Path ) { - return this.publishAction({ - "del-comment": { - who, - book, - note, - comment - }, - }); - } - -} - diff --git a/pkg/interface/src/logic/lib/BigIntOrderedMap.ts b/pkg/interface/src/logic/lib/BigIntOrderedMap.ts new file mode 100644 index 000000000..cf7883d97 --- /dev/null +++ b/pkg/interface/src/logic/lib/BigIntOrderedMap.ts @@ -0,0 +1,197 @@ +import bigInt, { BigInteger } from "big-integer"; + +interface NonemptyNode { + n: [BigInteger, V]; + l: MapNode; + r: MapNode; +} + +type MapNode = NonemptyNode | null; + +/** + * An implementation of ordered maps for JS + * Plagiarised wholesale from sys/zuse + */ +export class BigIntOrderedMap implements Iterable<[BigInteger, V]> { + private root: MapNode = null; + size: number = 0; + + constructor(initial: [BigInteger, V][] = []) { + initial.forEach(([key, val]) => { + this.set(key, val); + }); + } + + /** + * Retrieve an value for a key + */ + get(key: BigInteger): V | null { + const inner = (node: MapNode) => { + if (!node) { + return node; + } + const [k, v] = node.n; + if (key.eq(k)) { + return v; + } + if (key.gt(k)) { + return inner(node.l); + } else { + return inner(node.r); + } + }; + + return inner(this.root); + } + + /** + * Put an item by a key + */ + set(key: BigInteger, value: V): void { + + const inner = (node: MapNode) => { + if (!node) { + return { + n: [key, value], + l: null, + r: null, + }; + } + const [k] = node.n; + if (key.eq(k)) { + this.size--; + return { + ...node, + n: [k, value], + }; + } + if (key.gt(k)) { + const l = inner(node.l); + if (!l) { + throw new Error("invariant violation"); + } + return { + ...node, + l, + }; + } + const r = inner(node.r); + if (!r) { + throw new Error("invariant violation"); + } + + return { ...node, r }; + }; + this.size++; + this.root = inner(this.root); + } + + /** + * Remove all entries + */ + clear() { + this.root = null; + } + + /** + * Predicate testing if map contains key + */ + has(key: BigInteger): boolean { + const inner = (node: MapNode) => { + if (!node) { + return false; + } + const [k] = node.n; + + if (k.eq(key)) { + return true; + } + if (key.gt(k)) { + return inner(node.l); + } + return inner(node.r); + }; + return inner(this.root); + } + + /** + * Remove value associated with key, returning whether that key + * existed in the first place + */ + delete(key: BigInteger) { + const inner = (node: MapNode): [boolean, MapNode] => { + if (!node) { + return [false, null]; + } + const [k] = node.n; + if (k.eq(key)) { + return [true, this.nip(node)]; + } + if (key.gt(k)) { + const [bool, l] = inner(node.l); + return [ + bool, + { + ...node, + l, + }, + ]; + } + + const [bool, r] = inner(node.r); + return [ + bool, + { + ...node, + r, + }, + ]; + }; + const [ret, newRoot] = inner(this.root); + if(ret) { + this.size--; + } + this.root = newRoot; + return ret; + } + + private nip(nod: NonemptyNode): MapNode { + const inner = (node: NonemptyNode) => { + if (!node.l) { + return node.r; + } + if (!node.r) { + return node.l; + } + return { + ...node.l, + r: inner(node.r), + }; + }; + return inner(nod); + } + + [Symbol.iterator](): IterableIterator<[BigInteger, V]> { + let result: [BigInteger, V][] = []; + const inner = (node: MapNode) => { + if (!node) { + return; + } + inner(node.l); + result.push(node.n); + inner(node.r); + }; + inner(this.root); + + let idx = 0; + return { + [Symbol.iterator]: this[Symbol.iterator], + next: (): IteratorResult<[BigInteger, V]> => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + }, + }; + } +} diff --git a/pkg/interface/src/logic/lib/OrderedMap.ts b/pkg/interface/src/logic/lib/OrderedMap.ts index a640c2906..d66346ff6 100644 --- a/pkg/interface/src/logic/lib/OrderedMap.ts +++ b/pkg/interface/src/logic/lib/OrderedMap.ts @@ -6,7 +6,6 @@ export class OrderedMap extends Map const sorted = Array.from(super[Symbol.iterator]()).sort( ([a], [b]) => b - a ); - let index = 0; return { [Symbol.iterator]: this[Symbol.iterator], diff --git a/pkg/interface/src/logic/lib/bel.js b/pkg/interface/src/logic/lib/bel.js new file mode 100644 index 000000000..77ee14507 --- /dev/null +++ b/pkg/interface/src/logic/lib/bel.js @@ -0,0 +1 @@ +export default new Audio('data:@file/ogg;base64,T2dnUwACAAAAAAAAAAAu9RJ+AAAAAO+u/l4BHgF2b3JiaXMAAAAAAUAfAAAAAAAAYG0AAAAAAACZAU9nZ1MAAAAAAAAAAAAALvUSfgEAAACXEgK4Czv///////////+1A3ZvcmJpcysAAABYaXBoLk9yZyBsaWJWb3JiaXMgSSAyMDEyMDIwMyAoT21uaXByZXNlbnQpAAAAAAEFdm9yYmlzEkJDVgEAAAEADFIUISUZU0pjCJVSUikFHWNQW0cdY9Q5RiFkEFOISRmle08qlVhKyBFSWClFHVNMU0mVUpYpRR1jFFNIIVPWMWWhcxRLhkkJJWxNrnQWS+iZY5YxRh1jzlpKnWPWMUUdY1JSSaFzGDpmJWQUOkbF6GJ8MDqVokIovsfeUukthYpbir3XGlPrLYQYS2nBCGFz7bXV3EpqxRhjjDHGxeJTKILQkFUAAAEAAEAEAUJDVgEACgAAwlAMRVGA0JBVAEAGAIAAFEVxFMdxHEeSJMsCQkNWAQBAAAACAAAojuEokiNJkmRZlmVZlqZ5lqi5qi/7ri7rru3qug6EhqwEAMgAABiGIYfeScyQU5BJJilVzDkIofUOOeUUZNJSxphijFHOkFMMMQUxhtAphRDUTjmlDCIIQ0idZM4gSz3o4GLnOBAasiIAiAIAAIxBjCHGkHMMSgYhco5JyCBEzjkpnZRMSiittJZJCS2V1iLnnJROSialtBZSy6SU1kIrBQAABDgAAARYCIWGrAgAogAAEIOQUkgpxJRiTjGHlFKOKceQUsw5xZhyjDHoIFTMMcgchEgpxRhzTjnmIGQMKuYchAwyAQAAAQ4AAAEWQqEhKwKAOAEAgyRpmqVpomhpmih6pqiqoiiqquV5pumZpqp6oqmqpqq6rqmqrmx5nml6pqiqnimqqqmqrmuqquuKqmrLpqvatumqtuzKsm67sqzbnqrKtqm6sm6qrm27smzrrizbuuR5quqZput6pum6quvasuq6su2ZpuuKqivbpuvKsuvKtq3Ksq5rpum6oqvarqm6su3Krm27sqz7puvqturKuq7Ksu7btq77sq0Lu+i6tq7Krq6rsqzrsi3rtmzbQsnzVNUzTdf1TNN1Vde1bdV1bVszTdc1XVeWRdV1ZdWVdV11ZVv3TNN1TVeVZdNVZVmVZd12ZVeXRde1bVWWfV11ZV+Xbd33ZVnXfdN1dVuVZdtXZVn3ZV33hVm3fd1TVVs3XVfXTdfVfVvXfWG2bd8XXVfXVdnWhVWWdd/WfWWYdZ0wuq6uq7bs66os676u68Yw67owrLpt/K6tC8Or68ax676u3L6Patu+8Oq2Mby6bhy7sBu/7fvGsamqbZuuq+umK+u6bOu+b+u6cYyuq+uqLPu66sq+b+u68Ou+Lwyj6+q6Ksu6sNqyr8u6Lgy7rhvDatvC7tq6cMyyLgy37yvHrwtD1baF4dV1o6vbxm8Lw9I3dr4AAIABBwCAABPKQKEhKwKAOAEABiEIFWMQKsYghBBSCiGkVDEGIWMOSsYclBBKSSGU0irGIGSOScgckxBKaKmU0EoopaVQSkuhlNZSai2m1FoMobQUSmmtlNJaaim21FJsFWMQMuekZI5JKKW0VkppKXNMSsagpA5CKqWk0kpJrWXOScmgo9I5SKmk0lJJqbVQSmuhlNZKSrGl0kptrcUaSmktpNJaSam11FJtrbVaI8YgZIxByZyTUkpJqZTSWuaclA46KpmDkkopqZWSUqyYk9JBKCWDjEpJpbWSSiuhlNZKSrGFUlprrdWYUks1lJJaSanFUEprrbUaUys1hVBSC6W0FkpprbVWa2ottlBCa6GkFksqMbUWY22txRhKaa2kElspqcUWW42ttVhTSzWWkmJsrdXYSi051lprSi3W0lKMrbWYW0y5xVhrDSW0FkpprZTSWkqtxdZaraGU1koqsZWSWmyt1dhajDWU0mIpKbWQSmyttVhbbDWmlmJssdVYUosxxlhzS7XVlFqLrbVYSys1xhhrbjXlUgAAwIADAECACWWg0JCVAEAUAABgDGOMQWgUcsw5KY1SzjknJXMOQggpZc5BCCGlzjkIpbTUOQehlJRCKSmlFFsoJaXWWiwAAKDAAQAgwAZNicUBCg1ZCQBEAQAgxijFGITGIKUYg9AYoxRjECqlGHMOQqUUY85ByBhzzkEpGWPOQSclhBBCKaWEEEIopZQCAAAKHAAAAmzQlFgcoNCQFQFAFAAAYAxiDDGGIHRSOikRhExKJ6WREloLKWWWSoolxsxaia3E2EgJrYXWMmslxtJiRq3EWGIqAADswAEA7MBCKDRkJQCQBwBAGKMUY845ZxBizDkIITQIMeYchBAqxpxzDkIIFWPOOQchhM455yCEEELnnHMQQgihgxBCCKWU0kEIIYRSSukghBBCKaV0EEIIoZRSCgAAKnAAAAiwUWRzgpGgQkNWAgB5AACAMUo5JyWlRinGIKQUW6MUYxBSaq1iDEJKrcVYMQYhpdZi7CCk1FqMtXYQUmotxlpDSq3FWGvOIaXWYqw119RajLXm3HtqLcZac865AADcBQcAsAMbRTYnGAkqNGQlAJAHAEAgpBRjjDmHlGKMMeecQ0oxxphzzinGGHPOOecUY4w555xzjDHnnHPOOcaYc84555xzzjnnoIOQOeecc9BB6JxzzjkIIXTOOecchBAKAAAqcAAACLBRZHOCkaBCQ1YCAOEAAIAxlFJKKaWUUkqoo5RSSimllFICIaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKZVSSimllFJKKaWUUkoppQAg3woHAP8HG2dYSTorHA0uNGQlABAOAAAYwxiEjDknJaWGMQildE5KSSU1jEEopXMSUkopg9BaaqWk0lJKGYSUYgshlZRaCqW0VmspqbWUUigpxRpLSqml1jLnJKSSWkuttpg5B6Wk1lpqrcUQQkqxtdZSa7F1UlJJrbXWWm0tpJRaay3G1mJsJaWWWmupxdZaTKm1FltLLcbWYkutxdhiizHGGgsA4G5wAIBIsHGGlaSzwtHgQkNWAgAhAQAEMko555yDEEIIIVKKMeeggxBCCCFESjHmnIMQQgghhIwx5yCEEEIIoZSQMeYchBBCCCGEUjrnIIRQSgmllFJK5xyEEEIIpZRSSgkhhBBCKKWUUkopIYQQSimllFJKKSWEEEIopZRSSimlhBBCKKWUUkoppZQQQiillFJKKaWUEkIIoZRSSimllFJCCKWUUkoppZRSSighhFJKKaWUUkoJJZRSSimllFJKKSGUUkoppZRSSimlAACAAwcAgAAj6CSjyiJsNOHCAxAAAAACAAJMAIEBgoJRCAKEEQgAAAAAAAgA+AAASAqAiIho5gwOEBIUFhgaHB4gIiQAAAAAAAAAAAAAAAAET2dnUwAE1RQAAAAAAAAu9RJ+AgAAAI+1UkUWbC8oJiQmKTc/RUVKWVRZVFZSUlJUV7qmd+oLx6QAgM0PiQSIMgmD9wDA8XvSzu5GNsva2WY+G85HV47eGBjur0ytj7Wzzewi2GBPz+5b5X5VkUKKy+P8uLzGfVyHdViHddimbdqm+vy4btM2bZ807djY2NjYmGmapmlWldmyNVsAAKbnXqjLAQBgrioAKJAAb4YBnDhIAAC27/UAAAAA45QIAAC7yTUBAADiQvsHAQAAot2slRd+/38AgHMlAEjBmx0AbNebLgAAgELltBYAAKCevTMAAMApA6ZROkjlAADw70oAkIIW6jMGALj7mNICAAC4yb6wAAAA5AL8fgcApk062Be+/wAA/AYAAgwQThMFAACArWpvCQAAdgKupkwAjRoAps1ukZcDAMAtAEAABjMCALC6GAAAgGj+odwAAEAB+7LvDnsP2ACWzMqoP/z7/wWADgBjwHY/xAAAAMy+IgAANBy/qbrb7Pbss8JZflyWAZJLw6WXAQAwDBDkAkwOAwBQfkkAAADcl8vVBAAAmA8+jGyL2BYT0nbND21ideV3xyy/U4qXlgCSSeNKfvjxNQHAMMAMKiBsbroBAABqor8AAAA6aM89+Rq6bvnk8LNKyvW8jyhPT0aIqTiefOpxfN3z2tGPswCGCW+WuQAAVJUF+uoAADx8dxcAAMBXAMBZqNm60vW9d44pypUD2Tl6luUkHdG5J5lxL0aFvMpY9y7OZ7Kj0NP2j2okAQCKCd8aEhwAAAOrCubTAADuuhZTAACwBktTUYYsypUTa++md34yaa8b31WXw4LZ/dB8ts9kOjOBgcl+OxzDxOtjXdfTAQB2C59ZJvj+zwcgKg5g8281AADAO8mGdLGzJy8kGD3ERJHSb8+KRreqsOe5iOA9+xk5RWYymr8t9fFcQ7UYPsf2CXO954oPXuRGAHoJPwokOACABBB9GJcCcDgMkr9TdStxcpHkOhDXOM40AADwtFHUzvluekfz0aP9mJ3KRw3ySu6e3k716lNJD845W/XCUnx96lspKQF7uni6YS5qaskPgwAAbkmqK5Xg958CMAAAlRyw848OAABGZmJHO2stuZprN5F4lw9/TAzNcykrrzAGQKT90Hzs9r7xON7h+h6Zh6owHipmsZi9HkcWrez9yFa25VxKjKcAcgnfCiQ4AIAK4PvQVQCcdOjsxOnO6qfsJ3fjALg3jw8MAAA4+pwLvc++cP6Da+BtgBK2Vchno/edw7oW9qfD6fCyfroxFvJA1J66eKe6X3caZA80fZoqIQBiCluUZIK/vwYgxgAIxWABAACzX87PD/e+ypZoZFzUgnT++Vfp0fDw+dEiJHzSHi4Jx9zOop6xOOLsMJv7o2RE6rgPC7QJCbg+iH2+j5OvYnTfZwBiieULScgAAGICCMAMAJTm0o7SZPPNrK4DMVjQnAAAoNazHL/ohsVDDnj1B1OiRQleU7ja3e2WOJqRCOfRlPtCOd1Xx4golDIpbZ458jXWa69PzEdWAl6L5caU4PODAKhVnoBdv4oBAAAxjs0+Ot/dzjg+fzV8Ll86PhGvL0dScur4fEpmFL7LtyA4Nl/lyJPLSxTD6GB2yR6n0xYDZ/Ki8AelZfcaMgBeiuWCJAzH3QEgRh/Ax9sXACBA5nuEprLWUgjNyZV1K0F59+b2ekLV6ygkgbeuJuF2mIlXES5VwEoYIydHWAcdfNrynQPbVs45Vnz0W5H4NsEAXorpzpTguRsArDEAQsVfDQAAai1bx861KN9Kd+gh5gcxYnuummTspfSig6uKfBD7ktk84S407NtlEEiIwPnIFpc0c1mn6l8NIwrqmFZHTOQGAGKK9H2ZQX8AgOgHABonCQAIoSiMDtY3DcIRbnuH6zxUxkQwrhJ2Fpywr6ZfxvDqKyW58VRo40fXz5/cpf7H3YRUgr9LRT8pNxJaVHecnCt+ZV2tAWJK8dUqwVUdACVGkCL93e/IyMrIukLnyg3MMbZ+9/OKc/Z7JuYqlQlMVOODRxW/vKQqdZPbQui0ML9ZSJo33YhFgCY5BjIkne70UjNULgVNfirfm7+RSw=='); diff --git a/pkg/interface/src/logic/lib/default-apps.js b/pkg/interface/src/logic/lib/default-apps.js index 4fcbe3733..c9e1708fb 100644 --- a/pkg/interface/src/logic/lib/default-apps.js +++ b/pkg/interface/src/logic/lib/default-apps.js @@ -1,3 +1,3 @@ -const defaultApps = ['chat', 'dojo', 'groups', 'link', 'publish']; +const defaultApps = ['chat', 'term', 'groups', 'link', 'publish']; export default defaultApps; diff --git a/pkg/interface/src/logic/lib/graph.ts b/pkg/interface/src/logic/lib/graph.ts new file mode 100644 index 000000000..b17848ded --- /dev/null +++ b/pkg/interface/src/logic/lib/graph.ts @@ -0,0 +1,24 @@ +import { Content } from "~/types"; +import urbitOb from "urbit-ob"; + +export function scanForMentions(text: string) { + const regex = /~([a-z]|-)+/g; + let result: Content[] = []; + let match: RegExpExecArray | null; + let lastPos = 0; + while ((match = regex.exec(text)) !== null) { + const newPos = match.index + match[0].length; + if (urbitOb.isValidPatp(match[0])) { + if (match.index !== lastPos) { + result.push({ text: text.slice(lastPos, match.index) }); + } + result.push({ mention: match[0] }); + } + lastPos = newPos; + } + const remainder = text.slice(lastPos, text.length); + if (remainder) { + result.push({ text: remainder }); + } + return result; +} diff --git a/pkg/interface/src/logic/lib/group.ts b/pkg/interface/src/logic/lib/group.ts index bd4939c2f..7d554cc1b 100644 --- a/pkg/interface/src/logic/lib/group.ts +++ b/pkg/interface/src/logic/lib/group.ts @@ -4,7 +4,7 @@ import { PatpNoSig, Path } from '~/types/noun'; export function roleForShip(group: Group, ship: PatpNoSig): RoleTags | undefined { return roleTags.reduce((currRole, role) => { - const roleShips = group.tags.role[role]; + const roleShips = group?.tags?.role?.[role]; return roleShips && roleShips.has(ship) ? role : currRole; }, undefined as RoleTags | undefined); } diff --git a/pkg/interface/src/logic/lib/notification.ts b/pkg/interface/src/logic/lib/notification.ts new file mode 100644 index 000000000..87288d83d --- /dev/null +++ b/pkg/interface/src/logic/lib/notification.ts @@ -0,0 +1,21 @@ +import { GraphNotifIndex, GraphNotificationContents } from "~/types"; + +export function getParentIndex( + idx: GraphNotifIndex, + contents: GraphNotificationContents +) { + const origIndex = contents[0].index.slice(1).split("/"); + const ret = (i: string[]) => `/${i.join("/")}`; + switch (idx.description) { + case "link": + return "/"; + case "comment": + return ret(origIndex.slice(0, 1)); + case "note": + return "/"; + case "mention": + return undefined; + default: + return undefined; + } +} diff --git a/pkg/interface/src/logic/lib/omnibox.js b/pkg/interface/src/logic/lib/omnibox.js index 3c3de5dce..1bc38a4e2 100644 --- a/pkg/interface/src/logic/lib/omnibox.js +++ b/pkg/interface/src/logic/lib/omnibox.js @@ -54,7 +54,8 @@ const appIndex = function (apps) { const otherIndex = function() { const other = []; - other.push(result('Home', '/~landscape/home', 'home', null)); + other.push(result('DMs + Drafts', '/~landscape/home', 'home', null)); + other.push(result('Notifications', '/~notifications', 'inbox', null)); other.push(result('Profile and Settings', '/~profile/identity', 'profile', null)); other.push(result('Log Out', '/~/logout', 'logout', null)); diff --git a/pkg/interface/src/logic/lib/post.ts b/pkg/interface/src/logic/lib/post.ts new file mode 100644 index 000000000..1a311de55 --- /dev/null +++ b/pkg/interface/src/logic/lib/post.ts @@ -0,0 +1,18 @@ +import { Post, GraphNode } from "~/types"; + +export const buntPost = (): Post => ({ + author: '', + contents: [], + hash: null, + index: '', + signatures: [], + 'time-sent': 0 +}); + +export function makeNodeMap(posts: Post[]): Record { + let nodes = {}; + posts.forEach((p) => { + nodes[p.index] = { children: { empty: null }, post: p }; + }); + return nodes; +} diff --git a/pkg/interface/src/logic/lib/publish.ts b/pkg/interface/src/logic/lib/publish.ts new file mode 100644 index 000000000..8e44e423a --- /dev/null +++ b/pkg/interface/src/logic/lib/publish.ts @@ -0,0 +1,118 @@ +import { Post, GraphNode, TextContent, Graph, NodeMap } from "~/types"; +import { buntPost } from '~/logic/lib/post'; +import { unixToDa } from "~/logic/lib/util"; +import {BigIntOrderedMap} from "./BigIntOrderedMap"; +import bigInt, {BigInteger} from 'big-integer'; + +export function newPost( + title: string, + body: string +): [BigInteger, NodeMap] { + const now = Date.now(); + const nowDa = unixToDa(now); + const root: Post = { + author: `~${window.ship}`, + index: "/" + nowDa.toString(), + "time-sent": now, + contents: [], + hash: null, + signatures: [], + }; + + const revContainer: Post = { ...root, index: root.index + "/1" }; + const commentsContainer = { ...root, index: root.index + "/2" }; + + const firstRevision: Post = { + ...revContainer, + index: revContainer.index + "/1", + contents: [{ text: title }, { text: body }], + }; + + const nodes = { + [root.index]: { + post: root, + children: { + graph: { + 1: { + post: revContainer, + children: { + graph: { + 1: { + post: firstRevision, + children: { empty: null }, + }, + }, + }, + }, + 2: { + post: commentsContainer, + children: { empty: null }, + }, + }, + }, + }, + }; + + return [nowDa, nodes]; +} + +export function editPost(rev: number, noteId: BigInteger, title: string, body: string) { + const now = Date.now(); + const newRev: Post = { + author: `~${window.ship}`, + index: `/${noteId.toString()}/1/${rev}`, + "time-sent": now, + contents: [{ text: title }, { text: body }], + hash: null, + signatures: [], + }; + const nodes = { + [newRev.index]: { + post: newRev, + children: { empty: null } + } + }; + + return nodes; +} + +export function getLatestRevision(node: GraphNode): [number, string, string, Post] { + const revs = node.children.get(bigInt(1)); + const empty = [1, "", "", buntPost()] as [number, string, string, Post]; + if(!revs) { + return empty; + } + const [revNum, rev] = [...revs.children][0]; + if(!rev) { + return empty; + } + const [title, body] = rev.post.contents as TextContent[]; + return [revNum.toJSNumber(), title.text, body.text, rev.post]; +} + +export function getLatestCommentRevision(node: GraphNode): [number, Post] { + const empty = [1, buntPost()] as [number, Post]; + if (node.children.size <= 0) { + return empty; + } + const [revNum, rev] = [...node.children][0]; + if(!rev) { + return empty; + } + return [revNum.toJSNumber(), rev.post]; +} + + +export function getComments(node: GraphNode): GraphNode { + const comments = node.children.get(bigInt(2)); + if(!comments) { + return { post: buntPost(), children: new BigIntOrderedMap() } + } + return comments; +} + +export function getSnippet(body: string) { + const start = body.slice(0, 400); + return start === body ? start : `${start}...`; +} + diff --git a/pkg/interface/src/logic/lib/sigil.js b/pkg/interface/src/logic/lib/sigil.js index 6e606be90..067711236 100644 --- a/pkg/interface/src/logic/lib/sigil.js +++ b/pkg/interface/src/logic/lib/sigil.js @@ -25,6 +25,7 @@ export const Sigil = memo(({ classes = '', color, foreground = '', ship, size, s display='inline-block' height={size} width={size} + className={classes} />) : ( ( candidates: C[], key: (c: C) => string, - searchPred: (query: string, c: C) => boolean + searchPred: (query: string, c: C) => boolean, + isExact: (query: string) => C | undefined ) { const [options, setOptions] = useState(candidates); const [selected, setSelected] = useState(); const search = useCallback( (s: string) => { - const opts = candidates.filter((c) => searchPred(s, c)); + const exactMatch = isExact(s); + const exact = exactMatch ? [exactMatch] : []; + const opts = [...new Set([...exact, ...candidates.filter((c) => searchPred(s, c))])]; setOptions(opts); if (selected) { const idx = opts.findIndex((c) => key(c) === key(selected)); diff --git a/pkg/interface/src/logic/lib/util.js b/pkg/interface/src/logic/lib/util.js deleted file mode 100644 index 8a1a4b8da..000000000 --- a/pkg/interface/src/logic/lib/util.js +++ /dev/null @@ -1,258 +0,0 @@ -import _ from 'lodash'; -import f from 'lodash/fp'; - -export const MOBILE_BROWSER_REGEX = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i; - -export function parentPath(path) { - return _.dropRight(path.split('/'), 1).join('/'); -} - -export function clamp(x,min,max) { - return Math.max(min, Math.min(max, x)); -} - -// color is a #000000 color -export function adjustHex(color, amount) { - const res = f.flow( - f.split(''), f.chunk(2), // get individual color channels - f.map(c => parseInt(c.join(''), 16)), // as hex - f.map(c => clamp(c + amount, 0, 255).toString(16)), // adjust - f.join('') - )(color.slice(1)) - return `#${res}`; -} - - -export function resourceAsPath(resource) { - const { name, ship } = resource; - return `/ship/~${ship}/${name}`; -} - -export function uuid() { - let str = '0v'; - str += Math.ceil(Math.random()*8)+'.'; - for (let i = 0; i < 5; i++) { - let _str = Math.ceil(Math.random()*10000000).toString(32); - _str = ('00000'+_str).substr(-5,5); - str += _str+'.'; - } - - return str.slice(0,-1); -} - -/* - Goes from: - ~2018.7.17..23.15.09..5be5 // urbit @da - To: - (javascript Date object) -*/ -export function daToDate(st) { - const dub = function(n) { - return parseInt(n) < 10 ? '0' + parseInt(n) : n.toString(); - }; - const da = st.split('..'); - const bigEnd = da[0].split('.'); - const lilEnd = da[1].split('.'); - const ds = `${bigEnd[0].slice(1)}-${dub(bigEnd[1])}-${dub(bigEnd[2])}T${dub(lilEnd[0])}:${dub(lilEnd[1])}:${dub(lilEnd[2])}Z`; - return new Date(ds); -} - -/* - Goes from: - (javascript Date object) - To: - ~2018.7.17..23.15.09..5be5 // urbit @da -*/ - -export function dateToDa(d, mil) { -  const fil = function(n) { -    return n >= 10 ? n : '0' + n; -  }; -  return ( -    `~${d.getUTCFullYear()}.` + -    `${(d.getUTCMonth() + 1)}.` + -    `${fil(d.getUTCDate())}..` + -    `${fil(d.getUTCHours())}.` + -    `${fil(d.getUTCMinutes())}.` + -    `${fil(d.getUTCSeconds())}` + - `${mil ? '..0000' : ''}` -  ); -} - -export function deSig(ship) { - if(!ship) { - return null; - } - return ship.replace('~', ''); -} - -export function uxToHex(ux) { - if (ux.length > 2 && ux.substr(0,2) === '0x') { - const value = ux.substr(2).replace('.', '').padStart(6, '0'); - return value; - } - - const value = ux.replace('.', '').padStart(6, '0'); - return value; -} - -export function hexToUx(hex) { - const ux = f.flow( - f.chunk(4), - f.map(x => _.dropWhile(x, y => y === 0).join('')), - f.join('.') - )(hex.split('')) - return `0x${ux}`; -} - -export function writeText(str) { - return new Promise(((resolve, reject) => { - const range = document.createRange(); - range.selectNodeContents(document.body); - document.getSelection().addRange(range); - - let success = false; - function listener(e) { - e.clipboardData.setData('text/plain', str); - e.preventDefault(); - success = true; - } - document.addEventListener('copy', listener); - document.execCommand('copy'); - document.removeEventListener('copy', listener); - - document.getSelection().removeAllRanges(); - - success ? resolve() : reject(); - })).catch((error) => { - console.error(error); - });; -}; - -// trim patps to match dojo, chat-cli -export function cite(ship) { - let patp = ship, shortened = ''; - if (patp === null || patp === '') { - return null; - } - if (patp.startsWith('~')) { - patp = patp.substr(1); - } - // comet - if (patp.length === 56) { - shortened = '~' + patp.slice(0, 6) + '_' + patp.slice(50, 56); - return shortened; - } - // moon - if (patp.length === 27) { - shortened = '~' + patp.slice(14, 20) + '^' + patp.slice(21, 27); - return shortened; - } - return `~${patp}`; -} - -export function alphabeticalOrder(a,b) { - return a.toLowerCase().localeCompare(b.toLowerCase()); -} - -// TODO: deprecated -export function alphabetiseAssociations(associations) { - const result = {}; - Object.keys(associations).sort((a, b) => { - let aName = a.substr(1); - let bName = b.substr(1); - if (associations[a].metadata && associations[a].metadata.title) { - aName = associations[a].metadata.title !== '' - ? associations[a].metadata.title - : a.substr(1); - } - if (associations[b].metadata && associations[b].metadata.title) { - bName = associations[b].metadata.title !== '' - ? associations[b].metadata.title - : b.substr(1); - } - return alphabeticalOrder(aName,bName); - }).map((each) => { - result[each] = associations[each]; - }); - return result; -} - -// encode the string into @ta-safe format, using logic from +wood. -// for example, 'some Chars!' becomes '~.some.~43.hars~21.' -// -export function stringToTa(string) { - let out = ''; - for (let i = 0; i < string.length; i++) { - const char = string[i]; - let add = ''; - switch (char) { - case ' ': - add = '.'; - break; - case '.': - add = '~.'; - break; - case '~': - add = '~~'; - break; - default: - const charCode = string.charCodeAt(i); - if ( - (charCode >= 97 && charCode <= 122) || // a-z - (charCode >= 48 && charCode <= 57) || // 0-9 - char === '-' - ) { - add = char; - } else { - // TODO behavior for unicode doesn't match +wood's, - // but we can probably get away with that for now. - add = '~' + charCode.toString(16) + '.'; - } - } - out = out + add; - } - return '~.' + out; -} - -export function amOwnerOfGroup(groupPath) { - if (!groupPath) -return false; - const groupOwner = /(\/~)?\/~([a-z-]{3,})\/.*/.exec(groupPath)[2]; - return window.ship === groupOwner; -} - -export function getContactDetails(contact) { - const member = !contact; - contact = contact || { - nickname: '', - avatar: null, - color: '0x0' - }; - const nickname = contact.nickname || ''; - const color = uxToHex(contact.color || '0x0'); - const avatar = contact.avatar || null; - return { nickname, color, member, avatar }; -} - -export function stringToSymbol(str) { - let result = ''; - for (let i = 0; i < str.length; i++) { - const n = str.charCodeAt(i); - if (((n >= 97) && (n <= 122)) || - ((n >= 48) && (n <= 57))) { - result += str[i]; - } else if ((n >= 65) && (n <= 90)) { - result += String.fromCharCode(n + 32); - } else { - result += '-'; - } - } - result = result.replace(/^[\-\d]+|\-+/g, '-'); - result = result.replace(/^\-+|\-+$/g, ''); - if (result === '') { - return dateToDa(new Date()); - } - return result; -} - diff --git a/pkg/interface/src/logic/lib/util.ts b/pkg/interface/src/logic/lib/util.ts new file mode 100644 index 000000000..1ebe6e48b --- /dev/null +++ b/pkg/interface/src/logic/lib/util.ts @@ -0,0 +1,356 @@ +import { useEffect } from 'react'; +import _ from "lodash"; +import f from "lodash/fp"; +import bigInt, { BigInteger } from "big-integer"; + +export const MOBILE_BROWSER_REGEX = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i; + +export const MOMENT_CALENDAR_DATE = { + sameDay: "[Today]", + nextDay: "[Tomorrow]", + nextWeek: "dddd", + lastDay: "[Yesterday]", + lastWeek: "[Last] dddd", + sameElse: "DD/MM/YYYY", +}; + +export function appIsGraph(app: string) { + return app === 'publish' || app == 'link'; +} + +export function parentPath(path: string) { + return _.dropRight(path.split('/'), 1).join('/'); +} + +const DA_UNIX_EPOCH = bigInt("170141184475152167957503069145530368000"); // `@ud` ~1970.1.1 +const DA_SECOND = bigInt("18446744073709551616"); // `@ud` ~s1 +export function daToUnix(da: BigInteger) { + // ported from +time:enjs:format in hoon.hoon + const offset = DA_SECOND.divide(bigInt(2000)); + const epochAdjusted = offset.add(da.subtract(DA_UNIX_EPOCH)); + + return Math.round( + epochAdjusted.multiply(bigInt(1000)).divide(DA_SECOND).toJSNumber() + ); +} + +export function unixToDa(unix: number) { + const timeSinceEpoch = bigInt(unix).multiply(DA_SECOND).divide(bigInt(1000)); + return DA_UNIX_EPOCH.add(timeSinceEpoch); +} + +export function makePatDa(patda: string) { + return bigInt(udToDec(patda)); +} + +export function udToDec(ud: string): string { + return ud.replace(/\./g, ""); +} + +export function decToUd(str: string): string { + return _.trimStart( + f.flow( + f.split(""), + f.reverse, + f.chunk(3), + f.map(f.flow(f.reverse, f.join(""))), + f.reverse, + f.join(".") + )(str), + "0." + ); +} + +/** + * Clamp a number between a min and max + */ +export function clamp(x: number, min: number, max: number) { + return Math.max(min, Math.min(max, x)); +} + +// color is a #000000 color +export function adjustHex(color: string, amount: number): string { + return f.flow( + f.split(""), + f.chunk(2), // get RGB channels + f.map((c) => parseInt(c.join(""), 16)), // as hex + f.map((c) => clamp(c + amount, 0, 255).toString(16)), // adjust + f.join(""), + (res) => `#${res}` //format + )(color.slice(1)); +} + +export function resourceAsPath(resource: any) { + const { name, ship } = resource; + return `/ship/~${ship}/${name}`; +} + +export function uuid() { + let str = "0v"; + str += Math.ceil(Math.random() * 8) + "."; + for (let i = 0; i < 5; i++) { + let _str = Math.ceil(Math.random() * 10000000).toString(32); + _str = ("00000" + _str).substr(-5, 5); + str += _str + "."; + } + + return str.slice(0, -1); +} + +/* + Goes from: + ~2018.7.17..23.15.09..5be5 // urbit @da + To: + (javascript Date object) +*/ +export function daToDate(st: string) { + const dub = function (n: string) { + return parseInt(n) < 10 ? "0" + parseInt(n) : n.toString(); + }; + const da = st.split(".."); + const bigEnd = da[0].split("."); + const lilEnd = da[1].split("."); + const ds = `${bigEnd[0].slice(1)}-${dub(bigEnd[1])}-${dub(bigEnd[2])}T${dub( + lilEnd[0] + )}:${dub(lilEnd[1])}:${dub(lilEnd[2])}Z`; + return new Date(ds); +} + +/* + Goes from: + (javascript Date object) + To: + ~2018.7.17..23.15.09..5be5 // urbit @da +*/ + +export function dateToDa(d: Date, mil: boolean = false) { + const fil = function (n: number) { + return n >= 10 ? n : "0" + n; + }; + return ( + `~${d.getUTCFullYear()}.` + + `${d.getUTCMonth() + 1}.` + + `${fil(d.getUTCDate())}..` + + `${fil(d.getUTCHours())}.` + + `${fil(d.getUTCMinutes())}.` + + `${fil(d.getUTCSeconds())}` + + `${mil ? "..0000" : ""}` + ); +} + +export function deSig(ship: string) { + if (!ship) { + return null; + } + return ship.replace("~", ""); +} + +export function uxToHex(ux: string) { + if (ux.length > 2 && ux.substr(0, 2) === "0x") { + const value = ux.substr(2).replace(".", "").padStart(6, "0"); + return value; + } + + const value = ux.replace(".", "").padStart(6, "0"); + return value; +} + +export const hexToUx = (hex) => { + const ux = f.flow( + f.chunk(4), + f.map(x => _.dropWhile(x, y => y === 0).join('')), + f.join('.') + )(hex.split('')); + return `0x${ux}`; +}; + +export function writeText(str: string) { + return new Promise((resolve, reject) => { + const range = document.createRange(); + range.selectNodeContents(document.body); + document?.getSelection()?.addRange(range); + + let success = false; + function listener(e) { + e.clipboardData.setData("text/plain", str); + e.preventDefault(); + success = true; + } + document.addEventListener("copy", listener); + document.execCommand("copy"); + document.removeEventListener("copy", listener); + + document?.getSelection()?.removeAllRanges(); + + success ? resolve() : reject(); + }).catch((error) => { + console.error(error); + }); +} + +// trim patps to match dojo, chat-cli +export function cite(ship: string) { + let patp = ship, + shortened = ""; + if (patp === null || patp === "") { + return null; + } + if (patp.startsWith("~")) { + patp = patp.substr(1); + } + // comet + if (patp.length === 56) { + shortened = "~" + patp.slice(0, 6) + "_" + patp.slice(50, 56); + return shortened; + } + // moon + if (patp.length === 27) { + shortened = "~" + patp.slice(14, 20) + "^" + patp.slice(21, 27); + return shortened; + } + return `~${patp}`; +} + +export function alphabeticalOrder(a: string, b: string) { + return a.toLowerCase().localeCompare(b.toLowerCase()); +} + +// TODO: deprecated +export function alphabetiseAssociations(associations: any) { + const result = {}; + Object.keys(associations) + .sort((a, b) => { + let aName = a.substr(1); + let bName = b.substr(1); + if (associations[a].metadata && associations[a].metadata.title) { + aName = + associations[a].metadata.title !== "" + ? associations[a].metadata.title + : a.substr(1); + } + if (associations[b].metadata && associations[b].metadata.title) { + bName = + associations[b].metadata.title !== "" + ? associations[b].metadata.title + : b.substr(1); + } + return alphabeticalOrder(aName, bName); + }) + .map((each) => { + result[each] = associations[each]; + }); + return result; +} + +// encode the string into @ta-safe format, using logic from +wood. +// for example, 'some Chars!' becomes '~.some.~43.hars~21.' +// +export function stringToTa(str: string) { + let out = ""; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + let add = ""; + switch (char) { + case " ": + add = "."; + break; + case ".": + add = "~."; + break; + case "~": + add = "~~"; + break; + default: + const charCode = str.charCodeAt(i); + if ( + (charCode >= 97 && charCode <= 122) || // a-z + (charCode >= 48 && charCode <= 57) || // 0-9 + char === "-" + ) { + add = char; + } else { + // TODO behavior for unicode doesn't match +wood's, + // but we can probably get away with that for now. + add = "~" + charCode.toString(16) + "."; + } + } + out = out + add; + } + return "~." + out; +} + +export function amOwnerOfGroup(groupPath: string) { + if (!groupPath) return false; + const groupOwner = /(\/~)?\/~([a-z-]{3,})\/.*/.exec(groupPath)?.[2]; + return window.ship === groupOwner; +} + +export function getContactDetails(contact: any) { + const member = !contact; + contact = contact || { + nickname: "", + avatar: null, + color: "0x0", + }; + const nickname = contact.nickname || ""; + const color = uxToHex(contact.color || "0x0"); + const avatar = contact.avatar || null; + return { nickname, color, member, avatar }; +} + +export function stringToSymbol(str: string) { + let result = ""; + for (let i = 0; i < str.length; i++) { + const n = str.charCodeAt(i); + if ((n >= 97 && n <= 122) || (n >= 48 && n <= 57)) { + result += str[i]; + } else if (n >= 65 && n <= 90) { + result += String.fromCharCode(n + 32); + } else { + result += "-"; + } + } + result = result.replace(/^[\-\d]+|\-+/g, "-"); + result = result.replace(/^\-+|\-+$/g, ""); + if (result === "") { + return dateToDa(new Date()); + } + return result; +} + + + +/** + * Formats a numbers as a `@ud` inserting dot where needed + */ +export function numToUd(num: number) { + return f.flow( + f.split(''), + f.reverse, + f.chunk(3), + f.reverse, + f.map(s => s.join('')), + f.join('.') + )(num.toString()) +} + +export function usePreventWindowUnload(shouldPreventDefault: boolean, message = "You have unsaved changes. Are you sure you want to exit?") { + useEffect(() => { + if (!shouldPreventDefault) return; + const handleBeforeUnload = event => { + event.preventDefault(); + return message; + } + window.addEventListener("beforeunload", handleBeforeUnload); + window.onbeforeunload = handleBeforeUnload; + return () => { + window.removeEventListener("beforeunload", handleBeforeUnload); + // @ts-ignore + window.onbeforeunload = undefined; + } + }, [shouldPreventDefault]); +} + +export function pluralize(text: string, isPlural = false, vowel = false) { + return isPlural ? `${text}s`: `${vowel ? 'an' : 'a'} ${text}`; +} diff --git a/pkg/interface/src/logic/lib/workspace.ts b/pkg/interface/src/logic/lib/workspace.ts index a5ba59bb1..2ab8ce65b 100644 --- a/pkg/interface/src/logic/lib/workspace.ts +++ b/pkg/interface/src/logic/lib/workspace.ts @@ -6,7 +6,7 @@ export function getTitleFromWorkspace( ) { switch (workspace.type) { case "home": - return "Home"; + return "DMs + Drafts"; case "group": const association = associations.contacts[workspace.group]; return association?.metadata?.title || ""; diff --git a/pkg/interface/src/logic/reducers/graph-update.js b/pkg/interface/src/logic/reducers/graph-update.js index ead7c8209..d5884b4fe 100644 --- a/pkg/interface/src/logic/reducers/graph-update.js +++ b/pkg/interface/src/logic/reducers/graph-update.js @@ -1,16 +1,6 @@ import _ from 'lodash'; -import { OrderedMap } from "~/logic/lib/OrderedMap"; - -const DA_UNIX_EPOCH = 170141184475152167957503069145530368000; -const normalizeKey = (key) => { - if(key > DA_UNIX_EPOCH) { - // new links uses milliseconds since unix epoch - // old (pre-graph-store) use @da - // ported from +time:enjs:format in hoon.hoon - return Math.round((1000 * (9223372036854775 + (key - DA_UNIX_EPOCH))) / 18446744073709551616); - } - return key; -} +import { BigIntOrderedMap } from "~/logic/lib/BigIntOrderedMap"; +import bigInt, { BigInteger } from "big-integer"; export const GraphReducer = (json, state) => { const data = _.get(json, 'graph-update', false); @@ -38,33 +28,26 @@ const addGraph = (json, state) => { const _processNode = (node) => { // is empty if (!node.children) { - node.children = new OrderedMap(); - node.post.originalIndex = node.post.index; - node.post.index = node.post.index.split('/').map(x => x.length === 0 ? '' : normalizeKey(parseInt(x, 10))).join('/'); + node.children = new BigIntOrderedMap(); return node; } // is graph - let converted = new OrderedMap(); + let converted = new BigIntOrderedMap(); for (let i in node.children) { let item = node.children[i]; let index = item[0].split('/').slice(1).map((ind) => { - return parseInt(ind, 10); + return bigInt(ind); }); if (index.length === 0) { break; } - - const normalKey = normalizeKey(index[index.length - 1]); - item[1].post.originalKey = index[index.length - 1]; converted.set( - normalKey, + index[index.length - 1], _processNode(item[1]) ); } node.children = converted; - node.post.originalIndex = node.post.index; - node.post.index = node.post.index.split('/').map(x => x.length === 0 ? '' : normalizeKey(parseInt(x, 10))).join('/'); return node; }; @@ -75,21 +58,22 @@ const addGraph = (json, state) => { } let resource = data.resource.ship + '/' + data.resource.name; - state.graphs[resource] = new OrderedMap(); + state.graphs[resource] = new BigIntOrderedMap(); for (let i in data.graph) { let item = data.graph[i]; let index = item[0].split('/').slice(1).map((ind) => { - return parseInt(ind, 10); + return bigInt(ind); }); if (index.length === 0) { break; } let node = _processNode(item[1]); - const normalKey = normalizeKey(index[index.length - 1]) - node.post.originalKey = index[index.length - 1]; - state.graphs[resource].set(normalKey, node); + state.graphs[resource].set( + index[index.length - 1], + node + ); } state.graphKeys.add(resource); } @@ -102,16 +86,16 @@ const removeGraph = (json, state) => { if (!('graphs' in state)) { state.graphs = {}; } - let resource = data.resource.ship + '/' + data.resource.name; + let resource = data.ship + '/' + data.name; delete state.graphs[resource]; } }; const mapifyChildren = (children) => { - return new OrderedMap( + return new BigIntOrderedMap( children.map(([idx, node]) => { const nd = {...node, children: mapifyChildren(node.children || []) }; - return [normalizeKey(parseInt(idx.slice(1), 10)), nd]; + return [bigInt(idx.slice(1)), nd]; })); }; @@ -119,23 +103,18 @@ const addNodes = (json, state) => { const _addNode = (graph, index, node) => { // set child of graph if (index.length === 1) { - node.post.originalIndex = node.post.index; - node.post.index = node.post.index.split('/').map(x => x.length === 0 ? '' : normalizeKey(parseInt(x, 10))).join('/'); - - const normalKey = normalizeKey(index[0]) - node.post.originalKey = index[0]; - graph.set(normalKey, node); + graph.set(index[0], node); return graph; } // set parent of graph - let parNode = graph.get(normalizeKey(index[0])); + let parNode = graph.get(index[0]); if (!parNode) { console.error('parent node does not exist, cannot add child'); return; } parNode.children = _addNode(parNode.children, index.slice(1), node); - graph.set(normalizeKey(index[0]), parNode); + graph.set(index[0], parNode); return graph; }; @@ -151,7 +130,7 @@ const addNodes = (json, state) => { if (item[0].split('/').length === 0) { return; } let index = item[0].split('/').slice(1).map((ind) => { - return parseInt(ind, 10); + return bigInt(ind); }); if (index.length === 0) { return; } @@ -174,9 +153,9 @@ const removeNodes = (json, state) => { if (index.length === 1) { graph.delete(index[0]); } else { - const child = graph.get(normalizeKey(index[0])); + const child = graph.get(index[0]); _remove(child.children, index.slice(1)); - graph.set(normalizeKey(index[0]), child); + graph.set(index[0], child); } }; const data = _.get(json, 'remove-nodes', false); @@ -188,7 +167,7 @@ const removeNodes = (json, state) => { data.indices.forEach((index) => { if (index.split('/').length === 0) { return; } let indexArr = index.split('/').slice(1).map((ind) => { - return parseInt(ind, 10); + return bigInt(ind); }); _remove(state.graphs[res], indexArr); }); diff --git a/pkg/interface/src/logic/reducers/group-update.ts b/pkg/interface/src/logic/reducers/group-update.ts index 5862aaca1..0b0ad8ec0 100644 --- a/pkg/interface/src/logic/reducers/group-update.ts +++ b/pkg/interface/src/logic/reducers/group-update.ts @@ -103,7 +103,7 @@ export default class GroupReducer { const resourcePath = resourceAsPath(resource); state.groups[resourcePath] = { members: new Set(), - tags: { role: {} }, + tags: { role: { admin: new Set([window.ship]) } }, policy: decodePolicy(policy), hidden, }; diff --git a/pkg/interface/src/logic/reducers/hark-update.ts b/pkg/interface/src/logic/reducers/hark-update.ts new file mode 100644 index 000000000..590afde13 --- /dev/null +++ b/pkg/interface/src/logic/reducers/hark-update.ts @@ -0,0 +1,306 @@ +import { + Notifications, + NotifIndex, + NotificationGraphConfig, + GroupNotificationsConfig, +} from "~/types"; +import { makePatDa } from "~/logic/lib/util"; +import _ from "lodash"; +import { StoreState } from "../store/type"; + +type HarkState = Pick; + +export const HarkReducer = (json: any, state: HarkState) => { + const data = _.get(json, "harkUpdate", false); + if (data) { + reduce(data, state); + } + const graphHookData = _.get(json, "hark-graph-hook-update", false); + if (graphHookData) { + graphInitial(graphHookData, state); + graphIgnore(graphHookData, state); + graphListen(graphHookData, state); + graphWatchSelf(graphHookData, state); + graphMentions(graphHookData, state); + } + const groupHookData = _.get(json, "hark-group-hook-update", false); + if (groupHookData) { + groupInitial(groupHookData, state); + groupListen(groupHookData, state); + groupIgnore(groupHookData, state); + } + + const chatHookData = _.get(json, "hark-chat-hook-update", false); + if(chatHookData) { + + chatInitial(chatHookData, state); + chatListen(chatHookData, state); + chatIgnore(chatHookData, state); + + } +}; + +function chatInitial(json: any, state: HarkState) { + const data = _.get(json, "initial", false); + if (data) { + state.notificationsChatConfig = data; + } +} + + +function chatListen(json: any, state: HarkState) { + const data = _.get(json, "listen", false); + if (data) { + state.notificationsChatConfig = [...state.notificationsChatConfig, data]; + } +} + +function chatIgnore(json: any, state: HarkState) { + const data = _.get(json, "ignore", false); + if (data) { + state.notificationsChatConfig = state.notificationsChatConfig.filter(x => x !== data); + } +} + +function groupInitial(json: any, state: HarkState) { + const data = _.get(json, "initial", false); + if (data) { + state.notificationsGroupConfig = data; + } +} + +function graphInitial(json: any, state: HarkState) { + const data = _.get(json, "initial", false); + if (data) { + state.notificationsGraphConfig = data; + } +} + +function graphListen(json: any, state: HarkState) { + const data = _.get(json, "listen", false); + if (data) { + state.notificationsGraphConfig.watching = [ + ...state.notificationsGraphConfig.watching, + data, + ]; + } +} + +function graphIgnore(json: any, state: HarkState) { + const data = _.get(json, "ignore", false); + if (data) { + state.notificationsGraphConfig.watching = state.notificationsGraphConfig.watching.filter( + ({ graph, index }) => !(graph === data.graph && index === data.index) + ); + } +} + +function groupListen(json: any, state: HarkState) { + const data = _.get(json, "listen", false); + if (data) { + state.notificationsGroupConfig = [...state.notificationsGroupConfig, data]; + } +} + +function groupIgnore(json: any, state: HarkState) { + const data = _.get(json, "ignore", false); + if (data) { + state.notificationsGroupConfig = state.notificationsGroupConfig.filter( + (n) => n !== data + ); + } +} + +function graphMentions(json: any, state: HarkState) { + const data = _.get(json, "set-mentions", undefined); + if (!_.isUndefined(data)) { + state.notificationsGraphConfig.mentions = data; + } +} + +function graphWatchSelf(json: any, state: HarkState) { + const data = _.get(json, "set-watch-on-self", undefined); + if (!_.isUndefined(data)) { + state.notificationsGraphConfig.watchOnSelf = data; + } +} + +function reduce(data: any, state: HarkState) { + unread(data, state); + read(data, state); + archive(data, state); + timebox(data, state); + more(data, state); + dnd(data, state); + added(data, state); + unreads(data, state); +} + +function unreads(json: any, state: HarkState) { + const data = _.get(json, 'unreads'); + if(data) { + data.forEach(({ index, unread }) => { + updateUnreads(state, index, x => x + unread); + }); + } +} + +function updateUnreads(state: HarkState, index: NotifIndex, f: (u: number) => number) { + state.notificationsCount = f(state.notificationsCount); + if('graph' in index) { + const curr = state.unreads.graph[index.graph.graph] || 0; + state.unreads.graph[index.graph.graph] = f(curr); + } else if('group' in index) { + const curr = state.unreads.group[index.group.group] || 0; + state.unreads.group[index.group.group] = f(curr); + } else if('chat' in index) { + const curr = state.unreads.chat[index.chat.chat] || 0 + state.unreads.chat[index.chat.chat] = f(curr); + } +} + +function added(json: any, state: HarkState) { + const data = _.get(json, "added", false); + if (data) { + const { index, notification } = data; + const time = makePatDa(data.time); + const timebox = state.notifications.get(time) || []; + + const arrIdx = timebox.findIndex((idxNotif) => + notifIdxEqual(index, idxNotif.index) + ); + if (arrIdx !== -1) { + if(timebox[arrIdx]?.notification?.read) { + updateUnreads(state, index, x => x+1); + } + timebox[arrIdx] = { index, notification }; + state.notifications.set(time, timebox); + } else { + updateUnreads(state, index, x => x+1); + state.notifications.set(time, [...timebox, { index, notification }]); + } + } +} + +const dnd = (json: any, state: HarkState) => { + const data = _.get(json, "set-dnd", undefined); + if (!_.isUndefined(data)) { + state.doNotDisturb = data; + } +}; + +const timebox = (json: any, state: HarkState) => { + const data = _.get(json, "timebox", false); + if (data) { + const time = makePatDa(data.time); + if (data.archive) { + state.archivedNotifications.set(time, data.notifications); + } else { + state.notifications.set(time, data.notifications); + } + } +}; + +function more(json: any, state: HarkState) { + const data = _.get(json, "more", false); + if (data) { + _.forEach(data, (d) => reduce(d, state)); + } +} + +function notifIdxEqual(a: NotifIndex, b: NotifIndex) { + if ("graph" in a && "graph" in b) { + return ( + a.graph.graph === b.graph.graph && + a.graph.group === b.graph.group && + a.graph.module === b.graph.module && + a.graph.description === b.graph.description + ); + } else if ("group" in a && "group" in b) { + return ( + a.group.group === b.group.group && + a.group.description === b.group.description + ); + } else if ("chat" in a && "chat" in b) { + return a.chat.chat === b.chat.chat && + a.chat.mention === b.chat.mention; + } + return false; +} + +function setRead( + time: string, + index: NotifIndex, + read: boolean, + state: HarkState +) { + const patDa = makePatDa(time); + const timebox = state.notifications.get(patDa); + if (_.isNull(timebox)) { + console.warn("Modifying nonexistent timebox"); + return; + } + const arrIdx = timebox.findIndex((idxNotif) => + notifIdxEqual(index, idxNotif.index) + ); + if (arrIdx === -1) { + console.warn("Modifying nonexistent index"); + return; + } + timebox[arrIdx].notification.read = read; + state.notifications.set(patDa, timebox); +} + +function read(json: any, state: HarkState) { + const data = _.get(json, "read", false); + if (data) { + const { time, index } = data; + updateUnreads(state, index, x => x-1); + setRead(time, index, true, state); + } +} + +function unread(json: any, state: HarkState) { + const data = _.get(json, "unread", false); + if (data) { + const { time, index } = data; + updateUnreads(state, index, x => x+1); + setRead(time, index, false, state); + } +} + +function archive(json: any, state: HarkState) { + const data = _.get(json, "archive", false); + if (data) { + const { index } = data; + const time = makePatDa(data.time); + const timebox = state.notifications.get(time); + if (!timebox) { + console.warn("Modifying nonexistent timebox"); + return; + } + const [archived, unarchived] = _.partition(timebox, (idxNotif) => + notifIdxEqual(index, idxNotif.index) + ); + state.notifications.set(time, unarchived); + const archiveBox = state.archivedNotifications.get(time) || []; + const readCount = archived.filter( + ({ notification }) => !notification.read + ).length; + updateUnreads(state, index, x => x - readCount); + state.archivedNotifications.set(time, [ + ...archiveBox, + ...archived.map(({ notification, index }) => ({ + notification: { ...notification, read: true }, + index, + })), + ]); + } +} diff --git a/pkg/interface/src/logic/reducers/invite-update.ts b/pkg/interface/src/logic/reducers/invite-update.ts index bdeba0e4f..30fb61042 100644 --- a/pkg/interface/src/logic/reducers/invite-update.ts +++ b/pkg/interface/src/logic/reducers/invite-update.ts @@ -29,35 +29,35 @@ export default class InviteReducer { create(json: InviteUpdate, state: S) { const data = _.get(json, 'create', false); if (data) { - state.invites[data.path] = {}; + state.invites[data] = {}; } } delete(json: InviteUpdate, state: S) { const data = _.get(json, 'delete', false); if (data) { - delete state.invites[data.path]; + delete state.invites[data]; } } invite(json: InviteUpdate, state: S) { const data = _.get(json, 'invite', false); if (data) { - state.invites[data.path][data.uid] = data.invite; + state.invites[data.term][data.uid] = data.invite; } } accepted(json: InviteUpdate, state: S) { const data = _.get(json, 'accepted', false); if (data) { - delete state.invites[data.path][data.uid]; + delete state.invites[data.term][data.uid]; } } decline(json: InviteUpdate, state: S) { const data = _.get(json, 'decline', false); if (data) { - delete state.invites[data.path][data.uid]; + delete state.invites[data.term][data.uid]; } } } diff --git a/pkg/interface/src/logic/reducers/publish-response.ts b/pkg/interface/src/logic/reducers/publish-response.ts deleted file mode 100644 index 073efa399..000000000 --- a/pkg/interface/src/logic/reducers/publish-response.ts +++ /dev/null @@ -1,205 +0,0 @@ -import _ from 'lodash'; -import { StoreState } from '../../store/type'; -import { Cage } from '~/types/cage'; - -type PublishState = Pick; - -export default class PublishResponseReducer { - reduce(json: Cage, state: S) { - const data = _.get(json, 'publish-response', false); - if (!data) { return; } - switch(data.type) { - case "notebooks": - this.handleNotebooks(data, state); - break; - case "notebook": - this.handleNotebook(data, state); - break; - case "note": - this.handleNote(data, state); - break; - case "notes-page": - this.handleNotesPage(data, state); - break; - case "comments-page": - this.handleCommentsPage(data, state); - break; - default: - break; - } - } - - handleNotebooks(json, state) { - for (var host in state.notebooks) { - if (json.data[host]) { - for (var book in state.notebooks[host]) { - if (!json.data[host][book]) { - delete state.notebooks[host][book]; - } - } - } else { - delete state.notebooks[host]; - } - } - - for (var host in json.data) { - if (state.notebooks[host]) { - for (var book in json.data[host]) { - if (state.notebooks[host][book]) { - state.notebooks[host][book]["title"] = json.data[host][book]["title"]; - state.notebooks[host][book]["date-created"] = - json.data[host][book]["date-created"]; - state.notebooks[host][book]["num-notes"] = - json.data[host][book]["num-notes"]; - state.notebooks[host][book]["num-unread"] = - json.data[host][book]["num-unread"]; - } else { - state.notebooks[host][book] = json.data[host][book]; - } - } - } else { - state.notebooks[host] = json.data[host]; - } - } - } - - handleNotebook(json, state) { - if (state.notebooks[json.host]) { - if (state.notebooks[json.host][json.notebook]) { - state.notebooks[json.host][json.notebook]["notes-by-date"] = - json.data.notebook["notes-by-date"]; - state.notebooks[json.host][json.notebook].subscribers = - json.data.notebook.subscribers; - state.notebooks[json.host][json.notebook].writers = - json.data.notebook.writers; - state.notebooks[json.host][json.notebook].comments = - json.data.notebook.comments; - state.notebooks[json.host][json.notebook]["subscribers-group-path"] = - json.data.notebook["subscribers-group-path"]; - state.notebooks[json.host][json.notebook]["writers-group-path"] = - json.data.notebook["writers-group-path"]; - state.notebooks[json.host][json.notebook].about = - json.data.notebook.about; - if (state.notebooks[json.host][json.notebook].notes) { - for (var key in json.data.notebook.notes) { - let oldNote = state.notebooks[json.host][json.notebook].notes[key]; - if (!(oldNote)) { - state.notebooks[json.host][json.notebook].notes[key] = - json.data.notebook.notes[key]; - } else if (!(oldNote.build)) { - state.notebooks[json.host][json.notebook].notes[key]["author"] = - json.data.notebook.notes[key]["author"]; - state.notebooks[json.host][json.notebook].notes[key]["date-created"] = - json.data.notebook.notes[key]["date-created"]; - state.notebooks[json.host][json.notebook].notes[key]["note-id"] = - json.data.notebook.notes[key]["note-id"]; - state.notebooks[json.host][json.notebook].notes[key]["num-comments"] = - json.data.notebook.notes[key]["num-comments"]; - state.notebooks[json.host][json.notebook].notes[key]["title"] = - json.data.notebook.notes[key]["title"]; - } - } - } else { - state.notebooks[json.host][json.notebook].notes = - json.data.notebook.notes; - } - } else { - state.notebooks[json.host][json.notebook] = json.data.notebook; - } - } else { - state.notebooks[json.host] = {[json.notebook]: json.data.notebook}; - } - } - - handleNote(json, state) { - if (state.notebooks[json.host] && - state.notebooks[json.host][json.notebook]) { - state.notebooks[json.host][json.notebook]["notes-by-date"] = - json.data["notes-by-date"]; - if (state.notebooks[json.host][json.notebook].notes) { - for (var key in json.data.notes) { - let oldNote = state.notebooks[json.host][json.notebook].notes[key]; - if (!(oldNote && oldNote.build && key !== json.note)) { - state.notebooks[json.host][json.notebook].notes[key] = - json.data.notes[key]; - } - } - } else { - state.notebooks[json.host][json.notebook].notes = json.data.notes; - } - } else { - throw Error("tried to fetch note, but we don't have the notebook"); - } - } - - handleNotesPage(json, state) { - if (state.notebooks[json.host] && state.notebooks[json.host][json.notebook]) { - state.notebooks[json.host][json.notebook]["notes-by-date"] = - json.data["notes-by-date"]; - if (state.notebooks[json.host][json.notebook].notes) { - for (var key in json.data.notes) { - let oldNote = state.notebooks[json.host][json.notebook].notes[key]; - if (!(oldNote)) { - state.notebooks[json.host][json.notebook].notes[key] = - json.data.notes[key]; - } else if (!(oldNote.build)) { - state.notebooks[json.host][json.notebook].notes[key]["author"] = - json.data.notes[key]["author"]; - state.notebooks[json.host][json.notebook].notes[key]["date-created"] = - json.data.notes[key]["date-created"]; - state.notebooks[json.host][json.notebook].notes[key]["note-id"] = - json.data.notes[key]["note-id"]; - state.notebooks[json.host][json.notebook].notes[key]["num-comments"] = - json.data.notes[key]["num-comments"]; - state.notebooks[json.host][json.notebook].notes[key]["title"] = - json.data.notes[key]["title"]; - } - } - } else { - state.notebooks[json.host][json.notebook].notes = - json.data.notes; - } - } else { - throw Error("tried to fetch paginated notes, but we don't have the notebook"); - } - } - - handleCommentsPage(json, state) { - if (state.notebooks[json.host] && - state.notebooks[json.host][json.notebook] && - state.notebooks[json.host][json.notebook].notes[json.note]) - { - if (state.notebooks[json.host][json.notebook].notes[json.note].comments) { - json.data.forEach((val, i) => { - let newKey = Object.keys(val)[0]; - let newDate = val[newKey]["date-created"] - let oldComments = state.notebooks[json.host][json.notebook].notes[json.note].comments; - let insertIdx = -1; - - for (var j=0; j newDate) && - (j === oldComments.length-1)){ - insertIdx = j+1; - } - } - if (insertIdx !== -1) { - state.notebooks[json.host][json.notebook].notes[json.note].comments - .splice(insertIdx, 0, val); - } - }); - } else { - state.notebooks[json.host][json.notebook].notes[json.note].comments = - json.data; - } - } else { - throw Error("tried to fetch paginated comments, but we don't have the note"); - } - } -} diff --git a/pkg/interface/src/logic/reducers/publish-update.ts b/pkg/interface/src/logic/reducers/publish-update.ts deleted file mode 100644 index 3be297737..000000000 --- a/pkg/interface/src/logic/reducers/publish-update.ts +++ /dev/null @@ -1,269 +0,0 @@ -import _ from 'lodash'; - -import { PublishUpdate } from '~/types/publish-update'; -import { Cage } from '~/types/cage'; -import { StoreState } from '../../store/type'; -import { getTagFromFrond } from '~/types/noun'; - -type PublishState = Pick; - - -export default class PublishUpdateReducer { - reduce(data: Cage, state: S){ - let json = data["publish-update"]; - if(!json) { - return; - } - const tag = getTagFromFrond(json); - switch(tag){ - case "add-book": - this.addBook(json["add-book"], state); - break; - case "add-note": - this.addNote(json["add-note"], state); - break; - case "add-comment": - this.addComment(json["add-comment"], state); - break; - case "edit-book": - this.editBook(json["edit-book"], state); - break; - case "edit-note": - this.editNote(json["edit-note"], state); - break; - case "edit-comment": - this.editComment(json["edit-comment"], state); - break; - case "del-book": - this.delBook(json["del-book"], state); - break; - case "del-note": - this.delNote(json["del-note"], state); - break; - case "del-comment": - this.delComment(json["del-comment"], state); - break; - case "read": - this.read(json["read"], state); - break; - default: - break; - } - } - - addBook(json, state: S) { - let host = Object.keys(json)[0]; - let book = Object.keys(json[host])[0]; - if (state.notebooks[host]) { - state.notebooks[host][book] = json[host][book]; - } else { - state.notebooks[host] = json[host]; - } - } - - addNote(json, state: S) { - let host = Object.keys(json)[0]; - let book = Object.keys(json[host])[0]; - let noteId = json[host][book]["note-id"]; - if (state.notebooks[host] && state.notebooks[host][book]) { - if (state.notebooks[host][book].notes) { - if (state.notebooks[host][book].notes[noteId] && - state.notebooks[host][book].notes[noteId].pending) - { - state.notebooks[host][book].notes[noteId].pending = false; - return; - } - if (state.notebooks[host][book]["notes-by-date"]) { - state.notebooks[host][book]["notes-by-date"].unshift(noteId); - } else { - state.notebooks[host][book]["notes-by-date"] = [noteId]; - } - state.notebooks[host][book].notes[noteId] = json[host][book]; - } else { - state.notebooks[host][book].notes = {[noteId]: json[host][book]}; - } - state.notebooks[host][book]["num-notes"] += 1; - if (!json[host][book].read) { - state.notebooks[host][book]["num-unread"] += 1; - } - let prevNoteId = state.notebooks[host][book]["notes-by-date"][1] || null; - state.notebooks[host][book].notes[noteId]["prev-note"] = prevNoteId - state.notebooks[host][book].notes[noteId]["next-note"] = null; - if (prevNoteId && state.notebooks[host][book].notes[prevNoteId]) { - state.notebooks[host][book].notes[prevNoteId]["next-note"] = noteId; - } - } - } - - addComment(json, state: S) { - let host = json.host - let book = json.book - let note = json.note - let comment = json.comment; - if (state.notebooks[host] && - state.notebooks[host][book] && - state.notebooks[host][book].notes && - state.notebooks[host][book].notes[note]) - { - - if (state.notebooks[host][book].notes[note].comments) { - let limboCommentIdx = - _.findIndex(state.notebooks[host][book].notes[note].comments, (o) => { - let oldVal = o[getTagFromFrond(o)]; - let newVal = comment[Object.keys(comment)[0]]; - return (oldVal.pending && - (oldVal.author === newVal.author) && - (oldVal.content === newVal.content) - ); - }); - if (limboCommentIdx === -1) { - state.notebooks[host][book].notes[note]["num-comments"] += 1; - state.notebooks[host][book].notes[note].comments.unshift(comment); - } else { - state.notebooks[host][book].notes[note].comments[limboCommentIdx] = - comment; - } - } else if (state.notebooks[host][book].notes[note]["num-comments"] === 1) { - state.notebooks[host][book].notes[note]["num-comments"] += 1; - state.notebooks[host][book].notes[note].comments = [comment]; - } - } - } - - editBook(json, state) { - let host = Object.keys(json)[0]; - let book = Object.keys(json[host])[0]; - if (state.notebooks[host] && state.notebooks[host][book]) { - state.notebooks[host][book]["comments"] = json[host][book]["comments"]; - state.notebooks[host][book]["date-created"] = json[host][book]["date-created"]; - state.notebooks[host][book]["num-notes"] = json[host][book]["num-notes"]; - state.notebooks[host][book]["num-unread"] = json[host][book]["num-unread"]; - state.notebooks[host][book]["title"] = json[host][book]["title"]; - state.notebooks[host][book]["writers-group-path"] = - json[host][book]["writers-group-path"]; - state.notebooks[host][book]["subscribers-group-path"] = - json[host][book]["subscribers-group-path"]; - } - } - - editNote(json, state) { - let host = Object.keys(json)[0]; - let book = Object.keys(json[host])[0]; - let noteId = json[host][book]["note-id"]; - let note = json[host][book]; - if (state.notebooks[host] && - state.notebooks[host][book] && - state.notebooks[host][book].notes && - state.notebooks[host][book].notes[noteId]) - { - state.notebooks[host][book].notes[noteId]["author"] = note["author"]; - state.notebooks[host][book].notes[noteId]["build"] = note["build"]; - state.notebooks[host][book].notes[noteId]["file"] = note["file"]; - state.notebooks[host][book].notes[noteId]["title"] = note["title"]; - } - } - - editComment(json, state) { - let host = json.host - let book = json.book - let note = json.note - let comment = json.comment; - let commentId = Object.keys(comment)[0] - if (state.notebooks[host] && - state.notebooks[host][book] && - state.notebooks[host][book].notes && - state.notebooks[host][book].notes[note] && - state.notebooks[host][book].notes[note].comments) - { - let keys = state.notebooks[host][book].notes[note].comments.map((com) => { - return Object.keys(com)[0]; - }); - let index = keys.indexOf(commentId); - if (index > -1) { - state.notebooks[host][book].notes[note].comments[index] = comment; - } - } - } - - delBook(json, state) { - let host = json.host; - let book = json.book; - if (state.notebooks[host]) { - if (state.notebooks[host][book]) { - delete state.notebooks[host][book]; - } - if (Object.keys(state.notebooks[host]).length === 0) { - delete state.notebooks[host]; - } - } - } - - delNote(json, state) { - let host = json.host; - let book = json.book; - let note = json.note; - if (state.notebooks[host] && - state.notebooks[host][book] && - state.notebooks[host][book].notes) - { - if (state.notebooks[host][book].notes[note]) { - state.notebooks[host][book]["num-notes"] -= 1; - if (!state.notebooks[host][book].notes[note].read) { - state.notebooks[host][book]["num-unread"] -= 1; - } - - delete state.notebooks[host][book].notes[note]; - let index = state.notebooks[host][book]["notes-by-date"].indexOf(note); - if (index > -1) { - state.notebooks[host][book]["notes-by-date"].splice(index, 1); - } - - } - if (Object.keys(state.notebooks[host][book].notes).length === 0) { - delete state.notebooks[host][book].notes; - delete state.notebooks[host][book]["notes-by-date"]; - } - } - } - - delComment(json, state) { - let host = json.host - let book = json.book - let note = json.note - let comment = json.comment; - if (state.notebooks[host] && - state.notebooks[host][book] && - state.notebooks[host][book].notes && - state.notebooks[host][book].notes[note]) - { - state.notebooks[host][book].notes[note]["num-comments"] -= 1; - if (state.notebooks[host][book].notes[note].comments) { - let keys = state.notebooks[host][book].notes[note].comments.map((com) => { - return Object.keys(com)[0]; - }); - - let index = keys.indexOf(comment); - if (index > -1) { - state.notebooks[host][book].notes[note].comments.splice(index, 1); - } - } - } - } - - read(json, state){ - let host = json.host; - let book = json.book; - let noteId = json.note - if (state.notebooks[host] && - state.notebooks[host][book] && - state.notebooks[host][book].notes && - state.notebooks[host][book].notes[noteId]) - { - if (!state.notebooks[host][book].notes[noteId]["read"]) { - state.notebooks[host][book].notes[noteId]["read"] = true; - state.notebooks[host][book]["num-unread"] -= 1; - } - } - } - -} diff --git a/pkg/interface/src/logic/store/store.ts b/pkg/interface/src/logic/store/store.ts index 14f523e31..4b80ec83a 100644 --- a/pkg/interface/src/logic/store/store.ts +++ b/pkg/interface/src/logic/store/store.ts @@ -5,15 +5,17 @@ import LocalReducer from '../reducers/local'; import ChatReducer from '../reducers/chat-update'; 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 GroupReducer from '../reducers/group-update'; -import PublishUpdateReducer from '../reducers/publish-update'; -import PublishResponseReducer from '../reducers/publish-response'; import LaunchReducer from '../reducers/launch-update'; import ConnectionReducer from '../reducers/connection'; +import {OrderedMap} from '../lib/OrderedMap'; +import { BigIntOrderedMap } from '../lib/BigIntOrderedMap'; export const homeAssociation = { "app-path": "/home", @@ -21,7 +23,7 @@ export const homeAssociation = { "group-path": "/home", metadata: { color: "0x0", - title: "Home", + title: "DMs + Drafts", description: "", "date-created": "", module: "", @@ -37,8 +39,6 @@ export default class GlobalStore extends BaseStore { contactReducer = new ContactReducer(); s3Reducer = new S3Reducer(); groupReducer = new GroupReducer(); - publishUpdateReducer = new PublishUpdateReducer(); - publishResponseReducer = new PublishResponseReducer(); launchReducer = new LaunchReducer(); connReducer = new ConnectionReducer(); @@ -73,7 +73,6 @@ export default class GlobalStore extends BaseStore { chat: {}, contacts: {}, graph: {}, - publish: {} }, groups: {}, groupKeys: new Set(), @@ -98,6 +97,21 @@ export default class GlobalStore extends BaseStore { dark: false, inbox: {}, chatSynced: null, + notifications: new BigIntOrderedMap(), + archivedNotifications: new BigIntOrderedMap(), + notificationsGroupConfig: [], + notificationsChatConfig: [], + notificationsGraphConfig: { + watchOnSelf: false, + mentions: false, + watching: [], + }, + notificationsCount: 0, + unreads: { + graph: {}, + group: {}, + chat: {}, + } }; } @@ -109,10 +123,9 @@ export default class GlobalStore extends BaseStore { this.contactReducer.reduce(data, this.state); this.s3Reducer.reduce(data, this.state); this.groupReducer.reduce(data, this.state); - this.publishUpdateReducer.reduce(data, this.state); - this.publishResponseReducer.reduce(data, this.state); this.launchReducer.reduce(data, this.state); this.connReducer.reduce(data, this.state); GraphReducer(data, this.state); + HarkReducer(data, this.state); } } diff --git a/pkg/interface/src/logic/store/type.ts b/pkg/interface/src/logic/store/type.ts index a7b666b62..88ef6d3ad 100644 --- a/pkg/interface/src/logic/store/type.ts +++ b/pkg/interface/src/logic/store/type.ts @@ -4,13 +4,19 @@ import { Path } from '~/types/noun'; import { Invites } from '~/types/invite-update'; import { Associations } from '~/types/metadata-update'; import { Rolodex } from '~/types/contact-update'; -import { Notebooks } from '~/types/publish-update'; import { Groups } from '~/types/group-update'; import { S3State } from '~/types/s3-update'; import { LaunchState, WeatherState } from '~/types/launch-update'; import { ConnectionStatus } from '~/types/connection'; -import { BackgroundConfig, LocalUpdateRemoteContentPolicy } from '~/types/local-update'; import {Graphs} from '~/types/graph-update'; +import { + Notifications, + NotificationGraphConfig, + GroupNotificationsConfig, + LocalUpdateRemoteContentPolicy, + BackgroundConfig, + Unreads +} from "~/types"; export interface StoreState { // local state @@ -46,11 +52,20 @@ export interface StoreState { userLocation: string | null; // publish state - notebooks: Notebooks; + notebooks: any; // Chat state chatInitialized: boolean; chatSynced: ChatHookUpdate | null; inbox: Inbox; pendingMessages: Map; + + archivedNotifications: Notifications; + notifications: Notifications; + notificationsGraphConfig: NotificationGraphConfig; + notificationsGroupConfig: GroupNotificationsConfig; + notificationsChatConfig: string[]; + notificationsCount: number, + doNotDisturb: boolean; + unreads: Unreads; } diff --git a/pkg/interface/src/logic/subscription/global.ts b/pkg/interface/src/logic/subscription/global.ts index d3ad08e9e..4e6d6e1e9 100644 --- a/pkg/interface/src/logic/subscription/global.ts +++ b/pkg/interface/src/logic/subscription/global.ts @@ -51,6 +51,10 @@ export default class GlobalSubscription extends BaseSubscription { this.subscribe('/all', 'launch'); this.subscribe('/all', 'weather'); this.subscribe('/keys', 'graph-store'); + this.subscribe('/updates', 'hark-store'); + this.subscribe('/updates', 'hark-graph-hook'); + this.subscribe('/updates', 'hark-group-hook'); + this.subscribe('/updates', 'hark-chat-hook'); } restart() { diff --git a/pkg/interface/src/types/graph-update.ts b/pkg/interface/src/types/graph-update.ts index c9fb6a19c..2f452f908 100644 --- a/pkg/interface/src/types/graph-update.ts +++ b/pkg/interface/src/types/graph-update.ts @@ -1,30 +1,44 @@ -import {Patp} from "./noun"; +import { Patp } from "./noun"; +import { BigIntOrderedMap } from "~/logic/lib/BigIntOrderedMap"; - -export interface TextContent { text: string; }; -export interface UrlContent { url: string; } -export interface CodeContent { expresssion: string; output: string; }; -export interface ReferenceContent { uid: string; } -export type Content = TextContent | UrlContent | CodeContent | ReferenceContent; +export interface TextContent { + text: string; +} +export interface UrlContent { + url: string; +} +export interface CodeContent { + expresssion: string; + output: string; +} +export interface ReferenceContent { + uid: string; +} +export interface MentionContent { + mention: string; +} +export type Content = + | TextContent + | UrlContent + | CodeContent + | ReferenceContent + | MentionContent; export interface Post { author: Patp; contents: Content[]; - hash?: string; + hash: string | null; index: string; pending?: boolean; signatures: string[]; - 'time-sent': number; + "time-sent": number; } - export interface GraphNode { children: Graph; post: Post; } -export type Graph = Map; +export type Graph = BigIntOrderedMap; export type Graphs = { [rid: string]: Graph }; - - diff --git a/pkg/interface/src/types/hark-update.ts b/pkg/interface/src/types/hark-update.ts new file mode 100644 index 000000000..44935831f --- /dev/null +++ b/pkg/interface/src/types/hark-update.ts @@ -0,0 +1,73 @@ +import _ from "lodash"; +import { Post } from "./graph-update"; +import { GroupUpdate } from "./group-update"; +import { BigIntOrderedMap } from "~/logic/lib/BigIntOrderedMap"; +import { Envelope } from './chat-update'; + +type GraphNotifDescription = "link" | "comment" | "note" | "mention"; + +export interface GraphNotifIndex { + graph: string; + group: string; + description: GraphNotifDescription; + module: string; +} + +export interface GroupNotifIndex { + group: string; + description: string; +} + +export interface ChatNotifIndex { + chat: string; + mention: boolean; +} + +export type NotifIndex = + | { graph: GraphNotifIndex } + | { group: GroupNotifIndex } + | { chat: ChatNotifIndex }; + +export type GraphNotificationContents = Post[]; + +export type GroupNotificationContents = GroupUpdate[]; + +export type ChatNotificationContents = Envelope[]; + +export type NotificationContents = + | { graph: GraphNotificationContents } + | { group: GroupNotificationContents } + | { chat: ChatNotificationContents }; + +export interface Notification { + read: boolean; + time: number; + contents: NotificationContents; +} + +export interface IndexedNotification { + index: NotifIndex; + notification: Notification; +} + +export type Timebox = IndexedNotification[]; + +export type Notifications = BigIntOrderedMap; + +export interface NotificationGraphConfig { + watchOnSelf: boolean; + mentions: boolean; + watching: WatchedIndex[] +} + +export interface Unreads { + chat: Record; + group: Record; + graph: Record; +} + +interface WatchedIndex { + graph: string; + index: string; +} +export type GroupNotificationsConfig = string[]; diff --git a/pkg/interface/src/types/index.ts b/pkg/interface/src/types/index.ts index 10135b03d..684763c57 100644 --- a/pkg/interface/src/types/index.ts +++ b/pkg/interface/src/types/index.ts @@ -6,15 +6,11 @@ export * from './contact-update'; export * from './global'; export * from './group-update'; export * from './graph-update'; +export * from './hark-update'; export * from './invite-update'; export * from './launch-update'; -export * from './link-listen-update'; -export * from './link-update'; export * from './local-update'; export * from './metadata-update'; export * from './noun'; -export * from './permission-update'; -export * from './publish-response'; -export * from './publish-update'; export * from './s3-update'; export * from './workspace'; diff --git a/pkg/interface/src/types/publish-response.ts b/pkg/interface/src/types/publish-response.ts deleted file mode 100644 index addc55921..000000000 --- a/pkg/interface/src/types/publish-response.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Notebooks, Notebook, Note, BookId, NoteId } from './publish-update'; -import { Patp } from './noun'; - -export type PublishResponse = - NotebooksResponse -| NotebookResponse -| NoteResponse -| NotesPageResponse -| CommentsPageResponse; - -interface NotebooksResponse { - type: 'notebooks'; - data: Notebooks; -} - -interface NotebookResponse { - type: 'notebook'; - data: Notebook; - host: Patp; - notebook: BookId; -} - -interface NoteResponse { - type: 'note'; - data: Note; - host: Patp; - notebook: BookId; - note: NoteId; -} - -interface NotesPageResponse { - type: 'notes-page'; - data: Note[]; - host: Patp; - notebook: BookId; - startIndex: number; - length: number; -} - -interface CommentsPageResponse { - type: 'comments-page'; - data: Comment[]; - host: Patp; - notebook: BookId; - note: NoteId; - startIndex: number; - length: number; -} diff --git a/pkg/interface/src/types/publish-update.ts b/pkg/interface/src/types/publish-update.ts deleted file mode 100644 index f3f1e3d4d..000000000 --- a/pkg/interface/src/types/publish-update.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { Patp, PatpNoSig, Path } from './noun'; - - -export type NoteId = string; -export type BookId = string; - - -export type PublishUpdate = - PublishUpdateAddBook -| PublishUpdateAddNote -| PublishUpdateAddComment -| PublishUpdateEditBook -| PublishUpdateEditNote -| PublishUpdateEditComment -| PublishUpdateDelBook -| PublishUpdateDelNote -| PublishUpdateDelComment; - - -type PublishUpdateBook = { - [s in Patp]: { - [b in BookId]: { - title: string; - 'date-created': number; - about: string; - 'num-notes': number; - 'num-unread': number; - comments: boolean; - 'writers-group-path': Path; - 'subscribers-group-path': Path; - }; - }; -} - -type PublishUpdateNote = { - [s in Patp]: { - [b in BookId]: { - 'note-id': NoteId; - author: Patp; - title: string; - 'date-created': string; - snippet: string; - file: string; - 'num-comments': number; - comments: Comment[]; - read: boolean; - pending: boolean; - }; - }; -}; - -interface PublishUpdateAddBook { - 'add-book': PublishUpdateBook; -} - -interface PublishUpdateEditBook { - 'edit-book': PublishUpdateBook; -} - -interface PublishUpdateDelBook { - 'del-book': { - host: Patp; - book: string; - } -} - -interface PublishUpdateAddNote { - 'add-note': PublishUpdateNote; -} - -interface PublishUpdateEditNote { - 'edit-note': PublishUpdateNote; -} - -interface PublishUpdateDelNote { - 'del-note': { - host: Patp; - book: BookId; - note: NoteId; - } -} - -interface PublishUpdateAddComment { - 'add-comment': { - who: Patp; - host: BookId; - note: NoteId; - body: string; - } -} - -interface PublishUpdateEditComment { - 'edit-comment': { - host: Patp; - book: BookId; - note: NoteId; - body: string; - comment: Comment; - } -} - -interface PublishUpdateDelComment { - 'del-comment': { - host: Patp; - book: BookId; - note: NoteId; - comment: string; - } -} - -export type Notebooks = { - [host in Patp]: { - [book in BookId]: Notebook; - } -} - - -export interface Notebook { - about: string; - comments: boolean; - 'date-created': number; - notes: Notes; - 'notes-by-date': NoteId[]; - 'num-notes': number; - 'num-unread': number; - subscribers: PatpNoSig[]; - 'subscribers-group-path': Path; - title: string; - 'writers-group-path': Path; -} - -export type Notes = { - [id in NoteId]: Note; -}; - -export interface Note { - author: Patp; - comments: Comment[]; - 'date-created': number; - file: string; - 'next-note': NoteId | null; - 'note-id': NoteId; - 'num-comments': number; - pending: boolean; - 'prev-note': NoteId | null; - read: boolean; - snippet: string; - title: string; -} - -export interface Comment { - [date: string]: { - author: Patp; - content: string; - 'date-created': number; - pending: boolean; - }; -} diff --git a/pkg/interface/src/views/App.js b/pkg/interface/src/views/App.js index 87dc0f57a..f3315809c 100644 --- a/pkg/interface/src/views/App.js +++ b/pkg/interface/src/views/App.js @@ -43,7 +43,7 @@ const Root = styled.div` * { scrollbar-width: thin; - scrollbar-color: ${ p => p.theme.colors.gray } ${ p => p.theme.colors.white }; + scrollbar-color: ${ p => p.theme.colors.gray } transparent; } /* Works on Chrome/Edge/Safari */ @@ -125,6 +125,9 @@ class App extends React.Component { const theme = state.dark ? dark : light; const { background } = state; + const notificationsCount = state.notificationsCount || 0; + const doNotDisturb = state.doNotDisturb || false; + return ( @@ -143,6 +146,8 @@ class App extends React.Component { connection={this.state.connection} subscription={this.subscription} ship={this.ship} + doNotDisturb={doNotDisturb} + notificationsCount={notificationsCount} /> @@ -150,7 +155,8 @@ class App extends React.Component { associations={state.associations} apps={state.launch} api={this.api} - dark={state.dark} + notifications={state.notificationsCount} + invites={state.invites} groups={state.groups} show={state.omniboxShown} /> diff --git a/pkg/interface/src/views/apps/chat/ChatResource.tsx b/pkg/interface/src/views/apps/chat/ChatResource.tsx index 54b950480..0d8c905f7 100644 --- a/pkg/interface/src/views/apps/chat/ChatResource.tsx +++ b/pkg/interface/src/views/apps/chat/ChatResource.tsx @@ -1,17 +1,16 @@ -import React, { useRef, useCallback } from "react"; -import { RouteComponentProps } from "react-router-dom"; -import { Col } from "@tlon/indigo-react"; +import React, { useRef, useCallback, useEffect } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { Col } from '@tlon/indigo-react'; import _ from 'lodash'; -import { Association } from "~/types/metadata-update"; -import { StoreState } from "~/logic/store/type"; -import { useFileDrag } from "~/logic/lib/useDrag"; -import ChatWindow from "./components/ChatWindow"; -import ChatInput from "./components/ChatInput"; -import GlobalApi from "~/logic/api/global"; -import { deSig } from "~/logic/lib/util"; -import { SubmitDragger } from "~/views/components/s3-upload"; -import { useLocalStorageState } from "~/logic/lib/useLocalStorageState"; +import { Association } from '~/types/metadata-update'; +import { StoreState } from '~/logic/store/type'; +import { useFileDrag } from '~/logic/lib/useDrag'; +import ChatWindow from './components/ChatWindow'; +import ChatInput from './components/ChatInput'; +import GlobalApi from '~/logic/api/global'; +import { SubmitDragger } from '~/views/components/s3-upload'; +import { useLocalStorageState } from '~/logic/lib/useLocalStorageState'; type ChatResourceProps = StoreState & { association: Association; @@ -20,22 +19,22 @@ type ChatResourceProps = StoreState & { } & RouteComponentProps; export function ChatResource(props: ChatResourceProps) { - const station = props.association["app-path"]; + const station = props.association['app-path']; if (!props.chatInitialized) { return null; } - const { envelopes, config } = (props.inbox?.[station]) ? props.inbox[station] : {envelopes: [], config: {}}; + const { envelopes, config } = (props.inbox?.[station]) ? props.inbox[station] : { envelopes: [], config: {} }; const { read, length } = (config) ? config : undefined; - const groupPath = props.association["group-path"]; + const groupPath = props.association['group-path']; const group = props.groups[groupPath]; const contacts = props.contacts[groupPath] || {}; const pendingMessages = (props.pendingMessages.get(station) || []).map( - (value) => ({ + value => ({ ...value, - pending: true, + pending: true }) ); @@ -62,7 +61,7 @@ export function ChatResource(props: ChatResourceProps) { const unreadCount = length - read; const unreadMsg = unreadCount > 0 && envelopes[unreadCount - 1]; - const [, owner, name] = station.split("/"); + const [, owner, name] = station.split('/'); const ourContact = contacts?.[window.ship]; const lastMsgNum = envelopes.length || 0; @@ -81,19 +80,28 @@ export function ChatResource(props: ChatResourceProps) { const { bind, dragging } = useFileDrag(onFileDrag); const [unsent, setUnsent] = useLocalStorageState>( - "chat-unsent", + 'chat-unsent', {} ); const appendUnsent = useCallback( - (u: string) => setUnsent((s) => ({ ...s, [station]: u })), + (u: string) => setUnsent(s => ({ ...s, [station]: u })), [station] ); - const clearUnsent = useCallback(() => setUnsent((s) => _.omit(s, station)), [ - station, + const clearUnsent = useCallback(() => setUnsent(s => _.omit(s, station)), [ + station ]); + const scrollTo = new URLSearchParams(location.search).get('msg'); + useEffect(() => { + const clear = () => { + props.history.replace(location.pathname); + }; + setTimeout(clear, 10000); + return clear; + }, [station]); + return ( {dragging && } @@ -118,6 +126,7 @@ export function ChatResource(props: ChatResourceProps) { hideNicknames={props.hideNicknames} hideAvatars={props.hideAvatars} location={props.location} + scrollTo={scrollTo ? parseInt(scrollTo, 10) : undefined} /> diff --git a/pkg/interface/src/views/apps/chat/components/ChatInput.tsx b/pkg/interface/src/views/apps/chat/components/ChatInput.tsx index 7e10e3b53..09ff23904 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatInput.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatInput.tsx @@ -1,13 +1,13 @@ import React, { Component } from 'react'; import ChatEditor from './chat-editor'; -import { S3Upload, SubmitDragger } from '~/views/components/s3-upload' ; +import { S3Upload } from '~/views/components/s3-upload' ; import { uxToHex } from '~/logic/lib/util'; import { Sigil } from '~/logic/lib/sigil'; import tokenizeMessage, { isUrl } from '~/logic/lib/tokenizeMessage'; import GlobalApi from '~/logic/api/global'; import { Envelope } from '~/types/chat-update'; -import { Contacts, S3Configuration } from '~/types'; -import { Row } from '@tlon/indigo-react'; +import { Contacts } from '~/types'; +import { Row, BaseImage, Box, Icon } from '@tlon/indigo-react'; interface ChatInputProps { api: GlobalApi; @@ -31,7 +31,6 @@ interface ChatInputState { uploadingPaste: boolean; } - export default class ChatInput extends Component { public s3Uploader: React.RefObject; private chatEditor: React.RefObject; @@ -42,7 +41,7 @@ export default class ChatInput extends Component this.state = { inCodeMode: false, submitFocus: false, - uploadingPaste: false, + uploadingPaste: false }; this.s3Uploader = React.createRef(); @@ -50,7 +49,6 @@ export default class ChatInput extends Component this.submit = this.submit.bind(this); this.toggleCode = this.toggleCode.bind(this); - } toggleCode() { @@ -82,8 +80,6 @@ export default class ChatInput extends Component } } - - submit(text) { const { props, state } = this; if (state.inCodeMode) { @@ -134,7 +130,6 @@ export default class ChatInput extends Component { url } ); } - } uploadError(error) { @@ -159,10 +154,11 @@ export default class ChatInput extends Component if (!this.readyToUpload()) { return; } - if (!this.s3Uploader.current || !this.s3Uploader.current.inputRef.current) return; + if (!this.s3Uploader.current || !this.s3Uploader.current.inputRef.current) +return; this.s3Uploader.current.inputRef.current.files = files; - const fire = document.createEvent("HTMLEvents"); - fire.initEvent("change", true, true); + const fire = document.createEvent('HTMLEvents'); + fire.initEvent('change', true, true); this.s3Uploader.current?.inputRef.current?.dispatchEvent(fire); } @@ -179,7 +175,7 @@ export default class ChatInput extends Component props.ourContact && ((props.ourContact.avatar !== null) && !props.hideAvatars) ) - ? + ? : className='cf' zIndex='0' > -
+ {avatar} -
+ onPaste={this.onPaste.bind(this)} placeholder='Message...' /> -
+ uploadError={this.uploadError.bind(this)} accept="*" > - -
-
- + + -
+ color={state.inCodeMode ? 'blue' : 'black'} + /> +
); } diff --git a/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx b/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx index 1cf993ddf..4299d39bc 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx @@ -18,24 +18,21 @@ export const UnreadMarker = React.forwardRef(({ dayBreak, when }, ref) => ( New messages below - {dayBreak - ? {moment(when).calendar()} - : null} )); export const DayBreak = ({ when }) => (
-

{moment(when).calendar()}

+

{moment(when).calendar(null, { sameElse: DATESTAMP_FORMAT })}

); interface ChatMessageProps { measure(element): void; msg: Envelope | IMessage; - previousMsg: Envelope | IMessage | undefined; - nextMsg: Envelope | IMessage | undefined; + previousMsg?: Envelope | IMessage; + nextMsg?: Envelope | IMessage; isLastRead: boolean; group: Group; association: Association; @@ -51,6 +48,7 @@ interface ChatMessageProps { unreadMarkerRef: React.RefObject; history: any; api: any; + highlighted?: boolean; } export default class ChatMessage extends Component { @@ -87,14 +85,16 @@ export default class ChatMessage extends Component { isLastMessage, unreadMarkerRef, history, - api + api, + highlighted, + fontSize } = this.props; const renderSigil = Boolean((nextMsg && msg.author !== nextMsg.author) || !nextMsg || msg.number === 1); const dayBreak = nextMsg && new Date(msg.when).getDate() !== new Date(nextMsg.when).getDate(); const containerClass = `${renderSigil - ? `cf pt2 pl3 lh-copy` + ? `cf pl2 lh-copy` : `items-top cf hide-child`} ${isPending ? 'o-40' : ''} ${className}` const timestamp = moment.unix(msg.when / 1000).format(renderSigil ? 'hh:mm a' : 'hh:mm'); @@ -118,7 +118,9 @@ export default class ChatMessage extends Component { isPending, history, api, - scrollWindow + scrollWindow, + highlighted, + fontSize }; const unreadContainerStyle = { @@ -127,9 +129,11 @@ export default class ChatMessage extends Component { return ( { + isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + render() { const { msg, @@ -178,17 +184,18 @@ export class MessageWithSigil extends PureComponent { hideAvatars, remoteContentPolicy, measure, - history, api, - scrollWindow + history, + scrollWindow, + fontSize } = this.props; const datestamp = moment.unix(msg.when / 1000).format(DATESTAMP_FORMAT); const contact = msg.author in contacts ? contacts[msg.author] : false; const showNickname = !hideNicknames && contact && contact.nickname; const name = showNickname ? contact.nickname : cite(msg.author); - const color = contact ? `#${uxToHex(contact.color)}` : '#000000'; - const sigilClass = contact ? '' : 'mix-blend-diff'; + const color = contact ? `#${uxToHex(contact.color)}` : this.isDark ? '#000000' :'#FFFFFF' + const sigilClass = contact ? '' : this.isDark ? 'mix-blend-diff' : 'mix-blend-darken'; let nameSpan = null; @@ -215,7 +222,7 @@ export class MessageWithSigil extends PureComponent { scrollWindow={scrollWindow} history={history} api={api} - className="fl pr3 v-top bg-white bg-gray0-d pt1" + className="fl pr3 v-top pt1" /> { fontSize={0} mr={3} mono={!showNickname} + fontWeight={(showNickname) ? '500' : '400'} className={`mw5 db truncate pointer`} ref={e => nameSpan = e} onClick={() => { @@ -240,7 +248,7 @@ export class MessageWithSigil extends PureComponent { {timestamp} {datestamp} - + ); @@ -249,19 +257,19 @@ export class MessageWithSigil extends PureComponent { export const MessageWithoutSigil = ({ timestamp, msg, remoteContentPolicy, measure }) => ( <> - {timestamp} + {timestamp} ); -export const MessageContent = ({ content, remoteContentPolicy, measure }) => { +export const MessageContent = ({ content, remoteContentPolicy, measure, fontSize }) => { if ('code' in content) { return ; } else if ('url' in content) { return ( - + { ); } else if ('me' in content) { return ( - + {content.me} ); } else if ('text' in content) { - return ; + return ; } else { return null; } }; export const MessagePlaceholder = ({ height, index, className = '', style = {}, ...props }) => ( -
-
- + + -
-
-
-

- -

-

-

-
- -
-
+ >
+
+ + + + + + + + + + + + + + + + + ); diff --git a/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx b/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx index 31b0ab6d0..ee56242f7 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx @@ -43,6 +43,7 @@ type ChatWindowProps = RouteComponentProps<{ hideNicknames: boolean; hideAvatars: boolean; remoteContentPolicy: LocalUpdateRemoteContentPolicy; + scrollTo?: number; } interface ChatWindowState { @@ -84,6 +85,10 @@ export default class ChatWindow extends Component { + if(this.props.scrollTo) { + this.scrollToUnread(); + } + this.setState({ initialized: true }); }, this.INITIALIZATION_MAX_TIME); } @@ -167,14 +172,16 @@ export default class ChatWindow extends Component { @@ -297,7 +304,8 @@ export default class ChatWindow extends Component { if (!props.isChatLoading) { return null; } return ( -
-
- + + -

Past messages are being restored

-
-
+ Past messages are being restored + + ); -} +}; diff --git a/pkg/interface/src/views/apps/chat/components/chat-editor.js b/pkg/interface/src/views/apps/chat/components/chat-editor.js index 936bd3989..2bf49bf7e 100644 --- a/pkg/interface/src/views/apps/chat/components/chat-editor.js +++ b/pkg/interface/src/views/apps/chat/components/chat-editor.js @@ -186,6 +186,7 @@ export default class ChatEditor extends Component { {...props} /> : this.messageChange(e, d, v)} diff --git a/pkg/interface/src/views/apps/chat/components/content/code.js b/pkg/interface/src/views/apps/chat/components/content/code.js index 3a133e06d..49808a394 100644 --- a/pkg/interface/src/views/apps/chat/components/content/code.js +++ b/pkg/interface/src/views/apps/chat/components/content/code.js @@ -15,12 +15,12 @@ export default class CodeContent extends Component { mono p='1' my='0' - fontSize='14px' + borderRadius='1' overflow='auto' maxHeight='10em' maxWidth='100%' style={{ whiteSpace: 'pre' }} - backgroundColor='scales.black10' + backgroundColor='washedGray' > {content.code.output[0].join('\n')} @@ -33,7 +33,7 @@ export default class CodeContent extends Component { mono my='0' p='1' - fontSize='14px' + borderRadius='1' overflow='auto' maxHeight='10em' maxWidth='100%' diff --git a/pkg/interface/src/views/apps/chat/components/content/text.js b/pkg/interface/src/views/apps/chat/components/content/text.js index d15b14ba9..26ec452ac 100644 --- a/pkg/interface/src/views/apps/chat/components/content/text.js +++ b/pkg/interface/src/views/apps/chat/components/content/text.js @@ -24,10 +24,30 @@ const DISABLED_INLINE_TOKENS = [ 'reference' ]; +const renderers = { + inlineCode: ({language, value}) => { + return {value} + }, + code: ({language, value}) => { + return + {value} + + } +}; + const MessageMarkdown = React.memo(props => ( { if ( node.type === 'blockquote' @@ -63,7 +83,7 @@ export default class TextContent extends Component { && (urbitOb.isValidPatp(group[2]) // valid patp? && (group[0] === content.text))) { // entire message is room name? return ( - + @@ -73,7 +93,7 @@ export default class TextContent extends Component { ); } else { return ( - + ); diff --git a/pkg/interface/src/views/apps/chat/components/overlay-sigil.js b/pkg/interface/src/views/apps/chat/components/overlay-sigil.js index ad64cdbba..6194b1631 100644 --- a/pkg/interface/src/views/apps/chat/components/overlay-sigil.js +++ b/pkg/interface/src/views/apps/chat/components/overlay-sigil.js @@ -4,6 +4,7 @@ import { ProfileOverlay, OVERLAY_HEIGHT } from './profile-overlay'; +import { Box, BaseImage } from '@tlon/indigo-react'; export class OverlaySigil extends PureComponent { constructor() { @@ -58,7 +59,7 @@ export class OverlaySigil extends PureComponent { const { hideAvatars } = props; const img = (props.contact && (props.contact.avatar !== null) && !hideAvatars) - ? + ? : ; return ( -
{state.profileClicked && ( @@ -91,7 +94,7 @@ export class OverlaySigil extends PureComponent { /> )} {img} -
+ ); } } diff --git a/pkg/interface/src/views/apps/chat/components/profile-overlay.js b/pkg/interface/src/views/apps/chat/components/profile-overlay.js index 2d9708cc8..ef6303c14 100644 --- a/pkg/interface/src/views/apps/chat/components/profile-overlay.js +++ b/pkg/interface/src/views/apps/chat/components/profile-overlay.js @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import { cite } from '~/logic/lib/util'; import { Sigil } from '~/logic/lib/sigil'; -import { Box, Col, Button, Text } from "@tlon/indigo-react"; +import { Box, Col, Button, Text, BaseImage } from '@tlon/indigo-react'; export const OVERLAY_HEIGHT = 250; @@ -51,8 +51,8 @@ export class ProfileOverlay extends PureComponent { const isOwn = window.ship === ship; - let img = contact?.avatar && !hideAvatars - ? + const img = contact?.avatar && !hideAvatars + ? : (isHidden) ? history.push('/~profile/identity') : history.push(`${history.location.pathname}/popover/profile`)} > Edit Identity diff --git a/pkg/interface/src/views/apps/chat/components/resubscribe-element.js b/pkg/interface/src/views/apps/chat/components/resubscribe-element.js index 6ac875705..d12e39332 100644 --- a/pkg/interface/src/views/apps/chat/components/resubscribe-element.js +++ b/pkg/interface/src/views/apps/chat/components/resubscribe-element.js @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import { Box, Text, Button } from '@tlon/indigo-react'; export class ResubscribeElement extends Component { onClickResubscribe() { @@ -9,21 +10,23 @@ export class ResubscribeElement extends Component { } render() { - const { props } = this; + const { props } = this; if (props.isChatUnsynced) { return ( -
-

+ + Your ship has been disconnected from the chat's host. This may be due to a bad connection, going offline, lack of permission, or an over-the-air update. -

- +
+ + ); } else { return null; diff --git a/pkg/interface/src/views/apps/chat/css/custom.css b/pkg/interface/src/views/apps/chat/css/custom.css index bc3f69166..898422b79 100644 --- a/pkg/interface/src/views/apps/chat/css/custom.css +++ b/pkg/interface/src/views/apps/chat/css/custom.css @@ -87,24 +87,14 @@ h2 { mix-blend-mode: difference; } +.mix-blend-darken { + mix-blend-mode: darken; +} + .placeholder-inter::placeholder { font-family: "Inter", sans-serif; } -/* spinner */ - -.spin-active { - animation: spin 2s infinite; -} - -@keyframes spin { - 0% {transform: rotate(0deg);} - 25% {transform: rotate(90deg);} - 50% {transform: rotate(180deg);} - 75% {transform: rotate(270deg);} - 100% {transform: rotate(360deg);} -} - .embed-container iframe { max-width: 100%; } @@ -225,16 +215,7 @@ blockquote { font-size: 14px; } -pre, code { - background-color: var(--light-gray); -} - -pre code { - background-color: transparent; - white-space: pre-wrap; -} - -code, .code, .chat.code .react-codemirror2 .CodeMirror * { +.chat.code .react-codemirror2 .CodeMirror * { font-family: 'Source Code Pro'; } diff --git a/pkg/interface/src/views/apps/dojo/components/input.js b/pkg/interface/src/views/apps/dojo/components/input.js deleted file mode 100644 index a3a910541..000000000 --- a/pkg/interface/src/views/apps/dojo/components/input.js +++ /dev/null @@ -1,119 +0,0 @@ -import React, { Component } from 'react'; -import { cite } from '~/logic/lib/util'; -import { Spinner } from '~/views/components/Spinner'; - -export class Input extends Component { - constructor(props) { - super(props); - this.state = { - awaiting: false, - type: 'Sending to Dojo' - }; - this.keyPress = this.keyPress.bind(this); - this.inputRef = React.createRef(); - } - - componentDidUpdate() { - if ( - !document.activeElement == document.body - || document.activeElement == this.inputRef.current - ) { - this.inputRef.current.focus(); - this.inputRef.current.setSelectionRange(this.props.cursor, this.props.cursor); - } - } - - keyPress(e) { - if ((e.getModifierState('Control') || event.getModifierState('Meta')) - && e.key === 'v') { - return; - } - - e.preventDefault(); - - const allowedKeys = [ - 'Enter', 'Backspace', 'ArrowLeft', 'ArrowRight', 'Tab' - ]; - - if ((e.key.length > 1) && (!(allowedKeys.includes(e.key)))) { - return; - } - - // submit on enter - if (e.key === 'Enter') { - this.setState({ awaiting: true, type: 'Sending to Dojo' }); - this.props.api.soto('ret').then(() => { - this.setState({ awaiting: false }); - }); - } else if ((e.key === 'Backspace') && (this.props.cursor > 0)) { - this.props.store.doEdit({ del: this.props.cursor - 1 }); - return this.props.store.setState({ cursor: this.props.cursor - 1 }); - } else if (e.key === 'Backspace') { - return; - } else if (e.key.startsWith('Arrow')) { - if (e.key === 'ArrowLeft') { - if (this.props.cursor > 0) { - this.props.store.setState({ cursor: this.props.cursor - 1 }); - } - } else if (e.key === 'ArrowRight') { - if (this.props.cursor < this.props.input.length) { - this.props.store.setState({ cursor: this.props.cursor + 1 }); - } - } - } - - // tab completion - else if (e.key === 'Tab') { - this.setState({ awaiting: true, type: 'Getting suggestions' }); - this.props.api.soto({ tab: this.props.cursor }).then(() => { - this.setState({ awaiting: false }); - }); - } - - // capture and transmit most characters - else { - this.props.store.doEdit({ ins: { cha: e.key, at: this.props.cursor } }); - this.props.store.setState({ cursor: this.props.cursor + 1 }); - } - } - - render() { - return ( -
-
{cite(this.props.ship)}:dojo -
- - {this.props.prompt} - - this.props.store.setState({ cursor: e.target.selectionEnd })} - onKeyDown={this.keyPress} - onPaste={(e) => { - const clipboardData = e.clipboardData || window.clipboardData; - const paste = Array.from(clipboardData.getData('Text')); - paste.reduce(async (previous, next) => { - await previous; - this.setState({ cursor: this.props.cursor + 1 }); - return this.props.store.doEdit({ ins: { cha: next, at: this.props.cursor } }); - }, Promise.resolve()); - e.preventDefault(); - }} - ref={this.inputRef} - defaultValue={this.props.input} - /> - -
- ); - } -} - -export default Input; diff --git a/pkg/interface/src/views/apps/dojo/components/lib/sole.js b/pkg/interface/src/views/apps/dojo/components/lib/sole.js deleted file mode 100644 index 368ceae25..000000000 --- a/pkg/interface/src/views/apps/dojo/components/lib/sole.js +++ /dev/null @@ -1,157 +0,0 @@ -// See /lib/sole/hoon - -const str = JSON.stringify; - -export class Share { - constructor(buf, ven, leg) { - if (buf == null) { - buf = ''; - } - this.buf = buf; - if (ven == null) { - ven = [0, 0]; - } - this.ven = ven; - if (leg == null) { - leg = []; - } - this.leg = leg; - } - - abet() { - return { - buf: this.buf, - leg: this.leg.slice(), - ven: this.ven.slice() - }; - } - - apply(ted) { - switch (false) { - case 'nop' !== ted: return; - case !ted.map: return ted.map(this.apply, this); - default: switch (Object.keys(ted)[0]) { - case 'set': return this.buf = ted.set; - case 'del': return this.buf = this.buf.slice(0, ted.del) + this.buf.slice(ted.del + 1); - case 'ins': - var { at, cha } = ted.ins; - return this.buf = this.buf.slice(0, at) + cha + this.buf.slice(at); - default: throw `%sole-edit -lost.${str(ted)}`; - } - } - } - - transmute(sin, dex) { - switch (false) { - case (sin !== 'nop') && (dex !== 'nop'): return dex; - case !sin.reduce: - return sin.reduce(((dex, syn) => this.transmute(syn, dex)), dex); - case !dex.map: return dex.map(dax => this.transmute(sin, dax)); - case dex.set === undefined: return dex; - default: switch (Object.keys(sin)[0]) { - case 'set': return 'nop'; - case 'del': - if (sin.del === dex.del) { - return 'nop'; - } - dex = { ...dex }; - switch (Object.keys(dex)[0]) { - case 'del': if (sin.del < dex.del) { - dex.del--; - } - break; - case 'ins': if (sin.del < dex.ins.at) { - dex.ins.at--; - } - break; - } - return dex; - case 'ins': - dex = { ...dex }; - var { at, cha } = sin.ins; - switch (Object.keys(dex)[0]) { - case 'del': if (at < dex.del) { - dex.del++; - } - break; - case 'ins': if ((at < dex.ins.at) || - ((at === dex.ins.at) && !(cha <= dex.ins.cha))) { - dex.ins.at++; - } else if (at >= dex.ins.at) { - dex.ins.at = at; // NOTE possibly unpredictable behaviour - dex.ins.at++; // for sole inserts that aren't tabs - } - break; - } - return dex; - default: throw `%sole-edit -lost.${str(sin)}`; - } - } - } - - commit(ted) { - this.ven[0]++; - this.leg.push(ted); - return this.apply(ted); - } - - inverse(ted) { - switch (false) { - case 'nop' !== ted: return ted; - case !ted.map: - return ted.map((tad) => { - const res = this.inverse(tad); - this.apply(tad); - return res; - }).reverse(); - default: switch (Object.keys(ted)[0]) { - case 'set': return { set: this.buf }; - case 'ins': return { del: ted.ins }; - case 'del': return { ins: { at: ted.del, cha: this.buf[ted.del] } }; - default: throw `%sole-edit -lost.${str(ted)}`; - } - } - } - - receive({ ler, ted }) { - if (!(ler[1] === this.ven[1])) { - throw `-out-of-sync.[${str(ler)} ${str(this.ven)}]`; - } - this.leg = this.leg.slice((this.leg.length + ler[0]) - this.ven[0]); - const dat = this.transmute(this.leg, ted); - this.ven[1]++; - this.apply(dat); - return dat; - } - - remit() { - throw 'stub'; - } - - transmit(ted) { - const act = { ted, ler: [this.ven[1], this.ven[0]] }; - this.commit(ted); - return act; - } - - transceive({ ler, ted }) { - const old = new Share(this.buf); - const dat = this.receive({ ler, ted }); - return old.inverse(dat); - } - - transpose(ted, pos) { - if (pos === undefined) { - return this.transpose(this.leg, ted); - } else { - let left; - return ((left = - (this.transmute( - ted, { ins: { at: pos } })).ins) != null ? - left : { at: 0 } - ).at; - } - } -}; - -export default Share; diff --git a/pkg/interface/src/views/apps/dojo/css/custom.css b/pkg/interface/src/views/apps/dojo/css/custom.css deleted file mode 100644 index fd3c5b6cf..000000000 --- a/pkg/interface/src/views/apps/dojo/css/custom.css +++ /dev/null @@ -1,11 +0,0 @@ -input#dojo { - background-color: inherit; - color: inherit; -} - -/* responsive */ -@media all and (max-width: 34.375em) { - .h-100-m40-s { - height: calc(100% - 40px); - } -} diff --git a/pkg/interface/src/views/apps/dojo/store.js b/pkg/interface/src/views/apps/dojo/store.js deleted file mode 100644 index c5a755da8..000000000 --- a/pkg/interface/src/views/apps/dojo/store.js +++ /dev/null @@ -1,95 +0,0 @@ -import Share from './components/lib/sole'; -export default class Store { - constructor() { - this.state = this.initialState(); - this.sync = this.sync.bind(this); - this.print = this.print.bind(this); - this.buffer = new Share(); - } - - initialState() { - return { - txt: [], - prompt: '', - cursor: 0, - input: '' - }; - } - - clear() { - this.handleEvent({ - data: { clear: true } - }); - } - - handleEvent(data) { - // recursive handler - if (data.data) { - var dojoReply = data.data; - } else { - var dojoReply = data; - } - - if (dojoReply.clear) { - this.setState(this.initialState(), (() => { - return; - })); - } - - // %mor sole-effects are nested, so throw back to handler - if (dojoReply.map) { - return dojoReply.map(reply => this.handleEvent(reply)); - } - - switch (Object.keys(dojoReply)[0]) { - case 'txt': - return this.print(dojoReply.txt); - case 'tab': - this.print(dojoReply.tab.match + ' ' + dojoReply.tab.info); - return; - case 'tan': - return dojoReply.tan.split('\n').map(this.print); - case 'pro': - return this.setState({ prompt: dojoReply.pro.cad }); - case 'hop': - return this.setState({ cursor: dojoReply.hop }); - case 'det': - this.buffer.receive(dojoReply.det); - return this.sync(dojoReply.det.ted); - case 'act': - switch (dojoReply.act) { - case 'clr': return this.setState({ txt: [] }); - case 'nex': return this.setState({ - input: '', - cursor: 0 - }); - } - break; - default: console.log(dojoReply); - } - } - - doEdit(ted) { - const detSend = this.buffer.transmit(ted); - this.sync(ted); - return this.api.soto({ det: detSend }); - } - - print(txt) { - const textLog = this.state.txt; - textLog.push(txt); - return this.setState({ txt: textLog }); - } - - sync(ted) { - return this.setState({ - input: this.buffer.buf, - cursor: this.buffer.transpose(ted, this.state.cursor) - }); - } - - setStateHandler(setState) { - this.setState = setState; - } -} - diff --git a/pkg/interface/src/views/apps/graph/app.js b/pkg/interface/src/views/apps/graph/app.js index bfe47dc91..9e1112713 100644 --- a/pkg/interface/src/views/apps/graph/app.js +++ b/pkg/interface/src/views/apps/graph/app.js @@ -25,6 +25,10 @@ export default class GraphApp extends PureComponent { render={ (props) => { const resource = `${deSig(props.match.params.ship)}/${props.match.params.name}`; + const { ship, name } = props.match.params; + const path = `/ship/~${deSig(ship)}/${name}`; + const association = associations.graph[path]; + const autoJoin = () => { try { @@ -33,13 +37,7 @@ export default class GraphApp extends PureComponent { props.match.params.name ); - if (props.match.params.module) { - props.history.push( - `/~${props.match.params.module}/${resource}` - ); - } else { - props.history.push('/'); - } + } catch(err) { setTimeout(autoJoin, 2000); } @@ -47,8 +45,8 @@ export default class GraphApp extends PureComponent { if(!graphKeys.has(resource)) { autoJoin(); - } else if(props.match.params.module) { - props.history.push(`/~${props.match.params.module}/${resource}`); + } else if(!!association) { + props.history.push(`/~landscape/home/resource/${association.metadata.module}${path}`); } return (
diff --git a/pkg/interface/src/views/apps/launch/app.js b/pkg/interface/src/views/apps/launch/app.js index 0d85f11f5..4d7eea7e3 100644 --- a/pkg/interface/src/views/apps/launch/app.js +++ b/pkg/interface/src/views/apps/launch/app.js @@ -1,100 +1,94 @@ -import React from 'react'; +import React, { useState } from 'react'; import Helmet from 'react-helmet'; +import styled from 'styled-components'; -import { Box, Row, Icon, Text, Center } from '@tlon/indigo-react'; -import { uxToHex, adjustHex } from '~/logic/lib/util'; +import { Box, Row, Icon, Text } from '@tlon/indigo-react'; import './css/custom.css'; -import { Sigil } from '~/logic/lib/sigil'; import Tiles from './components/tiles'; import Tile from './components/tiles/tile'; import Welcome from './components/welcome'; import Groups from './components/Groups'; +import { writeText } from '~/logic/lib/util'; -export default class LaunchApp extends React.Component { - componentDidMount() { - // preload spinner asset - new Image().src = '/~landscape/img/Spinner.png'; +const ScrollbarLessBox = styled(Box)` + scrollbar-width: none !important; + + ::-webkit-scrollbar { + display: none; } +`; - render() { - const { props } = this; - const contact = props.contacts?.['/~/default']?.[window.ship]; - const sigilColor = contact?.color - ? `#${uxToHex(contact.color)}` - : props.dark - ? '#FFFFFF' - : '#000000'; +export default function LaunchApp(props) { + const [hashText, setHashText] = useState(props.baseHash); - return ( - <> - - OS1 - Home - - - - - - - - - Home - - - - -
- -
-
- -
- -
+ return ( + <> + + OS1 - Home + + + - {props.baseHash} + + + + + DMs + Drafts + + + + + + - - ); - } + + { + writeText(props.baseHash); + setHashText('copied'); + setTimeout(() => { + setHashText(props.baseHash); + }, 2000); + }} + > + {hashText || props.baseHash} + + + ); } - diff --git a/pkg/interface/src/views/apps/launch/components/Groups.tsx b/pkg/interface/src/views/apps/launch/components/Groups.tsx index 4f9302741..98692be60 100644 --- a/pkg/interface/src/views/apps/launch/components/Groups.tsx +++ b/pkg/interface/src/views/apps/launch/components/Groups.tsx @@ -1,11 +1,11 @@ import React from "react"; -import { Box, Text } from "@tlon/indigo-react"; -import { Link } from "react-router-dom"; +import { Box, Text, Col } from "@tlon/indigo-react"; +import f from "lodash/fp"; +import _ from "lodash"; -import { useLocalStorageState } from "~/logic/lib/useLocalStorageState"; -import { Associations, Association } from "~/types"; +import { Associations, Association, Unreads } from "~/types"; import { alphabeticalOrder } from "~/logic/lib/util"; -import Tile from '../components/tiles/tile'; +import Tile from "../components/tiles/tile"; interface GroupsProps { associations: Associations; @@ -14,72 +14,59 @@ interface GroupsProps { const sortGroupsAlph = (a: Association, b: Association) => alphabeticalOrder(a.metadata.title, b.metadata.title); -export default function Groups(props: GroupsProps & Parameters[0]) { - const { associations, invites, api, ...boxProps } = props; +const getKindUnreads = (associations: Associations) => (path: string) => ( + kind: "chat" | "graph" +): ((unreads: Unreads) => number) => + f.flow( + (x) => x[kind], + f.pickBy((_v, key) => associations[kind]?.[key]?.["group-path"] === path), + f.values, + f.reduce(f.add, 0) + ); - const incomingGroups = Object.values(invites?.['/contacts'] || {}); - const getKeyByValue = (object, value) => { - return Object.keys(object).find(key => object[key] === value); - } +export default function Groups(props: GroupsProps & Parameters[0]) { + const { associations, unreads, ...boxProps } = props; const groups = Object.values(associations?.contacts || {}) + .filter((e) => e?.["group-path"] in props.groups) .sort(sortGroupsAlph); - - const acceptInvite = (invite) => { - const [, , ship, name] = invite.path.split('/'); - const resource = { ship, name }; - return api.contacts.join(resource).then(() => { - api.invite.accept('/contacts', getKeyByValue(invites['/contacts'], invite)); - }); - }; + const getUnreads = getKindUnreads(associations || {}); return ( - - {incomingGroups.map((invite) => ( - - You have been invited to: - {invite.path.slice(6)} - - acceptInvite(invite)} - color='blue' - mr='2' - cursor='pointer'> - Accept - - api.invite.decline('/contacts', getKeyByValue(invites['/contacts'], invite))} - cursor='pointer'> - Reject - - - - ))} - {groups.map((group) => ( - - {group.metadata.title} - - ))} - + <> + {groups.map((group) => { + const path = group?.["group-path"]; + const unreadCount = (["chat", "graph"] as const) + .map(getUnreads(path)) + .map((f) => f(unreads)) + .reduce(f.add, 0); + return ( + + ); + })} + + ); +} + +interface GroupProps { + path: string; + title: string; + unreads: number; +} +function Group(props: GroupProps) { + const { path, title, unreads } = props; + return ( + + + {title} + {unreads > 0 && + ({unreads} update{unreads !== 1 && 's'} ) + } + + ); } diff --git a/pkg/interface/src/views/apps/launch/components/tiles/basic.js b/pkg/interface/src/views/apps/launch/components/tiles/basic.js index c511432a8..6206dd78b 100644 --- a/pkg/interface/src/views/apps/launch/components/tiles/basic.js +++ b/pkg/interface/src/views/apps/launch/components/tiles/basic.js @@ -9,11 +9,11 @@ export default class BasicTile extends React.PureComponent { return ( - - {props.title === 'Dojo' + + {props.title === 'Terminal' ? { + { const d = [ 'M', CX, CY, 'L', x1, y1, - 'A', RADIUS, RADIUS, '0', (isLarge ? '1' : '0'), '1', x2, y2, 'z' + 'A', RADIUS, RADIUS, '0', '1', '1', x2, y2, 'z' ].join(' '); return ; diff --git a/pkg/interface/src/views/apps/launch/components/tiles/tile.js b/pkg/interface/src/views/apps/launch/components/tiles/tile.js index 3d6d8d966..348234d5e 100644 --- a/pkg/interface/src/views/apps/launch/components/tiles/tile.js +++ b/pkg/interface/src/views/apps/launch/components/tiles/tile.js @@ -1,8 +1,24 @@ import React from 'react'; import { Link } from 'react-router-dom'; +import styled from 'styled-components'; + import defaultApps from '~/logic/lib/default-apps'; -import { Box, DisclosureBox } from "@tlon/indigo-react"; +import { Box } from "@tlon/indigo-react"; + +const SquareBox = styled(Box)` + &::before { + content: ""; + display: inline-block; + width: 1px; + height: 0; + padding-bottom: 100%; + } + & > * { + position: absolute; + top: 0; + } +`; const routeList = defaultApps.map(a => `/~${a}`); export default class Tile extends React.Component { @@ -26,11 +42,11 @@ export default class Tile extends React.Component { return ( - {childElement} - + ); } } diff --git a/pkg/interface/src/views/apps/launch/components/tiles/weather.js b/pkg/interface/src/views/apps/launch/components/tiles/weather.js index 64140b271..b973e3729 100644 --- a/pkg/interface/src/views/apps/launch/components/tiles/weather.js +++ b/pkg/interface/src/views/apps/launch/components/tiles/weather.js @@ -23,7 +23,7 @@ export default class WeatherTile extends React.Component { }, (err) => { console.log(err); }, { maximumAge: Infinity, timeout: 10000 }); - this.props.api.weather(latlng); + this.props.api.launch.weather(latlng); this.setState({ manualEntry: !this.state.manualEntry }); }); } diff --git a/pkg/interface/src/views/apps/links/LinkResource.tsx b/pkg/interface/src/views/apps/links/LinkResource.tsx index 571f9b2d1..e269ac012 100644 --- a/pkg/interface/src/views/apps/links/LinkResource.tsx +++ b/pkg/interface/src/views/apps/links/LinkResource.tsx @@ -1,6 +1,7 @@ import React, { useEffect } from "react"; import { Box, Row, Col, Center, LoadingSpinner } from "@tlon/indigo-react"; import { Switch, Route, Link } from "react-router-dom"; +import bigInt from 'big-integer'; import GlobalApi from "~/logic/api/global"; import { StoreState } from "~/logic/store/type"; @@ -11,8 +12,7 @@ import { RouteComponentProps } from "react-router-dom"; import { LinkItem } from "./components/link-item"; import { LinkSubmit } from "./components/link-submit"; import { LinkPreview } from "./components/link-preview"; -import { CommentSubmit } from "./components/comment-submit"; -import { Comments } from "./components/comments"; +import { Comments } from "~/views/components/comments"; import "./css/custom.css"; @@ -36,6 +36,7 @@ export function LinkResource(props: LinkResourceProps) { hideAvatars, hideNicknames, remoteContentPolicy, + history } = props; const appPath = association["app-path"]; @@ -48,6 +49,7 @@ export function LinkResource(props: LinkResourceProps) { ? associations.graph[appPath] : { metadata: {} }; const contactDetails = contacts[resource["group-path"]] || {}; + const group = groups[resource["group-path"]] || {}; const graph = graphs[resourcePath] || null; useEffect(() => { @@ -68,14 +70,14 @@ export function LinkResource(props: LinkResourceProps) { render={(props) => { return ( - + - + {Array.from(graph).map(([date, node]) => { const contact = contactDetails[node.post.author]; return ( ); })} @@ -91,15 +95,15 @@ export function LinkResource(props: LinkResourceProps) { }} /> { - const indexArr = props.match.params.index.split("-"); + const index = bigInt(props.match.params.index); + const editCommentId = props.match.params.commentId || null; - if (indexArr.length <= 1) { + if (!index) { return
Malformed URL
; } - const index = parseInt(indexArr[1], 10); const node = !!graph ? graph.get(index) : null; if (!node) { @@ -119,22 +123,19 @@ export function LinkResource(props: LinkResourceProps) { commentNumber={node.children.size} remoteContentPolicy={remoteContentPolicy} /> - - - ); diff --git a/pkg/interface/src/views/apps/links/components/comment-item.js b/pkg/interface/src/views/apps/links/components/comment-item.js deleted file mode 100644 index 1f37e045b..000000000 --- a/pkg/interface/src/views/apps/links/components/comment-item.js +++ /dev/null @@ -1,45 +0,0 @@ -import React, { Component } from 'react'; -import { Sigil } from '~/logic/lib/sigil'; -import { cite } from '~/logic/lib/util'; -import moment from 'moment'; -import { Box, Text, Row } from '@tlon/indigo-react'; -import RichText from '~/views/components/RichText'; - -export const CommentItem = (props) => { - const content = props.post.contents[0].text; - const timeSent = - moment.unix(props.post['time-sent'] / 1000).format('hh:mm a'); - - const showAvatar = props.avatar && !props.hideAvatars; - const showNickname = props.nickname && !props.hideNicknames; - const img = showAvatar - ? - : ; - - return ( - - - {img} - - - {showNickname ? props.nickname : cite(props.post.author)} - - {timeSent} - - - - - - {content} - - - - - ); -} - diff --git a/pkg/interface/src/views/apps/links/components/comment-submit.js b/pkg/interface/src/views/apps/links/components/comment-submit.js deleted file mode 100644 index baff2d4a8..000000000 --- a/pkg/interface/src/views/apps/links/components/comment-submit.js +++ /dev/null @@ -1,84 +0,0 @@ -import React, { Component } from 'react'; -import { Spinner } from '~/views/components/Spinner'; -import { createPost } from '~/logic/api/graph'; -import { deSig } from "~/logic/lib/util"; - - -export class CommentSubmit extends Component { - constructor(props) { - super(props); - - this.state = { - comment: '', - commentFocus: false, - disabled: false - }; - } - - onClickPost() { - const parentIndex = this.props.parentIndex || ''; - let post = createPost([ - { text: this.state.comment }, - ], parentIndex); - - this.setState({ disabled: true }, () => { - this.props.api.graph.addPost( - `~${deSig(this.props.ship)}`, - this.props.name, - post - ).then((r) => { - this.setState({ - disabled: false, - comment: '' - }); - }); - }); - } - - setComment(event) { - this.setState({ comment: event.target.value }); - } - - render() { - const { state, props } = this; - const focus = (state.commentFocus) - ? 'b--black b--white-d' - : 'b--gray4 b--gray2-d'; - - const activeClasses = state.comment - ? 'black white-d pointer' - : 'gray2 b--gray2'; - - return ( -
-