mirror of
https://github.com/urbit/shrub.git
synced 2024-12-18 15:55:00 +03:00
Merge remote-tracking branch 'upstream/master' into better-bar-fuse
This commit is contained in:
commit
5698e2662a
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1,3 +1,4 @@
|
||||
bin/* filter=lfs diff=lfs merge=lfs -text
|
||||
bin/*/* filter=lfs diff=lfs merge=lfs -text
|
||||
pkg/arvo/**/*.css binary
|
||||
**/package-lock.json binary merge=theirs
|
||||
|
2
.github/actions/glob/Dockerfile
vendored
2
.github/actions/glob/Dockerfile
vendored
@ -1,4 +1,4 @@
|
||||
FROM jaredtobin/janeway:v0.15.2
|
||||
FROM jaredtobin/janeway:v0.15.3.1
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
EXPOSE 22/tcp
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
4
.github/workflows/glob.yml
vendored
4
.github/workflows/glob.yml
vendored
@ -6,14 +6,14 @@ on:
|
||||
jobs:
|
||||
glob:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Create and deploy a glob to ~lomlyx-lopsem-nidsut-tomdun"
|
||||
name: "Create and deploy a glob to ~hanruc-nalfus-nidsut-tomdun"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
lfs: true
|
||||
- uses: ./.github/actions/glob
|
||||
with:
|
||||
ship: 'lomlyx-lopsem-nidsut-tomdun'
|
||||
ship: 'hanruc-nalfus-nidsut-tomdun'
|
||||
credentials: ${{ secrets.JANEWAY_SERVICE_KEY }}
|
||||
ssh-sec-key: ${{ secrets.JANEWAY_SSH_SEC_KEY }}
|
||||
ssh-pub-key: ${{ secrets.JANEWAY_SSH_PUB_KEY }}
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:61e583dd7db795dac4a7c31bfd3ee8b240e679bb882e35d4e7d1acb5f9f2f3d6
|
||||
size 8270131
|
||||
oid sha256:e0af91e5c51359719aaa943f37a1e953989c786412616b18fbaa0addb2cf0740
|
||||
size 10272514
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:185ea5e76dc48695e55efc543377e0682e485f81b16e3b443f9be881d026d4f2
|
||||
size 2616564
|
||||
oid sha256:23d8235b19a3404e0bfbed54aa56a018255beb1f33457e37f521bc0763b4d0eb
|
||||
size 6245506
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:28c1ce6409721365a8c24d77af767550bb6596260833af21fa96964b740b3cf8
|
||||
size 12381649
|
||||
oid sha256:e0c05655f47ff81c8d4985a061d3ff57526a436adf25f667432a48c5cd10d438
|
||||
size 12190347
|
||||
|
@ -85,8 +85,7 @@
|
||||
::
|
||||
?> ?=([%clients *] pax)
|
||||
?. (is-whitelisted:hc src.bowl)
|
||||
~& >>> "btc-provider: blocked client {<src.bowl>}"
|
||||
[~[[%give %kick ~ ~]] this]
|
||||
~|("btc-provider: blocked client {<src.bowl>}" !!)
|
||||
~& > "btc-provider: accepted client {<src.bowl>}"
|
||||
:- [do-ping:hc]~
|
||||
this(clients.host-info (~(put in clients.host-info) src.bowl))
|
||||
@ -195,6 +194,9 @@
|
||||
::
|
||||
%ping
|
||||
[%get-block-info ~]
|
||||
::
|
||||
%block-info
|
||||
[%get-block-info block.act]
|
||||
==
|
||||
[~[(req-card act ract)] state]
|
||||
::
|
||||
@ -284,6 +286,11 @@
|
||||
?: =(block.host-info block.r)
|
||||
~[(send-status [%connected network.host-info block.r fee.r])]
|
||||
~[(send-status [%new-block network.host-info block.r fee.r blockhash.r blockfilter.r])]
|
||||
::
|
||||
%block-info
|
||||
?> ?=([%get-block-info *] r)
|
||||
:_ state
|
||||
~[(send-update [%.y %block-info network.host-info +.r])]
|
||||
==
|
||||
::
|
||||
++ send-status
|
||||
|
@ -167,13 +167,20 @@
|
||||
|= [=wire =sign:agent:gall]
|
||||
^- (quip card _this)
|
||||
?+ -.sign (on-agent:def wire sign)
|
||||
%watch-ack
|
||||
?~ p.sign `this
|
||||
%- (slog leaf+"connection rejected by provider ({<src.bowl>})" u.p.sign)
|
||||
`this
|
||||
::
|
||||
%kick
|
||||
~& >>> "kicked from prov {<src.bowl>}"
|
||||
?~ prov `this
|
||||
?: ?& ?=(%set-provider -.wire)
|
||||
=(host.u.prov src.bowl)
|
||||
==
|
||||
`this(prov ~)
|
||||
:_ this(prov [~ src.bowl %.n])
|
||||
:~ (watch-provider src.bowl)
|
||||
(give-update %change-provider `[src.bowl %.n])
|
||||
==
|
||||
`this
|
||||
::
|
||||
%fact
|
||||
@ -238,7 +245,6 @@
|
||||
?> (team:title our.bowl src.bowl)
|
||||
?- -.comm
|
||||
%set-provider
|
||||
|^
|
||||
?~ provider.comm
|
||||
?~ prov `state
|
||||
:_ state(prov ~)
|
||||
@ -252,20 +258,6 @@
|
||||
(watch-provider u.provider.comm)
|
||||
(give-update %change-provider `[u.provider.comm %.n])
|
||||
==
|
||||
::
|
||||
++ watch-provider
|
||||
|= who=@p
|
||||
^- card
|
||||
:* %pass /set-provider/[(scot %p who)] %agent [who %btc-provider]
|
||||
%watch /clients
|
||||
==
|
||||
++ leave-provider
|
||||
|= who=@p
|
||||
^- card
|
||||
:* %pass /set-provider/[(scot %p who)] %agent [who %btc-provider]
|
||||
%leave ~
|
||||
==
|
||||
--
|
||||
::
|
||||
%check-provider
|
||||
=/ pax /permitted/(scot %p provider.comm)
|
||||
@ -685,7 +677,6 @@
|
||||
++ handle-provider-status
|
||||
|= s=status:bp
|
||||
^- (quip card _state)
|
||||
|^
|
||||
=^ cards state
|
||||
?~ prov `state
|
||||
?. =(host.u.prov src.bowl) `state
|
||||
@ -704,102 +695,146 @@
|
||||
(give-update %change-provider prov)
|
||||
cards
|
||||
==
|
||||
::
|
||||
++ on-connected
|
||||
|= $: p=provider
|
||||
=network
|
||||
block=@ud
|
||||
fee=(unit sats)
|
||||
blockhash=(unit hexb)
|
||||
blockfilter=(unit hexb)
|
||||
==
|
||||
^- (quip card _state)
|
||||
:_ %_ state
|
||||
prov `p(connected %.y)
|
||||
btc-state [block fee now.bowl]
|
||||
==
|
||||
?: ?|(?!(connected.p) (lth block.btc-state block))
|
||||
;: weld
|
||||
(retry-pend-piym network)
|
||||
(retry-poym network)
|
||||
(retry-addrs network)
|
||||
(retry-txs network)
|
||||
(retry-scans network)
|
||||
retry-ahistorical-txs
|
||||
::
|
||||
++ on-connected
|
||||
|= $: p=provider
|
||||
=network
|
||||
block=@ud
|
||||
fee=(unit sats)
|
||||
blockhash=(unit hexb)
|
||||
blockfilter=(unit hexb)
|
||||
==
|
||||
^- (quip card _state)
|
||||
:: request block-info for missing blocks
|
||||
:: if blockhash or blockfilter are ~ request block-info for current block
|
||||
::
|
||||
=| blocks=(list @ud)
|
||||
=/ gap (sub block block.btc-state)
|
||||
=? blocks (gth gap 1)
|
||||
(gulf +(block.btc-state) (dec block))
|
||||
=? blocks ?|(?=(~ blockhash) ?=(~ blockfilter))
|
||||
(snoc blocks block)
|
||||
=? blocks (gth gap 50) ~
|
||||
::
|
||||
=/ cards=(list card)
|
||||
;: weld
|
||||
:: (retry-addrs network)
|
||||
retry-ahistorical-txs
|
||||
(retry-pend-piym network)
|
||||
(retry-block-info blocks)
|
||||
==
|
||||
::
|
||||
++ retry-ahistorical-txs
|
||||
^- (list card)
|
||||
%+ turn ~(tap in ahistorical-txs)
|
||||
|= =txid
|
||||
(poke-provider [%tx-info txid])
|
||||
|
||||
::
|
||||
++ retry-scans
|
||||
|= =network
|
||||
^- (list card)
|
||||
%- zing
|
||||
%+ murn ~(tap by scans)
|
||||
|= [[=xpub:bc =chyg] =batch]
|
||||
?. =(network network:(~(got by walts) xpub)) ~
|
||||
`-:(req-scan batch xpub chyg)
|
||||
:: +retry-addrs: get info on addresses with unconfirmed UTXOs
|
||||
::
|
||||
++ retry-addrs
|
||||
|= =network
|
||||
^- (list card)
|
||||
%- zing
|
||||
%+ murn ~(val by walts)
|
||||
|= w=walt
|
||||
?. =(network network.w) ~
|
||||
^- (unit (list card))
|
||||
:- ~
|
||||
%+ turn ~(tap by wach.w)
|
||||
|= [a=address *]
|
||||
(poke-provider [%address-info a])
|
||||
:: +retry-txs: get info on txs without enough confirmations
|
||||
::
|
||||
++ retry-txs
|
||||
|= =network
|
||||
^- (list card)
|
||||
%+ murn ~(tap by history)
|
||||
|= [=txid =hest]
|
||||
=/ w (~(get by walts) xpub.hest)
|
||||
?~ w ~
|
||||
?. =(network network.u.w) ~
|
||||
?: (gte confs.hest confs.u.w) ~
|
||||
`(poke-provider [%tx-info txid])
|
||||
::
|
||||
++ retry-poym
|
||||
|= =network
|
||||
^- (list card)
|
||||
?~ txbu.poym ~
|
||||
=/ w (~(get by walts) xpub.u.txbu.poym)
|
||||
?~ w ~
|
||||
?. =(network network.u.w) ~
|
||||
%+ weld
|
||||
?~ signed-tx.u.txbu.poym ~
|
||||
~[(poke-provider [%broadcast-tx u.signed-tx.u.txbu.poym])]
|
||||
%+ turn txis.u.txbu.poym
|
||||
|= =txi
|
||||
(poke-provider [%raw-tx ~(get-txid txb:bl u.txbu.poym)])
|
||||
:: +retry-pend-piym: check whether txids in pend-piym are in mempool
|
||||
::
|
||||
++ retry-pend-piym
|
||||
|= =network
|
||||
^- (list card)
|
||||
%+ murn ~(tap by pend.piym)
|
||||
|= [=txid p=payment]
|
||||
=/ w (~(get by walts) xpub.p)
|
||||
?~ w ~
|
||||
?. =(network network.u.w) ~
|
||||
`(poke-provider [%tx-info txid])
|
||||
--
|
||||
=? cards ?|(!connected.p (gth gap 0))
|
||||
;: weld cards
|
||||
(retry-poym network)
|
||||
(retry-txs network)
|
||||
(retry-scans network)
|
||||
==
|
||||
=? cards ?&(?=(^ blockhash) ?=(^ blockfilter) (gth gap 0))
|
||||
(weld cards (retry-filtered-addrs network u.blockhash u.blockfilter))
|
||||
=? cards (gth gap 50)
|
||||
(weld cards (retry-addrs network))
|
||||
:- cards
|
||||
%_ state
|
||||
prov `p(connected %.y)
|
||||
btc-state [block fee now.bowl]
|
||||
==
|
||||
::
|
||||
++ retry-block-info
|
||||
|= blocks=(list @ud)
|
||||
%+ turn blocks
|
||||
|= block=@ud
|
||||
(poke-provider %block-info `block)
|
||||
::
|
||||
++ retry-ahistorical-txs
|
||||
^- (list card)
|
||||
%+ turn ~(tap in ahistorical-txs)
|
||||
|= =txid
|
||||
(poke-provider [%tx-info txid])
|
||||
::
|
||||
++ retry-scans
|
||||
|= =network
|
||||
^- (list card)
|
||||
%- zing
|
||||
%+ murn ~(tap by scans)
|
||||
|= [[=xpub:bc =chyg] =batch]
|
||||
=/ w (~(get by walts) xpub)
|
||||
?~ w ~
|
||||
?. =(network network.u.w) ~
|
||||
`-:(req-scan batch xpub chyg)
|
||||
:: +retry-addrs: get info on addresses with unconfirmed UTXOs
|
||||
::
|
||||
++ retry-addrs
|
||||
|= =network
|
||||
^- (list card)
|
||||
%- zing
|
||||
%+ murn ~(val by walts)
|
||||
|= w=walt
|
||||
?. =(network network.w) ~
|
||||
^- (unit (list card))
|
||||
:- ~
|
||||
%+ turn ~(tap by wach.w)
|
||||
|= [a=address *]
|
||||
(poke-provider [%address-info a])
|
||||
::
|
||||
::
|
||||
++ retry-filtered-addrs
|
||||
|= [=network blockhash=hexb blockfilter=hexb]
|
||||
^- (list card)
|
||||
%- zing
|
||||
%+ murn ~(val by walts)
|
||||
|= w=walt
|
||||
^- (unit (list card))
|
||||
?. =(network network.w) ~
|
||||
:- ~
|
||||
%+ murn
|
||||
%~ tap in
|
||||
%: all-match:bip-b158:bc
|
||||
blockfilter
|
||||
blockhash
|
||||
::
|
||||
%+ turn ~(tap by wach.w)
|
||||
|= [a=address *]
|
||||
[a (to-script-pubkey:adr:bc a)]
|
||||
==
|
||||
|= [a=address spk=hexb]
|
||||
^- (unit card)
|
||||
`(poke-provider [%address-info a])
|
||||
:: +retry-txs: get info on txs without enough confirmations
|
||||
::
|
||||
++ retry-txs
|
||||
|= =network
|
||||
^- (list card)
|
||||
%+ murn ~(tap by history)
|
||||
|= [=txid =hest]
|
||||
=/ w (~(get by walts) xpub.hest)
|
||||
?~ w ~
|
||||
?. =(network network.u.w) ~
|
||||
?: (gte confs.hest confs.u.w) ~
|
||||
`(poke-provider [%tx-info txid])
|
||||
::
|
||||
++ retry-poym
|
||||
|= =network
|
||||
^- (list card)
|
||||
?~ txbu.poym ~
|
||||
=/ w (~(get by walts) xpub.u.txbu.poym)
|
||||
?~ w ~
|
||||
?. =(network network.u.w) ~
|
||||
%+ weld
|
||||
?~ signed-tx.u.txbu.poym ~
|
||||
~[(poke-provider [%broadcast-tx u.signed-tx.u.txbu.poym])]
|
||||
%+ turn txis.u.txbu.poym
|
||||
|= =txi
|
||||
(poke-provider [%raw-tx ~(get-txid txb:bl u.txbu.poym)])
|
||||
:: +retry-pend-piym: check whether txids in pend-piym are in mempool
|
||||
::
|
||||
++ retry-pend-piym
|
||||
|= =network
|
||||
^- (list card)
|
||||
%+ murn ~(tap by pend.piym)
|
||||
|= [=txid p=payment]
|
||||
=/ w (~(get by walts) xpub.p)
|
||||
?~ w ~
|
||||
?. =(network network.u.w) ~
|
||||
`(poke-provider [%tx-info txid])
|
||||
::
|
||||
++ handle-provider-update
|
||||
|= upd=update:bp
|
||||
@ -833,6 +868,10 @@
|
||||
:~ (poke-internal [%fail-broadcast-tx txid.p.upd])
|
||||
(give-update %cancel-tx txid.p.upd)
|
||||
==
|
||||
::
|
||||
%block-info
|
||||
:_ state
|
||||
(retry-filtered-addrs network.p.upd blockhash.p.upd blockfilter.p.upd)
|
||||
==
|
||||
::
|
||||
++ handle-tx-info
|
||||
@ -1082,6 +1121,19 @@
|
||||
^- card
|
||||
[%give %fact ~[/all] %btc-wallet-update !>(upd)]
|
||||
::
|
||||
++ watch-provider
|
||||
|= who=@p
|
||||
^- card
|
||||
:* %pass /set-provider/[(scot %p who)] %agent [who %btc-provider]
|
||||
%watch /clients
|
||||
==
|
||||
++ leave-provider
|
||||
|= who=@p
|
||||
^- card
|
||||
:* %pass /set-provider/[(scot %p who)] %agent [who %btc-provider]
|
||||
%leave ~
|
||||
==
|
||||
::
|
||||
++ give-initial
|
||||
^- card
|
||||
=^ a=(unit address) state
|
||||
|
@ -26,6 +26,6 @@
|
||||
<div id="portal-root"></div>
|
||||
<script src="/~landscape/js/channel.js"></script>
|
||||
<script src="/~landscape/js/session.js"></script>
|
||||
<script src="/~btc/js/bundle/index.2fa306f66a2d4f9dd6c3.js"></script>
|
||||
<script src="/~btc/js/bundle/index.f7ab13b7db3ec1f8b55a.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -918,7 +918,7 @@
|
||||
^- (quip card _state)
|
||||
:_ state
|
||||
=- (turn - print:sh-out)
|
||||
:~ ";view ~host/chat to print messages for a chat you've already jonied."
|
||||
:~ ";view ~host/chat to print messages for a chat you've already joined."
|
||||
";flee ~host/chat to stop printing messages for a chat."
|
||||
"For more details:"
|
||||
"https://urbit.org/using/operations/using-your-ship/#messaging"
|
||||
|
@ -233,7 +233,7 @@
|
||||
|= =path
|
||||
^- (unit (unit cage))
|
||||
?+ path (on-peek:def path)
|
||||
[%x %all ~] ``noun+!>(rolodex)
|
||||
[%x %all ~] ``noun+!>(`rolodex:store`rolodex)
|
||||
::
|
||||
[%x %contact @ ~]
|
||||
=/ =ship (slav %p i.t.t.path)
|
||||
@ -245,14 +245,13 @@
|
||||
::
|
||||
[%x %allowed-ship @ ~]
|
||||
=/ =ship (slav %p i.t.t.path)
|
||||
``noun+!>((~(has in allowed-ships) ship))
|
||||
``noun+!>(`?`(~(has in allowed-ships) ship))
|
||||
::
|
||||
[%x %is-public ~]
|
||||
``noun+!>(is-public)
|
||||
``noun+!>(`?`is-public)
|
||||
::
|
||||
[%x %allowed-groups ~]
|
||||
``noun+!>(allowed-groups)
|
||||
|
||||
``noun+!>(`(set resource)`allowed-groups)
|
||||
::
|
||||
[%x %is-allowed @ @ @ @ ~]
|
||||
=/ is-personal =(i.t.t.t.t.t.path 'true')
|
||||
|
@ -189,7 +189,11 @@
|
||||
?> =(1 ~(wyt by nodes))
|
||||
=/ ship-screen (~(get ju screened) src.bowl)
|
||||
=. ship-screen (~(uni in ship-screen) (normalize-incoming nodes))
|
||||
`state(screened (~(put by screened) src.bowl ship-screen))
|
||||
=. screened (~(put by screened) src.bowl ship-screen)
|
||||
:_ state
|
||||
=/ =action:hook
|
||||
[%pendings ~(key by screened)]
|
||||
(fact:io dm-hook-action+!>(action) ~[/updates])^~
|
||||
::
|
||||
++ dm-exists
|
||||
|= =ship
|
||||
|
@ -5,8 +5,8 @@
|
||||
/- glob, *resource
|
||||
/+ default-agent, verb, dbug
|
||||
|%
|
||||
++ landscape-hash 0v2.i41hn.un6g3.jucd7.rhrah.n0qmv
|
||||
++ btc-wallet-hash 0v2.3qak4.al612.8m1ig.kg03r.mfide
|
||||
++ landscape-hash 0v4.3us6c.ma3il.h5bch.qacg3.70qjl
|
||||
++ btc-wallet-hash 0v1.9p61c.bd4vn.deevh.0ldbq.fkqo3
|
||||
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
|
||||
+$ state-1 [%1 =globs:glob]
|
||||
+$ all-states
|
||||
|
@ -131,10 +131,9 @@
|
||||
=^ allowed cards (is-allowed-add:hc rid nodes.q.update)
|
||||
?. allowed
|
||||
[cards ~]
|
||||
=/ mark-cached (~(has by graph-to-mark) rid)
|
||||
=/ mark
|
||||
?: mark-cached
|
||||
(~(got by graph-to-mark) rid)
|
||||
%+ fall
|
||||
(~(get by graph-to-mark) rid)
|
||||
(get-mark:gra rid)
|
||||
?~ mark
|
||||
[cards `vas]
|
||||
@ -143,15 +142,12 @@
|
||||
|%
|
||||
++ $
|
||||
^- (quip card (unit vase))
|
||||
=/ transform-cached (~(has by transform-marks) u.mark)
|
||||
=/ transform=cached-transform
|
||||
?: transform-cached
|
||||
(~(got by transform-marks) u.mark)
|
||||
%+ fall
|
||||
(~(get by transform-marks) u.mark)
|
||||
=/ =tube:clay
|
||||
.^(tube:clay (scry:hc %cc %home /[u.mark]/transform-add-nodes))
|
||||
!< cached-transform
|
||||
%. !>(*indexed-post:store)
|
||||
tube
|
||||
!<(cached-transform (tube !>(*indexed-post:store)))
|
||||
=/ [* result=(list [index:store node:store])]
|
||||
%+ roll
|
||||
(flatten-node-map ~(tap by nodes.q.update))
|
||||
@ -164,13 +160,15 @@
|
||||
update
|
||||
%+ weld cards
|
||||
%- zing
|
||||
:~ ?: mark-cached ~
|
||||
:~ ?: (~(has by graph-to-mark) rid)
|
||||
~
|
||||
:_ ~
|
||||
%+ poke-self:pass:io %graph-cache-hook
|
||||
!> ^- cache-action
|
||||
[%graph-to-mark rid mark]
|
||||
::
|
||||
?: transform-cached ~
|
||||
?: (~(has by transform-marks) u.mark)
|
||||
~
|
||||
:_ ~
|
||||
%+ poke-self:pass:io %graph-cache-hook
|
||||
!> ^- cache-action
|
||||
@ -316,28 +314,27 @@
|
||||
|= [=resource:res perm=@t vip=vip-metadata:metadata =indexed-post:store]
|
||||
^- [permissions:store (list card)]
|
||||
|^
|
||||
=/ mark-cached (~(has by graph-to-mark.cache) resource)
|
||||
=/ mark
|
||||
?: mark-cached
|
||||
(~(got by graph-to-mark.cache) resource)
|
||||
%+ fall
|
||||
(~(get by graph-to-mark.cache) resource)
|
||||
(get-mark:gra resource)
|
||||
?~ mark
|
||||
[[%no %no %no] ~]
|
||||
=/ key [u.mark (perm-mark-name perm)]
|
||||
=/ perms-cached (~(has by perm-marks.cache) key)
|
||||
=/ convert
|
||||
?: perms-cached
|
||||
(~(got by perm-marks.cache) key)
|
||||
%+ fall
|
||||
(~(get by perm-marks.cache) key)
|
||||
.^(cached-permission (scry %cf %home /[u.mark]/(perm-mark-name perm)))
|
||||
:- ((convert indexed-post) vip)
|
||||
%- zing
|
||||
:~ ?: mark-cached ~
|
||||
:~ ?: (~(has by graph-to-mark.cache) resource)
|
||||
~
|
||||
:_ ~
|
||||
%+ poke-self:pass:io %graph-cache-hook
|
||||
!> ^- cache-action
|
||||
[%graph-to-mark resource mark]
|
||||
::
|
||||
?: perms-cached ~
|
||||
?: (~(has by perm-marks.cache) key) ~
|
||||
:_ ~
|
||||
%+ poke-self:pass:io %graph-cache-hook
|
||||
!> ^- cache-action
|
||||
|
@ -5,8 +5,8 @@
|
||||
|%
|
||||
+$ card card:agent:gall
|
||||
+$ versioned-state
|
||||
$% [%0 network:zero:store]
|
||||
[%1 network:zero:store]
|
||||
$% [%0 *]
|
||||
[%1 *]
|
||||
[%2 network:zero:store]
|
||||
[%3 network:one:store]
|
||||
[%4 network:store]
|
||||
@ -16,7 +16,6 @@
|
||||
+$ state-5 [%5 network:store]
|
||||
++ orm orm:store
|
||||
++ orm-log orm-log:store
|
||||
+$ debug-input [%validate-graph =resource:store]
|
||||
::
|
||||
+$ cache
|
||||
$: validators=(map mark $-(indexed-post:store indexed-post:store))
|
||||
@ -50,34 +49,8 @@
|
||||
=| cards=(list card)
|
||||
|-
|
||||
?- -.old
|
||||
%0
|
||||
=* zro zero-load:upgrade:store
|
||||
%_ $
|
||||
-.old %1
|
||||
::
|
||||
graphs.old
|
||||
%- ~(run by graphs.old)
|
||||
|= [=graph:zero:store q=(unit mark)]
|
||||
^- [graph:zero:store (unit mark)]
|
||||
:- (convert-unix-timestamped-graph:zro graph)
|
||||
?^ q q
|
||||
`%graph-validator-link
|
||||
::
|
||||
update-logs.old
|
||||
%- ~(run by update-logs.old)
|
||||
|=(a=* *update-log:zero:store)
|
||||
==
|
||||
::
|
||||
%1
|
||||
=* zro zero-load:upgrade:store
|
||||
%_ $
|
||||
-.old %2
|
||||
graphs.old (~(run by graphs.old) change-revision-graph:zro)
|
||||
::
|
||||
update-logs.old
|
||||
%- ~(run by update-logs.old)
|
||||
|=(a=* *update-log:zero:store)
|
||||
==
|
||||
%0 !!
|
||||
%1 !!
|
||||
::
|
||||
%2
|
||||
=* upg upgrade:store
|
||||
@ -138,7 +111,7 @@
|
||||
++ give
|
||||
|= =action:store
|
||||
^- (list card)
|
||||
[%give %fact ~ [%graph-update-2 !>([now.bowl action])]]~
|
||||
[%give %fact ~ [%graph-update-2 !>(`update:store`[now.bowl action])]]~
|
||||
--
|
||||
::
|
||||
++ on-poke
|
||||
@ -148,10 +121,9 @@
|
||||
|^
|
||||
?> (team:title our.bowl src.bowl)
|
||||
=^ cards state
|
||||
?+ mark (on-poke:def mark vase)
|
||||
%graph-update-2 (graph-update !<(update:store vase))
|
||||
%noun (debug !<(debug-input vase))
|
||||
%import (poke-import q.vase)
|
||||
?+ mark (on-poke:def mark vase)
|
||||
%graph-update-2 (graph-update !<(update:store vase))
|
||||
%import (poke-import q.vase)
|
||||
==
|
||||
[cards this]
|
||||
::
|
||||
@ -204,7 +176,7 @@
|
||||
==
|
||||
%- zing
|
||||
:~ (give [/keys ~] %keys (~(put in ~(key by graphs)) resource))
|
||||
(give [/updates ~] %add-graph resource *graph:store mark overwrite)
|
||||
(give [/updates ~] %add-graph resource ~ mark overwrite)
|
||||
==
|
||||
::
|
||||
++ remove-graph
|
||||
@ -274,7 +246,7 @@
|
||||
?~ index
|
||||
?=(^ node)
|
||||
?~ t.index
|
||||
?=(^ (get:orm graph i.index))
|
||||
(has:orm graph i.index)
|
||||
=. node (get:orm graph i.index)
|
||||
?~ node %.n
|
||||
?- -.children.u.node
|
||||
@ -330,7 +302,8 @@
|
||||
~| "cannot add deleted post"
|
||||
?> ?=(%& -.post.node)
|
||||
=* p p.post.node
|
||||
?~ hash.p node(signatures.p.post *signatures:store)
|
||||
?~ hash.p
|
||||
node(signatures.p.post ~)
|
||||
=/ =validated-portion:store
|
||||
[parent-hash author.p time-sent.p contents.p]
|
||||
=/ =hash:store `@ux`(sham validated-portion)
|
||||
@ -343,24 +316,23 @@
|
||||
::
|
||||
=/ parent=node:store
|
||||
~| "index does not exist to add a node to!"
|
||||
(need (get:orm graph atom))
|
||||
(got:orm graph atom)
|
||||
%_ parent
|
||||
children
|
||||
^- internal-graph:store
|
||||
:- %graph
|
||||
%_ $
|
||||
index t.index
|
||||
index t.index
|
||||
::
|
||||
parent-hash
|
||||
?- -.post.parent
|
||||
%| `p.post.parent
|
||||
%& hash.p.post.parent
|
||||
==
|
||||
?: ?=(%| -.post.parent)
|
||||
`p.post.parent
|
||||
hash.p.post.parent
|
||||
::
|
||||
graph
|
||||
?: ?=(%graph -.children.parent)
|
||||
p.children.parent
|
||||
(gas:orm ~ ~)
|
||||
?. ?=(%graph -.children.parent)
|
||||
~
|
||||
p.children.parent
|
||||
==
|
||||
==
|
||||
--
|
||||
@ -416,7 +388,7 @@
|
||||
?~ t.index
|
||||
=/ =node:store
|
||||
~| "cannot remove index that does not exist {<index>}"
|
||||
(need (get:orm graph atom))
|
||||
(got:orm graph atom)
|
||||
%_ node
|
||||
post
|
||||
~| "cannot remove post that has already been removed"
|
||||
@ -434,7 +406,7 @@
|
||||
::
|
||||
=/ parent=node:store
|
||||
~| "parent index does not exist to remove a node from!"
|
||||
(need (get:orm graph atom))
|
||||
(got:orm graph atom)
|
||||
~| "child index does not exist to remove a node from!"
|
||||
?> ?=(%graph -.children.parent)
|
||||
%_ parent
|
||||
@ -444,10 +416,9 @@
|
||||
graph p.children.parent
|
||||
::
|
||||
parent-hash
|
||||
?- -.post.parent
|
||||
%| `p.post.parent
|
||||
%& hash.p.post.parent
|
||||
==
|
||||
?: ?=(%| -.post.parent)
|
||||
`p.post.parent
|
||||
hash.p.post.parent
|
||||
==
|
||||
==
|
||||
--
|
||||
@ -478,7 +449,7 @@
|
||||
=* atom i.index
|
||||
=/ =node:store
|
||||
~| "node does not exist to add signatures to!"
|
||||
(need (get:orm graph atom))
|
||||
(got:orm graph atom)
|
||||
:: last index in list
|
||||
::
|
||||
%^ put:orm
|
||||
@ -490,7 +461,10 @@
|
||||
~| "cannot add signatures to a node missing a hash"
|
||||
?> ?=(^ hash.p.post.node)
|
||||
~| "signatures did not match public keys!"
|
||||
?> (are-signatures-valid:sigs our.bowl signatures u.hash.p.post.node now.bowl)
|
||||
?> %: are-signatures-valid:sigs
|
||||
our.bowl signatures
|
||||
u.hash.p.post.node now.bowl
|
||||
==
|
||||
node(signatures.p.post (~(uni in signatures) signatures.p.post.node))
|
||||
~| "child graph does not exist to add signatures to!"
|
||||
?> ?=(%graph -.children.node)
|
||||
@ -525,7 +499,7 @@
|
||||
=* atom i.index
|
||||
=/ =node:store
|
||||
~| "node does not exist to add signatures to!"
|
||||
(need (get:orm graph atom))
|
||||
(got:orm graph atom)
|
||||
:: last index in list
|
||||
::
|
||||
%^ put:orm
|
||||
@ -578,7 +552,7 @@
|
||||
%_ state
|
||||
archive (~(del by archive) resource)
|
||||
graphs (~(put by graphs) resource (~(got by archive) resource))
|
||||
update-logs (~(put by update-logs) resource (gas:orm-log ~ ~))
|
||||
update-logs (~(put by update-logs) resource ~)
|
||||
==
|
||||
::
|
||||
++ run-updates
|
||||
@ -599,38 +573,28 @@
|
||||
%- graph-update
|
||||
^- update:store
|
||||
?- -.q.update
|
||||
%add-graph update(resource.q resource)
|
||||
%add-nodes update(resource.q resource)
|
||||
%remove-posts update(resource.q resource)
|
||||
%add-signatures update(resource.uid.q resource)
|
||||
%remove-signatures update(resource.uid.q resource)
|
||||
%add-graph update(resource.q resource)
|
||||
%add-nodes update(resource.q resource)
|
||||
%remove-posts update(resource.q resource)
|
||||
%add-signatures update(resource.uid.q resource)
|
||||
%remove-signatures update(resource.uid.q resource)
|
||||
==
|
||||
$(cards (weld cards crds), updates t.updates)
|
||||
::
|
||||
++ give
|
||||
|= [paths=(list path) update=action:store]
|
||||
^- (list card)
|
||||
[%give %fact paths [%graph-update-2 !>([now.bowl update])]]~
|
||||
[%give %fact paths [%graph-update-2 !>(`update:store`[now.bowl update])]]~
|
||||
--
|
||||
::
|
||||
++ debug
|
||||
|= =debug-input
|
||||
^- (quip card _state)
|
||||
=/ [=graph:store mark=(unit mark:store)]
|
||||
(~(got by graphs) resource.debug-input)
|
||||
=^ is-valid state
|
||||
(validate-graph graph mark)
|
||||
?> is-valid
|
||||
[~ state]
|
||||
::
|
||||
++ validate-graph
|
||||
|= [=graph:store mark=(unit mark:store)]
|
||||
^- [? _state]
|
||||
?~ mark [%.y state]
|
||||
=/ has-validator (~(has by validators) u.mark)
|
||||
?~ mark
|
||||
[%.y state]
|
||||
=/ validate=$-(indexed-post:store indexed-post:store)
|
||||
?: has-validator
|
||||
(~(got by validators) u.mark)
|
||||
%+ fall
|
||||
(~(get by validators) u.mark)
|
||||
.^ $-(indexed-post:store indexed-post:store)
|
||||
%cf
|
||||
(scot %p our.bowl)
|
||||
@ -640,11 +604,13 @@
|
||||
%graph-indexed-post
|
||||
~
|
||||
==
|
||||
:_ state(validators (~(put by validators) u.mark validate))
|
||||
=? validators !(~(has by validators) u.mark)
|
||||
(~(put by validators) u.mark validate)
|
||||
:_ state
|
||||
|- ^- ?
|
||||
?~ graph %.y
|
||||
%+ roll (tap:orm graph)
|
||||
|= [[=atom =node:store] out=?]
|
||||
%+ all:orm graph
|
||||
|= [=atom =node:store]
|
||||
^- ?
|
||||
?& ?| ?=(%| -.post.node)
|
||||
?=(^ (validate [atom p.post.node]))
|
||||
@ -676,7 +642,7 @@
|
||||
=/ result=(unit marked-graph:store)
|
||||
(~(get by graphs) [ship term])
|
||||
?~ result [~ ~]
|
||||
``noun+!>(q.u.result)
|
||||
``noun+!>(`(unit mark)`q.u.result)
|
||||
::
|
||||
[%x %keys ~]
|
||||
:- ~ :- ~ :- %graph-update-2
|
||||
@ -745,7 +711,7 @@
|
||||
(turn t.t.t.t.path (cury slav %ud))
|
||||
=/ node=(unit node:store)
|
||||
(get-node ship term index)
|
||||
``noun+!>(?=(^ node))
|
||||
``noun+!>(`?`?=(^ node))
|
||||
::
|
||||
[%x %node @ @ @ *]
|
||||
=/ =ship (slav %p i.t.t.path)
|
||||
@ -762,6 +728,7 @@
|
||||
(~(gas by *(map index:store node:store)) [index u.node] ~)
|
||||
::
|
||||
[%x %node-siblings ?(%older %younger) @ @ @ *]
|
||||
|^
|
||||
=/ older ?=(%older i.t.t.path)
|
||||
=/ =ship (slav %p i.t.t.t.path)
|
||||
=/ =term i.t.t.t.t.path
|
||||
@ -779,21 +746,28 @@
|
||||
:+ %add-nodes
|
||||
[ship term]
|
||||
%- ~(gas by *(map index:store node:store))
|
||||
:: TODO time complexity not desirable
|
||||
:: replace with custom ordered map functions
|
||||
%+ turn
|
||||
=- ?.(older (slag (safe-sub (lent -) count) -) (scag count -))
|
||||
?: older
|
||||
(tab:orm u.graph `(rear index) count)
|
||||
:: TODO time complexity not desirable for %younger case
|
||||
::
|
||||
%+ slag (safe-sub (lent -) count)
|
||||
%- tap:orm
|
||||
%+ lot:orm u.graph
|
||||
=/ idx
|
||||
(snag (dec (lent index)) index)
|
||||
?:(older [`idx ~] [~ `idx])
|
||||
[~ `(snag (dec (lent index)) index)]
|
||||
|= [=atom =node:store]
|
||||
^- [index:store node:store]
|
||||
[(snoc parent atom) node]
|
||||
::
|
||||
++ safe-sub
|
||||
|= [a=@ b=@]
|
||||
^- @
|
||||
?: (gte b a)
|
||||
0
|
||||
(sub a b)
|
||||
--
|
||||
::
|
||||
[%x %shallow-children @ @ *]
|
||||
=/ newest ?=(%newest i.t.path)
|
||||
=/ =ship (slav %p i.t.t.path)
|
||||
=/ =term i.t.t.t.path
|
||||
=/ =index:store
|
||||
@ -831,8 +805,9 @@
|
||||
%- ~(gas by *(map index:store node:store))
|
||||
%+ turn
|
||||
%+ scag count
|
||||
%- ?:(newest same flop)
|
||||
(tap:orm u.children)
|
||||
?: newest
|
||||
(tap:orm u.children)
|
||||
(bap:orm u.children)
|
||||
|= [=atom =node:store]
|
||||
^- [index:store node:store]
|
||||
[(snoc index atom) node]
|
||||
@ -923,7 +898,8 @@
|
||||
::
|
||||
++ collect-parents
|
||||
|= [=graph:store =index:store =ship =term]
|
||||
^- (unit [node:store index:store (map index:store node:store) ^ship ^term])
|
||||
^- %- unit
|
||||
[node:store index:store (map index:store node:store) ^ship ^term]
|
||||
=| =(map index:store node:store)
|
||||
=| =node:store
|
||||
=| ind=index:store
|
||||
@ -953,16 +929,16 @@
|
||||
==
|
||||
::
|
||||
++ collect-firstborn
|
||||
|= [=node:store =index:store map=(map index:store node:store) =ship =term]
|
||||
|= [=node:store =index:store mp=(map index:store node:store) =ship =term]
|
||||
^- (unit (unit cage))
|
||||
?: ?=(%empty -.children.node)
|
||||
:- ~ :- ~ :- %graph-update-2
|
||||
!> ^- update:store
|
||||
[now.bowl [%add-nodes [ship term] map]]
|
||||
[now.bowl [%add-nodes [ship term] mp]]
|
||||
=/ item=[k=atom v=node:store]
|
||||
(need (ram:orm p.children.node))
|
||||
=. index (snoc index k.item)
|
||||
$(map (~(put by map) index v.item(children empty+~)), node v.item)
|
||||
$(mp (~(put by mp) index v.item(children empty+~)), node v.item)
|
||||
--
|
||||
::
|
||||
[%x %update-log-subset @ @ @ @ ~]
|
||||
@ -973,35 +949,29 @@
|
||||
=/ update-log=(unit update-log:store) (~(get by update-logs) [ship term])
|
||||
?~ update-log [~ ~]
|
||||
:: orm-log is ordered backwards, so swap start and end
|
||||
``noun+!>((lot:orm-log u.update-log end start))
|
||||
``noun+!>(`update-log:store`(lot:orm-log u.update-log end start))
|
||||
::
|
||||
[%x %update-log @ @ ~]
|
||||
=/ =ship (slav %p i.t.t.path)
|
||||
=/ =term i.t.t.t.path
|
||||
=/ update-log=(unit update-log:store) (~(get by update-logs) [ship term])
|
||||
?~ update-log [~ ~]
|
||||
``noun+!>(u.update-log)
|
||||
``noun+!>(`update-log:store`u.update-log)
|
||||
::
|
||||
[%x %peek-update-log @ @ ~]
|
||||
=/ =ship (slav %p i.t.t.path)
|
||||
=/ =term i.t.t.t.path
|
||||
=/ m-update-log=(unit update-log:store) (~(get by update-logs) [ship term])
|
||||
=/ m-update-log=(unit update-log:store)
|
||||
(~(get by update-logs) [ship term])
|
||||
:- ~ :- ~ :- %noun
|
||||
!> ^- (unit time)
|
||||
%+ biff m-update-log
|
||||
|= =update-log:store
|
||||
=/ result=(unit [=time =update:store])
|
||||
(pry:orm-log:store update-log)
|
||||
(bind result |=([=time update:store] time))
|
||||
(bind result head)
|
||||
==
|
||||
::
|
||||
++ safe-sub
|
||||
|= [a=@ b=@]
|
||||
^- @
|
||||
?: (gte b a)
|
||||
0
|
||||
(sub a b)
|
||||
::
|
||||
++ get-node-children
|
||||
|= [=ship =term =index:store]
|
||||
^- (unit graph:store)
|
||||
@ -1044,40 +1014,12 @@
|
||||
?+ wire (on-arvo:def wire sign-arvo)
|
||||
::
|
||||
:: old wire, do nothing
|
||||
[%graph *] [~ this]
|
||||
[%validator @ ~] [~ this]
|
||||
::
|
||||
[%try-rejoin @ *]
|
||||
=/ rid=resource:store (de-path:res t.t.wire)
|
||||
=/ nack-count (slav %ud i.t.wire)
|
||||
?> ?=([%behn %wake *] sign-arvo)
|
||||
~? ?=(^ error.sign-arvo)
|
||||
"behn errored in backoff timers, continuing anyway"
|
||||
=/ new=^wire [%try-rejoin (scot %ud +(nack-count)) t.t.wire]
|
||||
:_ this
|
||||
[%pass new %agent [entity.rid %graph-push-hook] %watch resource+t.t.wire]~
|
||||
[%graph *] [~ this]
|
||||
[%validator @ ~] [~ this]
|
||||
[%try-rejoin @ *] [~ this]
|
||||
==
|
||||
::
|
||||
++ on-agent
|
||||
|= [=wire =sign:agent:gall]
|
||||
^- (quip card _this)
|
||||
?. ?=([%try-rejoin @ *] wire)
|
||||
(on-agent:def wire sign)
|
||||
?. ?=(%watch-ack -.sign)
|
||||
[~ this]
|
||||
=/ rid=resource:store (de-path:res t.t.wire)
|
||||
?~ p.sign
|
||||
=/ =cage [%pull-hook-action !>([%add entity.rid rid])]
|
||||
:_ this
|
||||
:~ [%pass / %agent [our.bowl %graph-pull-hook] %poke cage]
|
||||
[%pass wire %agent [entity.rid %graph-push-hook] %leave ~]
|
||||
==
|
||||
=/ nack-count=@ud (slav %ud i.t.wire)
|
||||
=/ wakeup=@da
|
||||
(add now.bowl (mul ~s1 (bex (min 19 nack-count))))
|
||||
:_ this
|
||||
[%pass wire %arvo %b %wait wakeup]~
|
||||
::
|
||||
++ on-agent on-agent:def
|
||||
++ on-leave on-leave:def
|
||||
++ on-fail on-fail:def
|
||||
--
|
||||
|
@ -30,12 +30,12 @@
|
||||
?> ?=(^ t.p)
|
||||
.^(mold i.p (scot %p our) i.t.p (scot %da now) t.t.p)
|
||||
::
|
||||
++ scry-conversion
|
||||
++ scry-notif-conversion
|
||||
|= [[our=@p now=@da] desk=term =mark]
|
||||
~+
|
||||
^- $-(indexed-post:graph-store (unit notif-kind:hook))
|
||||
%^ scry [our now]
|
||||
tube:clay
|
||||
/cc/[desk]/[mark]/notification-kind
|
||||
$-(indexed-post:graph-store (unit notif-kind:hook))
|
||||
/cf/[desk]/[mark]/notification-kind
|
||||
--
|
||||
::
|
||||
=| state-1
|
||||
@ -87,7 +87,7 @@
|
||||
|= =mark
|
||||
^- card
|
||||
=/ =wire /validator/[mark]
|
||||
=/ =rave:clay [%sing %c [%da now.bowl] /[mark]/notification-kind]
|
||||
=/ =rave:clay [%sing %f [%da now.bowl] /[mark]/notification-kind]
|
||||
[%pass wire %arvo %c %warp our.bowl [%home `rave]]
|
||||
::
|
||||
++ on-watch
|
||||
@ -214,19 +214,18 @@
|
||||
%- ~(gas by *(set [resource index:graph-store]))
|
||||
(turn ~(tap in indices) (lead rid))
|
||||
:_ state(watching (~(dif in watching) to-remove))
|
||||
=/ =tube:clay
|
||||
(get-conversion:ha rid)
|
||||
=/ convert (get-conversion:ha rid)
|
||||
%+ roll
|
||||
~(tap in indices)
|
||||
|= [=index:graph-store out=(list card)]
|
||||
=| =indexed-post:graph-store
|
||||
=. index.p.indexed-post index
|
||||
=+ !<(u-notif-kind=(unit notif-kind:hook) (tube !>(indexed-post)))
|
||||
?~ u-notif-kind out
|
||||
=* notif-kind u.u-notif-kind
|
||||
=/ notif-kind=(unit notif-kind:hook)
|
||||
(convert indexed-post)
|
||||
?~ notif-kind out
|
||||
=/ =stats-index:store
|
||||
[%graph rid (scag parent.index-len.notif-kind index)]
|
||||
?. ?=(%each mode.notif-kind) out
|
||||
[%graph rid (scag parent.index-len.u.notif-kind index)]
|
||||
?. ?=(%each mode.u.notif-kind) out
|
||||
:_ out
|
||||
(poke-hark %read-each stats-index index)
|
||||
::
|
||||
@ -285,7 +284,7 @@
|
||||
[%validator @ ~]
|
||||
:_ this
|
||||
=* validator i.t.wire
|
||||
=/ =rave:clay [%next %c [%da now.bowl] /[validator]/notification-kind]
|
||||
=/ =rave:clay [%next %f [%da now.bowl] /[validator]/notification-kind]
|
||||
[%pass wire %arvo %c %warp our.bowl [%home `rave]]~
|
||||
==
|
||||
++ on-fail on-fail:def
|
||||
@ -298,13 +297,13 @@
|
||||
::
|
||||
++ get-conversion
|
||||
|= rid=resource
|
||||
^- tube:clay
|
||||
^- $-(indexed-post:graph-store (unit notif-kind:hook))
|
||||
=+ %^ scry [our now]:bowl
|
||||
,mark=(unit mark)
|
||||
/gx/graph-store/graph-mark/(scot %p entity.rid)/[name.rid]/noun
|
||||
?~ mark
|
||||
|=(v=vase !>(~))
|
||||
(scry-conversion [our now]:bowl q.byk.bowl u.mark)
|
||||
|=(=indexed-post:graph-store ~)
|
||||
(scry-notif-conversion [our now]:bowl q.byk.bowl u.mark)
|
||||
::
|
||||
++ give
|
||||
|= [paths=(list path) =update:hook]
|
||||
@ -355,8 +354,6 @@
|
||||
update-core(rid r, updates upds, mark m)
|
||||
::
|
||||
++ get-conversion
|
||||
:: LA: this tube should be cached in %hark-graph-hook state
|
||||
:: instead of just trying to keep it warm, as the scry overhead is large
|
||||
~+ (^get-conversion rid)
|
||||
::
|
||||
++ abet
|
||||
@ -410,9 +407,8 @@
|
||||
?: ?=(%| -.post.node)
|
||||
update-core
|
||||
=* pos p.post.node
|
||||
=+ !< notif-kind=(unit notif-kind:hook)
|
||||
%- get-conversion
|
||||
!>(`indexed-post:graph-store`[0 pos])
|
||||
=/ notif-kind=(unit notif-kind:hook)
|
||||
(get-conversion [0 pos])
|
||||
?~ notif-kind
|
||||
update-core
|
||||
=/ desc=@t
|
||||
|
@ -422,7 +422,11 @@
|
||||
%read-note (read-note +.in)
|
||||
::
|
||||
%seen-index (seen-index +.in)
|
||||
::
|
||||
%remove-graph (remove-graph +.in)
|
||||
%read-graph (read-graph +.in)
|
||||
%read-group (read-group +.in)
|
||||
::
|
||||
%set-dnd (set-dnd +.in)
|
||||
%seen seen
|
||||
%read-all read-all
|
||||
@ -566,10 +570,53 @@
|
||||
(~(put by last-seen) stats-index new-time)
|
||||
(give %seen-index new-time stats-index)
|
||||
::
|
||||
++ get-stats-indices
|
||||
|= rid=resource
|
||||
%- ~(gas ^in *(set stats-index:store))
|
||||
%+ skim
|
||||
;: weld
|
||||
~(tap ^in ~(key by unreads-count))
|
||||
~(tap ^in ~(key by last-seen))
|
||||
~(tap ^in ~(key by unreads-each))
|
||||
==
|
||||
|= =stats-index:store
|
||||
?. ?=(%graph -.stats-index) %.n
|
||||
=(graph.stats-index rid)
|
||||
::
|
||||
++ read-all-each
|
||||
|= =stats-index:store
|
||||
=/ refs=(list index:graph-store)
|
||||
~(tap ^in (~(get ju unreads-each) stats-index))
|
||||
|-
|
||||
?~ refs poke-core
|
||||
$(refs t.refs, poke-core (read-each stats-index i.refs))
|
||||
::
|
||||
++ read-graph
|
||||
|= rid=resource
|
||||
=/ indices=(list stats-index:store)
|
||||
~(tap ^in (get-stats-indices rid))
|
||||
|-
|
||||
?~ indices poke-core
|
||||
=* index i.indices
|
||||
=? poke-core (~(has by unreads-count) index)
|
||||
(read-count i.indices)
|
||||
=? poke-core (~(has by unreads-each) index)
|
||||
(read-all-each i.indices)
|
||||
$(indices t.indices)
|
||||
::
|
||||
++ read-group
|
||||
|= rid=resource
|
||||
=/ graphs=(list resource)
|
||||
(graphs-of-group:met rid)
|
||||
|-
|
||||
?~ graphs poke-core
|
||||
=/ core=_poke-core (read-graph i.graphs)
|
||||
$(graphs t.graphs, poke-core core)
|
||||
::
|
||||
++ remove-graph
|
||||
|= rid=resource
|
||||
|^
|
||||
=/ indices get-stats-indices
|
||||
=/ indices (get-stats-indices rid)
|
||||
=. poke-core
|
||||
(give %remove-graph rid)
|
||||
=. poke-core
|
||||
@ -583,18 +630,6 @@
|
||||
((dif-map-by-key ,@da) last-seen indices)
|
||||
poke-core
|
||||
::
|
||||
++ get-stats-indices
|
||||
%- ~(gas ^in *(set stats-index:store))
|
||||
%+ skim
|
||||
;: weld
|
||||
~(tap ^in ~(key by unreads-count))
|
||||
~(tap ^in ~(key by last-seen))
|
||||
~(tap ^in ~(key by unreads-each))
|
||||
==
|
||||
|= =stats-index:store
|
||||
?. ?=(%graph -.stats-index) %.n
|
||||
=(graph.stats-index rid)
|
||||
::
|
||||
++ dif-map-by-key
|
||||
|* value=mold
|
||||
|= [=(map stats-index:store value) =(set stats-index:store)]
|
||||
|
@ -24,6 +24,6 @@
|
||||
<div id="portal-root"></div>
|
||||
<script src="/~landscape/js/channel.js"></script>
|
||||
<script src="/~landscape/js/session.js"></script>
|
||||
<script src="/~landscape/js/bundle/index.969caa5f68ba7bcf5762.js"></script>
|
||||
<script src="/~landscape/js/bundle/index.af45eeaf465dff7d73f1.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -194,10 +194,18 @@
|
||||
|= =path
|
||||
^- (unit (unit cage))
|
||||
?+ path (on-peek:def path)
|
||||
[%y %group-indices ~] ``noun+!>(group-indices)
|
||||
[%y %app-indices ~] ``noun+!>(app-indices)
|
||||
[%y %resource-indices ~] ``noun+!>(resource-indices)
|
||||
[%x %associations ~] ``noun+!>(associations)
|
||||
[%y %group-indices ~]
|
||||
``noun+!>(`(jug resource md-resource:store)`group-indices)
|
||||
::
|
||||
[%y %app-indices ~]
|
||||
``noun+!>(`(jug app-name:store [group=resource =resource])`app-indices)
|
||||
::
|
||||
[%y %resource-indices ~]
|
||||
``noun+!>(`(map md-resource:store resource)`resource-indices)
|
||||
::
|
||||
[%x %associations ~]
|
||||
``noun+!>(`associations:store`associations)
|
||||
::
|
||||
[%x %app-name @ ~]
|
||||
=/ =app-name:store i.t.t.path
|
||||
``noun+!>(`associations:store`(metadata-for-app:mc app-name))
|
||||
|
@ -83,13 +83,13 @@
|
||||
^- (unit (unit cage))
|
||||
?+ pax (on-peek:def pax)
|
||||
[%x %all ~]
|
||||
``settings-data+!>(all+settings)
|
||||
``settings-data+!>(`data`all+settings)
|
||||
::
|
||||
[%x %bucket @ ~]
|
||||
=* buc i.t.t.pax
|
||||
=/ bucket=(unit bucket) (~(get by settings) buc)
|
||||
?~ bucket [~ ~]
|
||||
``settings-data+!>(bucket+u.bucket)
|
||||
``settings-data+!>(`data`bucket+u.bucket)
|
||||
::
|
||||
[%x %entry @ @ ~]
|
||||
=* buc i.t.t.pax
|
||||
@ -97,19 +97,19 @@
|
||||
=/ =bucket (fall (~(get by settings) buc) ~)
|
||||
=/ entry=(unit val) (~(get by bucket) key)
|
||||
?~ entry [~ ~]
|
||||
``settings-data+!>(entry+u.entry)
|
||||
``settings-data+!>(`data`entry+u.entry)
|
||||
::
|
||||
[%x %has-bucket @ ~]
|
||||
=* buc i.t.t.pax
|
||||
=/ has-bucket=? (~(has by settings) buc)
|
||||
``noun+!>(has-bucket)
|
||||
``noun+!>(`?`has-bucket)
|
||||
::
|
||||
[%x %has-entry @ @ ~]
|
||||
=* buc i.t.t.pax
|
||||
=* key i.t.t.t.pax
|
||||
=/ =bucket (fall (~(get by settings) buc) ~)
|
||||
=/ has-entry=? (~(has by bucket) key)
|
||||
``noun+!>(has-entry)
|
||||
``noun+!>(`?`has-entry)
|
||||
==
|
||||
::
|
||||
++ on-agent on-agent:def
|
||||
|
@ -1,6 +1,7 @@
|
||||
/- spider
|
||||
/+ libstrand=strand, default-agent, verb, server
|
||||
=, strand=strand:libstrand
|
||||
~% %spider-top ..part ~
|
||||
|%
|
||||
+$ card card:agent:gall
|
||||
+$ thread thread:spider
|
||||
@ -60,6 +61,7 @@
|
||||
::
|
||||
:: Trie operations
|
||||
::
|
||||
~% %spider ..card ~
|
||||
|%
|
||||
++ get-yarn
|
||||
|= [=trie =yarn]
|
||||
@ -137,6 +139,7 @@
|
||||
=| =state
|
||||
=<
|
||||
%+ verb |
|
||||
~% %spider-agent ..bind-eyre ~
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
spider-core +>
|
||||
@ -192,6 +195,7 @@
|
||||
--
|
||||
::
|
||||
++ on-poke
|
||||
~/ %on-poke
|
||||
|= [=mark =vase]
|
||||
^- (quip card _this)
|
||||
?: ?=(%spider-kill mark)
|
||||
@ -208,6 +212,7 @@
|
||||
[cards this]
|
||||
::
|
||||
++ on-watch
|
||||
~/ %on-watch
|
||||
|= =path
|
||||
^- (quip card _this)
|
||||
=^ cards state
|
||||
@ -220,6 +225,7 @@
|
||||
::
|
||||
++ on-leave on-leave:def
|
||||
++ on-peek
|
||||
~/ %on-peek
|
||||
|= =path
|
||||
^- (unit (unit cage))
|
||||
?+ path (on-peek:def path)
|
||||
@ -234,6 +240,7 @@
|
||||
==
|
||||
::
|
||||
++ on-agent
|
||||
~/ %on-agent
|
||||
|= [=wire =sign:agent:gall]
|
||||
^- (quip card _this)
|
||||
=^ cards state
|
||||
@ -243,6 +250,7 @@
|
||||
[cards this]
|
||||
::
|
||||
++ on-arvo
|
||||
~/ %on-arvo
|
||||
|= [=wire =sign-arvo]
|
||||
^- (quip card _this)
|
||||
=^ cards state
|
||||
@ -261,6 +269,7 @@
|
||||
(on-load on-save)
|
||||
--
|
||||
::
|
||||
~% %spider-helper ..get-yarn ~
|
||||
|_ =bowl:gall
|
||||
::
|
||||
++ bind-eyre
|
||||
@ -272,6 +281,7 @@
|
||||
:((cury cat 3) file '--' (scot %uv (sham eny.bowl)))
|
||||
::
|
||||
++ handle-http-request
|
||||
~/ %handle-http-request
|
||||
|= [eyre-id=@ta =inbound-request:eyre]
|
||||
^- (quip card _state)
|
||||
?> authenticated.inbound-request
|
||||
@ -284,6 +294,8 @@
|
||||
=/ =tid (new-thread-id thread)
|
||||
=. serving.state
|
||||
(~(put by serving.state) tid [eyre-id output-mark])
|
||||
:: TODO: speed this up somehow. we spend about 15ms in this arm alone
|
||||
::
|
||||
=+ .^
|
||||
=tube:clay
|
||||
%cc
|
||||
@ -315,6 +327,7 @@
|
||||
`state
|
||||
::
|
||||
++ handle-sign
|
||||
~/ %handle-sign
|
||||
|= [=tid =wire =sign-arvo]
|
||||
=/ yarn (~(get by tid.state) tid)
|
||||
?~ yarn
|
||||
@ -331,6 +344,7 @@
|
||||
(take-input u.yarn ~ %agent wire sign)
|
||||
::
|
||||
++ handle-start-thread
|
||||
~/ %handle-start-thread
|
||||
|= [parent-tid=(unit tid) use=(unit tid) file=term =vase]
|
||||
^- (quip card ^state)
|
||||
=/ parent-yarn=yarn
|
||||
@ -353,12 +367,13 @@
|
||||
=/ pax=path
|
||||
~| no-file-for-thread+file
|
||||
(need (get-fit:clay [our q.byk da+now]:bowl %ted file))
|
||||
=/ =card
|
||||
:+ %pass /build/[new-tid]
|
||||
[%arvo %c %warp our.bowl %home ~ %sing %a da+now.bowl pax]
|
||||
[[card ~] state]
|
||||
:_ state
|
||||
:_ ~
|
||||
:+ %pass /build/[new-tid]
|
||||
[%arvo %c %warp our.bowl %home ~ %sing %a da+now.bowl pax]
|
||||
::
|
||||
++ handle-build
|
||||
~/ %handle-build
|
||||
|= [=tid =sign-arvo]
|
||||
^- (quip card ^state)
|
||||
=/ =yarn (~(got by tid.state) tid)
|
||||
@ -377,6 +392,7 @@
|
||||
(start-thread yarn p.maybe-thread)
|
||||
::
|
||||
++ start-thread
|
||||
~/ %start-thread
|
||||
|= [=yarn =thread]
|
||||
^- (quip card ^state)
|
||||
=/ =vase vase:(~(got by starting.state) yarn)
|
||||
@ -411,6 +427,7 @@
|
||||
(thread-fail u.yarn %cancelled ~)
|
||||
::
|
||||
++ take-input
|
||||
~/ %take-input
|
||||
|= [=yarn input=(unit input:strand)]
|
||||
^- (quip card ^state)
|
||||
=/ m (strand ,vase)
|
||||
|
@ -211,19 +211,20 @@
|
||||
$(last-val (add delta last-val))
|
||||
:: +all-match: returns all target byts that match
|
||||
:: - filter: full block filter, with leading N
|
||||
:: - k: key for siphash (end of blockhash, reversed)
|
||||
:: - targets: scriptpubkeys to match
|
||||
::
|
||||
++ all-match
|
||||
|= [filter=hexb:bc k=byts targets=(list byts)]
|
||||
^- (set hexb:bc)
|
||||
%- ~(gas in *(set hexb:bc))
|
||||
|= [filter=hexb:bc blockhash=hexb:bc targets=(list [address:bc byts])]
|
||||
^- (set [address:bc hexb:bc])
|
||||
=/ k (to-key (trip (to-cord:hxb:bcu blockhash)))
|
||||
%- ~(gas in *(set [address:bc hexb:bc]))
|
||||
=/ [p=@ m=@] [p:params m:params]
|
||||
=/ [n=@ux gcs-set=bits:bc] (parse-filter filter)
|
||||
=/ target-map=(map @ hexb:bc)
|
||||
%- ~(gas by *(map @ hexb:bc))
|
||||
=/ target-map=(map @ [address:bc hexb:bc])
|
||||
%- ~(gas by *(map @ [address:bc hexb:bc]))
|
||||
%+ turn targets
|
||||
|=(t=hexb:bc [(to-range:hsh t (mul n m) k) t])
|
||||
|= [a=address:bc t=hexb:bc]
|
||||
[(to-range:hsh t (mul n m) k) a t]
|
||||
=+ target-hs=(sort ~(tap in ~(key by target-map)) lth)
|
||||
=+ last-val=0
|
||||
=| matches=(list @)
|
||||
@ -244,4 +245,5 @@
|
||||
=^ delta gcs-set
|
||||
(de:gol gcs-set p)
|
||||
$(last-val (add delta last-val))
|
||||
::
|
||||
--
|
||||
|
@ -3,7 +3,7 @@
|
||||
:: expose BIP libraries
|
||||
::
|
||||
/- sur=bitcoin
|
||||
/+ bech32=bip-b173, pbt=bip-b174, bcu=bitcoin-utils
|
||||
/+ bech32=bip-b173, pbt=bip-b174, bcu=bitcoin-utils, bip-b158
|
||||
=, sur
|
||||
=, bcu
|
||||
|%
|
||||
|
@ -505,8 +505,10 @@
|
||||
(mk-url '/getblockcount' '')
|
||||
::
|
||||
%get-block-info
|
||||
=/ param=@t
|
||||
?~(block.ract '' (rsh [3 2] (scot %ui u.block.ract)))
|
||||
%- get-request
|
||||
(mk-url '/getblockinfo' '')
|
||||
(mk-url '/getblockinfo/' param)
|
||||
==
|
||||
++ mk-url
|
||||
|= [base=@t params=@t]
|
||||
|
@ -42,6 +42,7 @@
|
||||
(snoc rids [our.bowl %''])
|
||||
--
|
||||
++ scry-sharing
|
||||
^- (set resource)
|
||||
.^ (set resource)
|
||||
%gx
|
||||
(scot %p our.bowl)
|
||||
@ -58,6 +59,7 @@
|
||||
(~(get by rolodex) ship)
|
||||
::
|
||||
++ scry-is-public
|
||||
^- ?
|
||||
.^ ?
|
||||
%gx
|
||||
(scot %p our.bowl)
|
||||
|
@ -28,8 +28,8 @@
|
||||
rose+(ot style+(ot mid+sa open+sa close+sa ~) lines+(ar dank) ~)
|
||||
==
|
||||
::
|
||||
++ orm ((ordered-map atom node) gth)
|
||||
++ orm-log ((ordered-map time logged-update) gth)
|
||||
++ orm ((on atom node) gth)
|
||||
++ orm-log ((on time logged-update) gth)
|
||||
::
|
||||
++ enjs
|
||||
=, enjs:format
|
||||
@ -311,7 +311,7 @@
|
||||
++ graph
|
||||
|= a=json
|
||||
^- ^graph
|
||||
=/ or-mp ((ordered-map atom ^node) gth)
|
||||
=/ or-mp ((on atom ^node) gth)
|
||||
%+ gas:or-mp ~
|
||||
%+ turn ~(tap by ((om node) a))
|
||||
|* [b=cord c=*]
|
||||
@ -559,7 +559,7 @@
|
||||
=>
|
||||
|%
|
||||
++ in-orm
|
||||
((ordered-map atom in-node) gth)
|
||||
((on atom in-node) gth)
|
||||
+$ in-node
|
||||
[post=in-pst children=in-internal-graph]
|
||||
+$ in-graph
|
||||
@ -571,7 +571,7 @@
|
||||
==
|
||||
::
|
||||
++ out-orm
|
||||
((ordered-map atom out-node) gth)
|
||||
((on atom out-node) gth)
|
||||
+$ out-node
|
||||
[post=out-pst children=out-internal-graph]
|
||||
+$ out-graph
|
||||
@ -823,7 +823,7 @@
|
||||
++ remake-update-log
|
||||
|= t=tree-update-log
|
||||
^- update-log
|
||||
=/ ulm ((ordered-map time logged-update) gth)
|
||||
=/ ulm ((on time logged-update) gth)
|
||||
%+ gas:ulm *update-log
|
||||
%+ turn ~(tap by t)
|
||||
|= [=time tlu=tree-logged-update]
|
||||
|
@ -314,6 +314,8 @@
|
||||
add-note+add
|
||||
set-dnd+bo
|
||||
read-count+stats-index
|
||||
read-graph+dejs-path:resource
|
||||
read-group+dejs-path:resource
|
||||
read-each+read-graph-index
|
||||
read-all+ul
|
||||
==
|
||||
|
@ -100,4 +100,13 @@
|
||||
^- (unit resource)
|
||||
%+ bind (peek-association md-resource)
|
||||
|=(association:store group)
|
||||
::
|
||||
++ graphs-of-group
|
||||
|= group=resource
|
||||
=/ =associations:store
|
||||
(metadata-for-group group)
|
||||
%+ murn ~(tap in ~(key by associations))
|
||||
|= [=app-name:store rid=resource]
|
||||
?.(=(%graph app-name) ~ `rid)
|
||||
|
||||
--
|
||||
|
@ -31,6 +31,7 @@
|
||||
[%raw-tx txid=hexb]
|
||||
[%broadcast-tx rawtx=hexb]
|
||||
[%ping ~]
|
||||
[%block-info block=(unit @ud)]
|
||||
==
|
||||
::
|
||||
+$ result
|
||||
@ -38,6 +39,7 @@
|
||||
[%tx-info =info:tx]
|
||||
[%raw-tx txid=hexb rawtx=hexb]
|
||||
[%broadcast-tx txid=hexb broadcast=? included=?]
|
||||
[%block-info =network block=@ud fee=(unit sats) blockhash=hexb blockfilter=hexb]
|
||||
==
|
||||
+$ error
|
||||
$% [%not-connected status=@ud]
|
||||
@ -60,7 +62,7 @@
|
||||
[%get-raw-tx txid=hexb]
|
||||
[%broadcast-tx rawtx=hexb]
|
||||
[%get-block-count ~]
|
||||
[%get-block-info ~]
|
||||
[%get-block-info block=(unit @ud)]
|
||||
==
|
||||
::
|
||||
+$ result
|
||||
|
@ -73,8 +73,8 @@
|
||||
::
|
||||
++ one
|
||||
|%
|
||||
++ orm ((ordered-map atom node) gth)
|
||||
++ orm-log ((ordered-map time logged-update) gth)
|
||||
++ orm ((on atom node) gth)
|
||||
++ orm-log ((on time logged-update) gth)
|
||||
::
|
||||
+$ graph ((mop atom node) gth)
|
||||
+$ marked-graph [p=graph q=(unit mark)]
|
||||
|
@ -44,6 +44,9 @@
|
||||
[%read-note =index]
|
||||
::
|
||||
[%seen-index time=@da =stats-index]
|
||||
::
|
||||
[%read-graph =resource]
|
||||
[%read-group =resource]
|
||||
[%remove-graph =resource]
|
||||
::
|
||||
[%read-all ~]
|
||||
@ -281,6 +284,7 @@
|
||||
[%unread-note time=@da index]
|
||||
::
|
||||
[%seen-index time=@da =stats-index]
|
||||
::
|
||||
[%remove-graph =resource]
|
||||
::
|
||||
[%read-all ~]
|
||||
|
@ -252,11 +252,13 @@
|
||||
:: %what: update from files
|
||||
:: %whey: produce $mass :: XX remove, scry
|
||||
:: %verb: toggle laconicity
|
||||
:: %whiz: prime vane caches
|
||||
::
|
||||
$% [%trim p=@ud]
|
||||
[%what p=(list (pair path (cask)))]
|
||||
[%whey ~]
|
||||
[%verb p=(unit ?)]
|
||||
[%whiz ~]
|
||||
==
|
||||
+$ wasp
|
||||
:: %crud: reroute $ovum with $goof
|
||||
@ -291,14 +293,23 @@
|
||||
|=(b=beam =*(s scot `path`[(s %p p.b) q.b (s r.b) s.b]))
|
||||
::
|
||||
++ de-beam
|
||||
~/ %de-beam
|
||||
|= p=path
|
||||
^- (unit beam)
|
||||
?. ?=([@ @ @ *] p) ~
|
||||
?~ who=(slaw %p i.p) ~
|
||||
?~ des=?~(i.t.p (some %$) (slaw %tas i.t.p)) ~ :: XX +sym ;~(pose low (easy %$))
|
||||
?~ ved=(slay i.t.t.p) ~
|
||||
?. ?=([%$ case] u.ved) ~
|
||||
`(unit beam)`[~ [`ship`u.who `desk`u.des `case`p.u.ved] t.t.t.p]
|
||||
?~ ved=(de-case i.t.t.p) ~
|
||||
`[[`ship`u.who `desk`u.des u.ved] t.t.t.p]
|
||||
::
|
||||
++ de-case
|
||||
~/ %de-case
|
||||
|= =knot
|
||||
^- (unit case)
|
||||
?^ num=(slaw %ud knot) `[%ud u.num]
|
||||
?^ wen=(slaw %da knot) `[%da u.wen]
|
||||
?~ lab=(slaw %tas knot) ~
|
||||
`[%tas u.lab]
|
||||
::
|
||||
++ en-omen
|
||||
|= [vis=view bem=beam]
|
||||
@ -308,6 +319,7 @@
|
||||
~(rent co [%many $/tas/way.vis $/tas/car.vis ~])
|
||||
::
|
||||
++ de-omen
|
||||
~/ %de-omen
|
||||
|= pax=path
|
||||
^- (unit [vis=view bem=beam])
|
||||
?~ pax ~
|
||||
@ -1000,8 +1012,11 @@
|
||||
++ settle
|
||||
|= van=vase
|
||||
^- (pair vase worm)
|
||||
=/ [rig=vase wor=worm] (~(slym wa *worm) van *vane-sample)
|
||||
[van +:(~(slap wa wor) rig [%limb %scry])]
|
||||
=| sac=worm
|
||||
=^ rig=vase sac (~(slym wa sac) van *vane-sample)
|
||||
=^ gat=vase sac (~(slap wa sac) rig [%limb %scry])
|
||||
=^ pro=vase sac (~(slap wa sac) gat [%limb %$])
|
||||
[van +:(~(mint wa sac) p.pro [%$ 7])]
|
||||
::
|
||||
:: XX pass identity to preserve behavior?
|
||||
::
|
||||
@ -1470,6 +1485,9 @@
|
||||
%verb ..pith(lac.fad ?~(p.waif !lac.fad u.p.waif))
|
||||
%what ~(kel what p.waif)
|
||||
%whey ..pith(out [[//arvo mass/whey] out])
|
||||
::
|
||||
%whiz
|
||||
..pith(van.mod (~(run by van.mod) |=(vane (settle:va:part vase))))
|
||||
==
|
||||
::
|
||||
++ peek
|
||||
|
@ -259,6 +259,8 @@
|
||||
++ head |*(^ ,:+<-) :: get head
|
||||
++ same |*(* +<) :: identity
|
||||
::
|
||||
++ succ |=(@ +(+<)) :: successor
|
||||
::
|
||||
++ tail |*(^ ,:+<+) :: get tail
|
||||
++ test |=(^ =(+<- +<+)) :: equality
|
||||
::
|
||||
@ -8764,6 +8766,7 @@
|
||||
%peek peek
|
||||
%repo repo
|
||||
%rest rest
|
||||
%sink sink
|
||||
%tack tack
|
||||
%toss toss
|
||||
%wrap wrap
|
||||
@ -10838,7 +10841,7 @@
|
||||
|- ^- type
|
||||
?~ lov sut
|
||||
$(lov t.lov, sut (face i.lov sut))
|
||||
:: ::
|
||||
::
|
||||
++ sint :: reduce by reference
|
||||
|= $: :: hod: expand holds
|
||||
::
|
||||
@ -10911,6 +10914,39 @@
|
||||
%- ~(gas in *(set type))
|
||||
(turn leg |=([p=type q=hoon] (play(sut p) q)))
|
||||
::
|
||||
++ sink
|
||||
~/ %sink
|
||||
|^ ^- cord
|
||||
?- sut
|
||||
%void 'void'
|
||||
%noun 'noun'
|
||||
[%atom *] (rap 3 'atom ' p.sut ' ' ?~(q.sut '~' u.q.sut) ~)
|
||||
[%cell *] (rap 3 'cell ' (mup p.sut) ' ' (mup q.sut) ~)
|
||||
[%face *] (rap 3 'face ' ?@(p.sut p.sut (mup p.sut)) ' ' (mup q.sut) ~)
|
||||
[%fork *] (rap 3 'fork ' (mup p.sut) ~)
|
||||
[%hint *] (rap 3 'hint ' (mup p.sut) ' ' (mup q.sut) ~)
|
||||
[%hold *] (rap 3 'hold ' (mup p.sut) ' ' (mup q.sut) ~)
|
||||
::
|
||||
[%core *]
|
||||
%+ rap 3
|
||||
:~ 'core '
|
||||
(mup p.sut)
|
||||
' '
|
||||
?~(p.p.q.sut '~' u.p.p.q.sut)
|
||||
' '
|
||||
q.p.q.sut
|
||||
' '
|
||||
r.p.q.sut
|
||||
' '
|
||||
(mup q.q.sut)
|
||||
' '
|
||||
(mup p.r.q.sut)
|
||||
==
|
||||
==
|
||||
::
|
||||
++ mup |=(* (scot %p (mug +<)))
|
||||
--
|
||||
::
|
||||
++ take
|
||||
|= [vit=vein duz=$-(type type)]
|
||||
^- (pair axis type)
|
||||
|
@ -1069,14 +1069,23 @@
|
||||
:::: :: (1d2)
|
||||
::
|
||||
+$ blew [p=@ud q=@ud] :: columns rows
|
||||
+$ belt :: old belt
|
||||
+$ belt :: client input
|
||||
$? bolt :: simple input
|
||||
$% [%mod mod=?(%ctl %met %hyp) key=bolt] :: w/ modifier
|
||||
[%txt p=(list @c)] :: utf32 text
|
||||
::TODO consider moving %hey, %rez, %yow here ::
|
||||
::TMP forward backwards-compatibility ::
|
||||
:: ::
|
||||
[%ctl p=@c] ::
|
||||
[%met p=@c] ::
|
||||
== == ::
|
||||
+$ bolt :: simple input
|
||||
$@ @c :: simple keystroke
|
||||
$% [%aro p=?(%d %l %r %u)] :: arrow key
|
||||
[%bac ~] :: true backspace
|
||||
[%ctl p=@c] :: control-key
|
||||
[%del ~] :: true delete
|
||||
[%met p=@c] :: meta-key
|
||||
[%hit r=@ud c=@ud] :: mouse click
|
||||
[%ret ~] :: return
|
||||
[%txt p=(list @c)] :: utf32 text
|
||||
== ::
|
||||
+$ blit :: old blit
|
||||
$% [%bel ~] :: make a noise
|
||||
@ -2102,6 +2111,7 @@
|
||||
[%g task:gall]
|
||||
[%i task:iris]
|
||||
[%j task:jael]
|
||||
[%$ %whiz ~]
|
||||
[@tas %meta vase]
|
||||
==
|
||||
:: full vane names are required in vanes
|
||||
|
@ -3661,7 +3661,7 @@
|
||||
=/ lower=@ud 1
|
||||
|-
|
||||
:: a should be excluded, so wait until we're past it
|
||||
?: =(lower +(a))
|
||||
?: (gte lower +(a))
|
||||
acc
|
||||
=/ res=(set tako) (reachable-takos (~(got by hit.dom) lower))
|
||||
$(acc (~(uni in acc) res), lower +(lower))
|
||||
@ -3669,7 +3669,7 @@
|
||||
=| acc=(set tako)
|
||||
=/ upper=@ud b
|
||||
|-
|
||||
?: =(upper a)
|
||||
?: (lte upper a)
|
||||
acc
|
||||
=/ res=(set tako) (reachable-takos (~(got by hit.dom) upper))
|
||||
$(acc (~(uni in acc) res), upper (dec upper))
|
||||
|
@ -106,7 +106,6 @@
|
||||
%flow +>
|
||||
%harm +>
|
||||
%hail (send %hey ~)
|
||||
%belt (send `dill-belt`p.kyz)
|
||||
%text (from %out (tuba p.kyz))
|
||||
%crud :: (send `dill-belt`[%cru p.kyz q.kyz])
|
||||
(crud p.kyz q.kyz)
|
||||
@ -116,6 +115,18 @@
|
||||
%pack (dump kyz)
|
||||
%crop (dump trim+p.kyz)
|
||||
%verb (pass /verb %$ kyz)
|
||||
::
|
||||
%belt
|
||||
%- send
|
||||
::TMP forwards compatibility with next-dill
|
||||
::
|
||||
?@ p.kyz [%txt p.kyz ~]
|
||||
?: ?=(%hit -.p.kyz) [%txt ~]
|
||||
?. ?=(%mod -.p.kyz) p.kyz
|
||||
=/ =@c
|
||||
?@ key.p.kyz key.p.kyz
|
||||
?:(?=(?(%bac %del %ret) -.key.p.kyz) `@`-.key.p.kyz ~-)
|
||||
?:(?=(%met mod.p.kyz) [%met c] [%ctl c])
|
||||
==
|
||||
::
|
||||
++ crud
|
||||
|
@ -30,6 +30,9 @@
|
||||
$% [%rest p=@da]
|
||||
[%wait p=@da]
|
||||
== ==
|
||||
$: %c
|
||||
$>(%warp task:clay)
|
||||
==
|
||||
:: %d: to dill
|
||||
::
|
||||
$: %d
|
||||
@ -53,6 +56,12 @@
|
||||
$: %gall
|
||||
gift:gall
|
||||
:: $>(%unto gift:gall)
|
||||
::
|
||||
==
|
||||
$: %clay
|
||||
gift:clay
|
||||
:: $>(%writ gift:clay)
|
||||
::
|
||||
== ==
|
||||
--
|
||||
:: more structures
|
||||
@ -1231,9 +1240,9 @@
|
||||
::NOTE these will only fail if the mark and/or json types changed,
|
||||
:: since conversion failure also gets caught during first receive.
|
||||
:: we can't do anything about this, so consider it unsupported.
|
||||
?~ sign=(channel-event-to-sign channel-event) $
|
||||
?~ json=(sign-to-json request-id u.sign) $
|
||||
$(events [(event-json-to-wall id u.json) events])
|
||||
?~ sign=(channel-event-to-sign channel-event) $
|
||||
?~ jive=(sign-to-json request-id u.sign) $
|
||||
$(events [(event-json-to-wall id +.u.jive) events])
|
||||
:: send the start event to the client
|
||||
::
|
||||
=^ http-moves state
|
||||
@ -1499,8 +1508,12 @@
|
||||
:: if conversion succeeds, we *can* send it. if the client is actually
|
||||
:: connected, we *will* send it immediately.
|
||||
::
|
||||
=/ json=(unit json)
|
||||
=/ jive=(unit (quip move json))
|
||||
(sign-to-json request-id sign)
|
||||
=/ json=(unit json)
|
||||
?~(jive ~ `+.u.jive)
|
||||
=? moves ?=(^ jive)
|
||||
(weld moves -.u.jive)
|
||||
=* sending &(?=([%| *] state.u.channel) ?=(^ json))
|
||||
::
|
||||
=/ next-id next-id.u.channel
|
||||
@ -1578,7 +1591,7 @@
|
||||
^= data
|
||||
%- wall-to-octs
|
||||
%+ event-json-to-wall next-id
|
||||
(need (sign-to-json request-id %kick ~))
|
||||
+:(need (sign-to-json request-id %kick ~))
|
||||
::
|
||||
complete=%.n
|
||||
==
|
||||
@ -1619,32 +1632,33 @@
|
||||
:: +sign-to-json: render sign from request-id as json channel event
|
||||
::
|
||||
++ sign-to-json
|
||||
~% %sign-to-json ..part ~
|
||||
|= [request-id=@ud =sign:agent:gall]
|
||||
^- (unit json)
|
||||
^- (unit (quip move json))
|
||||
:: for facts, we try to convert the result to json
|
||||
::
|
||||
=/ jsyn=(unit sign:agent:gall)
|
||||
?. ?=(%fact -.sign) `sign
|
||||
?: ?=(%json p.cage.sign) `sign
|
||||
=/ [from=(unit mark) jsyn=(unit sign:agent:gall)]
|
||||
?. ?=(%fact -.sign) [~ `sign]
|
||||
?: ?=(%json p.cage.sign) [~ `sign]
|
||||
:: find and use tube from fact mark to json
|
||||
::
|
||||
=* have=mark p.cage.sign
|
||||
=* desc=tape "from {(trip have)} to json"
|
||||
=/ tube=(unit tube:clay)
|
||||
=/ tuc=(unit (unit cage))
|
||||
(rof ~ %cc [our %home da+now] /[have]/json)
|
||||
?. ?=([~ ~ *] tuc) ~
|
||||
`!<(tube:clay q.u.u.tuc)
|
||||
?~ tube
|
||||
((slog leaf+"eyre: no tube {desc}" ~) ~)
|
||||
::
|
||||
=/ res (mule |.((u.tube q.cage.sign)))
|
||||
?: ?=(%& -.res)
|
||||
`[%fact %json p.res]
|
||||
((slog leaf+"eyre: failed tube {desc}" ~) ~)
|
||||
::
|
||||
=/ convert=(unit vase)
|
||||
=/ cag=(unit (unit cage))
|
||||
(rof ~ %cf [our %home da+now] /[have]/json)
|
||||
?. ?=([~ ~ *] cag) ~
|
||||
`q.u.u.cag
|
||||
?~ convert
|
||||
((slog leaf+"eyre: no convert {desc}" ~) [~ ~])
|
||||
~| "conversion failed {desc}"
|
||||
[`have `[%fact %json (slym u.convert q.q.cage.sign)]]
|
||||
?~ jsyn ~
|
||||
%- some
|
||||
:- ?~ from ~
|
||||
:_ ~
|
||||
:^ duct %pass /conversion-cache/[u.from]
|
||||
[%c %warp our %home `[%sing %f da+now /[u.from]/json]]
|
||||
=* sign u.jsyn
|
||||
=, enjs:format
|
||||
%- pairs
|
||||
@ -1665,7 +1679,7 @@
|
||||
:- 'json'
|
||||
~| [%unexpected-fact-mark p.cage.sign]
|
||||
?> =(%json p.cage.sign)
|
||||
;;(json q.q.cage.sign)
|
||||
!<(json q.cage.sign)
|
||||
==
|
||||
::
|
||||
%kick
|
||||
@ -2320,14 +2334,15 @@
|
||||
::
|
||||
|^ ^- [(list move) _http-server-gate]
|
||||
::
|
||||
?+ i.wire
|
||||
~|([%bad-take-wire wire] !!)
|
||||
?+ i.wire
|
||||
~|([%bad-take-wire wire] !!)
|
||||
::
|
||||
%run-app-request run-app-request
|
||||
%watch-response watch-response
|
||||
%sessions sessions
|
||||
%channel channel
|
||||
%acme acme-ack
|
||||
%run-app-request run-app-request
|
||||
%watch-response watch-response
|
||||
%sessions sessions
|
||||
%channel channel
|
||||
%acme acme-ack
|
||||
%conversion-cache `http-server-gate
|
||||
==
|
||||
::
|
||||
++ run-app-request
|
||||
|
@ -159,7 +159,10 @@
|
||||
~< %slog.[0 leaf+"gall: molted"]
|
||||
:: +molt should never notify its client about agent changes
|
||||
::
|
||||
=- [(skip -< |=(move ?=([* %give %onto *] +<))) ->]
|
||||
=- :_ ->
|
||||
%+ welp
|
||||
(skip -< |=(move ?=([* %give %onto *] +<)))
|
||||
[^duct %pass /whiz/gall %$ %whiz ~]~
|
||||
=/ adult adult-core
|
||||
=. state.adult
|
||||
[%7 system-duct outstanding contacts yokes=~ blocked]:spore
|
||||
|
@ -3391,6 +3391,11 @@
|
||||
:: :: ++no:dejs:format
|
||||
++ no :: number as cord
|
||||
|=(jon=json ?>(?=([%n *] jon) p.jon))
|
||||
:: :: ++nu:dejs:format
|
||||
++ nu :: parse number as hex
|
||||
|= jon=json
|
||||
?> ?=([%s *] jon)
|
||||
(rash p.jon hex)
|
||||
:: :: ++of:dejs:format
|
||||
++ of :: object as frond
|
||||
|* wer=(pole [cord fist])
|
||||
@ -3440,6 +3445,11 @@
|
||||
=/ ten ~|(key+key.wer (wit.wer (~(get by jom) key.wer)))
|
||||
?~(t.wer ten [ten ((ou-raw t.wer) jom)])
|
||||
==
|
||||
:: :: ++oj:dejs:format
|
||||
++ oj :: object as jug
|
||||
|* =fist
|
||||
^- $-(json (jug cord _(fist *json)))
|
||||
(om (as fist))
|
||||
:: :: ++om:dejs:format
|
||||
++ om :: object as map
|
||||
|* wit=fist
|
||||
@ -3466,6 +3476,12 @@
|
||||
:: :: ++sa:dejs:format
|
||||
++ sa :: string as tape
|
||||
|=(jon=json ?>(?=([%s *] jon) (trip p.jon)))
|
||||
:: :: ++sd:dejs:format
|
||||
++ sd :: string @ud as date
|
||||
|= jon=json
|
||||
^- @da
|
||||
?> ?=(%s -.jon)
|
||||
`@da`(rash p.jon dem:ag)
|
||||
:: :: ++se:dejs:format
|
||||
++ se :: string as aura
|
||||
|= aur=@tas
|
||||
@ -3580,6 +3596,15 @@
|
||||
?. ?=([%s *] jon) ~
|
||||
(bind (stud:chrono:userlib p.jon) |=(a=date (year a)))
|
||||
::
|
||||
++ dank :: tank
|
||||
^- $-(json (unit tank))
|
||||
%+ re *tank |. ~+
|
||||
%- of :~
|
||||
leaf+sa
|
||||
palm+(ot style+(ot mid+sa cap+sa open+sa close+sa ~) lines+(ar dank) ~)
|
||||
rose+(ot style+(ot mid+sa open+sa close+sa ~) lines+(ar dank) ~)
|
||||
==
|
||||
::
|
||||
++ di :: millisecond date
|
||||
(cu from-unix-ms:chrono:userlib ni)
|
||||
::
|
||||
@ -3653,6 +3678,12 @@
|
||||
|* [pre=* wit=fist]
|
||||
(cu |*(* [pre +<]) wit)
|
||||
::
|
||||
++ re :: recursive reparsers
|
||||
|* [gar=* sef=_|.(fist)]
|
||||
|= jon=json
|
||||
^- (unit _gar)
|
||||
((sef) jon)
|
||||
::
|
||||
++ sa :: string as tape
|
||||
|= jon=json
|
||||
?.(?=([%s *] jon) ~ (some (trip p.jon)))
|
||||
|
@ -49,7 +49,7 @@
|
||||
^- hexb:bc
|
||||
%- flip:byt:bc
|
||||
%- sha256:bc
|
||||
(script-pubkey:bc a)
|
||||
(to-script-pubkey:adr:bc a)
|
||||
::
|
||||
++ parse-json-rpc
|
||||
|= =json
|
||||
|
@ -7,7 +7,12 @@
|
||||
^- form:m
|
||||
=+ !<([~ hash=@uv] arg)
|
||||
=/ url "https://bootstrap.urbit.org/glob-{(scow %uv hash)}.glob"
|
||||
;< =cord bind:m (fetch-cord:strandio url)
|
||||
~| failed-glob+hash
|
||||
=+ ;;(=glob:glob (cue cord))
|
||||
;< =glob:glob bind:m
|
||||
%+ (retry:strandio ,glob:glob) `5
|
||||
=/ n (strand ,(unit glob:glob))
|
||||
;< =cord bind:n (fetch-cord:strandio url)
|
||||
%- pure:n
|
||||
%- mole
|
||||
|.
|
||||
;;(=glob:glob (cue cord))
|
||||
(pure:m !>(glob))
|
||||
|
@ -151,9 +151,11 @@
|
||||
::
|
||||
++ check-all-match
|
||||
|= v=match-vector
|
||||
=+ k=(to-key blockhash.v)
|
||||
=/ b=hexb (from-cord:hxb (crip blockhash.v))
|
||||
=/ inc=(list [address hexb]) (turn inc-spks.v |=(h=hexb [*address h]))
|
||||
=/ exc=(list [address hexb]) (turn exc-spks.v |=(h=hexb [*address h]))
|
||||
%+ expect-eq
|
||||
!>(`(set hexb)`(sy inc-spks.v))
|
||||
!>(`(set hexb)`(all-match filter.v k (weld inc-spks.v exc-spks.v)))
|
||||
!>(`(set [address hexb])`(sy inc))
|
||||
!>(`(set [address hexb])`(all-match filter.v b (weld inc exc)))
|
||||
--
|
||||
--
|
||||
|
@ -5,4 +5,4 @@ dojo:
|
||||
|
||||
it should return with the following hash:
|
||||
|
||||
`0v2.3qak4.al612.8m1ig.kg03r.mfide`
|
||||
`0v1.9p61c.bd4vn.deevh.0ldbq.fkqo3`
|
||||
|
@ -28,15 +28,7 @@ export default class Balance extends Component {
|
||||
|
||||
copyAddress(arg) {
|
||||
let address = this.props.state.address;
|
||||
function listener(e) {
|
||||
e.clipboardData.setData('text/plain', address);
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
document.addEventListener('copy', listener);
|
||||
document.execCommand('copy');
|
||||
document.removeEventListener('copy', listener);
|
||||
|
||||
navigator.clipboard.writeText(address);
|
||||
this.props.api.btcWalletCommand({'gen-new-address': null});
|
||||
|
||||
if (arg === 'button'){
|
||||
@ -122,8 +114,7 @@ export default class Balance extends Component {
|
||||
style={{cursor: sendDisabled ? "default" : "pointer" }}
|
||||
borderColor="none"
|
||||
borderRadius="24px"
|
||||
py="24px"
|
||||
px="24px"
|
||||
height="48px"
|
||||
onClick={() => this.setState({sending: true})}
|
||||
/>
|
||||
<Button children={(this.state.copiedButton) ? "Address Copied!" : "Copy Address"}
|
||||
@ -136,8 +127,7 @@ export default class Balance extends Component {
|
||||
style={{cursor: (this.state.copiedButton) ? "default" : "pointer"}}
|
||||
borderColor="none"
|
||||
borderRadius="24px"
|
||||
py="24px"
|
||||
px="24px"
|
||||
height="48px"
|
||||
onClick={() => {this.copyAddress('button')}}
|
||||
/>
|
||||
</Row>
|
||||
|
@ -23,6 +23,9 @@ export default class Body extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const cardWidth = window.innerWidth <= 475 ? '350px' : '400px'
|
||||
|
||||
if (!this.props.loaded) {
|
||||
return (
|
||||
<Box display="flex" width="100%" height="100%" alignItems="center" justifyContent="center">
|
||||
@ -41,7 +44,7 @@ export default class Body extends Component {
|
||||
<Col
|
||||
display='flex'
|
||||
flexDirection='column'
|
||||
width='400px'
|
||||
width={cardWidth}
|
||||
>
|
||||
<Header settings={true} state={this.props.state}/>
|
||||
<Settings state={this.props.state}
|
||||
@ -54,7 +57,7 @@ export default class Body extends Component {
|
||||
<Col
|
||||
display='flex'
|
||||
flexDirection='column'
|
||||
width='400px'
|
||||
width={cardWidth}
|
||||
>
|
||||
<Header settings={false} state={this.props.state}/>
|
||||
{ (!this.props.warning) ? null : <Warning api={this.props.api}/>}
|
||||
|
@ -221,10 +221,12 @@ export default class BridgeInvoice extends Component {
|
||||
mr={3}
|
||||
fontSize={1}
|
||||
borderRadius='24px'
|
||||
py='24px'
|
||||
px='24px'
|
||||
border='none'
|
||||
height='48px'
|
||||
onClick={() => this.sendBitcoin(txHex)}
|
||||
disabled={!this.state.ready || error}
|
||||
disabled={!this.state.ready || error || this.state.broadcasting}
|
||||
color={(this.state.ready && !error && !this.state.broadcasting) ? "white" : "lighterGray"}
|
||||
backgroundColor={(this.state.ready && !error && !this.state.broadcasting) ? "green" : "veryLightGray"}
|
||||
style={{cursor: (this.state.ready && !error) ? "pointer" : "default"}}
|
||||
/>
|
||||
{this.state.broadcasting ? <LoadingSpinner mr={3}/> : null}
|
||||
|
@ -276,8 +276,7 @@ export default class Invoice extends Component {
|
||||
borderRadius='24px'
|
||||
color={(this.state.ready && !error && !this.state.broadcasting) ? "white" : "lighterGray"}
|
||||
backgroundColor={(this.state.ready && !error && !this.state.broadcasting) ? "green" : "veryLightGray"}
|
||||
py='24px'
|
||||
px='24px'
|
||||
height='48px'
|
||||
onClick={() => this.sendBitcoin(this.state.masterTicket, psbt)}
|
||||
disabled={!this.state.ready || error || this.state.broadcasting}
|
||||
style={{cursor: (this.state.ready && !error && !this.state.broadcasting) ? "pointer" : "default"}}
|
||||
|
@ -48,7 +48,7 @@ export default class Send extends Component {
|
||||
showModal: false,
|
||||
note: '',
|
||||
choosingSignMethod: false,
|
||||
signMethod: 'Sign Transaction',
|
||||
signMethod: 'bridge',
|
||||
};
|
||||
|
||||
this.initPayment = this.initPayment.bind(this);
|
||||
@ -86,7 +86,7 @@ export default class Send extends Component {
|
||||
}
|
||||
|
||||
setSignMethod(signMethod) {
|
||||
this.setState({signMethod});
|
||||
this.setState({signMethod, choosingSignMethod: false});
|
||||
}
|
||||
|
||||
checkPayee(e){
|
||||
@ -204,7 +204,7 @@ export default class Send extends Component {
|
||||
const signReady = (this.state.ready && (parseInt(this.state.satsAmount) > 0)) && !signing;
|
||||
|
||||
let invoice = null;
|
||||
if (signMethod === 'Sign Transaction') {
|
||||
if (signMethod === 'masterTicket') {
|
||||
invoice =
|
||||
<Invoice
|
||||
network={network}
|
||||
@ -218,7 +218,7 @@ export default class Send extends Component {
|
||||
satsAmount={satsAmount}
|
||||
state={this.props.state}
|
||||
/>
|
||||
} else if (signMethod === 'Sign with Bridge') {
|
||||
} else if (signMethod === 'bridge') {
|
||||
invoice =
|
||||
<BridgeInvoice
|
||||
state={this.props.state}
|
||||
@ -430,8 +430,7 @@ export default class Send extends Component {
|
||||
fontWeight='bold'
|
||||
borderRadius='24px'
|
||||
mr={2}
|
||||
py='24px'
|
||||
px='24px'
|
||||
height='48px'
|
||||
onClick={() => this.toggleSignMethod(choosingSignMethod)}
|
||||
color={signReady ? 'white' : 'lighterGray'}
|
||||
backgroundColor={signReady ? 'rgba(33, 157, 255, 0.2)' : 'veryLightGray'}
|
||||
@ -439,6 +438,17 @@ export default class Send extends Component {
|
||||
border='none'
|
||||
style={{cursor: signReady ? 'pointer' : 'default'}} />
|
||||
</Row>
|
||||
{signMethod === 'masterTicket' &&
|
||||
<Row
|
||||
mt={4}
|
||||
alignItems='center'
|
||||
>
|
||||
<Icon icon='Info' color='yellow' height={4} width={4}/>
|
||||
<Text fontSize="14px" fontWeight="regular" color="gray" ml={2}>
|
||||
We recommend that you sign transactions using Bridge to protect your master ticket.
|
||||
</Text>
|
||||
</Row>
|
||||
}
|
||||
</Col>
|
||||
}
|
||||
</>
|
||||
|
@ -19,31 +19,28 @@ export default function Signer(props) {
|
||||
backgroundColor='transparent'
|
||||
fontWeight='bold'
|
||||
cursor='pointer'
|
||||
color={(signMethod === 'Sign Transaction') ? 'blue' : 'lightBlue'}
|
||||
py='24px'
|
||||
px='24px'
|
||||
onClick={() => setSignMethod('Sign Transaction')}
|
||||
children='Sign Transaction' />
|
||||
color={(signMethod === 'masterTicket') ? 'blue' : 'lightBlue'}
|
||||
height='48px'
|
||||
onClick={() => setSignMethod('masterTicket')}
|
||||
children='Sign with Master Ticket' />
|
||||
<Button
|
||||
border='none'
|
||||
backgroundColor='transparent'
|
||||
fontWeight='bold'
|
||||
cursor='pointer'
|
||||
color={(signMethod === 'Sign with Bridge') ? 'blue' : 'lightBlue'}
|
||||
py='24px'
|
||||
px='24px'
|
||||
onClick={() => setSignMethod('Sign with Bridge')}
|
||||
color={(signMethod === 'bridge') ? 'blue' : 'lightBlue'}
|
||||
height='48px'
|
||||
onClick={() => setSignMethod('bridge')}
|
||||
children='Sign with Bridge' />
|
||||
</Box>
|
||||
:
|
||||
<Button
|
||||
primary
|
||||
children={signMethod}
|
||||
children={signMethod === 'bridge' ? 'Sign with Bridge' : 'Sign with Master Ticket'}
|
||||
fontSize={1}
|
||||
fontWeight='bold'
|
||||
borderRadius='24px'
|
||||
py='24px'
|
||||
px='24px'
|
||||
height='48px'
|
||||
onClick={initPayment}
|
||||
color={signReady ? 'white' : 'lighterGray'}
|
||||
backgroundColor={signReady ? 'blue' : 'veryLightGray'}
|
||||
|
@ -22,7 +22,7 @@ export default class WalletModal extends Component {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
mode: 'masterTicket',
|
||||
mode: 'xpub',
|
||||
masterTicket: '',
|
||||
confirmedMasterTicket: '',
|
||||
xpub: '',
|
||||
@ -103,13 +103,15 @@ export default class WalletModal extends Component {
|
||||
Step 2 of 2: Import your extended public key
|
||||
</Text>
|
||||
</Row>
|
||||
<Box mt={3}>
|
||||
<Text fontSize="14px" fontWeight="regular" color="gray">
|
||||
To begin, you'll need to derive an XPub Bitcoin address using your
|
||||
master ticket.
|
||||
<a fontSize="14px" target="_blank" href="https://urbit.org/bitcoin-wallet"> Learn More</a>
|
||||
<Row
|
||||
mt={3}
|
||||
alignItems='center'
|
||||
>
|
||||
<Icon icon='Info' color='yellow' height={4} width={4}/>
|
||||
<Text fontSize="14px" fontWeight="regular" color="gray" ml={2}>
|
||||
We recommend that you import your wallet using Bridge to protect your master ticket.
|
||||
</Text>
|
||||
</Box>
|
||||
</Row>
|
||||
<Box
|
||||
display='flex'
|
||||
alignItems='center'
|
||||
@ -126,7 +128,7 @@ export default class WalletModal extends Component {
|
||||
error: false
|
||||
})}/>}
|
||||
<Text fontSize="14px" fontWeight="500">
|
||||
{this.state.confirmingMasterTicket ? 'Confirm Master Key' : 'Master Key'}
|
||||
{this.state.confirmingMasterTicket ? 'Confirm Master Ticket' : 'Master Ticket'}
|
||||
</Text>
|
||||
</Box>
|
||||
<Row alignItems="center">
|
||||
@ -155,37 +157,38 @@ export default class WalletModal extends Component {
|
||||
</Text>
|
||||
</Row>
|
||||
}
|
||||
<Box mt={3} mb={3}>
|
||||
<Text fontSize="14px" fontWeight="regular"
|
||||
color={(inputDisabled) ? "lighterGray" : "gray"}
|
||||
style={{cursor: (inputDisabled) ? "default" : "pointer"}}
|
||||
<Row mt={3}>
|
||||
<Button
|
||||
primary
|
||||
color="black"
|
||||
backgroundColor="veryLightGray"
|
||||
borderColor="veryLightGray"
|
||||
children="Cancel"
|
||||
fontSize="14px"
|
||||
mr={2}
|
||||
style={{cursor: "pointer"}}
|
||||
onClick={() => {this.setState({mode: 'xpub', masterTicket: '', xpub: '', readyToSubmit: false})}}
|
||||
/>
|
||||
<Button
|
||||
primary
|
||||
disabled={buttonDisabled}
|
||||
children="Next Step"
|
||||
fontSize="14px"
|
||||
style={{cursor: buttonDisabled ? "default" : "pointer"}}
|
||||
onClick={() => {
|
||||
if (inputDisabled) return;
|
||||
this.setState({mode: 'xpub', xpub: '', masterTicket: '', readyToSubmit: false})
|
||||
}}
|
||||
>
|
||||
Manually import your extended public key ->
|
||||
</Text>
|
||||
</Box>
|
||||
<Button
|
||||
primary
|
||||
disabled={buttonDisabled}
|
||||
children="Next Step"
|
||||
fontSize="14px"
|
||||
style={{cursor: buttonDisabled ? "default" : "pointer"}}
|
||||
onClick={() => {
|
||||
if (!this.state.confirmingMasterTicket) {
|
||||
this.setState({confirmingMasterTicket: true});
|
||||
} else {
|
||||
if (this.state.masterTicket === this.state.confirmedMasterTicket) {
|
||||
this.setState({error: false});
|
||||
this.submitMasterTicket(this.state.masterTicket);
|
||||
if (!this.state.confirmingMasterTicket) {
|
||||
this.setState({confirmingMasterTicket: true});
|
||||
} else {
|
||||
this.setState({error: true});
|
||||
if (this.state.masterTicket === this.state.confirmedMasterTicket) {
|
||||
this.setState({error: false});
|
||||
this.submitMasterTicket(this.state.masterTicket);
|
||||
} else {
|
||||
this.setState({error: true});
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}}
|
||||
/>
|
||||
</Row>
|
||||
</Box>
|
||||
);
|
||||
} else if (this.state.mode === 'xpub') {
|
||||
@ -203,7 +206,7 @@ export default class WalletModal extends Component {
|
||||
</Row>
|
||||
<Box mt={3}>
|
||||
<Text fontSize="14px" fontWeight="regular" color="gray">
|
||||
Visit bridge.urbit.org to obtain your key
|
||||
Visit <a href='https://bridge.urbit.org/?kind=xpub' target='_blank' style={{color: 'black'}} >bridge.urbit.org</a> to obtain your key
|
||||
</Text>
|
||||
</Box>
|
||||
<Box mt={3} mb={2}>
|
||||
@ -221,27 +224,27 @@ export default class WalletModal extends Component {
|
||||
autoCorrect="off"
|
||||
onChange={this.checkXPub}
|
||||
/>
|
||||
<Row mt={3}>
|
||||
<Button
|
||||
primary
|
||||
color="black"
|
||||
backgroundColor="veryLightGray"
|
||||
borderColor="veryLightGray"
|
||||
children="Cancel"
|
||||
fontSize="14px"
|
||||
mr={2}
|
||||
style={{cursor: "pointer"}}
|
||||
onClick={() => {this.setState({mode: 'masterTicket', masterTicket: '', xpub: '', readyToSubmit: false})}}
|
||||
/>
|
||||
<Button
|
||||
primary
|
||||
disabled={buttonDisabled}
|
||||
children="Next Step"
|
||||
fontSize="14px"
|
||||
style={{cursor: this.state.ready ? "pointer" : "default"}}
|
||||
onClick={() => { this.submitXPub(this.state.xpub) }}
|
||||
/>
|
||||
</Row>
|
||||
<Box mt={3} mb={3}>
|
||||
<Text fontSize="14px" fontWeight="regular"
|
||||
color={(inputDisabled) ? "lighterGray" : "gray"}
|
||||
style={{cursor: (inputDisabled) ? "default" : "pointer"}}
|
||||
onClick={() => {
|
||||
if (inputDisabled) return;
|
||||
this.setState({mode: 'masterTicket', xpub: '', masterTicket: '', readyToSubmit: false})
|
||||
}}
|
||||
>
|
||||
Import using master ticket ->
|
||||
</Text>
|
||||
</Box>
|
||||
<Button
|
||||
primary
|
||||
mt={3}
|
||||
disabled={buttonDisabled}
|
||||
children="Next Step"
|
||||
fontSize="14px"
|
||||
style={{cursor: this.state.ready ? "pointer" : "default"}}
|
||||
onClick={() => { this.submitXPub(this.state.xpub) }}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { Association, GraphNotifDescription, IndexedNotification, NotifIndex } from '@urbit/api';
|
||||
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
|
||||
import { BigInteger } from 'big-integer';
|
||||
import { getParentIndex } from '../lib/notification';
|
||||
import { dateToDa, decToUd } from '../lib/util';
|
||||
import {reduce} from '../reducers/hark-update';
|
||||
import {doOptimistically, optReduceState} from '../state/base';
|
||||
import { reduce } from '../reducers/hark-update';
|
||||
import { doOptimistically } from '../state/base';
|
||||
import useHarkState from '../state/hark';
|
||||
import { StoreState } from '../store/type';
|
||||
import BaseApi from './base';
|
||||
@ -62,7 +61,7 @@ export class HarkApi extends BaseApi<StoreState> {
|
||||
index
|
||||
}
|
||||
};
|
||||
await doOptimistically(useHarkState, action, this.harkAction.bind(this), [reduce])
|
||||
await doOptimistically(useHarkState, action, this.harkAction.bind(this), [reduce]);
|
||||
}
|
||||
|
||||
read(time: BigInteger, index: NotifIndex) {
|
||||
@ -81,6 +80,18 @@ export class HarkApi extends BaseApi<StoreState> {
|
||||
return this.actOnNotification('unread-note', time, index);
|
||||
}
|
||||
|
||||
readGroup(group: string) {
|
||||
return this.harkAction({
|
||||
'read-group': group
|
||||
});
|
||||
}
|
||||
|
||||
readGraph(graph: string) {
|
||||
return this.harkAction({
|
||||
'read-graph': graph
|
||||
});
|
||||
}
|
||||
|
||||
dismissReadCount(graph: string, index: string) {
|
||||
return this.harkAction({
|
||||
'read-count': {
|
||||
|
@ -5,7 +5,7 @@ import React, {
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
useState
|
||||
} from 'react';
|
||||
import _ from 'lodash';
|
||||
import { getChord } from '~/logic/lib/util';
|
||||
@ -13,10 +13,9 @@ import { getChord } from '~/logic/lib/util';
|
||||
type Handler = (e: KeyboardEvent) => void;
|
||||
const fallback: ShortcutContextProps = {
|
||||
add: () => {},
|
||||
remove: () => {},
|
||||
remove: () => {}
|
||||
};
|
||||
|
||||
|
||||
export const ShortcutContext = createContext(fallback);
|
||||
export interface ShortcutContextProps {
|
||||
add: (cb: (e: KeyboardEvent) => void, key: string) => void;
|
||||
@ -27,19 +26,19 @@ export function ShortcutContextProvider({ children }) {
|
||||
const handlerRef = useRef<Handler>(() => {});
|
||||
|
||||
const add = useCallback((cb: Handler, key: string) => {
|
||||
setShortcuts((s) => ({ ...s, [key]: cb }));
|
||||
setShortcuts(s => ({ ...s, [key]: cb }));
|
||||
}, []);
|
||||
const remove = useCallback((cb: Handler, key: string) => {
|
||||
setShortcuts((s) => (key in s ? _.omit(s, key) : s));
|
||||
setShortcuts(s => (key in s ? _.omit(s, key) : s));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
function onKeypress(e: KeyboardEvent) {
|
||||
handlerRef.current(e);
|
||||
}
|
||||
document.addEventListener('keypress', onKeypress);
|
||||
document.addEventListener('keydown', onKeypress);
|
||||
return () => {
|
||||
document.removeEventListener('keypress', onKeypress);
|
||||
document.removeEventListener('keydown', onKeypress);
|
||||
};
|
||||
}, []);
|
||||
|
||||
@ -50,7 +49,7 @@ export function ShortcutContextProvider({ children }) {
|
||||
};
|
||||
}, [shortcuts]);
|
||||
|
||||
const value = useMemo(() => ({ add, remove }), [add, remove])
|
||||
const value = useMemo(() => ({ add, remove }), [add, remove]);
|
||||
|
||||
return (
|
||||
<ShortcutContext.Provider value={value}>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import urbitOb from 'urbit-ob';
|
||||
import { parsePermalink, permalinkToReference } from '~/logic/lib/permalinks';
|
||||
|
||||
const URL_REGEX = new RegExp(String(/^([^[\]]*?)(([\w\-\+]+:\/\/)[-a-zA-Z0-9:@;?&=\/%\+\.\*!'\(\),\$_\{\}\^~\[\]`#|]+[\w/])([\s\S]*)/.source));
|
||||
const URL_REGEX = new RegExp(String(/^([^[\]]*?)(([\w\-\+]+:\/\/)[-a-zA-Z0-9:@;?&=\/%\+\.\*!'\(\),\$_\{\}\^~\[\]`#|]+[-a-zA-Z0-9:@;?&=\/%\+\*!'\(\)\$_\{\}\^~\[\]`#|])([\s\S]*)/.source));
|
||||
|
||||
const PATP_REGEX = /^([\s\S]*?)(~[a-z_-]+)([\s\S]*)/;
|
||||
|
||||
|
@ -93,4 +93,24 @@ describe('tokenizeMessage', () => {
|
||||
expect(three).toEqual(' test ');
|
||||
expect(hastuc).toEqual('~hastuc-dibtux');
|
||||
});
|
||||
it('should tokenize a url with a par', () => {
|
||||
const example = 'test https://en.wikipedia.org/wiki/Turbo_(gastropod)';
|
||||
|
||||
const [{ text }, { url }] = tokenizeMessage(example);
|
||||
expect(text).toBe('test ');
|
||||
expect(url).toBe('https://en.wikipedia.org/wiki/Turbo_(gastropod)');
|
||||
});
|
||||
it('should ignore ending commas', () => {
|
||||
const example = 'https://tlon.io/test, foo';
|
||||
const [{ url }, { text }] = tokenizeMessage(example);
|
||||
expect(text).toBe(', foo');
|
||||
expect(url).toBe('https://tlon.io/test');
|
||||
});
|
||||
|
||||
it('should ignore ending dots', () => {
|
||||
const example = 'https://tlon.io/test. foo';
|
||||
const [{ url }, { text }] = tokenizeMessage(example);
|
||||
expect(text).toBe('. foo');
|
||||
expect(url).toBe('https://tlon.io/test');
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { DragEvent, useCallback, useEffect, useState } from 'react';
|
||||
|
||||
function validateDragEvent(e: DragEvent): FileList | File[] | true | null {
|
||||
const files: File[] = [];
|
||||
@ -37,7 +37,7 @@ export function useFileDrag(dragged: (f: FileList | File[], e: DragEvent) => voi
|
||||
const [dragging, setDragging] = useState(false);
|
||||
|
||||
const onDragEnter = useCallback(
|
||||
(e: DragEvent) => {
|
||||
(e: DragEvent<HTMLDivElement>) => {
|
||||
if (!validateDragEvent(e)) {
|
||||
return;
|
||||
}
|
||||
@ -47,7 +47,7 @@ export function useFileDrag(dragged: (f: FileList | File[], e: DragEvent) => voi
|
||||
);
|
||||
|
||||
const onDrop = useCallback(
|
||||
(e: DragEvent) => {
|
||||
(e: DragEvent<HTMLDivElement>) => {
|
||||
setDragging(false);
|
||||
const files = validateDragEvent(e);
|
||||
if (!files || files === true) {
|
||||
@ -60,7 +60,7 @@ export function useFileDrag(dragged: (f: FileList | File[], e: DragEvent) => voi
|
||||
);
|
||||
|
||||
const onDragOver = useCallback(
|
||||
(e: DragEvent) => {
|
||||
(e: DragEvent<HTMLDivElement>) => {
|
||||
if (!validateDragEvent(e)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import _ from 'lodash';
|
||||
import { patp2dec } from 'urbit-ob';
|
||||
import f, { compose, memoize } from 'lodash/fp';
|
||||
import f from 'lodash/fp';
|
||||
import { Association, Contact, Patp } from '@urbit/api';
|
||||
import produce, { enableMapSet } from 'immer';
|
||||
import { enableMapSet } from 'immer';
|
||||
import useSettingsState from '../state/settings';
|
||||
/* eslint-disable max-lines */
|
||||
import anyAscii from 'any-ascii';
|
||||
@ -50,14 +50,14 @@ export function parentPath(path: string) {
|
||||
return _.dropRight(path.split('/'), 1).join('/');
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* undefined -> initial
|
||||
* null -> disabled feed
|
||||
* string -> enabled feed
|
||||
*/
|
||||
export function getFeedPath(association: Association): string | null | undefined {
|
||||
const { metadata } = association;
|
||||
if(metadata.config && 'group' in metadata?.config && metadata.config?.group) {
|
||||
const { metadata = { config: {} } } = association;
|
||||
if (metadata.config && 'group' in metadata?.config && metadata.config?.group) {
|
||||
if ('resource' in metadata.config.group) {
|
||||
return metadata.config.group.resource;
|
||||
}
|
||||
@ -67,23 +67,26 @@ export function getFeedPath(association: Association): string | null | undefined
|
||||
}
|
||||
|
||||
export const getChord = (e: KeyboardEvent) => {
|
||||
let chord = [e.key];
|
||||
const chord = [e.key];
|
||||
if(e.metaKey) {
|
||||
chord.unshift('meta');
|
||||
}
|
||||
if(e.ctrlKey) {
|
||||
chord.unshift('ctrl');
|
||||
}
|
||||
if(e.shiftKey) {
|
||||
chord.unshift('shift');
|
||||
}
|
||||
return chord.join('+');
|
||||
}
|
||||
};
|
||||
|
||||
export function getResourcePath(workspace: Workspace, path: string, joined: boolean, mod: string) {
|
||||
const base = workspace.type === 'group'
|
||||
? `/~landscape${workspace.group}`
|
||||
: workspace.type === 'home'
|
||||
? `/~landscape/home`
|
||||
: `/~landscape/messages`;
|
||||
return `${base}/${joined ? 'resource' : 'join'}/${mod}${path}`
|
||||
? '/~landscape/home'
|
||||
: '/~landscape/messages';
|
||||
return `${base}/${joined ? 'resource' : 'join'}/${mod}${path}`;
|
||||
}
|
||||
|
||||
const DA_UNIX_EPOCH = bigInt('170141184475152167957503069145530368000'); // `@ud` ~1970.1.1
|
||||
@ -135,14 +138,14 @@ export function decToUd(str: string): string {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Clamp a number between a min and max
|
||||
*/
|
||||
export function clamp(x: number, min: number, max: number) {
|
||||
return Math.max(min, Math.min(max, x));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Euclidean modulo
|
||||
*/
|
||||
export function modulo(x: number, mod: number) {
|
||||
@ -355,6 +358,7 @@ export function stringToTa(str: string) {
|
||||
add = '~~';
|
||||
break;
|
||||
default:
|
||||
// eslint-disable-next-line
|
||||
const charCode = str.charCodeAt(i);
|
||||
if (
|
||||
(charCode >= 97 && charCode <= 122) || // a-z
|
||||
@ -413,7 +417,7 @@ export function stringToSymbol(str: string) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
/*
|
||||
* Formats a numbers as a `@ud` inserting dot where needed
|
||||
*/
|
||||
export function numToUd(num: number) {
|
||||
@ -428,7 +432,7 @@ export function numToUd(num: number) {
|
||||
}
|
||||
|
||||
export function patpToUd(patp: Patp) {
|
||||
return numToUd(patp2dec(patp))
|
||||
return numToUd(patp2dec(patp));
|
||||
}
|
||||
|
||||
export function usePreventWindowUnload(shouldPreventDefault: boolean, message = 'You have unsaved changes. Are you sure you want to exit?') {
|
||||
@ -443,7 +447,7 @@ export function usePreventWindowUnload(shouldPreventDefault: boolean, message =
|
||||
window.onbeforeunload = handleBeforeUnload;
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
// @ts-ignore
|
||||
// @ts-ignore need better window typings
|
||||
window.onbeforeunload = undefined;
|
||||
};
|
||||
}, [shouldPreventDefault]);
|
||||
@ -484,8 +488,8 @@ export function withHovering<T>(Component: React.ComponentType<T>) {
|
||||
return React.forwardRef((props, ref) => {
|
||||
const { hovering, bind } = useHovering();
|
||||
// @ts-ignore needs type signature on return?
|
||||
return <Component ref={ref} hovering={hovering} bind={bind} {...props} />
|
||||
})
|
||||
return <Component ref={ref} hovering={hovering} bind={bind} {...props} />;
|
||||
});
|
||||
}
|
||||
|
||||
const DM_REGEX = /ship\/~([a-z]|-)*\/dm--/;
|
||||
@ -500,14 +504,14 @@ export function getItemTitle(association: Association): string {
|
||||
return association.metadata.title ?? association.resource ?? '';
|
||||
}
|
||||
|
||||
export const svgDataURL = (svg) => 'data:image/svg+xml;base64,' + btoa(svg);
|
||||
export const svgDataURL = svg => 'data:image/svg+xml;base64,' + btoa(svg);
|
||||
|
||||
export const svgBlobURL = (svg) => URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }));
|
||||
export const svgBlobURL = svg => URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }));
|
||||
|
||||
export const favicon = () => {
|
||||
let background = '#ffffff';
|
||||
const contacts = useContactState.getState().contacts;
|
||||
if (contacts.hasOwnProperty(`~${window.ship}`)) {
|
||||
if (Object.prototype.hasOwnProperty.call(contacts, `~${window.ship}`)) {
|
||||
background = `#${uxToHex(contacts[`~${window.ship}`].color)}`;
|
||||
}
|
||||
const foreground = foregroundFromBackground(background);
|
||||
@ -518,4 +522,4 @@ export const favicon = () => {
|
||||
colors: [background, foreground]
|
||||
});
|
||||
return svg;
|
||||
}
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { NotificationGraphConfig, Timebox, Unreads, dateToDa } from "@urbit/api";
|
||||
import { NotificationGraphConfig, Timebox, Unreads } from '@urbit/api';
|
||||
import { patp2dec } from 'urbit-ob';
|
||||
import BigIntOrderedMap from "@urbit/api/lib/BigIntOrderedMap";
|
||||
import {useCallback} from "react";
|
||||
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
// import { harkGraphHookReducer, harkGroupHookReducer, harkReducer } from "~/logic/subscription/hark";
|
||||
import { createState } from './base';
|
||||
@ -70,7 +70,7 @@ const useHarkState = createState<HarkState>('Hark', {
|
||||
}, ['unreadNotes', 'notifications', 'archivedNotifications', 'unreads', 'notificationsCount']);
|
||||
|
||||
export function useHarkDm(ship: string) {
|
||||
return useHarkState(useCallback(s => {
|
||||
return useHarkState(useCallback((s) => {
|
||||
return s.unreads.graph[`/ship/~${window.ship}/dm-inbox`]?.[`/${patp2dec(ship)}`];
|
||||
}, [ship]));
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ export interface ShortcutMapping {
|
||||
navForward: string;
|
||||
navBack: string;
|
||||
hideSidebar: string;
|
||||
readGroup: string;
|
||||
}
|
||||
|
||||
export interface SettingsState extends BaseState<SettingsState> {
|
||||
@ -77,7 +78,8 @@ const useSettingsState = createState<SettingsState>('Settings', {
|
||||
cycleBack: 'ctrl+;',
|
||||
navForward: 'ctrl+]',
|
||||
navBack: 'ctrl+[',
|
||||
hideSidebar: 'ctrl+\\'
|
||||
hideSidebar: 'ctrl+\\',
|
||||
readGroup: 'shift+Escape'
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -78,6 +78,7 @@ class App extends React.Component {
|
||||
this.store.setStateHandler(this.setState.bind(this));
|
||||
this.state = this.store.state;
|
||||
|
||||
// eslint-disable-next-line
|
||||
this.appChannel = new window.channel();
|
||||
this.api = new GlobalApi(this.ship, this.appChannel, this.store);
|
||||
gcpManager.configure(this.api);
|
||||
@ -103,7 +104,7 @@ class App extends React.Component {
|
||||
this.updateTheme(this.themeWatcher);
|
||||
}, 500);
|
||||
this.api.local.getBaseHash();
|
||||
this.api.local.getRuntimeLag(); //TODO consider polling periodically
|
||||
this.api.local.getRuntimeLag(); // TODO consider polling periodically
|
||||
this.api.settings.getAll();
|
||||
gcpManager.start();
|
||||
Mousetrap.bindGlobal(['command+/', 'ctrl+/'], (e) => {
|
||||
|
@ -159,16 +159,17 @@ export const MessageAuthor = ({
|
||||
fontWeight={nameMono ? '400' : '500'}
|
||||
cursor='pointer'
|
||||
onClick={doCopy}
|
||||
title={`~${msg.author}`}
|
||||
title={showNickname ? `~${msg.author}` : contact?.nickname}
|
||||
>
|
||||
{copyDisplay}
|
||||
</Text>
|
||||
<Text flexShrink={0} fontSize={0} gray>
|
||||
<Text whiteSpace='nowrap' flexShrink={0} fontSize={0} gray>
|
||||
{timestamp}
|
||||
</Text>
|
||||
<Text
|
||||
flexShrink={0}
|
||||
fontSize={0}
|
||||
whiteSpace='nowrap'
|
||||
gray
|
||||
ml={2}
|
||||
display={['none', hovering ? 'block' : 'none']}
|
||||
@ -205,6 +206,7 @@ export const Message = React.memo(({
|
||||
top='2px'
|
||||
lineHeight="tall"
|
||||
fontSize={0}
|
||||
whiteSpace='nowrap'
|
||||
gray
|
||||
>
|
||||
{timestamp}
|
||||
|
@ -136,7 +136,6 @@ export function ChatPane(props: ChatPaneProps): ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<Col {...bind} height="100%" overflow="hidden" position="relative">
|
||||
<ShareProfile
|
||||
our={ourContact}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { BaseInput, Box, Button, LoadingSpinner, Text } from '@tlon/indigo-react';
|
||||
import { hasProvider } from 'oembed-parser';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useState, DragEvent, useEffect } from 'react';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { createPost } from '~/logic/api/graph';
|
||||
import { parsePermalink, permalinkToReference } from '~/logic/lib/permalinks';
|
||||
@ -21,34 +21,11 @@ const LinkSubmit = (props: LinkSubmitProps) => {
|
||||
|
||||
const [submitFocused, setSubmitFocused] = useState(false);
|
||||
const [urlFocused, setUrlFocused] = useState(false);
|
||||
const [linkValue, setLinkValueHook] = useState('');
|
||||
const [linkValue, setLinkValue] = useState('');
|
||||
const [linkTitle, setLinkTitle] = useState('');
|
||||
const [disabled, setDisabled] = useState(false);
|
||||
const [linkValid, setLinkValid] = useState(false);
|
||||
|
||||
const doPost = () => {
|
||||
const url = linkValue;
|
||||
const text = linkTitle ? linkTitle : linkValue;
|
||||
const contents = url.startsWith('web+urbitgraph:/')
|
||||
? [{ text }, permalinkToReference(parsePermalink(url)!)]
|
||||
: [{ text }, { url }];
|
||||
|
||||
setDisabled(true);
|
||||
const parentIndex = props.parentIndex || '';
|
||||
const post = createPost(contents, parentIndex);
|
||||
|
||||
props.api.graph.addPost(
|
||||
`~${props.ship}`,
|
||||
props.name,
|
||||
post
|
||||
).then(() => {
|
||||
setDisabled(false);
|
||||
setLinkValue('');
|
||||
setLinkTitle('');
|
||||
setLinkValid(false);
|
||||
});
|
||||
};
|
||||
|
||||
const validateLink = (link) => {
|
||||
const URLparser = new RegExp(
|
||||
/((?:([\w\d\.-]+)\:\/\/?){1}(?:(www)\.?){0,1}(((?:[\w\d-]+\.)*)([\w\d-]+\.[\w\d]+))){1}(?:\:(\d+)){0,1}((\/(?:(?:[^\/\s\?]+\/)*))(?:([^\?\/\s#]+?(?:.[^\?\s]+){0,1}){0,1}(?:\?([^\s#]+)){0,1})){0,1}(?:#([^#\s]+)){0,1}/
|
||||
@ -95,6 +72,33 @@ const LinkSubmit = (props: LinkSubmitProps) => {
|
||||
return link;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLinkValid(validateLink(linkValue));
|
||||
}, [linkValue]);
|
||||
|
||||
const doPost = () => {
|
||||
const url = linkValue;
|
||||
const text = linkTitle ? linkTitle : linkValue;
|
||||
const contents = url.startsWith('web+urbitgraph:/')
|
||||
? [{ text }, permalinkToReference(parsePermalink(url)!)]
|
||||
: [{ text }, { url }];
|
||||
|
||||
setDisabled(true);
|
||||
const parentIndex = props.parentIndex || '';
|
||||
const post = createPost(contents, parentIndex);
|
||||
|
||||
props.api.graph.addPost(
|
||||
`~${props.ship}`,
|
||||
props.name,
|
||||
post
|
||||
).then(() => {
|
||||
setDisabled(false);
|
||||
setLinkValue('');
|
||||
setLinkTitle('');
|
||||
setLinkValid(false);
|
||||
});
|
||||
};
|
||||
|
||||
const onFileDrag = useCallback(
|
||||
(files: FileList | File[], e: DragEvent): void => {
|
||||
if (!canUpload) {
|
||||
@ -107,17 +111,6 @@ const LinkSubmit = (props: LinkSubmitProps) => {
|
||||
|
||||
const { bind, dragging } = useFileDrag(onFileDrag);
|
||||
|
||||
const onLinkChange = (linkValue: string) => {
|
||||
setLinkValueHook(linkValue);
|
||||
const link = validateLink(linkValue);
|
||||
setLinkValid(link);
|
||||
};
|
||||
|
||||
const setLinkValue = (linkValue: string) => {
|
||||
onLinkChange(linkValue);
|
||||
setLinkValueHook(linkValue);
|
||||
};
|
||||
|
||||
const onPaste = useCallback(
|
||||
(event: ClipboardEvent) => {
|
||||
if (!event.clipboardData || !event.clipboardData.files.length) {
|
||||
@ -192,7 +185,7 @@ const LinkSubmit = (props: LinkSubmitProps) => {
|
||||
py={2}
|
||||
color="black"
|
||||
backgroundColor="transparent"
|
||||
onChange={e => onLinkChange(e.target.value)}
|
||||
onChange={e => setLinkValue(e.target.value)}
|
||||
onBlur={() => [setUrlFocused(false), setSubmitFocused(false)]}
|
||||
onFocus={() => [setUrlFocused(true), setSubmitFocused(true)]}
|
||||
spellCheck="false"
|
||||
|
@ -42,7 +42,7 @@ interface GroupNotificationProps {
|
||||
}
|
||||
|
||||
export function GroupNotification(props: GroupNotificationProps): ReactElement {
|
||||
const { contents, index, read, time, api, timebox } = props;
|
||||
const { contents, index, time } = props;
|
||||
|
||||
const authors = _.flatten(_.map(contents, getGroupUpdateParticipants));
|
||||
|
||||
|
@ -16,7 +16,7 @@ import GlobalApi from '~/logic/api/global';
|
||||
import { getNotificationKey } from '~/logic/lib/hark';
|
||||
import { useLazyScroll } from '~/logic/lib/useLazyScroll';
|
||||
import useLaunchState from '~/logic/state/launch';
|
||||
import { daToUnix, MOMENT_CALENDAR_DATE } from '~/logic/lib/util';
|
||||
import { daToUnix } from '~/logic/lib/util';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import { Invites } from './invites';
|
||||
import { Notification } from './notification';
|
||||
@ -72,16 +72,6 @@ export default function Inbox(props: {
|
||||
const notifications =
|
||||
Array.from(props.showArchive ? archivedNotifications : notificationState) || [];
|
||||
|
||||
const calendar = {
|
||||
...MOMENT_CALENDAR_DATE, sameDay: function (now) {
|
||||
if (this.subtract(6, 'hours').isBefore(now)) {
|
||||
return '[Earlier Today]';
|
||||
} else {
|
||||
return MOMENT_CALENDAR_DATE.sameDay;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const notificationsByDay = f.flow(
|
||||
f.map<DatedTimebox, DatedTimebox>(([date, nots]) => [
|
||||
date,
|
||||
|
@ -1,16 +1,16 @@
|
||||
import React, { ReactElement, ReactNode } from 'react';
|
||||
import React, { ReactElement } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import {
|
||||
Invite,
|
||||
AppInvites,
|
||||
JoinRequest,
|
||||
JoinRequest
|
||||
} from '@urbit/api';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { alphabeticalOrder, resourceAsPath } from '~/logic/lib/util';
|
||||
import useInviteState from '~/logic/state/invite';
|
||||
import useGraphState from '~/logic/state/graph';
|
||||
import {PendingDm} from './PendingDm';
|
||||
import { PendingDm } from './PendingDm';
|
||||
import InviteItem from '~/views/components/Invite';
|
||||
|
||||
interface InvitesProps {
|
||||
@ -26,9 +26,9 @@ interface InviteRef {
|
||||
|
||||
export function Invites(props: InvitesProps): ReactElement {
|
||||
const { api } = props;
|
||||
const invites = useInviteState((state) => state.invites);
|
||||
const invites = useInviteState(state => state.invites);
|
||||
|
||||
const pendingDms = useGraphState((s) => s.pendingDms) ?? [];
|
||||
const pendingDms = useGraphState(s => s.pendingDms) ?? [];
|
||||
|
||||
const inviteArr: InviteRef[] = _.reduce(
|
||||
invites,
|
||||
@ -49,13 +49,12 @@ export function Invites(props: InvitesProps): ReactElement {
|
||||
|
||||
const invitesAndStatus: { [rid: string]: JoinRequest | InviteRef } = {
|
||||
..._.keyBy(inviteArr, ({ invite }) => resourceAsPath(invite.resource)),
|
||||
...pendingJoin,
|
||||
...pendingJoin
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{[...pendingDms].map((ship) => (
|
||||
{[...pendingDms].map(ship => (
|
||||
<PendingDm key={ship} api={api} ship={`~${ship}`} />
|
||||
))}
|
||||
{Object.keys(invitesAndStatus)
|
||||
|
@ -4,18 +4,14 @@ import {
|
||||
|
||||
GroupNotificationContents,
|
||||
|
||||
GroupNotificationsConfig, IndexedNotification,
|
||||
IndexedNotification
|
||||
|
||||
NotificationGraphConfig
|
||||
} from '@urbit/api';
|
||||
import { BigInteger } from 'big-integer';
|
||||
import _ from 'lodash';
|
||||
import React, { ReactNode, useCallback } from 'react';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { getNotificationKey } from '~/logic/lib/hark';
|
||||
import { getParentIndex } from '~/logic/lib/notification';
|
||||
import { useHovering } from '~/logic/lib/util';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import useLocalState from '~/logic/state/local';
|
||||
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
|
||||
import { SwipeMenu } from '~/views/components/SwipeMenu';
|
||||
@ -29,32 +25,6 @@ export interface NotificationProps {
|
||||
unread: boolean;
|
||||
}
|
||||
|
||||
function getMuted(
|
||||
idxNotif: IndexedNotification,
|
||||
groups: GroupNotificationsConfig,
|
||||
graphs: NotificationGraphConfig
|
||||
) {
|
||||
const { index, notification } = idxNotif;
|
||||
if ('graph' in idxNotif.index) {
|
||||
const { graph } = idxNotif.index.graph;
|
||||
if (!('graph' in notification.contents)) {
|
||||
throw new Error();
|
||||
}
|
||||
const parent = getParentIndex(idxNotif.index.graph, notification.contents.graph);
|
||||
|
||||
return (
|
||||
_.findIndex(
|
||||
graphs?.watching || [],
|
||||
g => g.graph === graph && g.index === parent
|
||||
) === -1
|
||||
);
|
||||
}
|
||||
if ('group' in index) {
|
||||
return _.findIndex(groups || [], g => g === index.group.group) === -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function NotificationWrapper(props: {
|
||||
api: GlobalApi;
|
||||
time?: BigInteger;
|
||||
@ -74,12 +44,6 @@ export function NotificationWrapper(props: {
|
||||
return api.hark.archive(time, notification.index);
|
||||
}, [time, notification]);
|
||||
|
||||
const groupConfig = useHarkState(state => state.notificationsGroupConfig);
|
||||
const graphConfig = useHarkState(state => state.notificationsGraphConfig);
|
||||
|
||||
const isMuted =
|
||||
time && notification && getMuted(notification, groupConfig, graphConfig);
|
||||
|
||||
const onClick = (e: any) => {
|
||||
if (!notification || read) {
|
||||
return;
|
||||
|
@ -169,13 +169,10 @@ export function ProfileActions(props: any): ReactElement {
|
||||
}
|
||||
|
||||
export function Profile(props: any): ReactElement | null {
|
||||
const { hideAvatars } = useSettingsState(selectCalmState);
|
||||
const history = useHistory();
|
||||
const nackedContacts = useContactState(state => state.nackedContacts);
|
||||
|
||||
const { contact, hasLoaded, isEdit, ship } = props;
|
||||
const nacked = nackedContacts.has(ship);
|
||||
const formRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasLoaded && !contact && !nacked) {
|
||||
@ -183,8 +180,6 @@ export function Profile(props: any): ReactElement | null {
|
||||
}
|
||||
}, [hasLoaded, contact]);
|
||||
|
||||
const anchorRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
if (!props.ship) {
|
||||
return null;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import 'codemirror/addon/edit/continuelist';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
import 'codemirror/mode/markdown/markdown';
|
||||
import { useFormikContext } from 'formik';
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import React, { useCallback, useRef, DragEvent } from 'react';
|
||||
import { UnControlled as CodeEditor } from 'react-codemirror2';
|
||||
import { Prompt } from 'react-router-dom';
|
||||
import { useFileDrag } from '~/logic/lib/useDrag';
|
||||
@ -61,13 +61,6 @@ export function MarkdownEditor(
|
||||
[onChange]
|
||||
);
|
||||
|
||||
const handleBlur = useCallback(
|
||||
(_i, e: any) => {
|
||||
onBlur && onBlur(e);
|
||||
},
|
||||
[onBlur]
|
||||
);
|
||||
|
||||
const { uploadDefault, canUpload } = useStorage();
|
||||
|
||||
const onFileDrag = useCallback(
|
||||
@ -110,10 +103,10 @@ export function MarkdownEditor(
|
||||
value={value}
|
||||
options={options}
|
||||
onChange={handleChange}
|
||||
onDragLeave={(editor, e: DragEvent) => bind.onDragLeave(e)}
|
||||
onDragOver={(editor, e: DragEvent) => bind.onDragOver(e)}
|
||||
onDrop={(editor, e: DragEvent) => bind.onDrop(e)}
|
||||
onDragEnter={(editor, e: DragEvent) => bind.onDragEnter(e)}
|
||||
onDragLeave={(editor, e: any) => bind.onDragLeave(e)}
|
||||
onDragOver={(editor, e: any) => bind.onDragOver(e)}
|
||||
onDrop={(editor, e: any) => bind.onDrop(e)}
|
||||
onDragEnter={(editor, e: any) => bind.onDragEnter(e)}
|
||||
/>
|
||||
{dragging && <SubmitDragger />}
|
||||
</Box>
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Box, Col, Row, Text } from '@tlon/indigo-react';
|
||||
import { Box, Button, Col, Row, Text } from '@tlon/indigo-react';
|
||||
import { Association, Graph } from '@urbit/api';
|
||||
import React, { ReactElement } from 'react';
|
||||
import React, { ReactElement, useCallback } from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { useShowNickname } from '~/logic/lib/util';
|
||||
import useContactState from '~/logic/state/contact';
|
||||
import useGroupState from '~/logic/state/group';
|
||||
@ -14,6 +15,7 @@ interface NotebookProps {
|
||||
association: Association;
|
||||
baseUrl: string;
|
||||
rootUrl: string;
|
||||
api: GlobalApi;
|
||||
}
|
||||
|
||||
export function Notebook(props: NotebookProps & RouteComponentProps): ReactElement | null {
|
||||
@ -21,19 +23,23 @@ export function Notebook(props: NotebookProps & RouteComponentProps): ReactEleme
|
||||
ship,
|
||||
book,
|
||||
association,
|
||||
graph
|
||||
graph,
|
||||
api
|
||||
} = props;
|
||||
|
||||
const groups = useGroupState(state => state.groups);
|
||||
const contacts = useContactState(state => state.contacts);
|
||||
|
||||
const group = groups[association?.group];
|
||||
const relativePath = (p: string) => props.baseUrl + p;
|
||||
|
||||
const contact = contacts?.[`~${ship}`];
|
||||
|
||||
const showNickname = useShowNickname(contact);
|
||||
|
||||
const readBook = useCallback(() => {
|
||||
api.hark.readGraph(association.resource);
|
||||
}, [association.resource]);
|
||||
|
||||
if (!group) {
|
||||
return null; // Waiting on groups to populate
|
||||
}
|
||||
@ -48,6 +54,7 @@ export function Notebook(props: NotebookProps & RouteComponentProps): ReactEleme
|
||||
{showNickname ? contact?.nickname : ship}
|
||||
</Text>
|
||||
</Box>
|
||||
<Button onClick={readBook}>Mark all as Read</Button>
|
||||
</Row>
|
||||
<Box borderBottom={1} borderBottomColor="lightGray" />
|
||||
<NotebookPosts
|
||||
|
@ -3,14 +3,13 @@ import {
|
||||
|
||||
Text
|
||||
} from '@tlon/indigo-react';
|
||||
import { Form, Formik, FormikHelpers } from 'formik';
|
||||
import { Form } from 'formik';
|
||||
import React, { useCallback } from 'react';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import useSettingsState, { selectSettingsState, SettingsState } from '~/logic/state/settings';
|
||||
import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
import useSettingsState, { SettingsState } from '~/logic/state/settings';
|
||||
import { BackButton } from './BackButton';
|
||||
import _ from 'lodash';
|
||||
import {FormikOnBlur} from '~/views/components/FormikOnBlur';
|
||||
import { FormikOnBlur } from '~/views/components/FormikOnBlur';
|
||||
|
||||
interface FormSchema {
|
||||
hideAvatars: boolean;
|
||||
@ -36,24 +35,20 @@ const settingsSel = (s: SettingsState): FormSchema => ({
|
||||
audioShown: !s.remoteContentPolicy.audioShown
|
||||
});
|
||||
|
||||
|
||||
export function CalmPrefs(props: {
|
||||
api: GlobalApi;
|
||||
}) {
|
||||
const { api } = props;
|
||||
const initialValues = useSettingsState(settingsSel);
|
||||
|
||||
const onSubmit = useCallback(async (v: FormSchema, actions: FormikHelpers<FormSchema>) => {
|
||||
let promises: Promise<any>[] = [];
|
||||
const onSubmit = useCallback(async (v: FormSchema) => {
|
||||
_.forEach(v, (bool, key) => {
|
||||
const bucket = ['imageShown', 'videoShown', 'audioShown', 'oembedShown'].includes(key) ? 'remoteContentPolicy' : 'calm';
|
||||
if(initialValues[key] !== bool) {
|
||||
promises.push(api.settings.putEntry(bucket, key, bool));
|
||||
api.settings.putEntry(bucket, key, bool);
|
||||
}
|
||||
})
|
||||
await Promise.all(promises);
|
||||
actions.setStatus({ success: null });
|
||||
}, [api]);
|
||||
});
|
||||
}, [initialValues]);
|
||||
|
||||
return (
|
||||
<FormikOnBlur initialValues={initialValues} onSubmit={onSubmit}>
|
||||
|
@ -32,7 +32,9 @@ const StoreDebugger = (props: StoreDebuggerProps) => {
|
||||
let output: any = false;
|
||||
try {
|
||||
output = _.get(state, filterToTry, undefined);
|
||||
} catch (e) { }
|
||||
} catch (e) {
|
||||
console.log('filter failed');
|
||||
}
|
||||
if (output) {
|
||||
console.log(output);
|
||||
setText(objectToString(output));
|
||||
|
@ -8,7 +8,7 @@ import GlobalApi from '~/logic/api/global';
|
||||
import { getChord } from '~/logic/lib/util';
|
||||
import useSettingsState, {
|
||||
selectSettingsState,
|
||||
ShortcutMapping,
|
||||
ShortcutMapping
|
||||
} from '~/logic/state/settings';
|
||||
import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
import { BackButton } from './BackButton';
|
||||
@ -108,6 +108,7 @@ export default function ShortcutSettings(props: ShortcutSettingsProps) {
|
||||
label="Cycle backward through channel list"
|
||||
/>
|
||||
<ChordInput id="hideSidebar" label="Show/hide group sidebar" />
|
||||
<ChordInput id="readGroup" label="Read all in a group" />
|
||||
</Box>
|
||||
<AsyncButton primary width="fit-content">Save Changes</AsyncButton>
|
||||
</Col>
|
||||
|
@ -12,7 +12,7 @@ import { LeapSettings } from './components/lib/LeapSettings';
|
||||
import { NotificationPreferences } from './components/lib/NotificationPref';
|
||||
import S3Form from './components/lib/S3Form';
|
||||
import SecuritySettings from './components/lib/Security';
|
||||
import {DmSettings} from './components/lib/DmSettings';
|
||||
import { DmSettings } from './components/lib/DmSettings';
|
||||
import ShortcutSettings from './components/lib/ShortcutSettings';
|
||||
|
||||
export const Skeleton = (props: { children: ReactNode }) => (
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BaseImage, Box, Row } from '@tlon/indigo-react';
|
||||
import { BaseImage, Box, Row, Text } from '@tlon/indigo-react';
|
||||
import moment from 'moment';
|
||||
import React, { ReactElement, ReactNode } from 'react';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
@ -94,7 +94,7 @@ export default function Author(props: AuthorProps & PropFunc<typeof Box>): React
|
||||
)}
|
||||
</Box>
|
||||
<Box display='flex' alignItems='baseline'>
|
||||
<Box
|
||||
<Text
|
||||
ml={showImage ? 2 : 0}
|
||||
color='black'
|
||||
fontSize='1'
|
||||
@ -104,10 +104,11 @@ export default function Author(props: AuthorProps & PropFunc<typeof Box>): React
|
||||
fontWeight={showNickname ? '500' : '400'}
|
||||
mr={showNickname ? 0 : '2px'}
|
||||
mt={showNickname ? 0 : '0px'}
|
||||
title={showNickname ? cite(ship) : contact?.nickname}
|
||||
onClick={doCopy}
|
||||
>
|
||||
{copyDisplay}
|
||||
</Box>
|
||||
</Text>
|
||||
{ !dontShowTime && time && (
|
||||
<Timestamp
|
||||
height="fit-content"
|
||||
@ -115,6 +116,7 @@ export default function Author(props: AuthorProps & PropFunc<typeof Box>): React
|
||||
stamp={stamp}
|
||||
fontSize={0}
|
||||
time={time}
|
||||
whiteSpace='nowrap'
|
||||
ml={2}
|
||||
color={unread ? 'blue' : 'gray'}
|
||||
/>
|
||||
|
@ -11,14 +11,14 @@ export function FormikOnBlur<
|
||||
useEffect(() => {
|
||||
if (
|
||||
Object.keys(formikBag.errors || {}).length === 0 &&
|
||||
formikBag.dirty &&
|
||||
formikBag.dirty &&
|
||||
!formikBag.isSubmitting &&
|
||||
!submitting
|
||||
) {
|
||||
setSubmitting(true);
|
||||
const { values } = formikBag;
|
||||
formikBag.submitForm().then(() => {
|
||||
formikBag.resetForm({ values })
|
||||
formikBag.resetForm({ values });
|
||||
setSubmitting(false);
|
||||
});
|
||||
}
|
||||
@ -29,6 +29,10 @@ export function FormikOnBlur<
|
||||
formikBag.isSubmitting
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
formikBag.resetForm({ values: props.initialValues });
|
||||
}, [props.initialValues]);
|
||||
|
||||
const { children, innerRef } = props;
|
||||
|
||||
useImperativeHandle(innerRef, () => formikBag);
|
||||
|
@ -59,7 +59,7 @@ export function GroupLink(
|
||||
>
|
||||
{modal}
|
||||
<Row
|
||||
width="fit-content"
|
||||
width="100%"
|
||||
flexShrink={1}
|
||||
alignItems="center"
|
||||
py={2}
|
||||
@ -69,7 +69,7 @@ export function GroupLink(
|
||||
}
|
||||
opacity={preview ? '1' : '0.6'}
|
||||
>
|
||||
<MetadataIcon height={6} width={6} metadata={preview ? preview.metadata : { color: '0x0' , picture: ''}} />
|
||||
<MetadataIcon height={6} width={6} metadata={preview ? preview.metadata : { color: '0x0' , picture: '' }} />
|
||||
<Col>
|
||||
<Text ml={2} fontWeight="medium" mono={!preview}>
|
||||
{preview ? preview.metadata.title : name}
|
||||
|
@ -46,7 +46,6 @@ export function Mention(props: {
|
||||
const contact = useContact(`~${deSig(ship)}`);
|
||||
const showNickname = useShowNickname(contact);
|
||||
const name = showNickname ? contact?.nickname : cite(ship);
|
||||
|
||||
return (
|
||||
<ProfileOverlay ship={ship} api={api} display="inline">
|
||||
<Text
|
||||
@ -57,6 +56,8 @@ export function Mention(props: {
|
||||
color='blue'
|
||||
fontSize={showNickname ? 1 : 0}
|
||||
mono={!showNickname}
|
||||
title={showNickname ? cite(ship) : contact?.nickname}
|
||||
{...rest}
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Anchor, Box, Text } from '@tlon/indigo-react';
|
||||
import { Anchor, Text } from '@tlon/indigo-react';
|
||||
import { Contact, Group } from '@urbit/api';
|
||||
import React from 'react';
|
||||
import ReactMarkdown, { ReactMarkdownProps } from 'react-markdown';
|
||||
@ -6,7 +6,6 @@ import RemarkDisableTokenizers from 'remark-disable-tokenizers';
|
||||
import { isValidPatp } from 'urbit-ob';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { deSig } from '~/logic/lib/util';
|
||||
import {PropFunc} from '~/types';
|
||||
import { PermalinkEmbed } from '~/views/apps/permalinks/embed';
|
||||
import { Mention } from '~/views/components/MentionText';
|
||||
import RemoteContent from '~/views/components/RemoteContent';
|
||||
@ -49,7 +48,7 @@ type RichTextProps = ReactMarkdownProps & {
|
||||
py?: number;
|
||||
overflowX?: any;
|
||||
verticalAlign?: any;
|
||||
};
|
||||
};
|
||||
|
||||
const RichText = React.memo(({ disableRemoteContent = false, api, ...props }: RichTextProps) => (
|
||||
<ReactMarkdown
|
||||
|
@ -245,7 +245,7 @@ const renderers = {
|
||||
return (
|
||||
<Text
|
||||
mono
|
||||
fontWeight='inherit'
|
||||
fontWeight="inherit"
|
||||
p={1}
|
||||
backgroundColor="washedGray"
|
||||
fontSize={0}
|
||||
@ -285,7 +285,11 @@ const renderers = {
|
||||
paragraph: ({ children }) => {
|
||||
return (
|
||||
<Box display="block">
|
||||
<Text fontSize={1} lineHeight="tall" style={{ 'overflowWrap': 'break-word' }}>
|
||||
<Text
|
||||
fontSize={1}
|
||||
lineHeight="tall"
|
||||
style={{ overflowWrap: 'break-word' }}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
</Box>
|
||||
@ -310,7 +314,7 @@ const renderers = {
|
||||
className="clamp-message"
|
||||
display="block"
|
||||
borderRadius={1}
|
||||
fontWeight='inherit'
|
||||
fontWeight="inherit"
|
||||
mono
|
||||
fontSize={0}
|
||||
backgroundColor="washedGray"
|
||||
@ -340,23 +344,15 @@ const renderers = {
|
||||
list: ({ depth, ordered, children }) => {
|
||||
return ordered ? <Ol>{children}</Ol> : <Ul>{children}</Ul>;
|
||||
},
|
||||
'graph-mention': ({ ship }) => <Mention api={{} as any} ship={ship} />,
|
||||
'graph-mention': ({ api, ship }) => <Mention api={api} ship={ship} />,
|
||||
image: ({ url, tall }) => (
|
||||
<Box mt="1" mb="2" flexShrink={0}>
|
||||
<RemoteContent
|
||||
key={url}
|
||||
url={url}
|
||||
tall={tall}
|
||||
/>
|
||||
<RemoteContent key={url} url={url} tall={tall} />
|
||||
</Box>
|
||||
),
|
||||
'graph-url': ({ url, tall }) => (
|
||||
<Box mt={1} mb={2} flexShrink={0}>
|
||||
<RemoteContent
|
||||
key={url}
|
||||
url={url}
|
||||
tall={tall}
|
||||
/>
|
||||
<RemoteContent key={url} url={url} tall={tall} />
|
||||
</Box>
|
||||
),
|
||||
'graph-reference': ({ api, reference, transcluded }) => {
|
||||
@ -437,16 +433,8 @@ export type GraphContentProps = PropFunc<typeof Box> & {
|
||||
showOurContact: boolean;
|
||||
};
|
||||
|
||||
export const GraphContent = React.memo((
|
||||
props: GraphContentProps
|
||||
) => {
|
||||
const {
|
||||
contents,
|
||||
tall = false,
|
||||
transcluded = 0,
|
||||
api,
|
||||
...rest
|
||||
} = props;
|
||||
export const GraphContent = React.memo((props: GraphContentProps) => {
|
||||
const { contents, tall = false, transcluded = 0, api, ...rest } = props;
|
||||
const [, ast] = stitchAsts(contents.map(contentToMdAst(tall)));
|
||||
return (
|
||||
<Box {...rest}>
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { AppName } from '@urbit/api';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import {
|
||||
Route,
|
||||
RouteComponentProps, Switch
|
||||
} from 'react-router-dom';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { useShortcut } from '~/logic/state/settings';
|
||||
import { useLocalStorageState } from '~/logic/lib/useLocalStorageState';
|
||||
import { getGroupFromWorkspace } from '~/logic/lib/workspace';
|
||||
import useGroupState from '~/logic/state/group';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
import {DmResource} from '~/views/apps/chat/DmResource';
|
||||
import { DmResource } from '~/views/apps/chat/DmResource';
|
||||
import { StoreState } from '~/logic/store/type';
|
||||
import { Workspace } from '~/types/workspace';
|
||||
import '~/views/apps/links/css/custom.css';
|
||||
@ -42,6 +43,12 @@ export function GroupsPane(props: GroupsPaneProps) {
|
||||
const groupPath = getGroupFromWorkspace(workspace);
|
||||
const groups = useGroupState(state => state.groups);
|
||||
|
||||
useShortcut('readGroup', useCallback(() => {
|
||||
if(groupPath) {
|
||||
api.hark.readGroup(groupPath);
|
||||
}
|
||||
}, [groupPath, api]));
|
||||
|
||||
const groupAssociation =
|
||||
(groupPath && associations.groups[groupPath]) || undefined;
|
||||
const group = (groupPath && groups[groupPath]) || undefined;
|
||||
@ -56,7 +63,7 @@ export function GroupsPane(props: GroupsPaneProps) {
|
||||
}
|
||||
return () => {
|
||||
setRecentGroups(gs => _.uniq([workspace.group, ...gs]));
|
||||
}
|
||||
};
|
||||
}, [workspace]);
|
||||
|
||||
if (!(associations && (groupPath ? groupPath in groups : true))) {
|
||||
@ -180,7 +187,6 @@ export function GroupsPane(props: GroupsPaneProps) {
|
||||
<Route
|
||||
path={relativePath('/new')}
|
||||
render={(routeProps) => {
|
||||
const newUrl = `${baseUrl}/new`;
|
||||
return (
|
||||
<Skeleton mobileHide recentGroups={recentGroups} {...props} baseUrl={baseUrl}>
|
||||
<NewChannel
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
import { Enc, GroupPolicy } from '@urbit/api';
|
||||
import { Form, Formik, FormikHelpers } from 'formik';
|
||||
import React, { ReactElement, useCallback } from 'react';
|
||||
import { RouteComponentProps, useHistory } from 'react-router-dom';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import * as Yup from 'yup';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { useWaitForProps } from '~/logic/lib/useWaitForProps';
|
||||
@ -16,7 +16,9 @@ import useMetadataState from '~/logic/state/metadata';
|
||||
import { AsyncButton } from '~/views/components/AsyncButton';
|
||||
|
||||
const formSchema = Yup.object({
|
||||
title: Yup.string().required('Group must have a name'),
|
||||
title: Yup.string()
|
||||
.matches(/^([a-zA-Z]|[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff]).*$/, 'Group names must start with letters or emoji')
|
||||
.required('Group must have a name'),
|
||||
description: Yup.string(),
|
||||
isPrivate: Yup.boolean()
|
||||
});
|
||||
@ -94,7 +96,7 @@ export function NewGroup(props: NewGroupProps): ReactElement {
|
||||
id="title"
|
||||
label="Name"
|
||||
caption="Provide a name for your group"
|
||||
placeholder="eg. My Channel"
|
||||
placeholder="eg. My Group"
|
||||
/>
|
||||
<Input
|
||||
id="description"
|
||||
|
@ -31,7 +31,7 @@ export function PopoverRoutes(
|
||||
|
||||
const groupSize = props.group.members.size;
|
||||
|
||||
const owner = resourceFromPath(props.association.group).ship.slice(1) === window.ship;
|
||||
const owner = resourceFromPath(props.association?.group ?? '~zod/group').ship.slice(1) === window.ship;
|
||||
|
||||
const admin = props.group?.tags?.role?.admin.has(window.ship) || false;
|
||||
|
||||
|
@ -102,8 +102,10 @@ export function SidebarDmItem(props: {
|
||||
}) {
|
||||
const { ship, selected = false } = props;
|
||||
const contact = useContact(ship);
|
||||
const title = contact?.nickname || (cite(ship) ?? ship);
|
||||
const hideAvatars = false;
|
||||
const { hideAvatars, hideNicknames } = useSettingsState(s => s.calm);
|
||||
const title = (!hideNicknames && contact?.nickname)
|
||||
? contact?.nickname
|
||||
: (cite(ship) ?? ship);
|
||||
const { unreads } = useHarkDm(ship) || { unreads: 0 };
|
||||
const img =
|
||||
contact?.avatar && !hideAvatars ? (
|
||||
@ -131,7 +133,7 @@ export function SidebarDmItem(props: {
|
||||
hasUnread={(unreads as number) > 0}
|
||||
to={`/~landscape/messages/dm/${ship}`}
|
||||
title={title}
|
||||
mono={!contact?.nickname}
|
||||
mono={hideAvatars || !contact?.nickname}
|
||||
isSynced
|
||||
>
|
||||
{img}
|
||||
|
@ -20,7 +20,7 @@ function sidebarSort(
|
||||
const alphabetical = (a: string, b: string) => {
|
||||
const aAssoc = associations[a];
|
||||
const bAssoc = associations[b];
|
||||
const aTitle = aAssoc?.metadata?.title || b;
|
||||
const aTitle = aAssoc?.metadata?.title || a;
|
||||
const bTitle = bAssoc?.metadata?.title || b;
|
||||
|
||||
return alphabeticalOrder(aTitle, bTitle);
|
||||
@ -33,8 +33,9 @@ function sidebarSort(
|
||||
const bAppName = bAssoc?.['app-name'];
|
||||
|
||||
const aUpdated = a.startsWith('~')
|
||||
? (inboxUnreads?.[`/${patp2dec(a)}`]?.last)
|
||||
? (inboxUnreads?.[`/${patp2dec(a)}`]?.last || 0)
|
||||
: (apps[aAppName]?.lastUpdated(a) || 0);
|
||||
|
||||
const bUpdated = b.startsWith('~')
|
||||
? (inboxUnreads?.[`/${patp2dec(b)}`]?.last || 0)
|
||||
: (apps[bAppName]?.lastUpdated(b) || 0);
|
||||
@ -108,14 +109,19 @@ export function SidebarList(props: {
|
||||
const offset = backward ? -1 : 1;
|
||||
|
||||
const newIdx = modulo(idx+offset, ordered.length - 1);
|
||||
const { metadata, resource } = associations[ordered[newIdx]];
|
||||
const joined = graphKeys.has(resource.slice(7));
|
||||
let path = '/~landscape/home';
|
||||
if ('graph' in metadata.config) {
|
||||
path = getResourcePath(workspace, resource, joined, metadata.config.graph);
|
||||
const newChannel = ordered[newIdx];
|
||||
let path = '';
|
||||
if(newChannel.startsWith('~')) {
|
||||
path = `/~landscape/messages/dm/${newChannel}`;
|
||||
} else {
|
||||
const { metadata, resource } = associations.graph[ordered[newIdx]];
|
||||
const joined = graphKeys.has(resource.slice(7));
|
||||
if ('graph' in metadata.config) {
|
||||
path = getResourcePath(workspace, resource, joined, metadata.config.graph);
|
||||
}
|
||||
}
|
||||
history.push(path);
|
||||
}, [selected, history.push]);
|
||||
}, [ordered, selected, history.push]);
|
||||
|
||||
useShortcut('cycleForward', useCallback((e: KeyboardEvent) => {
|
||||
cycleChannels(false);
|
||||
|
@ -21,7 +21,7 @@ import { Dropdown } from '~/views/components/Dropdown';
|
||||
import { FormikOnBlur } from '~/views/components/FormikOnBlur';
|
||||
import { NewChannel } from '~/views/landscape/components/NewChannel';
|
||||
import { SidebarListConfig } from './types';
|
||||
import {getFeedPath} from '~/logic/lib/util';
|
||||
import { getFeedPath } from '~/logic/lib/util';
|
||||
|
||||
export function SidebarListHeader(props: {
|
||||
api: GlobalApi;
|
||||
@ -53,7 +53,7 @@ export function SidebarListHeader(props: {
|
||||
|
||||
const noun = (props.workspace?.type === 'messages') ? 'Messages' : 'Channels';
|
||||
|
||||
let feedPath = groupPath ? getFeedPath(associations.groups[groupPath]) : undefined;
|
||||
const feedPath = groupPath ? getFeedPath(associations.groups[groupPath]) : undefined;
|
||||
|
||||
const unreadCount = useHarkState(
|
||||
s => s.unreads?.graph?.[feedPath ?? '']?.['/']?.unreads as number ?? 0
|
||||
@ -61,7 +61,7 @@ export function SidebarListHeader(props: {
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{( !!feedPath) ? (
|
||||
{( feedPath) ? (
|
||||
<Row
|
||||
flexShrink={0}
|
||||
alignItems="center"
|
||||
|
@ -1,18 +1,14 @@
|
||||
import { Box } from '@tlon/indigo-react';
|
||||
import { PatpNoSig } from '@urbit/api';
|
||||
import moment from 'moment';
|
||||
import React, { ReactElement, useCallback, useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { Route, RouteComponentProps, Switch } from 'react-router-dom';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { cite } from '~/logic/lib/util';
|
||||
import useGraphState from '~/logic/state/graph';
|
||||
import useHarkState from '~/logic/state/hark';
|
||||
import { StoreState } from '~/logic/store/type';
|
||||
import GlobalSubscription from '~/logic/subscription/global';
|
||||
import { Workspace } from '~/types/workspace';
|
||||
import { Body } from '../components/Body';
|
||||
import { Loading } from '../components/Loading';
|
||||
import { GroupsPane } from './components/GroupsPane';
|
||||
import { JoinGroup } from './components/JoinGroup';
|
||||
import { NewGroup } from './components/NewGroup';
|
||||
@ -43,11 +39,10 @@ type LandscapeProps = StoreState & {
|
||||
ship: PatpNoSig;
|
||||
api: GlobalApi;
|
||||
subscription: GlobalSubscription;
|
||||
notificationsCount: number;
|
||||
}
|
||||
|
||||
export default function Landscape(props) {
|
||||
const notificationsCount = useHarkState(s => s.notificationsCount);
|
||||
|
||||
export default function Landscape(props: LandscapeProps) {
|
||||
return (
|
||||
<>
|
||||
<Helmet defer={false}>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@urbit/api",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"description": "",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -10,6 +10,7 @@
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d",
|
||||
"scripts": {
|
||||
"prepublish": "npm run build",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"watch": "onchange './**/*.ts' -e './dist/**' -- npm run build",
|
||||
"build": "npm run clean && tsc -p tsconfig.json",
|
||||
|
@ -5,7 +5,7 @@
|
||||
"outDir": "./dist",
|
||||
"module": "ES2020",
|
||||
"noImplicitAny": true,
|
||||
"target": "ES2020",
|
||||
"target": "ES2017",
|
||||
"pretty": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@urbit/http-api",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"license": "MIT",
|
||||
"description": "Library to interact with an Urbit ship over HTTP",
|
||||
"repository": {
|
||||
@ -15,6 +15,7 @@
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublish": "npm run build",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"watch": "onchange './*.ts' -- npm run build",
|
||||
"build": "npm run clean && tsc -p tsconfig.json",
|
||||
|
Loading…
Reference in New Issue
Block a user