on master help sign in
Add permissions page
commitc17dcfdd226e83d037531dba3ca8002ba687674d authorFang <git@fang.io> dateTue 2 Jul 2019, 21:56 (7 years ago) parent924e769
4 files changed+181−1
src/lib/routeNames.js+1 src/lib/router.js+2 src/views/Admin.js+11−1 src/views/Permissions.js+167
src/lib/routeNames.js+1
@@ -10,6 +10,7 @@ export const ROUTE_NAMES = {
1010 ADMIN: Symbol('ADMIN'),
1111 REDOWNLOAD: Symbol('REDOWNLOAD'),
1212 RETICKET: Symbol('RETICKET'),
13+ PERMISSIONS: Symbol('PERMISSIONS'),
1314 //
1415 ACCEPT_TRANSFER: Symbol('ACCEPT_TRANSFER'),
1516 CANCEL_TRANSFER: Symbol('CANCEL_TRANSFER'),
src/lib/router.js+2
@@ -4,6 +4,7 @@ import InvitesManage from '../views/InvitesManage.js';
44import Admin from '../views/Admin';
55import Redownload from '../views/Redownload';
66import Reticket from '../views/Reticket';
7+import Permissions from '../views/Permissions';
78import AcceptTransfer from '../views/AcceptTransfer';
89import CancelTransfer from '../views/CancelTransfer';
910import CreateGalaxy from '../views/CreateGalaxy';
@@ -34,6 +35,7 @@ export const ROUTES = {
3435 [ROUTE_NAMES.ADMIN]: Admin,
3536 [ROUTE_NAMES.REDOWNLOAD]: Redownload,
3637 [ROUTE_NAMES.RETICKET]: Reticket,
38+ [ROUTE_NAMES.PERMISSIONS]: Permissions,
3739 [ROUTE_NAMES.ACCEPT_TRANSFER]: AcceptTransfer,
3840 [ROUTE_NAMES.CANCEL_TRANSFER]: CancelTransfer,
3941 [ROUTE_NAMES.VIEW_POINT]: ViewPoint,
src/views/Admin.js+11−1
@@ -23,12 +23,15 @@ export default function Admin() {
2323 history,
2424 ]);
2525
26+ const goEditPerms = useCallback(() => history.push(ROUTE_NAMES.PERMISSIONS), [
27+ history,
28+ ]);
2629
2730 const canDownloadPassport = Just.hasInstance(urbitWallet);
2831
2932 return (
3033 <View>
31− <Grid className="pt2">
34+ <Grid className="pt3">
3235 <Grid.Item full>
3336 <ForwardButton
3437 disabled={!canDownloadPassport}
@@ -45,6 +48,13 @@ export default function Admin() {
4548 Reticket
4649 </ForwardButton>
4750 </Grid.Item>
51+ <Grid.Item full>
52+ <ForwardButton
53+ onClick={goEditPerms}
54+ detail="Management, networking keys, etc.">
55+ Edit permissions
56+ </ForwardButton>
57+ </Grid.Item>
4858 </Grid>
4959
5060 <FooterButton detail="Transfer this identity to a new owner" disabled>
src/views/Permissions.jsnew file+167
@@ -0,0 +1,167 @@
1+import React, { useState, useCallback } from 'react';
2+import { Just, Nothing } from 'folktale/maybe';
3+import * as need from 'lib/need';
4+import { azimuth } from 'azimuth-js';
5+import { Grid } from 'indigo-react';
6+
7+import { P } from 'indigo-react';
8+import View from 'components/View';
9+import { ForwardButton } from 'components/Buttons';
10+import FooterButton from 'components/FooterButton';
11+import Blinky, {
12+ LOADING_CHARACTER,
13+ INTERSTITIAL_CHARACTER,
14+} from 'components/Blinky';
15+
16+import { ROUTE_NAMES } from 'lib/routeNames';
17+import { eqAddr } from 'lib/wallet';
18+
19+import useLifecycle from 'lib/useLifecycle';
20+import { useNetwork } from 'store/network';
21+import { useHistory } from 'store/history';
22+import { useWallet } from 'store/wallet';
23+import { usePointCursor } from 'store/pointCursor';
24+import { usePointCache } from 'store/pointCache';
25+
26+//TODO consolidate with azimuth-js' getActivationBlock
27+const getRekeyDate = async (web3, contracts, point) => {
28+ const logs = await contracts.azimuth.getPastEvents('ChangedKeys', {
29+ fromBlock: 0,
30+ toBlock: 'latest',
31+ filter: { point: [point] },
32+ });
33+ if (logs.length === 0) {
34+ return null;
35+ } else {
36+ // last log is most recent
37+ const block = await web3.eth.getBlock(logs[logs.length - 1].blockNumber);
38+ return new Date(block.timestamp * 1000);
39+ }
40+};
41+
42+export default function Permissions() {
43+ const history = useHistory();
44+ const { web3, contracts } = useNetwork();
45+ const { wallet } = useWallet();
46+ const { pointCursor } = usePointCursor();
47+ const { pointCache } = usePointCache();
48+
49+ const [rekeyDate, setRekeyDate] = useState(Nothing());
50+
51+ const point = need.point(pointCursor);
52+ const pointSize = azimuth.getPointSize(point);
53+ const userAddress = need.wallet(wallet).address;
54+
55+ useLifecycle(() => {
56+ getRekeyDate(need.web3(web3), need.contracts(contracts), point).then(
57+ res => {
58+ if (res === null) setRekeyDate(Just('unknown'));
59+ else setRekeyDate(Just(res.toString()));
60+ }
61+ );
62+ });
63+
64+ const goSetManagement = useCallback(
65+ () => history.push(ROUTE_NAMES.SET_MANAGEMENT_PROXY),
66+ [history]
67+ );
68+
69+ const goSetSpawn = useCallback(
70+ () => history.push(ROUTE_NAMES.SET_SPAWN_PROXY),
71+ [history]
72+ );
73+
74+ const goSetVoting = useCallback(
75+ () => history.push(ROUTE_NAMES.SET_VOTING_PROXY),
76+ [history]
77+ );
78+
79+ const goSetKeys = useCallback(() => history.push(ROUTE_NAMES.SET_KEYS), [
80+ history,
81+ ]);
82+
83+ const pointDetails = need.fromPointCache(pointCache, point);
84+
85+ const isOwner = eqAddr(userAddress, pointDetails.owner);
86+ const canManage =
87+ isOwner || eqAddr(userAddress, pointDetails.managementProxy);
88+
89+ const proxyAction = (name, address, onClick) => {
90+ if (address === '0x0000000000000000000000000000000000000000')
91+ address = 'Unset';
92+ return (
93+ <Grid.Item full>
94+ <ForwardButton disabled={!isOwner} onClick={onClick} detail={address}>
95+ {`${name} proxy address`}
96+ </ForwardButton>
97+ </Grid.Item>
98+ );
99+ };
100+
101+ let items = 3;
102+
103+ let spawnProxyAction = null;
104+ if (pointSize !== azimuth.PointSize.Planet) {
105+ items++;
106+ spawnProxyAction = proxyAction(
107+ 'Spawn',
108+ pointDetails.spawnProxy,
109+ goSetSpawn
110+ );
111+ }
112+
113+ let votingProxyAction = null;
114+ if (pointSize === azimuth.PointSize.Galaxy) {
115+ items++;
116+ votingProxyAction = proxyAction(
117+ 'Voting',
118+ pointDetails.votingProxy,
119+ goSetVoting
120+ );
121+ }
122+
123+ const netKeysText =
124+ pointDetails.keyRevisionNumber === 0 ? (
125+ 'Not yet configured'
126+ ) : (
127+ <>
128+ {`Revision #${pointDetails.keyRevisionNumber}, since `}
129+ {Just.hasInstance(rekeyDate) ? (
130+ rekeyDate.value
131+ ) : (
132+ <Blinky a={LOADING_CHARACTER} b={INTERSTITIAL_CHARACTER} delayed />
133+ )}
134+ </>
135+ );
136+
137+ return (
138+ <View>
139+ <Grid className={`pt${items}`}>
140+ <Grid.Item full>
141+ <ForwardButton disabled="true" detail={pointDetails.owner}>
142+ Ownership address
143+ </ForwardButton>
144+ </Grid.Item>
145+ {proxyAction(
146+ 'Management',
147+ pointDetails.managementProxy,
148+ goSetManagement
149+ )}
150+ {spawnProxyAction}
151+ {votingProxyAction}
152+ <Grid.Item full>
153+ <ForwardButton
154+ disabled={!canManage}
155+ onClick={goSetKeys}
156+ detail={netKeysText}>
157+ Network keys
158+ </ForwardButton>
159+ </Grid.Item>
160+ </Grid>
161+
162+ <FooterButton detail="Transfer this identity to a new owner" disabled>
163+ Transfer
164+ </FooterButton>
165+ </View>
166+ );
167+}