Merge remote-tracking branch 'origin/dist' into hm/grid-design-refinements

This commit is contained in:
Liam Fitzgerald 2021-09-09 09:39:52 +10:00
commit 362b69c851
173 changed files with 2993 additions and 43226 deletions

View File

@ -1,3 +1,4 @@
/* Examples
Shared urbit and urbit-worker binaries:

View File

@ -2,8 +2,8 @@
/+ drum=hood-drum, helm=hood-helm, kiln=hood-kiln
|%
+$ state
$~ [%17 *state:drum *state:helm *state:kiln]
$>(%17 any-state)
$~ [%19 *state:drum *state:helm *state:kiln]
$>(%19 any-state)
::
+$ any-state
$% [ver=?(%1 %2 %3 %4 %5 %6) lac=(map @tas fin-any-state)]
@ -18,6 +18,8 @@
[%15 drum=state-2:drum helm=state:helm kiln=state-2:kiln]
[%16 drum=state-4:drum helm=state:helm kiln=state-3:kiln]
[%17 drum=state-4:drum helm=state:helm kiln=state-4:kiln]
[%18 drum=state-4:drum helm=state:helm kiln=state-5:kiln]
[%19 drum=state-4:drum helm=state:helm kiln=state-6:kiln]
==
+$ any-state-tuple
$: drum=any-state:drum

View File

@ -0,0 +1,5 @@
:- %say
|= $: [now=@da eny=@uvJ bec=beak]
[[=desk ~] ~]
==
[%kiln-pause desk]

View File

@ -0,0 +1,5 @@
:- %say
|= $: [now=@da eny=@uvJ bec=beak]
[[=desk ~] ~]
==
[%kiln-resume desk]

View File

@ -1 +0,0 @@
../../base-dev/lib/docket.hoon

View File

@ -5,7 +5,9 @@
=, format
=* dude dude:gall
|%
+$ state state-4
+$ state state-6
+$ state-6 [%6 pith-6]
+$ state-5 [%5 pith-5]
+$ state-4 [%4 pith-4]
+$ state-3 [%3 pith-3]
+$ state-2 [%2 pith-2]
@ -13,13 +15,32 @@
+$ state-0 [%0 pith-0]
+$ any-state
$~ *state
$% state-4
$% state-6
state-5
state-4
state-3
state-2
state-1
state-0
==
+$ pith-4 ::
::
+$ pith-6
$: wef=(unit weft)
rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) ::
ark=(map desk arak) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
:: map desk to the currently ongoing fuse request
:: and the latest version numbers for beaks to
fus=(map desk per-fuse)
:: used for fuses - every time we get a fuse we
:: bump this. used when calculating hashes to
:: ensure they're unique even when the same
:: request is made multiple times.
hxs=(map desk @ud)
== ::
::
+$ pith-5
$: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) ::
ark=(map desk arak) ::
@ -33,6 +54,28 @@
:: request is made multiple times.
hxs=(map desk @ud)
== ::
::
+$ pith-4 ::
$: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) ::
ark=(map desk arak-4) ::
commit-timer=[way=wire nex=@da tim=@dr mon=term] ::
:: map desk to the currently ongoing fuse request
:: and the latest version numbers for beaks to
fus=(map desk per-fuse)
:: used for fuses - every time we get a fuse we
:: bump this. used when calculating hashes to
:: ensure they're unique even when the same
:: request is made multiple times.
hxs=(map desk @ud)
== ::
+$ arak-4
$: =ship
=desk
=aeon
next=(list rung)
=rein
==
+$ pith-3 ::
$: rem=(map desk per-desk) ::
syn=(map kiln-sync let=@ud) ::
@ -51,7 +94,7 @@
$: =ship
=desk
=aeon
next=(list [=aeon =weft])
next=(list rung)
rein=rein-3
==
+$ rein-3
@ -217,22 +260,31 @@
fus.old
hxs.old
==
=? old ?=(%3 -.old)
:* %4
rem.old
syn.old
ark=(~(run by ark.old) |=(a=arak-3 a(rein [liv=& rein.a])))
commit-timer.old
fus.old
hxs.old
==
::
?> ?=(%4 -.old)
=? old ?=(%3 -.old)
:- %4
+.old(ark (~(run by ark.old) |=(a=arak-3 a(rein [liv=& rein.a]))))
::
=? old ?=(%4 -.old)
:- %5
=- +.old(ark -)
%- ~(run by ark.old)
|= a=arak-4
^- arak
[[paused=| ship desk aeon] next rein]:a
=? old ?=(%5 -.old)
[%6 ~ +.old]
::
?> ?=(%6 -.old)
=. +<+.$.abet old
=< abet
?~ old-ota
kiln
abet:(install:vats %base [her sud]:u.old-ota)
=? kiln ?=(^ old-ota)
abet:(install:vats %base [her sud]:u.old-ota)
=? kiln ?=(^ wef)
=/ except=(set desk) (sy %base %kids ~)
(bump:vats u.wef (all-desks-but:vats except) %.n)
=. wef ~
kiln
::
++ on-peek
|= =path
@ -279,7 +331,7 @@
~_ leaf/"kiln: {<lac>} not installed"
vats(loc lac, rak (~(got by ark) lac))
::
++ here "{<loc>} from {<[ship desk]:rak>}"
++ here "{<loc>} from {<[ship desk]:rail.rak>}"
++ make-wire |=(step=@tas /kiln/vats/[loc]/[step])
++ from-wire
|= =wire
@ -299,17 +351,21 @@
++ pyre |=(=tang [%pass /kiln/vats %pyre tang])
++ find (warp %find [%sing %y ud+1 /])
++ sync-da (warp %sync [%sing %w da+now /])
++ sync-ud (warp %sync [%sing %w ud+aeon.rak /])
++ download (warp %download [%sing %v ud+aeon.rak /])
++ warp |=([s=term r=rave] (clay-card s %warp ship.rak desk.rak `r))
++ sync-ud (warp %sync [%sing %w ud+aeon.rail.rak /])
++ download (warp %download [%sing %v ud+aeon.rail.rak /])
++ warp
|= [s=term r=rave]
(clay-card s %warp ship.rail.rak desk.rail.rak `r)
++ merge-main
=/ germ (get-germ loc)
=/ =aeon (dec aeon.rak)
(clay-card %merge-main [%merg loc ship.rak desk.rak ud+aeon germ])
=/ =aeon (dec aeon.rail.rak)
%+ clay-card %merge-main
[%merg loc ship.rail.rak desk.rail.rak ud+aeon germ]
++ merge-kids
=/ germ (get-germ %kids)
=/ =aeon (dec aeon.rak)
(clay-card %merge-kids [%merg %kids ship.rak desk.rak ud+aeon germ])
=/ =aeon (dec aeon.rail.rak)
%+ clay-card %merge-kids
[%merg %kids ship.rail.rak desk.rail.rak ud+aeon germ]
++ clay-card
|= [step=@tas =task:clay]
^- card:agent:gall
@ -361,7 +417,7 @@
vats
=? kiln ?=(^ got) (uninstall lac)
=: loc lac
rak [her rem *aeon next=~ *rein]
rak [[paused=| her rem *aeon] next=~ *rein]
==
~> %slog.0^leaf/"kiln: beginning install into {here}"
(emit find:pass)
@ -372,7 +428,32 @@
~> %slog.0^leaf/"kiln: resetting tracking for {here}"
=. vats (emit (diff:give %reset loc rak))
=. ark (~(del by ark) loc)
(install loc [ship desk]:rak)
(install loc [ship desk]:rail.rak)
:: +pause: stop syncing from upstream
::
++ pause
|= lac=desk
^+ vats
=. vats (abed lac)
~> %slog. :+ %0 %leaf
?: paused.rail.rak
"kiln: {<lac>} already paused, ignoring"
"kiln: {<lac>} pausing updates"
=: paused.rail.rak &
aeon.rail.rak 0
==
vats
:: +resume: restart tracking from upstream
::
++ resume
|= lac=desk
^+ vats
=. vats (abed lac)
~> %slog. :+ %0 %leaf
?. paused.rail.rak
"kiln: {<lac>} already tracking, ignoring"
"kiln: {<lac>} resuming updates"
reset
:: +suspend: shut down all agents, keep syncing
::
++ suspend
@ -423,7 +504,7 @@
=/ ded (find-blocked kel except)
?: force
=. kiln (suspend-many ded)
(bump-many kel (all-desks-but except))
(bump-many kel (all-desks-but (~(uni in except) ded)))
?: =(~ ded)
(bump-many kel (all-desks-but except))
=- (^emit (pyre:pass leaf/- ~))
@ -498,6 +579,8 @@
|= syn=sign-arvo
^+ vats
?> ?=(%writ +<.syn)
?: paused.rail.rak
vats
?~ p.syn
~> %slog.0^leaf/"kiln: cancelled (1) install into {here}, aborting"
vats(ark (~(del by ark) loc))
@ -508,54 +591,85 @@
|= syn=sign-arvo
^+ vats
?> ?=(%writ +<.syn)
?: paused.rail.rak
vats
?~ p.syn
~> %slog.0^leaf/"kiln: cancelled (1) install into {here}, retrying"
reset
~> %slog.0^leaf/"kiln: downloading update for {here}"
=? aeon.rak ?=(%w p.p.u.p.syn) ud:;;(cass:clay q.q.r.u.p.syn)
=? aeon.rail.rak ?=(%w p.p.u.p.syn) ud:;;(cass:clay q.q.r.u.p.syn)
(emit download:pass)
::
++ take-download
|= syn=sign-arvo
^+ vats
?> ?=(%writ +<.syn)
?: paused.rail.rak
vats
?~ p.syn
~> %slog.0^leaf/"kiln: cancelled (2) install into {here}, retrying"
reset
~> %slog.0^leaf/"kiln: finished downloading update for {here}"
=/ old-weft `weft`[%zuse zuse]
=/ new-weft (read-kelvin-foreign [ship desk aeon]:rak)
=. aeon.rak +(aeon.rak)
=/ new-weft (read-kelvin-foreign [ship desk aeon]:rail.rak)
=. aeon.rail.rak +(aeon.rail.rak)
|^ ^+ vats
?: =(%base loc)
do-base
?: (gth num.new-weft num.old-weft)
kelvin-retreat
?: =(num.new-weft num.old-weft)
kelvin-same
kelvin-advance
::
?. =(%base loc)
:: TODO: ?> =(%zuse lal.new-weft) but more flexible for future renames
?: (gth num.new-weft num.old-weft)
~> %slog.0^leaf/"kiln: cannot install {here}, old kelvin {<new-weft>}"
~> %slog.0^leaf/"kiln: will retry at foreign kelvin {<old-weft>}"
=/ =diff [%block loc rak new-weft blockers=(sy %base ~)]
(emil sync-ud:pass (diff:give diff) ~)
?: (lth num.new-weft num.old-weft)
~> %slog.0^leaf/"kiln: future version {<new-weft>}, enqueueing"
=. next.rak (snoc next.rak [(dec aeon.rak) new-weft])
=/ =diff [%block loc rak new-weft blockers=(sy %base ~)]
(emil sync-ud:pass (diff:give diff) ~)
++ kelvin-retreat
^+ vats
~> %slog.0^leaf/"kiln: cannot install {here}, old kelvin {<new-weft>}"
~> %slog.0^leaf/"kiln: will retry at foreign kelvin {<old-weft>}"
=/ =diff [%block loc rak new-weft blockers=(sy %base ~)]
(emil sync-ud:pass (diff:give diff) ~)
::
++ kelvin-advance
^+ vats
~> %slog.0^leaf/"kiln: future version {<new-weft>}, enqueueing"
:: retry upgrade if not blocked anymore
=/ base=arak (~(got by ark) %base)
=. next.rak (snoc next.rak [(dec aeon.rail.rak) new-weft])
=. ark (~(put by ark) loc rak)
=/ =diff [%block loc rak new-weft blockers=(sy %base ~)]
=. vats (emil sync-ud:pass (diff:give diff) ~)
?. &(?=(^ next.base) =(~ (get-blockers weft.i.next.base)))
vats
~> %slog.0^leaf/"kiln: unblocked system update, updating"
=. kiln
(bump-one weft.i.next.base %base)
vats
::
++ kelvin-same
^+ vats
~> %slog.0^leaf/"kiln: merging into {here}"
=. next.rak +:(crank-next %& (dec aeon.rak))
=. next.rak +:(crank-next %& (dec aeon.rail.rak))
(emil ~[merge-main sync-ud]:pass)
::
=/ blockers
?: =(new-weft old-weft)
~
(get-blockers new-weft)
::
?. =(~ blockers)
~> %slog.0^leaf/"kiln: OTA blocked on {<blockers>}"
=. next.rak (snoc next.rak [(dec aeon.rak) new-weft])
=/ =diff [%block loc rak new-weft blockers]
(emil sync-ud:pass (diff:give diff) ~)
~> %slog.0^leaf/"kiln: applying OTA to {here}, kelvin: {<new-weft>}"
=. next.rak +:(crank-next %& (dec aeon.rak))
(emil ~[merge-main sync-ud]:pass)
++ do-base
^+ vats
=/ blockers
?: =(new-weft old-weft)
~
(get-blockers new-weft)
::
?. =(~ blockers)
~> %slog.0^leaf/"kiln: OTA blocked on {<blockers>}"
=. next.rak (snoc next.rak [(dec aeon.rail.rak) new-weft])
=/ =diff [%block loc rak new-weft blockers]
(emil sync-ud:pass (diff:give diff) ~)
~> %slog.0^leaf/"kiln: applying OTA to {here}, kelvin: {<new-weft>}"
=. next.rak +:(crank-next %& (dec aeon.rail.rak))
=. wef
?: =(old-weft new-weft) ~
`new-weft
(emil ~[merge-main sync-ud]:pass)
--
::
++ take-merge-main
|= syn=sign-arvo
@ -577,8 +691,7 @@
(update-running-apps (get-apps-diff our loc now rein.rak))
?. =(%base loc)
vats
=/ except=(set desk) (sy %base %kids ~)
=. kiln (bump-many zuse/zuse (all-desks-but except))
~> %slog.0^leaf/"kiln: bumping {<zuse>}"
(emit merge-kids:pass)
::
++ take-merge-kids
@ -624,9 +737,9 @@
::
++ crank-next
|= new=(each aeon weft)
^+ [match=*(unit [=aeon =weft]) next.rak]
^+ [match=*(unit rung) next.rak]
=/ rog next.rak
|- ^+ [match=*(unit [=aeon =weft]) next.rak]
|- ^+ [match=*(unit rung) next.rak]
?~ rog [~ next.rak]
?: ?- -.new
%& =(p.new aeon.i.rog)
@ -683,12 +796,14 @@
%kiln-merge =;(f (f !<(_+<.f vase)) poke-merge)
%kiln-mount =;(f (f !<(_+<.f vase)) poke-mount)
%kiln-nuke =;(f (f !<(_+<.f vase)) poke-nuke)
%kiln-suspend =;(f (f !<(_+<.f vase)) poke-suspend)
%kiln-pause =;(f (f !<(_+<.f vase)) poke-pause)
%kiln-permission =;(f (f !<(_+<.f vase)) poke-permission)
%kiln-resume =;(f (f !<(_+<.f vase)) poke-resume)
%kiln-revive =;(f (f !<(_+<.f vase)) poke-revive)
%kiln-rein =;(f (f !<(_+<.f vase)) poke-rein)
%kiln-rm =;(f (f !<(_+<.f vase)) poke-rm)
%kiln-schedule =;(f (f !<(_+<.f vase)) poke-schedule)
%kiln-suspend =;(f (f !<(_+<.f vase)) poke-suspend)
%kiln-sync =;(f (f !<(_+<.f vase)) poke-sync)
%kiln-syncs =;(f (f !<(_+<.f vase)) poke-syncs)
%kiln-track =;(f (f !<(_+<.f vase)) poke-track)
@ -710,7 +825,10 @@
::
++ poke-bump
|= [except=(set desk) force=?]
=/ kel=weft zuse/+(zuse)
=/ =arak
(~(got by ark) %base)
=/ kel=weft
?~(next.arak zuse+zuse weft.i.next.arak)
abet:(bump:vats kel except force)
::
++ poke-cancel
@ -837,6 +955,10 @@
%+ turn (get-apps-have our term now)
|=([=dude ?] [%pass /nuke %arvo %g [%nuke dude]])
::
++ poke-pause
|= =desk
abet:abet:(pause:vats desk)
::
++ poke-permission
|= [syd=desk pax=path pub=?]
=< abet
@ -848,6 +970,10 @@
|= [=desk =rein]
abet:abet:(set-rein:vats +<)
::
++ poke-resume
|= =desk
abet:abet:(resume:vats desk)
::
++ poke-revive
|= =desk
abet:abet:(revive:vats desk)

View File

@ -1 +0,0 @@
../../base-dev/mar/docket.hoon

View File

@ -0,0 +1,23 @@
|%
+$ bump [%kiln-bump except=(set desk) force=_|]
--
|_ b=bump
++ grab
|%
++ noun bump
++ json
^- $-(^json bump)
=, dejs:format
%+ pe %kiln-bump
%- ot
:~ except+(as so)
force+bo
==
--
++ grow
|%
++ noun b
--
--

View File

@ -1 +0,0 @@
../../base-dev/sur/docket.hoon

View File

@ -1,218 +0,0 @@
/- *bill
=, clay
=* dude dude:gall
|%
:: $diff: subscription update
::
+$ diff
$% [%block =desk =arak =weft blockers=(set desk)]
[%reset =desk =arak]
[%merge =desk =arak]
[%merge-sunk =desk =arak =tang]
[%merge-fail =desk =arak =tang]
[%suspend =desk =arak]
[%revive =desk =arak]
==
:: $arak: foreign vat tracker
::
:: .next is a list of pending commits with future kelvins
::
+$ arak
$: =ship
=desk
=aeon
next=(list [=aeon =weft])
=rein
==
:: $rein: diff from desk manifest
::
:: .liv: suspended?
:: .add: agents not in manifest that should be running
:: .sub: agents in manifest that should not be running
::
+$ rein
$: liv=_&
add=(set dude)
sub=(set dude)
==
::
+$ vat [=desk hash=@uv =cass =arak]
:: +report-vats: report on all desk installations
::
++ report-vats
|= [our=@p now=@da]
^- tang
=+ .^ raz=(list vat)
%gx /(scot %p our)/hood/(scot %da now)/kiln/vats/noun
==
(turn raz |=(v=vat (report-vat our now v)))
:: +report-vat: report on a single desk installation
::
++ report-vat
|= [our=ship now=@da vat]
^- tank
=+ .^(=weft %cx /(scot %p our)/[desk]/(scot %da now)/sys/kelvin)
:+ %rose ["" "{<desk>}" "::"]
^- tang
=- ?: =(~ next.arak) -
%+ snoc -
leaf/"pending: {<(turn next.arak |=([@ lal=@tas num=@] [lal num]))>}"
^- tang
=/ meb (mergebase-hashes our desk now arak)
=/ sat ?:(liv.rein.arak "running" "suspended")
:~ leaf/"/sys/kelvin: {<[lal num]:weft>}"
leaf/"base hash: {?.(=(1 (lent meb)) <meb> <(head meb)>)}"
leaf/"%cz hash: {<hash>}"
leaf/"source ship: {<ship.arak>}"
leaf/"source desk: {<desk.arak>}"
leaf/"source aeon: {<aeon.arak>}"
leaf/"status: {sat}"
leaf/"force on: {?:(=(~ add.rein.arak) "~" <add.rein.arak>)}"
leaf/"force off: {?:(=(~ sub.rein.arak) "~" <sub.rein.arak>)}"
==
:: +read-kelvin-foreign: read /sys/kelvin from a foreign desk
::
++ read-kelvin-foreign
|= [=ship =desk =aeon]
^- weft
=/ her (scot %p ship)
=/ syd (scot %tas desk)
=/ yon (scot %ud aeon)
::
=/ dom .^(dome cv/~[her syd yon])
=/ tak (scot %uv (~(got by hit.dom) let.dom))
=/ yak .^(yaki cs/~[her syd yon %yaki tak])
=/ lob (scot %uv (~(got by q.yak) /sys/kelvin))
=/ bob .^(blob cs/~[her syd yon %blob lob])
::
;; weft
?- -.bob
%direct q.q.bob
%delta q.r.bob
==
:: +read-kelvin-local: read /sys/kelvin from a local desk
::
++ read-kelvin-local
|= [our=ship =desk now=@da]
^- (unit weft)
=/ pax (en-beam [our desk da+now] /sys/kelvin)
?~ =<(fil .^(arch cy/pax))
~
[~ .^(weft cx/pax)]
:: +read-bill: read contents of /desk/bill manifest
::
++ read-bill
|= [our=ship =desk now=@da]
=/ pax (en-beam [our desk da+now] /desk/bill)
?~ =<(fil .^(arch cy/pax))
*bill
.^(bill cx/pax)
:: +is-fish: should dill link .dude?
::
++ is-fish |=([=dude =bill] .?((find ~[dude] (read-fish bill))))
:: +get-apps-diff: which agents should be started and stopped
::
++ get-apps-diff
|= [our=ship =desk now=@da =rein]
^- [liv=(list dude) ded=(list dude)]
=/ =bill (read-bill our desk now)
=/ wan (sy (get-apps-want bill rein))
=/ hav (sy (get-apps-live our desk now))
=/ liv ~(tap in (~(dif in wan) hav))
=/ ded ~(tap in (~(dif in hav) wan))
[liv ded]
::
++ get-apps-live
|= [our=ship =desk now=@da]
^- (list dude)
%+ murn (get-apps-have our desk now)
|=([=dude live=?] ?.(live ~ `dude))
:: +get-apps-have: find which apps Gall is running on a desk
::
++ get-apps-have
|= [our=ship =desk now=@da]
^- (list [=dude live=?])
%~ tap in
.^((set [=dude live=?]) ge+/(scot %p our)/[desk]/(scot %da now))
:: +get-apps-want: find which apps should be running on a desk
::
++ get-apps-want
|= [=bill =rein]
^- (list dude)
=/ duz (read-apes bill)
=. duz (skip duz ~(has in sub.rein))
=. duz (weld duz (skip ~(tap in add.rein) ~(has in (sy duz))))
duz
::
++ mergebase-hashes
|= [our=@p =desk now=@da =arak]
=/ her (scot %p ship.arak)
=/ ego (scot %p our)
=/ wen (scot %da now)
%+ turn .^((list tako) %cs ~[ego desk wen %base her desk.arak])
|=(=tako .^(@uv %cs ~[ego desk wen %hash (scot %uv tako)]))
::
++ enjs
=, enjs:format
|%
++ vats
|= v=(list ^vat)
^- json
%- pairs
%+ turn v
|= va=^vat
[desk.va (vat va)]
::
++ tim
|= t=@
^- json
(numb (fall (mole |.((unm:chrono:userlib t))) 0))
::
++ cass
|= c=^cass
%- pairs
:~ ud+(numb ud.c)
da+(tim da.c)
==
::
++ vat
|= v=^vat
%- pairs
:~ desk+s+desk.v
hash+s+(scot %uv hash.v)
cass+(cass cass.v)
arak+(arak arak.v)
==
::
++ weft
|= w=^weft
%- pairs
:~ name+s+lal.w
kelvin+(numb num.w)
==
::
++ woof
|= w=[=aeon =^weft]
%- pairs
:~ aeon+(numb aeon.w)
weft+(weft weft.w)
==
::
++ rein
|= r=^rein
%- pairs
:~ add+a+(turn ~(tap in add.r) (lead %s))
sub+a+(turn ~(tap in sub.r) (lead %s))
==
::
++ arak
|= a=^arak
%- pairs
:~ ship+s+(scot %p ship.a)
desk+s+desk.a
aeon+(numb aeon.a)
next+a+(turn next.a woof)
rein+(rein rein.a)
==
--
--

1
pkg/arvo/sur/hood.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/sur/hood.hoon

View File

@ -260,6 +260,15 @@
;< ~ bind:m (send-raw-card card)
(take-watch-ack wire)
::
++ watch-one
|= [=wire =dock =path]
=/ m (strand ,cage)
^- form:m
;< ~ bind:m (watch wire dock path)
;< =cage bind:m (take-fact wire)
;< ~ bind:m (take-kick wire)
(pure:m cage)
::
++ watch-our
|= [=wire =term =path]
=/ m (strand ,~)

229
pkg/base-dev/sur/hood.hoon Normal file
View File

@ -0,0 +1,229 @@
/- *bill
=, clay
=* dude dude:gall
|%
:: $diff: subscription update
::
+$ diff
$% [%block =desk =arak =weft blockers=(set desk)]
[%reset =desk =arak]
[%merge =desk =arak]
[%merge-sunk =desk =arak =tang]
[%merge-fail =desk =arak =tang]
[%suspend =desk =arak]
[%revive =desk =arak]
==
:: $arak: foreign vat tracker
::
:: .rail: upstream tracking state, if any
:: .next: list of pending commits with future kelvins
:: .rein: configuration for agents
::
+$ arak
$: =rail
next=(list rung)
=rein
==
:: $rail: upstream tracking state
::
+$ rail
$: paused=?
=ship
=desk
=aeon
==
:: $rung: reference to upstream commit
::
+$ rung [=aeon =weft]
:: $rein: diff from desk manifest
::
:: .liv: suspended?
:: .add: agents not in manifest that should be running
:: .sub: agents in manifest that should not be running
::
+$ rein
$: liv=_&
add=(set dude)
sub=(set dude)
==
::
+$ vat [=desk hash=@uv =cass =arak]
:: +report-vats: report on all desk installations
::
++ report-vats
|= [our=@p now=@da]
^- tang
=+ .^ raz=(list vat)
%gx /(scot %p our)/hood/(scot %da now)/kiln/vats/noun
==
(turn raz |=(v=vat (report-vat our now v)))
:: +report-vat: report on a single desk installation
::
++ report-vat
|= [our=ship now=@da vat]
^- tank
=+ .^(=weft %cx /(scot %p our)/[desk]/(scot %da now)/sys/kelvin)
:+ %rose ["" "{<desk>}" "::"]
^- tang
=- ?: =(~ next.arak) -
%+ snoc -
leaf/"pending: {<(turn next.arak |=([@ lal=@tas num=@] [lal num]))>}"
^- tang
=/ meb (mergebase-hashes our desk now arak)
=/ sat ?:(liv.rein.arak "running" "suspended")
:~ leaf/"/sys/kelvin: {<[lal num]:weft>}"
leaf/"base hash: {?.(=(1 (lent meb)) <meb> <(head meb)>)}"
leaf/"%cz hash: {<hash>}"
leaf/"source ship: {<ship.rail.arak>}"
leaf/"source desk: {<desk.rail.arak>}"
leaf/"source aeon: {<aeon.rail.arak>}"
leaf/"status: {sat}"
leaf/"force on: {?:(=(~ add.rein.arak) "~" <add.rein.arak>)}"
leaf/"force off: {?:(=(~ sub.rein.arak) "~" <sub.rein.arak>)}"
==
:: +read-kelvin-foreign: read /sys/kelvin from a foreign desk
::
++ read-kelvin-foreign
|= [=ship =desk =aeon]
^- weft
=/ her (scot %p ship)
=/ syd (scot %tas desk)
=/ yon (scot %ud aeon)
::
=/ dom .^(dome cv/~[her syd yon])
=/ tak (scot %uv (~(got by hit.dom) let.dom))
=/ yak .^(yaki cs/~[her syd yon %yaki tak])
=/ lob (scot %uv (~(got by q.yak) /sys/kelvin))
=/ bob .^(blob cs/~[her syd yon %blob lob])
::
;; weft
?- -.bob
%direct q.q.bob
%delta q.r.bob
==
:: +read-kelvin-local: read /sys/kelvin from a local desk
::
++ read-kelvin-local
|= [our=ship =desk now=@da]
^- (unit weft)
=/ pax (en-beam [our desk da+now] /sys/kelvin)
?~ =<(fil .^(arch cy/pax))
~
[~ .^(weft cx/pax)]
:: +read-bill: read contents of /desk/bill manifest
::
++ read-bill
|= [our=ship =desk now=@da]
=/ pax (en-beam [our desk da+now] /desk/bill)
?~ =<(fil .^(arch cy/pax))
*bill
.^(bill cx/pax)
:: +is-fish: should dill link .dude?
::
++ is-fish |=([=dude =bill] .?((find ~[dude] (read-fish bill))))
:: +get-apps-diff: which agents should be started and stopped
::
++ get-apps-diff
|= [our=ship =desk now=@da =rein]
^- [liv=(list dude) ded=(list dude)]
=/ =bill (read-bill our desk now)
=/ wan (sy (get-apps-want bill rein))
=/ hav (sy (get-apps-live our desk now))
=/ liv ~(tap in (~(dif in wan) hav))
=/ ded ~(tap in (~(dif in hav) wan))
[liv ded]
::
++ get-apps-live
|= [our=ship =desk now=@da]
^- (list dude)
%+ murn (get-apps-have our desk now)
|=([=dude live=?] ?.(live ~ `dude))
:: +get-apps-have: find which apps Gall is running on a desk
::
++ get-apps-have
|= [our=ship =desk now=@da]
^- (list [=dude live=?])
%~ tap in
.^((set [=dude live=?]) ge+/(scot %p our)/[desk]/(scot %da now))
:: +get-apps-want: find which apps should be running on a desk
::
++ get-apps-want
|= [=bill =rein]
^- (list dude)
=/ duz (read-apes bill)
=. duz (skip duz ~(has in sub.rein))
=. duz (weld duz (skip ~(tap in add.rein) ~(has in (sy duz))))
duz
::
++ mergebase-hashes
|= [our=@p =desk now=@da =arak]
=/ her (scot %p ship.rail.arak)
=/ ego (scot %p our)
=/ wen (scot %da now)
%+ turn .^((list tako) %cs ~[ego desk wen %base her desk.rail.arak])
|=(=tako .^(@uv %cs ~[ego desk wen %hash (scot %uv tako)]))
::
++ enjs
=, enjs:format
|%
++ vats
|= v=(list ^vat)
^- json
%- pairs
%+ turn v
|= va=^vat
[desk.va (vat va)]
::
++ tim
|= t=@
^- json
(numb (fall (mole |.((unm:chrono:userlib t))) 0))
::
++ cass
|= c=^cass
%- pairs
:~ ud+(numb ud.c)
da+(tim da.c)
==
::
++ vat
|= v=^vat
%- pairs
:~ desk+s+desk.v
hash+s+(scot %uv hash.v)
cass+(cass cass.v)
arak+(arak arak.v)
==
::
++ weft
|= w=^weft
%- pairs
:~ name+s+lal.w
kelvin+(numb num.w)
==
::
++ rung
|= r=^rung
%- pairs
:~ aeon+(numb aeon.r)
weft+(weft weft.r)
==
::
++ rein
|= r=^rein
%- pairs
:~ add+a+(turn ~(tap in add.r) (lead %s))
sub+a+(turn ~(tap in sub.r) (lead %s))
==
::
++ arak
|= a=^arak
%- pairs
:~ ship+s+(scot %p ship.rail.a)
desk+s+desk.rail.a
aeon+(numb aeon.rail.a)
next+a+(turn next.a rung)
rein+(rein rein.a)
==
--
--

View File

@ -7,7 +7,8 @@
$: title=(unit @t)
info=(unit @t)
color=(unit @ux)
glob=(unit url)
glob-http=(unit url)
glob-ames=(unit =ship)
base=(unit term)
site=(unit path)
image=(unit url)
@ -28,8 +29,11 @@
=/ href=(unit href)
?^ site.draft `[%site u.site.draft]
?~ base.draft ~
?~ glob.draft ~
`[%glob [u.base.draft [%http u.glob]:draft]]
?^ glob-http.draft
`[%glob [u.base %http u.glob-http]:draft]
?~ glob-ames.draft
~
`[%glob [u.base %ames u.glob-ames]:draft]
?~ href ~
=, draft
:- ~
@ -56,7 +60,8 @@
%title draft(title `title.clause)
%info draft(info `info.clause)
%color draft(color `color.clause)
%glob draft(glob `url.clause)
%glob-http draft(glob-http `url.clause)
%glob-ames draft(glob-ames `ship:clause)
%base draft(base `base.clause)
%site draft(site `path.clause)
%image draft(image `url.clause)
@ -79,10 +84,12 @@
==
?~ image.d ~ ~[image+u.image.d]
?: ?=(%site -.href.d) ~[site+path.href.d]
=/ loc=glob-location glob-location.href.d
:~ base+base.href.d
glob+url.glob-location.href.d
==
==
?- -.loc
%http [%glob-http url.loc]
%ames [%glob-ames ship.loc]
== == ==
::
++ spit-clause
|= =clause
@ -91,6 +98,7 @@
?+ -.clause "'{(trip +.clause)}'"
%color (scow %ux color.clause)
%site (spud path.clause)
%glob-ames (scow %p ship.clause)
::
%version
=, version.clause
@ -154,9 +162,22 @@
++ href
|= h=^href
%+ frond -.h
?- -.h
%glob (pairs base+s+base.h ~)
%site s+(spat path.h)
?- -.h
%site s+(spat path.h)
%glob
%- pairs
:~ base+s+base.h
glob-location+(glob-location glob-location.h)
==
==
::
++ glob-location
|= loc=^glob-location
^- json
%+ frond -.loc
?- -.loc
%http (pairs url+s+url.loc ~)
%ames (ship ship.loc)
==
::
++ charge

View File

@ -10,6 +10,7 @@
::
+$ glob-location
$% [%http =url]
[%ames =ship]
==
:: $href: Where a tile links to
::
@ -45,7 +46,8 @@
$% [%title title=@t]
[%info info=@t]
[%color color=@ux]
[%glob url=cord]
[%glob-http url=cord]
[%glob-ames =ship]
[%image =url]
[%site =path]
[%base base=term]

View File

@ -1,5 +1,5 @@
/- *docket, hood, treaty
/+ *server, agentio, default-agent, dbug, verb
/+ *server, agentio, default-agent, multipart, dbug, verb
|%
+$ card card:agent:gall
+$ state-0
@ -51,11 +51,11 @@
^- (quip card _this)
=+ !<(old=state-0 vase)
=* cha ~(. ch q.byk.bowl)
|^
|^
=. -.state old
=. +.state inflate-cache
`this
::
::
++ inflate-cache
^- cache
%- ~(gas by *(map term desk))
@ -69,7 +69,7 @@
++ on-poke
|= [=mark =vase]
^- (quip card _this)
|^
|^
=^ cards state
?+ mark (on-poke:def:cc mark vase)
%docket-install (install !<([ship desk] vase))
@ -81,9 +81,7 @@
::
%handle-http-request
=+ !<([id=@ta req=inbound-request:eyre] vase)
:_ state
%+ give-simple-payload:app id
(handle-http-request:cc req)
(handle-http-request:cc id req)
==
[cards this]
::
@ -91,7 +89,9 @@
|= [=ship =desk]
^- (quip card _state)
=+ .^(=treaty:treaty %gx (scry:io %treaty /treaty/(scot %p ship)/[desk]/noun))
?< ~|(%bad-install-desk (~(has by charges) desk))
?: (~(has by charges) desk)
~| bad-install-desk/desk
!!
=. charges
(~(put by charges) desk docket.treaty %install ~)
=* cha ~(. ch desk)
@ -101,8 +101,7 @@
++ uninstall
|= =desk
^- (quip card _state)
~| %no-charge-install
=/ =charge (~(got by charges) desk)
=/ =charge ~|(no-charge-installed+desk (~(got by charges) desk))
=. charges (~(del by charges) desk)
=? by-base ?=(%glob -.href.docket.charge)
(~(del by by-base) base.href.docket)
@ -116,13 +115,22 @@
^- (quip card _this)
=^ cards state
?+ path (on-watch:def path)
[%http-response *]
[%http-response *]
?> (team:title [our src]:bowl)
`state
::
[%charges ~]
?> (team:title [our src]:bowl)
`state
::
[%glob @ ~]
=/ desk ~|(path/path (~(got by by-base) i.t.path))
=/ =charge ~|(desk/desk (~(got by charges) desk))
?> ?=(%glob -.chad.charge)
:_ state
:~ [%give %fact ~[path] %glob !>(`glob`glob.chad.charge)]
[%give %kick ~[path] ~]
==
==
[cards this]
::
@ -217,12 +225,12 @@
::
[%install ~]
?> ?=(%poke-ack -.sign)
?~ p.sign
?~ p.sign
`state
=. charges (new-chad:cha hung+'Failed install')
((slog leaf+"Failed installing %{(trip desk)}" u.p.sign) `state)
::
[%uninstall ~]
[%uninstall ~]
?> ?=(%poke-ack -.sign)
?~ p.sign `state
((slog leaf+"Failed to uninstall %{(trip desk)}" u.p.sign) `state)
@ -262,14 +270,14 @@
|= [=wire sign=sign-arvo]
=^ cards state
?+ wire (on-arvo:def wire sign)
[%init ~]
[%init ~]
=* cha ~(. ch q.byk.bowl)
=. charges (~(put by charges) q.byk.bowl [docket:cha %install ~])
[fetch-glob:cha state]
::
[%eyre ~]
?> ?=([%eyre %bound *] sign)
?: accepted.sign `state
?: accepted.sign `state
~& [dap.bowl %failed-to-bind path.binding.sign]
`state
==
@ -283,50 +291,181 @@
++ pass pass:io
++ def ~(. (default-agent state %|) bowl)
::
++ inline-js-response
|= js=cord
^- simple-payload:http
%. (as-octs:mimes:html js)
%* . js-response:gen
cache %.n
==
::
++ handle-http-request
|= =inbound-request:eyre
^- simple-payload:http
%+ require-authorization-simple:app inbound-request
=* req request.inbound-request
=* headers header-list.req
=/ req-line (parse-request-line url.req)
?. =(method.req %'GET') not-found:gen
?: &(=(ext.req-line `%js) ?=([%session ~] site.req-line))
%- inline-js-response
(rap 3 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";' ~)
?. ?=([%apps @ *] site.req-line)
(redirect:gen '/apps/grid/')
=/ des=(unit desk)
(~(get by by-base) i.t.site.req-line)
?~ des not-found:gen
=/ cha=(unit charge)
(~(get by charges) u.des)
?~ cha not-found:gen
?. ?=(%glob -.chad.u.cha) not-found:gen
=* glob glob.chad.u.cha
=/ suffix=^path
(weld (slag 2 `^path`site.req-line) (drop ext.req-line))
?: =(suffix /desk/js)
%- inline-js-response
(rap 3 'window.desk = "' u.des '";' ~)
=/ data=mime
(~(gut by glob) suffix (~(got by glob) /index/html))
=/ mime-type=@t (rsh 3 (crip <p.data>))
=/ headers
:~ content-type+mime-type
max-1-wk:gen
|= [eyre-id=@ta inbound-request:eyre]
^- (quip card _state)
::
=; [payload=simple-payload:http caz=(list card) =_state]
:_ state
%+ weld caz
(give-simple-payload:app eyre-id payload)
::
::NOTE we don't use +require-authorization-simple here because we want
:: to short-circuit all the below logic for the unauthenticated case.
?. authenticated
:_ [~ state]
=- [[307 ['location' -]~] ~]
(cat 3 '/~/login?redirect=' url.request)
::
=* headers header-list.request
=/ req-line (parse-request-line url.request)
::
|^ ?+ method.request [[405^~ ~] ~ state]
%'GET' [handle-get-request ~ state]
%'POST' handle-upload
==
::
++ handle-get-request
^- simple-payload:http
?+ [site ext]:req-line (redirect:gen '/apps/grid/')
[[%session ~] [~ %js]]
%- inline-js-response
(rap 3 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";' ~)
::
[[%docket %upload ~] ?(~ [~ %html])]
[[200 ~] `(upload-page ~)]
::
[[%apps @ *] *]
%+ payload-from-glob
(snag 1 site.req-line)
req-line(site (slag 2 site.req-line))
==
::
++ upload-page
|= msg=(list @t)
^- octs
%- as-octt:mimes:html
%- en-xml:html
^- manx
;html
;head
;title:"%docket globulator"
;meta(charset "utf-8");
;style:'* { font-family: monospace; margin-top: 1em; }'
==
;body
;h2:"%docket globulator"
;+ ?. =(~ msg)
:- [%p ~]
(join `manx`;br; (turn msg |=(m=@t `manx`:/"{(trip m)}")))
;p:"ur on ur own kid, glhf" ::TODO instructions
;form(method "post", enctype "multipart/form-data")
::TODO could be dropdown
;input(type "text", name "desk", placeholder "desk");
;br;
;input
=type "file"
=name "glob"
=directory ""
=webkitdirectory ""
=mozdirectory "";
;br;
;button(type "submit"):"Glob!"
==
==
==
::
++ handle-upload
^- [simple-payload:http (list card) _state]
?. ?=([[%docket %upload ~] ?(~ [~ %html])] [site ext]:req-line)
[[404^~ ~] [~ state]]
::
=; [desk=@ta =glob err=(list @t)]
=* cha ~(. ch desk)
=/ =charge (~(got by charges) desk)
::
=? err =(~ glob)
['no files for glob' err]
=? err ?=(%glob -.href.docket.charge)
['desk does not use glob' err]
::
?. =(~ err)
:_ [~ state]
[[400 ~] `(upload-page err)]
:- [[200 ~] `(upload-page 'successfully globbed' ~)]
::
=. charges (new-chad:cha glob+glob)
=. by-base
=- (~(put by by-base) - desk)
?> ?=(%glob -.href.docket.charge)
base.href.docket.charge
[~[add-fact:cha] state]
::
?~ parts=(de-request:multipart [header-list body]:request)
~& headers=header-list.request
[*@ta *glob 'failed to parse submitted data' ~]
::
%+ roll u.parts
|= [[name=@t part:multipart] desk=@ta =glob err=(list @t)]
^+ [desk glob err]
?: =('desk' name)
:: must be a desk with existing charge
::
?. ((sane %ta) body)
[desk glob (cat 3 'invalid desk: ' body) err]
?. (~(has by charges) body)
[desk glob (cat 3 'unknown desk: ' body) err]
[body glob err]
:- desk
:: all submitted files must be complete
::
?. =('glob' name) [glob (cat 3 'weird part: ' name) err]
?~ file [glob 'file without filename' err]
?~ type [glob (cat 3 'file without type: ' u.file) err]
?^ code [glob (cat 3 'strange encoding: ' u.code) err]
=/ filp (rush u.file fip)
?~ filp [glob (cat 3 'strange filename: ' u.file) err]
:: ignore metadata files and other "junk"
::TODO consider expanding coverage
::
?: =('.DS_Store' (rear `path`u.filp))
[glob err]
:: make sure to exclude the top-level dir from the path
::
:_ err
%+ ~(put by glob) (slag 1 `path`u.filp)
[u.type (as-octs:mimes:html body)]
::
++ fip
=, de-purl:html
%+ cook
|=(pork (weld q (drop p)))
(cook deft (more fas smeg))
::
++ inline-js-response
|= js=cord
^- simple-payload:http
%. (as-octs:mimes:html js)
%* . js-response:gen
cache %.n
==
::
++ payload-from-glob
|= [from=@ta what=request-line]
^- simple-payload:http
=/ des=(unit desk)
(~(get by by-base) from)
?~ des not-found:gen
=/ cha=(unit charge)
(~(get by charges) u.des)
?~ cha not-found:gen
?. ?=(%glob -.chad.u.cha) not-found:gen
=* glob glob.chad.u.cha
=/ suffix=^path
(weld site.what (drop ext.what))
?: =(suffix /desk/js)
%- inline-js-response
(rap 3 'window.desk = "' u.des '";' ~)
=/ data=mime
(~(gut by glob) suffix (~(got by glob) /index/html))
=/ mime-type=@t (rsh 3 (crip <p.data>))
=; headers
[[200 headers] `q.data]
:~ content-type+mime-type
max-1-wk:gen
'service-worker-allowed'^'/'
==
[[200 headers] `q.data]
--
::
++ get-light-charge
|= =charge
@ -347,12 +486,14 @@
(poke-our:(pass %uninstall) %hood kiln-uninstall+!>(desk))
++ new-chad |=(c=chad (~(jab by charges) desk |=(charge +<(chad c))))
++ fetch-glob
=/ =charge (~(got by charges) desk)
=/ =charge
~| desk/desk
(~(got by charges) desk)
=/ tid=@t (cat 3 'docket-' (scot %uv (sham (mix eny.bowl desk))))
?> ?=(%glob -.href.docket.charge)
?> ?=(%http -.glob-location.href.docket.charge)
=* url url.glob-location.href.docket.charge
=/ =cage spider-start+!>([~ `tid byk.bowl(r da+now.bowl) %glob !>(`url)])
=* loc glob-location.href.docket.charge
~> %slog.0^leaf/"docket: fetching glob for {<desk>} desk"
=/ =cage spider-start+!>([~ `tid byk.bowl(r da+now.bowl) %glob !>(`[loc desk])])
:~ (watch-our:(pass %glob) %spider /thread-result/[tid])
(poke-our:(pass %glob) %spider cage)
==

View File

@ -1,7 +1,8 @@
:~ title+'Grid'
info+'An app launcher for urbit.'
:~ title+'Garden'
info+'An app launcher for Urbit.'
color+0xee.5432
glob+'https://bootstrap.urbit.org/glob-0v6.t43bu.cpl0b.bsisc.sqr4d.dckpn.glob'
::glob-http+'https://bootstrap.urbit.org/glob-0v6.t43bu.cpl0b.bsisc.sqr4d.dckpn.glob'
glob-ames+~zod
base+'grid'
version+[0 0 1]
website+'https://tlon.io'

1
pkg/garden/lib/agentio.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/agentio.hoon

1
pkg/garden/lib/azimuth.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/azimuth.hoon

View File

@ -0,0 +1 @@
../../base-dev/lib/azimuthio.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/bip/b158.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/bip/b173.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/bip/b174.hoon

1
pkg/garden/lib/bip32.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/bip32.hoon

1
pkg/garden/lib/bip39.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/bip39.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/bip39/english.hoon

1
pkg/garden/lib/dbug.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/dbug.hoon

View File

@ -0,0 +1 @@
../../base-dev/lib/default-agent.hoon

1
pkg/garden/lib/docket.hoon Symbolic link
View File

@ -0,0 +1 @@
../../garden-dev/lib/docket.hoon

1
pkg/garden/lib/ethio.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/ethio.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/language-server/build.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/language-server/complete.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/language-server/easy-print.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/language-server/json.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/language-server/parser.hoon

View File

@ -0,0 +1 @@
../../../base-dev/lib/language-server/rune-snippet.hoon

View File

@ -0,0 +1,49 @@
:: multipart: multipart/form-data request decoding
::
|%
+$ part
$: file=(unit @t) :: filename
type=(unit mite) :: content-type
code=(unit @t) :: content-transfer-encoding
body=@t :: content
==
::
++ de-request
|= [=header-list:http body=(unit octs)]
^- (unit (list [@t part]))
?~ body ~
?~ cot=(get-header:http 'content-type' header-list) ~
?. =('multipart/form-data; boundary=' (end 3^30 u.cot)) ~
%+ rush q.u.body
(dep (rsh 3^30 u.cot))
::
++ dep
|= del=@t
|^
%+ knee *(list [@t part]) |. ~+
;~ pose (cold ~ (full tip)) :: end, or
;~ pfix dim nip :: section start
;~ plug ;~ plug :: containing:
(ifix [cof doq] nom) :: name
(punt (ifix [cup doq] nod)) :: filename
(punt ;~(pfix nip cut nab)) :: content-type
(punt ;~(pfix nip cue nom)) :: con-tra-encoding
(ifix [sip nip] nag) :: content
== ^$ == == ==
::
++ cof (jest 'Content-Disposition: form-data; name="')
++ cue (jest 'Content-Transfer-Encoding: ')
++ cup (jest '; filename="')
++ cut (jest 'Content-Type: ')
++ dim (jest (cat 3 '--' del))
++ nip (jest '\0d\0a')
++ nab (more fas urs:ab)
++ nag (dine ;~(less ;~(plug nip dim) next))
++ nod (dine ;~(less doq next))
++ nom (dine alp)
++ sip ;~(plug nip nip)
++ tip ;~(plug dim hep hep nip)
::
++ dine |*(r=rule (cook (cury rep 3) (star r)))
--
--

1
pkg/garden/lib/server.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/server.hoon

1
pkg/garden/lib/shoe.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/shoe.hoon

View File

@ -0,0 +1 @@
../../base-dev/lib/skeleton.hoon

1
pkg/garden/lib/sole.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/sole.hoon

1
pkg/garden/lib/strand.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/strand.hoon

View File

@ -0,0 +1 @@
../../base-dev/lib/strandio.hoon

1
pkg/garden/lib/treaty.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/treaty.hoon

1
pkg/garden/lib/verb.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/lib/verb.hoon

1
pkg/garden/mar/belt.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/belt.hoon

1
pkg/garden/mar/bill.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/bill.hoon

1
pkg/garden/mar/blit.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/blit.hoon

View File

@ -1,25 +0,0 @@
/+ dock=docket
|_ =docket:dock
++ grow
|%
++ mime
^- ^mime
[/text/x-docket (as-octt:mimes:html (spit-docket:mime:dock docket))]
++ noun docket
++ json (docket:enjs:dock docket)
--
++ grab
|%
::
++ mime
|= [=mite len=@ud tex=@]
^- docket:dock
%- need
%- from-clauses:mime:dock
!<((list clause:dock) (slap !>(~) (ream tex)))
::
++ noun docket:dock
--
++ grad %noun
--

1
pkg/garden/mar/docket.hoon Symbolic link
View File

@ -0,0 +1 @@
../../garden-dev/mar/docket.hoon

1
pkg/garden/mar/hoon.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/hoon.hoon

1
pkg/garden/mar/htm.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/htm.hoon

1
pkg/garden/mar/html.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/html.hoon

1
pkg/garden/mar/httr.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/httr.hoon

1
pkg/garden/mar/hymn.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/hymn.hoon

1
pkg/garden/mar/js.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/js.hoon

1
pkg/garden/mar/json.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/json.hoon

View File

@ -0,0 +1 @@
../../../../base-dev/mar/json/rpc/response.hoon

1
pkg/garden/mar/kelvin.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/kelvin.hoon

View File

@ -0,0 +1 @@
../../../../base-dev/mar/language-server/rpc/notification.hoon

View File

@ -0,0 +1 @@
../../../../base-dev/mar/language-server/rpc/request.hoon

View File

@ -0,0 +1 @@
../../../../base-dev/mar/language-server/rpc/response.hoon

1
pkg/garden/mar/mime.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/mime.hoon

1
pkg/garden/mar/noun.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/noun.hoon

1
pkg/garden/mar/path.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/path.hoon

1
pkg/garden/mar/png.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/png.hoon

1
pkg/garden/mar/purl.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/purl.hoon

View File

@ -0,0 +1 @@
../../../base-dev/mar/sole/action.hoon

View File

@ -0,0 +1 @@
../../../base-dev/mar/sole/effect.hoon

1
pkg/garden/mar/svg.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/svg.hoon

1
pkg/garden/mar/tang.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/tang.hoon

1
pkg/garden/mar/tape.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/tape.hoon

View File

@ -0,0 +1 @@
../../base-dev/mar/txt-diff.hoon

1
pkg/garden/mar/txt.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/txt.hoon

1
pkg/garden/mar/udon.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/udon.hoon

1
pkg/garden/mar/umd.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/umd.hoon

1
pkg/garden/mar/urb.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/urb.hoon

1
pkg/garden/mar/urbit.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/urbit.hoon

1
pkg/garden/mar/woff2.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/woff2.hoon

1
pkg/garden/mar/xml.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/mar/xml.hoon

1
pkg/garden/sur/bill.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/sur/bill.hoon

1
pkg/garden/sur/docket.hoon Symbolic link
View File

@ -0,0 +1 @@
../../garden-dev/sur/docket.hoon

View File

@ -1,206 +0,0 @@
/- *bill
=, clay
=* dude dude:gall
|%
:: $diff: subscription update
::
+$ diff
$% [%block =desk =arak =weft blockers=(set desk)]
[%reset =desk =arak]
[%merge =desk =arak]
[%merge-sunk =desk =arak =tang]
[%merge-fail =desk =arak =tang]
[%suspend =desk =arak]
[%revive =desk =arak]
==
:: $arak: foreign vat tracker
::
:: .next is a list of pending commits with future kelvins
::
+$ arak
$: =ship
=desk
=aeon
next=(list [=aeon =weft])
=rein
==
:: $rein: diff from desk manifest
::
:: .liv: suspended?
:: .add: agents not in manifest that should be running
:: .sub: agents in manifest that should not be running
::
+$ rein
$: liv=_&
add=(set dude)
sub=(set dude)
==
::
+$ vat [=desk hash=@uv =cass =arak]
:: +report-vats: report on all desk installations
::
++ report-vats
|= [our=@p now=@da]
^- tang
=+ .^ raz=(list vat)
%gx /(scot %p our)/hood/(scot %da now)/kiln/vats/noun
==
(turn raz |=(v=vat (report-vat our now v)))
:: +report-vat: report on a single desk installation
::
++ report-vat
|= [our=ship now=@da vat]
^- tank
=+ .^(=weft %cx /(scot %p our)/[desk]/(scot %da now)/sys/kelvin)
:+ %rose ["" "{<desk>}" "::"]
^- tang
=- ?: =(~ next.arak) -
%+ snoc -
leaf/"pending: {<(turn next.arak |=([@ lal=@tas num=@] [lal num]))>}"
^- tang
=/ meb (mergebase-hashes our desk now arak)
=/ sat ?:(liv.rein.arak "running" "suspended")
:~ leaf/"/sys/kelvin: {<[lal num]:weft>}"
leaf/"base hash: {?.(=(1 (lent meb)) <meb> <(head meb)>)}"
leaf/"%cz hash: {<hash>}"
leaf/"remote aeon: {<aeon.arak>}"
leaf/"status: {sat}"
leaf/"force on: {?:(=(~ add.rein.arak) "~" <add.rein.arak>)}"
leaf/"force off: {?:(=(~ sub.rein.arak) "~" <sub.rein.arak>)}"
==
::
++ read-kelvin-foreign
|= [=ship =desk =aeon]
^- weft
=/ her (scot %p ship)
=/ syd (scot %tas desk)
=/ yon (scot %ud aeon)
::
=/ dom .^(dome cv/~[her syd yon])
=/ tak (scot %uv (~(got by hit.dom) let.dom))
=/ yak .^(yaki cs/~[her syd yon %yaki tak])
=/ lob (scot %uv (~(got by q.yak) /sys/kelvin))
=/ bob .^(blob cs/~[her syd yon %blob lob])
::
;; weft
?- -.bob
%direct q.q.bob
%delta q.r.bob
==
:: +read-bill: read contents of /desk/bill manifest
::
++ read-bill
|= [our=ship =desk now=@da]
=/ pax (en-beam [our desk da+now] /desk/bill)
?~ =<(fil .^(arch cy/pax))
*bill
.^(bill cx/pax)
:: +is-fish: should dill link .dude?
::
++ is-fish |=([=dude =bill] .?((find ~[dude] (read-fish bill))))
:: +get-apps-diff: which agents should be started and stopped
::
++ get-apps-diff
|= [our=ship =desk now=@da =rein]
^- [liv=(list dude) ded=(list dude)]
=/ =bill (read-bill our desk now)
=/ wan (sy (get-apps-want bill rein))
=/ hav (sy (get-apps-live our desk now))
=/ liv ~(tap in (~(dif in wan) hav))
=/ ded ~(tap in (~(dif in hav) wan))
[liv ded]
::
++ get-apps-live
|= [our=ship =desk now=@da]
^- (list dude)
%+ murn (get-apps-have our desk now)
|=([=dude live=?] ?.(live ~ `dude))
:: +get-apps-have: find which apps Gall is running on a desk
::
++ get-apps-have
|= [our=ship =desk now=@da]
^- (list [=dude live=?])
%~ tap in
.^((set [=dude live=?]) ge+/(scot %p our)/[desk]/(scot %da now))
:: +get-apps-want: find which apps should be running on a desk
::
++ get-apps-want
|= [=bill =rein]
^- (list dude)
=/ duz (read-apes bill)
=. duz (skip duz ~(has in sub.rein))
=. duz (weld duz (skip ~(tap in add.rein) ~(has in (sy duz))))
duz
::
++ mergebase-hashes
|= [our=@p =desk now=@da =arak]
=/ her (scot %p ship.arak)
=/ ego (scot %p our)
=/ wen (scot %da now)
%+ turn .^((list tako) %cs ~[ego desk wen %base her desk.arak])
|=(=tako .^(@uv %cs ~[ego desk wen %hash (scot %uv tako)]))
::
++ enjs
=, enjs:format
|%
++ vats
|= v=(list ^vat)
^- json
%- pairs
%+ turn v
|= va=^vat
[desk.va (vat va)]
::
++ tim
|= t=@
^- json
(numb (fall (mole |.((unm:chrono:userlib t))) 0))
::
++ cass
|= c=^cass
%- pairs
:~ ud+(numb ud.c)
da+(tim da.c)
==
::
++ vat
|= v=^vat
%- pairs
:~ desk+s+desk.v
hash+s+(scot %uv hash.v)
cass+(cass cass.v)
arak+(arak arak.v)
==
::
++ weft
|= w=^weft
%- pairs
:~ name+s+lal.w
kelvin+(numb num.w)
==
::
++ woof
|= w=[=aeon =^weft]
%- pairs
:~ aeon+(numb aeon.w)
weft+(weft weft.w)
==
::
++ rein
|= r=^rein
%- pairs
:~ add+a+(turn ~(tap in add.r) (lead %s))
sub+a+(turn ~(tap in sub.r) (lead %s))
==
::
++ arak
|= a=^arak
%- pairs
:~ ship+s+(scot %p ship.a)
desk+s+desk.a
aeon+(numb aeon.a)
next+a+(turn next.a woof)
rein+(rein rein.a)
==
--
--

1
pkg/garden/sur/hood.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/sur/hood.hoon

1
pkg/garden/sur/sole.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/sur/sole.hoon

1
pkg/garden/sur/spider.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/sur/spider.hoon

1
pkg/garden/sur/verb.hoon Symbolic link
View File

@ -0,0 +1 @@
../../base-dev/sur/verb.hoon

View File

@ -5,13 +5,33 @@
|= arg=vase
=/ m (strand ,vase)
^- form:m
=+ !<([~ url=cord] arg)
;< =glob:docket bind:m
%+ (retry:strandio ,glob:docket) `5
=/ n (strand ,(unit glob:docket))
;< =cord bind:n (fetch-cord:strandio (trip url))
%- pure:n
%- mole
|.
;;(=glob:docket (cue cord))
(pure:m !>(glob))
=+ !<([~ loc=glob-location:docket base=term] arg)
|^
?- -.loc
%http (fetch-http url.loc)
%ames (fetch-ames ship.loc base)
==
::
++ fetch-http
|= url=cord
^- form:m
;< =glob:docket bind:m
%+ (retry:strandio ,glob:docket) `5
=/ n (strand ,(unit glob:docket))
;< =cord bind:n (fetch-cord:strandio (trip url))
%- pure:n
%- mole
|.
;;(=glob:docket (cue cord))
(pure:m !>(glob))
::
:: download from ship's docket state
++ fetch-ames
|= [=ship base=term]
^- form:m
;< =bowl:spider bind:m get-bowl:strandio
;< =cage bind:m
(watch-one:strandio /glob/(scot %da now.bowl) [ship %docket] /glob/[base])
?> ?=(%glob p.cage)
(pure:m q.cage)
--

38020
pkg/grid/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@
"@radix-ui/react-polymorphic": "^0.0.13",
"@radix-ui/react-portal": "^0.0.15",
"@radix-ui/react-toggle": "^0.0.10",
"@tlon/sigil-js": "^1.4.4",
"@urbit/api": "^1.4.0",
"@urbit/http-api": "^1.3.1",
"classnames": "^2.3.1",
@ -26,24 +27,24 @@
"color2k": "^1.2.4",
"fuzzy": "^0.1.3",
"immer": "^9.0.5",
"lodash-es": "^4.17.21",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"mousetrap": "^1.6.5",
"postcss-import": "^14.0.2",
"query-string": "^7.0.1",
"react": "^17.0.0",
"react-dom": "^17.0.0",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-router-dom": "^5.2.0",
"slugify": "^1.6.0",
"zustand": "^3.5.7"
},
"devDependencies": {
"@tailwindcss/aspect-ratio": "^0.2.1",
"@types/lodash-es": "^4.17.4",
"@types/lodash": "^4.14.172",
"@types/mousetrap": "^1.6.8",
"@types/node": "^16.7.9",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react": "^16.0.0",
"@types/react-dom": "^16.0.0",
"@types/react-router-dom": "^5.1.8",
"@typescript-eslint/eslint-plugin": "^4.26.1",
"@typescript-eslint/parser": "^4.26.1",

View File

@ -4,6 +4,8 @@ import { BrowserRouter, Switch, Route, useHistory } from 'react-router-dom';
import { Grid } from './pages/Grid';
import useDocketState from './state/docket';
import { usePreferencesStore } from './nav/preferences/usePreferencesStore';
import useContactState from './state/contact';
import api from './state/api';
const AppRoutes = () => {
const { push } = useHistory();
@ -38,6 +40,7 @@ const AppRoutes = () => {
const { fetchAllies, fetchCharges } = useDocketState.getState();
fetchCharges();
fetchAllies();
useContactState.getState().initialize(api);
Mousetrap.bind(['command+/', 'ctrl+/'], () => {
push('/leap/search');

View File

@ -1,6 +1,6 @@
import React from 'react';
import cn from 'classnames';
import { capitalize } from 'lodash-es';
import { capitalize } from 'lodash';
interface AttributeProps {
attr: string;

View File

@ -0,0 +1,85 @@
import classNames from 'classnames';
import React, { useMemo } from 'react';
import { sigil, reactRenderer } from '@tlon/sigil-js';
import { deSig, Contact } from '@urbit/api';
export type AvatarSizes = 'xs' | 'small' | 'default';
interface AvatarProps extends Contact {
shipName: string;
size: AvatarSizes;
className?: string;
}
interface AvatarMeta {
classes: string;
size: number;
}
const sizeMap: Record<AvatarSizes, AvatarMeta> = {
xs: { classes: 'w-6 h-6 rounded', size: 12 },
small: { classes: 'w-8 h-8 rounded-lg', size: 16 },
default: { classes: 'w-12 h-12 rounded-lg', size: 24 }
};
const foregroundFromBackground = (background: string): 'black' | 'white' => {
const rgb = {
r: parseInt(background.slice(1, 3), 16),
g: parseInt(background.slice(3, 5), 16),
b: parseInt(background.slice(5, 7), 16)
};
const brightness = (299 * rgb.r + 587 * rgb.g + 114 * rgb.b) / 1000;
const whiteBrightness = 255;
return whiteBrightness - brightness < 50 ? 'black' : 'white';
};
const emptyContact: Contact = {
nickname: '',
bio: '',
status: '',
color: '#000000',
avatar: null,
cover: null,
groups: [],
'last-updated': 0
};
export const Avatar = ({ size, className, ...ship }: AvatarProps) => {
const { shipName, color, avatar } = { ...emptyContact, ...ship };
const { classes, size: sigilSize } = sizeMap[size];
const foregroundColor = foregroundFromBackground(color);
const sigilElement = useMemo(() => {
if (shipName.match(/[_^]/)) {
return null;
}
return sigil({
patp: deSig(shipName) || 'zod',
renderer: reactRenderer,
size: sigilSize,
icon: true,
colors: [color, foregroundColor]
});
}, [shipName, color, foregroundColor]);
if (avatar) {
return <img className={classNames('', classes)} src={avatar} alt="" />;
}
return (
<div
className={classNames(
'flex-none relative bg-black rounded-lg',
classes,
size === 'xs' && 'p-1.5',
size === 'small' && 'p-2',
size === 'default' && 'p-3',
className
)}
style={{ backgroundColor: color }}
>
{sigilElement}
</div>
);
};

View File

@ -1,12 +1,13 @@
import classNames from 'classnames';
import React from 'react';
import { Link, LinkProps } from 'react-router-dom';
import { Provider } from '@urbit/api';
import { Contact, Provider } from '@urbit/api';
import { ShipName } from './ShipName';
import { Avatar, AvatarSizes } from './Avatar';
export type ProviderLinkProps = Omit<LinkProps, 'to'> & {
provider: Provider;
small?: boolean;
provider: { shipName: string } & Contact;
size?: AvatarSizes;
selected?: boolean;
to?: (p: Provider) => LinkProps['to'];
};
@ -15,10 +16,11 @@ export const ProviderLink = ({
provider,
to,
selected = false,
small = false,
size = 'default',
className,
...props
}: ProviderLinkProps) => {
const small = size === 'small' || size === 'xs';
return (
<Link
to={(to && to(provider)) || `/leap/search/${provider.shipName}/apps`}
@ -30,17 +32,10 @@ export const ProviderLink = ({
)}
{...props}
>
<div
className={classNames(
'flex-none relative bg-black',
small ? 'w-8 h-8 rounded-md' : 'w-12 h-12 rounded-lg'
)}
>
{/* TODO: Handle sigils */}
</div>
<Avatar size={size} {...provider} />
<div className="flex-1 text-black">
<p className="font-mono">{provider.nickname || <ShipName name={provider.shipName} />}</p>
{provider.status && !small && <p className="font-normal">{provider.status}</p>}
{provider.status && size === 'default' && <p className="font-normal">{provider.status}</p>}
</div>
</Link>
);

View File

@ -1,12 +1,12 @@
import React, { MouseEvent, useCallback } from 'react';
import { Provider } from '@urbit/api';
import { Contact, Provider } from '@urbit/api';
import classNames from 'classnames';
import { MatchItem } from '../nav/Nav';
import { useRecentsStore } from '../nav/search/Home';
import { ProviderLink, ProviderLinkProps } from './ProviderLink';
export type ProviderListProps = {
providers: Provider[];
providers: ({ shipName: string } & Contact)[];
labelledBy: string;
matchAgainst?: MatchItem;
onClick?: (e: MouseEvent<HTMLAnchorElement>, p: Provider) => void;
@ -28,7 +28,7 @@ export const ProviderList = ({
matchAgainst,
onClick,
listClass,
small = false,
size = 'default',
...props
}: ProviderListProps) => {
const addRecentDev = useRecentsStore((state) => state.addRecentDev);
@ -39,18 +39,18 @@ export const ProviderList = ({
return (
<ul
className={classNames('-mx-2', !small && 'space-y-4', listClass)}
className={classNames(size !== 'default' ? 'space-y-4' : 'space-y-8', listClass)}
aria-labelledby={labelledBy}
>
{providers.map((p) => (
<li key={p.shipName} id={p.shipName} role="option" aria-selected={selected(p)}>
<ProviderLink
{...props}
small={small}
size={size}
provider={p}
selected={selected(p)}
onClick={(e) => {
addRecentDev(p);
addRecentDev(p.shipName);
if (onClick) {
onClick(e, p);
}

View File

@ -1,4 +1,4 @@
import { debounce, DebounceSettings } from 'lodash-es';
import { debounce, DebounceSettings } from 'lodash';
import { useRef, useEffect, useCallback } from 'react';
import { useIsMounted } from './useIsMounted';

View File

@ -1,6 +1,6 @@
import { pick } from 'lodash-es';
import { pick } from 'lodash';
import React, { useCallback } from 'react';
import { kilnSuspend } from '@urbit/api/hood';
import { kilnBump } from '@urbit/api/hood';
import { AppList } from '../../components/AppList';
import { Button } from '../../components/Button';
import { Dialog, DialogClose, DialogContent, DialogTrigger } from '../../components/Dialog';
@ -49,9 +49,8 @@ export const BaseBlockedNotification = ({ notification }: BaseBlockedNotificatio
const handlePauseOTAs = useCallback(() => {}, []);
const handleArchiveApps = useCallback(async () => {
await Promise.all(desks.map((d) => api.poke(kilnSuspend(d))));
// TODO: retrigger OTA?
}, [desks]);
api.poke(kilnBump(true));
}, []);
return (
<section

View File

@ -2,8 +2,7 @@ import produce from 'immer';
import create from 'zustand';
import React, { useEffect } from 'react';
import { persist } from 'zustand/middleware';
import { take } from 'lodash-es';
import { Provider } from '@urbit/api';
import { take } from 'lodash';
import { MatchItem, useLeapStore } from '../Nav';
import { providerMatch } from './Providers';
import { AppList } from '../../components/AppList';
@ -13,12 +12,13 @@ import { ShipName } from '../../components/ShipName';
import { ProviderLink } from '../../components/ProviderLink';
import { DocketWithDesk, useCharges } from '../../state/docket';
import { getAppHref } from '../../state/util';
import useContactState from '../../state/contact';
export interface RecentsStore {
recentApps: DocketWithDesk[];
recentDevs: Provider[];
recentDevs: string[];
addRecentApp: (app: DocketWithDesk) => void;
addRecentDev: (dev: Provider) => void;
addRecentDev: (ship: string) => void;
}
export const useRecentsStore = create<RecentsStore>(
@ -41,7 +41,7 @@ export const useRecentsStore = create<RecentsStore>(
addRecentDev: (dev) => {
set(
produce((draft: RecentsStore) => {
const hasDev = draft.recentDevs.find((p) => p.shipName === dev.shipName);
const hasDev = draft.recentDevs.includes(dev);
if (!hasDev) {
draft.recentDevs.unshift(dev);
}
@ -60,7 +60,7 @@ export const useRecentsStore = create<RecentsStore>(
window.recents = useRecentsStore.getState;
export function addRecentDev(dev: Provider) {
export function addRecentDev(dev: string) {
return useRecentsStore.getState().addRecentDev(dev);
}
@ -73,7 +73,9 @@ export const Home = () => {
const { recentApps, recentDevs } = useRecentsStore();
const charges = useCharges();
const groups = charges?.groups;
const zod = { shipName: '~zod' };
const contacts = useContactState((s) => s.contacts);
const zod = { shipName: '~zod', ...contacts['~zod'] };
const providerList = recentDevs.map((d) => ({ shipName: d, ...contacts[d] }));
useEffect(() => {
const apps = recentApps.map((app) => ({
@ -122,18 +124,26 @@ export const Home = () => {
{recentDevs.length === 0 && (
<div className="min-h-[150px] p-6 rounded-xl bg-gray-100">
<p className="mb-4">Urbit app developers you search for will be listed here.</p>
<p className="mb-6">
Try out app discovery by visiting <ShipName name="~zod" /> below.
</p>
<ProviderLink provider={zod} small onClick={() => addRecentDev(zod)} />
{zod && (
<>
<p className="mb-6">
Try out app discovery by visiting <ShipName name="~zod" /> below.
</p>
<ProviderLink
provider={zod}
size="small"
onClick={() => addRecentDev(zod.shipName)}
/>
</>
)}
</div>
)}
{recentDevs.length > 0 && (
<ProviderList
providers={recentDevs}
providers={providerList}
labelledBy="recent-devs"
matchAgainst={selectedMatch}
small
size="small"
/>
)}
</div>

View File

@ -5,6 +5,7 @@ import { Provider } from '@urbit/api';
import { MatchItem, useLeapStore } from '../Nav';
import { useAllies } from '../../state/docket';
import { ProviderList } from '../../components/ProviderList';
import useContactState from '../../state/contact';
type ProvidersProps = RouteComponentProps<{ ship: string }>;
@ -23,6 +24,7 @@ export function providerMatch(provider: Provider | string): MatchItem {
export const Providers = ({ match }: ProvidersProps) => {
const selectedMatch = useLeapStore((state) => state.selectedMatch);
const provider = match?.params.ship;
const contacts = useContactState((s) => s.contacts);
const allies = useAllies();
const search = provider || '';
const results = useMemo(
@ -39,10 +41,11 @@ export const Providers = ({ match }: ProvidersProps) => {
return right - left;
})
.map((el) => ({ shipName: el.original }))
.map((el) => ({ shipName: el.original, ...contacts[el.original] }))
: [],
[allies, search]
[allies, search, contacts]
);
const count = results?.length;
useEffect(() => {

Some files were not shown because too many files have changed in this diff Show More