on master help sign in
Center buttons, Network Keys, MM fix, point polling, Points display fixes
e5348f2Will Galebach
src/components/Buttons.js+6−4
@@ -6,17 +6,19 @@ import { blinkIf } from './Blinky';
6
6
7// NOTE: the -> is correct because inter recognizes the pair
7// NOTE: the -> is correct because inter recognizes the pair
8export const ForwardButton = ({ loading, ...props }) => (
8export const ForwardButton = ({ loading, ...props }) => (
9− <Button accessory={blinkIf(loading, '->')} {...props} />
9+ <Button accessory={blinkIf(loading, '->')} {...props} center />
10);
10);
11export const DownloadButton = ({ loading, ...props }) => (
11export const DownloadButton = ({ loading, ...props }) => (
12− <Button accessory={blinkIf(loading, '↓')} {...props} />
12+ <Button accessory={blinkIf(loading, '↓')} {...props} center />
13+);
14+export const RestartButton = props => (
15+ <Button accessory="↺" {...props} center />
13);
16);
14−export const RestartButton = props => <Button accessory="↺" {...props} />;
15export const GenerateButton = ({ loading, ...props }) => (
17export const GenerateButton = ({ loading, ...props }) => (
16 <Button accessory={blinkIf(loading, '○')} solid {...props} />
18 <Button accessory={blinkIf(loading, '○')} solid {...props} />
17);
19);
18export const OutButton = props => (
20export const OutButton = props => (
19− <Button as="a" target="_blank" accessory="↗" {...props} />
21+ <Button as="a" target="_blank" accessory="↗" {...props} center />
20);
22);
21
23
22export const OfflineButton = props => (
24export const OfflineButton = props => (
src/components/NetworkingKeys.js → src/components/NetworkKeys.jsrenamed+1−1
@@ -20,7 +20,7 @@ const renderNetworkKey = key => {
20 return segments.join('\n');
20 return segments.join('\n');
21};
21};
22
22
23−export default function NetworkingKeys({ point }) {
23+export default function NetworkKeys({ point }) {
24 const { getDetails, getRekeyDate } = usePointCache();
24 const { getDetails, getRekeyDate } = usePointCache();
25
25
26 const details = getDetails(point);
26 const details = getDetails(point);
src/lib/constants.ts+2
@@ -168,6 +168,7 @@ const DUMMY_L2_ADDRESS = '0x1111111111111111111111111111111111111111';
168const ONE_SECOND = 1000;
168const ONE_SECOND = 1000;
169const TWO_SECONDS = 2 * ONE_SECOND;
169const TWO_SECONDS = 2 * ONE_SECOND;
170const TEN_SECONDS = 10 * ONE_SECOND;
170const TEN_SECONDS = 10 * ONE_SECOND;
171+const ONE_MINUTE = 60 * ONE_SECOND;
171
172
172const MASTER_TICKET_TOOLTIP =
173const MASTER_TICKET_TOOLTIP =
173 'Your Master Ticket is your 4-word password for your Urbit';
174 'Your Master Ticket is your 4-word password for your Urbit';
@@ -217,6 +218,7 @@ export {
217 ONE_SECOND,
218 ONE_SECOND,
218 TWO_SECONDS,
219 TWO_SECONDS,
219 TEN_SECONDS,
220 TEN_SECONDS,
221+ ONE_MINUTE,
220 MASTER_TICKET_TOOLTIP,
222 MASTER_TICKET_TOOLTIP,
221 PASSPORT_TOOLTIP,
223 PASSPORT_TOOLTIP,
222};
224};
src/lib/keys.js+1−1
@@ -69,7 +69,7 @@ export const createRing = pair =>
69 * @param {number} revision
69 * @param {number} revision
70 * @return {string}
70 * @return {string}
71 */
71 */
72−export const compileNetworkingKey = (pair, point, revision) => {
72+export const compileNetworkKey = (pair, point, revision) => {
73 const bnsec = new BN(createRing(pair), 'hex');
73 const bnsec = new BN(createRing(pair), 'hex');
74
74
75 const sed = noun.dwim(
75 const sed = noun.dwim(
src/lib/router.js−2
@@ -22,7 +22,6 @@ import PartySetPoolSize from 'views/Party/PartySetPoolSize';
22import InviteCohort from 'views/Invite/Cohort';
22import InviteCohort from 'views/Invite/Cohort';
23import AcceptTransfer from 'views/AcceptTransfer';
23import AcceptTransfer from 'views/AcceptTransfer';
24import CancelTransfer from 'views/CancelTransfer';
24import CancelTransfer from 'views/CancelTransfer';
25−import Adopt from 'views/Ops/Adopt.tsx';
26import Bitcoin from 'views/Bitcoin/Bitcoin';
25import Bitcoin from 'views/Bitcoin/Bitcoin';
27import Xpub from 'views/Bitcoin/Xpub';
26import Xpub from 'views/Bitcoin/Xpub';
28import SignTransaction from 'views/Bitcoin/SignTransaction';
27import SignTransaction from 'views/Bitcoin/SignTransaction';
@@ -56,7 +55,6 @@ export const ROUTES = {
56 [ROUTE_NAMES.URBIT_ID]: UrbitID,
55 [ROUTE_NAMES.URBIT_ID]: UrbitID,
57 [ROUTE_NAMES.RESIDENTS]: Residents,
56 [ROUTE_NAMES.RESIDENTS]: Residents,
58 [ROUTE_NAMES.REQUESTS]: Requests,
57 [ROUTE_NAMES.REQUESTS]: Requests,
59− [ROUTE_NAMES.ADOPT]: Adopt,
60 [ROUTE_NAMES.BITCOIN]: Bitcoin,
58 [ROUTE_NAMES.BITCOIN]: Bitcoin,
61 [ROUTE_NAMES.BITCOIN_XPUB]: Xpub,
59 [ROUTE_NAMES.BITCOIN_XPUB]: Xpub,
62 [ROUTE_NAMES.BITCOIN_SIGN_TRANSACTION]: SignTransaction,
60 [ROUTE_NAMES.BITCOIN_SIGN_TRANSACTION]: SignTransaction,
src/lib/types/Point.ts+3
@@ -111,6 +111,7 @@ export default class Point {
111 isPlaceholder: boolean;
111 isPlaceholder: boolean;
112 ownManageSpawn: boolean;
112 ownManageSpawn: boolean;
113 shouldDisplay: boolean;
113 shouldDisplay: boolean;
114+ isOutgoing: boolean;
114
115
115 constructor({
116 constructor({
116 value,
117 value,
@@ -180,6 +181,8 @@ export default class Point {
180 !this.isDefault &&
181 !this.isDefault &&
181 (this.isOwner || this.isSpawnProxy || this.isManagementProxy);
182 (this.isOwner || this.isSpawnProxy || this.isManagementProxy);
182 this.shouldDisplay = this.ownManageSpawn || this.isTransferProxy;
183 this.shouldDisplay = this.ownManageSpawn || this.isTransferProxy;
184+ this.isOutgoing =
185+ this.isTransferProxySet && this.isTransferProxy && this.canManage;
183 }
186 }
184
187
185 equals = (point: Point) => {
188 equals = (point: Point) => {
src/lib/useKeyfileGenerator.js+7−7
@@ -14,7 +14,7 @@ import {
14 attemptNetworkSeedDerivation,
14 attemptNetworkSeedDerivation,
15 keysMatchChain,
15 keysMatchChain,
16 deriveNetworkKeys,
16 deriveNetworkKeys,
17− compileNetworkingKey,
17+ compileNetworkKey,
18} from './keys';
18} from './keys';
19import useCurrentPermissions from './useCurrentPermissions';
19import useCurrentPermissions from './useCurrentPermissions';
20import { convertToInt } from './convertToInt';
20import { convertToInt } from './convertToInt';
@@ -40,14 +40,14 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
40 });
40 });
41 const { isOwner, isManagementProxy } = useCurrentPermissions();
41 const { isOwner, isManagementProxy } = useCurrentPermissions();
42
42
43− const hasNetworkingKeys = networkRevision > 0;
43+ const hasNetworkKeys = networkRevision > 0;
44 const available =
44 const available =
45− (isOwner || isManagementProxy) && hasNetworkingKeys && !!keyfile;
45+ (isOwner || isManagementProxy) && hasNetworkKeys && !!keyfile;
46
46
47 const generate = useCallback(async () => {
47 const generate = useCallback(async () => {
48− if (!hasNetworkingKeys) {
48+ if (!hasNetworkKeys) {
49 setGenerating(false);
49 setGenerating(false);
50− setNotice('Networking keys not yet set.');
50+ setNotice('Network keys not yet set.');
51 console.log(
51 console.log(
52 `no networking keys available for revision ${networkRevision}`
52 `no networking keys available for revision ${networkRevision}`
53 );
53 );
@@ -90,11 +90,11 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
90
90
91 setNotice();
91 setNotice();
92 setCode(generateCode(pair));
92 setCode(generateCode(pair));
93− setKeyfile(compileNetworkingKey(pair, _point, networkRevision));
93+ setKeyfile(compileNetworkKey(pair, _point, networkRevision));
94 setGenerating(false);
94 setGenerating(false);
95 }, [
95 }, [
96 networkRevision,
96 networkRevision,
97− hasNetworkingKeys,
97+ hasNetworkKeys,
98 manualNetworkSeed,
98 manualNetworkSeed,
99 urbitWallet,
99 urbitWallet,
100 wallet,
100 wallet,
src/lib/useRoller.ts+2−2
@@ -588,7 +588,7 @@ export default function useRoller() {
588 customNetworkSeed?: string;
588 customNetworkSeed?: string;
589 }
589 }
590
590
591− const configureNetworkingKeys = useCallback(
591+ const configureNetworkKeys = useCallback(
592 async ({ breach, customNetworkSeed }: ConfigureKeysParams) => {
592 async ({ breach, customNetworkSeed }: ConfigureKeysParams) => {
593 if (quotaReached()) {
593 if (quotaReached()) {
594 return;
594 return;
@@ -1024,7 +1024,7 @@ export default function useRoller() {
1024 cancelEscape,
1024 cancelEscape,
1025 checkForUpdates,
1025 checkForUpdates,
1026 config,
1026 config,
1027− configureNetworkingKeys,
1027+ configureNetworkKeys,
1028 generateInviteCodes,
1028 generateInviteCodes,
1029 getInvites,
1029 getInvites,
1030 getPoints,
1030 getPoints,
src/store/lib/useControlledPointsStore.js+8
@@ -7,6 +7,7 @@ import { useWallet } from 'store/wallet';
7import useRoller from 'lib/useRoller';
7import useRoller from 'lib/useRoller';
8import { onlyUnique } from 'lib/utils/array';
8import { onlyUnique } from 'lib/utils/array';
9import { useNetwork } from '../network';
9import { useNetwork } from '../network';
10+import { ONE_MINUTE } from 'lib/constants';
10
11
11export default function useControlledPointsStore() {
12export default function useControlledPointsStore() {
12 const { contracts } = useNetwork();
13 const { contracts } = useNetwork();
@@ -121,6 +122,13 @@ export default function useControlledPointsStore() {
121 syncControlledPoints();
122 syncControlledPoints();
122 }, [syncControlledPoints]);
123 }, [syncControlledPoints]);
123
124
125+ // Poll the roller every minute for changes to the points
126+ useEffect(() => {
127+ setInterval(() => {
128+ syncControlledPoints();
129+ }, ONE_MINUTE);
130+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
131+
124 return {
132 return {
125 controlledPoints,
133 controlledPoints,
126 syncControlledPoints,
134 syncControlledPoints,
src/views/Activate/MasterKeyDownload.tsx+2−2
@@ -14,7 +14,7 @@ import { FadeableMasterKeyPresenter as MasterKeyPresenter } from './MasterKeyPre
14import { useActivateFlow } from './ActivateFlow';
14import { useActivateFlow } from './ActivateFlow';
15import ActivateView from './ActivateView';
15import ActivateView from './ActivateView';
16import { useLocalRouter } from 'lib/LocalRouter';
16import { useLocalRouter } from 'lib/LocalRouter';
17−import { compileNetworkingKey } from 'lib/keys';
17+import { compileNetworkKey } from 'lib/keys';
18import { downloadWallet } from 'lib/invite';
18import { downloadWallet } from 'lib/invite';
19import PaperBuilder from 'components/PaperBuilder';
19import PaperBuilder from 'components/PaperBuilder';
20import { DEFAULT_FADE_TIMEOUT, MASTER_KEY_DURATION } from 'lib/constants';
20import { DEFAULT_FADE_TIMEOUT, MASTER_KEY_DURATION } from 'lib/constants';
@@ -47,7 +47,7 @@ const MasterKeyDownload = () => {
47 });
47 });
48
48
49 const download = useCallback(async () => {
49 const download = useCallback(async () => {
50− const netkey = compileNetworkingKey(wallet.network.keys, point, 1);
50+ const netkey = compileNetworkKey(wallet.network.keys, point, 1);
51 //TODO could be deduplicated with useKeyfileGenerator's logic
51 //TODO could be deduplicated with useKeyfileGenerator's logic
52 const filename = ob.patp(point).slice(1) + '-1.key';
52 const filename = ob.patp(point).slice(1) + '-1.key';
53 await downloadWallet(paper.getOrElse([]), netkey, filename);
53 await downloadWallet(paper.getOrElse([]), netkey, filename);
src/views/CancelTransfer.js+1−1
@@ -108,7 +108,7 @@ function AdminCancelTransfer() {
108 <Grid.Item
108 <Grid.Item
109 as={Button}
109 as={Button}
110 full
110 full
111− className="set-proxy mt4"
111+ className="set-proxy mt4 w-full"
112 center
112 center
113 solid
113 solid
114 onClick={cancelTransfer}>
114 onClick={cancelTransfer}>
src/views/Login/Mnemonic.tsx+18−21
@@ -36,12 +36,11 @@ export default function Mnemonic({ className, goHome }: MnemonicProps) {
36
36
37 const { setWallet, setAuthMnemonic, setWalletHdPath }: any = useWallet();
37 const { setWallet, setAuthMnemonic, setWalletHdPath }: any = useWallet();
38
38
39− const [anyMnemonic, setAnyMnemonic] = useState(false);
40 const [skipValidation, setSkipValidation] = useState(false);
39 const [skipValidation, setSkipValidation] = useState(false);
41 const [phraseHdPath, setPhraseHdPath] = useState(false);
40 const [phraseHdPath, setPhraseHdPath] = useState(false);
42
41
43 const validate = useMemo(() => {
42 const validate = useMemo(() => {
44− const mnemonicValidator = anyMnemonic
43+ const mnemonicValidator = skipValidation
45 ? buildAnyMnemonicValidator()
44 ? buildAnyMnemonicValidator()
46 : buildMnemonicValidator();
45 : buildMnemonicValidator();
47 return composeValidator({
46 return composeValidator({
@@ -50,12 +49,11 @@ export default function Mnemonic({ className, goHome }: MnemonicProps) {
50 passphrase: buildPassphraseValidator(),
49 passphrase: buildPassphraseValidator(),
51 hdpath: buildHdPathValidator(),
50 hdpath: buildHdPathValidator(),
52 });
51 });
53− }, [anyMnemonic]);
52+ }, [skipValidation]);
54
53
55 // when the properties change, re-derive wallet and set global state
54 // when the properties change, re-derive wallet and set global state
56 const onValues = useCallback(
55 const onValues = useCallback(
57 ({ valid, values }) => {
56 ({ valid, values }) => {
58− setAnyMnemonic(values.anyMnemonic);
59 if (valid) {
57 if (valid) {
60 setWalletHdPath(values.hdpath);
58 setWalletHdPath(values.hdpath);
61 setAuthMnemonic(Just(values.mnemonic));
59 setAuthMnemonic(Just(values.mnemonic));
@@ -64,7 +62,7 @@ export default function Mnemonic({ className, goHome }: MnemonicProps) {
64 values.mnemonic,
62 values.mnemonic,
65 values.hdpath,
63 values.hdpath,
66 values.passphrase,
64 values.passphrase,
67− values.anyMnemonic
65+ skipValidation
68 )
66 )
69 );
67 );
70 } else {
68 } else {
@@ -72,7 +70,7 @@ export default function Mnemonic({ className, goHome }: MnemonicProps) {
72 setWallet(Nothing());
70 setWallet(Nothing());
73 }
71 }
74 },
72 },
75− [setAuthMnemonic, setWallet, setWalletHdPath]
73+ [setAuthMnemonic, setWallet, setWalletHdPath, skipValidation]
76 );
74 );
77
75
78 const initialValues = {
76 const initialValues = {
@@ -115,22 +113,21 @@ export default function Mnemonic({ className, goHome }: MnemonicProps) {
115 <Grid.Item full>
113 <Grid.Item full>
116 <Grid.Item full as={MnemonicInput} name="mnemonic" />
114 <Grid.Item full as={MnemonicInput} name="mnemonic" />
117
115
118− {skipValidation && (
119− <Grid.Item
120− full
121− as={PassphraseInput}
122− name="passphrase"
123− label="Passphrase"
124− />
125− )}
126−
127 {phraseHdPath && (
116 {phraseHdPath && (
117+ <>
128− <Grid.Item
118+ <Grid.Item
129− full
119+ full
120+ as={PassphraseInput}
121+ name="passphrase"
122+ label="Passphrase"
123+ />
124+ <Grid.Item
125+ full
130− as={HdPathInput}
126+ as={HdPathInput}
131− name="hdpath"
127+ name="hdpath"
132− label="HD Path"
128+ label="HD Path"
133− />
129+ />
130+ </>
134 )}
131 )}
135
132
136 <Grid.Item full as={FormError} />
133 <Grid.Item full as={FormError} />
src/views/Ops/Adopt.tsxdeleted−103
@@ -1,103 +0,0 @@
1−import React, { useCallback, useEffect, useMemo } from 'react';
2−import { Grid } from 'indigo-react';
3−import * as ob from 'urbit-ob';
4−import { ecliptic } from 'azimuth-js';
5−
6−import { useNetwork } from 'store/network';
7−import { usePointCache } from 'store/pointCache';
8−import { usePointCursor } from 'store/pointCursor';
9−import { useHistory } from 'store/history';
10−
11−import * as need from 'lib/need';
12−import { GAS_LIMITS } from 'lib/constants';
13−import useEthereumTransaction from 'lib/useEthereumTransaction';
14−
15−import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
16−import Window from 'components/L2/Window/Window';
17−import HeaderPane from 'components/L2/Window/HeaderPane';
18−import BodyPane from 'components/L2/Window/BodyPane';
19−import View from 'components/View';
20−import L2BackHeader from 'components/L2/Headers/L2BackHeader';
21−import { Row } from '@tlon/indigo-react';
22−
23−function useAdopt() {
24− const { contracts }: any = useNetwork();
25− const _contracts = need.contracts(contracts);
26−
27− const { pointCursor }: any = usePointCursor();
28− const point = need.point(pointCursor);
29−
30− const { syncResidents }: any = usePointCache();
31−
32− return useEthereumTransaction(
33− useCallback(
34− (adoptee: number, denied: boolean) =>
35− denied
36− ? ecliptic.reject(_contracts, adoptee)
37− : ecliptic.adopt(_contracts, adoptee),
38− [_contracts]
39− ),
40− useCallback(() => syncResidents(point), [syncResidents, point]),
41− GAS_LIMITS.DEFAULT
42− );
43−}
44−
45−export default function Adopt() {
46− const { pop, data }: any = useHistory();
47−
48− const { adoptee, denied } = data;
49−
50− const patp = useMemo(() => ob.patp(adoptee), [adoptee]);
51−
52− const { construct, bind, completed } = useAdopt();
53−
54− const body = useMemo(
55− () =>
56− denied ? (
57− <>
58− {completed ? 'Rejected' : 'Rejecting'} adoption request for{' '}
59− <span className="mono">{patp}</span>
60− </>
61− ) : (
62− <>
63− {completed ? 'Approved' : 'Approving'} adoption request for{' '}
64− <span className="mono">{patp}</span>
65− </>
66− ),
67− [patp, denied, completed]
68− );
69−
70− useEffect(() => {
71− construct(adoptee, denied);
72− }, [construct, adoptee, denied]);
73−
74− const headerText = `${denied ? 'Reject' : 'Approve'} Adoption Request`;
75−
76− return (
77− <View
78− className="adopt-l1"
79− pop={pop}
80− inset
81− hideBack
82− header={<L2BackHeader hideBalance back={pop} />}>
83− <Window>
84− <HeaderPane>
85− <Row className="header-row">
86− <h5>{headerText}</h5>
87− </Row>
88− </HeaderPane>
89− <BodyPane>
90− <Grid.Item className="f5 mv2 w-full" style={{ fontSize: 14 }}>
91− {body}
92− </Grid.Item>
93− <Grid.Item
94− full
95− {...bind}
96− as={InlineEthereumTransaction}
97− onReturn={() => pop()}
98− />
99− </BodyPane>
100− </Window>
101− </View>
102− );
103−}
src/views/Ops/Requests.tsx+11−37
@@ -16,7 +16,7 @@ import { RequestRow } from './RequestRow';
16import './Requests.scss';
16import './Requests.scss';
17
17
18export const Requests = () => {
18export const Requests = () => {
19− const { pop, push, names }: any = useLocalRouter();
19+ const { pop }: any = useLocalRouter();
20 const { point, setLoading } = useRollerStore();
20 const { point, setLoading } = useRollerStore();
21 const { api, changeSponsorship } = useRoller();
21 const { api, changeSponsorship } = useRoller();
22 const [requestingPoints, setRequestingPoints] = useState<Ship[]>([]);
22 const [requestingPoints, setRequestingPoints] = useState<Ship[]>([]);
@@ -32,50 +32,24 @@ export const Requests = () => {
32 setLoading(false);
32 setLoading(false);
33 }, [api, point, setLoading]);
33 }, [api, point, setLoading]);
34
34
35− const acceptL1 = useCallback(
36− adoptee =>
37− push(names.ADOPT, {
38− adoptee,
39− denied: false,
40− }),
41− [push, names]
42− );
43−
44− const rejectL1 = useCallback(
45− adoptee =>
46− push(names.ADOPT, {
47− adoptee,
48− denied: true,
49− }),
50− [push, names]
51− );
52−
53 const handleAcceptClick = useCallback(
35 const handleAcceptClick = useCallback(
54 async (ship: Ship) => {
36 async (ship: Ship) => {
55− if (point.isL1) {
56− acceptL1(ship);
57− } else {
58− setLoading(true);
37+ setLoading(true);
59− await changeSponsorship(ship, 'adopt');
38+ await changeSponsorship(ship, 'adopt');
60− await fetchRequests();
39+ await fetchRequests();
61− setLoading(false);
40+ setLoading(false);
62− }
63 },
41 },
64− [point, acceptL1, changeSponsorship, fetchRequests, setLoading]
42+ [changeSponsorship, fetchRequests, setLoading]
65 );
43 );
66
44
67 const handleRejectClick = useCallback(
45 const handleRejectClick = useCallback(
68 async (ship: Ship) => {
46 async (ship: Ship) => {
69− if (point.isL1) {
70− rejectL1(ship);
71− } else {
72− setLoading(true);
47+ setLoading(true);
73− await changeSponsorship(ship, 'reject');
48+ await changeSponsorship(ship, 'reject');
74− await fetchRequests();
49+ await fetchRequests();
75− setLoading(false);
50+ setLoading(false);
76− }
77 },
51 },
78− [point, rejectL1, changeSponsorship, fetchRequests, setLoading]
52+ [changeSponsorship, fetchRequests, setLoading]
79 );
53 );
80
54
81 useEffect(() => {
55 useEffect(() => {
src/views/Ops/ResidentRow.tsx+18−24
@@ -4,7 +4,6 @@ import { Ship } from '@urbit/roller-api';
4import Sigil from 'components/Sigil';
4import Sigil from 'components/Sigil';
5import { useCallback, useRef, useState } from 'react';
5import { useCallback, useRef, useState } from 'react';
6import useOnClickOutside from 'lib/useOnClickOutside';
6import useOnClickOutside from 'lib/useOnClickOutside';
7−import { useRollerStore } from 'store/rollerStore';
8
7
9interface ResidentRowProps {
8interface ResidentRowProps {
10 point: Ship;
9 point: Ship;
@@ -12,9 +11,6 @@ interface ResidentRowProps {
12}
11}
13
12
14export const ResidentRow = ({ point, onKick }: ResidentRowProps) => {
13export const ResidentRow = ({ point, onKick }: ResidentRowProps) => {
15− const {
16− point: { isL2 },
17− } = useRollerStore();
18 const [showDropdown, setShowDropdown] = useState<boolean>(false);
14 const [showDropdown, setShowDropdown] = useState<boolean>(false);
19 const dropdownRef = useRef<HTMLDivElement | null>(null);
15 const dropdownRef = useRef<HTMLDivElement | null>(null);
20
16
@@ -45,26 +41,24 @@ export const ResidentRow = ({ point, onKick }: ResidentRowProps) => {
45 </Box>
41 </Box>
46 <Box className={'patp'}>{ob.patp(point)}</Box>
42 <Box className={'patp'}>{ob.patp(point)}</Box>
47 </Box>
43 </Box>
48− {isL2 && (
49− <Box className="button-wrapper" ref={dropdownRef}>
44+ <Box className="button-wrapper" ref={dropdownRef}>
50− <Icon
45+ <Icon
51− icon="Ellipsis"
46+ icon="Ellipsis"
52− size="18px"
47+ size="18px"
53− onClick={() => setShowDropdown(!showDropdown)}
48+ onClick={() => setShowDropdown(!showDropdown)}
54− />
49+ />
55− {showDropdown && (
50+ {showDropdown && (
56− <>
51+ <>
57− <Box
52+ <Box
58− className="close-background"
53+ className="close-background"
59− onClick={() => setShowDropdown(false)}
54+ onClick={() => setShowDropdown(false)}
60− />
55+ />
61− <Box className="kick-dropdown" onClick={handleKickClick}>
56+ <Box className="kick-dropdown" onClick={handleKickClick}>
62− <Text>Kick</Text>
57+ <Text>Kick</Text>
63− </Box>
58+ </Box>
64− </>
59+ </>
65− )}
60+ )}
66− </Box>
61+ </Box>
67− )}
68 </li>
62 </li>
69 );
63 );
70};
64};
src/views/Party/PartySetPoolSize.js+1−1
@@ -120,7 +120,7 @@ export default function PartySetPoolSize() {
120
120
121 {!hasKeysSet && (
121 {!hasKeysSet && (
122 <Grid.Item full as={WarningBox} className="mb4 f6">
122 <Grid.Item full as={WarningBox} className="mb4 f6">
123− Networking keys must be configured for invitations to be available
123+ Network keys must be configured for invitations to be available
124 for use.
124 for use.
125 </Grid.Item>
125 </Grid.Item>
126 )}
126 )}
src/views/Point/Point.tsx+1−2
@@ -229,7 +229,6 @@ export default function Point() {
229 Invite Group <Blinky />
229 Invite Group <Blinky />
230 </Grid.Item>
230 </Grid.Item>
231 )}
231 )}
232− {/* {inviteButton} */}
233 {(canManage || isSpawnProxy) && (
232 {(canManage || isSpawnProxy) && (
234 <Grid.Item full as={Flex} justify="between">
233 <Grid.Item full as={Flex} justify="between">
235 <Card
234 <Card
@@ -237,7 +236,7 @@ export default function Point() {
237 subtitle="Master Key, Passport, Proxy Addresses, etc"
236 subtitle="Master Key, Passport, Proxy Addresses, etc"
238 icon={(<Icon icon="User" />) as any}
237 icon={(<Icon icon="User" />) as any}
239 onClick={goUrbitID}
238 onClick={goUrbitID}
240− disabled={!canManage}
239+ disabled={!(canManage || isSpawnProxy)}
241 />
240 />
242 </Grid.Item>
241 </Grid.Item>
243 )}
242 )}
src/views/Point/UrbitOS.js+2−2
@@ -9,7 +9,7 @@ import View from 'components/View';
9import L2BackHeader from 'components/L2/Headers/L2BackHeader';
9import L2BackHeader from 'components/L2/Headers/L2BackHeader';
10
10
11import UrbitOSHome from '../UrbitOS/Home';
11import UrbitOSHome from '../UrbitOS/Home';
12−import UrbitOSNetworkingKeys from '../UrbitOS/NetworkingKeys';
12+import UrbitOSNetworkKeys from '../UrbitOS/NetworkKeys';
13import UrbitOSChangeSponsor from '../UrbitOS/ChangeSponsor';
13import UrbitOSChangeSponsor from '../UrbitOS/ChangeSponsor';
14
14
15const NAMES = {
15const NAMES = {
@@ -21,7 +21,7 @@ const NAMES = {
21const VIEWS = {
21const VIEWS = {
22 [NAMES.HOME]: UrbitOSHome,
22 [NAMES.HOME]: UrbitOSHome,
23 [NAMES.CHANGE_SPONSOR]: UrbitOSChangeSponsor,
23 [NAMES.CHANGE_SPONSOR]: UrbitOSChangeSponsor,
24− [NAMES.NETWORKING_KEYS]: UrbitOSNetworkingKeys,
24+ [NAMES.NETWORKING_KEYS]: UrbitOSNetworkKeys,
25};
25};
26
26
27export default function UrbitOS() {
27export default function UrbitOS() {
src/views/Points.js+24−48
@@ -106,7 +106,7 @@ function ActionButtons({ actions = [] }) {
106
106
107export default function Points() {
107export default function Points() {
108 const { wallet } = useWallet();
108 const { wallet } = useWallet();
109− const { pop, push, popAndPush, names } = useHistory();
109+ const { pop, push, names } = useHistory();
110 const { setPointCursor } = usePointCursor();
110 const { setPointCursor } = usePointCursor();
111 const { controlledPoints, getDetails } = usePointCache();
111 const { controlledPoints, getDetails } = usePointCache();
112 const { contracts } = useNetwork();
112 const { contracts } = useNetwork();
@@ -119,11 +119,7 @@ export default function Points() {
119 const { syncStarReleaseDetails, starReleaseDetails } = useStarReleaseCache();
119 const { syncStarReleaseDetails, starReleaseDetails } = useStarReleaseCache();
120
120
121 const outgoingPoints = useMemo(
121 const outgoingPoints = useMemo(
122− () =>
123− pointList.filter(
122+ () => pointList.filter(({ isOutgoing }) => isOutgoing),
124− ({ isTransferProxySet, isTransferProxy }) =>
125− isTransferProxySet && !isTransferProxy
126− ),
127 [pointList]
123 [pointList]
128 );
124 );
129
125
@@ -164,47 +160,38 @@ export default function Points() {
164 ),
160 ),
165 [getDetails, controlledPoints, _contracts]
161 [getDetails, controlledPoints, _contracts]
166 );
162 );
163+
164+ const allPoints = pointList
165+ .filter(
166+ ({ isTransferProxySet, shouldDisplay }) =>
167+ !isTransferProxySet && shouldDisplay
168+ )
169+ .map(({ value }) => value);
170+
167− // if we can only interact with a single point, forget about the existence
171+ // if we can only interact with a single point, jump to the point page.
168− // of this page and jump to the point page.
169 // if there are any pending transfers, incoming or outgoing, stay on this
172 // if there are any pending transfers, incoming or outgoing, stay on this
170 // page, because those can only be completed/cancelled here.
173 // page, because those can only be completed/cancelled here.
171 useEffect(() => {
174 useEffect(() => {
172 if (Nothing.hasInstance(starReleaseDetails)) {
175 if (Nothing.hasInstance(starReleaseDetails)) {
173 return;
176 return;
174 }
177 }
175− controlledPoints.matchWith({
176− Nothing: () => null,
177− Just: r => {
178− r.value.matchWith({
179− Error: () => null,
180− Ok: c => {
181− let all = [
182− ...c.value.ownedPoints,
183− ...c.value.votingPoints,
184− ...c.value.managingPoints,
185− ...c.value.spawningPoints,
186− ];
187− if (
178+ if (
188− all.length === 1 &&
179+ allPoints.length === 1 &&
189− incomingPoints.length === 0 &&
180+ incomingPoints.length === 0 &&
190− outgoingPoints.length === 0 &&
181+ outgoingPoints.length === 0 &&
191− (starReleaseDetails.value === null ||
182+ (starReleaseDetails.value === null ||
192− starReleaseDetails.value.total === 0)
183+ starReleaseDetails.value.total === 0)
193− ) {
184+ ) {
194− setPointCursor(Just(all[0]));
185+ setPointCursor(Just(allPoints[0]));
195− popAndPush(names.POINT);
186+ push(names.POINT);
196− }
197− },
198− });
199− },
200− });
187+ }
201 }, [
188 }, [
202− controlledPoints,
189+ allPoints,
203 rejectedPoints,
190 rejectedPoints,
204 outgoingPoints,
191 outgoingPoints,
205 incomingPoints,
192 incomingPoints,
206 setPointCursor,
193 setPointCursor,
207− popAndPush,
194+ push,
208 names,
195 names,
209 starReleaseDetails,
196 starReleaseDetails,
210 ]);
197 ]);
@@ -216,13 +203,6 @@ export default function Points() {
216 const ownedPoints = maybeGetResult(controlledPoints, 'ownedPoints', []);
203 const ownedPoints = maybeGetResult(controlledPoints, 'ownedPoints', []);
217 const lockedPoints = maybeLockedPoints.getOrElse([]);
204 const lockedPoints = maybeLockedPoints.getOrElse([]);
218
205
219− const allPoints = pointList
220− .filter(
221− ({ isTransferProxySet, shouldDisplay }) =>
222− !isTransferProxySet && shouldDisplay
223− )
224− .map(({ value }) => value);
225−
226 const processingPoints = pointList
206 const processingPoints = pointList
227 .filter(({ shouldDisplay }) => !shouldDisplay)
207 .filter(({ shouldDisplay }) => !shouldDisplay)
228 .map(({ value }) => value);
208 .map(({ value }) => value);
@@ -298,11 +278,7 @@ export default function Points() {
298 outgoingPoints.length === 0 &&
278 outgoingPoints.length === 0 &&
299 !starReleasing)
279 !starReleasing)
300 ) {
280 ) {
301− return (
302− <View inset>
303− <LoadingOverlay loading />
281+ return <LoadingOverlay loading />;
304− </View>
305− );
306 }
282 }
307
283
308 return (
284 return (
src/views/UrbitOS/Home.tsx+12−12
@@ -2,7 +2,7 @@ import React, { useCallback, useState } from 'react';
2import { Grid } from 'indigo-react';
2import { Grid } from 'indigo-react';
3import * as ob from 'urbit-ob';
3import * as ob from 'urbit-ob';
4
4
5−import NetworkingKeys from 'components/NetworkingKeys';
5+import NetworkKeys from 'components/NetworkKeys';
6import Window from 'components/L2/Window/Window';
6import Window from 'components/L2/Window/Window';
7import HeaderPane from 'components/L2/Window/HeaderPane';
7import HeaderPane from 'components/L2/Window/HeaderPane';
8import BodyPane from 'components/L2/Window/BodyPane';
8import BodyPane from 'components/L2/Window/BodyPane';
@@ -30,9 +30,9 @@ export default function UrbitOSHome() {
30 const toggleShowKeys = useCallback(() => setShowKeys(s => !s), [setShowKeys]);
30 const toggleShowKeys = useCallback(() => setShowKeys(s => !s), [setShowKeys]);
31
31
32 // The initial key revision number is 0, and increments when set
32 // The initial key revision number is 0, and increments when set
33− const hasSetNetworkingKeys = point.keyRevisionNumber !== '0';
33+ const hasSetNetworkKeys = point.keyRevisionNumber !== '0';
34
34
35− const goNetworkingKeys = useCallback(() => push(names.NETWORKING_KEYS), [
35+ const goNetworkKeys = useCallback(() => push(names.NETWORKING_KEYS), [
36 names,
36 names,
37 push,
37 push,
38 ]);
38 ]);
@@ -49,10 +49,10 @@ export default function UrbitOSHome() {
49 <HeaderPane>
49 <HeaderPane>
50 <Row className="header-row">
50 <Row className="header-row">
51 <h5>OS</h5>
51 <h5>OS</h5>
52− {hasSetNetworkingKeys && (
52+ {hasSetNetworkKeys && (
53 <Button
53 <Button
54 className="header-button keyfile"
54 className="header-button keyfile"
55− disabled={!hasSetNetworkingKeys}
55+ disabled={!hasSetNetworkKeys}
56 onClick={keyBind.download}>
56 onClick={keyBind.download}>
57 <KeyfileIcon />
57 <KeyfileIcon />
58 Download Keyfile
58 Download Keyfile
@@ -84,20 +84,20 @@ export default function UrbitOSHome() {
84 <Box>Network Keys</Box>
84 <Box>Network Keys</Box>
85 <Box
85 <Box
86 className={`subtitle ${
86 className={`subtitle ${
87− !hasSetNetworkingKeys ? 'error-text' : ''
87+ !hasSetNetworkKeys ? 'error-text' : ''
88 }`}>
88 }`}>
89− {hasSetNetworkingKeys
89+ {hasSetNetworkKeys
90 ? `Revision: ${point.keyRevisionNumber}`
90 ? `Revision: ${point.keyRevisionNumber}`
91 : 'No network keys found'}
91 : 'No network keys found'}
92 </Box>
92 </Box>
93 </Box>
93 </Box>
94 <Row>
94 <Row>
95 <Button
95 <Button
96− className={hasSetNetworkingKeys ? 'secondary' : 'primary'}
96+ className={hasSetNetworkKeys ? 'secondary' : 'primary'}
97− onClick={goNetworkingKeys}>
97+ onClick={goNetworkKeys}>
98− {hasSetNetworkingKeys ? 'Reset' : 'Initialize'}
98+ {hasSetNetworkKeys ? 'Reset' : 'Initialize'}
99 </Button>
99 </Button>
100− {hasSetNetworkingKeys && (
100+ {hasSetNetworkKeys && (
101 <Button className="secondary" onClick={toggleShowKeys}>
101 <Button className="secondary" onClick={toggleShowKeys}>
102 View
102 View
103 </Button>
103 </Button>
@@ -120,7 +120,7 @@ export default function UrbitOSHome() {
120
120
121 <Modal show={showKeys} hide={() => setShowKeys(false)}>
121 <Modal show={showKeys} hide={() => setShowKeys(false)}>
122 <Box className="show-keys-modal-content">
122 <Box className="show-keys-modal-content">
123− <Grid.Item full as={NetworkingKeys} point={point.value} />
123+ <Grid.Item full as={NetworkKeys} point={point.value} />
124 </Box>
124 </Box>
125 </Modal>
125 </Modal>
126 </Window>
126 </Window>
src/views/UrbitOS/NetworkingKeys.js → src/views/UrbitOS/NetworkKeys.jsrenamed+11−11
@@ -145,14 +145,14 @@ function useSetKeys(manualNetworkSeed, setManualNetworkSeed) {
145 };
145 };
146}
146}
147
147
148−export default function UrbitOSNetworkingKeys({
148+export default function UrbitOSNetworkKeys({
149 manualNetworkSeed,
149 manualNetworkSeed,
150 setManualNetworkSeed,
150 setManualNetworkSeed,
151}) {
151}) {
152 const { pop } = useLocalRouter();
152 const { pop } = useLocalRouter();
153 const { point, setLoading } = useRollerStore();
153 const { point, setLoading } = useRollerStore();
154 const {
154 const {
155− configureNetworkingKeys,
155+ configureNetworkKeys,
156 getPendingTransactions,
156 getPendingTransactions,
157 checkForUpdates,
157 checkForUpdates,
158 } = useRoller();
158 } = useRoller();
@@ -173,7 +173,7 @@ export default function UrbitOSNetworkingKeys({
173 if (completed) {
173 if (completed) {
174 checkForUpdates(
174 checkForUpdates(
175 point.value,
175 point.value,
176− `${point.patp}'s Networking Keys have been set!`
176+ `${point.patp}'s Network Keys have been set!`
177 );
177 );
178 }
178 }
179 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
179 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
@@ -219,10 +219,10 @@ export default function UrbitOSNetworkingKeys({
219 [construct, unconstruct, setManualNetworkSeed, setBreach]
219 [construct, unconstruct, setManualNetworkSeed, setBreach]
220 );
220 );
221
221
222− const setNetworkingKeys = useCallback(async () => {
222+ const setNetworkKeys = useCallback(async () => {
223 setLoading(true);
223 setLoading(true);
224 try {
224 try {
225− await configureNetworkingKeys({
225+ await configureNetworkKeys({
226 breach,
226 breach,
227 manualNetworkSeed,
227 manualNetworkSeed,
228 });
228 });
@@ -237,7 +237,7 @@ export default function UrbitOSNetworkingKeys({
237 //
237 //
238 checkForUpdates(
238 checkForUpdates(
239 point.value,
239 point.value,
240− `${point.patp}'s Networking Keys have been set!`
240+ `${point.patp}'s Network Keys have been set!`
241 );
241 );
242 pop();
242 pop();
243 } catch (error) {
243 } catch (error) {
@@ -251,7 +251,7 @@ export default function UrbitOSNetworkingKeys({
251 getPendingTransactions,
251 getPendingTransactions,
252 point,
252 point,
253 pop,
253 pop,
254− configureNetworkingKeys,
254+ configureNetworkKeys,
255 setLoading,
255 setLoading,
256 checkForUpdates,
256 checkForUpdates,
257 ]);
257 ]);
@@ -266,7 +266,7 @@ export default function UrbitOSNetworkingKeys({
266
266
267 const viewTitle = completed
267 const viewTitle = completed
268 ? 'Network Keys are now set'
268 ? 'Network Keys are now set'
269− : 'Set Networking Keys';
269+ : 'Set Network Keys';
270
270
271 const usageMessage =
271 const usageMessage =
272 'You need this keyfile to authenticate with your OS. Please Download.';
272 'You need this keyfile to authenticate with your OS. Please Download.';
@@ -350,15 +350,15 @@ export default function UrbitOSNetworkingKeys({
350 className=""
350 className=""
351 center
351 center
352 solid
352 solid
353− onClick={setNetworkingKeys}>
353+ onClick={setNetworkKeys}>
354− {'Reset Networking Keys'}
354+ {'Reset Network Keys'}
355 </Grid.Item>
355 </Grid.Item>
356 ) : (
356 ) : (
357 <Grid.Item
357 <Grid.Item
358 full
358 full
359 as={InlineEthereumTransaction}
359 as={InlineEthereumTransaction}
360 {...bind}
360 {...bind}
361− label={`${hasKeys ? 'Reset' : 'Set'} Networking Keys`}
361+ label={`${hasKeys ? 'Reset' : 'Set'} Network Keys`}
362 onReturn={() => pop()}
362 onReturn={() => pop()}
363 />
363 />
364 )}
364 )}