notistack#useSnackbar JavaScript Examples
The following examples show how to use
notistack#useSnackbar.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: DepositModal.js From akashlytics-deploy with GNU General Public License v3.0 | 6 votes |
DepositModal = ({ address, onClose }) => {
const classes = useStyles();
const { enqueueSnackbar } = useSnackbar();
const onQRClick = () => {
copyTextToClipboard(address);
enqueueSnackbar(<Snackbar title="Address copied to clipboard!" iconVariant="success" />, {
variant: "success",
autoHideDuration: 2000
});
};
return (
<Dialog maxWidth="xs" aria-labelledby="deposit-dialog-title" open={true} onClose={onClose}>
<DialogTitle id="deposit-dialog-title">Deposit</DialogTitle>
<DialogContent dividers className={classes.dialogContent}>
<Box fontSize="1rem">
<Address address={address} isCopyable />
</Box>
<Button onClick={onQRClick}>
<QRCode value={address} />
</Button>
</DialogContent>
<DialogActions>
<Button autoFocus variant="contained" onClick={onClose} color="primary">
Close
</Button>
</DialogActions>
</Dialog>
);
}
Example #2
Source File: notifications.js From spl-token-wallet with Apache License 2.0 | 6 votes |
export function useCallAsync() {
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
return async function callAsync(
promise,
{
progressMessage = 'Submitting...',
successMessage = 'Success',
onSuccess,
onError,
} = {},
) {
let id = enqueueSnackbar(progressMessage, {
variant: 'info',
persist: true,
});
try {
let result = await promise;
closeSnackbar(id);
if (successMessage) {
enqueueSnackbar(successMessage, { variant: 'success' });
}
if (onSuccess) {
onSuccess(result);
}
} catch (e) {
console.warn(e);
closeSnackbar(id);
enqueueSnackbar(e.message, { variant: 'error' });
if (onError) {
onError(e);
}
}
};
}
Example #3
Source File: StackedSnackbar.jsx From matx-react with MIT License | 6 votes |
function StackedSnackbar() {
const { enqueueSnackbar } = useSnackbar();
const handleClick = () => enqueueSnackbar("I love snacks.");
const handleClickVariant = (variant) => () => {
// variant could be success, error, warning, info, or default
enqueueSnackbar("This is a warning message!", { variant });
};
return (
<React.Fragment>
<Button onClick={handleClick}>Show snackbar</Button>
<Button onClick={handleClickVariant("warning")}>Show warning snackbar</Button>
</React.Fragment>
);
}
Example #4
Source File: AsyncTaskProvider.js From akashlytics-deploy with GNU General Public License v3.0 | 6 votes |
AsyncTaskProvider = ({ children }) => {
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
const launchAsyncTask = async (fn, cancel, message) => {
const onCancel = () => {
closeSnackbar(key);
try {
cancel();
} catch (error) {
// console.log(error);
}
};
const key = enqueueSnackbar(
<Snackbar
title={message}
subTitle={
<Button onClick={onCancel} variant="contained" color="primary" size="small">
Cancel
</Button>
}
showLoading
/>,
{ variant: "info", persist: true, action: (key) => null }
);
try {
await fn();
} catch (error) {
console.log(error);
} finally {
closeSnackbar(key);
}
};
return <AsyncTaskProviderContext.Provider value={{ launchAsyncTask }}>{children}</AsyncTaskProviderContext.Provider>;
}
Example #5
Source File: notifications.js From spl-token-wallet with Apache License 2.0 | 5 votes |
export function useSendTransaction() {
const connection = useConnection();
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
const [sending, setSending] = useState(false);
async function sendTransaction(
signaturePromise,
{ onSuccess, onError } = {},
) {
let id = enqueueSnackbar('Sending transaction...', {
variant: 'info',
persist: true,
});
setSending(true);
try {
let signature = await signaturePromise;
closeSnackbar(id);
id = enqueueSnackbar('Confirming transaction...', {
variant: 'info',
persist: true,
action: <ViewTransactionOnExplorerButton signature={signature} />,
});
await confirmTransaction(connection, signature);
closeSnackbar(id);
setSending(false);
enqueueSnackbar('Transaction confirmed', {
variant: 'success',
autoHideDuration: 15000,
action: <ViewTransactionOnExplorerButton signature={signature} />,
});
if (onSuccess) {
onSuccess(signature);
}
} catch (e) {
closeSnackbar(id);
setSending(false);
console.warn(e);
enqueueSnackbar(e.message, { variant: 'error' });
if (onError) {
onError(e);
}
}
}
return [sendTransaction, sending];
}
Example #6
Source File: user-team.js From nextjs-todo-list with MIT License | 5 votes |
UserTeam = ({ team }) => {
const classes = useStyles();
const { enqueueSnackbar } = useSnackbar();
const clipboard = useClipboard();
const handleCopyTeamCode = useCallback(() => {
clipboard.copy(`${team.code}`);
enqueueSnackbar('The team code has been copied');
}, [clipboard.copy, team.code]);
const renderTeamCode = () => (
<div className={classes.codeContainer}>
<Tooltip title="Share this code to add new members">
<IconButton aria-label="Share this code to add new members" onClick={handleCopyTeamCode}>
<FileCopyOutlined />
</IconButton>
</Tooltip>
<Typography variant="h6" color="textSecondary" component="h2">
Code:
{team.code}
</Typography>
</div>
);
return (
<Card className={classes.root}>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{team.name}
</Typography>
{renderTeamCode()}
{team.members && team.members.length > 0 ? (
<TeamList author={team.author} members={team.members} />
) : (
<p>You are the only member</p>
)}
</CardContent>
</Card>
);
}
Example #7
Source File: posts.jsx From react-redux-jsonplaceholder with MIT License | 5 votes |
PostContainer = ({
fetchPostsStart,
deletePostStart,
posts,
clearPostMessages,
errorMessage,
isFetching,
}) => {
const { enqueueSnackbar } = useSnackbar();
const [page, setPage] = useState(1);
const [minimum, setMinimum] = useState(0);
const [maximum, setMaximum] = useState(10);
const [pagePosts, setPagePosts] = useState([]);
const classes = useStyles();
const count = Math.ceil(posts.length / 10);
useEffect(() => {
if (posts.length < 1) fetchPostsStart();
}, [fetchPostsStart, posts]);
useEffect(() => {
if (errorMessage) {
enqueueSnackbar(errorMessage, { variant: "error" });
clearPostMessages();
}
}, [errorMessage, clearPostMessages, enqueueSnackbar]);
useEffect(() => {
setPagePosts(posts.slice(minimum, maximum));
}, [page, isFetching, posts, minimum, maximum]);
const handleChange = (event, value) => {
setPage(value);
setMinimum((value - 1) * 10);
setMaximum(value * 10);
};
return (
<Box className={classes.root}>
<Typography variant={"h2"} component={"h1"}>
Posts <strong className={classes.length}> [{posts.length}]</strong>
</Typography>
<AddItemModal />
<Grid container justify={"center"} alignItems={"center"} spacing={4}>
{pagePosts.length > 1 ? (
pagePosts.map((each) => (
<Grid item xs={10} sm={5} md={3} key={each.id}>
<Paper className={classes.card} elevation={10}>
id: {each.id} UserId: {each.userId}
<DeleteForeverRounded
color={"primary"}
className={classes.delete}
onClick={() => deletePostStart(each.id)}
/>
<Typography>Title: {each.title}</Typography>
<Typography>Body: {each.body}</Typography>
<Box>
<TransitionsModal key={each.id} post={each} />
</Box>
</Paper>
</Grid>
))
) : (
<SkeletonComponent />
)}
</Grid>
<Pagination
count={count}
page={page}
onChange={handleChange}
className={classes.pagination}
color="primary"
variant="outlined"
size="small"
/>
</Box>
);
}
Example #8
Source File: InspectClients.js From management-center with Apache License 2.0 | 5 votes |
Clients = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client: brokerClient } = context;
const { inspectFeature, userProfile, roles = [], clients = [], onSort, sortBy, sortDirection } = props;
const onUpdateUserRoles = async (user, roles = []) => {
if (!roles) {
roles = [];
}
const rolenames = roles.map((role) => role.value);
await brokerClient.updateUserRoles(user, rolenames);
const clients = await brokerClient.inspectListClients();
dispatch(updateInspectClients(clients));
};
const onSelectClient = async (username) => {
const client = await brokerClient.inspectGetClient(username);
dispatch(updateInspectClient(client));
history.push(`/admin/inspect/clients/detail/${username}`);
};
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} color="inherit" to="/admin">
Admin
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Inspect
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{inspectFeature?.error ? <><br/><Alert severity="warning">
<AlertTitle>{inspectFeature.error.title}</AlertTitle>
{inspectFeature.error.message}
</Alert></> : null}
{!inspectFeature?.error && inspectFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Feature not available</AlertTitle>
Make sure that this feature is included in your MMC license.
</Alert></> : null}
<br />
<br />
{ createClientsTable(clients, classes, props, onUpdateUserRoles, onSelectClient) }
</div>
);
}
Example #9
Source File: inner.js From chromeless with Mozilla Public License 2.0 | 5 votes |
SnackbarTriggerInner = () => {
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
useEffect(() => {
window.ipcRenderer.removeAllListeners('enqueue-snackbar');
window.ipcRenderer.on('enqueue-snackbar', (_, message, variant) => {
enqueueSnackbar(message, { variant, autoHideDuration: 10000 });
});
return () => {
window.ipcRenderer.removeAllListeners('enqueue-snackbar');
};
}, [enqueueSnackbar]);
const showRequestRestartSnackbar = useCallback(() => {
enqueueSnackbar('You need to restart the app for the changes to take effect.', {
variant: 'default',
preventDuplicate: true,
persist: true,
action: (key) => (
<>
<Button color="inherit" onClick={() => requestRestart()}>
Restart Now
</Button>
<Button color="inherit" onClick={() => closeSnackbar(key)}>
Later
</Button>
</>
),
});
}, [enqueueSnackbar, closeSnackbar]);
useEffect(() => {
window.ipcRenderer.removeAllListeners('enqueue-request-restart-snackbar');
window.ipcRenderer.on('enqueue-request-restart-snackbar', showRequestRestartSnackbar);
return () => {
window.ipcRenderer.removeAllListeners('enqueue-request-restart-snackbar');
};
}, [showRequestRestartSnackbar]);
return null;
}
Example #10
Source File: inner.js From neutron with Mozilla Public License 2.0 | 5 votes |
SnackbarTriggerInner = () => {
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
useEffect(() => {
ipcRenderer.removeAllListeners('enqueue-snackbar');
ipcRenderer.on('enqueue-snackbar', (_, message, variant) => {
enqueueSnackbar(message, { variant, autoHideDuration: 10000 });
});
return () => {
ipcRenderer.removeAllListeners('enqueue-snackbar');
};
}, [enqueueSnackbar]);
const showRequestRestartSnackbar = useCallback(() => {
enqueueSnackbar('You need to restart the app for the changes to take effect.', {
variant: 'default',
preventDuplicate: true,
persist: true,
action: (key) => (
<>
<Button color="inherit" onClick={() => requestRestart()}>
Restart Now
</Button>
<Button color="inherit" onClick={() => closeSnackbar(key)}>
Later
</Button>
</>
),
});
}, [enqueueSnackbar, closeSnackbar]);
useEffect(() => {
ipcRenderer.removeAllListeners('enqueue-request-restart-snackbar');
ipcRenderer.on('enqueue-request-restart-snackbar', showRequestRestartSnackbar);
return () => {
ipcRenderer.removeAllListeners('enqueue-request-restart-snackbar');
};
}, [showRequestRestartSnackbar]);
return null;
}
Example #11
Source File: DeploymentNameModal.js From akashlytics-deploy with GNU General Public License v3.0 | 5 votes |
DeploymentNameModal = ({ dseq, onClose, onSaved, getDeploymentName }) => {
const classes = useStyles();
const formRef = useRef();
const { enqueueSnackbar } = useSnackbar();
const { handleSubmit, control, setValue } = useForm({
defaultValues: {
name: ""
}
});
useEffect(() => {
if (dseq) {
const name = getDeploymentName(dseq);
setValue("name", name || "");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dseq, getDeploymentName]);
const onSaveClick = (event) => {
event.preventDefault();
formRef.current.dispatchEvent(new Event("submit", { cancelable: true, bubbles: true }));
};
function onSubmit({ name }) {
updateDeploymentLocalData(dseq, { name: name });
enqueueSnackbar(<Snackbar title="Success!" iconVariant="success" />, { variant: "success", autoHideDuration: 1000 });
onSaved();
}
return (
<Dialog open={!!dseq} onClose={onClose} maxWidth="xs" fullWidth>
<DialogTitle>Change Deployment Name {dseq ? `(${dseq})` : ""}</DialogTitle>
<DialogContent dividers className={classes.dialogContent}>
<form onSubmit={handleSubmit(onSubmit)} ref={formRef}>
<FormControl fullWidth>
<Controller
control={control}
name="name"
render={({ field }) => {
return <TextField {...field} autoFocus type="text" variant="outlined" label="Name" />;
}}
/>
</FormControl>
</form>
</DialogContent>
<DialogActions className={classes.dialogActions}>
<Button onClick={onClose}>Close</Button>
<Button variant="contained" color="primary" onClick={onSaveClick}>
Save
</Button>
</DialogActions>
</Dialog>
);
}
Example #12
Source File: Roles.js From management-center with Apache License 2.0 | 4 votes |
Roles = (props) => {
const classes = useStyles();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { enqueueSnackbar } = useSnackbar();
const { client } = context;
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(10);
const handleChangePage = async (event, newPage) => {
setPage(newPage);
const count = rowsPerPage;
const offset = newPage * rowsPerPage;
const roles = await client.listRoles(true, count, offset);
dispatch(updateRoles(roles));
};
const handleChangeRowsPerPage = async (event) => {
const rowsPerPage = parseInt(event.target.value, 10);
setRowsPerPage(rowsPerPage);
setPage(0);
const roles = await client.listRoles(true, rowsPerPage, 0);
dispatch(updateRoles(roles));
};
const onEditDefaultACLAccess = () => {
history.push('/security/acl');
}
const onNewRole = () => {
history.push('/security/roles/new');
};
const onDeleteRole = async (rolename) => {
await confirm({
title: 'Confirm role deletion',
description: `Do you really want to delete the role "${rolename}"?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
if (rolename === 'admin') {
await confirm({
title: 'Confirm default role deletion',
description: `Are you sure? You are about to delete the default role for the current Mosquitto instance.`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
}
await client.deleteRole(rolename);
enqueueSnackbar('Role successfully deleted', {
variant: 'success'
});
const roles = await client.listRoles(true, rowsPerPage, page * rowsPerPage);
dispatch(updateRoles(roles));
const clients = await client.listClients();
dispatch(updateClients(clients));
const groups = await client.listGroups();
dispatch(updateGroups(groups));
};
const onSelectRole = async (rolename) => {
const role = await client.getRole(rolename);
dispatch(updateRole(role));
history.push(`/security/roles/detail/${rolename}`);
};
const { dynamicsecurityFeature, defaultACLAccess, roles = [], onSort, sortBy, sortDirection } = props;
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/security">
Security
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Roles
</Typography>
</Breadcrumbs>
{/* TODO: Quick hack to detect whether feature is supported */}
{dynamicsecurityFeature?.supported === false ? <><br/><Alert severity="warning">
<AlertTitle>Feature not available</AlertTitle>
Make sure that the broker connected has the dynamic security enabled.
</Alert></> : null}
<br />
{dynamicsecurityFeature?.supported !== false && <><Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<AddIcon />}
onClick={(event) => {
event.stopPropagation();
onNewRole();
}}
>
New Role
</Button>
<Button
variant="outlined"
color="default"
size="small"
className={classes.button}
startIcon={<EditIcon />}
onClick={onEditDefaultACLAccess}
>
Edit default ACL access
</Button>
<br />
<br />
</>}
{dynamicsecurityFeature?.supported !== false && roles?.roles?.length > 0 ? (
<div>
<Hidden xsDown implementation="css">
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
{ROLE_TABLE_COLUMNS.map((column) => (
<TableCell
key={column.id}
sortDirection={sortBy === column.id ? sortDirection : false}
>
<TableSortLabel
active={sortBy === column.id}
direction={sortDirection}
onClick={() => onSort(column.id)}
>
{column.key}
</TableSortLabel>
</TableCell>
))}
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{roles.roles.map((role) => (
<TableRow
hover
key={role.rolename}
onClick={() => onSelectRole(role.rolename)}
style={{ cursor: 'pointer' }}
>
<TableCell>{role.rolename}</TableCell>
<TableCell>{role.textname}</TableCell>
<TableCell>{role.textdescription}</TableCell>
<TableCell align="right">
{/* <IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteRole(role.rolename);
}}
>
<EditIcon fontSize="small" />
</IconButton> */}
<Tooltip title="Delete role">
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
onDeleteRole(role.rolename);
}}
>
<DeleteIcon fontSize="small" />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={8}
count={roles?.totalCount}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
</Hidden>
<Hidden smUp implementation="css">
<Paper>
<List className={classes.root}>
{roles.roles.map((role) => (
<React.Fragment>
<ListItem alignItems="flex-start">
<ListItemText
primary={<span>{role.rolename}</span>}
// secondary={
// <React.Fragment>
// <Typography
// component="span"
// variant="body2"
// className={classes.inline}
// color="textPrimary"
// >
// Role details
// </Typography>
// </React.Fragment>
// }
/>
<ListItemSecondaryAction>
<IconButton edge="end" size="small" aria-label="edit">
<EditIcon fontSize="small" />
</IconButton>
<IconButton edge="end" size="small" aria-label="delete">
<DeleteIcon fontSize="small" />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</React.Fragment>
))}
</List>
</Paper>
</Hidden>
</div>
) : (
<div>No roles found</div>
)}
{/* <Fab
color="primary"
aria-label="add"
className={classes.fab}
onClick={(event) => {
event.stopPropagation();
onNewRole();
}}
>
<AddIcon />
</Fab> */}
</div>
);
}
Example #13
Source File: screen.jsx From react-redux-jsonplaceholder with MIT License | 4 votes |
ScreenContainer = (
Component,
fetchStart,
deleteStart,
data,
isFetching,
errorMessage
) => {
const { enqueueSnackbar } = useSnackbar();
const [page, setPage] = useState(1);
const [minimum, setMinimum] = useState(0);
const [maximum, setMaximum] = useState(10);
const [pageData, setPageData] = useState([]);
const classes = useStyles();
const count = Math.ceil(data.length / 10);
useEffect(() => {
if (data.length < 1) fetchCommentsStart();
}, [fetchStart, data]);
useEffect(() => {
if (errorMessage) {
enqueueSnackbar(errorMessage, { variant: "error" });
}
}, [errorMessage, enqueueSnackbar]);
useEffect(() => {
setPageData(data.slice(minimum, maximum));
}, [page, isFetching, data, minimum, maximum]);
const handleChange = (event, value) => {
setPage(value);
setMinimum((value - 1) * 10);
setMaximum(value * 10);
};
return (
<Box className={classes.root}>
<Typography variant={"h2"} component={"h1"}>
Comments
<strong className={classes.length}> [{data.length}]</strong>
</Typography>
<AddItemModal />
<Component page={page} delete={deleteStart} />
<Grid container justify={"center"} alignItems={"center"} spacing={4}>
{pageData.length > 1 ? (
pageData.map((each) => (
<Grid item xs={10} sm={5} md={3} key={each.id}>
<Paper className={classes.card} elevation={10}>
{each.id}
<DeleteForeverRounded
color={"primary"}
className={classes.delete}
onClick={() => deleteStart(each.id)}
/>
<Typography>
{each.name} ({each.email})
</Typography>
<Typography>Comment: {each.body}</Typography>
<Box>
<TransitionsModal key={each.id} comment={each} />
</Box>
</Paper>
</Grid>
))
) : (
<SkeletonComponent />
)}
</Grid>
<Pagination
count={count}
page={page}
onChange={handleChange}
className={classes.pagination}
color="primary"
variant="outlined"
size="small"
/>
</Box>
);
}
Example #14
Source File: LeaseRow.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
LeaseRow = React.forwardRef(({ lease, setActiveTab, deploymentManifest, dseq, providers, loadDeploymentDetail }, ref) => {
const { enqueueSnackbar } = useSnackbar();
const providerInfo = providers?.find((p) => p.owner === lease?.provider);
const { localCert } = useCertificate();
const isLeaseActive = lease.state === "active";
const [isServicesAvailable, setIsServicesAvailable] = useState(false);
const { favoriteProviders, updateFavoriteProviders } = useLocalNotes();
const [isViewingProviderDetail, setIsViewingProviderDetail] = useState(false);
const isFavorite = favoriteProviders.some((x) => lease?.provider === x);
const {
data: leaseStatus,
error,
refetch: getLeaseStatus,
isLoading: isLoadingLeaseStatus
} = useLeaseStatus(providerInfo?.host_uri, lease, {
enabled: isLeaseActive && !isServicesAvailable && !!providerInfo?.host_uri && !!localCert,
refetchInterval: 10_000,
onSuccess: (leaseStatus) => {
if (leaseStatus) {
checkIfServicesAreAvailable(leaseStatus);
}
}
});
const {
data: providerStatus,
isLoading: isLoadingProviderStatus,
refetch: getProviderStatus
} = useProviderStatus(providerInfo?.host_uri, {
enabled: false,
retry: false
});
const isLeaseNotFound = error && error.includes && error.includes("lease not found") && isLeaseActive;
const servicesNames = leaseStatus ? Object.keys(leaseStatus.services) : [];
const classes = useStyles();
const [isSendingManifest, setIsSendingManifest] = useState(false);
React.useImperativeHandle(ref, () => ({
getLeaseStatus: loadLeaseStatus
}));
const loadLeaseStatus = useCallback(() => {
if (isLeaseActive && providerInfo && localCert) {
getLeaseStatus();
getProviderStatus();
}
}, [isLeaseActive, providerInfo, localCert, getLeaseStatus, getProviderStatus]);
const checkIfServicesAreAvailable = (leaseStatus) => {
const servicesNames = leaseStatus ? Object.keys(leaseStatus.services) : [];
const isServicesAvailable =
servicesNames.length > 0
? servicesNames
.map((n) => leaseStatus.services[n])
.every((service, i) => {
return service.available > 0;
})
: false;
setIsServicesAvailable(isServicesAvailable);
};
useEffect(() => {
loadLeaseStatus();
}, [lease, providerInfo, localCert, loadLeaseStatus]);
function handleExternalUrlClick(ev, externalUrl) {
ev.preventDefault();
window.electron.openUrl("http://" + externalUrl);
}
function handleEditManifestClick(ev) {
ev.preventDefault();
setActiveTab("EDIT");
}
async function sendManifest() {
setIsSendingManifest(true);
try {
const doc = yaml.load(deploymentManifest);
const manifest = deploymentData.Manifest(doc);
await sendManifestToProvider(providerInfo, manifest, dseq, localCert);
enqueueSnackbar(<Snackbar title="Manifest sent!" iconVariant="success" />, { variant: "success", autoHideDuration: 10_000 });
loadDeploymentDetail();
} catch (err) {
enqueueSnackbar(<ManifestErrorSnackbar err={err} iconVariant="error" />, { variant: "error", autoHideDuration: null });
}
setIsSendingManifest(false);
}
const onStarClick = (event) => {
event.preventDefault();
event.stopPropagation();
const newFavorites = isFavorite ? favoriteProviders.filter((x) => x !== lease.provider) : favoriteProviders.concat([lease.provider]);
updateFavoriteProviders(newFavorites);
};
return (
<>
{isViewingProviderDetail && (
<ProviderDetailModal provider={{ ...providerStatus, ...providerInfo }} onClose={() => setIsViewingProviderDetail(false)} address={lease.provider} />
)}
<Card className={classes.root} elevation={4}>
<CardHeader
classes={{ title: classes.cardHeaderTitle, root: classes.cardHeader }}
title={
<Box display="flex">
<LabelValue
label="Status:"
value={
<>
<div>{lease.state}</div>
<StatusPill state={lease.state} size="small" />
</>
}
/>
<LabelValue label="GSEQ:" value={lease.gseq} marginLeft="1rem" fontSize="1rem" />
<LabelValue label="OSEQ:" value={lease.oseq} marginLeft="1rem" fontSize="1rem" />
{isLeaseActive && (
<Box marginLeft="1rem" display="inline-flex">
<LinkTo onClick={() => setActiveTab("LOGS")}>View logs</LinkTo>
</Box>
)}
</Box>
}
/>
<CardContent>
<Box display="flex">
<Box>
<Box paddingBottom="1rem">
<SpecDetail
cpuAmount={lease.cpuAmount}
memoryAmount={lease.memoryAmount}
storageAmount={lease.storageAmount}
color={isLeaseActive ? "primary" : "default"}
/>
</Box>
<LabelValue
label="Price:"
value={
<>
<PricePerMonth perBlockValue={uaktToAKT(lease.price.amount, 6)} />
<PriceEstimateTooltip value={uaktToAKT(lease.price.amount, 6)} />
<Box component="span" marginLeft=".5rem">
<FormattedNumber value={lease.price.amount} maximumSignificantDigits={18} />
uakt ({`~${getAvgCostPerMonth(lease.price.amount)}akt/month`})
</Box>
</>
}
/>
{isLeaseActive && (
<LabelValue
label="Provider:"
value={
<>
{isLoadingProviderStatus && <CircularProgress size="1rem" />}
{providerStatus && (
<>
<Link to={UrlService.providerDetail(lease.provider)}>{providerStatus.name}</Link>
<Box display="flex" alignItems="center" marginLeft={1}>
<FavoriteButton isFavorite={isFavorite} onClick={onStarClick} />
{providerInfo.isAudited && (
<Box marginLeft=".5rem">
<AuditorButton provider={providerInfo} />
</Box>
)}
<Box marginLeft=".5rem" display="flex">
<LinkTo onClick={() => setIsViewingProviderDetail(true)}>View details</LinkTo>
</Box>
</Box>
</>
)}
</>
}
marginTop="5px"
marginBottom=".5rem"
/>
)}
</Box>
{providerInfo && (
<Box paddingLeft="1rem" flexGrow={1}>
<ProviderAttributes provider={providerInfo} />
</Box>
)}
</Box>
{isLeaseNotFound && (
<Alert severity="warning">
The lease was not found on this provider. This can happen if no manifest was sent to the provider. To send one you can update your deployment in
the <LinkTo onClick={handleEditManifestClick}>VIEW / EDIT MANIFEST</LinkTo> tab.
{deploymentManifest && (
<>
<Box margin="1rem 0">
<strong>OR</strong>
</Box>
<Button variant="contained" color="primary" disabled={isSendingManifest} onClick={sendManifest} size="small">
{isSendingManifest ? <CircularProgress size="1.5rem" /> : <span>Send manifest manually</span>}
</Button>
</>
)}
</Alert>
)}
{!leaseStatus && isLoadingLeaseStatus && <CircularProgress size="1rem" />}
{isLeaseActive &&
leaseStatus &&
leaseStatus.services &&
servicesNames
.map((n) => leaseStatus.services[n])
.map((service, i) => (
<Box mb={1} key={`${service.name}_${i}`}>
<Box display="flex" alignItems="center">
<LabelValue label="Group:" value={service.name} fontSize="1rem" />
{isLoadingLeaseStatus || !isServicesAvailable ? (
<Box display="inline-flex" marginLeft="1rem">
<CircularProgress size="1rem" />
</Box>
) : (
<Box display="inline-flex" marginLeft=".5rem">
<Tooltip
classes={{ tooltip: classes.tooltip }}
arrow
interactive
title={
<>
Workloads can take some time to spin up. If you see an error when browsing the uri, it is recommended to refresh and wait a bit.
Check the{" "}
<LinkTo onClick={() => setActiveTab("LOGS")} className={classes.whiteLink}>
logs
</LinkTo>{" "}
for more information.
</>
}
>
<InfoIcon className={classes.tooltipIcon} fontSize="small" />
</Tooltip>
</Box>
)}
</Box>
<Box display="flex" alignItems="center" marginTop="2px">
<Box display="flex" alignItems="center">
<Typography variant="caption">Available: </Typography>
<Chip label={service.available} size="small" color={service.available > 0 ? "primary" : "default"} className={classes.serviceChip} />
</Box>
<Box display="flex" alignItems="center">
<Typography variant="caption" className={classes.marginLeft}>
Ready Replicas:
</Typography>
<Chip
label={service.ready_replicas}
size="small"
color={service.ready_replicas > 0 ? "primary" : "default"}
className={classes.serviceChip}
/>
</Box>
<Box display="flex" alignItems="center">
<Typography variant="caption" className={classes.marginLeft}>
Total:
</Typography>
<Chip label={service.total} size="small" color="primary" className={classes.serviceChip} />
</Box>
</Box>
{leaseStatus.forwarded_ports && leaseStatus.forwarded_ports[service.name]?.length > 0 && (
<Box marginTop="4px">
<LabelValue
label="Forwarded Ports:"
value={leaseStatus.forwarded_ports[service.name].map((p) => (
<Box key={"port_" + p.externalPort} display="inline" mr={0.5}>
<LinkTo label={``} disabled={p.available < 1} onClick={(ev) => handleExternalUrlClick(ev, `${p.host}:${p.externalPort}`)}>
{p.externalPort}:{p.port}
</LinkTo>
</Box>
))}
/>
</Box>
)}
{service.uris?.length > 0 && (
<>
<Box marginTop=".5rem">
<LabelValue label="Uris:" />
<List dense>
{service.uris.map((uri) => {
return (
<ListItem key={uri} className={classes.listItem}>
<ListItemText
primary={
<LinkTo className={classes.link} onClick={(ev) => handleExternalUrlClick(ev, uri)}>
{uri} <LaunchIcon fontSize="small" />
</LinkTo>
}
/>
<ListItemSecondaryAction>
<IconButton
edge="end"
aria-label="uri"
size="small"
onClick={(ev) => {
copyTextToClipboard(uri);
enqueueSnackbar(<Snackbar title="Uri copied to clipboard!" iconVariant="success" />, {
variant: "success",
autoHideDuration: 2000
});
}}
>
<FileCopyIcon fontSize="small" />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
);
})}
</List>
</Box>
</>
)}
</Box>
))}
</CardContent>
</Card>
</>
);
})
Example #15
Source File: photos.jsx From react-redux-jsonplaceholder with MIT License | 4 votes |
PhotoContainer = ({
fetchPhotosStart,
deletePhotoStart,
clearPhotoMessages,
errorMessage,
photos,
isFetching,
}) => {
const { enqueueSnackbar } = useSnackbar();
const [page, setPage] = useState(1);
const [minimum, setMinimum] = useState(0);
const [maximum, setMaximum] = useState(10);
const [pagePhotos, setPagePhotos] = useState([]);
const classes = useStyles();
const count = Math.ceil(photos.length / 10);
useEffect(() => {
if (photos.length < 1) fetchPhotosStart();
}, [fetchPhotosStart, photos]);
useEffect(() => {
if (errorMessage) {
enqueueSnackbar(errorMessage, { variant: "error" });
clearPhotoMessages();
}
}, [errorMessage, clearPhotoMessages, enqueueSnackbar]);
useEffect(() => {
setPagePhotos(photos.slice(minimum, maximum));
}, [page, isFetching, photos, minimum, maximum]);
const handleChange = (event, value) => {
setPage(value);
setMinimum((value - 1) * 10);
setMaximum(value * 10);
};
return (
<Box className={classes.root}>
<Typography variant={"h2"} component={"h1"}>
Photos <strong className={classes.length}> [{photos.length}]</strong>
</Typography>
<AddItemModal />
<Grid container justify={"center"} alignItems={"center"} spacing={4}>
{pagePhotos.length > 1 ? (
pagePhotos.map((each) => (
<Grid item xs={10} sm={5} md={3} key={each.id}>
<Paper className={classes.card} elevation={10}>
{each.id}
<DeleteForeverRounded
color={"primary"}
className={classes.delete}
onClick={() => deletePhotoStart(each.id)}
/>
<Typography>{each.title}</Typography>
<Box style={{ height: "200px" }}>
<img
loading={"eager"}
src={each.thumbnailUrl}
alt={""}
height={"200px"}
/>
</Box>
<Box>
<TransitionsModal key={each.id} photo={each} />
</Box>
</Paper>
</Grid>
))
) : (
<SkeletonComponent />
)}
</Grid>
<Pagination
count={count}
page={page}
onChange={handleChange}
className={classes.pagination}
color="primary"
variant="outlined"
size="small"
/>
</Box>
);
}
Example #16
Source File: RoleNew.js From management-center with Apache License 2.0 | 4 votes |
RoleNew = (props) => {
const classes = useStyles();
const [rolename, setRolename] = useState('');
const [textname, setTextname] = useState('');
const [textdescription, setTextdescription] = useState('');
const { enqueueSnackbar } = useSnackbar();
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const history = useHistory();
const confirm = useConfirm();
const { client } = context;
const validate = () => {
const valid = rolename !== '';
return valid;
};
const onSaveRole = async () => {
try {
await client.createRole(rolename, textname, textdescription);
const roles = await client.listRoles();
dispatch(updateRoles(roles));
history.push(`/security/roles`);
enqueueSnackbar(`Role "${rolename}" successfully created.`, {
variant: 'success'
});
} catch(error) {
enqueueSnackbar(`Error creating role "${rolename}". Reason: ${error.message || error}`, {
variant: 'error'
});
throw error;
}
};
const onCancel = async () => {
await confirm({
title: 'Cancel role creation',
description: `Do you really want to cancel creating this role?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
history.goBack();
};
return (
<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/security">
Security
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
Roles
</Typography>
</Breadcrumbs>
<br />
<div className={classes.root}>
<Paper>
<form className={classes.form} noValidate autoComplete="off">
<div className={classes.margin}>
<Grid container spacing={1} alignItems="flex-end">
<Grid item xs={12}>
<TextField
required
id="rolename"
label="Role name"
onChange={(event) => setRolename(event.target.value)}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle />
</InputAdornment>
)
}}
/>
</Grid>
<Grid item xs={12}>
<TextField
id="textname"
label="Text name"
onChange={(event) => setTextname(event.target.value)}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
<Grid item xs={12}>
<TextField
id="textdescription"
label="Text description"
onChange={(event) => setTextdescription(event.target.value)}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
<Grid container xs={12} alignItems="flex-start">
<Grid item xs={12} className={classes.buttons}>
<SaveCancelButtons
onSave={onSaveRole}
saveDisabled={!validate()}
onCancel={onCancel}
/>
</Grid>
</Grid>
</Grid>
</div>
</form>
</Paper>
</div>
</div>
);
}
Example #17
Source File: todos.jsx From react-redux-jsonplaceholder with MIT License | 4 votes |
TodoContainer = ({
fetchTodosStart,
deleteTodoStart,
todos,
isFetching,
errorMessage,
}) => {
const { enqueueSnackbar } = useSnackbar();
const [page, setPage] = useState(1);
const [minimum, setMinimum] = useState(0);
const [maximum, setMaximum] = useState(10);
const [pageTodos, setPageTodos] = useState([]);
const classes = useStyles();
const count = Math.ceil(todos.length / 10);
useEffect(() => {
if (todos.length < 1) fetchTodosStart();
}, [fetchTodosStart, todos]);
useEffect(() => {
if (errorMessage) {
enqueueSnackbar(errorMessage, { variant: "error" });
}
}, [errorMessage, enqueueSnackbar]);
useEffect(() => {
setPageTodos(todos.slice(minimum, maximum));
}, [page, isFetching, todos, minimum, maximum]);
const handleChange = (event, value) => {
setPage(value);
setMinimum((value - 1) * 10);
setMaximum(value * 10);
};
return (
<Box className={classes.root}>
<Typography variant={"h2"} component={"h1"}>
Todos <strong className={classes.length}> [{todos.length}]</strong>
</Typography>
<AddItemModal />
<Grid container justify={"center"} alignItems={"center"} spacing={4}>
{pageTodos.length > 1 ? (
pageTodos.map((each) => (
<Grid item xs={10} sm={5} md={3} key={each.id}>
<Paper className={classes.card} elevation={10}>
{each.id}
<DeleteForeverRounded
color={"primary"}
className={classes.delete}
onClick={() => deleteTodoStart(each.id)}
/>
<Typography>{each.title}</Typography>
<FormControlLabel
control={
<Checkbox
icon={<CheckCircleOutline />}
checkedIcon={<CheckCircle />}
name="checkedH"
checked={each.completed}
/>
}
label={each.completed ? "Completed" : "Uncompleted"}
/>
<Box>
<TransitionsModal key={each.id} todo={each} />
</Box>
</Paper>
</Grid>
))
) : (
<SkeletonComponent />
)}
</Grid>
<Pagination
count={count}
page={page}
onChange={handleChange}
className={classes.pagination}
color="primary"
variant="outlined"
size="small"
/>
</Box>
);
}
Example #18
Source File: CreateLease.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
export function CreateLease({ dseq }) {
const [isSendingManifest, setIsSendingManifest] = useState(false);
const [isFilteringFavorites, setIsFilteringFavorites] = useState(false);
const [selectedBids, setSelectedBids] = useState({});
const [filteredBids, setFilteredBids] = useState([]);
const [search, setSearch] = useState("");
const { sendTransaction } = useTransactionModal();
const { address } = useWallet();
const { localCert } = useCertificate();
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
const history = useHistory();
const [anchorEl, setAnchorEl] = useState(null);
const classes = useStyles();
const [numberOfRequests, setNumberOfRequests] = useState(0);
const { providers, getProviders } = useAkash();
const warningRequestsReached = numberOfRequests > WARNING_NUM_OF_BID_REQUESTS;
const maxRequestsReached = numberOfRequests > MAX_NUM_OF_BID_REQUESTS;
const { favoriteProviders } = useLocalNotes();
const { data: bids, isLoading: isLoadingBids } = useBidList(address, dseq, {
initialData: [],
refetchInterval: REFRESH_BIDS_INTERVAL,
onSuccess: () => {
setNumberOfRequests((prev) => ++prev);
},
enabled: !maxRequestsReached
});
const { data: deploymentDetail, refetch: getDeploymentDetail } = useDeploymentDetail(address, dseq, { refetchOnMount: false, enabled: false });
const groupedBids = bids
.sort((a, b) => a.price.amount - b.price.amount)
.reduce((a, b) => {
a[b.gseq] = [...(a[b.gseq] || []), b];
return a;
}, {});
const dseqList = Object.keys(groupedBids);
const allClosed = bids.length > 0 && bids.every((bid) => bid.state === "closed");
useEffect(() => {
getDeploymentDetail();
getProviders();
if (favoriteProviders.length > 0) {
setIsFilteringFavorites(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// Filter bids by search
useEffect(() => {
let fBids = [];
if ((search || isFilteringFavorites) && providers) {
bids?.forEach((bid) => {
let isAdded = false;
// Filter for search
if (search) {
const provider = providers.find((p) => p.owner === bid.provider);
// Filter by attribute value
provider?.attributes.forEach((att) => {
if (att.value?.includes(search)) {
fBids.push(bid.id);
isAdded = true;
}
});
}
// Filter for favorites
if (!isAdded && isFilteringFavorites) {
const provider = favoriteProviders.find((p) => p === bid.provider);
if (provider) {
fBids.push(bid.id);
}
}
});
} else {
fBids = bids?.map((b) => b.id) || [];
}
setFilteredBids(fBids);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [search, bids, providers, isFilteringFavorites]);
const handleBidSelected = (bid) => {
setSelectedBids({ ...selectedBids, [bid.gseq]: bid });
};
async function sendManifest(providerInfo, manifest) {
try {
const response = await sendManifestToProvider(providerInfo, manifest, dseq, localCert);
return response;
} catch (err) {
enqueueSnackbar(<ManifestErrorSnackbar err={err} />, { variant: "error", autoHideDuration: null });
throw err;
}
}
async function handleNext() {
const bidKeys = Object.keys(selectedBids);
// Create the lease
try {
const messages = bidKeys.map((gseq) => selectedBids[gseq]).map((bid) => TransactionMessageData.getCreateLeaseMsg(bid));
const response = await sendTransaction(messages);
if (!response) throw new Error("Rejected transaction");
await analytics.event("deploy", "create lease");
} catch (error) {
// Rejected transaction
return;
}
setIsSendingManifest(true);
const localDeploymentData = getDeploymentLocalData(dseq);
if (localDeploymentData && localDeploymentData.manifest) {
// Send the manifest
const sendManifestKey = enqueueSnackbar(<Snackbar title="Sending Manifest! ?" subTitle="Please wait a few seconds..." showLoading />, {
variant: "success",
autoHideDuration: null
});
try {
const yamlJson = yaml.load(localDeploymentData.manifest);
const mani = deploymentData.Manifest(yamlJson);
for (let i = 0; i < bidKeys.length; i++) {
const currentBid = selectedBids[bidKeys[i]];
const provider = providers.find((x) => x.owner === currentBid.provider);
await sendManifest(provider, mani);
}
} catch (err) {
console.error(err);
}
closeSnackbar(sendManifestKey);
}
setIsSendingManifest(false);
await analytics.event("deploy", "send manifest");
history.replace(UrlService.deploymentDetails(dseq, "LOGS", "events"));
}
async function handleCloseDeployment() {
try {
const message = TransactionMessageData.getCloseDeploymentMsg(address, dseq);
const response = await sendTransaction([message]);
if (response) {
history.replace(UrlService.deploymentList());
}
} catch (error) {
throw error;
}
}
function handleMenuClick(ev) {
setAnchorEl(ev.currentTarget);
}
const handleMenuClose = () => {
setAnchorEl(null);
};
const onSearchChange = (event) => {
const value = event.target.value;
setSearch(value);
};
return (
<>
<Helmet title="Create Deployment - Create Lease" />
<Box padding="0 1rem">
{!isLoadingBids && bids.length > 0 && !allClosed && (
<Box display="flex" alignItems="center" justifyContent="space-between">
<Box flexGrow={1}>
<TextField
label="Search by attribute..."
disabled={bids.length === 0 || isSendingManifest}
value={search}
onChange={onSearchChange}
type="text"
variant="outlined"
autoFocus
fullWidth
size="medium"
InputProps={{
endAdornment: search && (
<InputAdornment position="end">
<IconButton size="small" onClick={() => setSearch("")}>
<CloseIcon />
</IconButton>
</InputAdornment>
)
}}
/>
</Box>
<Box display="flex" alignItems="center">
<Tooltip
classes={{ tooltip: classes.tooltip }}
arrow
interactive
title={
<Alert severity="info" variant="standard">
Bids automatically close 5 minutes after the deployment is created if none are selected for a lease.
</Alert>
}
>
<InfoIcon className={clsx(classes.tooltipIcon, classes.marginLeft)} />
</Tooltip>
<Box margin="0 .5rem">
<IconButton aria-label="settings" aria-haspopup="true" onClick={handleMenuClick} size="small">
<MoreHorizIcon fontSize="large" />
</IconButton>
</Box>
<Menu
id="bid-actions-menu"
anchorEl={anchorEl}
keepMounted
getContentAnchorEl={null}
open={Boolean(anchorEl)}
onClose={handleMenuClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "right"
}}
transformOrigin={{
vertical: "top",
horizontal: "right"
}}
onClick={handleMenuClose}
>
<MenuItem onClick={() => handleCloseDeployment()}>Close Deployment</MenuItem>
</Menu>
<Button
variant="contained"
color="primary"
onClick={handleNext}
classes={{ label: classes.nowrap }}
disabled={dseqList.some((gseq) => !selectedBids[gseq]) || isSendingManifest || !providers}
>
Accept Bid{dseqList.length > 1 ? "s" : ""}
<Box component="span" marginLeft=".5rem" display="flex" alignItems="center">
<ArrowForwardIosIcon fontSize="small" />
</Box>
</Button>
</Box>
</Box>
)}
<Box display="flex" alignItems="center">
{!isLoadingBids && (allClosed || bids.length === 0) && (
<Button variant="contained" color={allClosed ? "primary" : "secondary"} onClick={handleCloseDeployment} size="small">
Close Deployment
</Button>
)}
{!isLoadingBids && allClosed && (
<Tooltip
classes={{ tooltip: classes.tooltip }}
arrow
interactive
title={
<Alert severity="warning">
All bids for this deployment are closed. This can happen if no bids are accepted for more than 5 minutes after the deployment creation. You
can close this deployment and create a new one.
</Alert>
}
>
<InfoIcon className={clsx(classes.tooltipIcon, classes.marginLeft)} color="error" />
</Tooltip>
)}
</Box>
{(isLoadingBids || bids.length === 0) && !maxRequestsReached && (
<Box textAlign="center" paddingTop="1rem">
<CircularProgress />
<Box paddingTop="1rem">
<Typography variant="body1">Waiting for bids...</Typography>
</Box>
</Box>
)}
{warningRequestsReached && !maxRequestsReached && bids.length === 0 && (
<Box paddingTop="1rem">
<Alert variant="standard" severity="info">
There should be bids by now... You can wait longer in case a bid shows up or close the deployment and try again with a different configuration.
</Alert>
</Box>
)}
{maxRequestsReached && bids.length === 0 && (
<Box paddingTop="1rem">
<Alert variant="standard" severity="warning">
There's no bid for the current deployment. You can close the deployment and try again with a different configuration.
</Alert>
</Box>
)}
{bids.length > 0 && (
<Box display="flex" alignItems="center" justifyContent="space-between">
<Box>
<FormControlLabel
control={<Checkbox checked={isFilteringFavorites} onChange={(ev, value) => setIsFilteringFavorites(value)} color="primary" size="small" />}
label="Favorites"
/>
</Box>
{!maxRequestsReached && (
<Box display="flex" alignItems="center" lineHeight="1rem" fontSize=".7rem">
<div style={{ color: "grey" }}>
<Typography variant="caption">Waiting for more bids...</Typography>
</div>
<Box marginLeft=".5rem">
<CircularProgress size=".7rem" />
</Box>
</Box>
)}
</Box>
)}
<LinearLoadingSkeleton isLoading={isSendingManifest} />
</Box>
{dseqList.length > 0 && (
<ViewPanel bottomElementId="footer" overflow="auto" padding="0 1rem 2rem">
{dseqList.map((gseq, i) => (
<BidGroup
key={gseq}
gseq={gseq}
bids={groupedBids[gseq]}
handleBidSelected={handleBidSelected}
selectedBid={selectedBids[gseq]}
disabled={isSendingManifest}
providers={providers}
filteredBids={filteredBids}
deploymentDetail={deploymentDetail}
isFilteringFavorites={isFilteringFavorites}
groupIndex={i}
totalBids={dseqList.length}
/>
))}
</ViewPanel>
)}
</>
);
}
Example #19
Source File: index.js From nextjs-todo-list with MIT License | 4 votes |
TeamContainer = memo(({ firebase, team, user, onSetTeam }) => {
const { updateUser } = useContext(AuthContext);
const [progress, setProgress] = useState(false);
const { enqueueSnackbar } = useSnackbar();
const completeTeamMembersData = async (teamObj) => {
const memberPromises = [];
const { members } = teamObj;
members.forEach((member) => {
memberPromises.push(member.get());
});
const memebersData = await Promise.all(memberPromises);
if (memebersData && memebersData.length > 0) {
memebersData.forEach((member, index) => {
members[index] = member.data();
});
}
return members;
};
const handleCreateTeam = async (teamName) => {
setProgress(true);
const teamCode = new Date().getUTCMilliseconds();
// Fetch auth user ref
const authRef = await firebase.authRef();
const teamToServer = {
author: user.uid,
name: teamName,
code: teamCode,
members: [authRef],
createdAt: new Date(),
};
const todoAdded = await firebase.saveData({ collection: 'teams', data: teamToServer });
// Add team to user collection
authRef.update({ team: todoAdded.id });
// Update local saved user
// eslint-disable-next-line no-param-reassign
user.team = todoAdded.id;
if (todoAdded.members.length > 0) {
await completeTeamMembersData(todoAdded);
}
updateUser(user);
onSetTeam(todoAdded);
setProgress(false);
};
const handleJoinTeam = async (teamCode) => {
setProgress(true);
const teams = await firebase.getCollectionData({
collection: 'teams',
where: { field: 'code', op: '==', value: teamCode },
addRef: true,
});
const foundTeam = first(teams);
if (!isEmpty(foundTeam)) {
// Fetch auth user ref
const authRef = await firebase.authRef();
// Fetch document ref
const teamRef = await firebase.getRef({ collection: 'teams', doc: foundTeam.id });
foundTeam.members.push(authRef);
teamRef.update({ members: foundTeam.members });
// Add team to user collection
authRef.update({ team: foundTeam.id });
// Update local saved user
// eslint-disable-next-line no-param-reassign
user.team = foundTeam.id;
if (foundTeam.members.length > 0) {
await completeTeamMembersData(foundTeam);
}
updateUser(user);
onSetTeam(foundTeam);
} else {
enqueueSnackbar('Team not found, review the team code', { variant: 'error' });
}
setProgress(false);
};
if (isEmpty(team)) {
return (
<EmptyTeam onCreateTeam={handleCreateTeam} onJoinTeam={handleJoinTeam} loading={progress} />
);
}
return <UserTeam team={team} />;
})
Example #20
Source File: WalletProviderContext.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
WalletProvider = ({ children }) => {
const { settings } = useSettings();
const [wallets, setWallets] = useState(null);
const [selectedWallet, setSelectedWallet] = useState(null);
const [address, setAddress] = useState(null);
const [balance, setBalance] = useState(null);
const [isRefreshingBalance, setIsRefreshingBalance] = useState(false);
const { enqueueSnackbar } = useSnackbar();
const history = useHistory();
const { apiEndpoint } = settings;
const refreshBalance = useCallback(
async (showSnackbar) => {
if (!address) return 0;
setIsRefreshingBalance(true);
try {
const response = await axios.get(`${apiEndpoint}/cosmos/bank/v1beta1/balances/${address}`);
const data = response.data;
const balance = data.balances.length > 0 && data.balances.some((b) => b.denom === "uakt") ? data.balances.find((b) => b.denom === "uakt").amount : 0;
setBalance(parseInt(balance));
setIsRefreshingBalance(false);
if (showSnackbar) {
enqueueSnackbar(<Snackbar title="Balance refreshed!" iconVariant="success" />, { variant: "success" });
}
return balance;
} catch (error) {
console.log(error);
setIsRefreshingBalance(false);
enqueueSnackbar(<Snackbar title="Error fetching balance." iconVariant="error" />, { variant: "error" });
return 0;
}
},
[address, apiEndpoint, enqueueSnackbar]
);
const deleteWallet = (address, deleteDeployments) => {
const storageWallets = deleteWalletFromStorage(address, deleteDeployments);
// Disconnect
setSelectedWallet(null);
if (storageWallets.length > 0) {
if (history.location.pathname !== UrlService.walletOpen()) {
history.replace(UrlService.walletOpen());
}
} else {
history.replace(UrlService.register());
}
return storageWallets;
};
useEffect(() => {
async function getAddress() {
const [account] = await selectedWallet.getAccounts();
setAddress(account.address);
}
if (selectedWallet) {
getAddress();
} else {
setBalance(null);
setAddress(null);
}
}, [selectedWallet]);
useEffect(() => {
if (address) {
refreshBalance();
}
}, [address, refreshBalance]);
return (
<WalletProviderContext.Provider
value={{ balance, setSelectedWallet, refreshBalance, selectedWallet, address, isRefreshingBalance, deleteWallet, wallets, setWallets }}
>
{children}
</WalletProviderContext.Provider>
);
}
Example #21
Source File: MergeAccountsDialog.js From spl-token-wallet with Apache License 2.0 | 4 votes |
export default function MergeAccountsDialog({ open, onClose }) {
const [publicKeys] = useWalletPublicKeys();
const connection = useConnection();
const wallet = useWallet();
const { enqueueSnackbar } = useSnackbar();
const [isMerging, setIsMerging] = useState(false);
const [mergeCheck, setMergeCheck] = useState('');
const tokenInfos = useTokenInfos();
// Merging accounts is a destructive operation that, for each mint,
//
// * Creates an associated token account, if not already created
// * Moves all funds into the associated token account
// * Closes every account, excluding the associated token account.
//
// Although it's ok if this operation fails--since the user can just
// retry again--it's not a good experience; hence the retry logic.
// The retry count of 30 is arbitrary and probably overly conservative.
const mergeAccounts = async (retryCount = 30) => {
try {
if (retryCount === 0) {
enqueueSnackbar(`Unable to complete migration. Please try again.`, {
variant: 'error',
});
return;
}
// Fetch all token accounts owned by the wallet. An account is null
// if we previously sent the close transaction, but did not receive
// a response due to RPC node instability.
const tokenAccounts = (
await getMultipleSolanaAccounts(connection, publicKeys)
)
.filter(
(acc) =>
acc !== null &&
acc.account.owner.equals(TokenInstructions.TOKEN_PROGRAM_ID),
)
.map(({ publicKey, account }) => {
return {
publicKey,
account: parseTokenAccountData(account.data),
owner: account.owner,
};
});
// Group the token accounts by mint.
const groupedTokenAccounts = {};
tokenAccounts.forEach((ta) => {
const key = ta.account.mint.toString();
if (groupedTokenAccounts[key]) {
groupedTokenAccounts[key].push(ta);
} else {
groupedTokenAccounts[key] = [ta];
}
});
// For each mint, merge them into one, associated token account.
const mints = Object.keys(groupedTokenAccounts);
for (let k = 0; k < mints.length; k += 1) {
const mintGroup = groupedTokenAccounts[mints[k]];
if (mintGroup.length > 0) {
const mint = mintGroup[0].account.mint;
const assocTokAddr = await findAssociatedTokenAddress(
wallet.publicKey,
mint,
);
// Don't merge if the only account is the associated token address.
if (
!(
mintGroup.length === 1 &&
assocTokAddr.equals(mintGroup[0].publicKey)
)
) {
const tokenInfo = getTokenInfo(
mint,
connection._rpcEndpoint,
tokenInfos,
);
const symbol = tokenInfo.symbol
? tokenInfo.symbol
: mint.toString();
console.log(`Migrating ${symbol}`);
enqueueSnackbar(`Migrating ${symbol}`, {
variant: 'info',
});
await mergeMint(
assocTokAddr,
mintGroup,
mint,
tokenInfo.decimals,
wallet,
connection,
enqueueSnackbar,
);
}
}
}
// Wait to give the RPC nodes some time to catch up.
await sleep(5000);
// Refresh the UI to remove any duplicates.
await refresh(wallet, publicKeys);
// Exit dialogue.
close();
} catch (err) {
console.error('There was a problem migrating accounts', err);
enqueueSnackbar('Could not confirm transaction. Please wait.', {
variant: 'info',
});
// Sleep to give the RPC nodes some time to catch up.
await sleep(10000);
enqueueSnackbar('Retrying migration', { variant: 'info' });
await mergeAccounts(retryCount - 1);
}
};
const close = () => {
setMergeCheck('');
onClose();
};
const disabled = mergeCheck.toLowerCase() !== 'migrate';
return (
<Dialog disableBackdropClick={isMerging} open={open} onClose={onClose}>
{isMerging ? (
<DialogContent>
<DialogContentText style={{ marginBottom: 0, textAlign: 'center' }}>
Merging Accounts
</DialogContentText>
<div
style={{
display: 'flex',
justifyContent: 'center',
padding: '24px',
}}
>
<CircularProgress />
</div>
</DialogContent>
) : (
<>
<DialogTitle>Are you sure you want to migrate tokens?</DialogTitle>
<DialogContent>
<DialogContentText>
<b>WARNING</b>: This action may break apps that depend on your
existing token accounts.
</DialogContentText>
<DialogContentText>
Migrating sends all tokens to{' '}
<Link
href={'https://spl.solana.com/associated-token-account'}
target="_blank"
rel="noopener"
>
associated token accounts
</Link>{' '}
<FingerprintIcon style={{ marginBottom: '-7px' }} />. If
associated token accounts do not exist, then they will be created.
</DialogContentText>
<DialogContentText>
If migrating fails during a period of high network load, you will
not have lost your funds. Just recontinue the migration from where you
left off. If you have a lot of accounts, migrating might take a
while.
</DialogContentText>
<TextField
label={`Please type "migrate" to confirm`}
fullWidth
variant="outlined"
margin="normal"
value={mergeCheck}
onChange={(e) => setMergeCheck(e.target.value.trim())}
/>
</DialogContent>
<DialogActions>
<Button onClick={close} color="primary">
Cancel
</Button>
<Button
disabled={disabled}
onClick={() => {
setIsMerging(true);
mergeAccounts()
.then(() => {
enqueueSnackbar('Account migrate complete', {
variant: 'success',
});
setIsMerging(false);
})
.catch((err) => {
enqueueSnackbar(
`There was a problem merging your accounts: ${err.toString()}`,
{ variant: 'error' },
);
setIsMerging(false);
});
}}
color="secondary"
autoFocus
>
Migrate
</Button>
</DialogActions>
</>
)}
</Dialog>
);
}
Example #22
Source File: ConfirmPasswordModal.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
export function ConfirmPasswordModal(props) {
const classes = useStyles();
const formRef = useRef();
const [isLoading, setIsLoading] = useState(false);
const { enqueueSnackbar } = useSnackbar();
const {
handleSubmit,
control,
formState: { errors },
clearErrors,
reset
} = useForm({
defaultValues: {
password: ""
}
});
useEffect(() => {
reset();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.isOpen]);
const onConfirmClick = (event) => {
event.preventDefault();
formRef.current.dispatchEvent(new Event("submit", { cancelable: true, bubbles: true }));
};
async function onSubmit({ password }) {
clearErrors();
try {
setIsLoading(true);
await openWallet(password);
props.onConfirmPassword(password);
} catch (err) {
if (err.message === "ciphertext cannot be decrypted using that key") {
enqueueSnackbar(<Snackbar title="Invalid password" iconVariant="error" />, { variant: "error" });
} else {
console.error(err);
enqueueSnackbar(<Snackbar title="Error while decrypting wallet" iconVariant="error" />, { variant: "error" });
}
} finally {
setIsLoading(false);
}
}
return (
<Dialog open={props.isOpen} onClose={props.onClose}>
<DialogTitle>Confirm your password</DialogTitle>
<DialogContent dividers className={classes.dialogContent}>
<Box marginBottom="1rem">
<Alert
icon={<LockOpenIcon fontSize="large" color="primary" />}
variant="outlined"
classes={{ root: classes.alertRoot, message: classes.alertMessage }}
>
<Typography variant="caption">Please input your password to proceed.</Typography>
</Alert>
</Box>
<form onSubmit={handleSubmit(onSubmit)} ref={formRef}>
<FormControl error={!errors.password} fullWidth>
<Controller
control={control}
name="password"
rules={{
required: true
}}
render={({ fieldState, field }) => {
const helperText = "Password is required.";
return (
<TextField
{...field}
autoFocus
type="password"
variant="outlined"
label="Password"
error={!!fieldState.invalid}
helperText={fieldState.invalid && helperText}
/>
);
}}
/>
</FormControl>
</form>
</DialogContent>
<DialogActions className={classes.dialogActions}>
<Button disabled={isLoading} onClick={props.onClose} type="button">
Cancel
</Button>
<Button disabled={isLoading} variant="contained" color="primary" onClick={onConfirmClick}>
{isLoading ? <CircularProgress size="24px" color="primary" /> : "Confirm"}
</Button>
</DialogActions>
</Dialog>
);
}
Example #23
Source File: wallet.js From spl-token-wallet with Apache License 2.0 | 4 votes |
export function WalletProvider({ children }) {
useListener(walletSeedChanged, 'change');
const [{
mnemonic,
seed,
importsEncryptionKey,
derivationPath,
}] = useUnlockedMnemonicAndSeed();
const { enqueueSnackbar } = useSnackbar();
const connection = useConnection();
const [wallet, setWallet] = useState();
// `privateKeyImports` are accounts imported *in addition* to HD wallets
const [privateKeyImports, setPrivateKeyImports] = useLocalStorageState(
'walletPrivateKeyImports',
{},
);
// `walletSelector` identifies which wallet to use.
let [walletSelector, setWalletSelector] = useLocalStorageState(
'walletSelector',
DEFAULT_WALLET_SELECTOR,
);
const [_hardwareWalletAccount, setHardwareWalletAccount] = useState(null);
// `walletCount` is the number of HD wallets.
const [walletCount, setWalletCount] = useLocalStorageState('walletCount', 1);
if (walletSelector.ledger && !_hardwareWalletAccount) {
walletSelector = DEFAULT_WALLET_SELECTOR;
setWalletSelector(DEFAULT_WALLET_SELECTOR);
}
useEffect(() => {
(async () => {
if (!seed) {
return null;
}
let wallet;
if (walletSelector.ledger) {
try {
const onDisconnect = () => {
setWalletSelector(DEFAULT_WALLET_SELECTOR);
setHardwareWalletAccount(null);
};
const args = {
onDisconnect,
derivationPath: walletSelector.derivationPath,
account: walletSelector.account,
change: walletSelector.change,
};
wallet = await Wallet.create(connection, 'ledger', args);
} catch (e) {
console.log(`received error using ledger wallet: ${e}`);
let message = 'Received error unlocking ledger';
if (e.statusCode) {
message += `: ${e.statusCode}`;
}
enqueueSnackbar(message, { variant: 'error' });
setWalletSelector(DEFAULT_WALLET_SELECTOR);
setHardwareWalletAccount(null);
return;
}
}
if (!wallet) {
const account =
walletSelector.walletIndex !== undefined
? getAccountFromSeed(
Buffer.from(seed, 'hex'),
walletSelector.walletIndex,
derivationPath,
)
: new Account(
(() => {
const { nonce, ciphertext } = privateKeyImports[
walletSelector.importedPubkey
];
return nacl.secretbox.open(
bs58.decode(ciphertext),
bs58.decode(nonce),
importsEncryptionKey,
);
})(),
);
wallet = await Wallet.create(connection, 'local', { account });
}
setWallet(wallet);
})();
}, [
connection,
seed,
walletSelector,
privateKeyImports,
importsEncryptionKey,
setWalletSelector,
enqueueSnackbar,
derivationPath,
]);
function addAccount({ name, importedAccount, ledger }) {
if (importedAccount === undefined) {
name && localStorage.setItem(`name${walletCount}`, name);
setWalletCount(walletCount + 1);
} else {
const nonce = nacl.randomBytes(nacl.secretbox.nonceLength);
const plaintext = importedAccount.secretKey;
const ciphertext = nacl.secretbox(plaintext, nonce, importsEncryptionKey);
// `useLocalStorageState` requires a new object.
let newPrivateKeyImports = { ...privateKeyImports };
newPrivateKeyImports[importedAccount.publicKey.toString()] = {
name,
ciphertext: bs58.encode(ciphertext),
nonce: bs58.encode(nonce),
};
setPrivateKeyImports(newPrivateKeyImports);
}
}
const getWalletNames = () => {
return JSON.stringify(
[...Array(walletCount).keys()].map((idx) =>
localStorage.getItem(`name${idx}`),
),
);
};
const [walletNames, setWalletNames] = useState(getWalletNames());
function setAccountName(selector, newName) {
if (selector.importedPubkey && !selector.ledger) {
let newPrivateKeyImports = { ...privateKeyImports };
newPrivateKeyImports[selector.importedPubkey.toString()].name = newName;
setPrivateKeyImports(newPrivateKeyImports);
} else {
localStorage.setItem(`name${selector.walletIndex}`, newName);
setWalletNames(getWalletNames());
}
}
const [accounts, derivedAccounts] = useMemo(() => {
if (!seed) {
return [[], []];
}
const seedBuffer = Buffer.from(seed, 'hex');
const derivedAccounts = [...Array(walletCount).keys()].map((idx) => {
let address = getAccountFromSeed(seedBuffer, idx, derivationPath)
.publicKey;
let name = localStorage.getItem(`name${idx}`);
return {
selector: {
walletIndex: idx,
importedPubkey: undefined,
ledger: false,
},
isSelected: walletSelector.walletIndex === idx,
address,
name: idx === 0 ? 'Main account' : name || `Account ${idx}`,
};
});
const importedAccounts = Object.keys(privateKeyImports).map((pubkey) => {
const { name } = privateKeyImports[pubkey];
return {
selector: {
walletIndex: undefined,
importedPubkey: pubkey,
ledger: false,
},
address: new PublicKey(bs58.decode(pubkey)),
name: `${name} (imported)`, // TODO: do this in the Component with styling.
isSelected: walletSelector.importedPubkey === pubkey,
};
});
const accounts = derivedAccounts.concat(importedAccounts);
return [accounts, derivedAccounts];
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [seed, walletCount, walletSelector, privateKeyImports, walletNames]);
let hardwareWalletAccount;
if (_hardwareWalletAccount) {
hardwareWalletAccount = {
..._hardwareWalletAccount,
selector: {
walletIndex: undefined,
ledger: true,
importedPubkey: _hardwareWalletAccount.publicKey,
derivationPath: _hardwareWalletAccount.derivationPath,
account: _hardwareWalletAccount.account,
change: _hardwareWalletAccount.change,
},
address: _hardwareWalletAccount.publicKey,
isSelected: walletSelector.ledger,
};
}
return (
<WalletContext.Provider
value={{
wallet,
seed,
mnemonic,
importsEncryptionKey,
walletSelector,
setWalletSelector,
privateKeyImports,
setPrivateKeyImports,
accounts,
derivedAccounts,
addAccount,
setAccountName,
derivationPath,
hardwareWalletAccount,
setHardwareWalletAccount,
}}
>
{children}
</WalletContext.Provider>
);
}
Example #24
Source File: CertificateProviderContext.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
CertificateProvider = ({ children }) => {
const [validCertificates, setValidCertificates] = useState([]);
const [selectedCertificate, setSelectedCertificate] = useState(null);
const [isLoadingCertificates, setIsLoadingCertificates] = useState(false);
const [localCerts, setLocalCerts] = useState(null);
const [localCert, setLocalCert] = useState(null);
const [isLocalCertMatching, setIsLocalCertMatching] = useState(false);
const { settings } = useSettings();
const { enqueueSnackbar } = useSnackbar();
const { address, selectedWallet } = useWallet();
const { apiEndpoint } = settings;
const loadValidCertificates = useCallback(
async (showSnackbar) => {
setIsLoadingCertificates(true);
try {
const response = await axios.get(`${apiEndpoint}/akash/cert/${networkVersion}/certificates/list?filter.state=valid&filter.owner=${address}`);
const certs = (response.data.certificates || []).map((cert) => {
const parsed = atob(cert.certificate.cert);
const pem = getCertPem(parsed);
return {
...cert,
parsed,
pem
};
});
setValidCertificates(certs);
setIsLoadingCertificates(false);
if (showSnackbar) {
enqueueSnackbar(<Snackbar title="Certificate refreshed!" iconVariant="success" />, { variant: "success" });
}
return certs;
} catch (error) {
console.log(error);
setIsLoadingCertificates(false);
enqueueSnackbar(<Snackbar title="Error fetching certificate." iconVariant="error" />, { variant: "error" });
return [];
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[address, apiEndpoint, localCert, selectedCertificate]
);
useEffect(() => {
if (address) {
loadValidCertificates();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [address]);
useEffect(() => {
// Clear certs when no selected wallet
if (!selectedWallet) {
setValidCertificates([]);
setSelectedCertificate(null);
setLocalCert(null);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedWallet]);
useEffect(() => {
let isMatching = false;
if (validCertificates?.length > 0 && localCert) {
let currentCert = validCertificates.find((x) => x.parsed === localCert.certPem);
if (!selectedCertificate && currentCert) {
setSelectedCertificate(currentCert);
} else {
currentCert = validCertificates.find((x) => x.parsed === localCert.certPem && selectedCertificate?.serial === x.serial);
}
isMatching = !!currentCert;
}
setIsLocalCertMatching(isMatching);
}, [selectedCertificate, localCert, validCertificates]);
const loadLocalCert = async (password) => {
// open certs for all the wallets to be able to switch without needing the password
const wallets = getStorageWallets();
const currentWallet = getSelectedStorageWallet();
const certs = [];
for (let i = 0; i < wallets.length; i++) {
const _wallet = wallets[i];
const cert = await openCert(password, _wallet.cert, _wallet.certKey);
certs.push({ ...cert, address: _wallet.address });
if (_wallet.address === currentWallet.address) {
setLocalCert(cert);
}
}
setLocalCerts(certs);
};
return (
<CertificateProviderContext.Provider
value={{
loadValidCertificates,
selectedCertificate,
setSelectedCertificate,
isLoadingCertificates,
loadLocalCert,
localCert,
setLocalCert,
isLocalCertMatching,
validCertificates,
setValidCertificates,
localCerts,
setLocalCerts
}}
>
{children}
</CertificateProviderContext.Provider>
);
}
Example #25
Source File: UserDetail.js From management-center with Apache License 2.0 | 4 votes |
UserDetail = (props) => {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const [editMode, setEditMode] = React.useState(false);
const { enqueueSnackbar } = useSnackbar();
const { user, userRoles = [] } = props;
if (user) {
user.password = null;
}
const [updatedUser, setUpdatedUser] = React.useState({
...user,
});
const roleSuggestions = userRoles
.sort()
.map((rolename) => ({
label: rolename,
value: rolename
}));
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const confirm = useConfirm();
const { client: brokerClient } = context;
const validate = () => {
if (editMode) {
return updatedUser.username !== '';
}
};
const handleChange = (event, newValue) => {
setValue(newValue);
};
const onUpdateUserDetail = async () => {
await brokerClient.updateUser(updatedUser);
enqueueSnackbar('User successfully updated', {
variant: 'success'
});
const userObject = await brokerClient.getUser(updatedUser.username);
dispatch(updateUser(userObject));
const users = await brokerClient.listUsers();
dispatch(updateUsers(users));
setEditMode(false);
};
const onCancelEdit = async () => {
await confirm({
title: 'Cancel user editing',
description: `Do you really want to cancel editing this user?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
setUpdatedUser({
...user
});
setEditMode(false);
};
return user ? (<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} color="inherit" to="/admin">
Admin
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/admin/users">
Users
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
{user.username}
</Typography>
</Breadcrumbs>
<br />
<Paper className={classes.paper}>
<form className={classes.form} noValidate autoComplete="off">
<div className={classes.margin}>
<Grid container spacing={1} alignItems="flex-end">
<Grid item xs={12}>
<TextField
required={editMode}
disabled={true}
id="username"
label="username"
value={updatedUser?.username}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle />
</InputAdornment>
)
}}
/>
</Grid>
<Grid item xs={12}>
<TextField
disabled={!editMode}
required
id="password"
label="Password"
value={updatedUser?.password}
defaultValue=""
variant="outlined"
fullWidth
type="password"
className={classes.textField}
onChange={(event) => {
if (editMode) {
setUpdatedUser({
...updatedUser,
password: event.target.value
});
}
}}
/>
</Grid>
<Grid item xs={12}>
<AutoSuggest
disabled={!editMode}
suggestions={roleSuggestions}
values={updatedUser?.roles?.map((role) => ({
label: role,
value: role
}))}
handleChange={(value) => {
if (editMode) {
setUpdatedUser({
...updatedUser,
roles: value.map((role) => role.value)
});
}
}}
/>
</Grid>
</Grid>
</div>
</form>
{!editMode && (
<Grid item xs={12} className={classes.buttons}>
<Button
disabled={updatedUser.editable === false}
variant="contained"
color="primary"
className={classes.button}
startIcon={<EditIcon />}
onClick={() => setEditMode(true)}
>
Edit
</Button>
</Grid>
)}
{editMode && (
<Grid item xs={12} className={classes.buttons}>
<Button
variant="contained"
disabled={!validate()}
color="primary"
className={classes.button}
startIcon={<SaveIcon />}
onClick={(event) => {
event.stopPropagation();
onUpdateUserDetail();
}}
>
Save
</Button>
<Button
variant="contained"
onClick={(event) => {
event.stopPropagation();
onCancelEdit();
}}
>
Cancel
</Button>
</Grid>
)}
</Paper>
</div>) : null;
}
Example #26
Source File: WalletImport.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
export function WalletImport() {
const classes = useStyles();
const { enqueueSnackbar } = useSnackbar();
const { setSelectedWallet, setWallets } = useWallet();
const [isLoading, setIsLoading] = useState(false);
const history = useHistory();
const queryParams = useQueryParams();
const isAddAccount = !!queryParams.get("add");
const [hdPath, setHdPath] = useState({ account: 0, change: 0, addressIndex: 0 });
const { setLocalCert, setValidCertificates, setSelectedCertificate, loadLocalCert } = useCertificate();
const {
handleSubmit,
control,
formState: { errors },
watch,
clearErrors
} = useForm({
defaultValues: {
mnemonic: "",
name: "",
password: "",
confirmPassword: ""
}
});
const { password } = watch();
const onHdPathChange = (account, change, addressIndex) => {
setHdPath({ account, change, addressIndex });
};
/**
* Import new wallet
*/
async function onSubmit({ mnemonic, name, password }) {
clearErrors();
try {
setIsLoading(true);
// validate that all wallets have the same password
const wallets = await validateWallets(password);
const trimmedMnemonic = mnemonic.trim();
const { account, change, addressIndex } = hdPath;
const importedWallet = await importWallet(trimmedMnemonic, name, password, account, change, addressIndex);
const newWallets = wallets.concat([importedWallet]);
for (let i = 0; i < newWallets.length; i++) {
newWallets[i].selected = newWallets[i].address === importedWallet.address;
}
setWallets(newWallets);
setSelectedWallet(importedWallet);
setValidCertificates([]);
setSelectedCertificate(null);
setLocalCert(null);
// Load local certificates
loadLocalCert(password);
await analytics.event("deploy", "import wallet");
history.replace(UrlService.dashboard());
} catch (error) {
if (error.message === "ciphertext cannot be decrypted using that key") {
enqueueSnackbar(<Snackbar title="Invalid password" iconVariant="error" />, { variant: "error" });
} else {
console.error(error);
enqueueSnackbar(<Snackbar title="An error has occured" subTitle={error.message} iconVariant="error" />, { variant: "error" });
}
} finally {
setIsLoading(false);
}
}
return (
<Layout>
<div className={classes.root}>
<TitleLogo />
<Container maxWidth="xs" className={classes.container}>
<Typography variant="h6" color="textSecondary" className={classes.title}>
Import your seed
</Typography>
<form onSubmit={handleSubmit(onSubmit)}>
<FormControl error={!errors.name} className={classes.formControl} fullWidth>
<Controller
control={control}
name="mnemonic"
rules={{
required: true
}}
render={({ fieldState, field }) => {
const helperText = "Mnemonic is required.";
return (
<TextField
{...field}
type="text"
variant="outlined"
label="Type your mnemonic"
multiline
autoFocus
rows={4}
error={!!fieldState.invalid}
helperText={fieldState.invalid && helperText}
/>
);
}}
/>
</FormControl>
<FormControl error={!errors.name} className={classes.formControl} fullWidth>
<Controller
control={control}
name="name"
rules={{
required: true
}}
render={({ fieldState, field }) => {
const helperText = "Account name is required.";
return (
<TextField
{...field}
type="text"
variant="outlined"
label="Account name"
error={!!fieldState.invalid}
helperText={fieldState.invalid && helperText}
/>
);
}}
/>
</FormControl>
<FormControl error={!errors.password} className={classes.formControl} fullWidth>
<Controller
control={control}
name="password"
rules={{
required: true
}}
render={({ fieldState, field }) => {
const helperText = "Password is required.";
return (
<TextField
{...field}
type="password"
variant="outlined"
label="Password"
error={!!fieldState.invalid}
helperText={fieldState.invalid && helperText}
/>
);
}}
/>
</FormControl>
{!isAddAccount && (
<FormControl error={!errors.confirmPassword} className={classes.formControl} fullWidth>
<Controller
control={control}
name="confirmPassword"
rules={{
required: true,
validate: (value) => !!value && value === password
}}
render={({ fieldState, field }) => {
const helperText = fieldState.error?.type === "validate" ? "Password doesn't match." : "Confirm password is required.";
return (
<TextField
{...field}
type="password"
variant="outlined"
label="Confirm password"
error={!!fieldState.invalid}
helperText={fieldState.invalid && helperText}
/>
);
}}
/>
</FormControl>
)}
<HdPath onChange={onHdPathChange} />
<Box display="flex" alignItems="center" justifyContent="space-between" marginTop="1rem">
<Button onClick={() => history.goBack()}>Back</Button>
<Button type="submit" variant="contained" color="primary" disabled={isLoading}>
{isLoading ? <CircularProgress size="1.5rem" color="primary" /> : <>Import</>}
</Button>
</Box>
</form>
</Container>
</div>
</Layout>
);
}
Example #27
Source File: CoinSwapper.js From Alternative-Uniswap-Interface with GNU General Public License v3.0 | 4 votes |
function CoinSwapper(props) {
const classes = useStyles();
const { enqueueSnackbar } = useSnackbar();
// Stores a record of whether their respective dialog window is open
const [dialog1Open, setDialog1Open] = React.useState(false);
const [dialog2Open, setDialog2Open] = React.useState(false);
const [wrongNetworkOpen, setwrongNetworkOpen] = React.useState(false);
// Stores data about their respective coin
const [coin1, setCoin1] = React.useState({
address: undefined,
symbol: undefined,
balance: undefined,
});
const [coin2, setCoin2] = React.useState({
address: undefined,
symbol: undefined,
balance: undefined,
});
// Stores the current reserves in the liquidity pool between coin1 and coin2
const [reserves, setReserves] = React.useState(["0.0", "0.0"]);
// Stores the current value of their respective text box
const [field1Value, setField1Value] = React.useState("");
const [field2Value, setField2Value] = React.useState("");
// Controls the loading button
const [loading, setLoading] = React.useState(false);
// Switches the top and bottom coins, this is called when users hit the swap button or select the opposite
// token in the dialog (e.g. if coin1 is TokenA and the user selects TokenB when choosing coin2)
const switchFields = () => {
setCoin1(coin2);
setCoin2(coin1);
setField1Value(field2Value);
setReserves(reserves.reverse());
};
// These functions take an HTML event, pull the data out and puts it into a state variable.
const handleChange = {
field1: (e) => {
setField1Value(e.target.value);
},
};
// Turns the account's balance into something nice and readable
const formatBalance = (balance, symbol) => {
if (balance && symbol)
return parseFloat(balance).toPrecision(8) + " " + symbol;
else return "0.0";
};
// Turns the coin's reserves into something nice and readable
const formatReserve = (reserve, symbol) => {
if (reserve && symbol) return reserve + " " + symbol;
else return "0.0";
};
// Determines whether the button should be enabled or not
const isButtonEnabled = () => {
// If both coins have been selected, and a valid float has been entered which is less than the user's balance, then return true
const parsedInput1 = parseFloat(field1Value);
const parsedInput2 = parseFloat(field2Value);
return (
coin1.address &&
coin2.address &&
!isNaN(parsedInput1) &&
!isNaN(parsedInput2) &&
0 < parsedInput1 &&
parsedInput1 <= coin1.balance
);
};
// Called when the dialog window for coin1 exits
const onToken1Selected = (address) => {
// Close the dialog window
setDialog1Open(false);
// If the user inputs the same token, we want to switch the data in the fields
if (address === coin2.address) {
switchFields();
}
// We only update the values if the user provides a token
else if (address) {
// Getting some token data is async, so we need to wait for the data to return, hence the promise
getBalanceAndSymbol(props.network.account, address, props.network.provider, props.network.signer, props.network.weth.address, props.network.coins).then((data) => {
setCoin1({
address: address,
symbol: data.symbol,
balance: data.balance,
});
});
}
};
// Called when the dialog window for coin2 exits
const onToken2Selected = (address) => {
// Close the dialog window
setDialog2Open(false);
// If the user inputs the same token, we want to switch the data in the fields
if (address === coin1.address) {
switchFields();
}
// We only update the values if the user provides a token
else if (address) {
// Getting some token data is async, so we need to wait for the data to return, hence the promise
getBalanceAndSymbol(props.network.account, address, props.network.provider, props.network.signer, props.network.weth.address, props.network.coins).then((data) => {
setCoin2({
address: address,
symbol: data.symbol,
balance: data.balance,
});
});
}
};
// Calls the swapTokens Ethereum function to make the swap, then resets nessicary state variables
const swap = () => {
console.log("Attempting to swap tokens...");
setLoading(true);
swapTokens(
coin1.address,
coin2.address,
field1Value,
props.network.router,
props.network.account,
props.network.signer
)
.then(() => {
setLoading(false);
// If the transaction was successful, we clear to input to make sure the user doesn't accidental redo the transfer
setField1Value("");
enqueueSnackbar("Transaction Successful", { variant: "success" });
})
.catch((e) => {
setLoading(false);
enqueueSnackbar("Transaction Failed (" + e.message + ")", {
variant: "error",
autoHideDuration: 10000,
});
});
};
// The lambdas within these useEffects will be called when a particular dependency is updated. These dependencies
// are defined in the array of variables passed to the function after the lambda expression. If there are no dependencies
// the lambda will only ever be called when the component mounts. These are very useful for calculating new values
// after a particular state change, for example, calculating the new exchange rate whenever the addresses
// of the two coins change.
// This hook is called when either of the state variables `coin1.address` or `coin2.address` change.
// This means that when the user selects a different coin to convert between, or the coins are swapped,
// the new reserves will be calculated.
useEffect(() => {
console.log(
"Trying to get Reserves between:\n" + coin1.address + "\n" + coin2.address
);
if (coin1.address && coin2.address) {
getReserves(coin1.address, coin2.address, props.network.factory, props.network.signer, props.network.account).then(
(data) => setReserves(data)
);
}
}, [coin1.address, coin2.address, props.network.account, props.network.factory, props.network.router, props.network.signer]);
// This hook is called when either of the state variables `field1Value` `coin1.address` or `coin2.address` change.
// It attempts to calculate and set the state variable `field2Value`
// This means that if the user types a new value into the conversion box or the conversion rate changes,
// the value in the output box will change.
useEffect(() => {
if (isNaN(parseFloat(field1Value))) {
setField2Value("");
} else if (parseFloat(field1Value) && coin1.address && coin2.address) {
getAmountOut(coin1.address, coin2.address, field1Value, props.network.router, props.network.signer).then(
(amount) => setField2Value(amount.toFixed(7))
).catch(e => {
console.log(e);
setField2Value("NA");
})
} else {
setField2Value("");
}
}, [field1Value, coin1.address, coin2.address]);
// This hook creates a timeout that will run every ~10 seconds, it's role is to check if the user's balance has
// updated has changed. This allows them to see when a transaction completes by looking at the balance output.
useEffect(() => {
const coinTimeout = setTimeout(() => {
console.log('props: ', props);
console.log("Checking balances...");
if (coin1.address && coin2.address && props.network.account) {
getReserves(
coin1.address,
coin2.address,
props.network.factory,
props.network.signer,
props.network.account
).then((data) => setReserves(data));
}
if (coin1.address && props.network.account &&!wrongNetworkOpen) {
getBalanceAndSymbol(
props.network.account,
coin1.address,
props.network.provider,
props.network.signer,
props.network.weth.address,
props.network.coins
).then(
(data) => {
setCoin1({
...coin1,
balance: data.balance,
});
}
);
}
if (coin2.address && props.network.account &&!wrongNetworkOpen) {
getBalanceAndSymbol(
props.network.account,
coin2.address,
props.network.provider,
props.network.signer,
props.network.weth.address,
props.network.coins
).then(
(data) => {
setCoin2({
...coin2,
balance: data.balance,
});
}
);
}
}, 10000);
return () => clearTimeout(coinTimeout);
});
return (
<div>
{/* Dialog Windows */}
<CoinDialog
open={dialog1Open}
onClose={onToken1Selected}
coins={props.network.coins}
props={props.network.signer}
/>
<CoinDialog
open={dialog2Open}
onClose={onToken2Selected}
coins={props.network.coins}
signer={props.network.signer}
/>
<WrongNetwork
open={wrongNetworkOpen}
/>
{/* Coin Swapper */}
<Container maxWidth="xs">
<Paper className={classes.paperContainer}>
<Typography variant="h5" className={classes.title}>
Swap Coins
</Typography>
<Grid container direction="column" alignItems="center" spacing={2}>
<Grid item xs={12} className={classes.fullWidth}>
<CoinField
activeField={true}
value={field1Value}
onClick={() => setDialog1Open(true)}
onChange={handleChange.field1}
symbol={coin1.symbol !== undefined ? coin1.symbol : "Select"}
/>
</Grid>
<IconButton onClick={switchFields} className={classes.switchButton}>
<SwapVerticalCircleIcon fontSize="medium" />
</IconButton>
<Grid item xs={12} className={classes.fullWidth}>
<CoinField
activeField={false}
value={field2Value}
onClick={() => setDialog2Open(true)}
symbol={coin2.symbol !== undefined ? coin2.symbol : "Select"}
/>
</Grid>
<hr className={classes.hr} />
{/* Balance Display */}
<Typography variant="h6">Your Balances</Typography>
<Grid container direction="row" justifyContent="space-between">
<Grid item xs={6}>
<Typography variant="body1" className={classes.balance}>
{formatBalance(coin1.balance, coin1.symbol)}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1" className={classes.balance}>
{formatBalance(coin2.balance, coin2.symbol)}
</Typography>
</Grid>
</Grid>
<hr className={classes.hr} />
{/* Reserves Display */}
<Typography variant="h6">Reserves</Typography>
<Grid container direction="row" justifyContent="space-between">
<Grid item xs={6}>
<Typography variant="body1" className={classes.balance}>
{formatReserve(reserves[0], coin1.symbol)}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body1" className={classes.balance}>
{formatReserve(reserves[1], coin2.symbol)}
</Typography>
</Grid>
</Grid>
<hr className={classes.hr} />
<LoadingButton
loading={loading}
valid={isButtonEnabled()}
success={false}
fail={false}
onClick={swap}
>
<LoopIcon />
Swap
</LoadingButton>
</Grid>
</Paper>
</Container>
<Grid
container
className={classes.footer}
direction="row"
justifyContent="center"
alignItems="flex-end"
>
<p>
Alternative Uniswap Interface | Get AUT for use in the bakerloo testnet{" "}
<a href="https://faucet.bakerloo.autonity.network/">here</a>
</p>
</Grid>
</div>
);
}
Example #28
Source File: deeplink.js From ltijs-demo-client with Apache License 2.0 | 4 votes |
export default function App () {
const classes = useStyles()
const { enqueueSnackbar } = useSnackbar()
const [resource, setResource] = useState(false)
const [dataset, setDataset] = useState([])
const [selected, setSelected] = useState([])
const getLtik = () => {
const searchParams = new URLSearchParams(window.location.search)
const ltik = searchParams.get('ltik')
if (!ltik) throw new Error('Missing lti key.')
return ltik
}
const errorPrompt = async (message) => {
enqueueSnackbar(message, { variant: 'error' })
}
// Retrieves resource dataset
useEffect(() => {
const fetchResources = async () => {
try {
const resources = await ky.get('/resources', { credentials: 'include', headers: { Authorization: 'Bearer ' + getLtik() } }).json()
setDataset(resources)
} catch (err) {
console.log(err)
errorPrompt('Failed retrieving example resources! ' + err)
}
}
fetchResources()
}, [])
// Submits resource to deep linking endpoint
const submit = async () => {
try {
if (resource === false) {
errorPrompt('Please select a resource.')
return
}
const form = await ky.post('/deeplink', { credentials: 'include', json: dataset[resource], headers: { Authorization: 'Bearer ' + getLtik() } }).text()
$('body').append(form)
} catch (err) {
console.log(err)
errorPrompt('Failed creating deep link! ' + err)
}
}
// Configuring data table
const columns = [
{
name: 'name',
label: 'Name'
},
{
name: 'value',
label: 'Value'
}
]
const options = {
filterType: 'checkbox',
selectableRows: 'single',
disableToolbarSelect: true,
download: false,
print: false,
searchOpen: false,
search: false,
viewColumns: false,
filter: false,
selectableRowsOnClick: true,
onRowsSelect: (selResource, allRows) => { setResource(selResource[0].dataIndex); setSelected(allRows.map(row => row.dataIndex)) },
rowsSelected: selected,
rowsPerPage: 5,
responsive: 'scrollFullHeight'
}
return (
<Container component='main' maxWidth='lg'>
<CssBaseline />
<div className={classes.paper}>
<Grid container>
<Grid item xs={12} className={classes.table}>
<MUIDataTable
title='Example custom resources:'
data={dataset}
columns={columns}
options={options}
/>
<Grid item xs className={classes.btnDiv}>
<Fab variant='extended' color='primary' aria-label='add' className={classes.fab} onClick={submit}>
<NavigationIcon className={classes.extendedIcon} />
Submit
</Fab>
</Grid>
</Grid>
</Grid>
</div>
{/* <Box mt={8}>
<Copyright />
</Box> */}
</Container>
)
}
Example #29
Source File: ClusterDetail.js From management-center with Apache License 2.0 | 4 votes |
ClusterDetail = (props) => {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const [editMode, setEditMode] = React.useState(false);
const [selectNodeDialogOpen, setSelectNodeDialogOpen] = React.useState(false);
const [progressDialogOpen, setProgressDialogOpen] = React.useState(false);
const { enqueueSnackbar } = useSnackbar();
const { cluster } = props;
const [updatedCluster, setUpdatedCluster] = React.useState({
...cluster,
});
const context = useContext(WebSocketContext);
const dispatch = useDispatch();
const confirm = useConfirm();
const { client: brokerClient } = context;
const validate = () => {
if (editMode) {
return updatedCluster.clustername !== '';
}
};
const addNodeToCluster = async (node) => {
setSelectNodeDialogOpen(false);
setProgressDialogOpen(true);
try {
await brokerClient.joinCluster(cluster.clustername, node);
enqueueSnackbar('Node successfully added to cluster', {
variant: 'success'
});
const clusterObject = await brokerClient.getCluster(cluster.clustername);
dispatch(updateCluster(clusterObject));
setUpdatedCluster({
...clusterObject
});
const clusters = await brokerClient.listClusters();
dispatch(updateClusters(clusters));
} catch (error) {
enqueueSnackbar(`Error adding node "${node.nodeId}" to cluster. Reason: ${error.message || error}`, {
variant: 'error'
});
}
setProgressDialogOpen(false);
}
const removeNodeFromCluster = async (nodeId) => {
await confirm({
title: 'Confirm node removal',
description: `Do you really want to remove the node "${nodeId}" from this cluster?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
setProgressDialogOpen(true);
try {
await brokerClient.leaveCluster(cluster.clustername, nodeId);
enqueueSnackbar('Node successfully removed from cluster', {
variant: 'success'
});
const clusterObject = await brokerClient.getCluster(cluster.clustername);
dispatch(updateCluster(clusterObject));
setUpdatedCluster({
...clusterObject
});
const clusters = await brokerClient.listClusters();
dispatch(updateClusters(clusters));
} catch (error) {
enqueueSnackbar(`Error removing node "${nodeId}" from cluster. Reason: ${error.message || error}`, {
variant: 'error'
});
}
setProgressDialogOpen(false);
}
const onUpdateClusterDetail = async () => {
await brokerClient.modifyCluster(updatedCluster);
enqueueSnackbar('Cluster successfully updated', {
variant: 'success'
});
const clusterObject = await brokerClient.getCluster(updatedCluster.clustername);
dispatch(updateCluster(clusterObject));
const clusters = await brokerClient.listClusters();
dispatch(updateClusters(clusters));
setEditMode(false);
};
const onEnableLTS = async (cluster, node) => {
// TODO
};
const onDisableLTS = async (cluster, node) => {
// TODO
};
const onCancelEdit = async () => {
await confirm({
title: 'Cancel cluster editing',
description: `Do you really want to cancel editing this cluster?`,
cancellationButtonProps: {
variant: 'contained'
},
confirmationButtonProps: {
color: 'primary',
variant: 'contained'
}
});
setUpdatedCluster({
...cluster
});
setEditMode(false);
};
return cluster ? (<div>
<Breadcrumbs aria-label="breadcrumb">
<RouterLink className={classes.breadcrumbLink} to="/home">
Home
</RouterLink>
<RouterLink className={classes.breadcrumbLink} color="inherit" to="/admin">
Admin
</RouterLink>
<RouterLink className={classes.breadcrumbLink} to="/admin/clusters">
Clusters
</RouterLink>
<Typography className={classes.breadcrumbItem} color="textPrimary">
{cluster.clustername}
</Typography>
</Breadcrumbs>
<br />
<Paper className={classes.paper}>
<form className={classes.form} noValidate autoComplete="off">
<div className={classes.margin}>
<Grid container spacing={1} alignItems="flex-end">
<Grid item xs={12} sm={4}>
<TextField
required={editMode}
disabled={true}
id="clustername"
label="Clustername"
value={updatedCluster?.clustername}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
<Grid item xs={12} sm={8}>
<TextField
disabled={!editMode}
id="description"
label="Description"
value={updatedCluster?.description}
onChange={(event) => {
if (editMode) {
setUpdatedCluster({
...updatedCluster,
description: event.target.value
});
}
}}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
<br />
</Grid>
<br />
<Grid container spacing={1} alignItems="flex-end">
{cluster?.nodes?.map((node, index) =>
<Grid item xs={12} md={4}>
<Card variant="outlined">
<CardHeader
avatar={getNodeIcon(node)}
subheader={node.broker}
/>
<CardContent>
<Grid container spacing={1} alignItems="flex-end">
<Grid item xs={12}>
<TextField
disabled={true}
id={node?.nodeId}
label="Node ID"
value={node?.nodeId}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
<Grid item xs={12}>
<TextField
disabled={true}
id={node?.address}
label="Address"
value={node?.address}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
<Grid item xs={12}>
<TextField
disabled={true}
label="Port"
value={node?.port}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
{/* <Grid item xs={12}>
<TextField
disabled={true}
id={`${node.id}-redis-hostname`}
label="Redis Host"
value={node.ha?.backendhosts[0]?.hostname}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid>
<Grid item xs={12}>
<TextField
disabled={true}
id={`${node.id}-redis-port`}
label="Redis Port"
value={node.ha?.backendhosts[0]?.port}
defaultValue=""
variant="outlined"
fullWidth
className={classes.textField}
/>
</Grid> */}
{/* <Grid item xs={12}>
<Tooltip title="Use LTS">
<FormControlLabel
disabled={!editMode}
control={
<Switch
disabled={!editMode}
checked={
node.ha?.uselts
}
onClick={(event) => {
event.stopPropagation();
if (event.target.checked) {
onEnableLTS(cluster, node);
} else {
onDisableLTS(cluster, node);
}
}}
/>
}
label="Use LTS"
/>
</Tooltip>
</Grid> */}
</Grid>
</CardContent>
<CardActions>
<Button
disabled={!editMode || cluster?.nodes?.length <= 3}
size="small"
onClick={() => removeNodeFromCluster(node.broker)}
startIcon={<RemoveNodeIcon />}
>
Remove
</Button>
</CardActions>
</Card>
</Grid>
)}
</Grid>
</div>
</form>
{!editMode && (
<Grid item xs={12} className={classes.buttons}>
<Button
variant="contained"
color="primary"
className={classes.button}
startIcon={<EditIcon />}
onClick={() => setEditMode(true)}
>
Edit
</Button>
</Grid>
)}
{editMode && (
<>
<Grid item xs={12} className={classes.buttons}>
<Button
variant="contained"
color="primary"
className={classes.button}
startIcon={<AddIcon />}
onClick={() => setSelectNodeDialogOpen(true)}
>
Add node
</Button>
</Grid>
<Grid item xs={12} className={classes.buttons}>
<Button
variant="contained"
disabled={!validate()}
color="primary"
className={classes.button}
startIcon={<SaveIcon />}
onClick={(event) => {
event.stopPropagation();
onUpdateClusterDetail();
}}
>
Save
</Button>
<Button
variant="contained"
onClick={(event) => {
event.stopPropagation();
onCancelEdit();
}}
>
Cancel
</Button>
</Grid>
</>
)}
<SelectNodeDialog
open={selectNodeDialogOpen}
handleClose={() => setSelectNodeDialogOpen(false)}
handleAddNode={(node) => addNodeToCluster(node)}
cluster={cluster}
/>
<WaitDialog
title='Update process of your cluster is in process'
open={progressDialogOpen}
handleClose={() => setProgressDialogOpen(false)}
/>
</Paper>
</div>) : (
<Redirect to="/admin/clusters" push />
);
}