on master help sign in
checkpoint: reconfigure admin routes
commit1c7aa3b4c9d28661db93d525d91808814fc0ee6c authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateMon 8 Jul 2019, 21:29 (7 years ago) parent3c467ed
10 files changed+168−142
src/Bridge.js+6−1 src/components/Crumbs.js+1−1 src/lib/router.js−6 src/lib/usePermissionsForPoint.js+28−2 src/lib/useRouter.js+11−6 src/views/Admin.js+15−4 src/views/Permissions.js → src/views/Admin/AdminEditPermissions.js+51−61 src/views/Admin/AdminHome.js+50−55 src/views/Redownload.js → src/views/Admin/AdminRedownload.js+1−1 src/views/Reticket.js → src/views/Admin/AdminReticket.js+5−5
src/Bridge.js+6−1
@@ -23,7 +23,12 @@ const INITIAL_NETWORK_TYPE = isDevelopment
2323const SHOULD_STUB_LOCAL = process.env.REACT_APP_STUB_LOCAL === 'true';
2424const IS_STUBBED = isDevelopment && SHOULD_STUB_LOCAL;
2525const INITIAL_ROUTES = IS_STUBBED
26− ? [{ key: ROUTE_NAMES.LANDING }, { key: ROUTE_NAMES.LOGIN }]
26+ ? [
27+ { key: ROUTE_NAMES.LANDING },
28+ { key: ROUTE_NAMES.LOGIN },
29+ { key: ROUTE_NAMES.POINTS },
30+ { key: ROUTE_NAMES.POINT },
31+ ]
2732 : [{ key: ROUTE_NAMES.LANDING }];
2833
2934const INITIAL_WALLET = IS_STUBBED
src/components/Crumbs.js+1−1
@@ -20,7 +20,7 @@ export default function Crumbs({ className, routes = [] }) {
2020 {route.text}
2121 </Flex.Item>
2222 {i !== lastIndex && (
23− <Flex.Item as={Breadcrumb} className={cn(textStyle, 'mh4')}>
23+ <Flex.Item as={Breadcrumb} className={cn(textStyle, 'mh2')}>
2424 /
2525 </Flex.Item>
2626 )}
src/lib/router.js−6
@@ -2,9 +2,6 @@ import Landing from '../views/Landing';
22import Login from '../views/Login.js';
33import InvitesManage from '../views/InvitesManage.js';
44import Admin from '../views/Admin';
5−import Redownload from '../views/Redownload';
6−import Reticket from '../views/Reticket';
7−import Permissions from '../views/Permissions';
85import AcceptTransfer from '../views/AcceptTransfer';
96import CancelTransfer from '../views/CancelTransfer';
107import CreateGalaxy from '../views/CreateGalaxy';
@@ -32,9 +29,6 @@ export const ROUTES = {
3229 [ROUTE_NAMES.INVITES_MANAGE]: InvitesManage,
3330 [ROUTE_NAMES.LOGIN]: Login,
3431 [ROUTE_NAMES.ADMIN]: Admin,
35− [ROUTE_NAMES.REDOWNLOAD]: Redownload,
36− [ROUTE_NAMES.RETICKET]: Reticket,
37− [ROUTE_NAMES.PERMISSIONS]: Permissions,
3832 [ROUTE_NAMES.ACCEPT_TRANSFER]: AcceptTransfer,
3933 [ROUTE_NAMES.CANCEL_TRANSFER]: CancelTransfer,
4034 [ROUTE_NAMES.VIEW_POINT]: ViewPoint,
src/lib/usePermissionsForPoint.js+28−2
@@ -1,11 +1,17 @@
1−import { eqAddr } from './wallet';
1+import { azimuth } from 'azimuth-js';
2+
23import { usePointCache } from 'store/pointCache';
34
5+import { eqAddr } from './wallet';
6+
47const NULL_PERMISSIONS = {
58 isOwner: false,
69 isTransferProxy: false,
710 isManagementProxy: false,
11+ canManage: false,
812 canTransfer: false,
13+ canSpawn: false,
14+ canVote: false,
915};
1016
1117/**
@@ -18,12 +24,32 @@ export default function usePermissionsForPoint(address, point) {
1824 return getDetails(point).matchWith({
1925 Nothing: () => NULL_PERMISSIONS,
2026 Just: ({ value: details }) => {
27+ const pointSize = azimuth.getPointSize(point);
28+ const isPlanet = pointSize === azimuth.PointSize.Planet;
29+ const isStar = pointSize === azimuth.PointSize.Star;
30+ const isGalaxy = pointSize === azimuth.PointSize.Galaxy;
31+
2132 const isOwner = eqAddr(address, details.owner);
2233 const isTransferProxy = eqAddr(address, details.transferProxy);
2334 const isManagementProxy = eqAddr(address, details.managementProxy);
35+ const isSpawnProxy = eqAddr(address, details.spawnProxy);
36+ const isVotingProxy = eqAddr(address, details.votingProxy);
37+
38+ const canManage = isOwner || isManagementProxy;
2439 const canTransfer = isOwner || isTransferProxy;
2540
26− return { isOwner, isTransferProxy, isManagementProxy, canTransfer };
41+ const canSpawn = (isStar || isGalaxy) && (isOwner || isSpawnProxy);
42+ const canVote = isGalaxy && (isOwner || isVotingProxy);
43+
44+ return {
45+ isOwner,
46+ isTransferProxy,
47+ isManagementProxy,
48+ canManage,
49+ canTransfer,
50+ canSpawn,
51+ canVote,
52+ };
2753 },
2854 });
2955}
src/lib/useRouter.js+11−6
@@ -71,23 +71,28 @@ export default function useRouter({
7171 // Scroll to top of page with each route transition
7272 useEffect(() => {
7373 window.scrollTo(0, 0);
74− }, [routes, primary]);
74+ }, [routes]);
7575
7676 // capture browser pop in primary router
7777 useEffect(() => {
78− if (!primary) {
79− return;
80− }
78+ const oldPopState = window.onpopstate;
8179
8280 window.history.pushState(null, null, null);
8381
8482 window.onpopstate = e => {
83+ if (size <= 1) {
84+ // if this is the root route, give the event to parent router
85+ return oldPopState(e);
86+ }
87+
8588 window.history.pushState(null, null, null);
8689 pop();
8790 };
8891
89− // TODO: disposer functon
90− }, [pop, primary]);
92+ return () => {
93+ window.onpopstate = oldPopState;
94+ };
95+ }, [size, pop]);
9196
9297 return {
9398 Route,
src/views/Admin.js+15−4
@@ -1,21 +1,32 @@
11import React from 'react';
22import { Grid } from 'indigo-react';
33
4−import View from 'components/View';
5−
64import { useHistory } from 'store/history';
7−import Crumbs from 'components/Crumbs';
5+
86import useCurrentPointName from 'lib/useCurrentPointName';
97import useRouter from 'lib/useRouter';
10−import AdminHome from './Admin/AdminHome';
118import { LocalRouterProvider } from 'lib/LocalRouter';
129
10+import View from 'components/View';
11+import Crumbs from 'components/Crumbs';
12+
13+import AdminHome from './Admin/AdminHome';
14+import AdminEditPermissions from './Admin/AdminEditPermissions';
15+import AdminRedownload from './Admin/AdminRedownload';
16+import AdminReticket from './Admin/AdminReticket';
17+
1318const NAMES = {
1419 HOME: 'HOME',
20+ EDIT_PERMISSIONS: 'EDIT_PERMISSIONS',
21+ REDOWNLOAD: 'REDOWNLOAD',
22+ RETICKET: 'RETICKET',
1523};
1624
1725const VIEWS = {
1826 [NAMES.HOME]: AdminHome,
27+ [NAMES.EDIT_PERMISSIONS]: AdminEditPermissions,
28+ [NAMES.REDOWNLOAD]: AdminRedownload,
29+ [NAMES.RETICKET]: AdminReticket,
1930};
2031
2132export default function Admin() {
src/views/Permissions.js → src/views/Admin/AdminEditPermissions.jsrenamed+51−61
@@ -1,16 +1,13 @@
11import React, { useState, useCallback } from 'react';
22import { Just, Nothing } from 'folktale/maybe';
33import * as need from 'lib/need';
4−import { azimuth } from 'azimuth-js';
54import { Grid } from 'indigo-react';
65
7−import View from 'components/View';
86import { ForwardButton } from 'components/Buttons';
9−import FooterButton from 'components/FooterButton';
107import { matchBlinky } from 'components/Blinky';
118
129import { ROUTE_NAMES } from 'lib/routeNames';
13−import { eqAddr } from 'lib/wallet';
10+import { ETH_ZERO_ADDR } from 'lib/wallet';
1411
1512import useLifecycle from 'lib/useLifecycle';
1613import { useNetwork } from 'store/network';
@@ -18,6 +15,8 @@ import { useHistory } from 'store/history';
1815import { useWallet } from 'store/wallet';
1916import { usePointCursor } from 'store/pointCursor';
2017import { usePointCache } from 'store/pointCache';
18+import ViewHeader from 'components/ViewHeader';
19+import usePermissionsForPoint from 'lib/usePermissionsForPoint';
2120
2221//TODO consolidate with azimuth-js' getActivationBlock
2322const getRekeyDate = async (web3, contracts, point) => {
@@ -35,19 +34,24 @@ const getRekeyDate = async (web3, contracts, point) => {
3534 }
3635};
3736
38−export default function Permissions() {
37+export default function AdminEditPermissions() {
3938 const history = useHistory();
4039 const { web3, contracts } = useNetwork();
4140 const { wallet } = useWallet();
4241 const { pointCursor } = usePointCursor();
43− const { pointCache } = usePointCache();
42+ const { getDetails } = usePointCache();
4443
4544 const [rekeyDate, setRekeyDate] = useState(Nothing());
4645
4746 const point = need.point(pointCursor);
48− const pointSize = azimuth.getPointSize(point);
4947 const userAddress = need.wallet(wallet).address;
5048
49+ const pointDetails = need.details(getDetails(point));
50+ const { isOwner, canManage, canSpawn, canVote } = usePermissionsForPoint(
51+ userAddress,
52+ point
53+ );
54+
5155 useLifecycle(() => {
5256 getRekeyDate(need.web3(web3), need.contracts(contracts), point).then(
5357 res => {
@@ -76,43 +80,21 @@ export default function Permissions() {
7680 history,
7781 ]);
7882
79− const pointDetails = need.fromPointCache(pointCache, point);
80−
81− const isOwner = eqAddr(userAddress, pointDetails.owner);
82− const canManage =
83− isOwner || eqAddr(userAddress, pointDetails.managementProxy);
84−
8583 const proxyAction = (name, address, onClick) => {
86− if (address === '0x0000000000000000000000000000000000000000')
87− address = 'Unset';
84+ if (address === ETH_ZERO_ADDR) {
85+ address = 'Not yet set';
86+ }
87+
8888 return (
8989 <Grid.Item full>
9090 <ForwardButton disabled={!isOwner} onClick={onClick} detail={address}>
91− {`${name} proxy address`}
91+ {`${name} Proxy Address`}
9292 </ForwardButton>
9393 </Grid.Item>
9494 );
9595 };
9696
97− let spawnProxyAction = null;
98− if (pointSize !== azimuth.PointSize.Planet) {
99− spawnProxyAction = proxyAction(
100− 'Spawn',
101− pointDetails.spawnProxy,
102− goSetSpawn
103− );
104− }
105−
106− let votingProxyAction = null;
107− if (pointSize === azimuth.PointSize.Galaxy) {
108− votingProxyAction = proxyAction(
109− 'Voting',
110− pointDetails.votingProxy,
111− goSetVoting
112− );
113− }
114−
115− const netKeysText =
97+ const networkKeysDetail =
11698 pointDetails.keyRevisionNumber === 0 ? (
11799 'Not yet configured'
118100 ) : (
@@ -123,31 +105,39 @@ export default function Permissions() {
123105 );
124106
125107 return (
126− <View>
127− <Grid className="pt2">
128− <Grid.Item full as={ForwardButton} disabled detail={pointDetails.owner}>
129− Ownership address
130− </Grid.Item>
131− {proxyAction(
132− 'Management',
133− pointDetails.managementProxy,
134− goSetManagement
135− )}
136− {spawnProxyAction}
137− {votingProxyAction}
138− <Grid.Item
139− full
140− as={ForwardButton}
141− disabled={!canManage}
142− onClick={goSetKeys}
143− detail={netKeysText}>
144− Network keys
145− </Grid.Item>
146− </Grid>
147−
148− <FooterButton detail="Transfer this identity to a new owner" disabled>
149− Transfer
150− </FooterButton>
151− </View>
108+ <Grid>
109+ <Grid.Item full as={ViewHeader}>
110+ Permissions
111+ </Grid.Item>
112+ <Grid.Item full as={ForwardButton} detail={pointDetails.owner} disabled>
113+ Ownership Address
114+ </Grid.Item>
115+ <Grid.Divider />
116+ {proxyAction('Management', pointDetails.managementProxy, goSetManagement)}
117+ <Grid.Divider />
118+
119+ {canSpawn && (
120+ <>
121+ {proxyAction('Spawn', pointDetails.spawnProxy, goSetSpawn)}
122+ <Grid.Divider />
123+ </>
124+ )}
125+
126+ {canVote && (
127+ <>
128+ {proxyAction('Voting', pointDetails.votingProxy, goSetVoting)}
129+ <Grid.Divider />
130+ </>
131+ )}
132+ <Grid.Item
133+ full
134+ as={ForwardButton}
135+ disabled={!canManage}
136+ onClick={goSetKeys}
137+ detail={networkKeysDetail}>
138+ Network keys
139+ </Grid.Item>
140+ <Grid.Divider />
141+ </Grid>
152142 );
153143}
src/views/Admin/AdminHome.js+50−55
@@ -15,9 +15,11 @@ import usePermissionsForPoint from 'lib/usePermissionsForPoint';
1515import FooterButton from 'components/FooterButton';
1616import ViewHeader from 'components/ViewHeader';
1717import Blinky from 'components/Blinky';
18+import { useLocalRouter } from 'lib/LocalRouter';
1819
1920export default function AdminHome() {
2021 const history = useHistory();
22+ const { push, names } = useLocalRouter();
2123 const { urbitWallet, wallet } = useWallet();
2224 const { pointCursor } = usePointCursor();
2325
@@ -31,20 +33,12 @@ export default function AdminHome() {
3133 generateAndDownload: generateAndDownloadKeyfile,
3234 } = useKeyfileGenerator(point);
3335
34− const goRedownload = useCallback(
35− () => history.push(history.names.REDOWNLOAD),
36− [history]
37− );
38−
39− const goReticket = useCallback(() => history.push(history.names.RETICKET), [
40− history,
36+ const goRedownload = useCallback(() => push(names.REDOWNLOAD), [push, names]);
37+ const goReticket = useCallback(() => push(names.RETICKET), [push, names]);
38+ const goEditPermissions = useCallback(() => push(names.EDIT_PERMISSIONS), [
39+ push,
40+ names,
4141 ]);
42−
43− const goEditPermissions = useCallback(
44− () => history.push(history.names.PERMISSIONS),
45− [history]
46− );
47−
4842 const goTransfer = useCallback(() => history.push(history.names.TRANSFER), [
4943 history,
5044 ]);
@@ -52,54 +46,55 @@ export default function AdminHome() {
5246 const canDownloadPassport = Just.hasInstance(urbitWallet);
5347
5448 return (
55− <Grid>
56− <Grid.Item full as={ViewHeader}>
57− Admin
58− </Grid.Item>
59−
60− <Grid.Item
61− full
62− as={ForwardButton}
63− disabled={!canDownloadPassport}
64− onClick={goRedownload}
65− detail="Re-download your paper wallet">
66− Download Passport
67− </Grid.Item>
68− <Grid.Divider />
69− <Grid.Item
70− full
71− as={DownloadButton}
72− disabled={!keyfileAvailable}
73− accessory={generatingKeyfile ? <Blinky /> : undefined}
74− onClick={generateAndDownloadKeyfile}
75− detail="Download your Arvo Keyfile">
76− Download Arvo Keyfile
77− </Grid.Item>
78− <Grid.Divider />
79− <Grid.Item
80− full
81− as={ForwardButton}
82− disabled={!isOwner}
83− onClick={goReticket}
84− detail="Move to brand new wallet, resetting all permissions">
85− Reticket
86− </Grid.Item>
87− <Grid.Divider />
88− <Grid.Item
89− full
90− as={ForwardButton}
91− onClick={goEditPermissions}
92− detail="Proxies, networking keys, etc.">
93− Edit permissions
94− </Grid.Item>
95− <Grid.Divider />
49+ <>
50+ <Grid>
51+ <Grid.Item full as={ViewHeader}>
52+ Admin
53+ </Grid.Item>
9654
55+ <Grid.Item
56+ full
57+ as={ForwardButton}
58+ disabled={!canDownloadPassport}
59+ onClick={goRedownload}
60+ detail="Re-download your paper wallet">
61+ Download Passport
62+ </Grid.Item>
63+ <Grid.Divider />
64+ <Grid.Item
65+ full
66+ as={DownloadButton}
67+ disabled={!keyfileAvailable}
68+ accessory={generatingKeyfile ? <Blinky /> : undefined}
69+ onClick={generateAndDownloadKeyfile}
70+ detail="Download your Arvo Keyfile">
71+ Download Arvo Keyfile
72+ </Grid.Item>
73+ <Grid.Divider />
74+ <Grid.Item
75+ full
76+ as={ForwardButton}
77+ disabled={!isOwner}
78+ onClick={goReticket}
79+ detail="Move to brand new wallet, resetting all permissions">
80+ Reticket
81+ </Grid.Item>
82+ <Grid.Divider />
83+ <Grid.Item
84+ full
85+ as={ForwardButton}
86+ onClick={goEditPermissions}
87+ detail="Proxies, networking keys, etc.">
88+ Edit Permissions
89+ </Grid.Item>
90+ <Grid.Divider />
91+ </Grid>
9792 <FooterButton
9893 detail="Transfer this identity to a new owner"
9994 disabled={!canTransfer}
10095 onClick={goTransfer}>
10196 Transfer
10297 </FooterButton>
103− </Grid>
98+ </>
10499 );
105100}
src/views/Redownload.js → src/views/Admin/AdminRedownload.jsrenamed+1−1
@@ -12,7 +12,7 @@ import { downloadWallet } from 'lib/invite';
1212
1313import { useWallet } from 'store/wallet';
1414
15−export default function Redownload() {
15+export default function AdminRedownload() {
1616 const { urbitWallet } = useWallet();
1717 const { pointCursor } = usePointCursor();
1818 const point = need.point(pointCursor);
src/views/Reticket.js → src/views/Admin/AdminReticket.jsrenamed+5−5
@@ -15,10 +15,10 @@ import useRouter from 'lib/useRouter';
1515
1616import { useHistory } from 'store/history';
1717
18−import Confirm from './Reticket/Confirm';
19−import Download from './Reticket/Download';
20−import Verify from './Reticket/Verify';
21−import DoReticket from './Reticket/DoReticket';
18+import Confirm from '../Reticket/Confirm';
19+import Download from '../Reticket/Download';
20+import Verify from '../Reticket/Verify';
21+import DoReticket from '../Reticket/DoReticket';
2222
2323const NAMES = {
2424 CONFIRM: 'CONFIRM',
@@ -36,7 +36,7 @@ const VIEWS = {
3636
3737const STEP_MAX = size(NAMES);
3838
39−export default function Reticket() {
39+export default function AdminReticket() {
4040 const history = useHistory();
4141 const { Route, ...innerRouter } = useRouter({
4242 names: NAMES,