Merge pull request #142 from tloncorp/hm/desk-renaming

meta: the final migration
This commit is contained in:
Hunter Miller 2023-09-20 12:19:02 -05:00 committed by GitHub
commit d499216289
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 1921 additions and 2028 deletions

View File

@ -20,7 +20,7 @@ jobs:
uses: "google-github-actions/setup-gcloud@v1"
- id: deploy
name: Deploy
run: ./.github/helpers/deploy.sh tloncorp/landscape garden binnec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
run: ./.github/helpers/deploy.sh tloncorp/landscape landscape binnec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
env:
SSH_SEC_KEY: ${{ secrets.GCP_SSH_SEC_KEY }}
SSH_PUB_KEY: ${{ secrets.GCP_SSH_PUB_KEY }}

View File

@ -20,7 +20,7 @@ jobs:
uses: "google-github-actions/setup-gcloud@v1"
- id: deploy
name: Deploy
run: ./.github/helpers/deploy.sh tloncorp/landscape garden doznec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
run: ./.github/helpers/deploy.sh tloncorp/landscape landscape doznec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
env:
SSH_SEC_KEY: ${{ secrets.GCP_SSH_SEC_KEY }}
SSH_PUB_KEY: ${{ secrets.GCP_SSH_PUB_KEY }}

View File

@ -20,7 +20,7 @@ jobs:
uses: "google-github-actions/setup-gcloud@v1"
- id: deploy
name: Deploy
run: ./.github/helpers/deploy.sh tloncorp/landscape garden marnec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
run: ./.github/helpers/deploy.sh tloncorp/landscape landscape marnec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
env:
SSH_SEC_KEY: ${{ secrets.GCP_SSH_SEC_KEY }}
SSH_PUB_KEY: ${{ secrets.GCP_SSH_PUB_KEY }}

View File

@ -9,7 +9,7 @@ on:
jobs:
deploy:
runs-on: ubuntu-latest
name: "Release to ~mister-dister-dozzod-dozzod (livenet)"
name: "Release to ~lander-dister-dozzod-dozzod (livenet)"
steps:
- uses: actions/checkout@v3
- id: 'auth'
@ -21,7 +21,7 @@ jobs:
- id: deploy
name: Deploy
run:
./.github/helpers/deploy.sh tloncorp/landscape garden mister-dister-dozzod-dozzod us-central1-b mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
./.github/helpers/deploy.sh tloncorp/landscape landscape mister-dister-dozzod-dozzod us-central1-b mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
env:
SSH_SEC_KEY: ${{ secrets.GCP_SSH_SEC_KEY }}
SSH_PUB_KEY: ${{ secrets.GCP_SSH_PUB_KEY }}

View File

@ -67,7 +67,7 @@ jobs:
deploy:
runs-on: ubuntu-latest
needs: glob
name: "Deploy a glob to ~wannec-dozzod-marzod (devstream)"
name: "Deploy a glob to ~wannec-dozzod-marnus (devstream)"
steps:
- uses: actions/checkout@v3
with:
@ -82,7 +82,7 @@ jobs:
- id: deploy
name: Deploy
run:
./.github/helpers/deploy.sh tloncorp/landscape garden wannec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
./.github/helpers/deploy.sh tloncorp/landscape landscape wannec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }}
env:
SSH_SEC_KEY: ${{ secrets.GCP_SSH_SEC_KEY }}
SSH_PUB_KEY: ${{ secrets.GCP_SSH_PUB_KEY }}

View File

@ -1,254 +0,0 @@
/- sur=hark-store
^?
=, sur
=< [. sur]
|%
++ enjs
=, enjs:format
|%
++ update
|= upd=^update
^- json
%+ frond -.upd
?+ -.upd a+~
%added (notification +.upd)
%add-note (add-note +.upd)
%timebox (timebox +.upd)
%more (more +.upd)
%read-each (read-each +.upd)
%read-count (place +.upd)
%unread-each (read-each +.upd)
%unread-count (unread-count +.upd)
%saw-place (saw-place +.upd)
%all-stats (all-stats +.upd)
%del-place (place +.upd)
::%read-note (index +.upd)
::%note-read (note-read +.upd)
%archived (archived +.upd)
==
::
++ add-note
|= [bi=^bin bo=^body]
%- pairs
:~ bin+(bin bi)
body+(body bo)
==
::
++ saw-place
|= [p=^place t=(unit ^time)]
%- pairs
:~ place+(place p)
time+?~(t ~ (time u.t))
==
::
++ archived
|= [t=^time l=^lid n=^notification]
%- pairs
:~ lid+(lid l)
time+s+(scot %ud t)
notification+(notification n)
==
::
++ note-read
|= *
(pairs ~)
::
++ all-stats
|= places=(map ^place ^stats)
^- json
:- %a
^- (list json)
%+ turn ~(tap by places)
|= [p=^place s=^stats]
%- pairs
:~ stats+(stats s)
place+(place p)
==
::
++ stats
|= s=^stats
^- json
%- pairs
:~ each+a+(turn ~(tap in each.s) (cork spat (lead %s)))
last+(time last.s)
count+(numb count.s)
==
++ more
|= upds=(list ^update)
^- json
a+(turn upds update)
::
++ place
|= =^place
%- pairs
:~ desk+s+desk.place
path+s+(spat path.place)
==
::
++ bin
|= =^bin
%- pairs
:~ place+(place place.bin)
path+s+(spat path.bin)
==
++ notification
|= ^notification
^- json
%- pairs
:~ time+(time date)
bin+(^bin bin)
body+(bodies body)
==
++ bodies
|= bs=(list ^body)
^- json
a+(turn bs body)
::
++ contents
|= cs=(list ^content)
^- json
a+(turn cs content)
::
++ content
|= c=^content
^- json
%+ frond -.c
?- -.c
%ship s+(scot %p ship.c)
%text s+cord.c
==
::
++ body
|= ^body
^- json
%- pairs
:~ title+(contents title)
content+(contents content)
time+(^time time)
link+s+(spat link)
==
::
++ binned-notification
|= [=^bin =^notification]
%- pairs
:~ bin+(^bin bin)
notification+(^notification notification)
==
++ lid
|= l=^lid
^- json
%+ frond -.l
?- -.l
?(%seen %unseen) ~
%archive s+(scot %ud time.l)
==
::
++ timebox
|= [li=^lid l=(list ^notification)]
^- json
%- pairs
:~ lid+(lid li)
notifications+a+(turn l notification)
==
::
++ read-each
|= [p=^place pax=^path]
%- pairs
:~ place+(place p)
path+(path pax)
==
::
++ unread-count
|= [p=^place inc=? count=@ud]
%- pairs
:~ place+(place p)
inc+b+inc
count+(numb count)
==
--
++ dejs
=, dejs:format
|%
++ ship (su ;~(pfix sig fed:ag))
:: TODO: fix +stab
::
++ pa
|= j=json
^- path
?> ?=(%s -.j)
?: =('/' p.j) /
(stab p.j)
::
++ place
%- ot
:~ desk+so
path+pa
==
::
++ bin
%- ot
:~ path+pa
place+place
==
::
++ read-each
%- ot
:~ place+place
path+pa
==
::
:: parse date as @ud
:: TODO: move to zuse
++ sd
|= jon=json
^- @da
?> ?=(%s -.jon)
`@da`(rash p.jon dem:ag)
::
++ lid
%- of
:~ archive+sd
unseen+ul
seen+ul
==
::
++ archive
%- ot
:~ lid+lid
bin+bin
==
++ content
%- of
:~ text+so
ship+ship
==
::
++ body
%- ot
:~ title+(ar content)
content+(ar content)
time+di
binned+pa
link+pa
==
::
++ add-note
%- ot
:~ bin+bin
body+body
==
::
++ action
^- $-(json ^action)
%- of
:~ archive-all+ul
archive+archive
opened+ul
read-count+place
read-each+read-each
read-note+bin
add-note+add-note
==
--
--

View File

@ -1,159 +0,0 @@
^?
::
:: %hark-store: Notification, unreads store
::
:: Timeboxing & binning:
::
:: Unread notifications accumulate in $unreads. They are grouped by
:: their $bin. A notification may become read by either:
:: a) being read by a %read-count or %read-each or %read-note
:: b) being read by a %seen
::
:: If a) then we insert the corresponding bin into $reads at the
:: current timestamp
:: If b) then we empty $unreads and move all bins to $reads at the
:: current timestamp
::
:: Unread tracking:
:: Unread tracking has two 'modes' which may be used concurrently,
:: if necessary.
::
:: count:
:: This stores the unreads as a simple atom, describing the number
:: of unread items. May be increased with %unread-count and
:: set to zero with %read-count. Ideal for high-frequency linear
:: datastructures, e.g. chat
:: each:
:: This stores the unreads as a set of paths, describing the set of
:: unread items. Unreads may be added to the set with %unread-each
:: and removed with %read-each. Ideal for non-linear, low-frequency
:: datastructures, e.g. blogs
::
|%
:: $place: A location, under which landscape stores stats
::
:: .desk must match q.byk.bowl
:: Examples:
:: A chat:
:: [%landscape /~dopzod/urbit-help]
:: A note in a notebook:
:: [%landscape /~darrux-landes/feature-requests/12374893234232]
:: A group:
:: [%hark-group-hook /~bitbet-bolbel/urbit-community]
:: Comments on a link
:: [%landscape /~dabben-larbet/urbit-in-the-news/17014118450499614194868/2]
::
+$ place [=desk =path]
::
:: $bin: Identifier for grouping notifications
::
:: Examples
:: A mention in a chat:
:: [/mention %landscape /~dopzod/urbit-help]
:: New messages in a chat
:: [/message %landscape /~dopzod/urbit-help]
:: A new comment in a notebook:
:: [/comment %landscape /~darrux-landes/feature-requests/12374893234232/2]
::
+$ bin [=path =place]
::
:: $lid: Reference to a timebox
::
+$ lid
$% [%archive =time]
[%seen ~]
[%unseen ~]
==
:: $content: Notification content
+$ content
$% [%ship =ship]
[%text =cord]
==
::
:: $body: A notification body
::
+$ body
$: title=(list content)
content=(list content)
=time
binned=path
link=path
==
::
+$ notification
[date=@da =bin body=(list body)]
:: $timebox: Group of notificatons
+$ timebox
(map bin notification)
:: $archive: Archived notifications, ordered by time
+$ archive
((mop @da timebox) gth)
::
+$ action
$% :: hook actions
::
:: %add-note: add a notification
[%add-note =bin =body]
::
:: %del-place: Underlying resource disappeared, remove all
:: associated notifications
[%del-place =place]
:: %unread-count: Change unread count by .count
[%unread-count =place inc=? count=@ud]
:: %unread-each: Add .path to list of unreads for .place
[%unread-each =place =path]
:: %saw-place: Update last-updated for .place to now.bowl
[%saw-place =place time=(unit time)]
:: store actions
::
:: %archive: archive single notification
:: if .time is ~, then archiving unread notification
:: else, archiving read notification
[%archive =lid =bin]
:: %read-count: set unread count to zero
[%read-count =place]
:: %read-each: remove path from unreads for .place
[%read-each =place =path]
:: %read-note: Read note at .bin
[%read-note =bin]
:: %archive-all: Archive all notifications
[%archive-all ~]
:: %opened: User opened notifications, reset timeboxing logic.
::
[%opened ~]
::
:: XX: previously in hark-store, now deprecated
:: the hooks responsible for creating notifications may offer pokes
:: similar to this
:: [%read-graph =resource]
:: [%read-group =resource]
:: [%remove-graph =resource]
::
==
:: .stats: Statistics for a .place
::
+$ stats
$: count=@ud
each=(set path)
last=@da
timebox=(unit @da)
==
::
+$ update
$% action
:: %more: more updates
[%archived =time =lid =notification]
[%more more=(list update)]
:: %note-read: note has been read with timestamp
[%note-read =time =bin]
[%added =notification]
:: %timebox: description of timebox.
::
[%timebox =lid =(list notification)]
:: %place-stats: description of .stats for a .place
[%place-stats =place =stats]
:: %place-stats: stats for all .places
[%all-stats places=(map place stats)]
==
--

View File

@ -112,7 +112,7 @@
:_ this
:~ :* %pass /save-summary/(scot %p src.bowl)/(scot %da requested.u.result)
%arvo %k %fard
%garden %save-summary %noun
%landscape %save-summary %noun
!>(`[tlon.api mailchimp.api src.bowl summary.u.result])
==
==

508
desk/app/contacts.hoon Normal file
View File

@ -0,0 +1,508 @@
/- *contacts
/+ default-agent, dbug, verb
:: performance, keep warm
/+ contacts-json
::
|%
:: conventions
::
:: .con: a contact
:: .rof: our profile
:: .rol: our full rolodex
:: .for: foreign profile
:: .sag: foreign subscription state
::
+| %types
+$ card card:agent:gall
+$ state-0 [%0 rof=$@(~ profile) rol=rolodex]
--
::
%- agent:dbug
%+ verb &
^- agent:gall
=| state-0
=* state -
::
=< |_ =bowl:gall
+* this .
def ~(. (default-agent this %|) bowl)
cor ~(. raw bowl)
::
++ on-init
^- (quip card _this)
=^ cards state abet:init:cor
[cards this]
::
++ on-save !>([state okay])
::
++ on-load
|= old=vase
^- (quip card _this)
=^ cards state abet:(load:cor old)
[cards this]
::
++ on-watch
|= =path
^- (quip card _this)
=^ cards state abet:(peer:cor path)
[cards this]
::
++ on-poke
|= [=mark =vase]
^- (quip card _this)
=^ cards state abet:(poke:cor mark vase)
[cards this]
::
++ on-peek peek:cor
++ on-leave on-leave:def
::
++ on-agent
|= [=wire =sign:agent:gall]
^- (quip card _this)
=^ cards state abet:(agent:cor wire sign)
[cards this]
::
++ on-arvo on-arvo:def
++ on-fail on-fail:def
--
::
|%
::
+| %help
::
++ do-edit
|= [c=contact f=field]
^+ c
?- -.f
%nickname c(nickname nickname.f)
%bio c(bio bio.f)
%status c(status status.f)
%color c(color color.f)
::
%avatar ~| "cannot add a data url to avatar!"
?> ?| ?=(~ avatar.f)
!=('data:' (end 3^5 u.avatar.f))
==
c(avatar avatar.f)
::
%cover ~| "cannot add a data url to cover!"
?> ?| ?=(~ cover.f)
!=('data:' (end 3^5 u.cover.f))
==
c(cover cover.f)
::
%add-group c(groups (~(put in groups.c) flag.f))
::
%del-group c(groups (~(del in groups.c) flag.f))
==
::
++ mono
|= [old=@da new=@da]
^- @da
?: (lth old new) new
(add old ^~((div ~s1 (bex 16))))
::
+| %state
::
:: namespaced to avoid accidental direct reference
::
++ raw
=| out=(list card)
|_ =bowl:gall
::
+| %generic
::
++ abet [(flop out) state]
++ cor .
++ emit |=(c=card cor(out [c out]))
++ give |=(=gift:agent:gall (emit %give gift))
++ pass |=([=wire =note:agent:gall] (emit %pass wire note))
::
+| %operations
::
:: |pub: publication mgmt
::
:: - /news: local updates to our profile and rolodex
:: - /contact: updates to our profile
::
:: as these publications are trivial, |pub does *not*
:: make use of the +abet pattern. the only behavior of note
:: is wrt the /contact/at/$date path, which exists to minimize
:: redundant network traffic.
::
:: /epic protocol versions are even more trivial,
:: published ad-hoc, elsewhere.
::
++ pub
=> |%
:: if this proves to be too slow, the set of paths
:: should be maintained statefully: put on +p-init:pub,
:: filtered at some interval (on +load?) to avoid a space leak.
::
++ subs
^- (set path)
%- ~(rep by sup.bowl)
|= [[duct ship pat=path] acc=(set path)]
?.(?=([%contact *] pat) acc (~(put in acc) pat))
::
++ fact
|= [pat=(set path) u=update]
^- gift:agent:gall
[%fact ~(tap in pat) upd:mar !>(u)]
--
::
|%
++ p-anon ?.(?=([@ ^] rof) cor (p-diff ~))
::
++ p-edit
|= l=(list field)
=/ old ?.(?=([@ ^] rof) *contact con.rof)
=/ new (roll l |=([f=field c=_old] (do-edit c f)))
?: =(old new)
cor
(p-diff:pub new)
::
++ p-diff
|= con=$@(~ contact)
=/ p=profile [?~(rof now.bowl (mono wen.rof now.bowl)) con]
(give:(p-news(rof p) our.bowl con) (fact subs full+p))
::
++ p-init
|= wen=(unit @da)
?~ rof cor
?~ wen (give (fact ~ full+rof))
?: =(u.wen wen.rof) cor
?>((lth u.wen wen.rof) (give (fact ~ full+rof))) :: no future subs
::
++ p-news |=(n=news (give %fact [/news ~] %contact-news !>(n)))
--
::
:: +sub: subscription mgmt
::
:: /epic: foreign protocol versions, |si-epic:s-impl
:: /contact/*: foreign profiles, |s-impl
::
:: subscription state is tracked per peer in .sag
::
:: ~: no subscription
:: %want: /contact/* being attempted
:: %fail: /contact/* failed, /epic being attempted
:: %lost: /epic failed
:: %chi: /contact/* established
:: %lev: we're (incompatibly) ahead of the publisher
:: %dex: we're behind the publisher
::
:: for a given peer, we always have at most one subscription,
:: to either /contact/* or /epic.
::
++ sub
|^ |= who=ship
^+ s-impl
?< =(our.bowl who)
=/ old (~(get by rol) who)
~(. s-impl who %live ?=(~ old) (fall old [~ ~]))
::
++ s-many
|= [l=(list ship) f=$-(_s-impl _s-impl)]
^+ cor
%+ roll l
|= [who=@p acc=_cor]
?: =(our.bowl who) acc
si-abet:(f (sub:acc who))
::
++ s-impl
|_ [who=ship sas=?(%dead %live) new=? foreign]
::
++ si-cor .
::
++ si-abet
^+ cor
?- sas
%live =. rol (~(put by rol) who for sag)
:: NB: this assumes con.for is only set in +si-hear
::
?.(new cor (p-news:pub who ~))
::
%dead ?: new cor
=. rol (~(del by rol) who)
::
:: this is not quite right, reflecting *total* deletion
:: as *contact* deletion. but it's close, and keeps /news simpler
::
(p-news:pub who ~)
==
::
++ si-take
|= =sign:agent:gall
^+ si-cor
?- -.sign
%poke-ack ~|(strange-poke-ack+wire !!)
::
%watch-ack ~| strange-watch-ack+wire
?> ?=(%want sag)
?~ p.sign si-cor(sag [%chi ~])
%- (slog 'contact-fail' u.p.sign)
pe-peer:si-epic(sag %fail)
::
%kick si-heed
::
:: [compat] we *should* maintain backcompat here
::
:: by either directly handling or upconverting
:: old actions. but if we don't, we'll fall back
:: to /epic and wait for our peer to upgrade.
::
:: %fact's from the future are also /epic,
:: in case our peer downgrades. if not, we'll
:: handle it on +load.
::
%fact ?+ p.cage.sign (si-odd p.cage.sign)
?(upd:base:mar %contact-update-0)
(si-hear !<(update q.cage.sign))
== ==
++ si-hear
|= u=update
^+ si-cor
?: &(?=(^ for) (lte wen.u wen.for))
si-cor
si-cor(for +.u, cor (p-news:pub who con.u))
::
++ si-meet si-cor :: init key in +si-abet
::
++ si-heed
^+ si-cor
?. ?=(~ sag)
si-cor
=/ pat [%contact ?~(for / /at/(scot %da wen.for))]
%= si-cor
cor (pass /contact %agent [who dap.bowl] %watch pat)
sag %want
==
::
++ si-drop si-snub(sas %dead)
::
++ si-snub
%_ si-cor
sag ~
cor ?+ sag cor
?(%fail [?(%lev %dex) *])
(pass /epic %agent [who dap.bowl] %leave ~)
::
?(%want [%chi *])
(pass /contact %agent [who dap.bowl] %leave ~)
== ==
::
++ si-odd
|= =mark
^+ si-cor
=* upd *upd:base:mar
=* wid ^~((met 3 upd))
?. =(upd (end [3 wid] mark))
~&(fake-news+mark si-cor) :: XX unsub?
?~ ver=(slaw %ud (rsh 3^+(wid) mark))
~&(weird-news+mark si-cor) :: XX unsub?
?: =(okay u.ver)
~|(odd-not-odd+mark !!) :: oops!
=. si-cor si-snub :: unsub before .sag update
=. sag ?:((lth u.ver okay) [%lev ~] [%dex u.ver])
pe-peer:si-epic
::
++ si-epic
|%
++ pe-take
|= =sign:agent:gall
^+ si-cor
?- -.sign
%poke-ack ~|(strange-poke-ack+wire !!)
::
%watch-ack ?~ p.sign si-cor
%- (slog 'epic-fail' u.p.sign)
si-cor(sag %lost)
::
%kick ?. ?=(?(%fail [?(%dex %lev) *]) sag)
si-cor :: XX strange
pe-peer
::
%fact ?+ p.cage.sign
~&(fact-not-epic+p.cage.sign si-cor)
%epic (pe-hear !<(epic q.cage.sign))
== ==
::
++ pe-hear
|= =epic
^+ si-cor
?. ?=(?(%fail [?(%dex %lev) *]) sag)
~|(strange-epic+[okay epic] !!) :: get %kick'd
?: =(okay epic)
?: ?=(%fail sag)
si-cor(sag %lost) :: abandon hope
si-heed:si-snub
::
:: handled generically to support peer downgrade
::
si-cor(sag ?:((gth epic okay) [%dex epic] [%lev ~]))
::
++ pe-peer
si-cor(cor (pass /epic %agent [who dap.bowl] %watch /epic))
--
--
--
:: +migrate: from :contact-store
::
:: all known ships, non-default profiles, no subscriptions
::
++ migrate
=> |%
++ legacy
|%
+$ rolodex (map ship contact)
+$ resource [=entity name=term]
+$ entity ship
+$ contact
$: nickname=@t
bio=@t
status=@t
color=@ux
avatar=(unit @t)
cover=(unit @t)
groups=(set resource)
last-updated=@da
==
--
--
::
^+ cor
=/ bas /(scot %p our.bowl)/contact-store/(scot %da now.bowl)
?. .^(? gu+(weld bas /$)) cor
=/ ful .^(rolodex:legacy gx+(weld bas /all/noun))
::
|^ cor(rof us, rol them)
++ us (biff (~(get by ful) our.bowl) convert)
::
++ them
^- rolodex
%- ~(rep by (~(del by ful) our.bowl))
|= [[who=ship con=contact:legacy] rol=rolodex]
(~(put by rol) who (convert con) ~)
::
++ convert
|= con=contact:legacy
^- $@(~ profile)
?: =(*contact:legacy con) ~
[last-updated.con con(|6 groups.con)]
--
::
+| %implementation
::
++ init
(emit %pass /migrate %agent [our dap]:bowl %poke noun+!>(%migrate))
::
++ load
|= old-vase=vase
^+ cor
|^ =+ !<([old=versioned-state cool=epic] old-vase)
=. state
?- -.old
%0 old
==
:: [compat] if our protocol version changed
::
:: we first tell the world, then see if we can now understand
:: any of our friends who were sending messages from the future.
::
?:(=(okay cool) cor l-bump(cor l-epic))
::
+$ versioned-state
$% state-0
==
::
++ l-epic (give %fact [/epic ~] epic+!>(okay))
::
++ l-bump
^+ cor
%- ~(rep by rol)
|= [[who=ship foreign] =_cor]
:: XX to fully support downgrade, we'd need to also
:: save an epic in %lev
::
?. ?& ?=([%dex *] sag)
=(okay ver.sag)
==
cor
si-abet:si-heed:si-snub:(sub:cor who)
--
::
++ poke
|= [=mark =vase]
^+ cor
:: [compat] we *should* maintain backcompat here
::
:: by either directly handling or upconverting old actions
::
?+ mark ~|(bad-mark+mark !!)
%noun
?+ q.vase !!
%migrate migrate
==
::
?(act:base:mar %contact-action-0)
?> =(our src):bowl
=/ act !<(action vase)
?- -.act
%anon p-anon:pub
%edit (p-edit:pub p.act)
%meet (s-many:sub p.act |=(s=_s-impl:sub si-meet:s))
%heed (s-many:sub p.act |=(s=_s-impl:sub si-heed:s))
%drop (s-many:sub p.act |=(s=_s-impl:sub si-drop:s))
%snub (s-many:sub p.act |=(s=_s-impl:sub si-snub:s))
==
==
::
++ peek
|= pat=(pole knot)
^- (unit (unit cage))
?+ pat [~ ~]
[%x %all ~]
=/ lor=rolodex
?: |(?=(~ rof) ?=(~ con.rof)) rol
(~(put by rol) our.bowl rof ~)
``contact-rolodex+!>(lor)
::
[%x %contact her=@ ~]
?~ who=`(unit @p)`(slaw %p her.pat)
[~ ~]
=/ tac=?(~ contact)
?: =(our.bowl u.who) ?~(rof ~ con.rof)
=+ (~(get by rol) u.who)
?: |(?=(~ -) ?=(~ for.u.-)) ~
con.for.u.-
?~ tac [~ ~]
``contact+!>(`contact`tac)
==
::
++ peer
|= pat=(pole knot)
^+ cor
?+ pat ~|(bad-watch-path+pat !!)
[%contact %at wen=@ ~] (p-init:pub `(slav %da wen.pat))
[%contact ~] (p-init:pub ~)
[%epic ~] (give %fact ~ epic+!>(okay))
[%news ~] ~|(local-news+src.bowl ?>(=(our src):bowl cor))
==
::
++ agent
|= [=wire =sign:agent:gall]
^+ cor
?+ wire ~|(evil-agent+wire !!)
[%contact ~] si-abet:(si-take:(sub src.bowl) sign)
[%epic ~] si-abet:(pe-take:si-epic:(sub src.bowl) sign)
::
[%migrate ~]
?> ?=(%poke-ack -.sign)
?~ p.sign cor
%- (slog leaf/"{<wire>} failed" u.p.sign)
cor
==
--
--

View File

@ -174,11 +174,9 @@
=^ cards state
?+ path (on-watch:def path)
[%http-response *]
?> (team:title [our src]:bowl)
`state
::
[%charges ~]
?> (team:title [our src]:bowl)
`state
::
[%glob @ @ ~]
@ -506,7 +504,7 @@
::
++ handle-get-request
^- simple-payload:http
?+ [site ext]:req-line (redirect:gen '/apps/grid/')
?+ [site ext]:req-line (redirect:gen '/apps/landscape/')
[[%session ~] [~ %js]]
%- inline-js-response
(rap 3 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";' ~)

View File

@ -1,550 +0,0 @@
:: hark-store: notifications and unread counts [landscape]
::
:: hark-store can store unread counts differently, depending on the
:: resource.
:: - last seen. This way, hark-store simply stores an index into
:: graph-store, which represents the last "seen" item, useful for
:: high-volume applications which are intrinsically time-ordered. i.e.
:: chats, comments
:: - each. Hark-store will store an index for each item that is unread.
:: Usefull for non-linear, low-volume applications, i.e. blogs,
:: collections
::
/- store=hark-store
/+ verb, dbug, default-agent, re=hark-unreads, agentio
::
::
~% %hark-store-top ..part ~
|%
+$ card card:agent:gall
+$ versioned-state
$% state-2
state-3
state-4
state-5
state-6
state-7
state-8
state-9
==
::
+$ base-state
$: places=(map place:store stats:store)
seen=timebox:store
unseen=timebox:store
=archive:store
half-open=(map bin:store @da)
==
::
+$ state-2
[%2 *]
::
+$ state-3
[%3 *]
::
+$ state-4
[%4 *]
::
+$ state-5
[%5 *]
::
+$ state-6
[%6 *]
::
+$ state-7
[%7 *]
::
+$ state-8
[%8 base-state]
::
+$ state-9
[%9 base-state]
::
::
+$ cached-state
$: by-place=(jug place:store [=lid:store =path])
~
==
+$ inflated-state
[state-9 cached-state]
::
++ orm ((ordered-map @da timebox:store) gth)
--
::
=| inflated-state
=* state -
::
=<
%+ verb |
%- agent:dbug
^- agent:gall
~% %hark-store-agent ..card ~
|_ =bowl:gall
+* this .
ha ~(. +> bowl)
def ~(. (default-agent this %|) bowl)
io ~(. agentio bowl)
pass pass:io
::
++ on-init
`this
::
++ on-save !>(-.state)
++ on-load
|= =old=vase
=/ old
!<(versioned-state old-vase)
=| cards=(list card)
|- ^- (quip card _this)
?+ -.old
:: pre-dist migration
:_ this
(poke-our:pass %hark-graph-hook hark-graph-migrate+old-vase)^~
::
%9
=. -.state old
=. +.state inflate:ha
:_(this (flop cards))
::
%8
$(-.old %9, archive.old *archive:store)
==
::
++ on-watch
|= =path
^- (quip card _this)
?> (team:title [src our]:bowl)
|^
?+ path (on-watch:def path)
[%notes ~] `this
::
[%updates ~]
:_ this
[%give %fact ~ hark-update+!>(initial-updates)]~
::
==
::
++ initial-updates
^- update:store
:- %more
^- (list update:store)
:~ [%timebox unseen+~ ~(val by unseen)]
[%timebox seen+~ ~(val by seen)]
[%all-stats places]
==
--
::
++ on-peek
~/ %hark-store-peek
|= =path
^- (unit (unit cage))
?+ path (on-peek:def path)
::
[%x %recent %inbox @ @ ~]
=/ date=@da
(slav %ud i.t.t.t.path)
=/ length=@ud
(slav %ud i.t.t.t.t.path)
:^ ~ ~ %hark-update
!> ^- update:store
:- %more
%+ turn (tab:orm archive `date length)
|= [time=@da =timebox:store]
^- update:store
[%timebox archive+time ~(val by timebox)]
::
[%x %all-stats ~]
:^ ~ ~ %hark-update
!> ^- update:store
:- %more
^- (list update:store)
:~ [%all-stats places]
==
==
::
++ 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))
%noun (poke-noun !<(* vase))
==
[cards this]
::
++ poke-noun
|= val=*
?+ val ~|(%bad-noun-poke !!)
%print ~&(+.state [~ state])
%clear [~ state(. *inflated-state)]
%sane
~& +.state
~& inflate
?>(=(+.state inflate) `state)
==
::
++ poke-us
|= =action:store
^- card
[%pass / %agent [our dap]:bowl %poke hark-action+!>(action)]
::
++ hark-action
|= =action:store
^- (quip card _state)
abet:(abed:poke-engine:ha action)
--
::
++ 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)
`this
::
++ on-fail on-fail:def
--
|_ =bowl:gall
+* met ~(. metadata bowl)
io ~(. agentio bowl)
pass pass:io
++ poke-engine
|_ [out=(list update:store) cards=(list card)]
++ poke-core .
::
++ abed
|= in=action:store
^+ poke-core
?- -.in
::
%add-note (add-note +.in)
%del-place (del-place +.in)
%archive (do-archive +.in)
::
%unread-count (unread-count +.in)
%read-count (read-count +.in)
::
%read-each (read-each +.in)
%unread-each (unread-each +.in)
::
%read-note (read-note +.in)
::
%saw-place (saw-place +.in)
::
%opened opened
%archive-all archive-all
::
==
::
++ abet
^- (quip card _state)
:_ state
%+ snoc (flop cards)
[%give %fact ~[/updates] %hark-update !>([%more (flop out)])]
::
++ give |=(=update:store poke-core(out [update out]))
++ emit |=(=card poke-core(cards [card cards]))
::
::
:: +| %note
::
:: notification tracking
++ put-notifs
|= [time=@da =timebox:store]
poke-core(archive (put:orm archive time timebox))
::
++ put-lid
|= [=lid:store =bin:store =notification:store]
^+ poke-core
=. by-place (~(put ju by-place) place.bin [lid path.bin])
?- -.lid
%seen
poke-core(seen (~(put by seen) bin notification))
::
%unseen
poke-core(unseen (~(put by unseen) bin notification))
::
%archive
poke-core(archive (~(put re archive) time.lid bin notification))
==
::
++ del-lid
|= [=lid:store =bin:store]
=. by-place (~(del ju by-place) place.bin [lid path.bin])
?- -.lid
%seen poke-core(seen (~(del by seen) bin))
%unseen poke-core(unseen (~(del by unseen) bin))
%archive poke-core(archive (~(del re archive) time.lid bin))
==
::
++ add-note
|= [=bin:store =body:store]
^+ poke-core
=. poke-core
(emit (fact:io hark-update+!>([%add-note bin body]) /notes ~))
=/ existing-notif
(~(gut by unseen) bin *notification:store)
=/ new=notification:store
[now.bowl bin [body body.existing-notif]]
=. poke-core
(put-lid unseen/~ bin new)
(give %added new)
::
++ del-place
|= =place:store
=. poke-core (give %del-place place)
=/ notes=(list [=lid:store =path])
~(tap in (~(get ju by-place) place))
|- ^+ poke-core
?~ notes poke-core
=, i.notes
=. poke-core
(del-lid lid path place)
$(notes t.notes)
::
++ do-archive
|= [=lid:store =bin:store]
^+ poke-core
~| %already-archived
?< ?=(%time -.lid)
~| %non-existent
=/ =notification:store (need (get-lid lid bin))
=. poke-core (del-lid lid bin)
=. poke-core (put-lid archive+now.bowl bin notification)
(give %archived now.bowl lid notification)
::
++ read-note
|= =bin:store
=/ =notification:store
(~(got by unseen) bin)
=. poke-core
(del-lid unseen/~ bin)
=/ =time
(fall timebox:(gut-place place.bin) now.bowl)
=. date.notification time
=. poke-core
(put-lid archive/time bin notification)
(give %note-read time bin)
::
::
:: +| %each
::
:: each unread tracking
::
++ unread-each
|= [=place:store =path]
=. poke-core (saw-place place ~)
=. poke-core (give %unread-each place path)
%+ jub-place place
|=(=stats:store stats(each (~(put in each.stats) path)))
::
++ read-index-each
|= [=place:store =path]
%- read-bins
%+ skim
~(tap in ~(key by unseen))
|= =bin:store
?. =(place place.bin) %.n
=/ not=notification:store
(~(got by unseen) bin)
(lien body.not |=(=body:store =(binned.body path)))
::
++ read-each
|= [=place:store =path]
=. poke-core (read-index-each place path)
=. poke-core (give %read-each place path)
%+ jub-place place
|= =stats:store
%_ stats
timebox `now.bowl
each (~(del in each.stats) path)
==
::
++ gut-place
|= =place:store
?: (~(has by places) place) (~(got by places) place)
=| def=stats:store
def(timebox ~, last now.bowl)
::
++ jub-place
|= $: =place:store
f=$-(stats:store stats:store)
==
^+ poke-core
=/ =stats:store
(gut-place place)
poke-core(places (~(put by places) place (f stats)))
::
++ unread-count
|= [=place:store inc=? count=@ud]
=. poke-core
(give %unread-count place inc count)
=. poke-core (saw-place place ~)
=/ f
?: inc (cury add count)
(curr sub count)
%+ jub-place place
|= =stats:store
stats(count (f count.stats))
::
++ half-archive
|= =place:store
=/ bins=(list [=lid:store =path])
~(tap in (~(get ju by-place) place))
|-
?~ bins poke-core
=/ =bin:store
[path.i.bins place]
=* lid lid.i.bins
?: ?=(%archive -.lid)
$(bins t.bins)
=/ seen-place (~(get by seen) bin)
=/ n=(unit notification:store) (get-lid lid bin)
?~ n $(bins t.bins)
=* note u.n
=/ =time (~(gut by half-open) bin now.bowl)
=? half-open !(~(has by half-open) bin)
(~(put by half-open) bin now.bowl)
=/ existing (get-lid archive/time bin)
=/ new (merge-notification existing note)
=? half-open (lth 30 (lent body.new))
(~(del by half-open) bin)
=. poke-core
(put-lid archive/time bin new)
=. poke-core (del-lid lid bin)
=. poke-core (give %archived time lid (~(got re archive) time bin))
$(bins t.bins)
::
++ read-count
|= =place:store
=. poke-core (give %read-count place)
=. poke-core (half-archive place)
%+ jub-place place
|= =stats:store
stats(count 0, timebox `now.bowl)
::
++ read-bins
|= bins=(list bin:store)
|-
?~ bins poke-core
=/ core
(read-note i.bins)
$(poke-core core, bins t.bins)
::
++ saw-place
|= [=place:store time=(unit time)]
=. poke-core (give %saw-place place time)
%+ jub-place place
|=(=stats:store stats(last (fall time now.bowl)))
::
++ archive-seen
=/ seen=(list [=bin:store =notification:store]) ~(tap by seen)
poke-core
::
++ opened
=. poke-core (turn-places |=(=stats:store stats(timebox ~)))
=. poke-core (give %opened ~)
%+ roll ~(tap in ~(key by unseen))
|= [=bin:store out=_poke-core]
(opened-note:out bin)
::
++ opened-note
|= =bin:store
^+ poke-core
=/ old
(~(got by unseen) bin)
=. poke-core
(del-lid unseen/~ bin)
=/ se (~(get by seen) bin)
%^ put-lid seen/~ bin
(merge-notification se old)
::
++ archive-all
|^
=. poke-core (archive-lid unseen/~ unseen)
(archive-lid seen/~ seen)
++ archive-lid
|= [=lid:store =timebox:store]
%+ roll ~(tap in ~(key by timebox))
|= [=bin:store out=_poke-core]
(do-archive:out lid bin)
--
::
++ turn-places
|= f=$-(stats:store stats:store)
=/ places ~(tap in ~(key by places))
|- ^+ poke-core
?~ places poke-core
=/ core=_poke-core (jub-place i.places f)
$(poke-core core, places t.places)
--
::
++ get-lid
|= [=lid:store =bin:store]
=; =timebox:store
(~(get by timebox) bin)
?- -.lid
%unseen unseen
%seen seen
%archive (fall (get:orm archive time.lid) *timebox:store)
==
::
++ merge-notification
|= [existing=(unit notification:store) new=notification:store]
^- notification:store
?~ existing new
[(max date.u.existing date.new) bin.new (welp body.new body.u.existing)]
::
:: +key-orm: +key:by for ordered maps
++ key-orm
|= =archive:store
^- (list @da)
(turn (tap:orm archive) |=([@da *] +<-))
::
:: +gut-orm: +gut:by for ordered maps
:: TODO: move to zuse.hoon
++ gut-orm
|= [=archive:store time=@da]
^- timebox:store
(fall (get:orm archive time) ~)
::
::
++ 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=update:store]
^- (list card)
[%give %fact paths [%hark-update !>(update)]]~
::
++ tap-nonempty
|= =archive:store
^- (list [@da timebox:store])
%+ skim (tap:orm archive)
|=([@da =timebox:store] !=(~(wyt by timebox) 0))
::
++ inflate
=. by-place ~
=. by-place (index-timebox seen+~ seen by-place)
=. by-place (index-timebox unseen+~ unseen by-place)
=. by-place
%+ roll (tap:orm archive)
|= [[=time =timebox:store] out=_by-place]
(index-timebox archive/time timebox out)
+.state
::
++ index-timebox
|= [=lid:store =timebox:store out=_by-place]
^+ by-place
%+ roll ~(tap by timebox)
|= [[=bin:store =notification:store] out=_out]
(~(put ju out) place.bin [lid path.bin])
--

View File

@ -1,208 +0,0 @@
/- hark=hark-store, hood, docket
/+ verb, dbug, default-agent, agentio
|%
+$ card card:agent:gall
+$ state-1 [%1 lagging=_|]
::
++ lag-interval ~m10
--
%+ verb |
%- agent:dbug
^- agent:gall
=| state-1
=* state -
=<
|_ =bowl:gall
+* this .
def ~(. (default-agent this %|) bowl)
io ~(. agentio bowl)
pass pass:io
cc ~(. +> bowl)
++ on-init
^- (quip card _this)
:_ this
[onboard tire:cy check:lag ~]:cc
::
++ on-load
|= =vase
^- (quip card _this)
|^
=+ !<(old=app-states vase)
=^ cards-1 old
?. ?=(%0 -.old) `old
[[tire:cy:cc]~ old(- %1)]
?> ?=(%1 -.old)
=/ cards-tire [tire:cy:cc ~]
[(weld cards-1 cards-tire) this(state old)]
::
+$ app-states $%(state-0 state-1)
+$ state-0 [%0 lagging=_|]
--
::
++ on-save !>(state)
++ on-poke on-poke:def
++ on-peek on-peek:def
++ on-watch on-watch:def
++ on-agent
|= [=wire =sign:agent:gall]
^- (quip card _this)
?+ wire (on-agent:def wire sign)
[%kiln %vats ~] `this
==
::
++ on-arvo
|= [=wire sign=sign-arvo]
^- (quip card _this)
|^
?+ wire (on-arvo:def wire sign)
[%clay %tire ~] take-clay-tire
[%clay %warp * ~] (take-clay-warp i.t.t.wire)
[%check-lag ~] take-check-lag
==
::
++ take-check-lag
^- (quip card _this)
?> ?=([%behn %wake *] sign)
=+ .^(lag=? %$ (scry:io %$ /zen/lag))
?: =(lagging lag) :_(this ~[check:lag:cc])
:_ this(lagging lag)
:_ ~[check:lag:cc]
?:(lagging start:lag:cc stop:lag:cc)
::
++ take-clay-tire
^- (quip card _this)
?> ?=(%tire +<.sign)
?- -.p.sign
%& [(turn ~(tap in ~(key by p.p.sign)) warp:cy:cc) this]
%|
?- -.p.p.sign
%zest `this
%warp `this
%wait
=/ =action:hark (~(blocked de:cc desk.p.p.sign) weft.p.p.sign)
:_ this
~[(poke:ha:cc action)]
==
==
::
++ take-clay-warp
|= =desk
^- (quip card _this)
?> ?=(%writ +<.sign)
=/ cards
?. |(=(desk %base) ~(has-docket de:cc desk)) ~
=/ =action:hark ~(commit de:cc desk)
~[(poke:ha:cc action)]
[[(warp:cy:cc desk) cards] this]
--
::
++ on-fail on-fail:def
++ on-leave on-leave:def
--
|_ =bowl:gall
+* io ~(. agentio bowl)
pass pass:io
::
++ onboard
^- card
%- poke:ha
:+ %add-note [/ [q.byk.bowl /onboard]]
:: We special case this in the grid UI, but should include something
:: for third parties
[~[text+'Welcome to urbit'] ~ now.bowl / /]
::
++ lag
|%
++ check (~(wait pass /check-lag) (add now.bowl lag-interval))
++ place [q.byk.bowl /lag]
++ body `body:hark`[~[text/'Runtime lagging'] ~ now.bowl / /]
++ start (poke:ha %add-note [/ place] body)
++ stop (poke:ha %del-place place)
--
++ ha
|%
++ pass ~(. ^pass /hark)
++ poke
|=(=action:hark (poke-our:pass %hark-store hark-action+!>(action)))
--
::
++ cy
|%
++ tire ~(tire pass /clay/tire)
++ warp
|= =desk
(~(warp-our pass /clay/warp/[desk]) desk ~ %next %z da+now.bowl /)
--
::
++ de
|_ =desk
++ scry-path (scry:io desk /desk/docket-0)
++ has-docket .^(? %cu scry-path)
++ docket .^(docket:^docket %cx scry-path)
++ hash .^(@uv %cz (scry:io desk ~))
++ place `place:hark`[q.byk.bowl /desk/[desk]]
++ version ud:.^(cass:clay %cw (scry:io desk /))
++ body
|= [=path title=cord content=(unit cord)]
^- body:hark
[~[text+title] ?~(content ~ ~[text/u.content]) now.bowl ~ path]
::
::
++ title-prefix
|= =cord
%+ rap 3
?: =(desk %base)
['System software' cord ~]
?: has-docket
['App: "' title:docket '"' cord ~]
['Desk: ' desk cord ~]
::
++ get-version
?: has-docket
(rap 3 'version: ' (ver version:docket) ~)
(rap 3 'hash: ' (scot %uv hash) ~)
::
++ commit
^- action:hark
?:(=(1 version) created updated)
::
++ created
^- action:hark
:+ %add-note [/created place]
(body /desk/[desk] (title-prefix ' has been installed') ~)
::
++ updated
^- action:hark
:+ %add-note [/update place]
(body /desk/[desk] (title-prefix (rap 3 ' has been updated to ' get-version ~)) ~)
::
++ blocked
|= =weft
^- action:hark
:+ %add-note [/blocked place]
%^ body /blocked (title-prefix ' is blocked from upgrading')
`(rap 3 'Blocked waiting for system version: ' (scot %ud num.weft) 'K' ~)
::
++ ver
|= =version:^docket
=, version
`@t`(rap 3 (num major) '.' (num minor) '.' (num patch) ~)
::
++ num
|= a=@ud
`@t`(rsh 4 (scot %ui a))
--
++ note
|%
++ merge
|= [=desk hash=@uv]
^- (list body:hark)
:_ ~
:* ~[text+'Desk Updated']
~[text+(crip "Desk {(trip desk)} has been updated to hash {(scow %uv hash)}")]
now.bowl
/update/[desk]
/
==
--
--

427
desk/app/hark.hoon Normal file
View File

@ -0,0 +1,427 @@
/- h=hark
/+ default-agent, verb, dbug
/+ mp=mop-extensions
:: performance, keep warm
/+ hark-json
|%
+$ card card:agent:gall
++ mope ((mp @ud thread:h) lte)
++ yarns-per-update 3
++ rug-trim-size 10
++ blanket-size 10 :: page size for blankets
++ gc-interval ~h24
:: TODO: move to stdlib
++ zip
|* [a=(list) b=(list)]
^- (list _?>(?=(^ a) ?>(?=(^ b) [i.a i.b])))
?~ a ~
?~ b ~
:- [i.a i.b]
$(a t.a, b t.b)
::
++ quilt-idx
|= =quilt:h
?~ tal=(ram:on:quilt:h quilt)
0
+(key.u.tal)
::
+$ state-0
$: %0
yarns=(map id:h yarn:h)
groups=(map flag:h rug:h)
desks=(map desk rug:h)
all=rug:h
next-gc=@da
==
--
%- agent:dbug
%+ verb |
=| state-0
=* state -
=<
|_ =bowl:gall
+* this .
cor ~(. +> [bowl ~])
def ~(. (default-agent this %|) bowl)
++ on-init
=^ cards state
abet:set-gc-wake:cor
[cards this]
++ on-save !>(state)
++ on-load
|= =vase
=/ old=(unit state-0)
(mole |.(!<(state-0 vase)))
?~ old on-init
`this(state u.old)
++ on-poke
|= [=mark =vase]
=^ cards state
abet:(poke:cor mark vase)
[cards this]
++ on-watch
|= =path
=^ cards state
abet:(watch:cor path)
[cards this]
++ on-peek peek:cor
++ on-arvo
|= [=wire sign=sign-arvo]
=^ cards state
abet:(arvo:cor wire sign)
[cards this]
++ on-agent
|= [=wire =sign:agent:gall]
=^ cards state
abet:(agent:cor wire sign)
[cards this]
++ on-leave on-leave:def
++ on-fail on-fail:def
--
|_ [=bowl:gall cards=(list card)]
++ abet [(flop cards) state]
++ cor .
++ emit |=(=card cor(cards [card cards]))
++ poke
|= [=mark =vase]
^+ cor
?+ mark ~|(bad-mark/mark !!)
%hark-action
=+ !<(act=action:h vase)
=. cor (give-ui act)
?- -.act
%saw-rope (saw-rope rope.act)
%saw-seam (saw-seam seam.act)
%add-yarn (add-yarn +.act)
==
::
%hark-action-1
=+ !<(act=action-1:h vase)
?+ -.act $(mark %hark-action)
%new-yarn
=/ =action:h
:* %add-yarn
all.act
desk.act
:* (end [7 1] (shax eny.bowl))
rop.act
now.bowl
con.act
wer.act
but.act
==
==
$(mark %hark-action, vase !>(action))
==
==
++ peek
|= =(pole knot)
^- (unit (unit cage))
?+ pole [~ ~]
::
[%x %all rest=*] (scry-rug rest.pole all/~ all)
::
[%x %group ship=@ name=@ rest=*]
=/ =ship (slav %p ship.pole)
=/ =flag:h [ship name.pole]
=/ =rug:h (~(got by groups) flag)
(scry-rug rest.pole group/flag rug)
::
[%x %desk desk=@ rest=*]
(scry-rug rest.pole desk/desk.pole (~(gut by desks) desk.pole *rug:h))
::
[%x %yarn uid=@ ~]
``hark-yarn+!>((~(got by yarns) (slav %uv uid.pole)))
==
::
++ is-us =(our src):bowl
::
++ watch
|= =path
^+ cor
?+ path ~|(evil-watch/path !!)
[%ui ~] ?>(is-us cor)
==
::
++ arvo
|= [=wire sign=sign-arvo]
^+ cor
?+ wire ~|(bad-arvo-take/wire !!)
[%gc ~]
=. cor stale
set-gc-wake
==
++ agent
|= [=wire =sign:agent:gall]
^+ cor
cor
::
++ scry-rug
|= [=(pole knot) =seam:h =rug:h]
^- (unit (unit cage))
?+ pole [~ ~]
[%skeins ~] ``hark-skeins+!>((rug-to-skeins seam rug))
[%latest ~] ``hark-carpet+!>((rug-to-carpet seam rug))
::
[%quilt idx=@ ~]
=/ idx (slav %ud idx.pole)
``hark-blanket+!>((rug-to-blanket seam idx rug))
==
++ rug-to-skeins
|= [=seam:h =rug:h]
^- (list skein:h)
%+ welp
%+ turn
~(tap by new.rug)
|= [* =thread:h]
(thread-to-skein thread &)
%+ turn
(top:mope qul.rug blanket-size)
|= [* =thread:h]
(thread-to-skein thread |)
::
++ thread-to-skein
|= [=thread:h unread=?]
=/ yrns=(list yarn:h)
%+ sort
(turn (thread-to-yarns thread) tail)
|= [a=yarn:h b=yarn:h]
(gth tim.a tim.b)
=/ top=yarn:h (head yrns)
^- skein:h
:* tim.top
(lent yrns)
(ship-count yrns)
top
unread
==
::
++ ship-count
|= yrns=(list yarn:h)
^- @ud
%~ wyt in
%+ roll
yrns
|= [=yarn:h ships=(set ship)]
%- ~(gas in ships)
^- (list ship)
%+ murn
con.yarn
|= =content:h
^- (unit ship)
?@ content ~
?+ -.content ~
%ship (some p.content)
==
::
++ rug-to-carpet
|= [=seam:h =rug:h]
^- carpet:h
=- [seam - new.rug (quilt-idx qul.rug)]
%- ~(gas by *(map id:h yarn:h))
%- zing
%+ turn ~(tap by new.rug)
|= [=rope:h =thread:h]
^- (list [id:h yarn:h])
(thread-to-yarns thread)
::
++ thread-to-yarns
|= =thread:h
^- (list [id:h yarn:h])
%+ murn ~(tap in thread)
|= =id:h
^- (unit [id:h yarn:h])
?~ yar=(~(get by yarns) id)
~
`[id u.yar]
::
++ index-quilt
|= [=quilt:h idx=@ud]
(gas:on:quilt:h *quilt:h (bat:mope quilt `idx blanket-size))
::
++ rug-to-blanket
|= [=seam:h idx=@ud =rug:h]
^- blanket:h
=/ indexed
(index-quilt qul.rug idx)
=/ yarns=(map id:h yarn:h)
%- ~(gas by *(map id:h yarn:h))
%- zing
%+ turn (tap:on:quilt:h indexed)
|= [num=@ud =thread:h]
(thread-to-yarns thread)
[seam yarns indexed]
::
++ set-gc-wake
=. next-gc (add now.bowl gc-interval)
(emit %pass /gc %arvo %b %wait next-gc)
::
++ give-ui
|= =action:h
^+ cor
(emit %give %fact ~[/ui] hark-action+!>(action))
::
++ threads-to-update
|= [=seam:h teds=(map @ thread:h)]
^- *
=- [- seam teds]
^- (map id:h yarn:h)
%- ~(gas by *(map id:h yarn:h))
%- zing
%+ turn ~(tap by teds)
|= [=time =thread:h]
%+ scag yarns-per-update
%+ murn ~(tap in thread)
|= =id:h
^- (unit [id:h yarn:h])
?~ yar=(~(get by yarns) id) ~
`[id u.yar]
:: TODO: namespacing conflicts?
++ saw-thread
|= =rope:h
|= =rug:h
?~ ted=(~(get by new.rug) rope) rug
=. new.rug (~(del by new.rug) rope)
=/ start (quilt-idx qul.rug)
=. qul.rug (put:on:quilt:h qul.rug start u.ted)
rug
::
++ saw-rope
|= =rope:h
=/ saw (saw-thread rope)
=. all (saw all)
=. desks
(~(jab by desks) des.rope saw)
=? groups ?=(^ gop.rope)
(~(jab by groups) u.gop.rope saw)
cor
++ rug-to-yarns
|= =rug:h
^- (map id:h yarn:h)
%- ~(gas by *(map id:h yarn:h))
~
::^- (list [id:h yarn:h])
:: %- zing
:: %+ turn ~(tap by new.rug)
:: |= [=rope:h =thread:h]
:: +stale: garbage collection
::
++ stale
|^
=/ ids ~(key by yarns)
=. ids (~(dif in ids) (ids-for-rug all))
=. ids (~(dif in ids) ids-for-groups)
=. ids (~(dif in ids) ids-for-desks)
=/ ids ~(tap in ids)
|-
?~ ids cor
$(yarns (~(del by yarns) i.ids), ids t.ids)
++ trim-rug
|= =rug:h
=* on on:quilt:h
^+ rug
?~ hed=(pry:on qul.rug)
rug
:: TODO: bad asymptotics
=+ siz=(lent (tap:on qul.rug))
?: (lte siz 50)
rug :: bail if not much there
=/ dip (dip:on ,count=@ud)
=. qul.rug
=< +
%^ dip qul.rug 0
|= [count=@ud key=@ud =thread:h]
^- [(unit thread:h) stop=? count=@ud]
=- [~ - +(count)]
(gte count rug-trim-size)
rug
::
++ ids-for-rug
|= =rug:h
%- ~(gas in *(set id:h))
^- (list id:h)
%+ welp
^- (list id:h)
%- zing
%+ turn ~(val by new.rug)
|= =thread:h
~(tap in thread)
^- (list id:h)
%- zing
%+ turn (tap:on:quilt:h qul.rug)
|= [idx=@ud =thread:h]
~(tap in thread)
::
++ ids-for-desks
=/ des ~(tap in ~(key by desks))
=| ids=(set id:h)
|- ^+ ids
?~ des ids
=/ =rug:h (~(got by desks) i.des)
$(ids (~(uni in ids) (ids-for-rug rug)), des t.des)
::
++ ids-for-groups
=/ gop ~(tap in ~(key by groups))
=| ids=(set id:h)
|- ^+ ids
?~ gop ids
=/ =rug:h (~(got by groups) i.gop)
$(ids (~(uni in ids) (ids-for-rug rug)), gop t.gop)
--
++ saw-seam
|= =seam:h
=/ fun
|= =rug:h
=/ start (quilt-idx qul.rug)
=/ new ~(val by new.rug)
%_ rug
new ~
::
qul
%+ gas:on:quilt:h qul.rug
(zip (gulf start (add start (lent new))) new)
==
=. .
?- -.seam
%group .(groups (~(jab by groups) flag.seam fun))
%desk .(desks (~(jab by desks) desk.seam fun))
%all .(all (fun all))
==
cor
::
++ add-yarn
=| [add-all=? add-desk=? =yarn:h]
|%
++ $
=. yarns (~(put by yarns) id.yarn yarn)
=. cor weave-all
=. cor weave-group
weave-desk
::
++ weave-all
?. add-all cor
cor(all (weave-rug all all/~))
++ weave-rug
|= [=rug:h =seam:h]
=/ =thread:h (~(gut by new.rug) rop.yarn ~)
=. thread (~(put in thread) id.yarn)
=. new.rug (~(put by new.rug) rop.yarn thread)
rug
::
++ weave-group
?~ gop.rop.yarn cor
=* group u.gop.rop.yarn
=/ =rug:h (~(gut by groups) group *rug:h)
=. rug (weave-rug rug group/group)
=. groups (~(put by groups) group rug)
cor
::
++ weave-desk
?. add-desk cor
=/ =rug:h (~(gut by desks) des.rop.yarn *rug:h)
=. rug (weave-rug rug desk/des.rop.yarn)
=. desks (~(put by desks) des.rop.yarn rug)
cor
--
--

View File

@ -1,202 +0,0 @@
/- *settings
/+ verb, dbug, default-agent, agentio
|%
+$ card card:agent:gall
+$ versioned-state
$% state-0
state-1
state-2
==
+$ state-0 [%0 settings=settings-0]
+$ state-1 [%1 settings=settings-1]
+$ state-2 [%2 =settings]
--
=| state-2
=* state -
::
%- agent:dbug
%+ verb |
^- agent:gall
=<
|_ bol=bowl:gall
+* this .
do ~(. +> bol)
def ~(. (default-agent this %|) bol)
io ~(. agentio bol)
::
++ on-init on-init:def
::
++ on-save !>(state)
::
++ on-load
|= =old=vase
^- (quip card _this)
=/ old !<(versioned-state old-vase)
|-
?- -.old
%0 $(old [%1 +.old])
%1 $(old [%2 (~(put by *^settings) %landscape settings.old)])
%2 `this(state old)
==
::
++ on-poke
|= [mar=mark vas=vase]
^- (quip card _this)
?> (team:title our.bol src.bol)
?. ?=(%settings-event mar)
(on-poke:def mar vas)
=/ evt=event !<(event vas)
=^ cards state
?- -.evt
%put-bucket (put-bucket:do [desk key bucket]:evt)
%del-bucket (del-bucket:do [desk key]:evt)
%put-entry (put-entry:do [desk buc key val]:evt)
%del-entry (del-entry:do [desk buc key]:evt)
==
[cards this]
::
++ on-watch
|= pax=path
^- (quip card _this)
?> (team:title our.bol src.bol)
?+ pax (on-watch:def pax)
[%all ~]
[~ this]
::
[%desk @ ~]
=* desk i.t.pax
[~ this]
::
[%bucket @ @ ~]
=* desk i.t.pax
=* bucket-key i.t.t.pax
?> (~(has bi settings) desk bucket-key)
[~ this]
::
[%entry @ @ @ ~]
=* desk i.t.pax
=* bucket-key i.t.t.pax
=* entry-key i.t.t.t.pax
=/ bucket (~(got bi settings) desk bucket-key)
?> (~(has by bucket) entry-key)
[~ this]
==
::
++ on-peek
|= pax=path
^- (unit (unit cage))
?+ pax (on-peek:def pax)
[%x %all ~]
``settings-data+!>(`data`all+settings)
::
[%x %desk @ ~]
=* desk i.t.t.pax
=/ desk-settings (~(gut by settings) desk ~)
``settings-data+!>(desk+desk-settings)
::
[%x %bucket @ @ ~]
=* desk i.t.t.pax
=* buc i.t.t.t.pax
=/ bucket=(unit bucket) (~(get bi settings) desk buc)
?~ bucket [~ ~]
``settings-data+!>(`data`bucket+u.bucket)
::
[%x %entry @ @ @ ~]
=* desk i.t.t.pax
=* buc i.t.t.t.pax
=* key i.t.t.t.t.pax
=/ =bucket (~(gut bi settings) desk buc *bucket)
=/ entry=(unit val) (~(get by bucket) key)
?~ entry [~ ~]
``settings-data+!>(`data`entry+u.entry)
::
[%x %has-bucket @ @ ~]
=/ desk i.t.t.pax
=/ buc i.t.t.t.pax
=/ has-bucket=? (~(has bi settings) desk buc)
``noun+!>(`?`has-bucket)
::
[%x %has-entry @ @ @ ~]
=* desk i.t.t.pax
=* buc i.t.t.t.pax
=* key i.t.t.t.t.pax
=/ =bucket (~(gut bi settings) desk buc *bucket)
=/ has-entry=? (~(has by bucket) key)
``noun+!>(`?`has-entry)
==
::
++ on-agent on-agent:def
++ on-leave on-leave:def
++ on-arvo on-arvo:def
++ on-fail on-fail:def
--
::
|_ bol=bowl:gall
::
:: +put-bucket: put a bucket in the top level settings map, overwriting if it
:: already exists
::
++ put-bucket
|= [=desk =key =bucket]
^- (quip card _state)
=/ pas=(list path)
:~ /all
/desk/[desk]
/bucket/[desk]/[key]
==
:- [(give-event pas %put-bucket desk key bucket)]~
state(settings (~(put bi settings) desk key bucket))
::
:: +del-bucket: delete a bucket from the top level settings map
::
++ del-bucket
|= [=desk =key]
^- (quip card _state)
=/ pas=(list path)
:~ /all
/desk/[desk]
/bucket/[key]
==
:- [(give-event pas %del-bucket desk key)]~
state(settings (~(del bi settings) desk key))
::
:: +put-entry: put an entry in a bucket, overwriting if it already exists
:: if bucket does not yet exist, create it
::
++ put-entry
|= [=desk buc=key =key =val]
^- (quip card _state)
=/ pas=(list path)
:~ /all
/desk/[desk]
/bucket/[desk]/[buc]
/entry/[desk]/[buc]/[key]
==
=/ =bucket (~(put by (~(gut bi settings) desk buc *bucket)) key val)
:- [(give-event pas %put-entry desk buc key val)]~
state(settings (~(put bi settings) desk buc bucket))
::
:: +del-entry: delete an entry from a bucket, fail quietly if bucket does not
:: exist
::
++ del-entry
|= [=desk buc=key =key]
^- (quip card _state)
=/ pas=(list path)
:~ /all
/desk/[desk]
/bucket/[desk]/[buc]
/entry/[desk]/[buc]/[key]
==
=/ bucket=(unit bucket) (~(get bi settings) desk buc)
?~ bucket
[~ state]
=. u.bucket (~(del by u.bucket) key)
:- [(give-event pas %del-entry desk buc key)]~
state(settings (~(put bi settings) desk buc u.bucket))
::
++ give-event
|= [pas=(list path) evt=event]
^- card
[%give %fact pas %settings-event !>(evt)]
--

View File

@ -135,7 +135,7 @@
%arvo
%k
%fard
%garden :: XX: %landscape?
%landscape
%vitals-connection-check
%noun
!>(ship)
@ -150,7 +150,7 @@
%arvo
%k
%fard
%garden :: XX: %landscape?
%landscape
%vitals-connection-check
%noun
!>(ship)

View File

@ -1,12 +1,11 @@
:~ %docket
%treaty
%hark-store
%hark-system-hook
%settings
%settings-store
%storage
:~ %bait
%contacts
%docket
%hark
%reel
%bait
%settings
%storage
%treaty
%vitals
%growl
==

View File

@ -4,7 +4,7 @@
glob-http+['https://bootstrap.urbit.org/glob-0v3.26u3l.bgtqj.v0tu0.t5kpu.91p45.glob' 0v3.26u3l.bgtqj.v0tu0.t5kpu.91p45]
::glob-ames+~zod^0v0
base+'grid'
version+[1 15 0]
version+[2 0 0]
website+'https://tlon.io'
license+'MIT'
==

View File

@ -0,0 +1,14 @@
/- h=hark
:- %say
|= $: [now=@da eny=@uvJ =beak]
[[all=? des=? =desk con=(list content:h)] [group=(unit flag:h) thread=path ~]]
==
=/ =id:h (end [7 1] eny)
=/ =rope:h
[group ~ desk thread]
=/ =note:h
[id rope now con ~ ~]
~& > adding/id
:- %hark-action
^- action:h
[%add-note all des note]

View File

@ -0,0 +1,8 @@
/- h=hark
:- %say
|= $: [now=@da eny=@uvJ =beak]
[[=rope:h ~] ~]
==
:- %hark-action
^- action:h
[%saw-rope rope]

View File

@ -0,0 +1,8 @@
/- h=hark
:- %say
|= $: [now=@da eny=@uvJ =beak]
[[=seam:h ~] ~]
==
:- %hark-action
^- action:h
[%saw-seam seam]

131
desk/lib/contacts-json.hoon Normal file
View File

@ -0,0 +1,131 @@
/- c=contacts, g=groups
/+ gj=groups-json
|%
++ enjs
=, enjs:format
|%
:: XX shadowed for compat, +ship:enjs removes the ~
::
++ ship
|=(her=@p n+(rap 3 '"' (scot %p her) '"' ~))
::
++ action
|= a=action:c
^- json
%+ frond -.a
?- -.a
%anon ~
%edit a+(turn p.a field)
%meet a+(turn p.a ship)
%heed a+(turn p.a ship)
%drop a+(turn p.a ship)
%snub a+(turn p.a ship)
==
::
++ contact
|= c=contact:c
^- json
%- pairs
:~ nickname+s+nickname.c
bio+s+bio.c
status+s+status.c
color+s+(scot %ux color.c)
avatar+?~(avatar.c ~ s+u.avatar.c)
cover+?~(cover.c ~ s+u.cover.c)
::
=- groups+a+-
%- ~(rep in groups.c)
|=([f=flag:g j=(list json)] [s+(flag:enjs:gj f) j])
==
::
++ field
|= f=field:c
^- json
%+ frond -.f
?- -.f
%nickname s+nickname.f
%bio s+bio.f
%status s+status.f
%color s+(rsh 3^2 (scot %ux color.f)) :: XX confirm
%avatar ?~(avatar.f ~ s+u.avatar.f)
%cover ?~(cover.f ~ s+u.cover.f)
%add-group s+(flag:enjs:gj flag.f)
%del-group s+(flag:enjs:gj flag.f)
==
::
++ rolodex
|= r=rolodex:c
^- json
%- pairs
%- ~(rep by r)
|= [[who=@p foreign:c] j=(list [@t json])]
[[(scot %p who) ?.(?=([@ ^] for) ~ (contact con.for))] j] :: XX stale flag per sub state?
::
++ news
|= n=news:c
^- json
%- pairs
:~ who+(ship who.n)
con+?~(con.n ~ (contact con.n))
==
--
::
++ dejs
=, dejs:format
|%
:: for performance, @p is serialized above to json %n (no escape)
:: for mark roundtrips, ships are parsed from either %s or %n
:: XX do this elsewhere in groups?
::
++ ship (se-ne %p)
++ se-ne
|= aur=@tas
|= jon=json
?+ jon !!
[%s *] (slav aur p.jon)
::
[%n *] ~| bad-n+p.jon
=/ wyd (met 3 p.jon)
?> ?& =('"' (end 3 p.jon))
=('"' (cut 3 [(dec wyd) 1] p.jon))
==
(slav aur (cut 3 [1 (sub wyd 2)] p.jon))
==
::
++ action
^- $-(json action:c)
%- of
:~ anon+ul
edit+(ar field)
meet+(ar ship)
heed+(ar ship)
drop+(ar ship)
snub+(ar ship)
==
::
++ contact
^- $-(json contact:c)
%- ot
:~ nickname+so
bio+so
status+so
color+nu
avatar+(mu so)
cover+(mu so)
groups+(as flag:dejs:gj)
==
::
++ field
^- $-(json field:c)
%- of
:~ nickname+so
bio+so
status+so
color+nu
avatar+(mu so)
cover+(mu so)
add-group+flag:dejs:gj
del-group+flag:dejs:gj
==
--
--

21
desk/lib/groups-json.hoon Normal file
View File

@ -0,0 +1,21 @@
/- g=groups
|%
++ enjs
=, enjs:format
|%
++ flag
|= f=flag:g
(rap 3 (scot %p p.f) '/' q.f ~)
::
++ nest
|= n=nest:g
(rap 3 p.n '/' (flag q.n) ~)
--
++ dejs
=, dejs:format
|%
++ ship (se %p)
++ flag (su ;~((glue fas) ;~(pfix sig fed:ag) sym))
++ nest (su ;~((glue fas) sym ;~(pfix sig fed:ag)))
--
--

232
desk/lib/hark-json.hoon Normal file
View File

@ -0,0 +1,232 @@
/- h=hark
/+ groups-json
|%
++ enjs
=, enjs:format
|%
++ action
|= a=action:h
%+ frond -.a
?- -.a
%add-yarn (add-yarn +.a)
%saw-seam (seam +.a)
%saw-rope (rope +.a)
==
::
++ blanket
|= b=blanket:h
%- pairs
:~ seam/(seam seam.b)
yarns/(yarns yarns.b)
quilt/(quilt quilt.b)
==
::
++ quilt
|= q=quilt:h
%- pairs
%+ turn (tap:on:quilt:h q)
|= [num=@ud t=thread:h]
[(scot %ud num) (thread t)]
::
++ add-yarn
|= [all=? desk=? yar=yarn:h]
%- pairs
:~ all/b/all
desk/b/desk
yarn/(yarn yar)
==
::
++ carpet
|= c=carpet:h
^- json
%- pairs
:~ seam/(seam seam.c)
yarns/(yarns yarns.c)
cable/(cable cable.c)
stitch/(numb stitch.c)
==
::
++ cable
|= c=(map rope:h thread:h)
^- json
:- %a
%+ turn ~(tap by c)
|= [r=rope:h t=thread:h]
%- pairs
:~ rope/(rope r)
thread/(thread t)
==
::
++ skeins
|= sks=(list skein:h)
^- json
:- %a
%+ turn sks
|= =skein:h
%- pairs
:~ time/(time time.skein)
count/(numb count.skein)
ship-count/(numb ship-count.skein)
top/(yarn top.skein)
unread/b/unread.skein
==
++ id
|= i=id:h
^- json
s/(scot %uv i)
::
++ thread
|= t=thread:h
^- json
:- %a
(turn ~(tap in t) id)
::
++ threads
|= ts=(map @da thread:h)
%- pairs
%+ turn ~(tap by ts)
|= [tim=@da t=thread:h]
^- [cord json]
[(scot %da tim) (thread t)]
::
++ update
|= u=update:h
%- pairs
:~ yarns/(yarns yarns.u)
seam/(seam seam.u)
threads/(threads threads.u)
==
::
++ yarns
|= ys=(map id:h yarn:h)
^- json
%- pairs
%+ turn ~(tap by ys)
|= [i=id:h y=yarn:h]
[(scot %uv i) (yarn y)]
::
++ yarn
|= y=yarn:h
^- json
%- pairs
:~ id/s/(scot %uv id.y)
rope/(rope rop.y)
time/(time tim.y)
con/a/(turn con.y content)
wer/s/(spat wer.y)
button/~
==
::
++ content
|= c=content:h
^- json
?@ c s/c
?- -.c
%ship (frond ship/s/(scot %p p.c))
%emph (frond emph/s/p.c)
==
::
++ seam
|= s=seam:h
%+ frond -.s
^- json
?- -.s
%all ~
%group s/(flag flag.s)
%desk s/desk.s
==
::
++ flag flag:enjs:groups-json
++ nest nest:enjs:groups-json
::
++ rope
|= r=rope:h
^- json
%- pairs
:~ group/?~(gop.r ~ s/(flag u.gop.r))
channel/?~(can.r ~ s/(nest u.can.r))
desk/s/des.r
thread/s/(spat ted.r)
==
--
::
++ dejs
=, dejs:format
|%
++ action
%- of
:~ saw-seam/seam
saw-rope/rope
add-yarn/add-yarn
==
++ action-1
%- of
:~ saw-seam/seam
saw-rope/rope
add-yarn/add-yarn
new-yarn/new-yarn
==
::
++ seam
%- of
:~ all/ul
desk/so
group/flag
==
::
++ add-yarn
%- ot
:~ all/bo
desk/bo
yarn/yarn
==
::
++ new-yarn
%- ot
:~ all/bo
desk/bo
rope/rope
con/(ar content)
wer/pa
but/(mu button)
==
::
++ button
%- ot
:~ title/so
hanlder/pa
==
::
++ content
|= j=json
^- content:h
?: ?=([%s *] j) p.j
=> .(j `json`j)
%. j
%- of
:~ ship/ship
emph/so
==
::
++ yarn
%- ot
:~ id/(se %uvh)
rope/rope
time/(se %da)
con/(ar content)
wer/pa
but/(mu button)
==
::
++ flag flag:dejs:groups-json
++ nest nest:dejs:groups-json
++ ship ship:dejs:groups-json
++ rope
%- ot
:~ group/(mu flag)
channel/(mu nest)
desk/so
thread/pa
==
--
--

View File

@ -1,254 +0,0 @@
/- sur=hark-store
^?
=, sur
=< [. sur]
|%
++ enjs
=, enjs:format
|%
++ update
|= upd=^update
^- json
%+ frond -.upd
?+ -.upd a+~
%added (notification +.upd)
%add-note (add-note +.upd)
%timebox (timebox +.upd)
%more (more +.upd)
%read-each (read-each +.upd)
%read-count (place +.upd)
%unread-each (read-each +.upd)
%unread-count (unread-count +.upd)
%saw-place (saw-place +.upd)
%all-stats (all-stats +.upd)
%del-place (place +.upd)
::%read-note (index +.upd)
::%note-read (note-read +.upd)
%archived (archived +.upd)
==
::
++ add-note
|= [bi=^bin bo=^body]
%- pairs
:~ bin+(bin bi)
body+(body bo)
==
::
++ saw-place
|= [p=^place t=(unit ^time)]
%- pairs
:~ place+(place p)
time+?~(t ~ (time u.t))
==
::
++ archived
|= [t=^time l=^lid n=^notification]
%- pairs
:~ lid+(lid l)
time+s+(scot %ud t)
notification+(notification n)
==
::
++ note-read
|= *
(pairs ~)
::
++ all-stats
|= places=(map ^place ^stats)
^- json
:- %a
^- (list json)
%+ turn ~(tap by places)
|= [p=^place s=^stats]
%- pairs
:~ stats+(stats s)
place+(place p)
==
::
++ stats
|= s=^stats
^- json
%- pairs
:~ each+a+(turn ~(tap in each.s) (cork spat (lead %s)))
last+(time last.s)
count+(numb count.s)
==
++ more
|= upds=(list ^update)
^- json
a+(turn upds update)
::
++ place
|= =^place
%- pairs
:~ desk+s+desk.place
path+s+(spat path.place)
==
::
++ bin
|= =^bin
%- pairs
:~ place+(place place.bin)
path+s+(spat path.bin)
==
++ notification
|= ^notification
^- json
%- pairs
:~ time+(time date)
bin+(^bin bin)
body+(bodies body)
==
++ bodies
|= bs=(list ^body)
^- json
a+(turn bs body)
::
++ contents
|= cs=(list ^content)
^- json
a+(turn cs content)
::
++ content
|= c=^content
^- json
%+ frond -.c
?- -.c
%ship s+(scot %p ship.c)
%text s+cord.c
==
::
++ body
|= ^body
^- json
%- pairs
:~ title+(contents title)
content+(contents content)
time+(^time time)
link+s+(spat link)
==
::
++ binned-notification
|= [=^bin =^notification]
%- pairs
:~ bin+(^bin bin)
notification+(^notification notification)
==
++ lid
|= l=^lid
^- json
%+ frond -.l
?- -.l
?(%seen %unseen) ~
%archive s+(scot %ud time.l)
==
::
++ timebox
|= [li=^lid l=(list ^notification)]
^- json
%- pairs
:~ lid+(lid li)
notifications+a+(turn l notification)
==
::
++ read-each
|= [p=^place pax=^path]
%- pairs
:~ place+(place p)
path+(path pax)
==
::
++ unread-count
|= [p=^place inc=? count=@ud]
%- pairs
:~ place+(place p)
inc+b+inc
count+(numb count)
==
--
++ dejs
=, dejs:format
|%
++ ship (su ;~(pfix sig fed:ag))
:: TODO: fix +stab
::
++ pa
|= j=json
^- path
?> ?=(%s -.j)
?: =('/' p.j) /
(stab p.j)
::
++ place
%- ot
:~ desk+so
path+pa
==
::
++ bin
%- ot
:~ path+pa
place+place
==
::
++ read-each
%- ot
:~ place+place
path+pa
==
::
:: parse date as @ud
:: TODO: move to zuse
++ sd
|= jon=json
^- @da
?> ?=(%s -.jon)
`@da`(rash p.jon dem:ag)
::
++ lid
%- of
:~ archive+sd
unseen+ul
seen+ul
==
::
++ archive
%- ot
:~ lid+lid
bin+bin
==
++ content
%- of
:~ text+so
ship+ship
==
::
++ body
%- ot
:~ title+(ar content)
content+(ar content)
time+di
binned+pa
link+pa
==
::
++ add-note
%- ot
:~ bin+bin
body+body
==
::
++ action
^- $-(json ^action)
%- of
:~ archive-all+ul
archive+archive
opened+ul
read-count+place
read-each+read-each
read-note+bin
add-note+add-note
==
--
--

View File

@ -1,35 +0,0 @@
/+ store=hark-store
|_ =archive:store
++ orm ((on @da timebox:store) gth)
++ del
|= [=time =bin:store]
?~ box=(get:orm archive time) archive
(put:orm archive time (~(del by u.box) bin))
++ put
|= [=time =bin:store =notification:store]
=/ box=timebox:store (fall (get:orm archive time) ~)
=. box (~(put by box) bin notification)
(put:orm archive time box)
::
++ get
|= [=time =bin:store]
^- (unit notification:store)
?~ box=(get:orm archive time) ~
(~(get by u.box) bin)
::
++ got
|= [=time =bin:store]
(need (get time bin))
::
++ has
|= [=time =bin:store]
?~((get time bin) %.n %.y)
::
++ jab
|= [=time =bin:store f=$-(notification:store notification:store)]
(put time bin (f (got time bin)))
::
++ job
|= [=time =bin:store f=$-((unit notification:store) notification:store)]
(put time bin (f (get time bin)))
--

View File

@ -0,0 +1,6 @@
/$ rolo %contact-rolodex %json
/$ contact %contact %json
/$ skeins %hark-skeins %json
/$ carpet %hark-carpet %json
/$ blanket %hark-blanket %json
~

View File

@ -0,0 +1,139 @@
|* [key=mold val=mold]
=> |%
+$ item [key=key val=val]
--
~% %mope-comp ..zuse ~
|= compare=$-([key key] ?)
~% %mope-core ..zuse ~
|%
:: +bat: tabulate a subset excluding start element with a max count (backwards)
::
++ bat
|= [a=(tree item) b=(unit key) c=@]
^- (list item)
|^
e:(tabulate (del-span a b) b c)
::
++ tabulate
|= [a=(tree item) b=(unit key) c=@]
^- [d=@ e=(list item)]
?: ?&(?=(~ b) =(c 0))
[0 ~]
=| f=[d=@ e=(list item)]
|- ^+ f
?: ?|(?=(~ a) =(d.f c)) f
=. f $(a r.a)
?: =(d.f c) f
=. f [+(d.f) [n.a e.f]]
?:(=(d.f c) f $(a l.a))
::
++ del-span
|= [a=(tree item) b=(unit key)]
^- (tree item)
?~ a a
?~ b a
?: =(key.n.a u.b)
l.a
?. (compare key.n.a u.b)
$(a l.a)
a(r $(a r.a))
--
:: +dop: dip:on but in reverse order (right to left)
::
++ dop
|* state=mold
|= $: a=(tree item)
=state
f=$-([state item] [(unit val) ? state])
==
^+ [state a]
:: acc: accumulator
::
:: .stop: set to %.y by .f when done traversing
:: .state: threaded through each run of .f and produced by +abet
::
=/ acc [stop=`?`%.n state=state]
=< abet =< main
|%
++ this .
++ abet [state.acc a]
:: +main: main recursive loop; performs a partial inorder traversal
::
++ main
^+ this
:: stop if empty or we've been told to stop
::
?: =(~ a) this
?: stop.acc this
:: reverse in-order traversal: right -> node -> left, until .f sets .stop
::
=. this right
?: stop.acc this
=^ del this node
=? this !stop.acc left
:: XX: remove for now; bring back when upstreaming
:: =? a del (nip a)
this
:: +node: run .f on .n.a, updating .a, .state, and .stop
::
++ node
^+ [del=*? this]
:: run .f on node, updating .stop.acc and .state.acc
::
?> ?=(^ a)
=^ res acc (f state.acc n.a)
?~ res
[del=& this]
[del=| this(val.n.a u.res)]
:: +left: recurse on left subtree, copying mutant back into .l.a
::
++ left
^+ this
?~ a this
=/ lef main(a l.a)
lef(a a(l a.lef))
:: +right: recurse on right subtree, copying mutant back into .r.a
::
++ right
^+ this
?~ a this
=/ rig main(a r.a)
rig(a a(r a.rig))
--
:: +bot: produce the N leftmost elements
::
++ bot
|= [a=(tree item) b=@]
^- (list item)
|^ p:(items-with-remainder a b)
++ items-with-remainder
|= [a=(tree item) b=@]
^- (pair (list item) @)
?~ a [~ b]
?: =(b 0) [~ 0]
=/ left-result (items-with-remainder l.a b)
?: =(q.left-result 0) left-result
?: =(q.left-result 1) [(zing ~[p.left-result ~[n.a]]) (dec q.left-result)]
=/ right-result
(items-with-remainder r.a (dec q.left-result))
[(zing ~[p.left-result ~[n.a] p.right-result]) q.right-result]
--
:: +top: produce the N rightmost elements
::
++ top
|= [a=(tree item) b=@]
^- (list item)
|^ p:(items-with-remainder a b)
++ items-with-remainder
|= [a=(tree item) b=@]
^- (pair (list item) @)
?~ a [~ b]
?: =(b 0) [~ 0]
=/ right-result (items-with-remainder r.a b)
?: =(q.right-result 0) right-result
?: =(q.right-result 1) [[n.a p.right-result] (dec q.right-result)]
=/ left-result
(items-with-remainder l.a (dec q.right-result))
[(zing ~[p.left-result ~[n.a] p.right-result]) q.left-result]
--
--

14
desk/mar/contact.hoon Normal file
View File

@ -0,0 +1,14 @@
/- c=contacts
/+ j=contacts-json
|_ =contact:g
++ grad %noun
++ grow
|%
++ noun group
++ json (contact:enjs:j contact)
--
++ grab
|%
++ noun contact:g
--
--

View File

@ -0,0 +1,15 @@
/- c=contacts
/+ j=contacts-json
|_ =action:c
++ grad %noun
++ grow
|%
++ noun action
++ json (action:enjs:j action)
--
++ grab
|%
++ noun action:c
++ json action:dejs:j
--
--

View File

@ -0,0 +1,2 @@
/= mark /mar/dummy
mark

View File

@ -0,0 +1,2 @@
/= mark /mar/contact/action-0
mark

View File

@ -0,0 +1,14 @@
/- c=contacts
/+ j=contacts-json
|_ =news:c
++ grad %noun
++ grow
|%
++ noun news
++ json (news:enjs:j news)
--
++ grab
|%
++ noun news:c
--
--

View File

@ -0,0 +1,14 @@
/- c=contacts
/+ j=contacts-json
|_ rol=rolodex:c
++ grad %noun
++ grow
|%
++ noun rol
++ json (rolodex:enjs:j rol)
--
++ grab
|%
++ noun rolodex:c
--
--

View File

@ -0,0 +1,12 @@
/- c=contacts
|_ =update:c
++ grad %noun
++ grow
|%
++ noun update
--
++ grab
|%
++ noun update:c
--
--

View File

@ -0,0 +1,2 @@
/= mark /mar/dummy
mark

View File

@ -0,0 +1,2 @@
/= mark /mar/contact/update-0
mark

11
desk/mar/dummy.hoon Normal file
View File

@ -0,0 +1,11 @@
|_ dum=*
++ grad %noun
++ grow
|%
++ noun dum
--
++ grab
|%
+$ noun *
--
--

12
desk/mar/epic.hoon Normal file
View File

@ -0,0 +1,12 @@
/- e=epic
|_ =epic:e
++ grad %noun
++ grow
|%
++ noun epic
--
++ grab
|%
++ noun epic:e
--
--

View File

@ -0,0 +1,14 @@
/- h=hark
/+ j=hark-json
|_ action=action-1:h
++ grad %noun
++ grow
|%
++ noun action
--
++ grab
|%
++ noun action-1:h
++ json action-1:dejs:j
--
--

View File

@ -1,13 +1,15 @@
/+ *hark-store
|_ act=action
/- h=hark
/+ j=hark-json
|_ =action:h
++ grad %noun
++ grow
|%
++ noun act
++ noun action
++ json (action:enjs:j action)
--
++ grab
|%
++ noun action
++ json action:dejs
++ noun action:h
++ json action:dejs:j
--
--

View File

@ -0,0 +1,14 @@
/- h=hark
/+ j=hark-json
|_ =blanket:h
++ grad %noun
++ grow
|%
++ noun blanket
++ json (blanket:enjs:j blanket)
--
++ grab
|%
++ noun blanket:h
--
--

14
desk/mar/hark/carpet.hoon Normal file
View File

@ -0,0 +1,14 @@
/- h=hark
/+ j=hark-json
|_ =carpet:h
++ grad %noun
++ grow
|%
++ noun carpet
++ json (carpet:enjs:j carpet)
--
++ grab
|%
++ noun carpet:h
--
--

14
desk/mar/hark/skeins.hoon Normal file
View File

@ -0,0 +1,14 @@
/- h=hark
/+ j=hark-json
|_ skeins=(list skein:h)
++ grad %noun
++ grow
|%
++ noun skeins
++ json (skeins:enjs:j skeins)
--
++ grab
|%
++ noun (list skein:h)
--
--

View File

@ -1,13 +0,0 @@
/+ *hark-store
|_ upd=update
++ grad %noun
++ grow
|%
++ noun upd
++ json (update:enjs upd)
--
++ grab
|%
++ noun update
--
--

14
desk/mar/hark/yarn.hoon Normal file
View File

@ -0,0 +1,14 @@
/- h=hark
/+ j=hark-json
|_ =yarn:h
++ grad %noun
++ grow
|%
++ noun yarn
++ json (yarn:enjs:j yarn)
--
++ grab
|%
++ noun yarn:h
--
--

View File

@ -1,9 +1,7 @@
/- g=groups, graph-store
/- g=groups
/- meta
/- metadata-store
/- cite
/- e=epic
/+ lib-graph=graph-store
|%
:: $writ: a chat message
+$ writ [seal memo]
@ -333,15 +331,4 @@
readers=(set sect:g)
writers=(set sect:g)
==
++ met metadata-store
+$ club-import [ships=(set ship) =association:met =graph:gra]
+$ club-imports (map flag club-import)
::
+$ import [writers=(set ship) =association:met =update-log:gra =graph:gra]
::
+$ imports (map flag import)
::
++ gra graph-store
++ orm-gra orm:lib-graph
++ orm-log-gra orm-log:lib-graph
--

View File

@ -1,9 +1,7 @@
/- g=groups, graph-store
/- g=groups
/- meta
/- metadata-store
/- cite
/- e=epic
/+ lib-graph=graph-store
|%
:: $writ: a chat message
+$ writ [seal memo]
@ -338,15 +336,4 @@
readers=(set sect:g)
writers=(set sect:g)
==
++ met metadata-store
+$ club-import [ships=(set ship) =association:met =graph:gra]
+$ club-imports (map flag club-import)
::
+$ import [writers=(set ship) =association:met =update-log:gra =graph:gra]
::
+$ imports (map flag import)
::
++ gra graph-store
++ orm-gra orm:lib-graph
++ orm-log-gra orm-log:lib-graph
--

View File

@ -1,9 +1,7 @@
/- g=groups, graph-store, uno=chat-1, zer=chat-0
/- g=groups, uno=chat-1, zer=chat-0
/- meta
/- metadata-store
/- cite
/- e=epic
/+ lib-graph=graph-store
|%
++ old
|%
@ -358,15 +356,4 @@
readers=(set sect:g)
writers=(set sect:g)
==
++ met metadata-store
+$ club-import [ships=(set ship) =association:met =graph:gra]
+$ club-imports (map flag club-import)
::
+$ import [writers=(set ship) =association:met =update-log:gra =graph:gra]
::
+$ imports (map flag import)
::
++ gra graph-store
++ orm-gra orm:lib-graph
++ orm-log-gra orm-log:lib-graph
--

89
desk/sur/contacts.hoon Normal file
View File

@ -0,0 +1,89 @@
/- e=epic, g=groups
|%
:: [compat] protocol-versioning scheme
::
:: adopted from :groups, slightly modified.
::
:: for our action/update marks, we
:: - *must* support our version (+okay)
:: - *should* support previous versions (especially actions)
:: - but *can't* support future versions
::
:: in the case of updates at unsupported protocol versions,
:: we backoff and subscribe for version changes (/epic).
:: (this alone is unlikely to help with future versions,
:: but perhaps our peer will downgrade. in the meantime,
:: we wait to be upgraded.)
::
+| %compat
++ okay `epic`0
++ mar
|%
++ base
|%
+$ act %contact-action
+$ upd %contact-update
--
::
++ act `mark`^~((rap 3 *act:base '-' (scot %ud okay) ~))
++ upd `mark`^~((rap 3 *upd:base '-' (scot %ud okay) ~))
--
::
+| %types
+$ contact
$: nickname=@t
bio=@t
status=@t
color=@ux
avatar=(unit @t)
cover=(unit @t)
groups=(set flag:g)
==
::
+$ foreign [for=$@(~ profile) sag=$@(~ saga)]
+$ profile [wen=@da con=$@(~ contact)]
+$ rolodex (map ship foreign)
::
+$ epic epic:e
+$ saga
$@ $? %want :: subscribing
%fail :: %want failed
%lost :: epic %fail
~ :: none intended
==
saga:e
::
+$ field
$% [%nickname nickname=@t]
[%bio bio=@t]
[%status status=@t]
[%color color=@ux]
[%avatar avatar=(unit @t)]
[%cover cover=(unit @t)]
[%add-group =flag:g]
[%del-group =flag:g]
==
::
+$ action
:: %anon: delete our profile
:: %edit: change our profile
:: %meet: track a peer
:: %heed: follow a peer
:: %drop: discard a peer
:: %snub: unfollow a peer
::
$% [%anon ~]
[%edit p=(list field)]
[%meet p=(list ship)]
[%heed p=(list ship)]
[%drop p=(list ship)]
[%snub p=(list ship)]
==
::
+$ update :: network
$% [%full profile]
==
::
+$ news :: local
[who=ship con=$@(~ contact)]
--

View File

@ -1,159 +0,0 @@
^?
::
:: %hark-store: Notification, unreads store
::
:: Timeboxing & binning:
::
:: Unread notifications accumulate in $unreads. They are grouped by
:: their $bin. A notification may become read by either:
:: a) being read by a %read-count or %read-each or %read-note
:: b) being read by a %seen
::
:: If a) then we insert the corresponding bin into $reads at the
:: current timestamp
:: If b) then we empty $unreads and move all bins to $reads at the
:: current timestamp
::
:: Unread tracking:
:: Unread tracking has two 'modes' which may be used concurrently,
:: if necessary.
::
:: count:
:: This stores the unreads as a simple atom, describing the number
:: of unread items. May be increased with %unread-count and
:: set to zero with %read-count. Ideal for high-frequency linear
:: datastructures, e.g. chat
:: each:
:: This stores the unreads as a set of paths, describing the set of
:: unread items. Unreads may be added to the set with %unread-each
:: and removed with %read-each. Ideal for non-linear, low-frequency
:: datastructures, e.g. blogs
::
|%
:: $place: A location, under which landscape stores stats
::
:: .desk must match q.byk.bowl
:: Examples:
:: A chat:
:: [%landscape /~dopzod/urbit-help]
:: A note in a notebook:
:: [%landscape /~darrux-landes/feature-requests/12374893234232]
:: A group:
:: [%hark-group-hook /~bitbet-bolbel/urbit-community]
:: Comments on a link
:: [%landscape /~dabben-larbet/urbit-in-the-news/17014118450499614194868/2]
::
+$ place [=desk =path]
::
:: $bin: Identifier for grouping notifications
::
:: Examples
:: A mention in a chat:
:: [/mention %landscape /~dopzod/urbit-help]
:: New messages in a chat
:: [/message %landscape /~dopzod/urbit-help]
:: A new comment in a notebook:
:: [/comment %landscape /~darrux-landes/feature-requests/12374893234232/2]
::
+$ bin [=path =place]
::
:: $lid: Reference to a timebox
::
+$ lid
$% [%archive =time]
[%seen ~]
[%unseen ~]
==
:: $content: Notification content
+$ content
$% [%ship =ship]
[%text =cord]
==
::
:: $body: A notification body
::
+$ body
$: title=(list content)
content=(list content)
=time
binned=path
link=path
==
::
+$ notification
[date=@da =bin body=(list body)]
:: $timebox: Group of notificatons
+$ timebox
(map bin notification)
:: $archive: Archived notifications, ordered by time
+$ archive
((mop @da timebox) gth)
::
+$ action
$% :: hook actions
::
:: %add-note: add a notification
[%add-note =bin =body]
::
:: %del-place: Underlying resource disappeared, remove all
:: associated notifications
[%del-place =place]
:: %unread-count: Change unread count by .count
[%unread-count =place inc=? count=@ud]
:: %unread-each: Add .path to list of unreads for .place
[%unread-each =place =path]
:: %saw-place: Update last-updated for .place to now.bowl
[%saw-place =place time=(unit time)]
:: store actions
::
:: %archive: archive single notification
:: if .time is ~, then archiving unread notification
:: else, archiving read notification
[%archive =lid =bin]
:: %read-count: set unread count to zero
[%read-count =place]
:: %read-each: remove path from unreads for .place
[%read-each =place =path]
:: %read-note: Read note at .bin
[%read-note =bin]
:: %archive-all: Archive all notifications
[%archive-all ~]
:: %opened: User opened notifications, reset timeboxing logic.
::
[%opened ~]
::
:: XX: previously in hark-store, now deprecated
:: the hooks responsible for creating notifications may offer pokes
:: similar to this
:: [%read-graph =resource]
:: [%read-group =resource]
:: [%remove-graph =resource]
::
==
:: .stats: Statistics for a .place
::
+$ stats
$: count=@ud
each=(set path)
last=@da
timebox=(unit @da)
==
::
+$ update
$% action
:: %more: more updates
[%archived =time =lid =notification]
[%more more=(list update)]
:: %note-read: note has been read with timestamp
[%note-read =time =bin]
[%added =notification]
:: %timebox: description of timebox.
::
[%timebox =lid =(list notification)]
:: %place-stats: description of .stats for a .place
[%place-stats =place =stats]
:: %place-stats: stats for all .places
[%all-stats places=(map place stats)]
==
--

117
desk/sur/hark.hoon Normal file
View File

@ -0,0 +1,117 @@
/- g=groups
|%
:: $rope: notification origin
::
:: Shows where a notification has come from. Used to group
:: notifications into threads
+$ rope
$: gop=(unit flag) :: originating group
can=(unit nest:g) :: originating channel
des=desk :: originating desk
ted=path :: threading identifer
==
:: $thread: notification group
::
+$ thread (set id)
:: $id: notification identifier
+$ id @uvH
:: $yarn: notification
+$ yarn
$: =id
rop=rope :: origin
tim=time :: time sent
con=(list content) :: content of notification
wer=path :: where to link to in FE
but=(unit button) :: action, if any
==
::
:: $new-yarn: type for creating yarns
+$ new-yarn
$: all=?
desk=?
rop=rope
con=(list content)
wer=path
but=(unit button)
==
::
+$ button
$: title=cord
handler=path
==
+$ flag (pair ship term)
:: $content: notification text to be rendered
+$ content
$@ @t
$% [%ship p=ship]
[%emph p=cord]
==
:: $action: Actions for hark
::
:: %add-yarn adds a notification to the relevant inboxes, indicated
:: by the loobs in the type
:: %saw-seam marks all notifications in an inbox as unread
:: %saw-rope marks a particular rope as read in all inboxes
::
+$ action
$% [%add-yarn all=? desk=? =yarn]
[%saw-seam =seam]
[%saw-rope =rope]
==
::
:: $action-1: Actions for hark pt 2
+$ action-1
$% [%new-yarn new-yarn]
action
==
::
+$ update
$: yarns=(map id yarn)
=seam
threads=(map time thread)
==
::
+$ carpet
$: =seam
yarns=(map id yarn)
cable=(map rope thread)
stitch=@ud
==
+$ blanket
$: =seam
yarns=(map id yarn)
=quilt
==
:: $seam: inbox identifier
::
:: All notifications end up in one of these inboxes
+$ seam
$% [%group =flag]
[%desk =desk]
[%all ~]
==
:: $rug: notifications inbox
:: .new contains all "unread" notifications, grouped by $rope
:: .qul is an archive
::
+$ rug
[new=(map rope thread) qul=quilt]
++ quilt
=< quilt
|%
:: $quilt: inbox archive
:: Threads are keyed by an autoincrementing counter that starts at
:: 0
::
+$ quilt ((mop @ud thread) lte)
++ on ((^on @ud thread) lte)
--
::
++ skein
$: =time
count=@ud
ship-count=@ud
top=yarn
unread=?
==
--

View File

@ -1 +1 @@
[%zuse 413]
[%zuse 412]

View File

@ -53,7 +53,7 @@
?> ?=(%finished -.rep)
?~ full-file.rep (pure:m !>(~))
=/ body=cord q.data.u.full-file.rep
=/ parsed=(unit json) (de-json:html body)
=/ parsed=(unit json) (de:json:html body)
?~ parsed (pure:m !>(~))
?~ u.parsed (pure:m !>(~))
=/ mined (mine-json u.parsed)

View File

@ -27,7 +27,7 @@
%- send-raw-card
:* %pass /check-email/(scot %p ship.u.args)
%arvo %k %fard
%garden %hosting-email %noun
%landscape %hosting-email %noun
!>(`[tlon-api-key.u.args ship.u.args])
==
;< [mire=wire mine=sign-arvo] bind:m take-sign-arvo
@ -43,7 +43,7 @@
%- send-raw-card
:* %pass /send-mailchimp-email/(scot %p ship.u.args)
%arvo %k %fard
%garden %mailchimp-send-template %noun
%landscape %mailchimp-send-template %noun
!>(`[mandrill-api-key.u.args (trip email) "landscape-weekly-digest" (template-vars ship.u.args carpet.u.args)])
==
;< [wimp=wire simp=sign-arvo] bind:m take-sign-arvo

View File

@ -18,7 +18,7 @@
header-list=['Content-Type'^'application/json' ~]
^= body
%- some %- as-octt:mimes:html
%- en-json:html
%- en:json:html
%- pairs:enjs:format
:~ ['key' s+(crip api-key)]
==

View File

@ -24,7 +24,7 @@
^= body
%- some
%- as-octt:mimes:html
%- en-json:html
%- en:json:html
%- pairs:enjs:format
:~ ['key' s+(crip api-key)]
['template_name' s+(crip template-name)]

View File

@ -18,7 +18,7 @@
^= body
%- some
%- as-octt:mimes:html
%- en-json:html
%- en:json:html
%- pairs:enjs:format
:~ ['key' s+(crip api-key)]
:- 'message'

View File

@ -27,7 +27,7 @@
^= body
%- some
%- as-octt:mimes:html
%- en-json:html
%- en:json:html
%- pairs:enjs:format
['merge_fields' o+vars]~
==

View File

@ -25,7 +25,7 @@
%- send-raw-card
:* %pass /check-email/(scot %p ship.args)
%arvo %k %fard
%garden %hosting-email %noun
%landscape %hosting-email %noun
!>(`[(trip tlon-api-key.args) ship.args])
==
;< [mire=wire mine=sign-arvo] bind:m take-sign-arvo
@ -41,7 +41,7 @@
%- send-raw-card
:* %pass /update-merge-fields/(scot %p ship.args)
%arvo %k %fard
%garden %mailchimp-update-merge-fields %noun
%landscape %mailchimp-update-merge-fields %noun
=; vars=(map @t json)
!>(`[mailchimp.args u.mail vars])
%- ~(gas by *(map @t json))

View File

@ -1,103 +0,0 @@
/- hark=hark-store
/+ *test, re=hark-unreads
/= agent /app/hark-store
|%
++ place
^- place:hark
[%landscape /graph/~zod/test]
::
++ bin
^- bin:hark
[/ place]
::
++ body
|= run=@
:* ~[text/'Title']
~[text/(crip "Contents {(scow %ud run)}")]
`time`(add (mul ~s1 run) *time)
/
/test
==
::
++ add-note
|= run=@
^- action:hark
[%add-note bin (body run)]
::
++ read-count
^- action:hark
[%read-count place]
::
+$ state
$: %9
places=(map place:hark stats:hark)
seen=timebox:hark
unseen=timebox:hark
=archive:hark
half-open=(map bin:hark @da)
==
++ bowl
|= run=@ud
^- bowl:gall
:* [~zod ~zod %hark-store]
[~ ~]
[run `@uvJ`(shax run) (add (mul run ~s1) *time) [~zod %garden ud+run]]
==
--
|%
::
++ test-half-open
=| run=@ud
=^ mov1 agent
(~(on-poke agent (bowl run)) %hark-action !>((add-note run)))
=^ mova agent
(~(on-poke agent (bowl run)) %noun !>(%sane))
=. run +(run)
=^ mov2 agent
(~(on-poke agent (bowl run)) %hark-action !>(read-count))
=^ mov3 agent
(~(on-poke agent (bowl run)) %noun !>(%sane))
=/ expected-archive=notification:hark
[(add *time (mul ~s1 0)) bin ~[(body 0)]]
=+ !<(=state on-save:agent)
=/ actual-archive=notification:hark
(~(got re archive.state) (add *time ~s1) bin)
(expect-eq !>(expected-archive) !>(actual-archive))
::
++ test-half-open-double
=| run=@ud
=^ mov1 agent
(~(on-poke agent (bowl run)) %hark-action !>((add-note run)))
=. run +(run)
=^ mov2 agent
(~(on-poke agent (bowl run)) %hark-action !>(read-count))
=. run +(run)
=^ mov3 agent
(~(on-poke agent (bowl run)) %hark-action !>((add-note run)))
=. run +(run)
=^ mov4 agent
(~(on-poke agent (bowl run)) %hark-action !>(read-count))
=. run +(run)
=^ mov5 agent
(~(on-poke agent (bowl run)) %noun !>(%sane))
=/ expected-archive=notification:hark
[(add *time (mul ~s1 2)) bin ~[(body 2) (body 0)]]
=+ !<(=state on-save:agent)
=/ actual-archive=notification:hark
(~(got re archive.state) (add *time ~s1) bin)
(expect-eq !>(expected-archive) !>(actual-archive))
::
++ test-half-open-capped
=| run=@ud
|-
?: =(run 31)
=+ !<(=state on-save:agent)
(expect-eq !>(~) !>(half-open.state))
=^ movs agent
(~(on-poke agent (bowl run)) %hark-action !>((add-note run)))
=^ mavs agent
(~(on-poke agent (bowl run)) %hark-action !>(read-count))
$(run +(run))
::
--

View File

@ -30,11 +30,11 @@ const getNoteRedirect = (path: string) => {
return `/apps/${desk}`;
}
if (path.startsWith('/grid/')) {
if (path.startsWith('/landscape/')) {
// Handle links to grid features (preferences, etc)
const route = path
.split('/')
.filter((el) => el !== 'grid')
.filter((el) => el !== 'landscape')
.join('/');
return route;
}
@ -68,8 +68,8 @@ const AppRoutes = () => {
useEffect(() => {
const query = new URLSearchParams(search);
if (query.has('grid-note')) {
const redir = getNoteRedirect(query.get('grid-note')!);
if (query.has('landscape-note')) {
const redir = getNoteRedirect(query.get('landscape-note')!);
navigate(redir);
}
}, [search]);
@ -89,7 +89,7 @@ const AppRoutes = () => {
useEffect(
handleError(() => {
window.name = 'grid';
window.name = 'landscape';
bootstrap();
@ -124,7 +124,7 @@ function Scheduler() {
}
export function App() {
const base = import.meta.env.MODE === 'mock' ? undefined : '/apps/grid';
const base = import.meta.env.MODE === 'mock' ? undefined : '/apps/landscape';
return (
<ErrorBoundary

View File

@ -259,7 +259,7 @@ export default function Notification({ bin, groups }: NotificationProps) {
>
<DeskLink
onClick={onClick}
to={`?grid-note=${encodeURIComponent(wer || '')}`}
to={`?landscape-note=${encodeURIComponent(wer || '')}`}
desk={rope.desk || ''}
className="flex flex-1 space-x-3"
>

View File

@ -55,7 +55,7 @@ function AppLinkNavigate({ desk, link }: { desk: string; link: string }) {
}
const query = new URLSearchParams({
'grid-link': encodeURIComponent(`/${link}`),
'landscape-link': encodeURIComponent(`/${link}`),
});
const url = `${getAppHref(charge.href)}?${query.toString()}`;

View File

@ -36,7 +36,7 @@ export function InterfacePrefs() {
try {
window.navigator.registerProtocolHandler(
'web+urbitgraph',
'/apps/grid/perma?ext=%s',
'/apps/landscape/perma?ext=%s',
// @ts-expect-error ts has the wrong types for protocolhandler
'Urbit Links'
);
@ -53,7 +53,7 @@ export function InterfacePrefs() {
// @ts-expect-error ts has the wrong types for protocolhandler
window.navigator.unregisterProtocolHandler(
'web+urbitgraph',
'/apps/grid/perma?ext=%s'
'/apps/landscape/perma?ext=%s'
);
setProtocolHandling(false);
} catch (e) {

View File

@ -20,7 +20,7 @@ export default ({ mode }) => {
console.log(SHIP_URL);
return defineConfig({
base: mode === 'mock' ? undefined : '/apps/grid/',
base: mode === 'mock' ? undefined : '/apps/landscape/',
server: mode === 'mock' ? undefined : { https: true },
build:
mode !== 'profile'
@ -50,7 +50,7 @@ export default ({ mode }) => {
: [
basicSsl(),
urbitPlugin({
base: 'grid',
base: 'landscape',
target: SHIP_URL,
changeOrigin: true,
secure: false,