Change text of button for go to peer config (#1849)

* Change text of button for go to peer config

* Got basic saved peer detail component working

* Got toggle saved peer configs dialog working

* Show network, host, and port for saved peer detail component

* Update frontend build

* Improve styles for detail cards

* Update frontend build
This commit is contained in:
Jonathan Zernik 2021-12-14 03:10:11 -08:00 committed by GitHub
parent ecf3d8cecb
commit 2935130e79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 391 additions and 214 deletions

View file

@ -0,0 +1,102 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
FormControl,
FormLabel,
FormGroup,
FormControlLabel,
Switch,
} from '@material-ui/core';
// styles
import useStyles from './styles';
import {
setPeerAutoconnectRequest,
setPeerShareForFreeRequest,
} from '../../squeakclient/requests';
export default function ConfigurePeerDialog({
open,
handleClose,
savedPeer,
reloadPeer,
...props
}) {
const classes = useStyles();
const setAutoconnect = (id, autoconnect) => {
setPeerAutoconnectRequest(id, autoconnect, () => {
reloadPeer();
});
};
const setShareForFree = (id, shareForFree) => {
setPeerShareForFreeRequest(id, shareForFree, () => {
reloadPeer();
});
};
const handleSettingsAutoconnectChange = (event) => {
console.log(`Autoconnect changed for peer id: ${savedPeer.getPeerId()}`);
console.log(`Autoconnect changed to: ${event.target.checked}`);
setAutoconnect(savedPeer.getPeerId(), event.target.checked);
};
const handleSettingsShareForFreeChange = (event) => {
console.log(`ShareForFree changed for peer id: ${savedPeer.getPeerId()}`);
console.log(`ShareForFree changed to: ${event.target.checked}`);
setShareForFree(savedPeer.getPeerId(), event.target.checked);
};
function MakeCancelButton() {
return (
<Button
onClick={handleClose}
variant="contained"
color="secondary"
>
Cancel
</Button>
);
}
function PeerSettingsForm() {
return (
<FormControl component="fieldset">
<FormLabel component="legend">Peer settings</FormLabel>
<FormGroup>
<FormControlLabel
control={<Switch checked={savedPeer.getAutoconnect()} onChange={handleSettingsAutoconnectChange} />}
label="Autoconnect"
/>
</FormGroup>
<FormGroup>
<FormControlLabel
control={<Switch checked={savedPeer.getShareForFree()} onChange={handleSettingsShareForFreeChange} />}
label="Share for free"
/>
</FormGroup>
</FormControl>
);
}
return (
<Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Configure Peer</DialogTitle>
<form className={classes.root} noValidate autoComplete="off">
<DialogContent>
{savedPeer
&& PeerSettingsForm()}
</DialogContent>
<DialogActions>
{MakeCancelButton()}
</DialogActions>
</form>
</Dialog>
);
}

View file

@ -0,0 +1,6 @@
{
"name": "ConfigurePeerDialog",
"version": "0.0.0",
"private": true,
"main": "ConfigurePeerDialog.js"
}

View file

@ -0,0 +1,43 @@
import { makeStyles } from '@material-ui/styles';
export default makeStyles((theme) => ({
widgetWrapper: {
display: 'flex',
minHeight: '100%',
},
widgetHeader: {
padding: theme.spacing(3),
paddingBottom: theme.spacing(1),
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
},
widgetRoot: {
boxShadow: theme.customShadows.widget,
},
widgetBody: {
paddingBottom: theme.spacing(3),
paddingRight: theme.spacing(3),
paddingLeft: theme.spacing(3),
},
noPadding: {
padding: 0,
},
paper: {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
overflow: 'hidden',
},
moreButton: {
margin: -theme.spacing(1),
padding: 0,
width: 40,
height: 40,
color: theme.palette.text.hint,
'&:hover': {
backgroundColor: theme.palette.primary.main,
color: 'rgba(255, 255, 255, 0.35)',
},
},
}));

View file

@ -6,7 +6,6 @@ import {
DialogActions,
Button,
} from '@material-ui/core';
import { useHistory } from 'react-router-dom';
// styles
import useStyles from './styles';
@ -14,22 +13,20 @@ import useStyles from './styles';
import {
deletePeerRequest,
} from '../../squeakclient/requests';
import {
reloadRoute,
} from '../../navigation/navigation';
export default function DeletePeerDialog({
open,
handleClose,
peer,
reloadPeer,
...props
}) {
const classes = useStyles();
const history = useHistory();
const deletePeer = (peerId) => {
deletePeerRequest(peerId, (response) => {
reloadRoute(history);
reloadPeer();
});
};

View file

@ -0,0 +1,175 @@
import React, { useState } from 'react';
import {
IconButton,
Menu,
MenuItem,
Typography,
Button,
} from '@material-ui/core';
import { useHistory } from 'react-router-dom';
import Card from '@material-ui/core/Card';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import MoreVertIcon from '@material-ui/icons/MoreVert';
// styles
import useStyles from './styles';
import DeletePeerDialog from '../DeletePeerDialog';
import ConfigurePeerDialog from '../ConfigurePeerDialog';
import {
goToPeerAddressPage,
} from '../../navigation/navigation';
export default function SavedPeerDetailItem({
savedPeer,
handleReloadPeer,
...props
}) {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState(null);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [configureDialogOpen, setConfigureDialogOpen] = useState(false);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const history = useHistory();
const onViewPeerConnectionClick = () => {
console.log('Handling view peer connection click...');
handleClose();
if (!savedPeer) {
return;
}
goToPeerAddressPage(
history,
savedPeer.getPeerAddress().getNetwork(),
savedPeer.getPeerAddress().getHost(),
savedPeer.getPeerAddress().getPort(),
);
};
const onConfigureClick = () => {
console.log('Handling configure click...');
handleClose();
if (!savedPeer) {
return;
}
setConfigureDialogOpen(true);
};
const onDeleteClick = () => {
console.log('Handling delete click...');
handleClose();
if (!savedPeer) {
return;
}
setDeleteDialogOpen(true);
};
const handleCloseDeleteDialog = () => {
setDeleteDialogOpen(false);
};
const handleCloseConfigureDialog = () => {
setConfigureDialogOpen(false);
};
function DeletePeerDialogContent() {
return (
<>
<DeletePeerDialog
open={deleteDialogOpen}
handleClose={handleCloseDeleteDialog}
peer={savedPeer}
reloadPeer={handleReloadPeer}
/>
</>
);
}
function ConfigurePeerDialogContent() {
return (
<>
<ConfigurePeerDialog
open={configureDialogOpen}
handleClose={handleCloseConfigureDialog}
savedPeer={savedPeer}
reloadPeer={handleReloadPeer}
/>
</>
);
}
return (
<>
<Card className={classes.root}>
<CardHeader
action={(
<>
<IconButton aria-label="settings" onClick={handleClick}>
<MoreVertIcon />
</IconButton>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={onConfigureClick}>Configure</MenuItem>
<MenuItem onClick={onDeleteClick}>Delete</MenuItem>
</Menu>
</>
)}
title={savedPeer.getPeerName()}
/>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
Network: {savedPeer.getPeerAddress().getNetwork()}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Host: {savedPeer.getPeerAddress().getHost()}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Port: {savedPeer.getPeerAddress().getPort()}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Autoconnect: {savedPeer.getAutoconnect().toString()}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Share for free: {savedPeer.getShareForFree().toString()}
</Typography>
</CardContent>
<CardActions>
<Button
onClick={() => {
onViewPeerConnectionClick();
}}
size="small"
color="primary"
>
View Peer Connection
</Button>
</CardActions>
</Card>
{DeletePeerDialogContent()}
{ConfigurePeerDialogContent()}
</>
);
}

View file

@ -0,0 +1,6 @@
{
"name": "SavedPeerDetailItem",
"version": "0.0.0",
"private": true,
"main": "SavedPeerDetailItem.js"
}

View file

@ -0,0 +1,7 @@
import { makeStyles } from '@material-ui/styles';
export default makeStyles((theme) => ({
root: {
maxWidth: 400,
},
}));

View file

@ -1,49 +1,10 @@
import { makeStyles } from '@material-ui/styles';
export default makeStyles((theme) => ({
widgetWrapper: {
display: 'flex',
minHeight: '100%',
},
widgetHeader: {
padding: theme.spacing(3),
paddingBottom: theme.spacing(1),
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
},
widgetRoot: {
boxShadow: theme.customShadows.widget,
},
widgetBody: {
paddingBottom: theme.spacing(3),
paddingRight: theme.spacing(3),
paddingLeft: theme.spacing(3),
},
noPadding: {
padding: 0,
},
paper: {
padding: '6px 12px',
},
secondaryTail: {
backgroundColor: theme.palette.secondary.main,
},
moreButton: {
margin: -theme.spacing(1),
padding: 0,
width: 40,
height: 40,
color: theme.palette.text.hint,
'&:hover': {
backgroundColor: theme.palette.primary.main,
color: 'rgba(255, 255, 255, 0.35)',
},
},
root: {
maxWidth: 345,
maxWidth: 400,
},
media: {
height: 180,
height: 280,
},
}));

View file

@ -1,188 +1,73 @@
import React, { useState, useEffect } from 'react';
import { useParams, useHistory } from 'react-router-dom';
import React, { useState, useEffect, useCallback } from 'react';
import { useParams } from 'react-router-dom';
import {
Grid,
FormLabel,
FormControl,
FormGroup,
FormControlLabel,
Switch,
Button,
CircularProgress,
CardHeader,
Card,
} from '@material-ui/core';
// styles
import useStyles from './styles';
// components
import DeletePeerDialog from '../../components/DeletePeerDialog';
import SavedPeerDetailItem from '../../components/SavedPeerDetailItem';
import {
getPeerRequest,
setPeerAutoconnectRequest,
setPeerShareForFreeRequest,
} from '../../squeakclient/requests';
import {
goToPeerAddressPage,
} from '../../navigation/navigation';
export default function PeerPage() {
const classes = useStyles();
const history = useHistory();
const { id } = useParams();
const [peerResp, setPeerResp] = useState(null);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const getSqueakPeer = (id) => {
const handleGetSqueakPeerErr = (err) => {
setPeerResp(null);
};
const getSqueakPeer = useCallback(() => {
getPeerRequest(id, (resp => {
setPeerResp(resp);
}));
};
const setAutoconnect = (id, autoconnect) => {
setPeerAutoconnectRequest(id, autoconnect, () => {
getSqueakPeer(id);
});
};
const setShareForFree = (id, shareForFree) => {
setPeerShareForFreeRequest(id, shareForFree, () => {
getSqueakPeer(id);
});
};
}), handleGetSqueakPeerErr);
},
[id]);
useEffect(() => {
getSqueakPeer(id);
}, [id]);
}, [getSqueakPeer, id]);
const handleClickOpenDeleteDialog = () => {
setDeleteDialogOpen(true);
console.log(`deleteDialogOpen: ${deleteDialogOpen}`);
const handleReloadPeer = () => {
getSqueakPeer(id);
};
const handleCloseDeleteDialog = () => {
setDeleteDialogOpen(false);
};
const handleSettingsAutoconnectChange = (event) => {
console.log(`Autoconnect changed for peer id: ${id}`);
console.log(`Autoconnect changed to: ${event.target.checked}`);
setAutoconnect(id, event.target.checked);
};
const handleSettingsShareForFreeChange = (event) => {
console.log(`share_for_free changed for peer id: ${id}`);
console.log(`share_for_free changed to: ${event.target.checked}`);
setShareForFree(id, event.target.checked);
};
const peerAddressToStr = (peerAddress) => `${peerAddress.getHost()}:${peerAddress.getPort()}`;
function PeerContent() {
return (
<>
{peerResp.getSqueakPeer()
? PeerDisplay()
: NoPeerDisplay()}
? SqueakPeerDisplay()
: NoSqueakPeerDisplay()}
</>
);
}
function NoPeerDisplay() {
function SqueakPeerDisplay() {
return (
<p>
No peer loaded
</p>
<SavedPeerDetailItem
savedPeer={peerResp.getSqueakPeer()}
handleReloadPeer={handleReloadPeer}
/>
);
}
function PeerDisplay() {
function NoSqueakPeerDisplay() {
return (
<>
<p>
Peer name:
{' '}
{peerResp.getSqueakPeer().getPeerName()}
</p>
<p>
{PeerAddressContent()}
</p>
{PeerSettingsForm()}
{DeletePeerButton()}
</>
);
}
function PeerSettingsForm() {
return (
<FormControl component="fieldset">
<FormLabel component="legend">Peer settings</FormLabel>
<FormGroup>
<FormControlLabel
control={<Switch checked={peerResp.getSqueakPeer().getAutoconnect()} onChange={handleSettingsAutoconnectChange} />}
label="Autoconnect"
/>
<FormControlLabel
control={<Switch checked={peerResp.getSqueakPeer().getShareForFree()} onChange={handleSettingsShareForFreeChange} />}
label="Share For Free"
/>
</FormGroup>
</FormControl>
);
}
function DeletePeerButton() {
return (
<>
<Grid item xs={12}>
<div className={classes.root}>
<Button
variant="contained"
onClick={() => {
handleClickOpenDeleteDialog();
}}
>
Delete Peer
</Button>
</div>
</Grid>
</>
);
}
function DeletePeerDialogContent() {
return (
<>
<DeletePeerDialog
open={deleteDialogOpen}
handleClose={handleCloseDeleteDialog}
peer={peerResp.getSqueakPeer()}
<Card
className={classes.root}
>
<CardHeader
subheader="Peer not found."
/>
</>
);
}
function PeerAddressContent() {
const peer = peerResp.getSqueakPeer();
console.log(peer.getPeerAddress());
console.log(peer.getPeerAddress().getNetwork());
const peerAddressStr = peerAddressToStr(peer.getPeerAddress());
return (
<>
<div className={classes.root}>
<Button
variant="contained"
onClick={() => {
goToPeerAddressPage(
history,
peer.getPeerAddress().getNetwork(),
peer.getPeerAddress().getHost(),
peer.getPeerAddress().getPort(),
);
}}
>
{peerAddressStr}
</Button>
</div>
</>
</Card>
);
}
@ -195,12 +80,7 @@ export default function PeerPage() {
return (
<>
{peerResp
? (
<>
{PeerContent()}
{DeletePeerDialogContent()}
</>
)
? PeerContent()
: WaitingIndicator()}
</>
);

View file

@ -276,7 +276,7 @@ export default function PeerAddressPage() {
goToPeerPage(history, savedPeer.getPeerId());
}}
>
{savedPeer.getPeerName()}
Go to peer config
</Button>
</Box>
);

View file

@ -1,15 +1,15 @@
{
"files": {
"main.js": "/static/js/main.e728df59.chunk.js",
"main.js.map": "/static/js/main.e728df59.chunk.js.map",
"main.js": "/static/js/main.e618d54f.chunk.js",
"main.js.map": "/static/js/main.e618d54f.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.48a1d1b9.js",
"runtime-main.js.map": "/static/js/runtime-main.48a1d1b9.js.map",
"static/css/2.f68b60d4.chunk.css": "/static/css/2.f68b60d4.chunk.css",
"static/js/2.92034823.chunk.js": "/static/js/2.92034823.chunk.js",
"static/js/2.92034823.chunk.js.map": "/static/js/2.92034823.chunk.js.map",
"static/js/2.ae99ecce.chunk.js": "/static/js/2.ae99ecce.chunk.js",
"static/js/2.ae99ecce.chunk.js.map": "/static/js/2.ae99ecce.chunk.js.map",
"index.html": "/index.html",
"static/css/2.f68b60d4.chunk.css.map": "/static/css/2.f68b60d4.chunk.css.map",
"static/js/2.92034823.chunk.js.LICENSE.txt": "/static/js/2.92034823.chunk.js.LICENSE.txt",
"static/js/2.ae99ecce.chunk.js.LICENSE.txt": "/static/js/2.ae99ecce.chunk.js.LICENSE.txt",
"static/media/font-awesome.min.css": "/static/media/fontawesome-webfont.f691f37e.woff",
"static/media/google.a4fa9b6f.svg": "/static/media/google.a4fa9b6f.svg",
"static/media/logo.31df0ce8.svg": "/static/media/logo.31df0ce8.svg"
@ -17,7 +17,7 @@
"entrypoints": [
"static/js/runtime-main.48a1d1b9.js",
"static/css/2.f68b60d4.chunk.css",
"static/js/2.92034823.chunk.js",
"static/js/main.e728df59.chunk.js"
"static/js/2.ae99ecce.chunk.js",
"static/js/main.e618d54f.chunk.js"
]
}

View file

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Squeaknode</title><meta name="description" content="Squeaknode is a frontend for accessing a squeak node"><meta name="keywords" content="squeak, bitcoin, lightning"><meta name="author" content="Flatlogic LLC."><link href="/static/css/2.f68b60d4.chunk.css" rel="stylesheet"></head><body style="font-family:Roboto,sans-serif"><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,f,l=r[0],a=r[1],i=r[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var a=t[l];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var l=this["webpackJsonpsqueak-node-frontend"]=this["webpackJsonpsqueak-node-frontend"]||[],a=l.push.bind(l);l.push=r,l=l.slice();for(var i=0;i<l.length;i++)r(l[i]);var p=a;t()}([])</script><script src="/static/js/2.92034823.chunk.js"></script><script src="/static/js/main.e728df59.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Squeaknode</title><meta name="description" content="Squeaknode is a frontend for accessing a squeak node"><meta name="keywords" content="squeak, bitcoin, lightning"><meta name="author" content="Flatlogic LLC."><link href="/static/css/2.f68b60d4.chunk.css" rel="stylesheet"></head><body style="font-family:Roboto,sans-serif"><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,f,l=r[0],a=r[1],i=r[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var a=t[l];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var l=this["webpackJsonpsqueak-node-frontend"]=this["webpackJsonpsqueak-node-frontend"]||[],a=l.push.bind(l);l.push=r,l=l.slice();for(var i=0;i<l.length;i++)r(l[i]);var p=a;t()}([])</script><script src="/static/js/2.ae99ecce.chunk.js"></script><script src="/static/js/main.e618d54f.chunk.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long