Merge remote-tracking branch 'origin/next/arvo' into philip/roller

This commit is contained in:
Philip Monk 2021-11-16 13:58:57 -08:00
commit a2a89d3532
No known key found for this signature in database
GPG Key ID: B66E1F02604E44EC
24 changed files with 233 additions and 235 deletions

View File

@ -1300,11 +1300,11 @@
~& [%failed-order-history fal.hit] ~& [%failed-order-history fal.hit]
this this
:: ::
:: install privkey and cert .pem from /=home=/acme, ignores app state :: install privkey and cert .pem from /=base=/acme, ignores app state
::TODO refactor this out of %acme, see also arvo#1151 ::TODO refactor this out of %acme, see also arvo#1151
:: ::
%install-from-clay %install-from-clay
=/ bas=path /(scot %p our.bow)/home/(scot %da now.bow)/acme =/ bas=path /(scot %p our.bow)/base/(scot %da now.bow)/acme
=/ key=wain .^(wain %cx (weld bas /privkey/pem)) =/ key=wain .^(wain %cx (weld bas /privkey/pem))
=/ cer=wain .^(wain %cx (weld bas /cert/pem)) =/ cer=wain .^(wain %cx (weld bas /cert/pem))
(emit %pass /install %arvo %e %rule %cert `[key cer]) (emit %pass /install %arvo %e %rule %cert `[key cer])

View File

@ -8,7 +8,13 @@
:: ::
:- %say :- %say
|= $: [now=@da eny=@uvJ bec=beak] |= $: [now=@da eny=@uvJ bec=beak]
[arg=[syd=desk lab=@tas ~] ~] [arg=[syd=desk lab=@tas ~] aeon=aeon:clay ~]
== ==
:: handle optional aeon
::
=/ aey=(unit aeon:clay)
?: =(0 aeon)
~
`aeon
:- %kiln-label :- %kiln-label
[syd lab]:arg [syd.arg lab.arg aey]

View File

@ -680,11 +680,11 @@
|= [kel=weft except=(set desk) force=?] |= [kel=weft except=(set desk) force=?]
^+ kiln ^+ kiln
=/ ded (find-blocked kel except) =/ ded (find-blocked kel except)
?: force =? kiln force (suspend-many ded)
=. kiln (suspend-many ded) ?: |(force =(~ ded))
(bump-many kel (all-desks-but (~(uni in except) ded))) ?: !=(zuse+zuse kel)
?: =(~ ded) (bump-one kel %base)
(bump-many kel (all-desks-but except)) (bump-many (all-desks-but (~(uni in except) ded)))
=- (^emit (pyre:pass leaf/- ~)) =- (^emit (pyre:pass leaf/- ~))
"kiln: desks blocked upgrade to {<zuse/zuse>}: {<ded>}" "kiln: desks blocked upgrade to {<zuse/zuse>}: {<ded>}"
:: ::
@ -704,7 +704,7 @@
$(ded t.ded, kiln abet:(suspend i.ded)) $(ded t.ded, kiln abet:(suspend i.ded))
:: ::
++ bump-many ++ bump-many
|= [kel=weft live=(set desk)] |= live=(set desk)
^+ kiln ^+ kiln
:: ensure %base is always reloaded first :: ensure %base is always reloaded first
:: ::
@ -718,7 +718,7 @@
:: ::
|- ^+ kiln |- ^+ kiln
?~ liv kiln ?~ liv kiln
$(liv t.liv, kiln (bump-one kel i.liv)) $(liv t.liv, kiln (bump-one zuse+zuse i.liv))
:: ::
++ bump-one ++ bump-one
|= [kel=weft =desk] |= [kel=weft =desk]
@ -733,7 +733,7 @@
?: =(kel u.kul) ?: =(kel u.kul)
~> %slog.(fmt "{here} already at {<[lal num]:kel>}") ~> %slog.(fmt "{here} already at {<[lal num]:kel>}")
update-running-dudes update-running-dudes
=^ tem rail.rak (crank-next %| kel) =^ tem rail.rak (crank-next kel)
?^ tem ?^ tem
(emit merge-main:pass) (emit merge-main:pass)
=- (emit (pyre:pass leaf/- ~)) =- (emit (pyre:pass leaf/- ~))
@ -861,7 +861,8 @@
++ kelvin-same ++ kelvin-same
^+ vats ^+ vats
~> %slog.(fmt "merging into {here}") ~> %slog.(fmt "merging into {here}")
=. rail.rak +:(crank-next %& (dec aeon:ral)) ?> ?=(^ rail.rak)
=. next.u.rail.rak ~
(emil ~[merge-main sync-ud]:pass) (emil ~[merge-main sync-ud]:pass)
:: ::
++ do-base ++ do-base
@ -878,7 +879,8 @@
=/ =diff [%block loc rak new-weft blockers] =/ =diff [%block loc rak new-weft blockers]
(emil sync-ud:pass (diff:give diff) ~) (emil sync-ud:pass (diff:give diff) ~)
~> %slog.(fmt "applying OTA to {here}, kelvin: {<new-weft>}") ~> %slog.(fmt "applying OTA to {here}, kelvin: {<new-weft>}")
=. rail.rak +:(crank-next %& (dec aeon:ral)) ?> ?=(^ rail.rak)
=. next.u.rail.rak ~
=. wef =. wef
?: =(old-weft new-weft) ~ ?: =(old-weft new-weft) ~
`new-weft `new-weft
@ -912,11 +914,7 @@
update-running-dudes update-running-dudes
?. =(%base loc) ?. =(%base loc)
kiln kiln
=/ kel=[@tas @ud] (bump-many (all-desks-but (get-unblockers ark)))
?~ rail.rak zuse/zuse
?~ next.u.rail.rak zuse/zuse
weft.i.next.u.rail.rak
(bump-many kel (all-desks-but (get-unblockers ark)))
:: ::
++ take-merge-main ++ take-merge-main
|= syn=sign-arvo |= syn=sign-arvo
@ -991,7 +989,7 @@
:: +crank-next: pop stale items from .next until one matches :: +crank-next: pop stale items from .next until one matches
:: ::
++ crank-next ++ crank-next
|= new=(each aeon weft) |= new=weft
^+ [match=*(unit rung) rail.rak] ^+ [match=*(unit rung) rail.rak]
?~ rail.rak ?~ rail.rak
~| [%no-rail-for desk=loc] ~| [%no-rail-for desk=loc]
@ -1000,10 +998,7 @@
=- [match `u.rail.rak(next next)] =- [match `u.rail.rak(next next)]
|- ^- [match=(unit rung) next=(list rung)] |- ^- [match=(unit rung) next=(list rung)]
?~ rog [~ next.u.rail.rak] ?~ rog [~ next.u.rail.rak]
?: ?- -.new ?: =(new weft.i.rog)
%& =(p.new aeon.i.rog)
%| =(p.new weft.i.rog)
==
[`i.rog t.rog] [`i.rog t.rog]
$(rog t.rog) $(rog t.rog)
:: ::
@ -1212,9 +1207,9 @@
abet:abet:(install:vats +<) abet:abet:(install:vats +<)
:: ::
++ poke-label ++ poke-label
|= [syd=desk lab=@tas] |= [syd=desk lab=@tas aey=(unit aeon)]
=+ pax=/(scot %p our)/[syd]/[lab] =+ pax=/(scot %p our)/[syd]/[lab]
(poke-info "labeled {(spud pax)}" `[syd %| lab]) (poke-info "labeled {(spud pax)}" `[syd %| lab aey])
:: ::
++ poke-merge ++ poke-merge
|= kiln-merge |= kiln-merge

View File

@ -1,5 +1,5 @@
|% |%
+$ bump [%kiln-bump except=(set desk) force=_|] +$ bump [except=(set desk) force=_|]
-- --
|_ b=bump |_ b=bump
++ grad %noun ++ grad %noun
@ -9,7 +9,6 @@
++ json ++ json
^- $-(^json bump) ^- $-(^json bump)
=, dejs:format =, dejs:format
%+ pe %kiln-bump
%- ot %- ot
:~ except+(as so) :~ except+(as so)
force+bo force+bo

View File

@ -5962,7 +5962,14 @@
++ spat |=(pax=path (crip (spud pax))) :: render path to cord ++ spat |=(pax=path (crip (spud pax))) :: render path to cord
++ spud |=(pax=path ~(ram re (smyt pax))) :: render path to tape ++ spud |=(pax=path ~(ram re (smyt pax))) :: render path to tape
++ stab |=(zep=@t `path`(rash zep stap)) :: parse cord to path ++ stab |=(zep=@t `path`(rash zep stap)) :: parse cord to path
++ stap ;~(pfix fas (more fas urs:ab)) :: path parser ++ stap :: path parser
%+ sear
|= p=path
^- (unit path)
?: ?=([~ ~] p) `~
?. =(~ (rear p)) `p
~
;~(pfix fas (most fas urs:ab))
:: ::
:::: 4n: virtualization :::: 4n: virtualization
:: ::
@ -9247,144 +9254,6 @@
hag [q.p.dix q.q.dix] hag [q.p.dix q.q.dix]
== ==
:: ::
++ ad
|%
++ arc
|%
++ deft :: generic
|%
++ bath * :: leg match type
++ claw * :: arm match type
++ form |*([* *] p=+<-) :: attach build state
++ skin |*(p=* p) :: reveal build state
++ meat |*(p=* p) :: remove build state
--
++ make :: for mint
|%
++ bath type :: leg match type
++ claw onyx :: arm
++ form |*([* *] [p=+<- q=+<+]) ::
++ skin |*([p=* q=*] q) :: unwrap baggage
++ meat |*([p=* q=*] p) :: unwrap filling
--
--
++ def
=+ deft:arc
|@ ++ $
=> +<
|%
++ pord |*(* (form +< *nock)) :: wrap mint formula
++ rosh |*(* (form +< *(list pock))) :: wrap mint changes
++ fleg _(pord $:bath) :: legmatch + code
++ fram _(pord $:claw) :: armmatch +
++ foat _(rosh $:bath) :: leg with changes
++ fult _(rosh $:claw) :: arm with changes
-- --
::
++ lib
|%
++ deft
=> (def deft:arc)
|%
++ halp ^|(|:($:hoon $:fleg))
++ vant
|% ++ trep ^|(|:($:,[bath wing bath] $:,[axis bath]))
++ tasp ^|(|:($:,[[axis bath] fleg foat] $:foat))
++ tyle ^|(|:($:foat $:foat))
--
++ vunt
|% ++ trep ^|(|:($:,[claw wing bath] $:,[axis claw]))
++ tasp ^|(|:($:,[[axis claw] fleg fult] $:fult))
++ tyle ^|(|:($:fult $:foat))
-- --
::
++ make
=> (def make:arc)
|%
++ halp |~ a=hoon
^- fleg
(mint %noun a)
++ vant
|% ++ trep |: $:,[a=type b=wing c=type]
^- [axis type]
(tack(sut a) b c)
++ tasp |: $:,[a=(pair axis type) b=fleg c=foat]
^- foat
[q.a [[p.a (skin b)] (skin c)]]
++ tyle |:($:foat +<)
--
++ vunt
|% ++ trep |: $:,[a=claw b=wing c=bath]
^- (pair axis claw)
(toss b c a)
++ tasp |: $:,[a=(pair axis claw) b=fleg c=fult]
^- fult
[q.a [[p.a (skin b)] (skin c)]]
++ tyle |: $:fult
^- foat
[(fire +<-) +<+]
-- -- --
::
++ bin
=+ deft:lib
|@ ++ $
=> +<
|%
++ rame
=> vant |%
++ clom bath
++ chog fleg
++ ceut foat
--
++ gelp
=> vunt |%
++ clom claw
++ chog fram
++ ceut fult
--
++ ecbo (ecco rame)
++ eclo (ecco gelp)
++ ecco
=+ rame
|@ ++ $
=> +<
|: $:,[rum=clom rig=(list (pair wing hoon))]
^- foat
%- tyle
|- ^- ceut
?~ rig (rosh rum)
=+ mor=$(rig t.rig)
=+ zil=(halp q.i.rig)
=+ dar=(trep (meat mor) p.i.rig (meat zil))
(tasp dar zil mor)
-- -- -- --
::
++ oc
=+ inc=(bin:ad)
|@ ++ $
=> inc
|%
++ echo
|: $:,[rum=bath rig=(list (pair wing hoon))]
(ecbo rum rig)
::
++ ecmo
|: $:,[hag=claw rig=(list (pair wing hoon))]
(eclo hag rig)
-- --
::
++ etco
|= [lop=palo rig=(list (pair wing hoon))]
^- (pair type nock)
=+ cin=(oc (bin:ad make:lib:ad))
=. rig (flop rig) :: XX this unbreaks, void order in devulc
=+ axe=(tend p.lop)
?: ?=(%& -.q.lop)
=- [p.- (hike axe q.-)]
(echo:cin p.q.lop rig)
=- [p.- [%9 p.q.lop (hike axe q.-)]]
(ecmo:cin ~(tap in q.q.lop) rig)
::
++ et ++ et
|_ [hyp=wing rig=(list (pair wing hoon))] |_ [hyp=wing rig=(list (pair wing hoon))]
:: ::
@ -9400,7 +9269,7 @@
=+ lug=(find %read hyp) =+ lug=(find %read hyp)
?: ?=(%| -.lug) ~>(%mean.'hoon' ?>(?=(~ rig) p.lug)) ?: ?=(%| -.lug) ~>(%mean.'hoon' ?>(?=(~ rig) p.lug))
=- ?>(?|(!vet (nest(sut gol) & p.-)) -) =- ?>(?|(!vet (nest(sut gol) & p.-)) -)
(etco p.lug rig) (ergo p.lug rig)
:: ::
++ mull ++ mull
|= [gol=type dox=type] |= [gol=type dox=type]
@ -10088,7 +9957,6 @@
[(nice %noun) [%2 q:$(gen p.gen, gol %noun) q:$(gen q.gen, gol %noun)]] [(nice %noun) [%2 q:$(gen p.gen, gol %noun) q:$(gen q.gen, gol %noun)]]
:: ::
[%dtts *] [%dtts *]
=+ [one two]=[$(gen p.gen, gol %noun) $(gen q.gen, gol %noun)]
[(nice bool) [%5 q:$(gen p.gen, gol %noun) q:$(gen q.gen, gol %noun)]] [(nice bool) [%5 q:$(gen p.gen, gol %noun) q:$(gen q.gen, gol %noun)]]
:: ::
[%dtwt *] [(nice bool) [%3 q:$(gen p.gen, gol %noun)]] [%dtwt *] [(nice bool) [%3 q:$(gen p.gen, gol %noun)]]

View File

@ -850,7 +850,7 @@
+$ mool [=case paths=(set (pair care path))] :: requests in desk +$ mool [=case paths=(set (pair care path))] :: requests in desk
+$ nori :: repository action +$ nori :: repository action
$% [%& p=soba] :: delta $% [%& p=soba] :: delta
[%| p=@tas] :: label [%| p=@tas q=(unit aeon)] :: label
== :: == ::
+$ nuri :: repository action +$ nuri :: repository action
$% [%& p=suba] :: delta $% [%& p=suba] :: delta
@ -1906,6 +1906,7 @@
[%private-keys ~] :: sub to privates [%private-keys ~] :: sub to privates
[%public-keys ships=(set ship)] :: sub to publics [%public-keys ships=(set ship)] :: sub to publics
[%rekey =life =ring] :: update private keys [%rekey =life =ring] :: update private keys
[%ruin ships=(set ship)] :: pretend breach
$>(%trim vane-task) :: trim state $>(%trim vane-task) :: trim state
[%turf ~] :: view domains [%turf ~] :: view domains
$>(%vega vane-task) :: report upgrade $>(%vega vane-task) :: report upgrade

View File

@ -1445,6 +1445,32 @@
== ==
== ==
:: ::
:: Attach label to aeon
::
++ label
|= [bel=@tas aey=(unit aeon)]
^+ ..park
=/ yon ?~(aey let.dom u.aey)
=/ yen (~(get by lab.dom) bel) :: existing aeon?
:: no existing aeon is bound to this label
::
?~ yen
=. lab.dom (~(put by lab.dom) bel yon)
..park
:: an aeon is bound to this label,
:: but it is the same as the existing one, so we no-op
::
?: =(u.yen yon)
~& "clay: tried to rebind existing label {<bel>} to equivalent aeon {<yon>}"
..park
:: an existing aeon bound to the label
:: that is distinct from the requested one.
:: rewriting would violate referential transparency
::
~| %tried-to-rewrite-existing-label
~| "requested aeon: {<yon>}, existing aeon: {<u.yen>}"
!!
::
:: Porcelain commit :: Porcelain commit
:: ::
++ info ++ info
@ -4374,8 +4400,12 @@
:: ::
%info %info
?: ?=(%| -.dit.req) ?: ?=(%| -.dit.req)
~| %labelling-not-implemented =/ bel=@tas p.dit.req
!! =/ aey=(unit aeon) q.dit.req
=^ mos ruf
=/ den ((de now rof hen ruf) our des.req)
abet:(label:den bel aey)
[mos ..^$]
=/ [deletes=(set path) changes=(map path cage)] =/ [deletes=(set path) changes=(map path cage)]
=/ =soba p.dit.req =/ =soba p.dit.req
=| deletes=(set path) =| deletes=(set path)

View File

@ -482,6 +482,7 @@
:: [%trim p=@ud] :: [%trim p=@ud]
:: ::
%trim %trim
::TODO consider %ruin-ing long-offline comets
+>.$ +>.$
:: ::
:: watch private keys :: watch private keys
@ -514,6 +515,20 @@
=. moz [[hen %give %done ~] moz] =. moz [[hen %give %done ~] moz]
$(tac message) $(tac message)
== ==
::
:: pretend ships breached
:: [%ruin ships=(set ship)]
::
%ruin
::NOTE we blast this out to _all_ known ducts, because the common
:: use case for this is comets, about who nobody cares.
=/ dus ~(key by yen.zim.pki)
=/ sus ~(. su hen now pki etn)
=/ sis ~(tap in ships.tac)
|-
?~ sis (curd abet:sus)
=. sus (exec:sus dus %give %public-keys %breach i.sis)
$(sis t.sis)
== ==
:: ::
++ take ++ take

View File

@ -4910,13 +4910,20 @@
++ cite :: render ship ++ cite :: render ship
|= who=@p |= who=@p
^- tape ^- tape
=+ kind=(clan who) =/ wid (met 4 who)
=+ name=(scow %p who) ?: (lte wid 2) (scow %p who)
?: =(%earl kind) ?: (lte wid 4)
:(weld "~" (swag [15 6] name) "^" (swag [22 6] name)) =/ nom (scow %p (end 5 who))
?: =(%pawn kind) :(weld (scag 7 nom) "^" (slag 8 nom))
:(weld (swag [0 7] name) "_" (swag [51 6] name)) %- trip
name %+ rap 3
:~ '~'
(tos:po (cut 3 [(dec (mul wid 2)) 1] who))
(tod:po (cut 3 [(mul (dec wid) 2) 1] who))
'_'
(tos:po (cut 3 [1 1] who))
(tod:po (end 3 who))
==
:: :: ++saxo:title :: :: ++saxo:title
++ saxo :: autocanon ++ saxo :: autocanon
|= [our=ship now=@da who=ship] |= [our=ship now=@da who=ship]

View File

@ -0,0 +1,28 @@
:: tests for |title
::
/+ *test
=, title
|%
++ test-cite
;: weld
%+ expect-eq
!> "~zod^"
!> (cite ~dister-dozzod-dozzod)
::
%+ expect-eq
!> "~marzod^"
!> (cite ~dister-dozzod-marzod)
::
%+ expect-eq
!> "~palfun^foslup"
!> (cite ~littel-palfun-foslup)
::
%+ expect-eq
!> "~palfun^foslup"
!> (cite ~littel-bittel-palfun-foslup)
::
%+ expect-eq
!> "~sampel_sampel"
!> (cite ~sampel--dozzod-dozzod-dozzod-sampel)
==
--

View File

@ -1,5 +0,0 @@
:~ :- %apes
~
:- %fish
~
==

View File

@ -1 +1 @@
[%zuse 420] [%zuse 419]

View File

@ -1,10 +1,10 @@
:~ title+'System' :~ title+'System'
info+'An app launcher for Urbit.' info+'An app launcher for Urbit.'
color+0xee.5432 color+0xee.5432
glob-http+['https://bootstrap.urbit.org/glob-0v5.fdf99.nph65.qecq3.ncpjn.q13mb.glob' 0v5.fdf99.nph65.qecq3.ncpjn.q13mb] glob-http+['https://bootstrap.urbit.org/glob-0v4.64ana.19ug9.ik7l6.og080.68ce4.glob' 0v4.64ana.19ug9.ik7l6.og080.68ce4]
::glob-ames+~zod^0v0 ::glob-ames+~zod^0v0
base+'grid' base+'grid'
version+[1 0 1] version+[1 0 2]
website+'https://tlon.io' website+'https://tlon.io'
license+'MIT' license+'MIT'
== ==

View File

@ -1 +1 @@
[%zuse 420] [%zuse 419]

View File

@ -49,8 +49,6 @@ const AppRoutes = () => {
} }
}, [isDarkMode, theme]); }, [isDarkMode, theme]);
useEffect(() => {}, []);
useEffect( useEffect(
handleError(() => { handleError(() => {
window.name = 'grid'; window.name = 'grid';

View File

@ -227,6 +227,7 @@ export const Leap = React.forwardRef(
[selection, rawInput, match, matches, selectedMatch] [selection, rawInput, match, matches, selectedMatch]
); );
return ( return (
<div className="relative z-50 w-full"> <div className="relative z-50 w-full">
<form <form
@ -234,6 +235,7 @@ export const Leap = React.forwardRef(
'flex items-center h-full w-full px-2 rounded-full bg-white default-ring focus-within:ring-2', 'flex items-center h-full w-full px-2 rounded-full bg-white default-ring focus-within:ring-2',
shouldDim && 'opacity-60', shouldDim && 'opacity-60',
!navOpen ? 'bg-gray-50' : '', !navOpen ? 'bg-gray-50' : '',
menu === 'upgrading' ? 'bg-orange-500' : '',
className className
)} )}
onSubmit={onSubmit} onSubmit={onSubmit}
@ -241,28 +243,32 @@ export const Leap = React.forwardRef(
<label <label
htmlFor="leap" htmlFor="leap"
className={classNames( className={classNames(
'inline-block flex-none p-2 h4 text-blue-400', 'inline-block flex-none p-2 h4 ',
!selection && 'sr-only' menu === 'upgrading' ? 'text-white' : !selection ? 'sr-only' : 'text-blue-400'
)} )}
> >
{selection || 'Search'} {menu === 'upgrading'
? 'Your Urbit is being updated, this page will update when ready'
: selection || 'Search'}
</label> </label>
<input {menu !== 'upgrading' ? (
id="leap" <input
type="text" id="leap"
ref={inputRef} type="text"
placeholder={selection ? '' : 'Search'} ref={inputRef}
className="flex-1 w-full h-full px-2 h4 text-base rounded-full bg-transparent outline-none" placeholder={selection ? '' : 'Search'}
value={rawInput} className="flex-1 w-full h-full px-2 h4 text-base rounded-full bg-transparent outline-none"
onClick={toggleSearch} value={rawInput}
onFocus={onFocus} onClick={toggleSearch}
onChange={onChange} onFocus={onFocus}
onKeyDown={onKeyDown} onChange={onChange}
autoComplete="off" onKeyDown={onKeyDown}
aria-autocomplete="both" autoComplete="off"
aria-controls={dropdown} aria-autocomplete="both"
aria-activedescendant={selectedMatch?.display || selectedMatch?.value} aria-controls={dropdown}
/> aria-activedescendant={selectedMatch?.display || selectedMatch?.value}
/>
) : null}
</form> </form>
{menu === 'search' && ( {menu === 'search' && (
<Link <Link

View File

@ -52,7 +52,8 @@ export type MenuState =
| 'search' | 'search'
| 'notifications' | 'notifications'
| 'help-and-support' | 'help-and-support'
| 'system-preferences'; | 'system-preferences'
| 'upgrading';
interface NavProps { interface NavProps {
menu?: MenuState; menu?: MenuState;
@ -68,7 +69,7 @@ export const Nav: FunctionComponent<NavProps> = ({ menu }) => {
const select = useLeapStore((state) => state.select); const select = useLeapStore((state) => state.select);
const menuState = menu || 'closed'; const menuState = menu || 'closed';
const isOpen = menuState !== 'closed'; const isOpen = menuState !== 'upgrading' && menuState !== 'closed';
const eitherOpen = isOpen || systemMenuOpen; const eitherOpen = isOpen || systemMenuOpen;
useEffect(() => { useEffect(() => {

View File

@ -12,7 +12,7 @@ function renderNotification(notification: Notification, key: string, lid: HarkLi
if (notification.bin.place.path === '/lag') { if (notification.bin.place.path === '/lag') {
return <RuntimeLagNotification key={key} />; return <RuntimeLagNotification key={key} />;
} }
if (notification.bin.place.path === '/blocked') { if (notification.bin.path === '/blocked' && notification.bin.place.path === '/desk/base') {
return <BaseBlockedNotification key={key} />; return <BaseBlockedNotification key={key} />;
} }
if (notification.bin.place.path === '/onboard') { if (notification.bin.place.path === '/onboard') {

View File

@ -1,4 +1,4 @@
import { pick } from 'lodash'; import { pick, pickBy, partition } from 'lodash';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { kilnBump } from '@urbit/api/hood'; import { kilnBump } from '@urbit/api/hood';
import { AppList } from '../../components/AppList'; import { AppList } from '../../components/AppList';
@ -7,9 +7,12 @@ import { Dialog, DialogClose, DialogContent, DialogTrigger } from '../../compone
import { Elbow } from '../../components/icons/Elbow'; import { Elbow } from '../../components/icons/Elbow';
import api from '../../state/api'; import api from '../../state/api';
import { useCharges } from '../../state/docket'; import { useCharges } from '../../state/docket';
import useKilnState, { useVat } from '../../state/kiln';
import { NotificationButton } from './NotificationButton'; import { NotificationButton } from './NotificationButton';
import { disableDefault } from '../../state/util'; import { disableDefault } from '../../state/util';
import { Vat } from '@urbit/api';
import {useHistory} from 'react-router-dom';
export const RuntimeLagNotification = () => ( export const RuntimeLagNotification = () => (
<section <section
@ -35,16 +38,29 @@ export const RuntimeLagNotification = () => (
</section> </section>
); );
function vatIsBlocked(newKelvin: number, vat: Vat) {
return !(vat.arak?.rail?.next || []).find(({ aeon, weft }) => weft.kelvin === newKelvin);
}
export const BaseBlockedNotification = () => { export const BaseBlockedNotification = () => {
const desks: string[] = []; const base = useVat('base');
const { push } = useHistory();
// TODO: assert weft.name === 'zuse'??
const newKelvin = base?.arak?.rail?.next?.[0]?.weft?.kelvin || 420;
const charges = useCharges(); const charges = useCharges();
const blockedCharges = Object.values(pick(charges, desks)); const [blocked, unblocked] = useKilnState((s) => {
const [b, u] = partition(Object.entries(s.vats), ([desk, vat]) => vatIsBlocked(newKelvin, vat));
return [b.map(([d]) => d), u.map(([d]) => d)] as const;
});
const blockedCharges = Object.values(pick(charges, blocked));
const count = blockedCharges.length; const count = blockedCharges.length;
const handlePauseOTAs = useCallback(() => {}, []); const handlePauseOTAs = useCallback(() => {}, []);
const handleArchiveApps = useCallback(async () => { const handleArchiveApps = useCallback(async () => {
api.poke(kilnBump(true)); api.poke(kilnBump(true));
push('/leap/upgrading');
}, []); }, []);
return ( return (

View File

@ -1,27 +1,51 @@
import { map, omit } from 'lodash'; import { map, omit } from 'lodash';
import React, { FunctionComponent } from 'react'; import React, { FunctionComponent, useEffect } from 'react';
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
import { Route, RouteComponentProps } from 'react-router-dom'; import { Route, RouteComponentProps, useHistory, useParams } from 'react-router-dom';
import { ErrorAlert } from '../components/ErrorAlert'; import { ErrorAlert } from '../components/ErrorAlert';
import { MenuState, Nav } from '../nav/Nav'; import { MenuState, Nav } from '../nav/Nav';
import { useCharges } from '../state/docket'; import { useCharges } from '../state/docket';
import useKilnState from '../state/kiln';
import { RemoveApp } from '../tiles/RemoveApp'; import { RemoveApp } from '../tiles/RemoveApp';
import { SuspendApp } from '../tiles/SuspendApp'; import { SuspendApp } from '../tiles/SuspendApp';
import { Tile } from '../tiles/Tile'; import { Tile } from '../tiles/Tile';
import { TileInfo } from '../tiles/TileInfo'; import { TileInfo } from '../tiles/TileInfo';
type GridProps = RouteComponentProps<{ interface RouteProps {
menu?: MenuState; menu?: MenuState;
}>; }
export const Grid: FunctionComponent<GridProps> = ({ match, history }) => { export const Grid: FunctionComponent<{}> = () => {
const charges = useCharges(); const charges = useCharges();
const { push } = useHistory();
const { menu } = useParams<RouteProps>();
const chargesLoaded = Object.keys(charges).length > 0; const chargesLoaded = Object.keys(charges).length > 0;
useEffect(() => {
// TOOD: rework
// Heuristically detect reload completion and redirect
async function attempt(count = 0) {
if(count > 5) {
window.location.reload();
}
const start = performance.now();
await useKilnState.getState().fetchVats();
await useKilnState.getState().fetchVats();
if((performance.now() - start) > 5000) {
attempt(count+1);
} else {
push('/');
}
}
if(menu === 'upgrading') {
attempt();
}
}, [menu])
return ( return (
<div className="flex flex-col"> <div className="flex flex-col">
<header className="fixed sm:sticky bottom-0 sm:bottom-auto sm:top-0 left-0 z-30 flex justify-center w-full px-4"> <header className="fixed sm:sticky bottom-0 sm:bottom-auto sm:top-0 left-0 z-30 flex justify-center w-full px-4">
<Nav menu={match.params.menu} /> <Nav menu={menu} />
</header> </header>
<main className="h-full w-full flex justify-center pt-4 md:pt-16 pb-32 relative z-0"> <main className="h-full w-full flex justify-center pt-4 md:pt-16 pb-32 relative z-0">
@ -30,11 +54,11 @@ export const Grid: FunctionComponent<GridProps> = ({ match, history }) => {
<div className="grid justify-center grid-cols-2 sm:grid-cols-[repeat(auto-fit,minmax(auto,250px))] gap-4 px-4 md:px-8 w-full max-w-6xl"> <div className="grid justify-center grid-cols-2 sm:grid-cols-[repeat(auto-fit,minmax(auto,250px))] gap-4 px-4 md:px-8 w-full max-w-6xl">
{charges && {charges &&
map(omit(charges, window.desk), (charge, desk) => ( map(omit(charges, window.desk), (charge, desk) => (
<Tile key={desk} charge={charge} desk={desk} /> <Tile key={desk} charge={charge} desk={desk} disabled={menu === 'upgrading'} />
))} ))}
</div> </div>
)} )}
<ErrorBoundary FallbackComponent={ErrorAlert} onReset={() => history.push('/')}> <ErrorBoundary FallbackComponent={ErrorAlert} onReset={() => push('/')}>
<Route exact path="/app/:desk"> <Route exact path="/app/:desk">
<TileInfo /> <TileInfo />
</Route> </Route>

View File

@ -241,7 +241,17 @@ function createMockSysNotification(path: string, body: HarkBody[] = []) {
} }
const lag = createMockSysNotification('/lag'); const lag = createMockSysNotification('/lag');
const blocked = createMockSysNotification('/blocked'); const blocked = {
bin: {
place: {
desk: window.desk,
path: '/desk/base'
},
path: '/blocked'
},
time: Date.now() - 3_600,
body: []
};
const onboard = createMockSysNotification('/onboard'); const onboard = createMockSysNotification('/onboard');
const updateNotification = createMockSysNotification('/desk/bitcoin', [ const updateNotification = createMockSysNotification('/desk/bitcoin', [

View File

@ -13,19 +13,20 @@ import { Bullet } from '../components/icons/Bullet';
type TileProps = { type TileProps = {
charge: ChargeWithDesk; charge: ChargeWithDesk;
desk: string; desk: string;
disabled?: boolean;
}; };
export const Tile: FunctionComponent<TileProps> = ({ charge, desk }) => { export const Tile: FunctionComponent<TileProps> = ({ charge, desk, disabled = false }) => {
const addRecentApp = useRecentsStore((state) => state.addRecentApp); const addRecentApp = useRecentsStore((state) => state.addRecentApp);
const { title, image, color, chad, href } = charge; const { title, image, color, chad, href } = charge;
const vat = useVat(desk); const vat = useVat(desk);
const { lightText, tileColor, menuColor, suspendColor, suspendMenuColor } = useTileColor(color); const { lightText, tileColor, menuColor, suspendColor, suspendMenuColor } = useTileColor(color);
const loading = 'install' in chad; const loading = !disabled && 'install' in chad;
const suspended = 'suspend' in chad; const suspended = disabled || 'suspend' in chad;
const hung = 'hung' in chad; const hung = 'hung' in chad;
const active = chadIsRunning(chad); const active = !disabled && chadIsRunning(chad);
const link = getAppHref(href); const link = getAppHref(href);
const backgroundColor = active ? tileColor || 'purple' : suspendColor; const backgroundColor = suspended ? suspendColor : active ? tileColor || 'purple' : suspendColor;
return ( return (
<a <a
@ -47,14 +48,12 @@ export const Tile: FunctionComponent<TileProps> = ({ charge, desk }) => {
<> <>
{loading && <Spinner className="h-6 w-6 mr-2" />} {loading && <Spinner className="h-6 w-6 mr-2" />}
<span className="text-gray-500"> <span className="text-gray-500">
{suspended && 'Suspended'} {suspended ? 'Suspended' : loading ? 'Installing' : hung ? 'Errored' : null }
{loading && 'Installing'}
{hung && 'Errored'}
</span> </span>
</> </>
)} )}
</div> </div>
{vat?.arak.rail?.paused && ( {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" /> <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 <TileMenu

View File

@ -1 +1 @@
[%zuse 420] [%zuse 419]

View File

@ -1 +1 @@
[%zuse 420] [%zuse 419]