react-icons/bs#BsThreeDotsVertical TypeScript Examples
The following examples show how to use
react-icons/bs#BsThreeDotsVertical.
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: PostComment.tsx From 3Speak-app with GNU General Public License v3.0 | 6 votes |
CustomToggle = React.forwardRef(({ children, onClick }: any, ref: any) => (
<a
href=""
ref={ref}
onClick={(e) => {
e.preventDefault()
onClick(e)
}}
>
<BsThreeDotsVertical />
{children}
</a>
))
Example #2
Source File: Card.tsx From hub with Apache License 2.0 | 4 votes |
MemberCard = (props: Props) => {
const { ctx, dispatch } = useContext(AppCtx);
const [isDeletingMember, setIsDeletingMember] = useState(false);
const dropdownMenu = useRef(null);
const [dropdownMenuStatus, setDropdownMenuStatus] = useState<boolean>(false);
const [modalStatus, setModalStatus] = useState<boolean>(false);
const closeDropdown = () => {
setDropdownMenuStatus(false);
};
useOutsideClick([dropdownMenu], dropdownMenuStatus, closeDropdown);
async function deleteMember() {
try {
setIsDeletingMember(true);
await API.deleteOrganizationMember(ctx.prefs.controlPanel.selectedOrg!, props.member.alias);
setIsDeletingMember(false);
if (props.member.alias === ctx.user!.alias) {
dispatch(unselectOrg());
} else {
props.onSuccess();
}
} catch (err: any) {
setIsDeletingMember(false);
if (err.kind !== ErrorKind.Unauthorized) {
let errorMessage = 'An error occurred removing member from the organization, please try again later.';
if (err.kind === ErrorKind.Forbidden) {
errorMessage = 'You do not have permissions to remove members from the organization.';
}
alertDispatcher.postAlert({
type: 'danger',
message: errorMessage,
});
} else {
props.onAuthError();
}
}
}
const isUser = props.member.alias === ctx.user!.alias;
const getFullName = (): string => {
let fullName = '';
if (props.member.firstName) {
fullName += `${props.member.firstName} `;
}
if (props.member.lastName) {
fullName += props.member.lastName;
}
return fullName;
};
return (
<div className="col-12 col-xxl-6 py-sm-3 py-2 px-0 px-xxl-3" data-testid="memberCard">
<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 align-items-start">
<div
className={`d-flex align-items-center justify-content-center p-1 overflow-hidden me-2 border border-2 rounded-circle bg-white ${styles.imageWrapper} imageWrapper`}
>
<FaUser className={`fs-4 ${styles.image}`} />
</div>
<div className="flex-grow-1">
<div className="d-flex flex-row align-items-start">
<div className="h5 mb-1">
{props.member.firstName || props.member.lastName ? getFullName() : props.member.alias}
</div>
{!isUndefined(props.member.confirmed) && !props.member.confirmed && (
<div className={classnames('ms-3', { 'me-3': props.membersNumber > 1 })}>
<span className="badge bg-warning">Invitation not accepted yet</span>
</div>
)}
</div>
<div className="h6 text-muted me-1 fst-italic">{props.member.alias}</div>
</div>
{props.membersNumber > 1 && (
<>
{modalStatus && (
<Modal
className="d-inline-block"
closeButton={
<>
<button
className="btn btn-sm btn-outline-secondary"
onClick={() => setModalStatus(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();
deleteMember();
}}
disabled={isDeletingMember}
aria-label={isUser ? 'Leave organization' : 'Remove member'}
>
<div className="d-flex flex-row align-items-center text-uppercase">
{isDeletingMember ? (
<>
<span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
<span className="ms-2">{isUser ? 'Leaving...' : 'Removing...'}</span>
</>
) : (
<>
{isUser ? (
<FaSignOutAlt className={`me-2 ${styles.btnIcon}`} />
) : (
<FaUserMinus className={`me-2 ${styles.btnIcon}`} />
)}
<span>{isUser ? 'Leave' : 'Remove'}</span>
</>
)}
</div>
</button>
</>
}
header={
<div className={`h3 flex-grow-1 m-2 ${styles.title}`}>
{isUser ? 'Leave ' : 'Remove from '} organization
</div>
}
onClose={() => setModalStatus(false)}
open
>
<div className="mt-3 mw-100 text-center">
<p>
{isUser
? 'Are you sure you want to leave this organization?'
: 'Are you sure you want to remove this member from this organization?'}
</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" />
{isUser ? (
<button
className="dropdown-item btn btn-sm rounded-0 text-dark"
onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
e.preventDefault();
closeDropdown();
setModalStatus(true);
}}
aria-label="Open leave organization modal"
>
<div className="d-flex flex-row align-items-center">
<FaSignOutAlt className={`me-2 ${styles.btnIcon}`} />
<span>Leave</span>
</div>
</button>
) : (
<ActionBtn
className="dropdown-item btn btn-sm rounded-0 text-dark"
onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
e.preventDefault();
closeDropdown();
setModalStatus(true);
}}
action={AuthorizerAction.DeleteOrganizationMember}
label="Open leave organization modal"
>
<>
<FaUserMinus className={`me-2 ${styles.btnIcon}`} />
<span>Remove</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>
</div>
</div>
</div>
);
}
Example #3
Source File: Card.tsx From hub with Apache License 2.0 | 4 votes |
OrganizationCard = (props: Props) => {
const { ctx, dispatch } = useContext(AppCtx);
const [isLeaving, setIsLeaving] = useState(false);
const [isAccepting, setIsAccepting] = useState(false);
const dropdownMenu = useRef(null);
const [dropdownMenuStatus, setDropdownMenuStatus] = useState<boolean>(false);
const [leaveModalStatus, setLeaveModalStatus] = useState<boolean>(false);
const isMember =
!isUndefined(props.organization.confirmed) && !isNull(props.organization.confirmed) && props.organization.confirmed;
const closeDropdown = () => {
setDropdownMenuStatus(false);
};
useOutsideClick([dropdownMenu], dropdownMenuStatus, closeDropdown);
async function leaveOrganization() {
try {
setIsLeaving(true);
await API.deleteOrganizationMember(props.organization.name, ctx.user!.alias);
setIsLeaving(false);
closeDropdown();
props.onSuccess();
if (
!isUndefined(ctx.prefs.controlPanel.selectedOrg) &&
ctx.prefs.controlPanel.selectedOrg === props.organization.name
) {
dispatch(unselectOrg());
}
} catch (err: any) {
setIsLeaving(false);
if (err.kind !== ErrorKind.Unauthorized) {
closeDropdown();
alertDispatcher.postAlert({
type: 'danger',
message: 'An error occurred leaving the organization, please try again later.',
});
} else {
props.onAuthError();
}
}
}
async function confirmOrganizationMembership() {
setIsAccepting(true);
try {
await API.confirmOrganizationMembership(props.organization.name);
setIsAccepting(false);
props.onSuccess();
} catch {
setIsAccepting(false);
}
}
const hasDropdownContent =
!isUndefined(props.organization) &&
(!props.organization.confirmed ||
(props.organization.confirmed &&
isMember &&
props.organization.membersCount &&
props.organization.membersCount > 1));
return (
<div className="col-12 col-xxl-6 py-sm-3 py-2 px-0 px-xxl-3" data-testid="organizationCard">
<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 align-items-start">
<div className="d-flex flex-row align-items-center w-100">
<div
className={`d-flex align-items-center justify-content-center overflow-hidden p-1 me-2 position-relative border border-3 bg-white rounded-circle ${styles.imageWrapper} imageWrapper`}
>
{!isUndefined(props.organization.logoImageId) ? (
<Image
alt={props.organization.displayName || props.organization.name}
imageId={props.organization.logoImageId}
className={`fs-4 ${styles.image}`}
placeholderIcon={<MdBusiness />}
/>
) : (
<MdBusiness className={styles.image} />
)}
</div>
<div className="text-truncate">
<div className={`h5 mb-0 text-truncate ${styles.title}`}>
{props.organization.displayName || props.organization.name}
</div>
</div>
{!isMember && (
<div className="ms-3">
<span className="badge bg-warning">Invitation not accepted yet</span>
</div>
)}
<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}`} />
{props.organization.confirmed ? (
<>
{isMember && props.organization.membersCount && props.organization.membersCount > 1 && (
<button
className="dropdown-item btn btn-sm rounded-0 text-dark"
onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
e.preventDefault();
closeDropdown();
setLeaveModalStatus(true);
}}
aria-label="Open modal"
>
<div className="d-flex flex-row align-items-center">
<FaSignOutAlt className={`me-2 ${styles.btnIcon}`} />
<span>Leave</span>
</div>
</button>
)}
</>
) : (
<div>
<button
className="dropdown-item btn btn-sm rounded-0 text-dark"
onClick={(e: ReactMouseEvent<HTMLButtonElement>) => {
e.preventDefault();
confirmOrganizationMembership();
closeDropdown();
}}
disabled={isAccepting}
aria-label="Confirm membership"
>
<div className="d-flex flex-row align-items-center">
{isAccepting ? (
<>
<span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
<span className="ms-2">Accepting invitation...</span>
</>
) : (
<>
<FaEnvelopeOpenText className={`me-2 ${styles.btnIcon}`} />
<span>Accept invitation</span>
</>
)}
</div>
</button>
</div>
)}
</div>
{hasDropdownContent && (
<button
className={`ms-3 mb-2 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>
{leaveModalStatus && (
<Modal
className={`d-inline-block ${styles.modal}`}
closeButton={
<>
<button
className="btn btn-sm btn-outline-secondary text-uppercase"
onClick={() => setLeaveModalStatus(false)}
aria-label="Close 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();
leaveOrganization();
}}
disabled={isLeaving}
aria-label="Leave organization"
>
<div className="d-flex flex-row align-items-center text-uppercase">
{isLeaving ? (
<>
<span className="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" />
<span className="ms-2">Leaving...</span>
</>
) : (
<>
<FaSignOutAlt className={`me-2 ${styles.btnIcon}`} />
<span>Leave</span>
</>
)}
</div>
</button>
</>
}
header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Leave organization</div>}
onClose={() => setLeaveModalStatus(false)}
open
>
<div className="mt-3 mw-100 text-center">
<p>Are you sure you want to leave this organization?</p>
</div>
</Modal>
)}
</div>
{props.organization.homeUrl && (
<div className="mt-3 text-truncate">
<small className="text-muted text-uppercase me-1">Homepage: </small>
<ExternalLink
href={props.organization.homeUrl}
className={`text-reset ${styles.link}`}
label={`Open link ${props.organization.homeUrl}`}
>
{props.organization.homeUrl}
</ExternalLink>
</div>
)}
{props.organization.description && (
<div className="mt-2">
<p className="mb-0">{props.organization.description}</p>
</div>
)}
</div>
</div>
</div>
);
}
Example #4
Source File: Card.tsx From hub with Apache License 2.0 | 4 votes |
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 #5
Source File: Card.tsx From hub with Apache License 2.0 | 4 votes |
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: Card.tsx From hub with Apache License 2.0 | 4 votes |
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 #7
Source File: index.tsx From slice-machine with Apache License 2.0 | 4 votes |
function ListItem<F extends TabField, S extends AnyObjectSchema>({
item,
index,
deleteItem,
enterEditMode,
modelFieldName,
renderFieldAccessor,
HintElement,
CustomEditElement,
CustomEditElements,
widget,
draggableId,
children,
}: ListItemProps<F, S>): JSX.Element {
const { theme } = useThemeUI();
const {
key,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
value: { config },
} = item;
return (
<Fragment>
<Draggable draggableId={draggableId} index={index}>
{(provided) => (
<Fragment>
<Li
ref={provided.innerRef}
{...provided.draggableProps}
Component={Box}
sx={{
p: 0,
mx: 0,
my: 3,
}}
>
<Flex sx={{ width: "100%" }}>
<SliceMachineIconButton
label="Reorder slice field (drag and drop)"
Icon={FaBars}
color={theme.colors?.icons as string}
mr={1}
mt={3}
{...provided.dragHandleProps}
/>
<Box
sx={{
bg: "headSection",
width: "100%",
borderRadius: "3px",
border: (t) => `1px solid ${String(t.colors?.borders)}`,
}}
>
<Flex
sx={{
p: 3,
alignItems: "center",
justifyContent: "space-between",
width: "100%",
}}
>
<ItemHeader
theme={theme}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
text={config?.label || key}
sliceFieldName={
renderFieldAccessor && renderFieldAccessor(key)
}
WidgetIcon={widget.Meta.icon}
/>
<Flex>
{CustomEditElements ? CustomEditElements : null}
{CustomEditElement ? (
CustomEditElement
) : (
<SliceMachineIconButton
size={22}
Icon={AiOutlineEdit}
label="Edit slice field"
sx={{ cursor: "pointer", color: theme.colors?.icons }}
onClick={() =>
enterEditMode(
[key, item.value],
modelFieldName,
index
)
}
/>
)}
<Menu>
<MenuButton
className="sliceMenuButton"
style={{
padding: "0",
cursor: "pointer",
width: "32px",
height: "32px",
border: "none",
background: "transparent",
outline: "0",
}}
>
<BsThreeDotsVertical
size={20}
color={theme.colors?.icons as string}
style={{ pointerEvents: "none" }}
/>
</MenuButton>
<MenuList
style={{
background: theme.colors?.gray as string,
border: "1px solid",
borderRadius: "3px",
borderColor: theme.colors?.borders as string,
outline: "0",
}}
>
<MenuItem
style={{ padding: "6px", cursor: "pointer" }}
onSelect={() => deleteItem(key)}
>
Delete field
</MenuItem>
</MenuList>
</Menu>
</Flex>
</Flex>
{HintElement ? HintElement : null}
</Box>
</Flex>
{children}
</Li>
</Fragment>
)}
</Draggable>
</Fragment>
);
}