react-icons/fa#FaTrashAlt TypeScript Examples

The following examples show how to use react-icons/fa#FaTrashAlt. 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: Page.tsx    From freedeck-configurator with GNU General Public License v3.0 5 votes vote down vote up
PageComponent: React.FC<IProps> = ({
  brightness,
  pageIndex,
  deleteImage,
  makeDefaultBackImage,
  originalImages,
  width,
  height,
  convertedImages,
  setOriginalImage,
  buttonSettingsPages,
  displaySettingsPages,
  deletePage,
  addPage,
  setButtonSettings,
  setDisplaySettings,
  pageCount,
  switchDisplays,
}) => {
  return (
    <Wrapper id={`page_${pageIndex}`}>
      <Header>
        <PageIndicator>{pageIndex}</PageIndicator>
        <DeletePage
          onClick={() => {
            const deleteConfirmed = window.confirm(
              "Do you really want to delete this page forever?"
            );
            if (deleteConfirmed) deletePage(pageIndex);
          }}
        >
          <FaTrashAlt size={18} color="white" />
        </DeletePage>
      </Header>
      <Grid height={height} width={width}>
        <DndProvider backend={Backend}>
          {displaySettingsPages.map((imageDisplay, displayIndex) => (
            <Display
              brightness={brightness}
              deleteImage={() => deleteImage(displayIndex)}
              makeDefaultBackImage={() => makeDefaultBackImage(displayIndex)}
              convertedImage={
                convertedImages?.[displayIndex] ?? getEmptyConvertedImage()
              }
              setButtonSettings={(displayAction) =>
                setButtonSettings(displayIndex, displayAction)
              }
              setDisplaySettings={(displayImage) =>
                setDisplaySettings(displayIndex, displayImage)
              }
              actionDisplay={buttonSettingsPages[displayIndex]}
              imageDisplay={displaySettingsPages[displayIndex]}
              key={displayIndex}
              displayIndex={displayIndex}
              pageIndex={pageIndex}
              setOriginalImage={(image) =>
                setOriginalImage(displayIndex, image)
              }
              pages={[...Array(pageCount).keys()].filter(
                (pageNumber) => pageNumber !== pageIndex
              )}
              addPage={(primary: boolean) => addPage(displayIndex, primary)}
              originalImage={originalImages[displayIndex]}
              switchDisplays={switchDisplays}
            />
          ))}
        </DndProvider>
      </Grid>
    </Wrapper>
  );
}
Example #2
Source File: Card.tsx    From hub with Apache License 2.0 4 votes vote down vote up
RepositoryCard = (props: Props) => {
  const history = useHistory();
  const { ctx } = useContext(AppCtx);
  const [dropdownMenuStatus, setDropdownMenuStatus] = useState<boolean>(false);
  const [transferModalStatus, setTransferModalStatus] = useState<boolean>(false);
  const [deletionModalStatus, setDeletionModalStatus] = useState<boolean>(false);
  const [badgeModalStatus, setBadgeModalStatus] = useState<boolean>(false);
  const dropdownMenu = useRef(null);
  const organizationName = ctx.prefs.controlPanel.selectedOrg;
  const hasErrors = !isUndefined(props.repository.lastTrackingErrors) && !isNull(props.repository.lastTrackingErrors);
  const hasScanningErrors =
    !isUndefined(props.repository.lastScanningErrors) && !isNull(props.repository.lastScanningErrors);
  const [openErrorsModal, setOpenErrorsModal] = useState<boolean>(false);
  const [openScanningErrorsModal, setOpenScanningErrorsModal] = useState<boolean>(false);

  const closeDropdown = () => {
    setDropdownMenuStatus(false);
  };

  useOutsideClick([dropdownMenu], dropdownMenuStatus, closeDropdown);

  useEffect(() => {
    if (props.visibleModal) {
      if (props.visibleModal === 'scanning') {
        setOpenScanningErrorsModal(true);
      } else {
        setOpenErrorsModal(true);
      }
      history.replace({
        search: '',
      });
    }
  }, []); /* eslint-disable-line react-hooks/exhaustive-deps */

  const getLastTracking = (): JSX.Element => {
    const nextCheckTime: number = minutesToNearestInterval(30);

    if (isUndefined(props.repository.lastTrackingTs) || isNull(props.repository.lastTrackingTs)) {
      return (
        <>
          Not processed yet
          {props.repository.disabled
            ? '.'
            : nextCheckTime > 0
            ? `, it will be processed automatically in ~ ${nextCheckTime} minutes`
            : ', it will be processed automatically in less than 30 minutes'}
        </>
      );
    }

    const content = (
      <>
        {!isFuture(props.repository.lastTrackingTs!) && (
          <span>{moment.unix(props.repository.lastTrackingTs!).fromNow()}</span>
        )}
        {hasErrors ? (
          <>
            <FaExclamation className="mx-1 text-warning" />
            <RepositoryWarningModal />
          </>
        ) : (
          <FaCheck className="mx-1 text-success" />
        )}
      </>
    );

    let nextCheckMsg: string = '';
    if (nextCheckTime > 0 && !props.repository.disabled) {
      nextCheckMsg = `(it will be checked for updates again in ~ ${nextCheckTime} minutes)`;
    }

    if (hasErrors) {
      return (
        <>
          {content}
          <Modal
            modalDialogClassName={styles.modalDialog}
            modalClassName="mh-100"
            className={`d-inline-block ${styles.modal}`}
            buttonType={`ms-1 btn badge btn-outline-secondary ${styles.btn}`}
            buttonContent={
              <div className="d-flex flex-row align-items-center">
                <HiExclamation className="me-2" />
                <span className="d-none d-xl-inline d-xxl-none d-xxxl-inline">Show tracking errors log</span>
                <span className="d-inline d-xl-none d-xxl-inline d-xxxl-none">Logs</span>
              </div>
            }
            header={
              <div className={`h3 m-2 flex-grow-1 text-truncate ${styles.title}`}>
                Tracking errors log - {props.repository.displayName || props.repository.name}
              </div>
            }
            open={openErrorsModal}
            onClose={() => setOpenErrorsModal(false)}
            footerClassName={styles.modalFooter}
          >
            <div className="d-flex h-100 mw-100 overflow-hidden">
              <div className="d-flex flex-column w-100">
                <div className={`mb-2 ${styles.trackingTime}`}>
                  {moment.unix(props.repository.lastTrackingTs!).format('llll Z')}
                </div>
                <div
                  className={`position-relative flex-grow-1 mw-100 mh-100 overflow-hidden ${styles.modalSyntaxTrackerWrapper}`}
                >
                  {props.repository.lastTrackingErrors && (
                    <SyntaxHighlighter
                      language="bash"
                      style={tomorrowNight}
                      customStyle={{ fontSize: '90%', height: '100%' }}
                    >
                      {props.repository.lastTrackingErrors}
                    </SyntaxHighlighter>
                  )}
                </div>
              </div>
            </div>
          </Modal>
          <span className="ms-3 fst-italic text-muted">{nextCheckMsg}</span>
        </>
      );
    } else {
      return (
        <>
          {content}
          {openErrorsModal && (
            <Modal
              className={`d-inline-block ${styles.modal}`}
              header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Tracking errors log</div>}
              open
            >
              <div className="h5 text-center my-5 mw-100">
                It looks like the last tracking of this repository worked fine and no errors were produced.
                <br />
                <br />
                If you have arrived to this screen from an email listing some errors, please keep in mind those may have
                been already solved.
              </div>
            </Modal>
          )}
          <span className="ms-1 fst-italic text-muted">{nextCheckMsg}</span>
        </>
      );
    }
  };

  const getLastScanning = (): JSX.Element => {
    const nextCheckTime: number = minutesToNearestInterval(30, 15);

    if (
      props.repository.scannerDisabled ||
      isUndefined(props.repository.lastTrackingTs) ||
      isNull(props.repository.lastTrackingTs)
    )
      return <>-</>;

    if (isUndefined(props.repository.lastScanningTs) || isNull(props.repository.lastScanningTs)) {
      return (
        <>
          Not scanned yet
          {props.repository.disabled
            ? '.'
            : nextCheckTime > 0
            ? `, it will be scanned for security vulnerabilities in ~ ${nextCheckTime} minutes`
            : ', it will be scanned for security vulnerabilities in less than 30 minutes'}
        </>
      );
    }

    const content = (
      <>
        {!isFuture(props.repository.lastScanningTs!) && (
          <span>{moment.unix(props.repository.lastScanningTs!).fromNow()}</span>
        )}
        {hasScanningErrors ? (
          <FaExclamation className="mx-2 text-warning" />
        ) : (
          <FaCheck className="mx-2 text-success" />
        )}
      </>
    );

    let nextCheckMsg: string = '';
    if (nextCheckTime > 0 && !props.repository.disabled) {
      nextCheckMsg = `(it will be checked for updates again in ~ ${nextCheckTime} minutes)`;
    }

    if (hasScanningErrors) {
      return (
        <>
          {content}
          <Modal
            modalDialogClassName={styles.modalDialog}
            modalClassName="mh-100"
            className={`d-inline-block ${styles.modal}`}
            buttonType={`ms-1 btn badge btn-outline-secondary ${styles.btn}`}
            buttonContent={
              <div className="d-flex flex-row align-items-center">
                <HiExclamation className="me-2" />
                <span className="d-none d-sm-inline">Show scanning errors log</span>
                <span className="d-inline d-sm-none">Logs</span>
              </div>
            }
            header={
              <div className={`h3 m-2 flex-grow-1 text-truncate ${styles.title}`}>
                Scanning errors log - {props.repository.displayName || props.repository.name}
              </div>
            }
            open={openScanningErrorsModal}
            onClose={() => setOpenErrorsModal(false)}
            footerClassName={styles.modalFooter}
          >
            <div className="d-flex h-100 mw-100 overflow-hidden">
              <div className={`d-flex overflow-scroll ${styles.modalSyntaxWrapper}`}>
                {props.repository.lastScanningErrors && (
                  <SyntaxHighlighter
                    language="bash"
                    style={tomorrowNight}
                    customStyle={{ fontSize: '90%', height: '100%', marginBottom: '0' }}
                  >
                    {props.repository.lastScanningErrors}
                  </SyntaxHighlighter>
                )}
              </div>
            </div>
          </Modal>
          <span className="ms-3 fst-italic text-muted">{nextCheckMsg}</span>
        </>
      );
    } else {
      return (
        <>
          {content}
          {openScanningErrorsModal && (
            <Modal
              className={`d-inline-block ${styles.modal}`}
              header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Scanning errors log</div>}
              open
            >
              <div className="h5 text-center my-5 mw-100">
                It looks like the last security vulnerabilities scan of this repository worked fine and no errors were
                produced.
                <br />
                <br />
                If you have arrived to this screen from an email listing some errors, please keep in mind those may have
                been already solved.
              </div>
            </Modal>
          )}
          <span className="ms-1 fst-italic text-muted">{nextCheckMsg}</span>
        </>
      );
    }
  };

  return (
    <div className="col-12 col-xxl-6 py-sm-3 py-2 px-0 px-xxl-3" data-testid="repoCard">
      <div className="card h-100">
        <div className="card-body d-flex flex-column h-100">
          <div className="d-flex flex-row w-100 justify-content-between">
            <div className={`text-truncate h5 mb-0 ${styles.titleCard}`}>
              {props.repository.displayName || props.repository.name}
            </div>

            <OfficialBadge
              official={props.repository.official}
              className={`ms-3 d-none d-md-inline ${styles.labelWrapper}`}
              type="repo"
            />

            <VerifiedPublisherBadge
              verifiedPublisher={props.repository.verifiedPublisher}
              className={`ms-3 d-none d-md-inline ${styles.labelWrapper}`}
            />

            <DisabledRepositoryBadge
              disabled={props.repository.disabled!}
              className={`ms-3 d-none d-md-inline ${styles.labelWrapper}`}
            />

            <ScannerDisabledRepositoryBadge
              scannerDisabled={props.repository.scannerDisabled!}
              className={`ms-3 d-none d-md-inline ${styles.labelWrapper}`}
            />

            {transferModalStatus && (
              <TransferRepositoryModal
                open={true}
                repository={props.repository}
                onSuccess={props.onSuccess}
                onAuthError={props.onAuthError}
                onClose={() => setTransferModalStatus(false)}
              />
            )}

            {deletionModalStatus && (
              <DeletionModal
                repository={props.repository}
                organizationName={organizationName}
                setDeletionModalStatus={setDeletionModalStatus}
                onSuccess={props.onSuccess}
                onAuthError={props.onAuthError}
              />
            )}

            {badgeModalStatus && (
              <BadgeModal
                repository={props.repository}
                onClose={() => setBadgeModalStatus(false)}
                open={badgeModalStatus}
              />
            )}

            <div className="ms-auto ps-3">
              <RepositoryIconLabel kind={props.repository.kind} isPlural />
            </div>

            <div className="ms-3">
              <div
                ref={dropdownMenu}
                className={classnames('dropdown-menu dropdown-menu-end p-0', styles.dropdownMenu, {
                  show: dropdownMenuStatus,
                })}
              >
                <div className={`dropdown-arrow ${styles.arrow}`} />

                <button
                  className="dropdown-item btn btn-sm rounded-0 text-dark"
                  onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
                    e.preventDefault();
                    closeDropdown();
                    setBadgeModalStatus(true);
                  }}
                  aria-label="Open badge modal"
                >
                  <div className="d-flex flex-row align-items-center">
                    <MdLabel className={`me-2 ${styles.btnIcon}`} />
                    <span>Get badge</span>
                  </div>
                </button>

                <ActionBtn
                  className="dropdown-item btn btn-sm rounded-0 text-dark"
                  onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
                    e.preventDefault();
                    closeDropdown();
                    setTransferModalStatus(true);
                  }}
                  action={AuthorizerAction.TransferOrganizationRepository}
                  label="Open transfer repository modal"
                >
                  <>
                    <RiArrowLeftRightLine className={`me-2 ${styles.btnIcon}`} />
                    <span>Transfer</span>
                  </>
                </ActionBtn>

                <ActionBtn
                  className="dropdown-item btn btn-sm rounded-0 text-dark"
                  onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
                    e.preventDefault();
                    closeDropdown();
                    props.setModalStatus({
                      open: true,
                      repository: props.repository,
                    });
                  }}
                  action={AuthorizerAction.UpdateOrganizationRepository}
                  label="Open update repository modal"
                >
                  <>
                    <FaPencilAlt className={`me-2 ${styles.btnIcon}`} />
                    <span>Edit</span>
                  </>
                </ActionBtn>

                <ActionBtn
                  className="dropdown-item btn btn-sm rounded-0 text-dark"
                  onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
                    e.preventDefault();
                    closeDropdown();
                    setDeletionModalStatus(true);
                  }}
                  action={AuthorizerAction.DeleteOrganizationRepository}
                  label="Open delete repository modal"
                >
                  <>
                    <FaTrashAlt className={`me-2 ${styles.btnIcon}`} />
                    <span>Delete</span>
                  </>
                </ActionBtn>
              </div>

              <button
                className={`btn btn-outline-secondary rounded-circle p-0 text-center ${styles.btnDropdown}`}
                onClick={() => setDropdownMenuStatus(true)}
                aria-label="Open menu"
                aria-expanded={dropdownMenuStatus}
              >
                <BsThreeDotsVertical />
              </button>
            </div>
          </div>
          {props.repository.repositoryId && (
            <div className="mt-2 d-flex flex-row align-items-baseline">
              <div className="text-truncate">
                <small className="text-muted text-uppercase me-1">ID: </small>
                <small>{props.repository.repositoryId}</small>
              </div>
              <div className={`ms-1 ${styles.copyBtn}`}>
                <div className={`position-absolute ${styles.copyBtnWrapper}`}>
                  <ButtonCopyToClipboard
                    text={props.repository.repositoryId}
                    className="btn-link border-0 text-dark fw-bold"
                    label="Copy repository ID to clipboard"
                  />
                </div>
              </div>
            </div>
          )}
          <div className="text-truncate">
            <small className="text-muted text-uppercase me-1">Url: </small>
            <small>{props.repository.url}</small>
          </div>
          <div>
            <small className="text-muted text-uppercase me-1">Last processed: </small>
            <small>{getLastTracking()}</small>
          </div>
          <div>
            <small className="text-muted text-uppercase me-1">Last security scan: </small>
            <small>{getLastScanning()}</small>
          </div>

          <div className="mt-3 m-md-0 d-flex flex-row d-md-none">
            <OfficialBadge official={props.repository.official} className="me-3" type="repo" />
            <VerifiedPublisherBadge verifiedPublisher={props.repository.verifiedPublisher} className="me-3" />
            <DisabledRepositoryBadge disabled={props.repository.disabled!} />
          </div>
        </div>
      </div>
    </div>
  );
}
Example #3
Source File: DeletionModal.tsx    From hub with Apache License 2.0 4 votes vote down vote up
DeletionModal = (props: Props) => {
  const [isDeleting, setIsDeleting] = useState(false);
  const [isValidInput, setIsValidInput] = useState<boolean>(false);

  const onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
    setIsValidInput(e.target.value === props.repository.name);
  };

  async function deleteRepository() {
    try {
      setIsDeleting(true);
      await API.deleteRepository(props.repository.name, props.organizationName);
      setIsDeleting(false);
      props.onSuccess();
    } catch (err: any) {
      setIsDeleting(false);
      if (err.kind === ErrorKind.Unauthorized) {
        props.onAuthError();
      } else {
        let errorMessage = 'An error occurred deleting the repository, please try again later.';
        if (!isUndefined(props.organizationName) && err.kind === ErrorKind.Forbidden) {
          errorMessage = 'You do not have permissions to delete the repository from the organization.';
        }
        alertDispatcher.postAlert({
          type: 'danger',
          message: errorMessage,
        });
      }
    }
  }

  return (
    <Modal
      className="d-inline-block"
      closeButton={
        <>
          <button
            className="btn btn-sm btn-outline-secondary text-uppercase"
            onClick={() => props.setDeletionModalStatus(false)}
            aria-label="Cancel"
          >
            <div className="d-flex flex-row align-items-center">
              <IoMdCloseCircle className="me-2" />
              <span>Cancel</span>
            </div>
          </button>

          <button
            className="btn btn-sm btn-danger ms-3"
            onClick={(e) => {
              e.preventDefault();
              deleteRepository();
            }}
            disabled={isDeleting || !isValidInput}
            aria-label="Delete repository"
          >
            <div className="d-flex flex-row align-items-center text-uppercase">
              {isDeleting ? (
                <>
                  <span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
                  <span className="ms-2">Deleting...</span>
                </>
              ) : (
                <>
                  <FaTrashAlt className="me-2" />
                  <span>Delete</span>
                </>
              )}
            </div>
          </button>
        </>
      }
      header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Delete repository</div>}
      onClose={() => props.setDeletionModalStatus(false)}
      open
    >
      <div className="mw-100">
        <div className="alert alert-warning my-4">
          <span className="fw-bold text-uppercase">Important:</span> Please read this carefully.
        </div>

        <p>If you delete this repository all packages belonging to it will be deleted.</p>

        <p>
          All information related to your repository or packages will be permanently deleted as well. This includes
          packages' stars, users subscriptions to packages, webhooks, events and notifications.
        </p>

        <p>
          <span className="fw-bold">This operation cannot be undone</span>.
        </p>

        <p>
          Please type <span className="fw-bold">{props.repository.name}</span> to confirm:
        </p>

        <InputField type="text" name="repoName" autoComplete="off" value="" onChange={onInputChange} />
      </div>
    </Modal>
  );
}
Example #4
Source File: DeleteOrg.tsx    From hub with Apache License 2.0 4 votes vote down vote up
DeleteOrganization = (props: Props) => {
  const { dispatch } = useContext(AppCtx);
  const [openStatus, setOpenStatus] = useState<boolean>(false);
  const [isDeleting, setIsDeleting] = useState(false);
  const [isValidInput, setIsValidInput] = useState<boolean>(false);

  const onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
    setIsValidInput(e.target.value === props.organization.name);
  };

  async function deleteOrganization() {
    try {
      setIsDeleting(true);
      await API.deleteOrganization(props.organization.name);
      dispatch(unselectOrg());
      window.scrollTo(0, 0); // Scroll to top when org is deleted
      setIsDeleting(false);
    } catch (err: any) {
      setIsDeleting(false);
      if (err.kind === ErrorKind.Unauthorized) {
        props.onAuthError();
      } else {
        let errorMessage = 'An error occurred deleting the organization, please try again later.';
        if (err.kind === ErrorKind.Forbidden) {
          errorMessage = 'You do not have permissions to delete the organization.';
        }
        alertDispatcher.postAlert({
          type: 'danger',
          message: errorMessage,
        });
      }
    }
  }

  return (
    <>
      <div className="mt-4 mt-md-5">
        <p className="mb-4">
          Deleting your organization will also delete all the content that belongs to it. Please be certain as{' '}
          <span className="fw-bold">this operation cannot be undone</span>.
        </p>

        <ActionBtn
          className="btn btn-sm btn-danger"
          onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
            e.preventDefault();
            setOpenStatus(true);
          }}
          action={AuthorizerAction.DeleteOrganization}
          label="Open delete organization modal"
        >
          <div className="d-flex flex-row align-items-center text-uppercase">
            <FaTrashAlt className="me-2" />
            <div>Delete organization</div>
          </div>
        </ActionBtn>
      </div>

      <Modal
        className="d-inline-block"
        closeButton={
          <>
            <button
              className="btn btn-sm btn-outline-secondary text-uppercase"
              onClick={() => setOpenStatus(false)}
              aria-label="Close"
            >
              <div className="d-flex flex-row align-items-center">
                <IoMdCloseCircle className="me-2" />
                <span>Cancel</span>
              </div>
            </button>

            <button
              className="btn btn-sm btn-danger ms-3"
              onClick={(e) => {
                e.preventDefault();
                deleteOrganization();
              }}
              disabled={isDeleting || !isValidInput}
              aria-label="Delete organization"
            >
              <div className="d-flex flex-row align-items-center text-uppercase">
                {isDeleting ? (
                  <>
                    <span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
                    <span className="ms-2">Deleting...</span>
                  </>
                ) : (
                  <>
                    <FaTrashAlt className="me-2" />
                    <span>Delete</span>
                  </>
                )}
              </div>
            </button>
          </>
        }
        header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Delete organization</div>}
        onClose={() => setOpenStatus(false)}
        open={openStatus}
      >
        <div className="mw-100">
          <div className="alert alert-warning my-4">
            <span className="fw-bold text-uppercase">Important:</span> Please read this carefully.
          </div>

          <p>
            If you delete this organization all repositories belonging to it will be deleted. Please consider
            transferring them to another organization or your personal account.
          </p>
          <p>
            All information related to the repositories will be permanently deleted as well. This includes packages,
            stars, users subscriptions, webhooks, events and notifications. Some of this information was created by
            users and will be lost.
          </p>

          <p>
            <span className="fw-bold">This operation cannot be undone</span>.
          </p>

          <p data-testid="confirmationText">
            Please type <span className="fw-bold">{props.organization.name}</span> to confirm:
          </p>

          <InputField type="text" name="orgName" autoComplete="off" value="" onChange={onInputChange} />
        </div>
      </Modal>
    </>
  );
}
Example #5
Source File: Card.tsx    From hub with Apache License 2.0 4 votes vote down vote up
APIKeyCard = (props: Props) => {
  const [isDeleting, setIsDeleting] = useState(false);
  const [dropdownMenuStatus, setDropdownMenuStatus] = useState<boolean>(false);
  const dropdownMenu = useRef(null);
  const [deletionModalStatus, setDeletionModalStatus] = useState<boolean>(false);

  const closeDropdown = () => {
    setDropdownMenuStatus(false);
  };

  useOutsideClick([dropdownMenu], dropdownMenuStatus, closeDropdown);

  async function deleteAPIKey() {
    try {
      setIsDeleting(true);
      await API.deleteAPIKey(props.apiKey.apiKeyId!);
      setIsDeleting(false);
      props.onSuccess();
    } catch (err: any) {
      setIsDeleting(false);
      if (err.kind === ErrorKind.Unauthorized) {
        props.onAuthError();
      } else {
        alertDispatcher.postAlert({
          type: 'danger',
          message: 'An error occurred deleting the API key, please try again later.',
        });
      }
    }
  }

  return (
    <div className="col-12 col-xxl-6 py-sm-3 py-2 px-0 px-xxl-3" data-testid="APIKeyCard">
      <div className="card h-100">
        <div className="card-body d-flex flex-column h-100">
          <div className="d-flex flex-row w-100 justify-content-between">
            <div className={`h5 mb-1 me-2 text-break ${styles.titleCard}`}>{props.apiKey.name}</div>
            {deletionModalStatus && (
              <Modal
                className={`d-inline-block ${styles.modal}`}
                closeButton={
                  <>
                    <button
                      className="btn btn-sm btn-outline-secondary text-uppercase"
                      onClick={() => setDeletionModalStatus(false)}
                      aria-label="Cancel"
                    >
                      <div className="d-flex flex-row align-items-center">
                        <IoMdCloseCircle className="me-2" />
                        <span>Cancel</span>
                      </div>
                    </button>

                    <button
                      className="btn btn-sm btn-danger ms-3"
                      onClick={(e) => {
                        e.preventDefault();
                        closeDropdown();
                        deleteAPIKey();
                      }}
                      disabled={isDeleting}
                      aria-label="Delete API key"
                    >
                      <div className="d-flex flex-row align-items-center text-uppercase">
                        {isDeleting ? (
                          <>
                            <span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
                            <span className="ms-2">Deleting...</span>
                          </>
                        ) : (
                          <>
                            <FaTrashAlt className={`me-2 ${styles.btnDeleteIcon}`} />
                            <span>Delete</span>
                          </>
                        )}
                      </div>
                    </button>
                  </>
                }
                header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Delete API key</div>}
                onClose={() => setDeletionModalStatus(false)}
                open
              >
                <div className="mt-3 mw-100 text-center">
                  <p>Are you sure you want to remove this API key?</p>
                </div>
              </Modal>
            )}

            <div className="ms-auto">
              <div
                ref={dropdownMenu}
                className={classnames('dropdown-menu dropdown-menu-end p-0', styles.dropdownMenu, {
                  show: dropdownMenuStatus,
                })}
              >
                <div className={`dropdown-arrow ${styles.arrow}`} />

                <button
                  className="dropdown-item btn btn-sm rounded-0 text-dark"
                  onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
                    e.preventDefault();
                    closeDropdown();
                    props.setModalStatus({
                      open: true,
                      apiKey: props.apiKey,
                    });
                  }}
                  aria-label="Open API key modal"
                >
                  <div className="d-flex flex-row align-items-center">
                    <FaPencilAlt className={`me-2 ${styles.btnIcon}`} />
                    <span>Edit</span>
                  </div>
                </button>

                <button
                  className="dropdown-item btn btn-sm rounded-0 text-dark"
                  onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
                    e.preventDefault();
                    closeDropdown();
                    setDeletionModalStatus(true);
                  }}
                  aria-label="Open deletion modal"
                >
                  <div className="d-flex flex-row align-items-center">
                    <FaTrashAlt className={`me-2 ${styles.btnIcon}`} />
                    <span>Delete</span>
                  </div>
                </button>
              </div>

              <button
                className={`btn btn-outline-secondary rounded-circle p-0 text-center  ${styles.btnDropdown}`}
                onClick={() => setDropdownMenuStatus(true)}
                aria-label="Open menu"
                aria-expanded={dropdownMenuStatus}
              >
                <BsThreeDotsVertical />
              </button>
            </div>
          </div>

          <div className="mt-2 d-flex flex-row align-items-baseline">
            <div className="text-truncate">
              <small className="text-muted text-uppercase me-1">API-KEY-ID: </small>
              <small>{props.apiKey.apiKeyId}</small>
            </div>
            <div className={`ms-1 ${styles.copyBtn}`}>
              <div className={`position-absolute ${styles.copyBtnWrapper}`}>
                <ButtonCopyToClipboard
                  text={props.apiKey.apiKeyId!}
                  className="btn-link border-0 text-dark fw-bold"
                  label="Copy API key ID to clipboard"
                />
              </div>
            </div>
          </div>
          <div className="text-truncate">
            <small className="text-muted text-uppercase me-1">Created at: </small>
            <small>{moment.unix(props.apiKey.createdAt!).format('YYYY/MM/DD HH:mm:ss (Z)')}</small>
          </div>
        </div>
      </div>
    </div>
  );
}
Example #6
Source File: DeleteAccount.tsx    From hub with Apache License 2.0 4 votes vote down vote up
DeleteAccount = (props: Props) => {
  const { ctx } = useContext(AppCtx);
  const [openStatus, setOpenStatus] = useState<boolean>(false);
  const [isDeleting, setIsDeleting] = useState(false);
  const [deleteSuccess, setDeleteSuccess] = useState<boolean>(false);
  const [isValidInput, setIsValidInput] = useState<boolean>(false);

  const onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
    setIsValidInput(e.target.value === ctx.user!.alias);
  };

  const onClose = () => {
    setOpenStatus(false);
    setDeleteSuccess(false);
    setIsValidInput(false);
  };

  async function registerDeleteUserCode() {
    try {
      setIsDeleting(true);
      await API.registerDeleteUserCode();
      setIsDeleting(false);
      setDeleteSuccess(true);
    } catch (err: any) {
      setIsDeleting(false);
      if (err.kind === ErrorKind.Unauthorized) {
        props.onAuthError();
      } else {
        alertDispatcher.postAlert({
          type: 'danger',
          message: 'An error occurred deleting your account, please try again later.',
        });
      }
    }
  }

  return (
    <>
      <div className="mt-4 mt-md-5">
        <p className="mb-4">
          Deleting your account will also delete all the content that belongs to it (repositories, subscriptions,
          webhooks, etc), as well as all organizations where you are the only member.
        </p>

        <button
          className="btn btn-sm btn-danger"
          onClick={() => setOpenStatus(true)}
          aria-label="Open deletion account modal"
        >
          <div className="d-flex flex-row align-items-center text-uppercase">
            <FaTrashAlt className="me-2" />
            <div>Delete account</div>
          </div>
        </button>
      </div>

      <Modal
        className="d-inline-block"
        modalClassName={styles.modal}
        closeButton={
          deleteSuccess ? undefined : (
            <>
              <button
                className="btn btn-sm btn-outline-secondary text-uppercase"
                onClick={() => setOpenStatus(false)}
                aria-label="Close"
              >
                <div className="d-flex flex-row align-items-center">
                  <IoMdCloseCircle className="me-2" />
                  <span>Cancel</span>
                </div>
              </button>

              <button
                className="btn btn-sm btn-danger ms-3"
                onClick={(e) => {
                  e.preventDefault();
                  registerDeleteUserCode();
                }}
                disabled={isDeleting || !isValidInput}
                aria-label="Delete account"
              >
                <div className="d-flex flex-row align-items-center text-uppercase">
                  {isDeleting ? (
                    <>
                      <span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
                      <span className="ms-2">Deleting...</span>
                    </>
                  ) : (
                    <>
                      <FaTrashAlt className="me-2" />
                      <span>Delete account</span>
                    </>
                  )}
                </div>
              </button>
            </>
          )
        }
        header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Delete account</div>}
        onClose={onClose}
        open={openStatus}
      >
        <div className="mw-100 h-100">
          {deleteSuccess ? (
            <div className="d-flex h-100 w-100 align-items-center justify-content-center">
              <div className="alert" role="alert" aria-live="assertive" aria-atomic="true">
                <div className="d-flex flex-sm-column flex-md-row align-items-center">
                  <div className="me-3">
                    <CgUserRemove className="h1 text-dark mb-3 mb-md-0" />
                  </div>
                  <h4 className="alert-heading mb-0">We've just sent you a confirmation email</h4>
                </div>
                <hr />
                <p>
                  Please click on the link that has just been sent to your email account to delete your account and
                  complete the process.
                </p>
                <p className="mb-0">
                  Please note that the link <span className="fw-bold">is only valid for 15 minutes</span>. If you
                  haven't clicked the link by then you'll need to start the process from the beginning.
                </p>
              </div>
            </div>
          ) : (
            <>
              <div className="alert alert-warning my-4">
                <span className="fw-bold text-uppercase">Important:</span> Please read this carefully.
              </div>

              <p>
                If you delete your account all repositories belonging to it will be deleted. Please consider
                transferring them to another user.
              </p>
              <p>
                All information related to the repositories will be permanently deleted as well. This includes packages,
                stars, users subscriptions, webhooks, events and notifications. Some of this information was created by
                users and will be lost. In addition to that, all organizations where you are the only member and all
                content belonging to those organizations will be removed as well.
              </p>

              <p>
                <span className="fw-bold">This operation cannot be undone</span>.
              </p>

              <p data-testid="confirmationText">
                Please type <span className="fw-bold">{ctx.user!.alias}</span> to confirm:
              </p>

              <div className="pb-3">
                <InputField type="text" name="alias" autoComplete="off" value="" onChange={onInputChange} />
              </div>
            </>
          )}
        </div>
      </Modal>
    </>
  );
}
Example #7
Source File: Card.tsx    From hub with Apache License 2.0 4 votes vote down vote up
WebhookCard = (props: Props) => {
  const { ctx } = useContext(AppCtx);
  const [isDeleting, setIsDeleting] = useState<boolean>(false);
  const [dropdownMenuStatus, setDropdownMenuStatus] = useState<boolean>(false);
  const dropdownMenu = useRef(null);
  const [deletionModalStatus, setDeletionModalStatus] = useState<boolean>(false);

  const closeDropdown = () => {
    setDropdownMenuStatus(false);
  };

  useOutsideClick([dropdownMenu], dropdownMenuStatus, closeDropdown);

  async function deleteWebhook() {
    try {
      setIsDeleting(true);
      await API.deleteWebhook(props.webhook.webhookId!, ctx.prefs.controlPanel.selectedOrg);
      setIsDeleting(false);
      props.onDeletion();
    } catch (err: any) {
      setIsDeleting(false);
      if (err.kind === ErrorKind.Unauthorized) {
        props.onAuthError();
      } else {
        alertDispatcher.postAlert({
          type: 'danger',
          message: 'An error occurred deleting the webhook, please try again later.',
        });
      }
    }
  }

  return (
    <div className="col-12 col-xxl-6 py-sm-3 py-2 px-0 px-xxl-3" role="listitem">
      <div className={`card cardWithHover w-100 h-100 mw-100 bg-white ${styles.card}`}>
        <div className="card-body position-relative">
          <div className="d-flex flex-row">
            <div className="h5 card-title mb-3 me-3 lh-1 text-break">
              <div className="d-flex flex-row align-items-start">
                <div>{props.webhook.name}</div>
                {props.webhook.active ? (
                  <span
                    className={`ms-3 mt-1 fw-bold badge rounded-pill border border-success text-success text-uppercase ${styles.badge}`}
                  >
                    Active
                  </span>
                ) : (
                  <span
                    className={`ms-3 mt-1 fw-bold badge rounded-pill border border-dark text-dark text-uppercase ${styles.badge} ${styles.inactiveBadge}`}
                  >
                    Inactive
                  </span>
                )}
              </div>
            </div>

            {deletionModalStatus && (
              <Modal
                className={`d-inline-block ${styles.modal}`}
                closeButton={
                  <>
                    <button
                      className="btn btn-sm btn-outline-secondary text-uppercase"
                      onClick={() => setDeletionModalStatus(false)}
                      aria-label="Close deletion modal"
                    >
                      <div className="d-flex flex-row align-items-center">
                        <IoMdCloseCircle className="me-2" />
                        <span>Cancel</span>
                      </div>
                    </button>

                    <button
                      className="btn btn-sm btn-danger ms-3"
                      onClick={(e) => {
                        e.preventDefault();
                        deleteWebhook();
                      }}
                      disabled={isDeleting}
                      aria-label="Delete webhook"
                    >
                      <div className="d-flex flex-row align-items-center text-uppercase">
                        {isDeleting ? (
                          <>
                            <span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
                            <span className="ms-2">Deleting...</span>
                          </>
                        ) : (
                          <>
                            <FaTrashAlt className={`me-2 ${styles.btnDeleteIcon}`} />
                            <span>Delete</span>
                          </>
                        )}
                      </div>
                    </button>
                  </>
                }
                header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Delete webhook</div>}
                onClose={() => setDeletionModalStatus(false)}
                open
              >
                <div className="mt-3 mw-100 text-center">
                  <p>Are you sure you want to delete this webhook?</p>
                </div>
              </Modal>
            )}

            <div className="ms-auto">
              <div
                ref={dropdownMenu}
                className={classnames('dropdown-menu dropdown-menu-end p-0', styles.dropdownMenu, {
                  show: dropdownMenuStatus,
                })}
              >
                <div className={`dropdown-arrow ${styles.arrow}`} />

                <button
                  className="dropdown-item btn btn-sm rounded-0 text-dark"
                  onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
                    e.preventDefault();
                    closeDropdown();
                    props.onEdition();
                  }}
                  aria-label="Edit webhook"
                >
                  <div className="d-flex flex-row align-items-center">
                    <FaPencilAlt className={`me-2 ${styles.btnIcon}`} />
                    <span>Edit</span>
                  </div>
                </button>

                <button
                  className="dropdown-item btn btn-sm rounded-0 text-dark"
                  onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
                    e.preventDefault();
                    closeDropdown();
                    setDeletionModalStatus(true);
                  }}
                  aria-label="Open deletion webhook modal"
                >
                  <div className="d-flex flex-row align-items-center">
                    <FaTrashAlt className={`me-2 ${styles.btnIcon}`} />
                    <span>Delete</span>
                  </div>
                </button>
              </div>

              <button
                className={`btn btn-outline-secondary rounded-circle p-0 text-center  ${styles.btnDropdown}`}
                onClick={() => setDropdownMenuStatus(true)}
                aria-label="Open menu"
                aria-expanded={dropdownMenuStatus}
              >
                <BsThreeDotsVertical />
              </button>
            </div>
          </div>

          <div className="d-flex flex-column">
            <div className="card-subtitle d-flex flex-column mw-100 mt-1">
              <p className="card-text">{props.webhook.description}</p>
            </div>

            <div className="text-truncate">
              <small className="text-muted text-uppercase me-2">Url:</small>
              <small>{props.webhook.url}</small>
            </div>

            <div className="d-flex flex-row justify-content-between align-items-baseline">
              {props.webhook.lastNotifications && (
                <div className="d-none d-md-inline mt-2">
                  <LastNotificationsModal notifications={props.webhook.lastNotifications} />
                </div>
              )}

              {(isUndefined(props.webhook.packages) || props.webhook.packages.length === 0) && (
                <div className="ms-auto mt-2">
                  <ElementWithTooltip
                    element={
                      <span
                        className={`d-flex flex-row align-items-center badge bg-warning rounded-pill ${styles.badgeNoPackages}`}
                      >
                        <TiWarningOutline />
                        <span className="ms-1">No packages</span>
                      </span>
                    }
                    tooltipMessage="This webhook is not associated to any packages."
                    active
                    visibleTooltip
                  />
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
Example #8
Source File: index.tsx    From postcode with MIT License 4 votes vote down vote up
KeyValueRow = (props) => {
  const {
    itemKey,
    itemValue,
    itemDescription,
    itemDisabled,
    actions,
    onDelete,
    onChange,
    fixed,
  } = props;

  return (
    <tr className={itemDisabled ? "kv-disabled" : null}>
      {!fixed && (
        <td className="kv-action-cell">
          {actions && (
            <input
              type="checkbox"
              checked={!itemDisabled}
              onChange={(e) =>
                onChange({
                  key: itemKey,
                  value: itemValue,
                  description: itemDescription,
                  disabled: !e.target.checked,
                })
              }
            />
          )}
        </td>
      )}
      <td>
        <input
          className="kv-input"
          placeholder="Key"
          value={itemKey}
          disabled={fixed}
          onChange={(e) =>
            onChange({
              key: e.target.value,
              value: itemValue,
              description: itemDescription,
              disabled: itemDisabled,
            })
          }
        />
      </td>
      <td>
        <input
          className="kv-input"
          placeholder="Value"
          value={itemValue}
          disabled={fixed}
          onChange={(e) =>
            onChange({
              key: itemKey,
              value: e.target.value,
              description: itemDescription,
              disabled: itemDisabled,
            })
          }
        />
      </td>
      {!fixed && (
        <td>
          <input
            className="kv-input"
            placeholder="Description"
            value={itemDescription}
            disabled={fixed}
            onChange={(e) =>
              onChange({
                key: itemKey,
                value: itemValue,
                description: e.target.value,
                disabled: itemDisabled,
              })
            }
          />
        </td>
      )}
      {!fixed && (
        <td className="kv-action-cell">
          {actions && (
            <FaTrashAlt className="kv-delete-button" onClick={onDelete} />
          )}
        </td>
      )}
    </tr>
  );
}