mirror of
https://github.com/tloncorp/landscape.git
synced 2024-12-01 02:45:49 +03:00
Merge pull request #16 from urbit/t/merge-agent-clay
grid: migrate upstream changes for compatibility with 417 clay + kiln
This commit is contained in:
commit
d882b0dce0
@ -3,7 +3,7 @@
|
||||
|%
|
||||
+$ card card:agent:gall
|
||||
+$ app-state
|
||||
$: %2
|
||||
$: %3
|
||||
:: local
|
||||
charges=(map desk charge)
|
||||
==
|
||||
@ -42,7 +42,7 @@
|
||||
++ on-init
|
||||
^- (quip card _this)
|
||||
:_ this
|
||||
:~ (~(watch-our pass /kiln) %hood /kiln/vats)
|
||||
:~ ~(tire pass /tire)
|
||||
(~(connect pass /eyre) [~ /] %docket)
|
||||
(~(wait pass /init) (add 1 now.bowl))
|
||||
(~(connect pass /eyre) [~ /apps] %docket)
|
||||
@ -54,20 +54,21 @@
|
||||
|^
|
||||
=+ !<(old=app-states vase)
|
||||
=? old ?=(?(~ ^) -.old) [%1 old]
|
||||
=^ cards old
|
||||
=^ cards-1 old
|
||||
?. ?=(%1 -.old) `old
|
||||
=/ rein=cage kiln-rein+!>([%base %.y ~ ~])
|
||||
=/ nuke=cage kiln-uninstall+!>(%hodl)
|
||||
:_ old(- %2)
|
||||
:~ [%pass /rein %agent [our.bowl %hood] %poke rein]
|
||||
[%pass /nuke %agent [our.bowl %hood] %poke nuke]
|
||||
==
|
||||
?> ?=(%2 -.old)
|
||||
`old(- %2)
|
||||
=^ cards-2 old
|
||||
?. ?=(%2 -.old) `old
|
||||
:_ old(- %3) :_ ~
|
||||
~(tire pass /tire)
|
||||
?> ?=(%3 -.old)
|
||||
=/ cards-tire [~(tire pass /tire) ~]
|
||||
=. -.state old
|
||||
:: inflate-cache needs to be called after the state is set
|
||||
::
|
||||
=. +.state inflate-cache
|
||||
[cards this]
|
||||
[:(weld cards-1 cards-2 cards-tire) this]
|
||||
|
||||
::
|
||||
++ inflate-cache
|
||||
^- cache
|
||||
@ -81,9 +82,11 @@
|
||||
$^ state-0-ket
|
||||
$% state-0-sig
|
||||
state-1
|
||||
state-2
|
||||
app-state
|
||||
==
|
||||
::
|
||||
+$ state-2 [%2 (map desk charge)]
|
||||
+$ state-1 [%1 (map desk charge)]
|
||||
+$ state-0-sig
|
||||
$: ~
|
||||
@ -94,6 +97,7 @@
|
||||
==
|
||||
--
|
||||
::
|
||||
|
||||
++ on-save !>(-.state)
|
||||
++ on-poke
|
||||
|= [=mark =vase]
|
||||
@ -189,13 +193,21 @@
|
||||
==
|
||||
::
|
||||
[%x %charges ~]
|
||||
=/ tyr
|
||||
.^(rock:tire:clay %cx /(scot %p our.bowl)//(scot %da now.bowl)/tire)
|
||||
:- ~ :- ~
|
||||
%- charge-update:cg
|
||||
:- %initial
|
||||
%- ~(gas by *(map desk charge))
|
||||
%+ turn ~(tap by charges)
|
||||
%+ murn ~(tap by charges)
|
||||
|= [=desk =charge]
|
||||
[desk (get-light-charge charge)]
|
||||
?~ got=(~(get by tyr) desk)
|
||||
~
|
||||
?: ?& ?=(%dead zest.u.got)
|
||||
?=(~ (get-apps-have:hood our.bowl desk now.bowl))
|
||||
==
|
||||
~
|
||||
`u=[desk (get-light-charge charge)]
|
||||
::
|
||||
[%x %charges @ %version ~]
|
||||
?~ charge=(~(get by charges) i.t.t.path)
|
||||
@ -212,114 +224,11 @@
|
||||
~ `state
|
||||
[%rein ~] ~&(%reined `state)
|
||||
[%nuke ~] ~&(%nuked `state)
|
||||
[%kiln ~] take-kiln
|
||||
[%kiln ~] `state
|
||||
[%charge @ *] (take-charge i.t.wire t.t.wire)
|
||||
==
|
||||
[cards this]
|
||||
::
|
||||
++ take-kiln
|
||||
^- (quip card _state)
|
||||
?+ -.sign (on-agent:def:cc wire sign)
|
||||
%kick [(~(watch-our pass /kiln) %hood /kiln/vats)^~ state]
|
||||
%fact
|
||||
|^ ^- (quip card _state)
|
||||
?+ p.cage.sign ~|(take-kiln-mark/p.cage.sign !!)
|
||||
%kiln-vats-snap-0 (on-snap !<(snap:hood q.cage.sign))
|
||||
%kiln-vats-diff-0 (on-diff !<(diff:hood q.cage.sign))
|
||||
==
|
||||
::
|
||||
++ on-snap
|
||||
|= =snap:hood
|
||||
^- (quip card _state)
|
||||
=| fex=(list card)
|
||||
=/ ark ~(tap by snap)
|
||||
|- ^- (quip card _state)
|
||||
?~ ark [(flop fex) state]
|
||||
=^ caz state (on-commit i.ark)
|
||||
$(ark t.ark, fex (weld (flop caz) fex))
|
||||
::
|
||||
++ on-diff
|
||||
|= =diff:hood
|
||||
=+ !<(=diff:hood q.cage.sign)
|
||||
?- -.diff
|
||||
%commit (on-commit [desk arak]:diff)
|
||||
%suspend (on-suspend [desk arak]:diff)
|
||||
%revive (on-revive [desk arak]:diff)
|
||||
?(%block %reset %merge-sunk %merge-fail)
|
||||
`state
|
||||
==
|
||||
::
|
||||
++ on-commit
|
||||
|= [=desk =arak:hood]
|
||||
^- (quip card _state)
|
||||
=* cha ~(. ch desk)
|
||||
?. docket-exists:cha
|
||||
~? ?& !=(%base desk)
|
||||
!=(%kids desk)
|
||||
==
|
||||
[dap.bowl %no-docket-file-for desk]
|
||||
`state
|
||||
:: always update the docket in state to match clay's
|
||||
::
|
||||
=/ =docket docket:cha
|
||||
=/ pre=(unit charge) (~(get by charges) desk)
|
||||
=. charges (new-docket:cha docket)
|
||||
:: if the new chad is a site, we're instantly done
|
||||
::
|
||||
?: ?=(%site -.href.docket)
|
||||
=. charges (new-chad:cha %site ~)
|
||||
:- ~[add-fact:cha]
|
||||
state
|
||||
::
|
||||
=. by-base (~(put by by-base) base.href.docket desk)
|
||||
:: if the glob specification is unchanged, keep it
|
||||
::
|
||||
?: &(?=(^ pre) =(href.docket.u.pre href.docket) ?=(%glob -.chad.u.pre))
|
||||
[~[add-fact:cha] state]
|
||||
:: if the glob spec changed, but we already host it, keep it
|
||||
:: (this is the "just locally uploaded" case)
|
||||
::
|
||||
?: ?& ?=(^ pre)
|
||||
?=(%glob -.chad.u.pre)
|
||||
::
|
||||
.= [(sham glob.chad.u.pre) %ames our.bowl]
|
||||
glob-reference.href.docket
|
||||
==
|
||||
[~[add-fact:cha] state]
|
||||
:: if the glob changed, forget the old and fetch the new
|
||||
::
|
||||
=. charges (new-chad:cha %install ~)
|
||||
[[add-fact:cha fetch-glob:cha] state]
|
||||
::
|
||||
++ on-suspend
|
||||
|= [=desk =arak:hood]
|
||||
^- (quip card _state)
|
||||
=* cha ~(. ch desk)
|
||||
?. (~(has by charges) desk) `state
|
||||
=/ glob=(unit glob)
|
||||
=/ =chad
|
||||
chad:(~(got by charges) desk)
|
||||
?:(?=(%glob -.chad) `glob.chad ~)
|
||||
=. charges (new-chad:cha %suspend glob)
|
||||
:_(state ~[add-fact:cha])
|
||||
::
|
||||
++ on-revive
|
||||
|= [=desk =arak:hood]
|
||||
^- (quip card _state)
|
||||
=* cha ~(. ch desk)
|
||||
?. (~(has by charges) desk) `state
|
||||
=/ =charge (~(got by charges) desk)
|
||||
?. ?=(%glob -.href.docket.charge)
|
||||
=. charges (new-chad:cha %site ~)
|
||||
:_(state ~[add-fact:cha])
|
||||
=. charges
|
||||
%- new-chad:cha
|
||||
?. ?=([%suspend ~ *] chad.charge)
|
||||
[%install ~]
|
||||
[%glob u.glob.chad.charge]
|
||||
:_(state [add-fact fetch-glob]:cha)
|
||||
--
|
||||
==
|
||||
++ take-charge
|
||||
|= [=desk =^wire]
|
||||
^- (quip card _state)
|
||||
@ -398,6 +307,7 @@
|
||||
::
|
||||
++ on-arvo
|
||||
|= [=wire sign=sign-arvo]
|
||||
|^
|
||||
=^ cards state
|
||||
?+ wire (on-arvo:def wire sign)
|
||||
[%init ~]
|
||||
@ -410,8 +320,114 @@
|
||||
?: accepted.sign `state
|
||||
~& [dap.bowl %failed-to-bind path.binding.sign]
|
||||
`state
|
||||
::
|
||||
[%tire ~]
|
||||
?> ?=([%clay %tire *] sign)
|
||||
?- -.p.sign
|
||||
%& (on-rock p.p.sign)
|
||||
%| (on-wave p.p.sign)
|
||||
==
|
||||
::
|
||||
[%warp * ~]
|
||||
?> ?=(%writ +<.sign)
|
||||
(on-writ i.t.wire p.sign)
|
||||
==
|
||||
[cards this]
|
||||
::
|
||||
++ on-rock
|
||||
|= tyr=rock:tire:clay
|
||||
^- (quip card _state)
|
||||
=| fex=(list card)
|
||||
=/ ark ~(tap by tyr)
|
||||
|- ^- (quip card _state)
|
||||
?~ ark [(flop fex) state]
|
||||
=^ caz state (on-zest [p zest.q]:i.ark)
|
||||
$(ark t.ark, fex (weld (flop caz) fex))
|
||||
::
|
||||
++ on-wave
|
||||
|= =wave:tire:clay
|
||||
^- (quip card _state)
|
||||
?- -.wave
|
||||
%wait `state
|
||||
%warp `state
|
||||
%zest (on-zest +.wave)
|
||||
==
|
||||
::
|
||||
++ on-zest
|
||||
|= [=desk =zest:clay]
|
||||
^- (quip card _state)
|
||||
=* cha ~(. ch desk)
|
||||
=/ card-1
|
||||
(~(warp-our pass /warp/[desk]) desk ~ %sing %z da+now.bowl /desk/docket-0)
|
||||
=^ cards-2 state
|
||||
?. (~(has by charges) desk)
|
||||
`state
|
||||
=/ =charge (~(got by charges) desk)
|
||||
?- zest
|
||||
%live
|
||||
?. ?=(%glob -.href.docket.charge)
|
||||
=. charges (new-chad:cha %site ~)
|
||||
:_(state ~[add-fact:cha])
|
||||
:_(state ~[add-fact:cha])
|
||||
::
|
||||
?(%held %dead)
|
||||
=/ glob=(unit glob)
|
||||
?:(?=(%glob -.chad.charge) `glob.chad.charge ~)
|
||||
=. charges (new-chad:cha %suspend glob)
|
||||
:_(state ~[add-fact:cha])
|
||||
==
|
||||
[[card-1 cards-2] state]
|
||||
::
|
||||
++ on-writ
|
||||
|= [=desk =riot:clay]
|
||||
^- (quip card _state)
|
||||
=/ card-1
|
||||
(~(warp-our pass /warp/[desk]) desk ~ %next %z da+now.bowl /desk/docket-0)
|
||||
=^ cards-2 state
|
||||
=* cha ~(. ch desk)
|
||||
=/ tyr
|
||||
.^(rock:tire:clay %cx /(scot %p our.bowl)//(scot %da now.bowl)/tire)
|
||||
?. =(%live zest:(~(got by tyr) desk))
|
||||
`state
|
||||
?. docket-exists:cha
|
||||
:: ~? ?& !=(%base desk)
|
||||
:: !=(%kids desk)
|
||||
:: ==
|
||||
:: [dap.bowl %no-docket-file-for desk]
|
||||
`state
|
||||
:: always update the docket in state to match clay's
|
||||
::
|
||||
=/ =docket docket:cha
|
||||
=/ pre=(unit charge) (~(get by charges) desk)
|
||||
=. charges (new-docket:cha docket)
|
||||
:: if the new chad is a site, we're instantly done
|
||||
::
|
||||
?: ?=(%site -.href.docket)
|
||||
=. charges (new-chad:cha %site ~)
|
||||
:- ~[add-fact:cha]
|
||||
state
|
||||
::
|
||||
=. by-base (~(put by by-base) base.href.docket desk)
|
||||
:: if the glob specification is unchanged, keep it
|
||||
::
|
||||
?: &(?=(^ pre) =(href.docket.u.pre href.docket) ?=(%glob -.chad.u.pre))
|
||||
[~[add-fact:cha] state]
|
||||
:: if the glob spec changed, but we already host it, keep it
|
||||
:: (this is the "just locally uploaded" case)
|
||||
::
|
||||
?: ?& ?=(^ pre)
|
||||
?=(%glob -.chad.u.pre)
|
||||
::
|
||||
.= [(sham glob.chad.u.pre) %ames our.bowl]
|
||||
glob-reference.href.docket
|
||||
==
|
||||
[~[add-fact:cha] state]
|
||||
:: if the glob changed, forget the old and fetch the new
|
||||
::
|
||||
=. charges (new-chad:cha %install ~)
|
||||
[[add-fact:cha fetch-glob:cha] state]
|
||||
[[card-1 cards-2] state]
|
||||
--
|
||||
::
|
||||
++ on-fail on-fail:def
|
||||
++ on-leave on-leave:def
|
||||
@ -728,4 +744,3 @@
|
||||
++ docket .^(^docket %cx (scry:io desk docket-loc))
|
||||
--
|
||||
--
|
||||
|
||||
|
@ -2,16 +2,16 @@
|
||||
/+ verb, dbug, default-agent, agentio
|
||||
|%
|
||||
+$ card card:agent:gall
|
||||
+$ state-0 [%0 lagging=_|]
|
||||
+$ state-1 [%1 lagging=_|]
|
||||
::
|
||||
++ lag-interval ~m10
|
||||
--
|
||||
%+ verb |
|
||||
%- agent:dbug
|
||||
^- agent:gall
|
||||
=| state-0
|
||||
=| state-1
|
||||
=* state -
|
||||
=<
|
||||
=<
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
@ -21,12 +21,23 @@
|
||||
++ on-init
|
||||
^- (quip card _this)
|
||||
:_ this
|
||||
[onboard watch:kiln check:lag ~]:cc
|
||||
[onboard tire:cy check:lag ~]:cc
|
||||
::
|
||||
++ on-load
|
||||
|= =vase
|
||||
=+ !<(old=state-0 vase)
|
||||
`this(state old)
|
||||
^- (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
|
||||
@ -34,45 +45,57 @@
|
||||
++ on-watch on-watch:def
|
||||
++ on-agent
|
||||
|= [=wire =sign:agent:gall]
|
||||
|^
|
||||
^- (quip card _this)
|
||||
?+ wire (on-agent:def wire sign)
|
||||
[%kiln %vats ~] take-kiln-vats
|
||||
[%kiln %vats ~] `this
|
||||
==
|
||||
++ take-kiln-vats
|
||||
?- -.sign
|
||||
?(%poke-ack %watch-ack) (on-agent:def wire sign)
|
||||
%kick :_(this (drop safe-watch:kiln:cc))
|
||||
::
|
||||
%fact
|
||||
?. ?=(%kiln-vats-diff-0 p.cage.sign) `this
|
||||
=+ !<(=diff:hood q.cage.sign)
|
||||
?+ -.diff `this
|
||||
::
|
||||
%commit
|
||||
?. |(=(desk.diff %base) ~(has-docket de:cc desk.diff)) `this
|
||||
=/ =action:hark ~(commit de:cc desk.diff)
|
||||
::
|
||||
++ 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)]
|
||||
::
|
||||
%block
|
||||
=/ =action:hark (~(blocked de:cc desk.diff) blockers.diff)
|
||||
:_ 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-arvo
|
||||
|= [=wire sign=sign-arvo]
|
||||
^- (quip card _this)
|
||||
?. ?=([%check-lag ~] wire) (on-arvo:def wire sign)
|
||||
?> ?=([%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)
|
||||
::
|
||||
++ on-fail on-fail:def
|
||||
++ on-leave on-leave:def
|
||||
--
|
||||
@ -89,7 +112,7 @@
|
||||
[~[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 / /]
|
||||
@ -102,24 +125,23 @@
|
||||
++ poke
|
||||
|=(=action:hark (poke-our:pass %hark-store hark-action+!>(action)))
|
||||
--
|
||||
++ kiln
|
||||
::
|
||||
++ cy
|
||||
|%
|
||||
++ path /kiln/vats
|
||||
++ pass ~(. ^pass path)
|
||||
++ watch (watch-our:pass %hood path)
|
||||
++ watching (~(has by wex.bowl) [path our.bowl %hood])
|
||||
++ safe-watch `(unit card)`?:(watching ~ `watch)
|
||||
++ 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)
|
||||
++ 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]]
|
||||
++ vat
|
||||
.^(vat:hood %gx (scry:io %hood /kiln/vat/[desk]/noun))
|
||||
++ 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
|
||||
@ -131,7 +153,7 @@
|
||||
%+ rap 3
|
||||
?: =(desk %base)
|
||||
['System software' cord ~]
|
||||
?: has-docket
|
||||
?: has-docket
|
||||
['App: "' title:docket '"' cord ~]
|
||||
['Desk: ' desk cord ~]
|
||||
::
|
||||
@ -142,7 +164,7 @@
|
||||
::
|
||||
++ commit
|
||||
^- action:hark
|
||||
?:(=(1 ud.cass:vat) created updated)
|
||||
?:(=(1 version) created updated)
|
||||
::
|
||||
++ created
|
||||
^- action:hark
|
||||
@ -155,11 +177,11 @@
|
||||
(body /desk/[desk] (title-prefix (rap 3 ' has been updated to ' get-version ~)) ~)
|
||||
::
|
||||
++ blocked
|
||||
|= blockers=(set ^desk)
|
||||
|= =weft
|
||||
^- action:hark
|
||||
:+ %add-note [/blocked place]
|
||||
%^ body /blocked (title-prefix ' is blocked from upgrading')
|
||||
`(rap 3 'Blocking desks: ' (join ', ' ~(tap in blockers)))
|
||||
`(rap 3 'Blocked waiting for system version: ' (scot %ud num.weft) 'K' ~)
|
||||
::
|
||||
++ ver
|
||||
|= =version:^docket
|
||||
@ -172,7 +194,7 @@
|
||||
--
|
||||
++ note
|
||||
|%
|
||||
++ merge
|
||||
++ merge
|
||||
|= [=desk hash=@uv]
|
||||
^- (list body:hark)
|
||||
:_ ~
|
||||
|
@ -28,6 +28,7 @@
|
||||
%tas s+(scot %tas p.c)
|
||||
%ud (numb p.c)
|
||||
==
|
||||
::
|
||||
++ foreign-desk
|
||||
|= [s=^ship =desk]
|
||||
^- cord
|
||||
|
@ -1 +1 @@
|
||||
[%zuse 418]
|
||||
[%zuse 417]
|
||||
|
53
desk/ted/get-dudes.hoon
Normal file
53
desk/ted/get-dudes.hoon
Normal file
@ -0,0 +1,53 @@
|
||||
/- spider
|
||||
/+ *strandio
|
||||
::
|
||||
=, strand=strand:spider
|
||||
::
|
||||
:: send on /spider/garden/json/get-dudes/json
|
||||
::
|
||||
|%
|
||||
++ buds :: get agents currently running
|
||||
|= p=desk
|
||||
=/ m (strand ,(list dude:gall))
|
||||
^- form:m
|
||||
?. =(%$ p)
|
||||
;< q=(list dude:gall) bind:m (suds p)
|
||||
(pure:m q)
|
||||
;< q=(list desk) bind:m duds
|
||||
=| r=(list (list dude:gall))
|
||||
|- ^- form:m
|
||||
=* s $
|
||||
?~ q (pure:m (zing r))
|
||||
;< t=(list dude:gall) bind:m (suds i.q)
|
||||
s(q t.q, r [t r])
|
||||
::
|
||||
++ suds :: clean %ge scry
|
||||
|= p=desk
|
||||
=/ m (strand ,(list dude:gall))
|
||||
^- form:m
|
||||
;< q=(set [dude:gall ?]) bind:m
|
||||
(scry (set ,[dude:gall ?]) /ge/(scot %tas p))
|
||||
%- pure:m
|
||||
(murn ~(tap in q) |=([dude:gall ?] ?.(+.+< ~ `-.+<)))
|
||||
::
|
||||
++ duds :: get desks
|
||||
=/ m (strand ,(list desk))
|
||||
^- form:m
|
||||
;< p=(set desk) bind:m (scry (set ,desk) /cd/base)
|
||||
(pure:m ~(tap in p))
|
||||
--
|
||||
::
|
||||
^- thread:spider
|
||||
|= jon=vase
|
||||
=/ m (strand ,vase)
|
||||
^- form:m
|
||||
;< =bowl:spider bind:m get-bowl
|
||||
=, bowl
|
||||
?~ know=!<((unit json) jon)
|
||||
(pure:m !>(`json`[%s 'invalid-request']))
|
||||
?. ?=([%s @] u.know)
|
||||
(pure:m !>(`json`[%s 'invalid-request']))
|
||||
=, format
|
||||
;< breh=(list @tas) bind:m (buds (so:dejs u.know))
|
||||
%- pure:m
|
||||
!>(`json`(frond:enjs 'buds' a+(turn breh |=(@tas s+[+<]))))
|
16
ui/package-lock.json
generated
16
ui/package-lock.json
generated
@ -20,8 +20,8 @@
|
||||
"@tlon/sigil-js": "^1.4.4",
|
||||
"@tloncorp/mock-http-api": "^1.2.0",
|
||||
"@types/lodash": "^4.14.172",
|
||||
"@urbit/api": "^2.1.1",
|
||||
"@urbit/http-api": "^2.2.0",
|
||||
"@urbit/api": "^2.2.0",
|
||||
"@urbit/http-api": "^2.3.0",
|
||||
"big-integer": "^1.6.48",
|
||||
"browser-cookies": "^1.2.0",
|
||||
"classnames": "^2.3.1",
|
||||
@ -1695,9 +1695,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@urbit/api": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.1.1.tgz",
|
||||
"integrity": "sha512-QRlqhtJ73q+pgMdSwuOO62HlxA7/2c5ylCcOUT01LXkJ2LTVCl5u+QnejdDvUmqjOuN2PyZk7df30xJVg6rC2A==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.2.0.tgz",
|
||||
"integrity": "sha512-W8kP9OT6yOK62n+4yCPO3i9QqU5xriLvZQ9WYW4SAV7ktbSrGuf2kmYbnoqfA/NybIs9Q/MbFkPewrz4XJ96Ag==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.16.0",
|
||||
"big-integer": "^1.6.48",
|
||||
@ -8888,9 +8888,9 @@
|
||||
}
|
||||
},
|
||||
"@urbit/api": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.1.1.tgz",
|
||||
"integrity": "sha512-QRlqhtJ73q+pgMdSwuOO62HlxA7/2c5ylCcOUT01LXkJ2LTVCl5u+QnejdDvUmqjOuN2PyZk7df30xJVg6rC2A==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.2.0.tgz",
|
||||
"integrity": "sha512-W8kP9OT6yOK62n+4yCPO3i9QqU5xriLvZQ9WYW4SAV7ktbSrGuf2kmYbnoqfA/NybIs9Q/MbFkPewrz4XJ96Ag==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.16.0",
|
||||
"big-integer": "^1.6.48",
|
||||
|
@ -27,8 +27,8 @@
|
||||
"@tlon/sigil-js": "^1.4.4",
|
||||
"@tloncorp/mock-http-api": "^1.2.0",
|
||||
"@types/lodash": "^4.14.172",
|
||||
"@urbit/api": "^2.1.1",
|
||||
"@urbit/http-api": "^2.2.0",
|
||||
"@urbit/api": "^2.2.0",
|
||||
"@urbit/http-api": "^2.3.0",
|
||||
"big-integer": "^1.6.48",
|
||||
"browser-cookies": "^1.2.0",
|
||||
"classnames": "^2.3.1",
|
||||
|
@ -86,9 +86,8 @@ const AppRoutes = () => {
|
||||
fetchCharges();
|
||||
fetchAllies();
|
||||
|
||||
const { fetchVats, fetchLag } = useKilnState.getState();
|
||||
fetchVats();
|
||||
fetchLag();
|
||||
const { initializeKiln } = useKilnState.getState();
|
||||
initializeKiln();
|
||||
|
||||
useContactState.getState().initialize(api);
|
||||
useHarkState.getState().start();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { chadIsRunning, Treaty, Vat } from '@urbit/api';
|
||||
import { chadIsRunning, Pike, Treaty } from '@urbit/api';
|
||||
import clipboardCopy from 'clipboard-copy';
|
||||
import React, { FC, useCallback, useState } from 'react';
|
||||
import cn from 'classnames';
|
||||
@ -6,7 +6,7 @@ import { Button, PillButton } from './Button';
|
||||
import { Dialog, DialogClose, DialogContent, DialogTrigger } from './Dialog';
|
||||
import { DocketHeader } from './DocketHeader';
|
||||
import { Spinner } from './Spinner';
|
||||
import { VatMeta } from './VatMeta';
|
||||
import { PikeMeta } from './PikeMeta';
|
||||
import useDocketState, { ChargeWithDesk, useTreaty } from '../state/docket';
|
||||
import { getAppHref, getAppName } from '../state/util';
|
||||
import { addRecentApp } from '../nav/search/Home';
|
||||
@ -17,7 +17,7 @@ type InstallStatus = 'uninstalled' | 'installing' | 'installed';
|
||||
type App = ChargeWithDesk | Treaty;
|
||||
interface AppInfoProps {
|
||||
docket: App;
|
||||
vat?: Vat;
|
||||
pike?: Pike;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@ -34,10 +34,9 @@ function getInstallStatus(docket: App): InstallStatus {
|
||||
return 'uninstalled';
|
||||
}
|
||||
|
||||
function getRemoteDesk(docket: App, vat?: Vat) {
|
||||
if (vat && vat.arak.rail) {
|
||||
const { ship, desk } = vat.arak.rail;
|
||||
return [ship, desk];
|
||||
function getRemoteDesk(docket: App, pike?: Pike) {
|
||||
if (pike && pike.sync) {
|
||||
return [pike.sync.ship, pike.sync.desk];
|
||||
}
|
||||
if ('chad' in docket) {
|
||||
return ['', docket.desk];
|
||||
@ -46,10 +45,10 @@ function getRemoteDesk(docket: App, vat?: Vat) {
|
||||
return [ship, desk];
|
||||
}
|
||||
|
||||
export const AppInfo: FC<AppInfoProps> = ({ docket, vat, className }) => {
|
||||
export const AppInfo: FC<AppInfoProps> = ({ docket, pike, className }) => {
|
||||
const installStatus = getInstallStatus(docket);
|
||||
const [ship, desk] = getRemoteDesk(docket, vat);
|
||||
const publisher = vat?.arak?.rail?.publisher ?? ship;
|
||||
const [ship, desk] = getRemoteDesk(docket, pike);
|
||||
const publisher = pike?.sync?.ship ?? ship;
|
||||
const [copied, setCopied] = useState(false);
|
||||
const treaty = useTreaty(ship, desk);
|
||||
|
||||
@ -136,10 +135,10 @@ export const AppInfo: FC<AppInfoProps> = ({ docket, vat, className }) => {
|
||||
</div>
|
||||
</DocketHeader>
|
||||
<div className="space-y-6">
|
||||
{vat ? (
|
||||
{pike ? (
|
||||
<>
|
||||
<hr className="-mx-5 sm:-mx-8 border-gray-50" />
|
||||
<VatMeta vat={vat} />
|
||||
<PikeMeta pike={pike} />
|
||||
</>
|
||||
) : null}
|
||||
{!treaty ? null : (
|
||||
|
25
ui/src/components/PikeMeta.tsx
Normal file
25
ui/src/components/PikeMeta.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { Pike } from '@urbit/api';
|
||||
|
||||
import { Attribute } from './Attribute';
|
||||
|
||||
export function PikeMeta(props: { pike: Pike }) {
|
||||
const { pike } = props;
|
||||
|
||||
const pluralUpdates = pike.wefts?.length !== 1;
|
||||
return (
|
||||
<div className="mt-5 sm:mt-8 space-y-5 sm:space-y-8">
|
||||
<Attribute title="Desk Hash" attr="hash">
|
||||
{pike.hash}
|
||||
</Attribute>
|
||||
<Attribute title="Installed into" attr="local-desk">
|
||||
%{pike.sync?.desk}
|
||||
</Attribute>
|
||||
{pike.wefts && pike.wefts.length > 0 ? (
|
||||
<Attribute attr="next" title="Pending Updates">
|
||||
{pike.wefts.length} update{pluralUpdates ? 's are' : ' is'} pending a System Update
|
||||
</Attribute>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -3,11 +3,12 @@ import React, { HTMLAttributes } from 'react';
|
||||
|
||||
type ShipNameProps = {
|
||||
name: string;
|
||||
truncate?: boolean;
|
||||
} & HTMLAttributes<HTMLSpanElement>;
|
||||
|
||||
export const ShipName = ({ name, ...props }: ShipNameProps) => {
|
||||
export const ShipName = ({ name, truncate = true, ...props }: ShipNameProps) => {
|
||||
const separator = /([_^-])/;
|
||||
const citedName = cite(name);
|
||||
const citedName = truncate ? cite(name) : name;
|
||||
|
||||
if (!citedName) {
|
||||
return null;
|
||||
|
103
ui/src/components/SourceSetter.tsx
Normal file
103
ui/src/components/SourceSetter.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useAsyncCall } from '../logic/useAsyncCall';
|
||||
import { Button } from './Button';
|
||||
import { ShipName } from './ShipName';
|
||||
import { Spinner } from './Spinner';
|
||||
|
||||
interface SourceSetterProps {
|
||||
appName: string;
|
||||
srcDesk: string;
|
||||
srcShip?: string;
|
||||
title: string;
|
||||
toggleSrc: (desk: string, ship: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export default function SourceSetter({
|
||||
appName,
|
||||
srcDesk,
|
||||
srcShip,
|
||||
title,
|
||||
toggleSrc
|
||||
}: SourceSetterProps) {
|
||||
const [newSyncShip, setNewSyncShip] = useState(srcShip ?? '');
|
||||
const { status: requestStatus, call: handleSubmit } = useAsyncCall(toggleSrc);
|
||||
const syncDirty = newSyncShip !== srcShip;
|
||||
|
||||
const onUnset = useCallback(() => {
|
||||
if (!srcShip) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
// eslint-disable-next-line no-alert, no-restricted-globals
|
||||
confirm(`Are you sure you want to unsync ${appName}? You will no longer receive updates.`)
|
||||
) {
|
||||
toggleSrc(srcDesk, srcShip);
|
||||
}
|
||||
}, [srcShip, srcDesk]);
|
||||
|
||||
const handleSourceChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { target } = e;
|
||||
const value = target.value.trim();
|
||||
setNewSyncShip(value.startsWith('~') ? value : `~${value}`);
|
||||
}, []);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
await handleSubmit(srcDesk, newSyncShip);
|
||||
},
|
||||
[srcDesk, newSyncShip]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="h3 mb-7">{title}</h2>
|
||||
<div className="space-y-3">
|
||||
{srcShip ? (
|
||||
<>
|
||||
<h3 className="flex items-center h4 mb-2">Automatic Updates</h3>
|
||||
<p>Automatically download and apply updates to keep {appName} up to date.</p>
|
||||
<div className="flex-1 flex flex-col justify-center space-y-6">
|
||||
<p>
|
||||
OTA Source:{' '}
|
||||
<ShipName name={srcShip} truncate={false} className="font-semibold font-mono" />
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
<Button onClick={onUnset} variant="destructive">
|
||||
Unsync Updates for {appName}...
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<form className="inner-section relative" onSubmit={onSubmit}>
|
||||
<label htmlFor="ota-source" className="h4 mb-3">
|
||||
Set Update Source
|
||||
</label>
|
||||
<p className="mb-2">Enter a valid urbit name to receive updates for {appName}.</p>
|
||||
<div className="relative">
|
||||
<input
|
||||
id="ota-source"
|
||||
type="text"
|
||||
value={newSyncShip}
|
||||
onChange={handleSourceChange}
|
||||
className="input font-semibold default-ring"
|
||||
/>
|
||||
{syncDirty && (
|
||||
<Button type="submit" className="absolute top-1 right-1 py-1 px-3 text-sm">
|
||||
{requestStatus !== 'loading' && 'Save'}
|
||||
{requestStatus === 'loading' && (
|
||||
<>
|
||||
<span className="sr-only">Saving...</span>
|
||||
<Spinner className="w-5 h-5" />
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Vat } from '@urbit/api';
|
||||
|
||||
import { Attribute } from './Attribute';
|
||||
|
||||
export function VatMeta(props: { vat: Vat }) {
|
||||
const { vat } = props;
|
||||
const { desk, arak, cass, hash } = vat;
|
||||
|
||||
const { desk: foreignDesk, ship, next } = arak.rail || {};
|
||||
const pluralUpdates = next?.length !== 1;
|
||||
return (
|
||||
<div className="mt-5 sm:mt-8 space-y-5 sm:space-y-8">
|
||||
<Attribute title="Desk Hash" attr="hash">
|
||||
{hash}
|
||||
</Attribute>
|
||||
<Attribute title="Installed into" attr="local-desk">
|
||||
%{desk}
|
||||
</Attribute>
|
||||
{next && next.length > 0 ? (
|
||||
<Attribute attr="next" title="Pending Updates">
|
||||
{next.length} update{pluralUpdates ? 's are' : ' is'} pending a System Update
|
||||
</Attribute>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,42 +1,37 @@
|
||||
import { kilnBump, Vat } from '@urbit/api';
|
||||
import { kilnBump, Pike } from '@urbit/api';
|
||||
import { partition, pick } from 'lodash';
|
||||
import { useCallback } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import api from '../state/api';
|
||||
import { useCharges } from '../state/docket';
|
||||
import useKilnState, { useVat } from '../state/kiln';
|
||||
import useKilnState, { usePike } from '../state/kiln';
|
||||
|
||||
export function vatIsBlocked(newKelvin: number | undefined, vat: Vat) {
|
||||
if (!newKelvin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !(vat.arak?.rail?.next || []).find(({ weft }) => weft.kelvin === newKelvin);
|
||||
function pikeIsBlocked(newKelvin: number, pike: Pike) {
|
||||
return !pike.wefts?.find(({ kelvin }) => kelvin === newKelvin);
|
||||
}
|
||||
|
||||
export function useSystemUpdate() {
|
||||
const { push } = useHistory();
|
||||
const base = useVat('base');
|
||||
const update = base?.arak?.rail?.next?.[0];
|
||||
const newKelvin = update?.weft?.kelvin;
|
||||
const base = usePike('base');
|
||||
const nextUpdate = base?.wefts[0];
|
||||
const newKelvin = base?.wefts[0]?.kelvin ?? 417;
|
||||
const charges = useCharges();
|
||||
const [blocked] = useKilnState((s) => {
|
||||
const [b, u] = partition(Object.entries(s.vats), ([, vat]) => vatIsBlocked(newKelvin, vat));
|
||||
const [b, u] = partition(Object.entries(s.pikes), ([, pike]) => pikeIsBlocked(newKelvin, pike));
|
||||
return [b.map(([d]) => d), u.map(([d]) => d)] as const;
|
||||
});
|
||||
|
||||
const systemBlocked = update && blocked;
|
||||
const systemBlocked = nextUpdate && blocked;
|
||||
const blockedCharges = Object.values(pick(charges, blocked));
|
||||
const blockedCount = blockedCharges.length;
|
||||
|
||||
const freezeApps = useCallback(async () => {
|
||||
api.poke(kilnBump(true));
|
||||
await api.poke(kilnBump());
|
||||
push('/leap/upgrading');
|
||||
}, []);
|
||||
|
||||
return {
|
||||
base,
|
||||
update,
|
||||
nextUpdate,
|
||||
systemBlocked,
|
||||
blockedCharges,
|
||||
blockedCount,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Handler, SubscriptionHandler, createResponse } from '@tloncorp/mock-http-api';
|
||||
import mockContacts from './mockContacts';
|
||||
import { mockAllies, mockCharges, mockTreaties, mockVats } from '../state/mock-data';
|
||||
import { mockAllies, mockCharges, mockTreaties } from '../state/mock-data';
|
||||
|
||||
const settingsSub = {
|
||||
action: 'subscribe',
|
||||
@ -45,14 +45,6 @@ const mockHandlers: Handler[] = [
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
action: 'scry',
|
||||
app: 'hood',
|
||||
path: '/kiln/vats',
|
||||
func: () => ({
|
||||
mockVats
|
||||
})
|
||||
},
|
||||
{
|
||||
action: 'scry',
|
||||
app: 'hood',
|
||||
|
@ -3,9 +3,9 @@ import classNames from 'classnames';
|
||||
import clipboardCopy from 'clipboard-copy';
|
||||
import React, { HTMLAttributes, useCallback, useState } from 'react';
|
||||
import { Link, Route, useHistory } from 'react-router-dom';
|
||||
import { Vat } from '@urbit/api';
|
||||
import { Pike } from '@urbit/api';
|
||||
import { Adjust } from '../components/icons/Adjust';
|
||||
import { useVat } from '../state/kiln';
|
||||
import { usePike } from '../state/kiln';
|
||||
import { disableDefault, handleDropdownLink } from '../state/util';
|
||||
import { useMedia } from '../logic/useMedia';
|
||||
import { Cross } from '../components/icons/Cross';
|
||||
@ -17,15 +17,15 @@ type SystemMenuProps = HTMLAttributes<HTMLButtonElement> & {
|
||||
shouldDim: boolean;
|
||||
};
|
||||
|
||||
function getHash(vat: Vat): string {
|
||||
const parts = vat.hash.split('.');
|
||||
function getHash(pike: Pike): string {
|
||||
const parts = pike.hash.split('.');
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
|
||||
export const SystemMenu = ({ className, open, subMenuOpen, shouldDim }: SystemMenuProps) => {
|
||||
const { push } = useHistory();
|
||||
const [copied, setCopied] = useState(false);
|
||||
const garden = useVat(window.desk);
|
||||
const garden = usePike(window.desk);
|
||||
const hash = garden ? getHash(garden) : null;
|
||||
const isMobile = useMedia('(max-width: 639px)');
|
||||
const select = useLeapStore((s) => s.select);
|
||||
|
@ -3,7 +3,7 @@ import { useParams } from 'react-router-dom';
|
||||
import { AppInfo } from '../../components/AppInfo';
|
||||
import { Spinner } from '../../components/Spinner';
|
||||
import useDocketState, { useCharge, useTreaty } from '../../state/docket';
|
||||
import { useVat } from '../../state/kiln';
|
||||
import { usePike } from '../../state/kiln';
|
||||
import { getAppName } from '../../state/util';
|
||||
import { useLeapStore } from '../Nav';
|
||||
|
||||
@ -11,7 +11,7 @@ export const TreatyInfo = () => {
|
||||
const select = useLeapStore((state) => state.select);
|
||||
const { host, desk } = useParams<{ host: string; desk: string }>();
|
||||
const treaty = useTreaty(host, desk);
|
||||
const vat = useVat(desk);
|
||||
const pike = usePike(desk);
|
||||
const charge = useCharge(desk);
|
||||
const name = getAppName(treaty);
|
||||
|
||||
@ -34,5 +34,5 @@ export const TreatyInfo = () => {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <AppInfo className="dialog-inner-container" docket={charge || treaty} vat={vat} />;
|
||||
return <AppInfo className="dialog-inner-container" docket={charge || treaty} pike={pike} />;
|
||||
};
|
||||
|
@ -26,8 +26,8 @@ export const Grid: FunctionComponent = () => {
|
||||
window.location.reload();
|
||||
}
|
||||
const start = performance.now();
|
||||
await useKilnState.getState().fetchVats();
|
||||
await useKilnState.getState().fetchVats();
|
||||
await useKilnState.getState().fetchPikes();
|
||||
await useKilnState.getState().fetchPikes();
|
||||
if (performance.now() - start > 5000) {
|
||||
attempt(count + 1);
|
||||
} else {
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { Pikes } from '@urbit/api';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom';
|
||||
import { Spinner } from '../components/Spinner';
|
||||
import { useQuery } from '../logic/useQuery';
|
||||
import { useCharge } from '../state/docket';
|
||||
import useKilnState, { useKilnLoaded } from '../state/kiln';
|
||||
import { useKilnLoaded, usePikes } from '../state/kiln';
|
||||
import { getAppHref } from '../state/util';
|
||||
|
||||
function getDeskByForeignRef(ship: string, desk: string): string | undefined {
|
||||
const { vats } = useKilnState.getState();
|
||||
const found = Object.entries(vats).find(
|
||||
([, vat]) => vat.arak.rail?.ship === ship && vat.arak.rail?.desk === desk
|
||||
function getDeskByForeignRef(pikes: Pikes, ship: string, desk: string): string | undefined {
|
||||
const found = Object.entries(pikes).find(
|
||||
([, pike]) => pike.sync?.ship === ship && pike.sync?.desk === desk
|
||||
);
|
||||
return found ? found[0] : undefined;
|
||||
}
|
||||
@ -22,8 +22,8 @@ type AppLinkProps = RouteComponentProps<{
|
||||
|
||||
function AppLink({ match, history, location }: AppLinkProps) {
|
||||
const { ship, desk, link = '' } = match.params;
|
||||
const ourDesk = getDeskByForeignRef(ship, desk);
|
||||
console.log(ourDesk);
|
||||
const pikes = usePikes();
|
||||
const ourDesk = getDeskByForeignRef(pikes, ship, desk);
|
||||
|
||||
if (ourDesk) {
|
||||
return <AppLinkRedirect desk={ourDesk} link={link} />;
|
||||
|
@ -1,50 +1,27 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { Setting } from '../components/Setting';
|
||||
import { ShipName } from '../components/ShipName';
|
||||
import { useCharge } from '../state/docket';
|
||||
import useKilnState, { useVat } from '../state/kiln';
|
||||
import useKilnState, { usePike } from '../state/kiln';
|
||||
import { getAppName } from '../state/util';
|
||||
import SourceSetter from '../components/SourceSetter';
|
||||
|
||||
export const AppPrefs = ({ match }: RouteComponentProps<{ desk: string }>) => {
|
||||
const { desk } = match.params;
|
||||
const charge = useCharge(desk);
|
||||
const vat = useVat(desk);
|
||||
const tracking = !!vat?.arak.rail;
|
||||
const otasEnabled = !vat?.arak.rail?.paused;
|
||||
const otaSource = vat?.arak.rail?.ship;
|
||||
const toggleOTAs = useKilnState((s) => s.toggleOTAs);
|
||||
|
||||
const toggleUpdates = useCallback((on: boolean) => toggleOTAs(desk, on), [desk, toggleOTAs]);
|
||||
const appName = getAppName(charge);
|
||||
const pike = usePike(desk);
|
||||
const srcShip = pike?.sync?.ship;
|
||||
const { toggleSync } = useKilnState();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="h3 mb-7">{getAppName(charge)} Settings</h2>
|
||||
<div className="space-y-8">
|
||||
{tracking ? (
|
||||
<Setting
|
||||
on={otasEnabled}
|
||||
toggle={toggleUpdates}
|
||||
name="Automatic Updates"
|
||||
>
|
||||
<p className="mb-1 leading-5">
|
||||
Automatically download and apply updates to keep{' '}
|
||||
{getAppName(charge)} up to date.
|
||||
</p>
|
||||
{otaSource && (
|
||||
<p>
|
||||
OTA Source:{' '}
|
||||
<ShipName
|
||||
name={otaSource}
|
||||
className="font-mono font-semibold"
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
</Setting>
|
||||
) : (
|
||||
<h4 className="text-gray-500">No settings</h4>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
<div className="inner-section space-y-8 relative">
|
||||
<SourceSetter
|
||||
appName={appName}
|
||||
title={`${appName} Settings`}
|
||||
toggleSrc={toggleSync}
|
||||
srcDesk={desk}
|
||||
srcShip={srcShip}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Vat } from '@urbit/api';
|
||||
import { Pike } from '@urbit/api';
|
||||
import React from 'react';
|
||||
import { AppList } from '../../components/AppList';
|
||||
import { Button } from '../../components/Button';
|
||||
@ -6,24 +6,22 @@ import { Dialog, DialogClose, DialogContent, DialogTrigger } from '../../compone
|
||||
import { FullTlon16Icon } from '../../components/icons/FullTlon16Icon';
|
||||
import { useSystemUpdate } from '../../logic/useSystemUpdate';
|
||||
import { useCharge } from '../../state/docket';
|
||||
import { useVat } from '../../state/kiln';
|
||||
import { usePike } from '../../state/kiln';
|
||||
import { disableDefault, pluralize } from '../../state/util';
|
||||
import { UpdatePreferences } from './UpdatePreferences';
|
||||
|
||||
function getHash(vat: Vat): string {
|
||||
const parts = vat.hash.split('.');
|
||||
function getHash(pike: Pike): string {
|
||||
const parts = pike.hash.split('.');
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
|
||||
export const AboutSystem = () => {
|
||||
const garden = useVat('garden');
|
||||
const gardenCharge = useCharge('garden');
|
||||
const { base, update, systemBlocked, blockedCharges, blockedCount, freezeApps } =
|
||||
const gardenPike = usePike(window.desk);
|
||||
const { systemBlocked, blockedCharges, blockedCount, freezeApps } =
|
||||
useSystemUpdate();
|
||||
const hash = base && getHash(base);
|
||||
const aeon = base ? base.arak.rail?.aeon : '';
|
||||
const nextAeon = update?.aeon;
|
||||
|
||||
const hash = gardenPike && getHash(gardenPike);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="inner-section space-y-8 relative mb-4">
|
||||
@ -45,15 +43,6 @@ export const AboutSystem = () => {
|
||||
<p>
|
||||
Version {gardenCharge?.version} ({hash})
|
||||
</p>
|
||||
{systemBlocked && (
|
||||
<p>
|
||||
Aeon {aeon}{' '}
|
||||
<span className="text-orange-500 mx-4 space-x-2">
|
||||
<span>—></span> <span>/</span> <span>—></span>
|
||||
</span>{' '}
|
||||
Aeon {nextAeon}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{systemBlocked ? (
|
||||
<>
|
||||
@ -98,7 +87,7 @@ export const AboutSystem = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<UpdatePreferences base={base} />
|
||||
<UpdatePreferences />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,81 +1,25 @@
|
||||
import { Vat } from '@urbit/api';
|
||||
import _ from 'lodash';
|
||||
import React, { ChangeEvent, FormEvent, useCallback, useEffect, useState } from 'react';
|
||||
import { Button } from '../../components/Button';
|
||||
import { Setting } from '../../components/Setting';
|
||||
import { Spinner } from '../../components/Spinner';
|
||||
import { useAsyncCall } from '../../logic/useAsyncCall';
|
||||
import useKilnState from '../../state/kiln';
|
||||
|
||||
interface UpdatePreferencesProps {
|
||||
base: Vat | undefined;
|
||||
}
|
||||
|
||||
export const UpdatePreferences = ({ base }: UpdatePreferencesProps) => {
|
||||
const { changeOTASource, toggleOTAs } = useKilnState((s) =>
|
||||
_.pick(s, ['toggleOTAs', 'changeOTASource'])
|
||||
);
|
||||
const otasEnabled = base && !(base.arak?.rail?.paused ?? true);
|
||||
const otaSource = base && base.arak.rail?.ship;
|
||||
|
||||
const toggleBase = useCallback((on: boolean) => toggleOTAs('base', on), [toggleOTAs]);
|
||||
|
||||
const [source, setSource] = useState('');
|
||||
const sourceDirty = source !== otaSource;
|
||||
const { status: sourceStatus, call: setOTA } = useAsyncCall(changeOTASource);
|
||||
|
||||
useEffect(() => {
|
||||
if (otaSource) {
|
||||
setSource(otaSource);
|
||||
}
|
||||
}, [otaSource]);
|
||||
|
||||
const handleSourceChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||
const { target } = e;
|
||||
const value = target.value.trim();
|
||||
setSource(value.startsWith('~') ? value : `~${value}`);
|
||||
}, []);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
setOTA(source);
|
||||
},
|
||||
[source]
|
||||
);
|
||||
import React from 'react';
|
||||
import SourceSetter from '../../components/SourceSetter';
|
||||
import useKilnState, { usePike } from '../../state/kiln';
|
||||
|
||||
export const UpdatePreferences = () => {
|
||||
const desk = 'base';
|
||||
const appName = 'your Urbit';
|
||||
const pike = usePike(desk);
|
||||
const srcShip = pike?.sync?.ship;
|
||||
const { toggleInstall } = useKilnState();
|
||||
|
||||
return (
|
||||
<div className="inner-section space-y-8 relative">
|
||||
<h2 className="h4">Update Preferences</h2>
|
||||
<form onSubmit={onSubmit}>
|
||||
<label htmlFor="ota-source" className="block font-semibold mb-1.5">
|
||||
System Update Provider
|
||||
</label>
|
||||
<div className="flex items-center space-x-2">
|
||||
<input
|
||||
id="ota-source"
|
||||
type="text"
|
||||
value={source}
|
||||
onChange={handleSourceChange}
|
||||
className="input bg-gray-50 font-semibold default-ring"
|
||||
/>
|
||||
<Button type="submit" disabled={!sourceDirty}>
|
||||
{sourceStatus !== 'loading' && 'Update'}
|
||||
{sourceStatus === 'loading' && (
|
||||
<>
|
||||
<span className="sr-only">Saving...</span>
|
||||
<Spinner className="w-5 h-5" />
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
<Setting on={!!otasEnabled} toggle={toggleBase} name="Automatically Update My Urbit">
|
||||
<p className="text-gray-600 leading-5">
|
||||
Ensure that system updates are downloaded and applied as soon as my update provider has an
|
||||
update readied
|
||||
</p>
|
||||
</Setting>
|
||||
<SourceSetter
|
||||
appName={appName}
|
||||
toggleSrc={toggleInstall}
|
||||
srcDesk={desk}
|
||||
srcShip={srcShip}
|
||||
title="System Updates"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,79 +1,76 @@
|
||||
import {
|
||||
getVats,
|
||||
Vats,
|
||||
scryLag,
|
||||
getBlockers,
|
||||
Vat,
|
||||
kilnInstall,
|
||||
kilnPause,
|
||||
kilnResume
|
||||
getPikes,
|
||||
Pikes,
|
||||
Pike,
|
||||
kilnUnsync,
|
||||
kilnSync,
|
||||
kilnUninstall,
|
||||
kilnInstall
|
||||
} from '@urbit/api';
|
||||
import create from 'zustand';
|
||||
import produce from 'immer';
|
||||
import { useCallback } from 'react';
|
||||
import api from './api';
|
||||
import { fakeRequest, useMockData } from './util';
|
||||
import { mockPikes } from './mock-data';
|
||||
|
||||
interface KilnState {
|
||||
vats: Vats;
|
||||
pikes: Pikes;
|
||||
loaded: boolean;
|
||||
fetchVats: () => Promise<void>;
|
||||
lag: boolean;
|
||||
fetchLag: () => Promise<void>;
|
||||
changeOTASource: (ship: string) => Promise<void>;
|
||||
toggleOTAs: (desk: string, on: boolean) => Promise<void>;
|
||||
fetchPikes: () => Promise<void>;
|
||||
toggleInstall: (desk: string, ship: string) => Promise<void>;
|
||||
toggleSync: (desk: string, ship: string) => Promise<void>;
|
||||
set: (s: KilnState) => void;
|
||||
initializeKiln: () => Promise<void>;
|
||||
}
|
||||
const useKilnState = create<KilnState>((set, get) => ({
|
||||
vats: {},
|
||||
pikes: useMockData ? mockPikes : {},
|
||||
lag: false,
|
||||
loaded: false,
|
||||
fetchVats: async () => {
|
||||
const vats = await api.scry<Vats>(getVats);
|
||||
set({ vats, loaded: true });
|
||||
fetchPikes: async () => {
|
||||
if (useMockData) {
|
||||
await fakeRequest({}, 500);
|
||||
set({ loaded: true });
|
||||
return;
|
||||
}
|
||||
const pikes = await api.scry<Pikes>(getPikes);
|
||||
set({ pikes, loaded: true });
|
||||
},
|
||||
fetchLag: async () => {
|
||||
const lag = await api.scry<boolean>(scryLag);
|
||||
set({ lag });
|
||||
},
|
||||
changeOTASource: async (ship: string) => {
|
||||
await api.poke(kilnInstall(ship, 'kids', 'base'));
|
||||
toggleInstall: async (desk: string, ship: string) => {
|
||||
const synced = !!get().pikes[desk].sync;
|
||||
await (useMockData
|
||||
? fakeRequest('')
|
||||
: api.poke(synced ? kilnUninstall(desk) : kilnInstall(ship, 'kids', desk)));
|
||||
await get().fetchPikes();
|
||||
},
|
||||
toggleOTAs: async (desk: string, on: boolean) => {
|
||||
set(
|
||||
produce((draft: KilnState) => {
|
||||
const { arak } = draft.vats[desk];
|
||||
if (!arak.rail) {
|
||||
return;
|
||||
}
|
||||
if (on) {
|
||||
arak.rail.paused = false;
|
||||
} else {
|
||||
arak.rail.paused = true;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
await api.poke(on ? kilnResume(desk) : kilnPause(desk));
|
||||
await get().fetchVats(); // refresh vat state
|
||||
},
|
||||
set: produce(set)
|
||||
toggleSync: async (desk: string, ship: string) => {
|
||||
const synced = !!get().pikes[desk].sync;
|
||||
await (useMockData
|
||||
? fakeRequest('')
|
||||
: api.poke(synced ? kilnUnsync(ship, desk) : kilnSync(ship, desk)));
|
||||
await get().fetchPikes();
|
||||
},
|
||||
set: produce(set),
|
||||
initializeKiln: async () => {
|
||||
await get().fetchLag();
|
||||
await get().fetchPikes();
|
||||
}
|
||||
}));
|
||||
|
||||
api.subscribe({
|
||||
app: 'hood',
|
||||
path: '/kiln/vats',
|
||||
event: () => {
|
||||
useKilnState.getState().fetchVats();
|
||||
}
|
||||
});
|
||||
|
||||
const selBlockers = (s: KilnState) => getBlockers(s.vats);
|
||||
export function useBlockers() {
|
||||
return useKilnState(selBlockers);
|
||||
const selPikes = (s: KilnState) => s.pikes;
|
||||
export function usePikes(): Pikes {
|
||||
return useKilnState(selPikes);
|
||||
}
|
||||
|
||||
export function useVat(desk: string): Vat | undefined {
|
||||
return useKilnState(useCallback((s) => s.vats[desk], [desk]));
|
||||
export function usePike(desk: string): Pike | undefined {
|
||||
return useKilnState(useCallback((s) => s.pikes[desk], [desk]));
|
||||
}
|
||||
|
||||
const selLag = (s: KilnState) => s.lag;
|
||||
|
@ -1,6 +1,4 @@
|
||||
import {
|
||||
Vat,
|
||||
Vats,
|
||||
Allies,
|
||||
Charges,
|
||||
DocketHrefGlob,
|
||||
@ -13,7 +11,8 @@ import {
|
||||
Contact,
|
||||
Contacts,
|
||||
Timebox,
|
||||
harkBinToId
|
||||
harkBinToId,
|
||||
Pikes
|
||||
} from '@urbit/api';
|
||||
import _ from 'lodash';
|
||||
import systemUrl from '../assets/system.png';
|
||||
@ -341,37 +340,35 @@ export const mockContacts: Contacts = {
|
||||
}
|
||||
};
|
||||
|
||||
export const mockVat = (desk: string, blockers?: boolean): Vat => ({
|
||||
cass: {
|
||||
da: '~2021.9.13..05.41.04..ae65',
|
||||
ud: 1
|
||||
export const mockPikes: Pikes = {
|
||||
kids: {
|
||||
sync: null,
|
||||
zest: 'dead',
|
||||
wefts: [],
|
||||
hash: '0v19.q7u27.omps3.fbhf4.53rai.co157.pben7.pu94n.63v4p.3kcb7.iafj0'
|
||||
},
|
||||
desk,
|
||||
arak: {
|
||||
rein: {
|
||||
sub: [],
|
||||
add: []
|
||||
garden: {
|
||||
sync: {
|
||||
desk: 'garden',
|
||||
ship: '~mister-dister-dozzod-dozzod'
|
||||
},
|
||||
rail:
|
||||
desk === 'uniswap'
|
||||
? null
|
||||
: {
|
||||
aeon: 3,
|
||||
desk,
|
||||
publisher: '~zod',
|
||||
next: blockers ? [{ aeon: 3, weft: { name: 'zuse', kelvin: 419 } }] : [],
|
||||
ship: '~zod',
|
||||
paused: desk === 'groups'
|
||||
}
|
||||
zest: 'live',
|
||||
wefts: [],
|
||||
hash: '0v18.hbbs6.onu15.skjkv.qrfgl.vf4oo.0igo5.2q0d3.6r3r8.2dkmo.oa04m'
|
||||
},
|
||||
hash: '0vh.lhfn6.julg1.fs52d.g2lqj.q5kp0.2o7j3.2bljl.jdm34.hd46v.9uv5v'
|
||||
});
|
||||
|
||||
const badVats = ['inbox', 'system', 'terminal', 'base'];
|
||||
export const mockVats = _.reduce(
|
||||
mockCharges,
|
||||
(vats, charge, desk) => {
|
||||
return { ...vats, [desk]: mockVat(desk, !badVats.includes(desk)) };
|
||||
landscape: {
|
||||
sync: {
|
||||
desk: 'landscape',
|
||||
ship: '~lander-dister-dozzod-dozzod'
|
||||
},
|
||||
zest: 'live',
|
||||
wefts: [],
|
||||
hash: '0v1t.qln8k.cskmt.cn6lv.gu335.jfba6.kte90.iqqn3.aj67b.t389a.8imuo'
|
||||
},
|
||||
{ base: mockVat('base', true) } as Vats
|
||||
);
|
||||
base: {
|
||||
sync: null,
|
||||
zest: 'live',
|
||||
wefts: [],
|
||||
hash: '0v1e.b5auh.6u82i.hqk1r.22kli.4ubef.a1cbo.3g532.6l49k.g0i8e.t6eid'
|
||||
}
|
||||
};
|
||||
|
@ -2,6 +2,16 @@ import { Docket, DocketHref, Treaty } from '@urbit/api';
|
||||
import { hsla, parseToHsla } from 'color2k';
|
||||
import _ from 'lodash';
|
||||
|
||||
export const useMockData = import.meta.env.MODE === 'mock';
|
||||
|
||||
export async function fakeRequest<T>(data: T, time = 300): Promise<T> {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(data);
|
||||
}, time);
|
||||
});
|
||||
}
|
||||
|
||||
export function getAppHref(href: DocketHref) {
|
||||
return 'site' in href ? href.site : `/apps/${href.glob.base}/`;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import { getAppHref } from '../state/util';
|
||||
import { useRecentsStore } from '../nav/search/Home';
|
||||
import { ChargeWithDesk } from '../state/docket';
|
||||
import { useTileColor } from './useTileColor';
|
||||
import { useVat } from '../state/kiln';
|
||||
import { usePike } from '../state/kiln';
|
||||
import { Bullet } from '../components/icons/Bullet';
|
||||
import { dragTypes } from './TileGrid';
|
||||
|
||||
@ -21,11 +21,12 @@ type TileProps = {
|
||||
export const Tile: FunctionComponent<TileProps> = ({ charge, desk, disabled = false }) => {
|
||||
const addRecentApp = useRecentsStore((state) => state.addRecentApp);
|
||||
const { title, image, color, chad, href } = charge;
|
||||
const vat = useVat(desk);
|
||||
const pike = usePike(desk);
|
||||
const { lightText, tileColor, menuColor, suspendColor, suspendMenuColor } = useTileColor(color);
|
||||
const loading = !disabled && 'install' in chad;
|
||||
const suspended = disabled || 'suspend' in chad;
|
||||
const hung = 'hung' in chad;
|
||||
// TODO should held zest be considered inactive? suspended? also, null sync?
|
||||
const active = !disabled && chadIsRunning(chad);
|
||||
const link = getAppHref(href);
|
||||
const backgroundColor = suspended ? suspendColor : active ? tileColor || 'purple' : suspendColor;
|
||||
@ -56,6 +57,9 @@ export const Tile: FunctionComponent<TileProps> = ({ charge, desk, disabled = fa
|
||||
>
|
||||
<div>
|
||||
<div className="absolute z-10 top-4 left-4 sm:top-6 sm:left-6 flex items-center">
|
||||
{pike?.zest === 'held' && !disabled && (
|
||||
<Bullet className="w-4 h-4 text-orange-500 dark:text-black" />
|
||||
)}
|
||||
{!active && (
|
||||
<>
|
||||
{loading && <Spinner className="h-6 w-6 mr-2" />}
|
||||
@ -65,9 +69,6 @@ export const Tile: FunctionComponent<TileProps> = ({ charge, desk, disabled = fa
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{vat?.arak.rail?.paused && !disabled && (
|
||||
<Bullet className="absolute z-10 top-5 left-5 sm:top-7 sm:left-7 w-4 h-4 text-orange-500 dark:text-black" />
|
||||
)}
|
||||
<TileMenu
|
||||
desk={desk}
|
||||
chad={chad}
|
||||
|
@ -3,13 +3,13 @@ import { useHistory, useParams } from 'react-router-dom';
|
||||
import { Dialog, DialogContent } from '../components/Dialog';
|
||||
import { AppInfo } from '../components/AppInfo';
|
||||
import { useCharge } from '../state/docket';
|
||||
import { useVat } from '../state/kiln';
|
||||
import { usePike } from '../state/kiln';
|
||||
|
||||
export const TileInfo = () => {
|
||||
const { desk } = useParams<{ desk: string }>();
|
||||
const { push } = useHistory();
|
||||
const charge = useCharge(desk);
|
||||
const vat = useVat(desk);
|
||||
const pike = usePike(desk);
|
||||
|
||||
if (!charge) {
|
||||
return null;
|
||||
@ -18,7 +18,7 @@ export const TileInfo = () => {
|
||||
return (
|
||||
<Dialog open onOpenChange={(open) => !open && push('/')}>
|
||||
<DialogContent>
|
||||
<AppInfo vat={vat} docket={charge} />
|
||||
<AppInfo pike={pike} docket={charge} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user