mirror of
https://github.com/urbit/shrub.git
synced 2025-01-04 10:32:34 +03:00
Merge remote-tracking branch 'origin/release/next-userspace' into release/next-sys
This commit is contained in:
commit
a9b88c8762
@ -10,9 +10,10 @@ let
|
|||||||
tlon = import ../pkgs { inherit pkgs; };
|
tlon = import ../pkgs { inherit pkgs; };
|
||||||
arvo = tlon.arvo;
|
arvo = tlon.arvo;
|
||||||
urbit = tlon.urbit;
|
urbit = tlon.urbit;
|
||||||
|
herb = tlon.herb;
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
import ./fakeship {
|
import ./fakeship {
|
||||||
inherit pkgs tlon deps arvo pill ship debug;
|
inherit pkgs arvo pill ship herb urbit;
|
||||||
}
|
}
|
||||||
|
@ -647,24 +647,24 @@
|
|||||||
++ tab-list
|
++ tab-list
|
||||||
^- (list [@t tank])
|
^- (list [@t tank])
|
||||||
:~
|
:~
|
||||||
[%join leaf+";join ~ship/chat-name (glyph)"]
|
[';join' leaf+";join ~ship/chat-name (glyph)"]
|
||||||
[%leave leaf+";leave ~ship/chat-name"]
|
[';leave' leaf+";leave ~ship/chat-name"]
|
||||||
::
|
::
|
||||||
[%create leaf+";create [type] /chat-name (glyph)"]
|
[';create' leaf+";create [type] /chat-name (glyph)"]
|
||||||
[%delete leaf+";delete /chat-name"]
|
[';delete' leaf+";delete /chat-name"]
|
||||||
[%invite leaf+";invite /chat-name ~ships"]
|
[';invite' leaf+";invite /chat-name ~ships"]
|
||||||
[%banish leaf+";banish /chat-name ~ships"]
|
[';banish' leaf+";banish /chat-name ~ships"]
|
||||||
::
|
::
|
||||||
[%bind leaf+";bind [glyph] ~ship/chat-name"]
|
[';bind' leaf+";bind [glyph] ~ship/chat-name"]
|
||||||
[%unbind leaf+";unbind [glyph]"]
|
[';unbind' leaf+";unbind [glyph]"]
|
||||||
[%what leaf+";what (~ship/chat-name) (glyph)"]
|
[';what' leaf+";what (~ship/chat-name) (glyph)"]
|
||||||
::
|
::
|
||||||
[%settings leaf+";settings"]
|
[';settings' leaf+";settings"]
|
||||||
[%set leaf+";set key (value)"]
|
[';set' leaf+";set key (value)"]
|
||||||
[%unset leaf+";unset key"]
|
[';unset' leaf+";unset key"]
|
||||||
::
|
::
|
||||||
[%chats leaf+";chats"]
|
[';chats' leaf+";chats"]
|
||||||
[%help leaf+";help"]
|
[';help' leaf+";help"]
|
||||||
==
|
==
|
||||||
:: +work: run user command
|
:: +work: run user command
|
||||||
::
|
::
|
||||||
|
@ -683,7 +683,8 @@
|
|||||||
~|(%one-argument !!)
|
~|(%one-argument !!)
|
||||||
=/ res (mule |.((slam q.cay (dy-vase p.i.p.cig))))
|
=/ res (mule |.((slam q.cay (dy-vase p.i.p.cig))))
|
||||||
?: ?=(%| -.res)
|
?: ?=(%| -.res)
|
||||||
(he-diff(poy ~) %tan p.res) :: TODO: or +dy-rash ?
|
:: TODO: or +dy-rash ?
|
||||||
|
(he-diff(poy ~) %tan leaf+"dojo: naked generator failure" p.res)
|
||||||
(dy-hand %noun p.res)
|
(dy-hand %noun p.res)
|
||||||
:: normal generator
|
:: normal generator
|
||||||
::
|
::
|
||||||
@ -697,7 +698,7 @@
|
|||||||
::
|
::
|
||||||
=/ wat (mule |.(!<(?(%ask %say) (slot 2 q.cay))))
|
=/ wat (mule |.(!<(?(%ask %say) (slot 2 q.cay))))
|
||||||
?: ?=(%| -.wat)
|
?: ?=(%| -.wat)
|
||||||
(he-diff(poy ~) %tan p.wat)
|
(he-diff(poy ~) %tan leaf+"dojo: generator neither %ask nor %say" p.wat)
|
||||||
=- =/ res (mule -)
|
=- =/ res (mule -)
|
||||||
?: ?=(%| -.res)
|
?: ?=(%| -.res)
|
||||||
(he-diff(poy ~) %tan leaf+"dojo: generator failure" p.res)
|
(he-diff(poy ~) %tan leaf+"dojo: generator failure" p.res)
|
||||||
@ -811,10 +812,10 @@
|
|||||||
%do
|
%do
|
||||||
=/ gat (dy-eval p.bil)
|
=/ gat (dy-eval p.bil)
|
||||||
?: ?=(%| -.gat)
|
?: ?=(%| -.gat)
|
||||||
(he-diff(poy ~) %tan p.gat)
|
(he-diff(poy ~) %tan leaf+"dojo: %do create gate failed" p.gat)
|
||||||
=/ res (mule |.((slam q.p.gat (dy-vase p.q.bil))))
|
=/ res (mule |.((slam q.p.gat (dy-vase p.q.bil))))
|
||||||
?: ?=(%| -.res)
|
?: ?=(%| -.res)
|
||||||
(he-diff(poy ~) %tan p.res)
|
(he-diff(poy ~) %tan leaf+"dojo: %do execute failed" p.res)
|
||||||
(dy-hand %noun p.res)
|
(dy-hand %noun p.res)
|
||||||
::
|
::
|
||||||
%tu
|
%tu
|
||||||
@ -848,7 +849,7 @@
|
|||||||
|= =hoon
|
|= =hoon
|
||||||
=/ res (dy-eval hoon)
|
=/ res (dy-eval hoon)
|
||||||
?: ?=(%| -.res)
|
?: ?=(%| -.res)
|
||||||
(he-diff(poy ~) %tan p.res)
|
(he-diff(poy ~) %tan leaf+"dojo: hoon expression failed" p.res)
|
||||||
(dy-hand p.res)
|
(dy-hand p.res)
|
||||||
:: +dy-eval: run hoon source against the dojo subject
|
:: +dy-eval: run hoon source against the dojo subject
|
||||||
::
|
::
|
||||||
@ -975,7 +976,7 @@
|
|||||||
+>
|
+>
|
||||||
?~ p.cit
|
?~ p.cit
|
||||||
(he-diff %txt ">=")
|
(he-diff %txt ">=")
|
||||||
(he-diff %tan u.p.cit)
|
(he-diff %tan leaf+"dojo: app poke failed" u.p.cit)
|
||||||
::
|
::
|
||||||
++ he-wool
|
++ he-wool
|
||||||
|= [way=wire =sign:agent:gall]
|
|= [way=wire =sign:agent:gall]
|
||||||
@ -984,13 +985,13 @@
|
|||||||
%poke-ack
|
%poke-ack
|
||||||
?~ p.sign
|
?~ p.sign
|
||||||
+>.$
|
+>.$
|
||||||
=. +>.$ (he-diff(poy ~) %tan u.p.sign)
|
=. +>.$ (he-diff(poy ~) %tan leaf+"dojo: thread poke failed" u.p.sign)
|
||||||
(he-card %pass /wool %agent [our.hid %spider] %leave ~)
|
(he-card %pass /wool %agent [our.hid %spider] %leave ~)
|
||||||
::
|
::
|
||||||
%watch-ack
|
%watch-ack
|
||||||
?~ p.sign
|
?~ p.sign
|
||||||
+>.$
|
+>.$
|
||||||
(he-diff(poy ~) %tan u.p.sign)
|
(he-diff(poy ~) %tan leaf+"dojo: thread watch failed" u.p.sign)
|
||||||
::
|
::
|
||||||
%fact
|
%fact
|
||||||
?+ p.cage.sign ~|([%dojo-thread-bad-mark-result p.cage.sign] !!)
|
?+ p.cage.sign ~|([%dojo-thread-bad-mark-result p.cage.sign] !!)
|
||||||
|
@ -218,11 +218,33 @@
|
|||||||
?+ +<.sign (on-arvo:def wire sign)
|
?+ +<.sign (on-arvo:def wire sign)
|
||||||
%bound
|
%bound
|
||||||
?: accepted.sign [~ this]
|
?: accepted.sign [~ this]
|
||||||
|
~& [dap.bowl %failed-to-bind path.binding.sign]
|
||||||
[~ this(serving (~(del by serving) path.binding.sign))]
|
[~ this(serving (~(del by serving) path.binding.sign))]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
++ on-peek on-peek:def
|
++ on-peek
|
||||||
|
|= =path
|
||||||
|
^- (unit (unit cage))
|
||||||
|
|^
|
||||||
|
?+ path (on-peek:def path)
|
||||||
|
[%x %clay %base %hash ~] ``hash+!>(base-hash)
|
||||||
|
==
|
||||||
|
:: stolen from +trouble
|
||||||
|
:: TODO: move to a lib?
|
||||||
|
++ base-hash
|
||||||
|
^- @uv
|
||||||
|
=+ .^ ota=(unit [=ship =desk =aeon:clay])
|
||||||
|
%gx /(scot %p our.bowl)/hood/(scot %da now.bowl)/kiln/ota/noun
|
||||||
|
==
|
||||||
|
?~ ota
|
||||||
|
*@uv
|
||||||
|
=/ parent (scot %p ship.u.ota)
|
||||||
|
=+ .^(=cass:clay %cs /[parent]/[desk.u.ota]/1/late/foo)
|
||||||
|
%^ end 3 3
|
||||||
|
.^(@uv %cz /[parent]/[desk.u.ota]/(scot %ud ud.cass))
|
||||||
|
--
|
||||||
|
|
||||||
++ on-agent on-agent:def
|
++ on-agent on-agent:def
|
||||||
++ on-fail on-fail:def
|
++ on-fail on-fail:def
|
||||||
--
|
--
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
++ on-peek
|
++ on-peek
|
||||||
|= =path
|
|= =path
|
||||||
~& peeking=path
|
|
||||||
^- (unit (unit cage))
|
^- (unit (unit cage))
|
||||||
?+ path (on-peek:def path)
|
?+ path (on-peek:def path)
|
||||||
[* %kiln *] (on-peek:kiln-core path)
|
[* %kiln *] (on-peek:kiln-core path)
|
||||||
|
@ -9,6 +9,9 @@ class Channel {
|
|||||||
this.onChannelError = (err) => {
|
this.onChannelError = (err) => {
|
||||||
console.error('event source error: ', err);
|
console.error('event source error: ', err);
|
||||||
};
|
};
|
||||||
|
this.onChannelOpen = (e) => {
|
||||||
|
console.log('open', e);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@ -58,6 +61,10 @@ class Channel {
|
|||||||
this.onChannelError = onError;
|
this.onChannelError = onError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOnChannelOpen(onOpen = (e) => {}) {
|
||||||
|
this.onChannelOpen = onOpen;
|
||||||
|
}
|
||||||
|
|
||||||
deleteOnUnload() {
|
deleteOnUnload() {
|
||||||
window.addEventListener("unload", (event) => {
|
window.addEventListener("unload", (event) => {
|
||||||
this.delete();
|
this.delete();
|
||||||
@ -216,6 +223,8 @@ class Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.eventSource.onopen = this.onChannelOpen;
|
||||||
|
|
||||||
this.eventSource.onerror = e => {
|
this.eventSource.onerror = e => {
|
||||||
this.delete();
|
this.delete();
|
||||||
this.init();
|
this.init();
|
||||||
|
@ -42,8 +42,10 @@
|
|||||||
?. ?=([%all ~] wire) (on-watch:def wire)
|
?. ?=([%all ~] wire) (on-watch:def wire)
|
||||||
=/ jon
|
=/ jon
|
||||||
%- pairs:enjs:format
|
%- pairs:enjs:format
|
||||||
:~ [%weather data]
|
:* ['location' s+location]
|
||||||
[%location s+location]
|
::
|
||||||
|
?. ?=([%o *] data) ~
|
||||||
|
~(tap by p.data)
|
||||||
==
|
==
|
||||||
:_ this
|
:_ this
|
||||||
[%give %fact ~ %json !>(jon)]~
|
[%give %fact ~ %json !>(jon)]~
|
||||||
|
14
pkg/arvo/mar/hash.hoon
Normal file
14
pkg/arvo/mar/hash.hoon
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|_ hash=@uv
|
||||||
|
::
|
||||||
|
++ grad %noun
|
||||||
|
++ grow
|
||||||
|
|%
|
||||||
|
++ noun hash
|
||||||
|
++ json
|
||||||
|
s+(rsh 3 2 (scot %uv hash))
|
||||||
|
--
|
||||||
|
++ grab
|
||||||
|
|%
|
||||||
|
++ noun @uv
|
||||||
|
--
|
||||||
|
--
|
@ -5,8 +5,9 @@
|
|||||||
|= arg=vase
|
|= arg=vase
|
||||||
=/ m (strand ,vase)
|
=/ m (strand ,vase)
|
||||||
^- form:m
|
^- form:m
|
||||||
=+ !<([a=mark b=mark ~] arg)
|
=+ !<([pax=path ~] arg)
|
||||||
;< =bowl:spider bind:m get-bowl:strandio
|
?~ bem=(de-beam:format pax)
|
||||||
=/ bek=beak [our q.byk da+now]:bowl
|
(strand-fail:strand %path-not-beam >pax< ~)
|
||||||
;< =tube:clay bind:m (build-cast:strandio bek a b)
|
=/ =mars:clay [i.t i]:?>(?=([@ @ ~] s.u.bem) s.u.bem)
|
||||||
|
;< =tube:clay bind:m (build-cast:strandio -.u.bem mars)
|
||||||
(pure:m !>(tube))
|
(pure:m !>(tube))
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
/- spider
|
/- spider
|
||||||
/+ strandio
|
/+ strand, strandio
|
||||||
=, strand=strand:spider
|
=, strand=strand:spider
|
||||||
^- thread:spider
|
^- thread:spider
|
||||||
|= arg=vase
|
|= arg=vase
|
||||||
=/ m (strand ,vase)
|
=/ m (strand ,vase)
|
||||||
^- form:m
|
^- form:m
|
||||||
=+ !<([pax=path ~] arg)
|
=+ !<([pax=path ~] arg)
|
||||||
;< =bowl:spider bind:m get-bowl:strandio
|
?^ bem=(de-beam:format pax)
|
||||||
=/ bek=beak [our q.byk da+now]:bowl
|
(build-file:strandio u.bem)
|
||||||
(build-file:strandio bek (flop pax))
|
(strand-fail:strand %path-not-beam >pax< ~)
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
|= arg=vase
|
|= arg=vase
|
||||||
=/ m (strand ,vase)
|
=/ m (strand ,vase)
|
||||||
^- form:m
|
^- form:m
|
||||||
=+ !<([mak=mark ~] arg)
|
=+ !<([pax=path ~] arg)
|
||||||
;< =bowl:spider bind:m get-bowl:strandio
|
?~ bem=(de-beam:format pax)
|
||||||
=/ bek=beak [our q.byk da+now]:bowl
|
(strand-fail:strand %path-not-beam >pax< ~)
|
||||||
;< =dais:clay bind:m (build-mark:strandio bek mak)
|
=/ =mark (head s.u.bem)
|
||||||
|
;< =dais:clay bind:m (build-mark:strandio -.u.bem mark)
|
||||||
(pure:m !>(dais))
|
(pure:m !>(dais))
|
||||||
|
@ -10,19 +10,98 @@ applications. Landscape applications will usually make good use of Gall, but
|
|||||||
it's not strictly required if a Landscape application is not interacting with
|
it's not strictly required if a Landscape application is not interacting with
|
||||||
ships directly.
|
ships directly.
|
||||||
|
|
||||||
Create a development ship, then once your ship is running, mount to Unix with
|
|
||||||
`|mount %`. This will create a folder named 'home' in your pier in Unix. The
|
|
||||||
'home' desk contains the working state of your ship -- like a Git repository,
|
|
||||||
when you want to make a change to it, `|commit %home`.
|
|
||||||
|
|
||||||
## Contributing to Landscape applications
|
## Contributing to Landscape applications
|
||||||
|
|
||||||
|
To begin developing on Landscape, find the `urbitrc-sample` file found
|
||||||
|
at `urbit/pkg/interface/config/urbitrc-sample`. Copy it as `urbitrc`.
|
||||||
|
Open it using your preferred code editor and you should see the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
module.exports = {
|
||||||
|
URBIT_PIERS: [
|
||||||
|
"/Users/user/ships/zod/home",
|
||||||
|
],
|
||||||
|
herb: false,
|
||||||
|
URL: 'http://localhost:80'
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
This file is the configuration file for your front-end development environment.
|
||||||
|
Let's walk through it.
|
||||||
|
|
||||||
|
The first line, listing piers, specifies which piers to copy the JS files into.
|
||||||
|
By default, the development environment won't copy files into any pier, even if
|
||||||
|
you've set the pier in `urbitrc`.
|
||||||
|
|
||||||
|
If you want to copy the JS files into your ship, as it would run in a regular
|
||||||
|
user environment, uncomment these lines in
|
||||||
|
`pkg/interface/config/webpack.dev.js`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// uncomment to copy into all piers
|
||||||
|
//
|
||||||
|
// return Promise.all(this.piers.map(pier => {
|
||||||
|
// const dst = path.resolve(pier, 'app/landscape/js/index.js');
|
||||||
|
// copyFile(src, dst).then(() => {
|
||||||
|
// if(!this.herb) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// pier = pier.split('/');
|
||||||
|
// const desk = pier.pop();
|
||||||
|
// return exec(`herb -p hood -d '+hood/commit %${desk}' ${pier.join('/')}`);
|
||||||
|
// });
|
||||||
|
// }));
|
||||||
|
```
|
||||||
|
|
||||||
|
And then set your pier in `urbitrc` (ensure it ends in `/home`). The `herb`
|
||||||
|
option in your `urbitrc` will automatically commit the changes to your ship if
|
||||||
|
you have herb installed (see `pkg/herb`).
|
||||||
|
|
||||||
|
For most developers, if you are making changes to Landscape without any back-end
|
||||||
|
changes on the Urbit ship itself, and you have an Urbit ship running already,
|
||||||
|
you don't have to boot a development ship. You can simply set up the dev server
|
||||||
|
for the development environment and point it at your running ship.
|
||||||
|
|
||||||
|
To do this, set the `URL` property in your urbitrc and replace it with the URL
|
||||||
|
of the urbit that you are testing on. For example, a development ship by default
|
||||||
|
lives at `localhost:80` so our `urbitrc` would have:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
URL: 'http://localhost:80'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then get everything installed:
|
||||||
|
|
||||||
|
```
|
||||||
|
## go to urbit's interface directory and install the required tooling
|
||||||
|
cd urbit/pkg/interface
|
||||||
|
npm install
|
||||||
|
|
||||||
|
## Start your development server
|
||||||
|
npm run start
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then access a hot reloaded version of the interface at
|
||||||
|
`http://localhost:9000`.
|
||||||
|
|
||||||
|
If you set the URL to your running ship, like
|
||||||
|
`http://sampel-palnet.arvo.network`, then you can use your actual ship while
|
||||||
|
running local-only development changes.
|
||||||
|
|
||||||
|
As previously stated, if your changes require back-end development (front-end
|
||||||
|
and Gall changes, for example), or you just want an empty development
|
||||||
|
environment, you'll want to create a development ship.
|
||||||
|
|
||||||
|
### Creating a development ship
|
||||||
|
|
||||||
[nix](https://github.com/NixOS/nix) and `git-lfs` should be installed at this
|
[nix](https://github.com/NixOS/nix) and `git-lfs` should be installed at this
|
||||||
point, and have been used to `make build` the project.
|
point, and have been used to `make build` the project.
|
||||||
|
|
||||||
Designing interfaces within urbit/urbit additionally requires that the
|
First follow the
|
||||||
[instructions](https://urbit.org/using/develop/#creating-a-development-ship) for
|
[instructions](https://urbit.org/using/develop/#creating-a-development-ship) for
|
||||||
fake `~zod` initialization have been followed.
|
fake `~zod` initialization.
|
||||||
|
|
||||||
Once your fake ship is running and you see
|
Once your fake ship is running and you see
|
||||||
```
|
```
|
||||||
@ -32,43 +111,27 @@ in your console, be sure to 'mount' your ship's working state (what we call
|
|||||||
'desks') to your local machine via the `|mount %` command. This will ensure that
|
'desks') to your local machine via the `|mount %` command. This will ensure that
|
||||||
code you modify locally can be committed to your ship and initialized.
|
code you modify locally can be committed to your ship and initialized.
|
||||||
|
|
||||||
To begin developing Urbit's frontend, you'll need to sync your currently-running
|
|
||||||
fake ship with the urbit/urbit repo's code. Find the `urbitrc-sample` file found
|
|
||||||
at `urbit/pkg/interface/config/urbitrc-sample`. Open it using your preferred
|
|
||||||
code editor and you should see the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
module.exports = {
|
|
||||||
URBIT_PIERS: [
|
|
||||||
"/Users/user/ships/zod/home",
|
|
||||||
]
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
Edit the path between quotes `/Users/user/ships/zod/home` with wherever your
|
|
||||||
fake ship is located on your machine. This zod location path *must* end in
|
|
||||||
`../home` to correctly intitalize any code you write. Save the file as `urbitrc`
|
|
||||||
inside that same folder. Any code edited within the `urbit/urbit` will now be
|
|
||||||
able to be synced to your running ship, and previewed in the browser.
|
|
||||||
|
|
||||||
To set up urbit's Javascript environment, you'll need node (ideally installed
|
To set up urbit's Javascript environment, you'll need node (ideally installed
|
||||||
via [nvm](https://github.com/nvm-sh/nvm)) and webpack, which will be installed via
|
via [nvm](https://github.com/nvm-sh/nvm)) and webpack, which will be installed
|
||||||
node.
|
via node.
|
||||||
|
|
||||||
Perform the following steps to get the above set up for urbit's apps:
|
If you want to copy the code into your ship, perform the following steps:
|
||||||
|
|
||||||
```
|
```
|
||||||
## go to urbit's interface directory and install the required tooling
|
## go to urbit's interface directory and install the required tooling
|
||||||
cd urbit/pkg/interface
|
cd urbit/pkg/interface
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
## Start watching the entire directory for changes
|
## Build the JS code
|
||||||
npm run build:dev
|
npm run build:dev
|
||||||
```
|
```
|
||||||
|
|
||||||
Any changes made to any files within the `/pkg/interface` directory will now trigger
|
If you want to run the JavaScript code in a dev server, you can simply set the
|
||||||
a gulp rebuild when saved. To sync these changes to your running ship, enter
|
URL in your `urbitrc` to `localhost:80` and `npm run start` instead.
|
||||||
dojo and input the following:
|
|
||||||
|
If you set your pier in `urbitrc`, and uncommented the code in the webpack
|
||||||
|
config, then once the build process is running, commit on your ship to copy the
|
||||||
|
changed JS code in:
|
||||||
|
|
||||||
```
|
```
|
||||||
|commit %home
|
|commit %home
|
||||||
@ -78,19 +141,21 @@ Your urbit should take a moment to process the changes, and will emit a `>=`.
|
|||||||
Refreshing your browser will display the newly-rendered interface.
|
Refreshing your browser will display the newly-rendered interface.
|
||||||
|
|
||||||
Once you are done editing code, and wish to commit changes to git, stop your
|
Once you are done editing code, and wish to commit changes to git, stop your
|
||||||
`build:dev` process. Do not commit compiled code, but submit the source code
|
process. Do not commit compiled code, but submit the source code
|
||||||
for review.
|
for review.
|
||||||
|
|
||||||
Please also ensure your pull request fits our standards for [Git
|
Please also ensure your pull request fits our standards for [Git
|
||||||
hygiene][contributing].
|
hygiene][contributing].
|
||||||
|
|
||||||
[contributing]: /CONTRIBUTING.md#git-practice [arvo]: /pkg/arvo
|
[contributing]: /CONTRIBUTING.md#git-practice
|
||||||
|
[arvo]: /pkg/arvo
|
||||||
[interface]:/pkg/interface
|
[interface]:/pkg/interface
|
||||||
|
|
||||||
## Linting
|
## Linting
|
||||||
|
|
||||||
The Urbit interface uses Eslint to lint the JavaScript code. To install the
|
The Urbit interface uses Eslint to lint the JavaScript code. To install the
|
||||||
linter and for usage through the command, do the following:
|
linter and for usage through the command, do the following:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cd ./pkg/interface
|
$ cd ./pkg/interface
|
||||||
$ npm install
|
$ npm install
|
||||||
@ -98,6 +163,7 @@ $ npm run lint
|
|||||||
```
|
```
|
||||||
|
|
||||||
To use the linter, run npm scripts
|
To use the linter, run npm scripts
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm run lint # lints all files in `interface`
|
$ npm run lint # lints all files in `interface`
|
||||||
$ npm run lint-file ./src/apps/chat/**/*.js # lints all .js files in `interface/chat`
|
$ npm run lint-file ./src/apps/chat/**/*.js # lints all .js files in `interface/chat`
|
||||||
@ -119,7 +185,8 @@ documentation for its everyday use -- just create a repo [using its
|
|||||||
template][template], install and then start it, and you'll soon be up and
|
template][template], install and then start it, and you'll soon be up and
|
||||||
running.
|
running.
|
||||||
|
|
||||||
[cla]: https://github.com/urbit/create-landscape-app [template]:
|
[cla]: https://github.com/urbit/create-landscape-app
|
||||||
https://github.com/urbit/create-landscape-app/generate [gall]:
|
[template]: https://github.com/urbit/create-landscape-app/generate
|
||||||
https://urbit.org/docs/learn/arvo/gall/ [chat]: /pkg/arvo/app/chat-view.hoon
|
[gall]:https://urbit.org/docs/learn/arvo/gall/
|
||||||
|
[chat]: /pkg/arvo/app/chat-view.hoon
|
||||||
[publish]: /pkg/arvo/app/publish.hoon
|
[publish]: /pkg/arvo/app/publish.hoon
|
@ -2,5 +2,6 @@ module.exports = {
|
|||||||
URBIT_PIERS: [
|
URBIT_PIERS: [
|
||||||
"/Users/user/ships/zod/home",
|
"/Users/user/ships/zod/home",
|
||||||
],
|
],
|
||||||
herb: false
|
herb: false,
|
||||||
|
URL: 'http://localhost:80'
|
||||||
};
|
};
|
||||||
|
@ -22,22 +22,49 @@ class UrbitShipPlugin {
|
|||||||
'UrbitShipPlugin',
|
'UrbitShipPlugin',
|
||||||
async (compilation) => {
|
async (compilation) => {
|
||||||
const src = path.resolve(compiler.options.output.path, 'index.js');
|
const src = path.resolve(compiler.options.output.path, 'index.js');
|
||||||
return Promise.all(this.piers.map(pier => {
|
// uncomment to copy into all piers
|
||||||
const dst = path.resolve(pier, 'app/landscape/js/index.js');
|
//
|
||||||
copyFile(src, dst).then(() => {
|
// return Promise.all(this.piers.map(pier => {
|
||||||
if(!this.herb) {
|
// const dst = path.resolve(pier, 'app/landscape/js/index.js');
|
||||||
return;
|
// copyFile(src, dst).then(() => {
|
||||||
}
|
// if(!this.herb) {
|
||||||
pier = pier.split('/');
|
// return;
|
||||||
const desk = pier.pop();
|
// }
|
||||||
return exec(`herb -p hood -d '+hood/commit %${desk}' ${pier.join('/')}`);
|
// pier = pier.split('/');
|
||||||
});
|
// const desk = pier.pop();
|
||||||
}));
|
// return exec(`herb -p hood -d '+hood/commit %${desk}' ${pier.join('/')}`);
|
||||||
|
// });
|
||||||
|
// }));
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let devServer = {
|
||||||
|
contentBase: path.join(__dirname, '../dist'),
|
||||||
|
hot: true,
|
||||||
|
port: 9000,
|
||||||
|
historyApiFallback: true
|
||||||
|
};
|
||||||
|
|
||||||
|
if(urbitrc.URL) {
|
||||||
|
devServer = {
|
||||||
|
...devServer,
|
||||||
|
index: '',
|
||||||
|
proxy: {
|
||||||
|
'/~landscape/js/index.js': {
|
||||||
|
target: 'http://localhost:9000',
|
||||||
|
pathRewrite: (req, path) => '/index.js'
|
||||||
|
},
|
||||||
|
'**': {
|
||||||
|
target: urbitrc.URL,
|
||||||
|
// ensure proxy doesn't timeout channels
|
||||||
|
proxyTimeout: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
entry: {
|
entry: {
|
||||||
@ -54,7 +81,8 @@ module.exports = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
'@babel/plugin-proposal-object-rest-spread',
|
'@babel/plugin-proposal-object-rest-spread',
|
||||||
'@babel/plugin-proposal-optional-chaining',
|
'@babel/plugin-proposal-optional-chaining',
|
||||||
'@babel/plugin-proposal-class-properties'
|
'@babel/plugin-proposal-class-properties',
|
||||||
|
'react-hot-loader/babel'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -77,12 +105,7 @@ module.exports = {
|
|||||||
extensions: ['.js', '.ts', '.tsx']
|
extensions: ['.js', '.ts', '.tsx']
|
||||||
},
|
},
|
||||||
devtool: 'inline-source-map',
|
devtool: 'inline-source-map',
|
||||||
// devServer: {
|
devServer: devServer,
|
||||||
// contentBase: path.join(__dirname, './'),
|
|
||||||
// hot: true,
|
|
||||||
// port: 9000,
|
|
||||||
// historyApiFallback: true
|
|
||||||
// },
|
|
||||||
plugins: [
|
plugins: [
|
||||||
new UrbitShipPlugin(urbitrc)
|
new UrbitShipPlugin(urbitrc)
|
||||||
// new CleanWebpackPlugin(),
|
// new CleanWebpackPlugin(),
|
||||||
|
143
pkg/interface/package-lock.json
generated
143
pkg/interface/package-lock.json
generated
@ -3510,6 +3510,12 @@
|
|||||||
"entities": "^2.0.0"
|
"entities": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dom-walk": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"domain-browser": {
|
"domain-browser": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
|
||||||
@ -4761,6 +4767,16 @@
|
|||||||
"is-glob": "^4.0.1"
|
"is-glob": "^4.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"global": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"min-document": "^2.19.0",
|
||||||
|
"process": "^0.11.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"global-modules": {
|
"global-modules": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
|
||||||
@ -6113,6 +6129,15 @@
|
|||||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"min-document": {
|
||||||
|
"version": "2.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
|
||||||
|
"integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"dom-walk": "^0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"mini-create-react-context": {
|
"mini-create-react-context": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz",
|
||||||
@ -7327,11 +7352,41 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
||||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
||||||
},
|
},
|
||||||
|
"react-hot-loader": {
|
||||||
|
"version": "4.12.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.12.21.tgz",
|
||||||
|
"integrity": "sha512-Ynxa6ROfWUeKWsTHxsrL2KMzujxJVPjs385lmB2t5cHUxdoRPGind9F00tOkdc1l5WBleOF4XEAMILY1KPIIDA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"fast-levenshtein": "^2.0.6",
|
||||||
|
"global": "^4.3.0",
|
||||||
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
|
"loader-utils": "^1.1.0",
|
||||||
|
"prop-types": "^15.6.1",
|
||||||
|
"react-lifecycles-compat": "^3.0.4",
|
||||||
|
"shallowequal": "^1.1.0",
|
||||||
|
"source-map": "^0.7.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"react-lifecycles-compat": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"react-markdown": {
|
"react-markdown": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-4.3.1.tgz",
|
||||||
@ -9452,8 +9507,7 @@
|
|||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -9474,14 +9528,12 @@
|
|||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@ -9496,20 +9548,17 @@
|
|||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@ -9626,8 +9675,7 @@
|
|||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@ -9639,7 +9687,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -9654,7 +9701,6 @@
|
|||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
@ -9662,14 +9708,12 @@
|
|||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.9.0",
|
"version": "2.9.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@ -9688,7 +9732,6 @@
|
|||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
@ -9750,8 +9793,7 @@
|
|||||||
"npm-normalize-package-bin": {
|
"npm-normalize-package-bin": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"npm-packlist": {
|
"npm-packlist": {
|
||||||
"version": "1.4.8",
|
"version": "1.4.8",
|
||||||
@ -9779,8 +9821,7 @@
|
|||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@ -9792,7 +9833,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@ -9870,8 +9910,7 @@
|
|||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@ -9907,7 +9946,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@ -9927,7 +9965,6 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@ -9971,14 +10008,12 @@
|
|||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -10459,8 +10494,7 @@
|
|||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -10481,14 +10515,12 @@
|
|||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@ -10503,20 +10535,17 @@
|
|||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@ -10633,8 +10662,7 @@
|
|||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@ -10646,7 +10674,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -10661,7 +10688,6 @@
|
|||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
@ -10669,14 +10695,12 @@
|
|||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.9.0",
|
"version": "2.9.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@ -10695,7 +10719,6 @@
|
|||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
@ -10757,8 +10780,7 @@
|
|||||||
"npm-normalize-package-bin": {
|
"npm-normalize-package-bin": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"npm-packlist": {
|
"npm-packlist": {
|
||||||
"version": "1.4.8",
|
"version": "1.4.8",
|
||||||
@ -10786,8 +10808,7 @@
|
|||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@ -10799,7 +10820,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@ -10877,8 +10897,7 @@
|
|||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@ -10914,7 +10933,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@ -10934,7 +10952,6 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@ -10978,14 +10995,12 @@
|
|||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
"eslint-plugin-react": "^7.19.0",
|
"eslint-plugin-react": "^7.19.0",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
"html-webpack-plugin": "^4.2.0",
|
"html-webpack-plugin": "^4.2.0",
|
||||||
|
"react-hot-loader": "^4.12.21",
|
||||||
"sass": "^1.26.5",
|
"sass": "^1.26.5",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.43.0",
|
||||||
@ -59,7 +60,7 @@
|
|||||||
"tsc:watch": "tsc --watch",
|
"tsc:watch": "tsc --watch",
|
||||||
"build:dev": "cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
|
"build:dev": "cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
|
||||||
"build:prod": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js",
|
"build:prod": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js",
|
||||||
"start": "webpack-dev-server",
|
"start": "webpack-dev-server --config config/webpack.dev.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { hot } from 'react-hot-loader/root';
|
||||||
|
import 'react-hot-loader';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { BrowserRouter as Router, Route, withRouter, Switch } from 'react-router-dom';
|
import { BrowserRouter as Router, Route, withRouter, Switch } from 'react-router-dom';
|
||||||
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
|
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
|
||||||
@ -32,7 +34,6 @@ import GlobalApi from './api/global';
|
|||||||
|
|
||||||
const Root = styled.div`
|
const Root = styled.div`
|
||||||
font-family: ${p => p.theme.fonts.sans};
|
font-family: ${p => p.theme.fonts.sans};
|
||||||
line-height: ${p => p.theme.lineHeights.regular};
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -45,7 +46,7 @@ const Content = styled.div`
|
|||||||
|
|
||||||
const StatusBarWithRouter = withRouter(StatusBar);
|
const StatusBarWithRouter = withRouter(StatusBar);
|
||||||
|
|
||||||
export default class App extends React.Component {
|
class App extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.ship = window.ship;
|
this.ship = window.ship;
|
||||||
@ -61,6 +62,7 @@ export default class App extends React.Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.subscription.start();
|
this.subscription.start();
|
||||||
|
this.api.local.getBaseHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -78,6 +80,8 @@ export default class App extends React.Component {
|
|||||||
associations={associations}
|
associations={associations}
|
||||||
invites={this.state.invites}
|
invites={this.state.invites}
|
||||||
api={this.api}
|
api={this.api}
|
||||||
|
connection={this.state.connection}
|
||||||
|
subscription={this.subscription}
|
||||||
/>
|
/>
|
||||||
<Content>
|
<Content>
|
||||||
<Switch>
|
<Switch>
|
||||||
@ -152,3 +156,5 @@ export default class App extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default process.env.NODE_ENV === 'production' ? App : hot(App);
|
||||||
|
|
||||||
|
@ -53,4 +53,8 @@ export default class BaseApi<S extends object = {}> {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scry<T>(app: string, path: Path): Promise<T> {
|
||||||
|
return fetch(`/~/scry/${app}${path}.json`).then(r => r.json() as Promise<T>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,13 @@ import BaseApi from "./base";
|
|||||||
import { StoreState } from "../store/type";
|
import { StoreState } from "../store/type";
|
||||||
import { SelectedGroup } from "../types/local-update";
|
import { SelectedGroup } from "../types/local-update";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default class LocalApi extends BaseApi<StoreState> {
|
export default class LocalApi extends BaseApi<StoreState> {
|
||||||
|
getBaseHash() {
|
||||||
|
this.scry<string>('file-server', '/clay/base/hash').then(baseHash => {
|
||||||
|
this.store.handleEvent({ data: { local: { baseHash } } });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setSelected(selected: SelectedGroup[]) {
|
setSelected(selected: SelectedGroup[]) {
|
||||||
this.store.handleEvent({
|
this.store.handleEvent({
|
||||||
data: {
|
data: {
|
||||||
|
@ -73,6 +73,7 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
|||||||
unreads[stat] = Boolean(unread);
|
unreads[stat] = Boolean(unread);
|
||||||
if (
|
if (
|
||||||
unread &&
|
unread &&
|
||||||
|
stat in associations.chat &&
|
||||||
(selectedGroups.length === 0 ||
|
(selectedGroups.length === 0 ||
|
||||||
selectedGroups
|
selectedGroups
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
@ -87,7 +88,7 @@ export default class ChatApp extends React.Component<ChatAppProps, {}> {
|
|||||||
|
|
||||||
if (totalUnreads !== this.totalUnreads) {
|
if (totalUnreads !== this.totalUnreads) {
|
||||||
document.title =
|
document.title =
|
||||||
totalUnreads > 0 ? `OS1 - Chat (${totalUnreads})` : 'OS1 - Chat';
|
totalUnreads > 0 ? `(${totalUnreads}) OS1 - Chat` : 'OS1 - Chat';
|
||||||
this.totalUnreads = totalUnreads;
|
this.totalUnreads = totalUnreads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component, Fragment } from "react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
|
||||||
@ -359,6 +359,10 @@ export class ChatScreen extends Component<ChatScreenProps, ChatScreenState> {
|
|||||||
props.pendingMessages.get(props.station) || []
|
props.pendingMessages.get(props.station) || []
|
||||||
).map((value) => ({ ...value, pending: true }));
|
).map((value) => ({ ...value, pending: true }));
|
||||||
|
|
||||||
|
if(unread !== 0) {
|
||||||
|
unread += pendingMessages.length;
|
||||||
|
}
|
||||||
|
|
||||||
messages = pendingMessages.concat(messages);
|
messages = pendingMessages.concat(messages);
|
||||||
|
|
||||||
const messageElements = messages.map((msg, i) => {
|
const messageElements = messages.map((msg, i) => {
|
||||||
@ -389,10 +393,9 @@ export class ChatScreen extends Component<ChatScreenProps, ChatScreenState> {
|
|||||||
);
|
);
|
||||||
if (unread > 0 && i === unread - 1) {
|
if (unread > 0 && i === unread - 1) {
|
||||||
return (
|
return (
|
||||||
<>
|
<Fragment key={msg.uid}>
|
||||||
{messageElem}
|
{messageElem}
|
||||||
<div
|
<div
|
||||||
key={"unreads" + msg.uid}
|
|
||||||
ref={this.setUnreadMarker}
|
ref={this.setUnreadMarker}
|
||||||
className="mv2 green2 flex items-center f9"
|
className="mv2 green2 flex items-center f9"
|
||||||
>
|
>
|
||||||
@ -409,19 +412,18 @@ export class ChatScreen extends Component<ChatScreenProps, ChatScreenState> {
|
|||||||
className="b--green2 ma0 bt-0"
|
className="b--green2 ma0 bt-0"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</Fragment>
|
||||||
);
|
);
|
||||||
} else if (dayBreak) {
|
} else if (dayBreak) {
|
||||||
return (
|
return (
|
||||||
<>
|
<Fragment key={msg.uid}>
|
||||||
{messageElem}
|
{messageElem}
|
||||||
<div
|
<div
|
||||||
key={"daybreak" + msg.uid}
|
|
||||||
className="pv3 gray2 b--gray2 flex items-center justify-center f9 "
|
className="pv3 gray2 b--gray2 flex items-center justify-center f9 "
|
||||||
>
|
>
|
||||||
<p>{moment(_.get(messages[i], when)).calendar()}</p>
|
<p>{moment(_.get(messages[i], when)).calendar()}</p>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</Fragment>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return messageElem;
|
return messageElem;
|
||||||
|
@ -23,7 +23,7 @@ export class ChannelItem extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={'z1 ph4 pb1 ' + selectedCss}
|
className={'z1 ph4 pv1 ' + selectedCss}
|
||||||
onClick={this.onClick.bind(this)}
|
onClick={this.onClick.bind(this)}
|
||||||
>
|
>
|
||||||
<div className="w-100 v-mid">
|
<div className="w-100 v-mid">
|
||||||
|
@ -51,7 +51,7 @@ export class ChatTabBar extends Component {
|
|||||||
<a href={'/~chat/popout/room' + props.station} rel="noopener noreferrer"
|
<a href={'/~chat/popout/room' + props.station} rel="noopener noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="dib fr pr1"
|
className="dib fr pr1"
|
||||||
style={{ paddingTop: '5px' }}
|
style={{ paddingTop: '8px' }}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
className={'flex-shrink-0 pr3 dn ' + hidePopoutIcon}
|
className={'flex-shrink-0 pr3 dn ' + hidePopoutIcon}
|
||||||
|
@ -138,7 +138,7 @@ export class Sidebar extends Component {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`h-100-minus-96-s h-100 w-100 overflow-x-hidden flex
|
className={`h-100-minus-96-s h-100 w-100 overflow-x-hidden flex
|
||||||
bg-gray0-d flex-column relative z1`}
|
bg-gray0-d flex-column relative z1 lh-solid`}
|
||||||
>
|
>
|
||||||
<div className="w-100 bg-transparent pa4">
|
<div className="w-100 bg-transparent pa4">
|
||||||
<a
|
<a
|
||||||
|
@ -27,7 +27,7 @@ export class Welcome extends Component {
|
|||||||
|
|
||||||
return ((!wasWelcomed && this.state.show) && (contacts.length !== 0)) ? (
|
return ((!wasWelcomed && this.state.show) && (contacts.length !== 0)) ? (
|
||||||
<div className="ma4 pa2 bg-welcome-green bg-gray1-d white-d">
|
<div className="ma4 pa2 bg-welcome-green bg-gray1-d white-d">
|
||||||
<p className="f8 lh-copy">Each Group is a list of other Urbit IDs that share some set of modules: chats, links and notebooks.</p>
|
<p className="f8 lh-copy">Each Group is a list of other Urbit IDs that share some set of modules: chats, links, and notebooks.</p>
|
||||||
<p className="f8 pt2 dib pointer bb"
|
<p className="f8 pt2 dib pointer bb"
|
||||||
onClick={(() => this.disableWelcome())}
|
onClick={(() => this.disableWelcome())}
|
||||||
>
|
>
|
||||||
|
@ -24,6 +24,7 @@ export default class LaunchApp extends React.Component {
|
|||||||
const { props } = this;
|
const { props } = this;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className="h-100 flex flex-column h-100">
|
||||||
<div className='v-mid ph2 dtc-m dtc-l dtc-xl flex justify-between flex-wrap' style={{ maxWidth: '40rem' }}>
|
<div className='v-mid ph2 dtc-m dtc-l dtc-xl flex justify-between flex-wrap' style={{ maxWidth: '40rem' }}>
|
||||||
<Welcome firstTime={props.launch.firstTime} api={props.api} />
|
<Welcome firstTime={props.launch.firstTime} api={props.api} />
|
||||||
<Tiles
|
<Tiles
|
||||||
@ -34,6 +35,8 @@ export default class LaunchApp extends React.Component {
|
|||||||
weather={props.weather}
|
weather={props.weather}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="absolute bottom-0 left-0 f9 gray2 ml4 mb4 f8"> {props.baseHash} </div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ export class LinksApp extends Component {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if(totalUnseen !== this.totalUnseen) {
|
if(totalUnseen !== this.totalUnseen) {
|
||||||
document.title = totalUnseen !== 0 ? `OS1 - Links (${totalUnseen})` : 'OS1 - Links';
|
document.title = totalUnseen !== 0 ? `(${totalUnseen}) OS1 - Links` : 'OS1 - Links';
|
||||||
this.totalUnseen = totalUnseen;
|
this.totalUnseen = totalUnseen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ export default class PublishApp extends React.Component {
|
|||||||
.value();
|
.value();
|
||||||
|
|
||||||
if (this.unreadTotal !== unreadTotal) {
|
if (this.unreadTotal !== unreadTotal) {
|
||||||
document.title = unreadTotal > 0 ? `OS1 - Publish (${unreadTotal})` : 'OS1 - Publish';
|
document.title = unreadTotal > 0 ? `(${unreadTotal}) OS1 - Publish` : 'OS1 - Publish';
|
||||||
this.unreadTotal = unreadTotal;
|
this.unreadTotal = unreadTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ export class Notebook extends Component {
|
|||||||
newPost = (
|
newPost = (
|
||||||
<Link
|
<Link
|
||||||
to={newUrl}
|
to={newUrl}
|
||||||
className='NotebookButton bg-light-green green2 ph2 pt3'
|
className='NotebookButton bg-light-green green2 pa2'
|
||||||
>
|
>
|
||||||
New Post
|
New Post
|
||||||
</Link>
|
</Link>
|
||||||
@ -169,7 +169,7 @@ export class Notebook extends Component {
|
|||||||
const unsub = (window.ship === props.ship.slice(1))
|
const unsub = (window.ship === props.ship.slice(1))
|
||||||
? null
|
? null
|
||||||
: <button onClick={this.unsubscribe}
|
: <button onClick={this.unsubscribe}
|
||||||
className="NotebookButton bg-white bg-gray0-d black white-d ba b--black b--gray2-d ml3"
|
className="NotebookButton bg-white bg-gray0-d black white-d ba b--black b--gray2-d ml3 ph1"
|
||||||
>
|
>
|
||||||
Unsubscribe
|
Unsubscribe
|
||||||
</button>;
|
</button>;
|
||||||
|
@ -97,7 +97,7 @@ export default class GroupFilter extends Component {
|
|||||||
selected: selected,
|
selected: selected,
|
||||||
results: []
|
results: []
|
||||||
}, (() => {
|
}, (() => {
|
||||||
this.props.api.setSelected(this.state.selected);
|
this.props.api.local.setSelected(this.state.selected);
|
||||||
localStorage.setItem('urbit-selectedGroups', JSON.stringify(this.state.selected));
|
localStorage.setItem('urbit-selectedGroups', JSON.stringify(this.state.selected));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ export default class GroupFilter extends Component {
|
|||||||
return e !== group;
|
return e !== group;
|
||||||
});
|
});
|
||||||
this.setState({ selected: selected }, (() => {
|
this.setState({ selected: selected }, (() => {
|
||||||
this.props.api.setSelected(this.state.selected);
|
this.props.api.local.setSelected(this.state.selected);
|
||||||
localStorage.setItem('urbit-selectedGroups', JSON.stringify(this.state.selected));
|
localStorage.setItem('urbit-selectedGroups', JSON.stringify(this.state.selected));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ export class SidebarSwitcher extends Component {
|
|||||||
|
|
||||||
const classes = this.props.classes ? this.props.classes : '';
|
const classes = this.props.classes ? this.props.classes : '';
|
||||||
|
|
||||||
const paddingTop = this.props.classes ? '0px' : '5px';
|
const paddingTop = this.props.classes ? '0px' : '8px';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes} style={{ paddingTop: paddingTop }}>
|
<div className={classes} style={{ paddingTop: paddingTop }}>
|
||||||
|
@ -33,6 +33,9 @@ const StatusBar = (props) => {
|
|||||||
const invites = (props.invites && props.invites['/contacts'])
|
const invites = (props.invites && props.invites['/contacts'])
|
||||||
? props.invites['/contacts']
|
? props.invites['/contacts']
|
||||||
: {};
|
: {};
|
||||||
|
const connection = props.connection || 'connected';
|
||||||
|
|
||||||
|
const reconnect = props.subscription.restart.bind(props.subscription);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -65,6 +68,15 @@ const StatusBar = (props) => {
|
|||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
<p className="dib f9 v-mid inter ml2 white-d">{locationName}</p>
|
<p className="dib f9 v-mid inter ml2 white-d">{locationName}</p>
|
||||||
|
{ connection === 'disconnected' &&
|
||||||
|
(<span
|
||||||
|
onClick={reconnect}
|
||||||
|
className="ml4 ph2 dib f9 v-mid red2 inter ba b-red2 br1 pointer"
|
||||||
|
>Reconnect ↻</span> )
|
||||||
|
}
|
||||||
|
{ connection === 'reconnecting' &&
|
||||||
|
(<span className="ml4 ph2 dib f9 v-mid yellow2 inter ba b-yellow2 br1">Reconnecting</span> )
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
14
pkg/interface/src/reducers/connection.ts
Normal file
14
pkg/interface/src/reducers/connection.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { StoreState } from '../store/type';
|
||||||
|
import { Cage } from '../types/cage';
|
||||||
|
|
||||||
|
type LocalState = Pick<StoreState, 'connection'>;
|
||||||
|
|
||||||
|
export default class ConnectionReducer<S extends LocalState> {
|
||||||
|
reduce(json: Cage, state: S) {
|
||||||
|
if('connection' in json && json.connection) {
|
||||||
|
console.log(`Conn: ${json.connection}`);
|
||||||
|
state.connection = json.connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ import { StoreState } from '../store/type';
|
|||||||
import { Cage } from '../types/cage';
|
import { Cage } from '../types/cage';
|
||||||
import { LocalUpdate } from '../types/local-update';
|
import { LocalUpdate } from '../types/local-update';
|
||||||
|
|
||||||
type LocalState = Pick<StoreState, 'sidebarShown' | 'selectedGroups'>;
|
type LocalState = Pick<StoreState, 'sidebarShown' | 'selectedGroups' | 'baseHash'>;
|
||||||
|
|
||||||
export default class LocalReducer<S extends LocalState> {
|
export default class LocalReducer<S extends LocalState> {
|
||||||
reduce(json: Cage, state: S) {
|
reduce(json: Cage, state: S) {
|
||||||
@ -11,8 +11,14 @@ export default class LocalReducer<S extends LocalState> {
|
|||||||
if (data) {
|
if (data) {
|
||||||
this.sidebarToggle(data, state);
|
this.sidebarToggle(data, state);
|
||||||
this.setSelected(data, state);
|
this.setSelected(data, state);
|
||||||
|
this.baseHash(data, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
baseHash(obj: LocalUpdate, state: S) {
|
||||||
|
if ('baseHash' in obj) {
|
||||||
|
state.baseHash = obj.baseHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sidebarToggle(obj: LocalUpdate, state: S) {
|
sidebarToggle(obj: LocalUpdate, state: S) {
|
||||||
if ('sidebarToggle' in obj) {
|
if ('sidebarToggle' in obj) {
|
||||||
|
@ -15,6 +15,7 @@ import PublishUpdateReducer from '../reducers/publish-update';
|
|||||||
import PublishResponseReducer from '../reducers/publish-response';
|
import PublishResponseReducer from '../reducers/publish-response';
|
||||||
import LaunchReducer from '../reducers/launch-update';
|
import LaunchReducer from '../reducers/launch-update';
|
||||||
import LinkListenReducer from '../reducers/listen-update';
|
import LinkListenReducer from '../reducers/listen-update';
|
||||||
|
import ConnectionReducer from '../reducers/connection';
|
||||||
|
|
||||||
|
|
||||||
export default class GlobalStore extends BaseStore<StoreState> {
|
export default class GlobalStore extends BaseStore<StoreState> {
|
||||||
@ -31,13 +32,16 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
|||||||
publishUpdateReducer = new PublishUpdateReducer();
|
publishUpdateReducer = new PublishUpdateReducer();
|
||||||
publishResponseReducer = new PublishResponseReducer();
|
publishResponseReducer = new PublishResponseReducer();
|
||||||
launchReducer = new LaunchReducer();
|
launchReducer = new LaunchReducer();
|
||||||
|
connReducer = new ConnectionReducer();
|
||||||
|
|
||||||
|
|
||||||
initialState(): StoreState {
|
initialState(): StoreState {
|
||||||
return {
|
return {
|
||||||
pendingMessages: new Map(),
|
pendingMessages: new Map(),
|
||||||
chatInitialized: false,
|
chatInitialized: false,
|
||||||
|
connection: 'connected',
|
||||||
sidebarShown: true,
|
sidebarShown: true,
|
||||||
|
baseHash: null,
|
||||||
invites: {},
|
invites: {},
|
||||||
associations: {
|
associations: {
|
||||||
chat: {},
|
chat: {},
|
||||||
@ -88,5 +92,6 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
|||||||
this.publishResponseReducer.reduce(data, this.state);
|
this.publishResponseReducer.reduce(data, this.state);
|
||||||
this.launchReducer.reduce(data, this.state);
|
this.launchReducer.reduce(data, this.state);
|
||||||
this.linkListenReducer.reduce(data, this.state);
|
this.linkListenReducer.reduce(data, this.state);
|
||||||
|
this.connReducer.reduce(data, this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,14 @@ import { S3State } from '../types/s3-update';
|
|||||||
import { Permissions } from '../types/permission-update';
|
import { Permissions } from '../types/permission-update';
|
||||||
import { LaunchState, WeatherState } from '../types/launch-update';
|
import { LaunchState, WeatherState } from '../types/launch-update';
|
||||||
import { LinkComments, LinkCollections, LinkSeen } from '../types/link-update';
|
import { LinkComments, LinkCollections, LinkSeen } from '../types/link-update';
|
||||||
|
import { ConnectionStatus } from '../types/connection';
|
||||||
|
|
||||||
export interface StoreState {
|
export interface StoreState {
|
||||||
// local state
|
// local state
|
||||||
sidebarShown: boolean;
|
sidebarShown: boolean;
|
||||||
selectedGroups: SelectedGroup[];
|
selectedGroups: SelectedGroup[];
|
||||||
|
connection: ConnectionStatus;
|
||||||
|
baseHash: string | null;
|
||||||
// invite state
|
// invite state
|
||||||
invites: Invites;
|
invites: Invites;
|
||||||
// metadata state
|
// metadata state
|
||||||
|
@ -3,20 +3,39 @@ import BaseApi from "../api/base";
|
|||||||
import { Path } from "../types/noun";
|
import { Path } from "../types/noun";
|
||||||
|
|
||||||
export default class BaseSubscription<S extends object> {
|
export default class BaseSubscription<S extends object> {
|
||||||
|
private errorCount = 0;
|
||||||
constructor(public store: BaseStore<S>, public api: BaseApi<S>, public channel: any) {
|
constructor(public store: BaseStore<S>, public api: BaseApi<S>, public channel: any) {
|
||||||
this.channel.setOnChannelError(this.onChannelError.bind(this));
|
this.channel.setOnChannelError(this.onChannelError.bind(this));
|
||||||
|
this.channel.setOnChannelOpen(this.onChannelOpen.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.channel.delete();
|
this.channel.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exists to allow subclasses to hook
|
||||||
|
restart() {
|
||||||
|
this.handleEvent({ data: { connection: 'reconnecting' }});
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
onChannelOpen(e: any) {
|
||||||
|
this.errorCount = 0;
|
||||||
|
this.handleEvent({ data: { connection: 'connected' }});
|
||||||
|
}
|
||||||
|
|
||||||
onChannelError(err) {
|
onChannelError(err) {
|
||||||
console.error('event source error: ', err);
|
console.error('event source error: ', err);
|
||||||
|
this.errorCount++;
|
||||||
|
if(this.errorCount >= 5) {
|
||||||
|
console.error("bailing out, too many retries");
|
||||||
|
this.handleEvent({ data: { connection: 'disconnected' }});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.handleEvent({ data: { connection: 'reconnecting' }});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.store.clear();
|
this.restart();
|
||||||
this.start();
|
}, Math.pow(2,this.errorCount - 1) * 750);
|
||||||
}, 2000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(path: Path, app: string) {
|
subscribe(path: Path, app: string) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import BaseSubscription from './base';
|
import BaseSubscription from './base';
|
||||||
import { StoreState } from '../store/type';
|
import { StoreState } from '../store/type';
|
||||||
import { Path } from '../types/noun';
|
import { Path } from '../types/noun';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,6 +54,16 @@ export default class GlobalSubscription extends BaseSubscription<StoreState> {
|
|||||||
this.subscribe('/all', 'weather');
|
this.subscribe('/all', 'weather');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restart() {
|
||||||
|
super.restart();
|
||||||
|
_.mapValues(this.openSubscriptions, (subs, app: AppName) => {
|
||||||
|
if(subs.length > 0) {
|
||||||
|
this.stopApp(app);
|
||||||
|
this.startApp(app);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
startApp(app: AppName) {
|
startApp(app: AppName) {
|
||||||
if(this.openSubscriptions[app].length > 0) {
|
if(this.openSubscriptions[app].length > 0) {
|
||||||
console.log(`${app} already started`);
|
console.log(`${app} already started`);
|
||||||
|
@ -10,6 +10,7 @@ import { GroupUpdate } from "./group-update";
|
|||||||
import { PermissionUpdate } from "./permission-update";
|
import { PermissionUpdate } from "./permission-update";
|
||||||
import { LaunchUpdate, WeatherState } from "./launch-update";
|
import { LaunchUpdate, WeatherState } from "./launch-update";
|
||||||
import { LinkListenUpdate } from './link-listen-update';
|
import { LinkListenUpdate } from './link-listen-update';
|
||||||
|
import { ConnectionStatus } from "./connection";
|
||||||
|
|
||||||
interface MarksToTypes {
|
interface MarksToTypes {
|
||||||
readonly json: any;
|
readonly json: any;
|
||||||
@ -28,6 +29,7 @@ interface MarksToTypes {
|
|||||||
readonly 'local': LocalUpdate;
|
readonly 'local': LocalUpdate;
|
||||||
readonly 'weather': WeatherState | {};
|
readonly 'weather': WeatherState | {};
|
||||||
readonly 'location': string;
|
readonly 'location': string;
|
||||||
|
readonly 'connection': ConnectionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Cage = Partial<MarksToTypes>;
|
export type Cage = Partial<MarksToTypes>;
|
||||||
|
2
pkg/interface/src/types/connection.ts
Normal file
2
pkg/interface/src/types/connection.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
export type ConnectionStatus = 'reconnecting' | 'disconnected' | 'connected';
|
@ -2,7 +2,8 @@ import { Path } from './noun';
|
|||||||
|
|
||||||
export type LocalUpdate =
|
export type LocalUpdate =
|
||||||
LocalUpdateSidebarToggle
|
LocalUpdateSidebarToggle
|
||||||
| LocalUpdateSelectedGroups;
|
| LocalUpdateSelectedGroups
|
||||||
|
| LocalUpdateBaseHash;
|
||||||
|
|
||||||
interface LocalUpdateSidebarToggle {
|
interface LocalUpdateSidebarToggle {
|
||||||
sidebarToggle: boolean;
|
sidebarToggle: boolean;
|
||||||
@ -12,4 +13,8 @@ interface LocalUpdateSelectedGroups {
|
|||||||
selected: SelectedGroup[];
|
selected: SelectedGroup[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LocalUpdateBaseHash {
|
||||||
|
baseHash: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type SelectedGroup = [Path, string];
|
export type SelectedGroup = [Path, string];
|
||||||
|
Loading…
Reference in New Issue
Block a user