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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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:&nbsp;
        {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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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:&nbsp;</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:&nbsp;
                      </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:&nbsp;
                      </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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 />
	);
}