on master help sign in
visual qa && lint fixes
7701299Liam Fitzgerald
src/Bridge.js+1−1
@@ -20,7 +20,7 @@ import WithErrorBoundary from 'components/WithErrorBoundary';
20import GlobalErrorBoundary from 'components/GlobalErrorBoundary';
20import GlobalErrorBoundary from 'components/GlobalErrorBoundary';
21
21
22const INITIAL_NETWORK_TYPE = isDevelopment
22const INITIAL_NETWORK_TYPE = isDevelopment
23− ? NETWORK_TYPES.LOCAL
23+ ? NETWORK_TYPES.ROPSTEN
24 : NETWORK_TYPES.MAINNET;
24 : NETWORK_TYPES.MAINNET;
25
25
26// NB(shrugs): modify these variables to change the default local state.
26// NB(shrugs): modify these variables to change the default local state.
src/components/Buttons.js−6
@@ -23,9 +23,3 @@ export const OfflineButton = props => (
23 Offline
23 Offline
24 </OutButton>
24 </OutButton>
25);
25);
26−
27−export const HostingButton = props => (
28− <ForwardButton detail="Boot your Urbit OS" {...props}>
29− Boot your Urbit OS
30− </ForwardButton>
31−);
src/components/Greeting.js−6
@@ -3,18 +3,12 @@ import cn from 'classnames';
3import ob from 'urbit-ob';
3import ob from 'urbit-ob';
4import { Grid, Text, LinkButton } from 'indigo-react';
4import { Grid, Text, LinkButton } from 'indigo-react';
5
5
6−import { useLocalRouter } from 'lib/LocalRouter';
7−
8import useWasGreeted from 'lib/useWasGreeted';
6import useWasGreeted from 'lib/useWasGreeted';
9−import useCurrentPermissions from 'lib/useCurrentPermissions';
10
7
11const TEXT_STYLE = 'f5';
8const TEXT_STYLE = 'f5';
12
9
13export default function ActivateDisclaimer({ point }) {
10export default function ActivateDisclaimer({ point }) {
14− const { push, names } = useLocalRouter();
15−
16 const [wasGreeted, setWasGreeted] = useWasGreeted();
11 const [wasGreeted, setWasGreeted] = useWasGreeted();
17− const { isActiveOwner } = useCurrentPermissions();
18
12
19 const pointName = ob.patp(point);
13 const pointName = ob.patp(point);
20
14
src/components/InlineEthereumTransaction.js+1−2
@@ -8,7 +8,6 @@ import {
8 LinkButton,
8 LinkButton,
9 H5,
9 H5,
10 Text,
10 Text,
11− IconButton,
12} from 'indigo-react';
11} from 'indigo-react';
13import { toBN } from 'web3-utils';
12import { toBN } from 'web3-utils';
14
13
@@ -16,7 +15,6 @@ import { ReactComponent as InfoIcon } from 'assets/info.svg';
16
15
17import { useExploreTxUrls } from 'lib/explorer';
16import { useExploreTxUrls } from 'lib/explorer';
18import { hexify } from 'lib/txn';
17import { hexify } from 'lib/txn';
19−import pluralize from 'lib/pluralize';
20import { safeFromWei, safeToWei } from 'lib/lib';
18import { safeFromWei, safeToWei } from 'lib/lib';
21
19
22import { composeValidator, buildCheckboxValidator } from 'form/validators';
20import { composeValidator, buildCheckboxValidator } from 'form/validators';
@@ -275,6 +273,7 @@ export default function InlineEthereumTransaction({
275
273
276 {completed && (
274 {completed && (
277 <>
275 <>
276+ <Grid.Divider />
278 <Grid.Item full as={RestartButton} onClick={onReturn}>
277 <Grid.Item full as={RestartButton} onClick={onReturn}>
279 Return
278 Return
280 </Grid.Item>
279 </Grid.Item>
src/lib/hosting.js+2
@@ -18,6 +18,8 @@ export const getVaneName = code => {
18 return 'Iris';
18 return 'Iris';
19 case 'j':
19 case 'j':
20 return 'Jael';
20 return 'Jael';
21+ default:
22+ return '';
21 }
23 }
22};
24};
23
25
src/lib/routeNames.js−1
@@ -23,7 +23,6 @@ export const ROUTE_NAMES = {
23 INVITE_COHORT: Symbol('INVITE_COHORT'),
23 INVITE_COHORT: Symbol('INVITE_COHORT'),
24 STAR_RELEASE: Symbol('STAR_RELEASE'),
24 STAR_RELEASE: Symbol('STAR_RELEASE'),
25 URBIT_OS: Symbol('URBIT_OS'),
25 URBIT_OS: Symbol('URBIT_OS'),
26− HOSTING: Symbol('HOSTING'),
27 URBIT_ID: Symbol('URBIT_ID'),
26 URBIT_ID: Symbol('URBIT_ID'),
28 RESIDENTS: Symbol('RESIDENTS'),
27 RESIDENTS: Symbol('RESIDENTS'),
29 ADOPT: Symbol('ADOPT'),
28 ADOPT: Symbol('ADOPT'),
src/lib/router.js−4
@@ -18,8 +18,6 @@ import UrbitOS from 'views/UrbitOS';
18import UrbitID from 'views/UrbitID';
18import UrbitID from 'views/UrbitID';
19import Residents from 'views/Residents';
19import Residents from 'views/Residents';
20import Adopt from 'views/Adopt';
20import Adopt from 'views/Adopt';
21−import Boot from 'views/Boot';
22−import Hosting from 'views/Hosting';
23
21
24import { ROUTE_NAMES } from './routeNames';
22import { ROUTE_NAMES } from './routeNames';
25
23
@@ -41,8 +39,6 @@ export const ROUTES = {
41 [ROUTE_NAMES.INVITE_COHORT]: InviteCohort,
39 [ROUTE_NAMES.INVITE_COHORT]: InviteCohort,
42 [ROUTE_NAMES.STAR_RELEASE]: StarRelease,
40 [ROUTE_NAMES.STAR_RELEASE]: StarRelease,
43 [ROUTE_NAMES.URBIT_OS]: UrbitOS,
41 [ROUTE_NAMES.URBIT_OS]: UrbitOS,
44− [ROUTE_NAMES.BOOT]: Boot,
45− [ROUTE_NAMES.HOSTING]: Hosting,
46 [ROUTE_NAMES.URBIT_ID]: UrbitID,
42 [ROUTE_NAMES.URBIT_ID]: UrbitID,
47 [ROUTE_NAMES.RESIDENTS]: Residents,
43 [ROUTE_NAMES.RESIDENTS]: Residents,
48 [ROUTE_NAMES.ADOPT]: Adopt,
44 [ROUTE_NAMES.ADOPT]: Adopt,
src/lib/useEthereumTransaction.js+2−2
@@ -1,4 +1,4 @@
1−import { useCallback, useEffect, useState, useMemo } from 'react';
1+import { useCallback, useEffect, useState } from 'react';
2import { Just } from 'folktale/maybe';
2import { Just } from 'folktale/maybe';
3import { toBN } from 'web3-utils';
3import { toBN } from 'web3-utils';
4
4
@@ -22,7 +22,7 @@ import { ensureFundsFor } from 'lib/tank';
22import useDeepEqualReference from 'lib/useDeepEqualReference';
22import useDeepEqualReference from 'lib/useDeepEqualReference';
23import useGasPrice from 'lib/useGasPrice';
23import useGasPrice from 'lib/useGasPrice';
24import timeout from 'lib/timeout';
24import timeout from 'lib/timeout';
25−import { safeToWei, safeFromWei } from 'lib/lib';
25+import { safeToWei } from 'lib/lib';
26
26
27const STATE = {
27const STATE = {
28 NONE: 'NONE',
28 NONE: 'NONE',
src/lib/useHostedShip.jsdeleted−166
@@ -1,166 +0,0 @@
1−import { useCallback, useState } from 'react';
2−
3−const STATE = {
4− // container states
5− UNKNOWN: 'UNKNOWN',
6− MISSING: 'MISSING',
7− RUNNING: 'RUNNING',
8− PENDING: 'PENDING',
9− // api states
10− QUERYING: 'QUERYING',
11− BOOTING: 'BOOTING',
12− CONNECTING: 'CONNECTING',
13− // connection states
14− CONNECTED: 'CONNECTED',
15−};
16−
17−export function useHostedShip(client, patp) {
18− const [state, _setState] = useState(STATE.UNKNOWN);
19− const setState = useCallback(
20− s => {
21− console.log(s);
22− _setState(s);
23− },
24− [_setState]
25− );
26−
27− const [sysEvents, setSysEvents] = useState([]);
28− const [newEvents, setNewEvents] = useState([]);
29− const [runEvents, setRunEvents] = useState([]);
30−
31− const [error, _setError] = useState();
32− const setError = useCallback(
33− error => {
34− _setError(error);
35− if (error) {
36− setState(STATE.UNKNOWN);
37− console.error(error);
38− }
39− },
40− [_setError, setState]
41− );
42−
43− const unknown = state === STATE.UNKNOWN;
44− const missing = state === STATE.MISSING;
45− const running = state === STATE.RUNNING;
46− const pending = state === STATE.PENDING;
47− const querying = state === STATE.QUERYING;
48− const booting = state === STATE.BOOTING;
49− const connecting = state === STATE.CONNECTING;
50− const connected = state === STATE.CONNECTED;
51−
52− const resetEvents = useCallback(() => {
53− setSysEvents([]);
54− setNewEvents([]);
55− setRunEvents([]);
56− }, []);
57−
58− const getStatus = useCallback(async () => {
59− try {
60− setError(undefined);
61−
62− resetEvents();
63−
64− setState(STATE.QUERYING);
65−
66− const response = await client.getShipsByPatp(patp);
67−
68− if (response.status === 404) {
69− setState(STATE.MISSING);
70− } else if (!response.ok) {
71− setError(response.statusText);
72− } else {
73− const ship = await response.json();
74−
75− if (ship.status === 'Pending') {
76− setState(STATE.PENDING);
77− } else if (ship.status === 'Running') {
78− setState(STATE.RUNNING);
79− } else {
80− setError(ship);
81− }
82− }
83− } catch (error) {
84− setError(error);
85− }
86− }, [client, patp, resetEvents, setError, setState]);
87−
88− const getEvents = useCallback(() => {
89− try {
90− setError(undefined);
91−
92− resetEvents();
93−
94− setState(STATE.CONNECTING);
95−
96− const url = client.getShipsByPatpUrl(patp) + '/events';
97− const source = new EventSource(url);
98−
99− source.onopen = () => setState(STATE.CONNECTED);
100− // source.onerror = () => setState(STATE.UNKNOWN);
101− // source.onmessage = console.log;
102−
103− source.addEventListener('sys', event => {
104− setSysEvents(previous => [...previous, JSON.parse(event.data)]);
105− });
106−
107− source.addEventListener('new', event => {
108− if (event.data !== '') {
109− setNewEvents(previous => [...previous, event.data]);
110− }
111− });
112−
113− source.addEventListener('run', event => {
114− if (event.data !== '') {
115− setRunEvents(previous => [...previous, event.data]);
116− }
117− });
118− } catch (error) {
119− setError(error);
120− }
121− }, [setError, resetEvents, client, patp, setState]);
122−
123− const create = useCallback(async () => {
124− try {
125− setError(undefined);
126−
127− setState(STATE.BOOTING);
128−
129− const response = await client.postShips({
130− patp,
131− key: '123',
132− });
133−
134− if (!response.ok) {
135− setError(response.statusText);
136− } else {
137− getEvents();
138− }
139− } catch (error) {
140− setError(error);
141− }
142− }, [setError, setState, client, patp, getEvents]);
143−
144− return {
145− error,
146− unknown,
147− missing,
148− running,
149− pending,
150− querying,
151− booting,
152− connecting,
153− connected,
154−
155− sysEvents,
156− newEvents,
157− runEvents,
158−
159− getStatus,
160− getEvents,
161− create,
162−
163− // debugging
164− state,
165− };
166−}
src/store/lib/useHostingStore.js+5−9
@@ -1,13 +1,13 @@
1import { useState, useCallback, useMemo } from 'react';
1import { useState, useCallback, useMemo } from 'react';
2−import { Just, Nothing } from 'folktale/maybe';
2+import { Nothing } from 'folktale/maybe';
3import * as ob from 'urbit-ob';
3import * as ob from 'urbit-ob';
4
4
5import { getVaneName, getVaneNumber } from 'lib/hosting';
5import { getVaneName, getVaneNumber } from 'lib/hosting';
6import SolarisClient from 'lib/SolarisClient';
6import SolarisClient from 'lib/SolarisClient';
7+
7−// import { usePointCursor } from 'store/pointCursor';
8+import { usePointCursor } from 'store/pointCursor';
8−import useKeyfileGenerator from 'lib/useKeyfileGenerator';
9+
9const STATE = {
10const STATE = {
10− // container states
11 UNKNOWN: 'UNKNOWN',
11 UNKNOWN: 'UNKNOWN',
12 MISSING: 'MISSING',
12 MISSING: 'MISSING',
13 RUNNING: 'RUNNING',
13 RUNNING: 'RUNNING',
@@ -17,9 +17,7 @@ const STATE = {
17function useHostingStore(url) {
17function useHostingStore(url) {
18 const client = new SolarisClient(url);
18 const client = new SolarisClient(url);
19
19
20− // const { pointCursor } = usePointCursor();
20+ const { pointCursor } = usePointCursor();
21− //
22− const pointCursor = Just(ob.patp2dec('~wicdev-wisryt'));
23
21
24 const [bootProgress, setBootProgress] = useState(0);
22 const [bootProgress, setBootProgress] = useState(0);
25 const [bootMessage, setBootMessage] = useState('Assembling Urbit');
23 const [bootMessage, setBootMessage] = useState('Assembling Urbit');
@@ -182,8 +180,6 @@ function useHostingStore(url) {
182 if (Nothing.hasInstance(pointCursor)) {
180 if (Nothing.hasInstance(pointCursor)) {
183 return;
181 return;
184 }
182 }
185− keyfile =
186− '0wnE.Z56pm.i2HLZ.6Pf1R.tAVZH.65R~C.Zgy6y.caI5Z.bZ2vV.09M5A.QP5-p.29UfR.35h2U.2k8-D.QP~~p.6bL62.~x3Em.t9h0x.0y01N.w80c1';
187 const patp = ob.patp(pointCursor.value).slice(1);
183 const patp = ob.patp(pointCursor.value).slice(1);
188 setError(undefined);
184 setError(undefined);
189
185
src/store/lib/useResidentsStore.js+2−3
@@ -1,11 +1,10 @@
1−import { useState, useCallback, useEffect } from 'react';
1+import { useState, useCallback } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
2import { Just, Nothing } from 'folktale/maybe';
3
3
4import { azimuth } from 'azimuth-js';
4import { azimuth } from 'azimuth-js';
5
5
6import { useNetwork } from 'store/network';
6import { useNetwork } from 'store/network';
7
7
8−import useCurrentPermissions from 'lib/useCurrentPermissions';
9import * as need from 'lib/need';
8import * as need from 'lib/need';
10
9
11const emptyCacheEntry = {
10const emptyCacheEntry = {
@@ -29,7 +28,7 @@ export default function useResidents() {
29 [residentCache]
28 [residentCache]
30 );
29 );
31
30
32− const { contracts, web3 } = useNetwork();
31+ const { contracts } = useNetwork();
33 const _contracts = need.contracts(contracts);
32 const _contracts = need.contracts(contracts);
34
33
35 const syncResidentCount = useCallback(
34 const syncResidentCount = useCallback(
src/style/hosted-ship.scssdeleted−14
@@ -1,14 +0,0 @@
1−.hosting-events {
2− margin: 0;
3− padding: 2px;
4− background: #000;
5− list-style: none;
6− font-family: monospace;
7−
8− li {
9− margin: 1px;
10− padding: 2px;
11− background: #111;
12− color: #26ca41;
13− }
14−}
src/views/Admin/AdminNetworkingKeys.js−2
@@ -26,7 +26,6 @@ import { addHexPrefix } from 'lib/wallet';
26import useKeyfileGenerator from 'lib/useKeyfileGenerator';
26import useKeyfileGenerator from 'lib/useKeyfileGenerator';
27
27
28import ViewHeader from 'components/ViewHeader';
28import ViewHeader from 'components/ViewHeader';
29−import { HostingButton } from 'components/Buttons';
30import FooterButton from 'components/FooterButton';
29import FooterButton from 'components/FooterButton';
31import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
30import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
32import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
31import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
@@ -417,7 +416,6 @@ export default function AdminNetworkingKeys() {
417
416
418 {completed && (
417 {completed && (
419 <>
418 <>
420− <Grid.Item full as={HostingButton} onReturn={() => pop()} />
421 <Grid.Divider />
419 <Grid.Divider />
422 </>
420 </>
423 )}
421 )}
src/views/Point.js+15−10
@@ -1,4 +1,4 @@
1−import React, { useCallback, useState, useEffect } from 'react';
1+import React, { useCallback, useState } from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3import { Just } from 'folktale/maybe';
3import { Just } from 'folktale/maybe';
4import { Grid, Flex, Button } from 'indigo-react';
4import { Grid, Flex, Button } from 'indigo-react';
@@ -14,9 +14,7 @@ import Blinky, { matchBlinky } from 'components/Blinky';
14import BarGraph from 'components/BarGraph';
14import BarGraph from 'components/BarGraph';
15import Chip from 'components/Chip';
15import Chip from 'components/Chip';
16import InviteSigilList from 'components/InviteSigilList';
16import InviteSigilList from 'components/InviteSigilList';
17−import { ForwardButton, HostingButton } from 'components/Buttons';
17+import { ForwardButton } from 'components/Buttons';
18−import CopyButton from 'components/CopyButton';
19−import DownloadSigilButton from 'components/DownloadSigilButton';
20
18
21import * as need from 'lib/need';
19import * as need from 'lib/need';
22import useInvites from 'lib/useInvites';
20import useInvites from 'lib/useInvites';
@@ -72,8 +70,6 @@ export default function Point() {
72
70
73 const goSenate = useCallback(() => push(names.SENATE), [push, names]);
71 const goSenate = useCallback(() => push(names.SENATE), [push, names]);
74
72
75− const goSigil = useCallback(() => push(names.SIGIL_GENERATOR), [push, names]);
76−
77 const goCohort = useCallback(() => push(names.INVITE_COHORT), [push, names]);
73 const goCohort = useCallback(() => push(names.INVITE_COHORT), [push, names]);
78
74
79 const goUrbitOS = useCallback(() => push(names.URBIT_OS), [push, names]);
75 const goUrbitOS = useCallback(() => push(names.URBIT_OS), [push, names]);
@@ -96,9 +92,6 @@ export default function Point() {
96
92
97 const [showInviteForm, setShowInviteForm] = useState(false);
93 const [showInviteForm, setShowInviteForm] = useState(false);
98
94
99− const goBoot = useCallback(() => push(names.BOOT), [push, names]);
100− const goHosting = useCallback(() => push(names.HOSTING), [push, names]);
101−
102 const inviteButton = (() => {
95 const inviteButton = (() => {
103 if (azimuth.getPointSize(point) === azimuth.PointSize.Star) {
96 if (azimuth.getPointSize(point) === azimuth.PointSize.Star) {
104 return (
97 return (
@@ -210,7 +203,19 @@ export default function Point() {
210 <Grid.Item full className="mb2" />
203 <Grid.Item full className="mb2" />
211 </>
204 </>
212 );
205 );
206+ }, [
207+ showInviteForm,
208+ setShowInviteForm,
209+ _pendingInvites,
210+ _totalInvites,
211+ acceptedInvites,
212+ acceptedPoints,
213+ availableInvites,
214+ goCohort,
215+ pendingPoints,
216+ sentInvites,
217+ showInvites,
213− });
218+ ]);
214
219
215 const _requestCount = requestCount.getOrElse(0);
220 const _requestCount = requestCount.getOrElse(0);
216
221
src/views/Residents.js+14−10
@@ -125,19 +125,23 @@ export default function Residents() {
125
125
126 const isRequests = useMemo(() => currentTab === NAMES.REQUESTS, [currentTab]);
126 const isRequests = useMemo(() => currentTab === NAMES.REQUESTS, [currentTab]);
127
127
128− const _onAccept = useCallback(adoptee =>
128+ const _onAccept = useCallback(
129+ adoptee =>
129− push(names.ADOPT, {
130+ push(names.ADOPT, {
130− adoptee,
131+ adoptee,
131− denied: false,
132+ denied: false,
132− })
133+ }),
134+ [push, names]
133 );
135 );
134 const onAccept = isRequests && _onAccept;
136 const onAccept = isRequests && _onAccept;
135
137
136− const _onDecline = useCallback(adoptee =>
138+ const _onDecline = useCallback(
139+ adoptee =>
137− push(names.ADOPT, {
140+ push(names.ADOPT, {
138− adoptee,
141+ adoptee,
139− denied: true,
142+ denied: true,
140− })
143+ }),
144+ [push, names]
141 );
145 );
142 const onDecline = isRequests && _onDecline;
146 const onDecline = isRequests && _onDecline;
143
147
src/views/UrbitID.js+5
@@ -16,6 +16,7 @@ import SigilGenerator from './UrbitID/SigilGenerator';
16import DownloadKeys from './UrbitID/DownloadKeys';
16import DownloadKeys from './UrbitID/DownloadKeys';
17import SetProxy from './UrbitID/SetProxy';
17import SetProxy from './UrbitID/SetProxy';
18import ResetKeys from './UrbitID/ResetKeys';
18import ResetKeys from './UrbitID/ResetKeys';
19+import Transfer from './UrbitID/Transfer';
19
20
20const NAMES = {
21const NAMES = {
21 HOME: 'HOME',
22 HOME: 'HOME',
@@ -23,6 +24,7 @@ const NAMES = {
23 DOWNLOAD_KEYS: 'DOWNLOAD_KEYS',
24 DOWNLOAD_KEYS: 'DOWNLOAD_KEYS',
24 SET_PROXY: 'SET_PROXY',
25 SET_PROXY: 'SET_PROXY',
25 RESET_KEYS: 'RESET_KEYS',
26 RESET_KEYS: 'RESET_KEYS',
27+ TRANSFER: 'TRANSFER',
26};
28};
27
29
28const VIEWS = {
30const VIEWS = {
@@ -31,6 +33,7 @@ const VIEWS = {
31 [NAMES.DOWNLOAD_KEYS]: DownloadKeys,
33 [NAMES.DOWNLOAD_KEYS]: DownloadKeys,
32 [NAMES.RESET_KEYS]: ResetKeys,
34 [NAMES.RESET_KEYS]: ResetKeys,
33 [NAMES.SET_PROXY]: SetProxy,
35 [NAMES.SET_PROXY]: SetProxy,
36+ [NAMES.TRANSFER]: Transfer,
34};
37};
35
38
36const humanizeName = name => {
39const humanizeName = name => {
@@ -43,6 +46,8 @@ const humanizeName = name => {
43 return 'Set Key';
46 return 'Set Key';
44 case NAMES.RESET_KEYS:
47 case NAMES.RESET_KEYS:
45 return 'Reset Keys';
48 return 'Reset Keys';
49+ case NAMES.TRANSFER:
50+ return 'Transfer';
46 default:
51 default:
47 return undefined;
52 return undefined;
48 }
53 }
src/views/UrbitID/Home.js+18−8
@@ -7,17 +7,14 @@ import { ForwardButton } from 'components/Buttons';
7import CopyButton from 'components/CopyButton';
7import CopyButton from 'components/CopyButton';
8
8
9import { useLocalRouter } from 'lib/LocalRouter';
9import { useLocalRouter } from 'lib/LocalRouter';
10−import { isZeroAddress } from 'lib/wallet';
11import { PROXY_TYPE, proxyTypeToHuman } from 'lib/proxy';
10import { PROXY_TYPE, proxyTypeToHuman } from 'lib/proxy';
12import * as need from 'lib/need';
11import * as need from 'lib/need';
13import capitalize from 'lib/capitalize';
12import capitalize from 'lib/capitalize';
14−import { eqAddr } from 'lib/wallet';
15import useCurrentPermissions from 'lib/useCurrentPermissions';
13import useCurrentPermissions from 'lib/useCurrentPermissions';
16import convertToInt from 'lib/convertToInt';
14import convertToInt from 'lib/convertToInt';
17
15
18import { usePointCursor } from 'store/pointCursor';
16import { usePointCursor } from 'store/pointCursor';
19import { usePointCache } from 'store/pointCache';
17import { usePointCache } from 'store/pointCache';
20−import { useNetwork } from 'store/network';
21import { useWallet } from 'store/wallet';
18import { useWallet } from 'store/wallet';
22
19
23export default function UrbitIDHome() {
20export default function UrbitIDHome() {
@@ -26,8 +23,6 @@ export default function UrbitIDHome() {
26 const { getDetails } = usePointCache();
23 const { getDetails } = usePointCache();
27 const { urbitWallet } = useWallet();
24 const { urbitWallet } = useWallet();
28
25
29− const { contracts } = useNetwork();
30−
31 const goSigil = useCallback(() => push(names.SIGIL_GENERATOR), [push, names]);
26 const goSigil = useCallback(() => push(names.SIGIL_GENERATOR), [push, names]);
32
27
33 const goDownloadKeys = useCallback(() => push(names.DOWNLOAD_KEYS), [
28 const goDownloadKeys = useCallback(() => push(names.DOWNLOAD_KEYS), [
@@ -38,10 +33,9 @@ export default function UrbitIDHome() {
38 const goResetKeys = useCallback(() => push(names.RESET_KEYS), [push, names]);
33 const goResetKeys = useCallback(() => push(names.RESET_KEYS), [push, names]);
39
34
40 const isMasterTicket = Just.hasInstance(urbitWallet);
35 const isMasterTicket = Just.hasInstance(urbitWallet);
41− const _contracts = need.contracts(contracts);
42 const point = need.point(pointCursor);
36 const point = need.point(pointCursor);
43 const details = need.details(getDetails(point));
37 const details = need.details(getDetails(point));
44− const { canManage, isOwner } = useCurrentPermissions();
38+ const { isOwner } = useCurrentPermissions();
45 const networkRevision = convertToInt(details.keyRevisionNumber, 10);
39 const networkRevision = convertToInt(details.keyRevisionNumber, 10);
46
40
47 const pointSize = azimuth.getPointSize(point);
41 const pointSize = azimuth.getPointSize(point);
@@ -53,6 +47,8 @@ export default function UrbitIDHome() {
53 [push, names]
47 [push, names]
54 );
48 );
55
49
50+ const goTransfer = useCallback(() => push(names.TRANSFER), [names, push]);
51+
56 const renderProxyAction = useCallback(
52 const renderProxyAction = useCallback(
57 (proxyType, address) => {
53 (proxyType, address) => {
58 const disabled =
54 const disabled =
@@ -74,7 +70,7 @@ export default function UrbitIDHome() {
74 );
70 );
75 return (
71 return (
76 <Grid>
72 <Grid>
77− <Grid.Item full className="mv7 f5">
73+ <Grid.Item full className="mb7 f5">
78 Urbit ID
74 Urbit ID
79 </Grid.Item>
75 </Grid.Item>
80 <Grid.Divider />
76 <Grid.Divider />
@@ -99,6 +95,10 @@ export default function UrbitIDHome() {
99 full
95 full
100 as={ForwardButton}
96 as={ForwardButton}
101 onClick={goResetKeys}
97 onClick={goResetKeys}
98+ disabled={!isOwner}
99+ disabledDetail={
100+ <B className="wrap ws-normal"> · Ownership key required</B>
101+ }
102 detail="Reset Master Key and all other keys">
102 detail="Reset Master Key and all other keys">
103 Reset Keys
103 Reset Keys
104 </Grid.Item>
104 </Grid.Item>
@@ -145,6 +145,16 @@ export default function UrbitIDHome() {
145 <Grid.Divider />
145 <Grid.Divider />
146 </>
146 </>
147 )}
147 )}
148+ <Grid.Item
149+ full
150+ as={ForwardButton}
151+ onClick={goTransfer}
152+ disabled={!isOwner}
153+ disabledDetail={
154+ <B className="wrap ws-normal"> · Ownership key required</B>
155+ }>
156+ Transfer this point
157+ </Grid.Item>
148 </Grid>
158 </Grid>
149 );
159 );
150}
160}
src/views/UrbitID/ResetKeys.js−2
@@ -7,8 +7,6 @@ import useRouter from 'lib/useRouter';
7
7
8import Steps from 'components/Steps';
8import Steps from 'components/Steps';
9
9
10−import { usePointCursor } from 'store/pointCursor';
11−
12import ResetConfirm from './ResetKeys/ResetConfirm';
10import ResetConfirm from './ResetKeys/ResetConfirm';
13import ResetDownload from './ResetKeys/ResetDownload';
11import ResetDownload from './ResetKeys/ResetDownload';
14import ResetVerify from './ResetKeys/ResetVerify';
12import ResetVerify from './ResetKeys/ResetVerify';
src/views/UrbitID/SetProxy.js+1−7
@@ -1,6 +1,6 @@
1import React, { useCallback, useMemo } from 'react';
1import React, { useCallback, useMemo } from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3−import { Grid, Text, Flex, ToggleInput } from 'indigo-react';
3+import { Grid, Text, Flex } from 'indigo-react';
4import * as azimuth from 'azimuth-js';
4import * as azimuth from 'azimuth-js';
5
5
6import { useNetwork } from 'store/network';
6import { useNetwork } from 'store/network';
@@ -18,7 +18,6 @@ import { ETH_ZERO_ADDR, eqAddr, isZeroAddress } from 'lib/wallet';
18import capitalize from 'lib/capitalize';
18import capitalize from 'lib/capitalize';
19import useEthereumTransaction from 'lib/useEthereumTransaction';
19import useEthereumTransaction from 'lib/useEthereumTransaction';
20
20
21−import ViewHeader from 'components/ViewHeader';
22import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
21import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
23import { GAS_LIMITS } from 'lib/constants';
22import { GAS_LIMITS } from 'lib/constants';
24import { AddressInput } from 'form/Inputs';
23import { AddressInput } from 'form/Inputs';
@@ -29,7 +28,6 @@ import {
29} from 'form/validators';
28} from 'form/validators';
30import BridgeForm from 'form/BridgeForm';
29import BridgeForm from 'form/BridgeForm';
31import FormError from 'form/FormError';
30import FormError from 'form/FormError';
32−import CopiableAddress from 'components/CopiableAddress';
33
31
34const proxyFromDetails = (details, contracts, proxyType) => {
32const proxyFromDetails = (details, contracts, proxyType) => {
35 switch (proxyType) {
33 switch (proxyType) {
@@ -154,10 +152,6 @@ export default function SetProxy() {
154 const proxyAddress = proxyFromDetails(_details, _contracts, data.proxyType);
152 const proxyAddress = proxyFromDetails(_details, _contracts, data.proxyType);
155 const isProxySet = !isZeroAddress(proxyAddress);
153 const isProxySet = !isZeroAddress(proxyAddress);
156
154
157− const proxyAddressLabel = useMemo(() => `Current ${properProxyType} Key`, [
158− properProxyType,
159− ]);
160−
161 const header = useMemo(() => {
155 const header = useMemo(() => {
162 const pfix = completed ? 'New' : 'Edit';
156 const pfix = completed ? 'New' : 'Edit';
163 return `${pfix} ${properProxyType} Key`;
157 return `${pfix} ${properProxyType} Key`;
src/views/UrbitID/SigilGenerator.js−3
@@ -6,11 +6,9 @@ import { colors } from 'indigo-tokens';
6
6
7import { usePointCursor } from 'store/pointCursor';
7import { usePointCursor } from 'store/pointCursor';
8
8
9−import View from 'components/View';
10import Sigil from 'components/Sigil';
9import Sigil from 'components/Sigil';
11
10
12import * as need from 'lib/need';
11import * as need from 'lib/need';
13−import { useLocalRouter } from 'lib/LocalRouter';
14import useSigilDownloader from 'lib/useSigilDownloader';
12import useSigilDownloader from 'lib/useSigilDownloader';
15
13
16import { composeValidator, buildNumberValidator } from 'form/validators';
14import { composeValidator, buildNumberValidator } from 'form/validators';
@@ -40,7 +38,6 @@ const BG_COLORS = [
40const FG_COLORS = [colors.black, colors.white];
38const FG_COLORS = [colors.black, colors.white];
41
39
42export default function SigilGenerator() {
40export default function SigilGenerator() {
43− const { pop } = useLocalRouter();
44 const { pointCursor } = usePointCursor();
41 const { pointCursor } = usePointCursor();
45
42
46 const validate = composeValidator({ size: buildNumberValidator(16) });
43 const validate = composeValidator({ size: buildNumberValidator(16) });
src/views/UrbitID/Transfer.jsnew file+113
@@ -0,0 +1,113 @@
1+import React, { useCallback, useMemo } from 'react';
2+import cn from 'classnames';
3+import { Grid, Text } from 'indigo-react';
4+import * as azimuth from 'azimuth-js';
5+
6+import { useNetwork } from 'store/network';
7+import { usePointCursor } from 'store/pointCursor';
8+import { usePointCache } from 'store/pointCache';
9+
10+import * as need from 'lib/need';
11+import { useLocalRouter } from 'lib/LocalRouter';
12+import useCurrentPointName from 'lib/useCurrentPointName';
13+import useEthereumTransaction from 'lib/useEthereumTransaction';
14+import { GAS_LIMITS } from 'lib/constants';
15+
16+import ViewHeader from 'components/ViewHeader';
17+import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
18+import { AddressInput } from 'form/Inputs';
19+import { composeValidator, buildAddressValidator } from 'form/validators';
20+import BridgeForm from 'form/BridgeForm';
21+import FormError from 'form/FormError';
22+
23+function useTransfer() {
24+ const { contracts } = useNetwork();
25+ const { pointCursor } = usePointCursor();
26+ const { syncDetails } = usePointCache();
27+
28+ const _contracts = need.contracts(contracts);
29+ const _point = need.point(pointCursor);
30+
31+ return useEthereumTransaction(
32+ useCallback(
33+ address => azimuth.ecliptic.setTransferProxy(_contracts, _point, address),
34+ [_contracts, _point]
35+ ),
36+ useCallback(() => syncDetails(_point), [_point, syncDetails]),
37+ GAS_LIMITS.SET_PROXY
38+ );
39+}
40+
41+export default function AdminTransfer() {
42+ const { pop } = useLocalRouter();
43+ const name = useCurrentPointName();
44+
45+ const {
46+ construct,
47+ unconstruct,
48+ completed,
49+ inputsLocked,
50+ bind,
51+ } = useTransfer();
52+
53+ const validate = useMemo(
54+ () => composeValidator({ address: buildAddressValidator() }),
55+ []
56+ );
57+
58+ const onValues = useCallback(
59+ ({ valid, values }) => {
60+ if (valid) {
61+ construct(values.address);
62+ } else {
63+ unconstruct();
64+ }
65+ },
66+ [construct, unconstruct]
67+ );
68+
69+ return (
70+ <Grid>
71+ <Grid.Item full as={ViewHeader}>
72+ Transfer Point
73+ </Grid.Item>
74+
75+ <BridgeForm validate={validate} onValues={onValues}>
76+ {({ handleSubmit, values }) => (
77+ <>
78+ <Grid.Item
79+ full
80+ as={Text}
81+ className={cn('f5 wrap', {
82+ green3: completed,
83+ })}>
84+ {completed
85+ ? `${values.address} is now the Transfer Proxy for ${name} and can accept the transfer by logging into Bridge themselves. Until they accept your transfer, you will still have ownership over ${name}.`
86+ : `Transfer ${name} to a new owner.`}
87+ </Grid.Item>
88+
89+ {!completed && (
90+ <Grid.Item
91+ full
92+ as={AddressInput}
93+ className="mv4"
94+ name="address"
95+ label="Ethereum Address"
96+ disabled={inputsLocked}
97+ />
98+ )}
99+
100+ <Grid.Item full as={FormError} />
101+
102+ <Grid.Item
103+ full
104+ as={InlineEthereumTransaction}
105+ {...bind}
106+ onReturn={() => pop()}
107+ />
108+ </>
109+ )}
110+ </BridgeForm>
111+ </Grid>
112+ );
113+}
src/views/UrbitOS.js+7−2
@@ -1,4 +1,4 @@
1−import React from 'react';
1+import React, { useState } from 'react';
2import { Grid } from 'indigo-react';
2import { Grid } from 'indigo-react';
3
3
4import { useHistory } from 'store/history';
4import { useHistory } from 'store/history';
@@ -37,6 +37,8 @@ export default function UrbitOS() {
37 initialRoutes: [{ key: NAMES.HOME }],
37 initialRoutes: [{ key: NAMES.HOME }],
38 });
38 });
39
39
40+ const [manualNetworkSeed, setManualNetworkSeed] = useState();
41+
40 return (
42 return (
41 <View pop={router.pop} inset>
43 <View pop={router.pop} inset>
42 <NavHeader>
44 <NavHeader>
@@ -49,7 +51,10 @@ export default function UrbitOS() {
49 </NavHeader>
51 </NavHeader>
50 <LocalRouterProvider value={router}>
52 <LocalRouterProvider value={router}>
51 <Grid className="mb4"></Grid>
53 <Grid className="mb4"></Grid>
52− <Route />
54+ <Route
55+ manualNetworkSeed={manualNetworkSeed}
56+ setManualNetworkSeed={setManualNetworkSeed}
57+ />
53 </LocalRouterProvider>
58 </LocalRouterProvider>
54 </View>
59 </View>
55 );
60 );
src/views/UrbitOS/Home.js+23−38
@@ -21,7 +21,7 @@ import { useLocalRouter } from 'lib/LocalRouter';
21import { useHosting } from 'store/hosting';
21import { useHosting } from 'store/hosting';
22import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
22import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
23
23
24−export default function UrbitOSHome() {
24+export default function UrbitOSHome({ manualNetworkSeed }) {
25 const { pointCursor } = usePointCursor();
25 const { pointCursor } = usePointCursor();
26 const { getDetails } = usePointCache();
26 const { getDetails } = usePointCache();
27
27
@@ -51,7 +51,7 @@ export default function UrbitOSHome() {
51 ]);
51 ]);
52 return (
52 return (
53 <>
53 <>
54− <Hosting />
54+ <Hosting manualNetworkSeed={manualNetworkSeed} />
55
55
56 <Grid>
56 <Grid>
57 <Grid.Item full className="mv7 f5">
57 <Grid.Item full className="mv7 f5">
@@ -91,22 +91,12 @@ export default function UrbitOSHome() {
91}
91}
92
92
93// eslint-disable-next-line
93// eslint-disable-next-line
94−function Hosting() {
94+function Hosting({ manualNetworkSeed }) {
95− const bind = useKeyfileGenerator();
95+ const bind = useKeyfileGenerator(manualNetworkSeed);
96− const { keyfile, code, notice } = bind;
96+ const { keyfile, code } = bind;
97 const ship = useHosting();
97 const ship = useHosting();
98
98
99− const {
99+ const { syncStatus, url, unknown, bootProgress, bootMessage } = ship;
100− syncStatus,
101− url,
102− unknown,
103− running,
104− sysEvents,
105− runEvents,
106− newEvents,
107− bootProgress,
108− bootMessage,
109− } = ship;
110
100
111 const [synced, setSynced] = useState(false);
101 const [synced, setSynced] = useState(false);
112 useEffect(() => {
102 useEffect(() => {
@@ -121,8 +111,6 @@ function Hosting() {
121 const name = useCurrentPointName();
111 const name = useCurrentPointName();
122 const options = [{ text: 'Tlon', value: 'tlon' }];
112 const options = [{ text: 'Tlon', value: 'tlon' }];
123
113
124− const props = { name, options, ship };
125−
126 const renderMain = useCallback(() => {
114 const renderMain = useCallback(() => {
127 if (ship.running) {
115 if (ship.running) {
128 return (
116 return (
@@ -181,18 +169,14 @@ function Hosting() {
181 </>
169 </>
182 );
170 );
183 }
171 }
184− if (ship.missing) {
172+ if (!keyfile && ship.missing) {
185 return (
173 return (
186− <>
187− <Grid.Item full className="gray4">
174+ <Grid.Item full className="gray4">
188− <span className="gray3">Status:</span> Disconnected
175+ Please reset your networking keys in order to use hosting
189− <br />
190− <span className="f6">Last connected: 4m ago</span>
191− </Grid.Item>
176+ </Grid.Item>
192− </>
193 );
177 );
194 }
178 }
195− }, [name, ship]);
179+ }, [name, ship, keyfile]);
196
180
197 return (
181 return (
198 <>
182 <>
@@ -201,7 +185,7 @@ function Hosting() {
201 <Flex.Item>Urbit OS </Flex.Item>
185 <Flex.Item>Urbit OS </Flex.Item>
202 <Flex.Item
186 <Flex.Item
203 className={cn(
187 className={cn(
204− { green3: ship.running, grey4: !ship.running },
188+ { green3: ship.running, gray4: !ship.running },
205 'ml3'
189 'ml3'
206 )}>
190 )}>
207 {ship.running ? 'Connected' : 'Disconnected'}
191 {ship.running ? 'Connected' : 'Disconnected'}
@@ -233,16 +217,17 @@ function Hosting() {
233 detail="A keyfile authenticates your Urbit ID to Urbit OS"
217 detail="A keyfile authenticates your Urbit ID to Urbit OS"
234 />
218 />
235 <Grid.Divider />
219 <Grid.Divider />
220+ {code && (
236− <Grid.Item
221+ <Grid.Item
237− full
222+ full
238− className="mt2"
223+ className="mt2"
239− as={ForwardButton}
224+ as={ForwardButton}
240− accessory={code && <CopyButton text={code} />}
225+ accessory={<CopyButton text={code} />}
241− detail={code || notice}
226+ detail={code}
242− disabled={!code}
243− detailClassName="mono">
227+ detailClassName="mono">
244− Login Code
228+ Login Code
245− </Grid.Item>
229+ </Grid.Item>
230+ )}
246 </Grid>
231 </Grid>
247 </>
232 </>
248 );
233 );
src/views/UrbitOS/NetworkingKeys.js+20−14
@@ -1,4 +1,4 @@
1−import React, { useCallback, useMemo, useRef, useState } from 'react';
1+import React, { useCallback, useMemo, useRef } from 'react';
2import { Just } from 'folktale/maybe';
2import { Just } from 'folktale/maybe';
3import { Grid, ToggleInput, CheckboxInput } from 'indigo-react';
3import { Grid, ToggleInput, CheckboxInput } from 'indigo-react';
4import * as azimuth from 'azimuth-js';
4import * as azimuth from 'azimuth-js';
@@ -37,7 +37,7 @@ import Condition from 'form/Condition';
37import FormError from 'form/FormError';
37import FormError from 'form/FormError';
38import convertToInt from 'lib/convertToInt';
38import convertToInt from 'lib/convertToInt';
39
39
40−function useSetKeys() {
40+function useSetKeys(manualNetworkSeed, setManualNetworkSeed) {
41 const { urbitWallet, wallet, authMnemonic } = useWallet();
41 const { urbitWallet, wallet, authMnemonic } = useWallet();
42 const { pointCursor } = usePointCursor();
42 const { pointCursor } = usePointCursor();
43 const { syncDetails, syncRekeyDate, getDetails } = usePointCache();
43 const { syncDetails, syncRekeyDate, getDetails } = usePointCache();
@@ -50,19 +50,16 @@ function useSetKeys() {
50 const networkRevision = convertToInt(_details.keyRevisionNumber, 10);
50 const networkRevision = convertToInt(_details.keyRevisionNumber, 10);
51 const randomSeed = useRef();
51 const randomSeed = useRef();
52
52
53− // NOTE: nd = 'nondeterministic' (can also be a 'manual' seed)
54− const [ndNetworkSeed, setNdNetworkSeed] = useState();
55−
56 const {
53 const {
57 available: keyfileAvailable,
54 available: keyfileAvailable,
58 filename,
55 filename,
59 bind: keyfileBind,
56 bind: keyfileBind,
60− } = useKeyfileGenerator(ndNetworkSeed);
57+ } = useKeyfileGenerator(manualNetworkSeed);
61
58
62 const buildNetworkSeed = useCallback(
59 const buildNetworkSeed = useCallback(
63 async manualSeed => {
60 async manualSeed => {
64 if (manualSeed !== undefined) {
61 if (manualSeed !== undefined) {
65− setNdNetworkSeed(manualSeed);
62+ setManualNetworkSeed(manualSeed);
66 return manualSeed;
63 return manualSeed;
67 } else {
64 } else {
68 const newNetworkRevision = networkRevision + 1;
65 const newNetworkRevision = networkRevision + 1;
@@ -81,12 +78,19 @@ function useSetKeys() {
81 }
78 }
82
79
83 randomSeed.current = randomSeed.current || randomHex(32); // 32 bytes
80 randomSeed.current = randomSeed.current || randomHex(32); // 32 bytes
84− setNdNetworkSeed(randomSeed.current);
81+ setManualNetworkSeed(randomSeed.current);
85
82
86 return randomSeed.current;
83 return randomSeed.current;
87 }
84 }
88 },
85 },
86+ [
87+ _details,
88+ authMnemonic,
89− [_details, authMnemonic, networkRevision, urbitWallet, wallet]
89+ networkRevision,
90+ setManualNetworkSeed,
91+ urbitWallet,
92+ wallet,
93+ ]
90 );
94 );
91
95
92 const { completed: _completed, ...rest } = useEthereumTransaction(
96 const { completed: _completed, ...rest } = useEthereumTransaction(
@@ -118,14 +122,16 @@ function useSetKeys() {
118
122
119 return {
123 return {
120 completed,
124 completed,
121− ndNetworkSeed,
122 filename,
125 filename,
123 keyfileBind,
126 keyfileBind,
124 ...rest,
127 ...rest,
125 };
128 };
126}
129}
127
130
128−export default function UrbitOSNetworkingKeys() {
131+export default function UrbitOSNetworkingKeys({
132+ manualNetworkSeed,
133+ setManualNetworkSeed,
134+}) {
129 const { pop } = useLocalRouter();
135 const { pop } = useLocalRouter();
130 const { pointCursor } = usePointCursor();
136 const { pointCursor } = usePointCursor();
131 const { getDetails } = usePointCache();
137 const { getDetails } = usePointCache();
@@ -143,12 +149,11 @@ export default function UrbitOSNetworkingKeys() {
143 const {
149 const {
144 construct,
150 construct,
145 unconstruct,
151 unconstruct,
146− broadcasting,
147 completed,
152 completed,
148 inputsLocked,
153 inputsLocked,
149 bind,
154 bind,
150 keyfileBind,
155 keyfileBind,
151− } = useSetKeys();
156+ } = useSetKeys(manualNetworkSeed, setManualNetworkSeed);
152
157
153 const validateForm = useCallback((values, errors) => {
158 const validateForm = useCallback((values, errors) => {
154 if (values.useNetworkSeed && errors.networkSeed) {
159 if (values.useNetworkSeed && errors.networkSeed) {
@@ -195,7 +200,8 @@ export default function UrbitOSNetworkingKeys() {
195 []
200 []
196 );
201 );
197
202
203+ const usageMessage =
198− const usageMessage = 'You need this to authenticate with arvo';
204+ 'You need this to authenticate with Arvo. Please download';
199
205
200 return (
206 return (
201 <>
207 <>