@fortawesome/free-solid-svg-icons#faInfoCircle TypeScript Examples
The following examples show how to use
@fortawesome/free-solid-svg-icons#faInfoCircle.
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: LessonSelect.tsx From frontend.ro with MIT License | 6 votes |
function LessonSelect({ selectedId, onChange } : Props) {
const chapterLessonPairs = LESSONS
.filter((lesson) => lesson.written)
.map((lesson) => ({
value: {
chapter: lesson.type,
// FIXME
id: lesson.url.split('/').pop(),
},
label: `${lesson.type}/${lesson.title}`,
}));
const defaultValue = chapterLessonPairs.find((pair) => pair.label === selectedId);
return (
<div className={styles['lesson-select']}>
<p>
<FontAwesomeIcon width="16" height="16" icon={faInfoCircle} />
Dacă vrei să sugerezi acest exercițiu pentru una din lecțiile existente,
alege de mai jos:
</p>
<ReactSelect
isSearchable
placeholder=""
onChange={onChange}
className={styles.select}
defaultValue={defaultValue}
options={chapterLessonPairs}
/>
</div>
);
}
Example #2
Source File: index.tsx From MagicUI with Apache License 2.0 | 6 votes |
ToolBar: React.FC = (props) => {
const user = useSelector((state: IStoreState) => state.user);
const handleAvatarClick = () => {
Bridge.open(WidgetType.USER, user);
};
return (
<div className={style.header_navigation}>
<div className={style.right_content}>
<div className={style.tools_bar}>
<button className={style.help_btn} onClick={() => history.push(Routers.HELP)}>
<FontAwesomeIcon icon={faInfoCircle}/>
</button>
<button className={style.todo_btn}>
<FontAwesomeIcon icon={faCalendarCheck}/>
</button>
<button className={style.msg_btn}>
<FontAwesomeIcon icon={faBell}/>
</button>
<button className={style.chart_btn}>
<FontAwesomeIcon icon={faChartBar}/>
</button>
</div>
<div className={style.avatar_wrapper}>
<Avatar src={user.avatar as string} onClick={handleAvatarClick}/>
</div>
</div>
</div>
);
}
Example #3
Source File: index.tsx From bad-cards-game with GNU Affero General Public License v3.0 | 6 votes |
library.add( faDotCircle, faCircle, faBars, faTimes, faInfoCircle, faTrophy, faShareSquare, faHeart, faInstagram, faTwitter, faGithub, faFacebook, faHandPointRight, faEdit, faSave, faCamera, faPlus, faMinus, faRandom, );
Example #4
Source File: Info.tsx From longwave with MIT License | 6 votes |
export function Info(props: { children: string | ReactElement<any> }) {
return (
<Tippy content={props.children} placement="bottom">
<div style={{ margin: 8 }}>
<FontAwesomeIcon icon={faInfoCircle} />
</div>
</Tippy>
);
}
Example #5
Source File: PrivacyControls.tsx From frontend.ro with MIT License | 6 votes |
function PrivacyControls(props: Props) {
// ceva
const { isPrivate, onPrivacyChange, form } = props;
return (
<div className={styles['privacy-controls']}>
<Checkbox
form={form}
className="d-block"
type="radio"
name="private"
onChange={() => onPrivacyChange(false)}
checked={!isPrivate}
value="false"
>
Public
</Checkbox>
<Checkbox
form={form}
className="d-block"
type="radio"
name="private"
onChange={() => onPrivacyChange(true)}
checked={isPrivate}
value="true"
>
Privat
</Checkbox>
<p>
<FontAwesomeIcon width="16" icon={faInfoCircle} />
{isPrivate ? PRIVATE_INFO : PUBLIC_INFO}
</p>
</div>
);
}
Example #6
Source File: create-position.component.ts From 1x.ag with MIT License | 5 votes |
info = faInfoCircle;
Example #7
Source File: NetworkSwitcher.tsx From devex with GNU General Public License v3.0 | 5 votes |
NetworkSwitcher: React.FC = () => {
const history = useHistory()
const networkName = useNetworkName()
const networkUrl = useNetworkUrl()
const userPrefContext = useContext(UserPrefContext)
const { networkMap } = userPrefContext!
const [showDropdown, setShowDropdown] = useState(false)
const [currentNetwork, setCurrentNetwork] = useState(networkName)
useEffect(() => {
setCurrentNetwork(networkName)
}, [networkName])
const changeNetwork = useCallback((k: string) => {
history.push({
pathname: '/',
search: '?' + new URLSearchParams({ network: k }).toString()
})
}, [history])
return (
<Nav style={{ minWidth: '120px' }}>
<OverlayTrigger placement='left'
overlay={<Tooltip id={'network-tt'}> {networkUrl} </Tooltip>}>
<FontAwesomeIcon className='info-icon' icon={faInfoCircle} />
</OverlayTrigger>
<NavDropdown onToggle={(e: boolean) => { setShowDropdown(e) }}
show={showDropdown} title={currentNetwork} id="header-network-dropdown">
{networkMap.size === 0
? <div className='text-center'>
No networks
</div>
: Array.from(networkMap, ([k, v]) => (
<div key={k} className='node-div'>
<NavDropdown.Item className='node-item' onClick={() => {
if (currentNetwork !== v) {
changeNetwork(k)
}
}}>
{v}
</NavDropdown.Item>
</div>
))}
</NavDropdown>
</Nav>
)
}
Example #8
Source File: main.ts From snip with MIT License | 5 votes |
library.add(faLink, faHandPeace, faCopy, faInfoCircle);
Example #9
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 5 votes |
SettleManuallyBtn: React.FC<{
settleAuctionHandler: () => void;
auction: Auction;
}> = props => {
const { settleAuctionHandler, auction } = props;
const MINS_TO_ENABLE_MANUAL_SETTLEMENT = 5;
const [settleEnabled, setSettleEnabled] = useState(false);
const [auctionTimer, setAuctionTimer] = useState(MINS_TO_ENABLE_MANUAL_SETTLEMENT * 60);
const auctionTimerRef = useRef(auctionTimer); // to access within setTimeout
auctionTimerRef.current = auctionTimer;
const timerDuration = dayjs.duration(auctionTimerRef.current, 's');
// timer logic
useEffect(() => {
// Allow immediate manual settlement when testing
if (CHAIN_ID !== 1) {
setSettleEnabled(true);
setAuctionTimer(0);
return;
}
// prettier-ignore
const timeLeft = MINS_TO_ENABLE_MANUAL_SETTLEMENT * 60 - (dayjs().unix() - (auction && Number(auction.endTime)));
setAuctionTimer(auction && timeLeft);
if (auction && timeLeft <= 0) {
setSettleEnabled(true);
setAuctionTimer(0);
} else {
const timer = setTimeout(() => {
setAuctionTimer(auctionTimerRef.current - 1);
}, 1_000);
return () => {
clearTimeout(timer);
};
}
}, [auction, auctionTimer]);
const mins = timerDuration.minutes();
return (
<p className={classes.emergencySettleWrapper}>
<button
onClick={settleAuctionHandler}
className={classes.emergencySettleButton}
disabled={!settleEnabled}
>
{settleEnabled ? (
<>
<Trans>Settle manually</Trans>
</>
) : (
<>
<FontAwesomeIcon icon={faInfoCircle} />
{mins !== 0 ? (
<Trans>You can settle manually in {mins + 1} minutes</Trans>
) : (
<Trans>You can settle manually in 1 minute</Trans>
)}
</>
)}
</button>
</p>
);
}
Example #10
Source File: InfoTooltip.tsx From genshin-optimizer with MIT License | 5 votes |
InfoTooltip = ({ className, ...props }: ITooltipProps) =>
<BootstrapTooltip placement="top" {...props} className={className}>
<Box component="span" sx={{ cursor: "help" }}><FontAwesomeIcon icon={faInfoCircle} /></Box>
</BootstrapTooltip>
Example #11
Source File: icon.service.ts From WowUp with GNU General Public License v3.0 | 5 votes |
public constructor(private _matIconRegistry: MatIconRegistry, private _sanitizer: DomSanitizer) {
this.addSvg(faAngleDoubleDown);
this.addSvg(faArrowUp);
this.addSvg(faArrowDown);
this.addSvg(faSyncAlt);
this.addSvg(faTimes);
this.addSvg(faExternalLinkAlt);
this.addSvg(faQuestionCircle);
this.addSvg(faPlay);
this.addSvg(faClock);
this.addSvg(faBug);
this.addSvg(faLink);
this.addSvg(faDiscord);
this.addSvg(faGithub);
this.addSvg(faInfoCircle);
this.addSvg(faCodeBranch);
this.addSvg(faCaretDown);
this.addSvg(faExclamationTriangle);
this.addSvg(faCode);
this.addSvg(faPatreon);
this.addSvg(faCoins);
this.addSvg(faCompressArrowsAlt);
this.addSvg(faPencilAlt);
this.addSvg(faCheckCircle);
this.addSvg(faDiceD6);
this.addSvg(faSearch);
this.addSvg(faInfoCircle);
this.addSvg(faNewspaper);
this.addSvg(faCog);
this.addSvg(faAngleUp);
this.addSvg(faAngleDown);
this.addSvg(faChevronRight);
this.addSvg(faUserCircle);
this.addSvg(faEllipsisV);
this.addSvg(faCopy);
this.addSvg(farCheckCircle);
this.addSvg(faExclamation);
this.addSvg(faTrash);
this.addSvg(faHistory);
this.addSvg(faCaretSquareRight);
this.addSvg(faCaretSquareLeft);
this.addSvg(faMinimize);
this.addSvg(faUpRightFromSquare);
}
Example #12
Source File: SkillBreakdown.tsx From apps with MIT License | 5 votes |
render() {
const skill = this.props.skill;
const skillAdd =
this.props.skill.skillAdd.length > 0 ? (
<Tooltip id="skillAdd-tooltip" style={{ fontSize: "1em" }} lang={Manager.lang()}>
{getRubyText(this.props.region, skill.skillAdd[0].name, skill.skillAdd[0].ruby, true)}
</Tooltip>
) : null;
return (
<div>
<h3>
<SkillDescriptor region={this.props.region} skill={skill} iconHeight={33} />
{skillAdd !== null ? (
<>
{" "}
<OverlayTrigger overlay={skillAdd}>
<FontAwesomeIcon icon={faInfoCircle} style={{ fontSize: "0.75em" }} />
</OverlayTrigger>
</>
) : null}
</h3>
{this.props.rankUp !== undefined ? (
<Alert variant={"primary"}>Rank Up +{this.props.rankUp}</Alert>
) : null}
{skill.condQuestId && skill.condQuestPhase ? (
<Alert variant={"primary"}>
Available after{" "}
<QuestDescriptor
region={this.props.region}
questId={skill.condQuestId}
questPhase={
["91", "94"].includes(skill.condQuestId.toString().slice(0, 2))
? 1
: skill.condQuestPhase
}
/>
</Alert>
) : null}
<p className="newline">{skill.detail}</p>
{this.props.extraPassiveCond && skill.extraPassive.length > 0 ? (
<>
<ExtraPassiveCondition region={this.props.region} extraPassive={skill.extraPassive[0]} />
</>
) : null}
<EffectBreakdown
region={this.props.region}
cooldowns={this.props.cooldowns ? skill.coolDown : undefined}
funcs={skill.functions}
triggerSkillIdStack={[skill.id]}
levels={this.props.levels}
scripts={skill.script}
additionalSkillId={skill.script.additionalSkillId}
/>
</div>
);
}
Example #13
Source File: QuestEnemy.tsx From apps with MIT License | 5 votes |
QuestDropDescriptor = ({ region, drops }: { region: Region; drops: QuestEnemy.EnemyDrop[] }) => {
return (
<Alert variant="success">
<ul style={{ marginBottom: 0 }}>
{drops.map((drop) => {
const dummyGift = {
...drop,
id: 0,
priority: 0,
giftAdds: [],
};
let ciText = <></>;
if (drop.runs > 1) {
const c = quantile(0.975, drop.runs - 1);
const stdDevOverRuns = Math.sqrt(drop.dropVariance / drop.runs);
const lower = drop.dropExpected - c * stdDevOverRuns;
const upper = drop.dropExpected + c * stdDevOverRuns;
ciText = (
<>
<br />
95% CI: {numToPct(lower)} – {numToPct(upper)}
</>
);
}
const tooltip = (
<Tooltip id={`drop-detail-tooltip`} style={{ fontSize: "1em" }}>
{drop.dropCount.toLocaleString()} drops / {drop.runs.toLocaleString()} runs
{ciText}
</Tooltip>
);
return (
<li key={`${drop.type}-${drop.objectId}-${drop.num}`}>
<GiftDescriptor region={region} gift={dummyGift} />:{" "}
<span>{numToPct(drop.dropExpected)}</span>{" "}
<OverlayTrigger overlay={tooltip}>
<FontAwesomeIcon icon={faInfoCircle} />
</OverlayTrigger>
</li>
);
})}
</ul>
</Alert>
);
}
Example #14
Source File: WalletRecharge.tsx From argo-react with MIT License | 4 votes |
function WalletRecharge() {
const history = useHistory();
const { fetchUser } = useContext<IActionModel>(ActionContext);
const { selectedOrg, orgLoading } = useContext<IStateModel>(StateContext);
const [wallet, setWallet] = useState<string>("");
const [walletBal, setWalletBal] = useState<number>(0);
const [walletApproval, setWalletApproval] = useState<number>(0);
const [rechargeAmount, setRechargeAmount] = useState<string>("");
const [walletLoader, setWalletLoader] = useState<boolean>(false);
const [rechargeLoader, setRechargeLoader] = useState<boolean>(false);
const [walletLoading, setWalletLoading] = useState<boolean>(false);
const [orgWallet, setOrgWallet] = useState<string>("");
const [errorWarning, setErrorWarning] = useState<boolean>(false);
const [errorMessage, setErrorMessage] = useState<string>("");
const componentIsMounted = useRef(true);
useEffect(() => {
if (selectedOrg && !orgLoading) {
setWalletLoading(true);
if (componentIsMounted.current) {
setOrgWallet(selectedOrg.wallet.address);
setWalletLoading(false);
}
} else {
if (orgLoading) {
setWalletLoading(true);
} else {
setWalletLoading(false);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedOrg, orgLoading]);
const rechargeArGo = async () => {
setErrorWarning(false);
try {
if (!wallet) {
setWalletLoader(true);
const wallet = await Web3Service.getPolygonAccount();
setWallet(wallet);
if (wallet) {
const walletBal = await Web3Service.getArgoBalance(wallet);
const walletApproval = await Web3Service.getArgoAllowances(wallet);
setWalletBal(walletBal);
setWalletApproval(walletApproval);
}
setWalletLoader(false);
} else {
setRechargeLoader(true);
await Web3Service.giveAllowance(rechargeAmount);
setRechargeLoader(false);
fetchUser();
history.goBack();
}
} catch (err) {
// eslint-disable-next-line no-console
console.log(err);
setWalletLoader(false);
setRechargeLoader(false);
setErrorMessage((err as any).message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
// window.location.reload();
}
};
const refreshWallet = async () => {
try {
setErrorWarning(false);
setWalletLoader(true);
const wallet = await Web3Service.getPolygonCurrentAccount();
const walletBal = await Web3Service.getArgoBalance(wallet);
const walletApproval = await Web3Service.getArgoAllowances(wallet);
setWallet(wallet);
setWalletBal(walletBal);
setWalletApproval(walletApproval);
setWalletLoader(false);
} catch (err) {
// eslint-disable-next-line no-console
console.log(err);
setWalletLoader(false);
setErrorMessage((err as any).message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
// window.location.reload();
}
};
useEffect(() => {
return () => {
componentIsMounted.current = false;
Web3Service.disconnectPolygon();
};
}, []);
const rechargeDisable =
rechargeLoader || wallet ? !rechargeAmount || wallet !== orgWallet : false;
return (
<div className="WalletRecharge">
<RootHeader parent={"CreateOrg"} />
<main className="app-main">
<div className="wallet-recharge-container">
<div className="wallet-recharge-card">
<div className="wallet-recharge-card-inner">
<h1 className="wallet-recharge-title">Set Allowance</h1>
<div className="wallet-recharge-form">
<label className="wallet-recharge-form-title">Your wallet</label>
<label className="wallet-chain-info">
<FontAwesomeIcon
icon={faInfoCircle}
style={{ marginRight: 7 }}
></FontAwesomeIcon>
We currently support Matic Mumbai Testnet. Please add Matic Mumbai
chain in your metamask.
</label>
<label className="wallet-recharge-form-subtitle">
Please approve more than minimum $ARGO tokens to our Payment Smart
Contract. Approval transaction is <b>Gassless</b>, no need to hold
$MATIC tokens for approval.
</label>
<label className="wallet-recharge-form-subtitle">
To start deploying your application, minimum allowance required is
60 $ARGO and minimum balance required is 60 $ARGO tokens.
</label>
<label className="wallet-recharge-form-subtitle">
To get <b>Matic Testnet $ARGO Tokens</b>, please visit{" "}
<a
href="https://faucet.spheron.network/"
target="_blank"
rel="noopener noreferrer"
>
https://faucet.spheron.network
</a>
.
</label>
<div className="current-wallet-details">
<div className="current-wallet-details-title">Owner Address:</div>
<div className="current-wallet-details-desc">
{!walletLoading ? (
`${orgWallet}`
) : (
<Skeleton width={150} duration={2} />
)}
</div>
</div>
</div>
{wallet && (
<>
<div className="wallet-recharge-form">
<div className="wallet-recharge-form-title-container">
<label className="wallet-recharge-form-title">
Wallet Details
</label>
<div className="refresh-control" onClick={refreshWallet}>
<FontAwesomeIcon icon={faSyncAlt}></FontAwesomeIcon>
</div>
</div>
<div className="wallet-details-container">
<div className="wallet-details-items">
<div className="wallet-details-item-title">
Wallet Address
</div>
<div className="wallet-details-item-desc">
{!walletLoader ? (
wallet
) : (
<Skeleton width={300} duration={2} />
)}
</div>
</div>
<div className="wallet-details-items">
<div className="wallet-details-item-title">ARGO Balance</div>
<div className="wallet-details-item-desc">
{!walletLoader ? (
`${walletBal} $ARGO`
) : (
<Skeleton width={150} duration={2} />
)}
</div>
</div>
<div className="wallet-details-items">
<div className="wallet-details-item-title">
ARGO Allowance
</div>
<div className="wallet-details-item-desc">
{!walletLoader ? (
`${walletApproval} $ARGO`
) : (
<Skeleton width={150} duration={2} />
)}
</div>
</div>
</div>
</div>
<div className="wallet-recharge-form">
<label className="wallet-recharge-form-title">
Approval Amount
</label>
<label className="wallet-recharge-form-subtitle">
Please provide the approval amount.
</label>
<input
type="number"
className="wallet-recharge-form-input"
value={rechargeAmount}
onChange={(e) => setRechargeAmount(e.target.value)}
/>
</div>
</>
)}
{wallet && wallet !== orgWallet ? (
<div className="note-container">
Note: We currently support Matic Mumbai Testnet. Only owner of this
wallet can increase allowance
</div>
) : null}
<div className="button-container">
<button
type="button"
className="primary-button"
disabled={rechargeDisable}
onClick={rechargeArGo}
>
{rechargeLoader && (
<BounceLoader size={20} color={"#fff"} loading={true} />
)}
{!wallet ? "Connect" : "Approve"}
</button>
<button
type="button"
className="cancel-button"
onClick={(e) => history.goBack()}
>
Cancel
</button>
</div>
{errorWarning ? (
<div className="warning-container">
<div className="warning-header">
<FontAwesomeIcon icon={faExclamationCircle} /> {errorMessage}
</div>
</div>
) : null}
</div>
</div>
</div>
</main>
</div>
);
}
Example #15
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 4 votes |
AuctionActivity: React.FC<AuctionActivityProps> = (props: AuctionActivityProps) => {
const {
auction,
isFirstAuction,
isLastAuction,
onPrevAuctionClick,
onNextAuctionClick,
displayGraphDepComps,
} = props;
const isCool = useAppSelector(state => state.application.isCoolBackground);
const [auctionEnded, setAuctionEnded] = useState(false);
const [auctionTimer, setAuctionTimer] = useState(false);
const [showBidHistoryModal, setShowBidHistoryModal] = useState(false);
const showBidModalHandler = () => {
setShowBidHistoryModal(true);
};
const dismissBidModalHanlder = () => {
setShowBidHistoryModal(false);
};
// timer logic - check auction status every 30 seconds, until five minutes remain, then check status every second
useEffect(() => {
if (!auction) return;
const timeLeft = Number(auction.endTime) - Math.floor(Date.now() / 1000);
if (auction && timeLeft <= 0) {
setAuctionEnded(true);
} else {
setAuctionEnded(false);
const timer = setTimeout(
() => {
setAuctionTimer(!auctionTimer);
},
timeLeft > 300 ? 30000 : 1000,
);
return () => {
clearTimeout(timer);
};
}
}, [auctionTimer, auction]);
if (!auction) return null;
return (
<>
{showBidHistoryModal && (
<BidHistoryModal onDismiss={dismissBidModalHanlder} auction={auction} />
)}
<AuctionActivityWrapper>
<div className={classes.informationRow}>
<Row className={classes.activityRow}>
<AuctionTitleAndNavWrapper>
{displayGraphDepComps && (
<AuctionNavigation
isFirstAuction={isFirstAuction}
isLastAuction={isLastAuction}
onNextAuctionClick={onNextAuctionClick}
onPrevAuctionClick={onPrevAuctionClick}
/>
)}
<AuctionActivityDateHeadline startTime={auction.startTime} />
</AuctionTitleAndNavWrapper>
<Col lg={12}>
<AuctionActivityNounTitle isCool={isCool} nounId={auction.nounId} />
</Col>
</Row>
<Row className={classes.activityRow}>
<Col lg={4} className={classes.currentBidCol}>
<CurrentBid
currentBid={new BigNumber(auction.amount.toString())}
auctionEnded={auctionEnded}
/>
</Col>
<Col lg={6} className={classes.auctionTimerCol}>
{auctionEnded ? (
<Winner winner={auction.bidder} />
) : (
<AuctionTimer auction={auction} auctionEnded={auctionEnded} />
)}
</Col>
</Row>
</div>
{!auctionEnded && (
<Row className={classes.activityRow}>
<Col lg={12} className={classes.fomoNounsLink}>
<FontAwesomeIcon icon={faInfoCircle} />
<a href={'https://fomonouns.wtf'} target={'_blank'} rel="noreferrer">
<Trans>Help mint the next Noun</Trans>
</a>
</Col>
</Row>
)}
{isLastAuction && (
<>
<Row className={classes.activityRow}>
<Col lg={12}>
<Bid auction={auction} auctionEnded={auctionEnded} />
</Col>
</Row>
</>
)}
<Row className={classes.activityRow}>
<Col lg={12}>
{!isLastAuction ? (
<NounInfoCard
nounId={auction.nounId.toNumber()}
bidHistoryOnClickHandler={showBidModalHandler}
/>
) : (
displayGraphDepComps && (
<BidHistory
auctionId={auction.nounId.toString()}
max={3}
classes={bidHistoryClasses}
/>
)
)}
{/* If no bids, show nothing. If bids avail:graph is stable? show bid history modal,
else show etherscan contract link */}
{isLastAuction &&
!auction.amount.eq(0) &&
(displayGraphDepComps ? (
<BidHistoryBtn onClick={showBidModalHandler} />
) : (
<BidHistoryBtn onClick={openEtherscanBidHistory} />
))}
</Col>
</Row>
</AuctionActivityWrapper>
</>
);
}
Example #16
Source File: index.tsx From prism-frontend with MIT License | 4 votes |
function NavBar({ classes }: NavBarProps) {
const { t } = useSafeTranslation();
const rightSideLinks = [
{
title: t('about'),
icon: faInfoCircle,
href: 'https://innovation.wfp.org/project/prism',
},
{
title: 'GitHub',
icon: faGithub,
href: 'https://github.com/oviohub/prism-frontend',
},
];
const [openMobileMenu, setOpenMobileMenu] = useState(false);
const menu = menuList.map(({ title, ...category }) => (
<MenuItem key={title} title={title} {...category} />
));
// menu for mobile, 1 active accordion at a time so I put the state in here
const [expanded, setExpanded] = useState('');
const selectAccordion = (title: string) => {
setExpanded(title);
};
const menuMobile = menuList.map(({ title, ...category }) => (
<MenuItemMobile
expanded={expanded}
selectAccordion={selectAccordion}
key={title}
title={title}
{...category}
/>
));
const buttons = rightSideLinks.map(({ title, icon, href }) => (
<Grid item key={title}>
<Typography
variant="body2"
component="a"
target="_blank"
href={href}
onClick={() => setOpenMobileMenu(false)}
>
<FontAwesomeIcon icon={icon} /> {title}
</Typography>
</Grid>
));
return (
<AppBar position="static" className={classes.appBar}>
<Toolbar variant="dense">
<Grid container>
<Grid item xs={3} className={classes.logoContainer}>
<Typography
variant="h6"
className={classes.logo}
component={Link}
to="/"
>
{t('Prism')}
</Typography>
</Grid>
<Hidden smDown>
<Grid className={classes.menuContainer} item xs={6}>
{menu}
</Grid>
<Grid
spacing={3}
container
justify="flex-end"
alignItems="center"
item
xs={3}
>
{buttons}
<LanguageSelector />
</Grid>
</Hidden>
<Hidden mdUp>
<Grid item xs={9} className={classes.mobileMenuContainer}>
<Button
onClick={() => setOpenMobileMenu(prevOpen => !prevOpen)}
aria-controls={openMobileMenu ? 'mobile-menu-list' : undefined}
aria-haspopup="true"
className={classes.menuBars}
>
<FontAwesomeIcon icon={faBars} />
</Button>
<Drawer
anchor="right"
open={openMobileMenu}
onClose={() => setOpenMobileMenu(false)}
>
<div className={classes.mobileDrawerContent}>
<Grid container spacing={3}>
<Grid container justify="space-around" item>
{buttons}
</Grid>
<Grid container direction="column" item>
{menuMobile}
</Grid>
</Grid>
</div>
</Drawer>
</Grid>
</Hidden>
</Grid>
</Toolbar>
</AppBar>
);
}
Example #17
Source File: War.tsx From apps with MIT License | 4 votes |
warFaq = (region: Region) => {
const whatIsAWar = (
<>
You can think of a war as a container for the various quests in game. The{" "}
<Link to={`/${region}/war/100`}>Fuyuki Singularity</Link>, <Link to={`/${region}/war/301`}>Lostbelt 1</Link>
, the map for <Link to={`/${region}/war/8290`}>Battle in New York</Link>, and even the lists of{" "}
<Link to={`/${region}/war/8290`}>Daily Quests</Link> or <Link to={`/${region}/war/1003`}>Interludes</Link>{" "}
that you see on the main page of FGO are wars. It is important to note that wars are distinct from events,
which have their own page on the Atlas Academy DB. While an event may have a war attached to it, such as
GudaGuda, the event itself is not a war, nor do all events have wars. A half AP event in FGO, for example,
does not have a war attached. See the event section for more details on events.
</>
);
const warBreakDown = (
<>
An example war to look at is{" "}
<Link to={`/${region}/war/100`}>Singularity F: Flame Contaminated City: Fuyuki</Link>. You'll see that the
page is broken into several sections. The first section, as represented below, includes general information
about the war, including:
<ul>
<li>
<b>Name</b>
</li>
<li>
<b>Age</b>: Time of the war in game, such as 2004 for Fuyuki
</li>
<li>
<b>Event</b>: The event that the war is tied to (if any)
</li>
<li>
<b>Opening Scripts</b>: story sequences that appear when first opening the war
</li>
<li>
<b>Banner</b>: the war's icon on your terminal
</li>
<li>
<b>BGM</b>: the war's main background music
</li>
</ul>
You will also see buttons for the raw data of the war itself that is used to render the page, either in Nice
or Raw format.
<img alt="War Page Main Info" src={war_page_main_info} width="100%" />
Beneath the war's general information you will find the main quests associated with the war, if any. Each
quest will tell you the following information:
<ul>
<li>
<b>Section</b>: chapter in game
</li>
<li>
<b>ID</b>
</li>
<li>
<b>Name</b>
</li>
<li>
<b>Spot</b>: node, or location on a map in game
</li>
<li>
<b>Phases</b>: the different arrows or parts to a quest, such as 1-1, 1-2, 1-3 etc.
</li>
<li>
<b>Completion Reward</b> (if applicable)
</li>
<li>
<b>Scripts</b>: any story sections that the quest has
</li>
</ul>
Clicking on the quest's ID or name will take you to that quest's page, and clicking on any individual phase
will take you directly to that phase of the quest. A dragon symbol <FontAwesomeIcon icon={faDragon} /> by a
phase indicates it has enemies; a book symbol <FontAwesomeIcon icon={faBook} /> indicates it is story only.
<img alt="War Page Main Quests" src={war_page_main_quests} width="100%" />
Beneath the main quests you will find, if applicable, <b>free quests</b>, <b>interludes</b>,{" "}
<b>event quests</b>, or any other type of available quests, each sorted into its own dropdown. Within each
dropdown, the quests are ordered within their respective nodes, then by quest ID.
<img alt="War Page Free Quests" src={war_page_free_quests} width="100%" />
</>
);
const whatIsAQuest = (
<>
Quests are the individual containers for dialogue or battle sequences in FGO. When you click on a map
location within a singularity or event, the options that you have, be it the next part of the story, a free
quest, or an interlude, are quests.
</>
);
const questBreakDown = (
<>
An example quest to look at is <Link to={`/${region}/quest/1000001/1`}>Burning City</Link>. You'll see that
like the war page, it is broken into several sections. The first section, as represented below, includes
general information about the quest, including, among other things:
<ul>
<li>
<b>Type</b>: free quest, main quest, interlude etc.
</li>
<li>
<b>Cost</b>: AP or any other currency required to complete the quest
</li>
<li>
<b>Rewards</b>: First clear rewards for completing the quest (if applicable)
</li>
<li>
<b>Opening</b> and <b>Closing</b> times (in your local time)
</li>
<li>
<b>Individuality</b>: whether it is a sun field, city field, a specific event field, etc.
</li>
</ul>
Many quests have multiple phases, or parts to the quest. These are seen as 1-1, 1-2, 1-3, etc. in game, with
each piece being its own phase. For quests with multiple phases, you can navigate between them using the
arrows or numbers in the <b>Phases</b> row.
<img alt="Quest Page Main Info" src={quest_page_main_info} width="100%" />
Beneath the general information, you will see a list of the scripts for the phase you are on (if any), as
well as any pre-battle messages and drop data if available. Mouse over the{" "}
<FontAwesomeIcon icon={faInfoCircle} /> to see a tooltip indicating how many runs the drop data is based on.
The more runs worth of data, the more accurate it is.
<img alt="Quest Page Script and Drop data" src={quest_page_script_drop_data} width="100%" />
Finally, below the drop data you will see a list of stages, or battle waves, as well as the enemies within
them if available. Please note that enemy data is not available for all quests. The enemy data includes a
list of the drops of each particular mob if available, as well as all the general information regarding each
enemy, including their, among other things:
<ul>
<li>
<b>Stats</b>: such as HP, NP bars, death rate, etc.
</li>
<li>
<b>Skills</b>
</li>
<li>
<b>Traits</b>
</li>
<li>
<b>AI</b>: used to determine how enemies will act in battle
</li>
</ul>
You may also see a <b>Field AI</b> before the enemies. This refers to effects tied to the field itself
rather than any individual enemy.
<img alt="Quest Page Enemy" src={quest_page_enemy} width="100%" />
</>
);
const huntingQuest = (
<>
Hunting and Trial quests can be found in <Link to={`/${region}/war/999`}>War 9999: Chaldea Gate</Link>.
</>
);
const whatIsAnEvent = (
<>
As noted in the Wars section, Events and Wars, while sometimes sounding similar, are very different things.
If one thinks of Saber Wars for an example, there are two separate components: the{" "}
<Link to={`/${region}/war/8095`}>War</Link>, or the actual Saber Wars map with nodes and quests on it, and
the <Link to={`/${region}/event/80008`}>Event</Link> behind it. The event is where you can find information
like the lottery, point ladder, or shop tied to an in-game event. Note that some events may not have these,
such as a 1/2 AP or bonus FP event.
</>
);
const eventBreakDown = (
<>
Like the other pages, the Event page is broken down into sections. The top section provides general
information about the event, including:
<ul>
<li>
<b>ID</b>
</li>
<li>
<b>Name</b>
</li>
<li>
<b>Wars</b>: any Wars tied to the event
</li>
<li>
<b>Status</b>: whether the event is ongoing or not
</li>
<li>
<b>Status</b> and <b>End</b> times (in your local time)
</li>
</ul>
<img alt="Event Page Main Info" src={event_page_main_info} width="100%" />
Beneath the general information will be any point ladders, shops, or lotteries if applicable. For shops in
particular, you are able to utilize the planner to calculate the amount of event currency you will need for
what you want. To enable the planner feature, click the green edit button on the right side of the currency
bar, pictured below:
<img alt="Event Page Shop Planner" src={event_page_shop_planner} width="100%" />
Once you have enabled planner mode, you have several options. You can utilize the <b>Quick Toggles</b> in
order to instantly select or deselect all items, and you can also filter out commonly excluded items from
the calculated totals, such as gems, monuments, or pieces. In addition to the Quick Toggles, you can also
individually select items that you want. The two rightmost columns for each item are <b>Limit</b> and
<b>Target</b>. Limit refers to the maximum amount of an item that can be purchased, while Target allows you
to indicate how many of that item you wish to purchase. For each item you set with Target, the total cost of
that item is added to the cost bar above the shop. In the image below, you will see that two "Purely Bloom"
craft essences which cost 150 Vacuum Tubes each have been selected via the Target column, and the total cost
of 300 Vacuum Tubes is represented in the cost bar.
<img alt="Event Page Shop Planner Exclude" src={event_page_shop_planner_exclude} width="100%" />
</>
);
const findAScript = (
<>
Story text on the Atlas Academy DB is known as a <b>Script</b>. There are several ways you can find a
particular quest's script on the DB.
<ol>
<li>
<b>Script Search</b>
<br />
You can find the <Link to={`/${region}/scripts`}>Script Search</Link> page from the "Search"
dropdown in the navigation bar at the top of the DB page.
<img alt="Script Search Page Navigation" src={script_search_page} width="100%" />
This page allows you to search through the contents of all the scripts in the game to find the one
you are looking for. Make sure to pay attention to the search syntax listed on the page to refine
your searches.{" "}
<b>
Please keep in mind which region you are using the script page on. You cannot search a script
using English on the JP page and vice versa.
</b>
</li>
<li>
<b>Via the Wars Page</b>
<br />
If you don't remember exactly what was said in the script in question to find it via search, but you
do remember the singularity or event it was in, you can navigate to the{" "}
<Link to={`/${region}/wars`}>Wars</Link> page on the navigation bar, and select the war in question.
There, on the rightmost side of each quest, you will see the scripts that quest has available, and
can select the one you want. They are sorted into phases, so if the list says <b>1: 10, 11</b>, then
you know those two scripts come from phase 1 of the quest. For more details about when the scripts
appear in the quest, you can go to the quest's page.
</li>
<li>
<b>Via the Quests Page</b>
<br />
If you know what quest your script comes from, you can either utilize the{" "}
<Link to={`/${region}/quests`}>Quest Search</Link>, or utilize the{" "}
<Link to={`/${region}/wars`}>Wars</Link> page to navigate to the quest you have in mind. There, for
each phase of the quest, you can see which scripts are available and when they play in the quest
beneath the general quest information. Use the phase row to navigate between phases.
</li>
</ol>
</>
);
return {
id: "wars-quests-events",
title: "Wars, Quests, Events and Scripts",
subSections: [
{
id: "what-is-a-war",
title: "What is a War?",
content: whatIsAWar,
},
{
id: "breakdown-of-the-war-page",
title: "Breakdown of the War Page",
content: warBreakDown,
},
{
id: "what-is-a-quest",
title: "What is a Quest?",
content: whatIsAQuest,
},
{
id: "breakdown-of-the-quest-page",
title: "Breakdown of the Quest Page",
content: questBreakDown,
},
{
id: "where-can-i-find-hunting-and-trial-quests",
title: "Where can I find Hunting Quests / Trial Quests?",
content: huntingQuest,
},
{
id: "what-is-an-event",
title: "What is an Event / How are Events and Wars Different?",
content: whatIsAnEvent,
},
{
id: "breakdown-of-the-event-page",
title: "Breakdown of the Events Page",
content: eventBreakDown,
},
{
id: "how-can-i-find-story-text",
title: "How Can I Find Story Text?",
content: findAScript,
},
],
};
}
Example #18
Source File: WebhookItem.tsx From argo-react with MIT License | 4 votes |
WebhookItem: React.FC<IWebhookItemProps> = ({
id,
name,
branch,
protocol,
workspace,
framework,
packageManager,
buildCommand,
publishDirectory,
selectedProject,
type,
}) => {
const { selectedOrg } = useContext<IStateModel>(StateContext);
const { fetchProject } = useContext<IActionModel>(ActionContext);
const [editMode, setEditMode] = useState<boolean>(false);
const [removeWebhookLoading, setRemoveWebhookLoading] = useState<boolean>(false);
const [updateWebhookLoading, setUpdateWebhookLoading] = useState<boolean>(false);
const [repoBranches, setRepoBranches] = useState<any[]>([]);
const [repoBranchesLoading, setRepoBranchesLoading] = useState<boolean>(true);
const [editName, setEditName] = useState<string>("");
const [editBranch, setEditBranch] = useState<string>("");
const [editProtocol, setEditProtocol] = useState<string>("");
const [editWorkspace, setEditWorkspace] = useState<string>("");
const [editPackageManager, setEditPackageManager] = useState<string>("");
const [editBuildCommand, setEditBuildCommand] = useState<string>("");
const [editPublishDirectory, setEditPublishDirectory] = useState<string>("");
const [webhookDisabled, setWebhookDisabled] = useState<boolean>(false);
useEffect(() => {
if (name) {
setEditName(name);
}
if (branch) {
setEditBranch(branch);
}
if (protocol) {
setEditProtocol(protocol);
}
if (workspace) {
setEditWorkspace(workspace);
}
if (packageManager) {
setEditPackageManager(packageManager);
}
if (buildCommand) {
setEditBuildCommand(buildCommand);
}
if (publishDirectory) {
setEditPublishDirectory(publishDirectory);
}
}, [
name,
branch,
protocol,
workspace,
packageManager,
buildCommand,
publishDirectory,
]);
const componentIsMounted = useRef(true);
useEffect(() => {
return () => {
componentIsMounted.current = false;
};
}, []);
useEffect(() => {
if (
framework !== "static" &&
(name !== editName ||
branch !== editBranch ||
packageManager !== editPackageManager ||
buildCommand !== editBuildCommand ||
publishDirectory !== editPublishDirectory ||
protocol !== editProtocol ||
workspace !== editWorkspace)
) {
setWebhookDisabled(false);
} else {
if (
framework === "static" &&
(name !== editName ||
branch !== editBranch ||
protocol !== editProtocol ||
workspace !== editWorkspace)
) {
setWebhookDisabled(false);
} else {
setWebhookDisabled(true);
}
}
}, [
branch,
framework,
packageManager,
buildCommand,
publishDirectory,
selectedOrg,
protocol,
name,
editName,
editBranch,
editPackageManager,
editBuildCommand,
editPublishDirectory,
editProtocol,
workspace,
editWorkspace,
]);
useEffect(() => {
if (selectedProject && editMode) {
const repoName = selectedProject?.githubUrl
.substring(19, selectedProject?.githubUrl.length - 4)
.split("/")[1];
const ownerName = selectedProject?.githubUrl
.substring(19, selectedProject?.githubUrl.length - 4)
.split("/")[0];
const branchUrl = `https://api.github.com/repos/${ownerName}/${repoName}/branches`;
ApiService.getGithubRepoBranches(branchUrl).subscribe((res) => {
if (componentIsMounted.current) {
setRepoBranches(res.branches);
setRepoBranchesLoading(false);
}
});
}
}, [selectedProject, editMode]);
let buildCommandPrefix: string = "";
if (packageManager === "npm") {
buildCommandPrefix = "npm run";
} else {
buildCommandPrefix = "yarn";
}
const removeWebhook = () => {
setRemoveWebhookLoading(true);
ApiService.removeWebhook(id, { orgId: selectedOrg?._id }).subscribe((result) => {
if (result.success) {
setEditName("");
setEditBranch("");
setEditProtocol("");
setEditWorkspace("");
setEditPackageManager("");
setEditBuildCommand("");
setEditPublishDirectory("");
fetchProject(`${selectedProject?._id}`);
} else {
setEditName("");
setEditBranch("");
setEditProtocol("");
setEditWorkspace("");
setEditPackageManager("");
setEditBuildCommand("");
setEditPublishDirectory("");
}
setRemoveWebhookLoading(false);
});
};
const updateWebhook = () => {
setUpdateWebhookLoading(true);
const configuration = {
framework,
workspace: editWorkspace,
packageManager: editPackageManager,
buildCommand: editBuildCommand,
publishDir: editPublishDirectory,
branch: editBranch,
protocol: editProtocol,
};
ApiService.createConfiguration(configuration).subscribe((confResult) => {
if (componentIsMounted.current) {
const webhookMeta = {
orgId: selectedOrg?._id,
name: editName !== name ? editName : undefined,
branch: editBranch !== branch ? editBranch : undefined,
configurationId: confResult._id,
};
ApiService.editWebhook(id, webhookMeta).subscribe((result) => {
if (result.success) {
setEditName("");
setEditBranch("");
setEditProtocol("");
setEditWorkspace("");
setEditPackageManager("");
setEditBuildCommand("");
setEditPublishDirectory("");
fetchProject(`${selectedProject?._id}`);
} else {
setEditName("");
setEditBranch("");
setEditProtocol("");
setEditWorkspace("");
setEditPackageManager("");
setEditBuildCommand("");
setEditPublishDirectory("");
}
setUpdateWebhookLoading(false);
});
}
});
};
return (
<div className="webhook-item" key={id}>
{type === "filled" && (
<div className="webhook-item-container">
<ReactTooltip />
<div className="webhook-header">
<div className="webhook-header-left">
<div>
<LazyLoadedImage height={24} once>
<img
src={require("../../../../../../../../assets/svg/cd.svg")}
alt="webhook-icon"
className="webhook-icon"
height={24}
width={24}
loading="lazy"
/>
</LazyLoadedImage>
</div>
<div>{!editMode ? name.toUpperCase() : "Edit"}</div>
</div>
<div className="webhook-header-right">
{!editMode ? (
<button className="edit-button" onClick={(e) => setEditMode(true)}>
Edit
</button>
) : (
<button
className="save-button"
disabled={webhookDisabled}
onClick={updateWebhook}
>
<span style={{ marginRight: 4 }}>Save</span>
{updateWebhookLoading && (
<BounceLoader size={20} color={"#fff"} loading={true} />
)}
</button>
)}
{!editMode ? (
<button
className="remove-button"
disabled={removeWebhookLoading}
onClick={removeWebhook}
>
<span>Remove</span>
{removeWebhookLoading ? (
<BounceLoader size={20} color={"#ee0902"} loading={true} />
) : null}
</button>
) : (
<button
className="cancel-button"
onClick={(e) => setEditMode(false)}
>
Cancel
</button>
)}
</div>
</div>
<div className="deploy-site-item-form">
{editMode && (
<div className="deploy-site-item-form-item">
<label>
Name
<span
className="tooltip"
data-tip="name of your CD pipeline (e.g. PROD, DEV, TESTING)."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<input
type="text"
className="deploy-site-item-input"
value={editName}
onChange={(e) => setEditName(e.target.value)}
/>
</div>
)}
<div className="deploy-site-item-form-item">
<label>Branch to deploy</label>
{!editMode ? (
<span>{branch}</span>
) : (
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={editBranch}
onChange={(e) => setEditBranch(e.target.value)}
>
{repoBranches.map((branch, index) => (
<option value={branch.name} key={index}>
{branch.name}
</option>
))}
</select>
<span className="select-down-icon">
{!repoBranchesLoading ? (
<FontAwesomeIcon icon={faChevronDown} />
) : (
<BounceLoader size={20} color={"#0a3669"} loading={true} />
)}
</span>
</div>
)}
</div>
<div className="deploy-site-item-form-item">
<label>
Protocol
<span
className="tooltip"
data-tip="The framework that your app is built upon."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
{!editMode ? (
<span>{protocol}</span>
) : (
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={editProtocol}
onChange={(e) => setEditProtocol(e.target.value)}
>
<option value="arweave">Arweave</option>
<option value="skynet">Skynet</option>
<option value="ipfs-filecoin">IPFS-Filecoin</option>
<option value="ipfs-pinata">IPFS-Pinata</option>
</select>
<span className="select-down-icon">
<FontAwesomeIcon icon={faChevronDown} />
</span>
</div>
)}
</div>
<div className="deploy-site-item-form-item">
<label>
Workspace to deploy
<span
className="tooltip"
data-tip="If your app is a monorepo, then you can specify your app directory you want to deploy using the workspace."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
{!editMode ? (
<span>{workspace ? workspace : "N.A"}</span>
) : (
<input
type="text"
className="deploy-site-item-input"
value={editWorkspace}
onChange={(e) => setEditWorkspace(e.target.value)}
/>
)}
</div>
{framework !== "static" && (
<>
<div className="deploy-site-item-form-item">
<label>
Package Manager
<span
className="tooltip"
data-tip="The package manager that you want your app to be built with."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
{!editMode ? (
<span>{packageManager}</span>
) : (
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={editPackageManager}
onChange={(e) => setEditPackageManager(e.target.value)}
>
<option value="npm">NPM</option>
<option value="yarn">YARN</option>
</select>
<span className="select-down-icon">
<FontAwesomeIcon icon={faChevronDown} />
</span>
</div>
)}
</div>
<div className="deploy-site-item-form-item">
<label>
Build command
<span
className="tooltip"
data-tip="The command your frontend framework provides for compiling your code."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
{!editMode ? (
<span>
{packageManager === "npm" ? "npm run " : "yarn "}{" "}
{buildCommand}
</span>
) : framework !== "next" ? (
<div className="deploy-site-item-input-container">
<input
type="text"
className="deploy-site-item-input-disabled"
value={buildCommandPrefix}
disabled
/>
<input
type="text"
className="deploy-site-item-input-build"
value={editBuildCommand}
onChange={(e) => setEditBuildCommand(e.target.value)}
/>
</div>
) : (
<input
type="text"
className="deploy-site-item-input"
value={editBuildCommand}
onChange={(e) => setEditBuildCommand(e.target.value)}
/>
)}
</div>
<div className="deploy-site-item-form-item">
<label>
Publish directory
<span
className="tooltip"
data-tip="The directory in which your compiled frontend will be located."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
{!editMode ? (
<span>{publishDirectory}</span>
) : (
<input
type="text"
className="deploy-site-item-input"
value={editPublishDirectory}
onChange={(e) => setEditPublishDirectory(e.target.value)}
/>
)}
</div>
</>
)}
</div>
</div>
)}
{type === "skeleton" && (
<div className="webhook-item-container">
<div className="webhook-header">
<Skeleton width={250} duration={2} />
</div>
<div className="deploy-site-item-form">
<div className="deploy-site-item-form-item">
<label>
<Skeleton width={80} duration={2} />
</label>
<span>
<Skeleton width={150} duration={2} />
</span>
</div>
<div className="deploy-site-item-form-item">
<label>
<Skeleton width={80} duration={2} />
</label>
<span>
<Skeleton width={150} duration={2} />
</span>
</div>
<div className="deploy-site-item-form-item">
<label>
<Skeleton width={80} duration={2} />
</label>
<span>
<Skeleton width={150} duration={2} />
</span>
</div>
{framework !== "static" && (
<>
<div className="deploy-site-item-form-item">
<label>
<Skeleton width={80} duration={2} />
</label>
<span>
<Skeleton width={150} duration={2} />
</span>
</div>
<div className="deploy-site-item-form-item">
<label>
<Skeleton width={80} duration={2} />
</label>
<span>
<Skeleton width={150} duration={2} />
</span>
</div>
<div className="deploy-site-item-form-item">
<label>
<Skeleton width={80} duration={2} />
</label>
<span>
<Skeleton width={150} duration={2} />
</span>
</div>
</>
)}
</div>
</div>
)}
</div>
);
}
Example #19
Source File: ContinuousDeployment.tsx From argo-react with MIT License | 4 votes |
ContinuousDeployment = () => {
const { selectedProject, projectLoading, selectedOrg } =
useContext<IStateModel>(StateContext);
const { fetchProject } = useContext<IActionModel>(ActionContext);
const [repoBranches, setRepoBranches] = useState<any[]>([]);
const [repoBranchesLoading, setRepoBranchesLoading] = useState<boolean>(true);
const [addWebhookLoading, setAddWebhookLoading] = useState<boolean>(false);
const [installationId, setInstallationId] = useState<number>(0);
const [branch, setBranch] = useState<string>("");
const [name, setName] = useState<string>("");
const [workspace, setWorkspace] = useState<string>("");
const [framework, setFramework] = useState<string>("static");
const [packageManager, setPackageManager] = useState<string>("npm");
const [buildCommand, setBuildCommand] = useState<string>("");
const [publishDirectory, setPublishDirectory] = useState<string>("");
const [protocol, setProtocol] = useState<string>("");
const [webhookDisabled, setWebhookDisabled] = useState<boolean>(false);
const componentIsMounted = useRef(true);
useEffect(() => {
return () => {
componentIsMounted.current = false;
};
}, []);
let buildCommandPrefix: string = "";
if (packageManager === "npm") {
buildCommandPrefix = "npm run";
} else {
buildCommandPrefix = "yarn";
}
useEffect(() => {
if (
name &&
branch &&
framework !== "static" &&
packageManager &&
buildCommand &&
publishDirectory &&
protocol &&
installationId
) {
setWebhookDisabled(false);
} else {
if (name && branch && framework === "static" && protocol && installationId) {
setWebhookDisabled(false);
} else {
setWebhookDisabled(true);
}
}
}, [
branch,
framework,
packageManager,
buildCommand,
publishDirectory,
selectedOrg,
protocol,
name,
installationId,
]);
useEffect(() => {
if (framework === "static") {
setPackageManager("");
setBuildCommand("");
setPublishDirectory("");
} else if (framework === "react") {
setPackageManager("npm");
setBuildCommand("build");
setPublishDirectory("build");
} else if (framework === "vue") {
setPackageManager("npm");
setBuildCommand("build");
setPublishDirectory("dist");
} else if (framework === "angular") {
setPackageManager("npm");
setBuildCommand("build");
setPublishDirectory("dist/your-app-name");
} else if (framework === "next") {
setPackageManager("yarn");
setBuildCommand("next build && next export");
setPublishDirectory("out");
}
}, [framework]);
useEffect(() => {
if (selectedProject) {
const repoName = selectedProject?.githubUrl
.substring(19, selectedProject?.githubUrl.length - 4)
.split("/")[1];
const ownerName = selectedProject?.githubUrl
.substring(19, selectedProject?.githubUrl.length - 4)
.split("/")[0];
const branchUrl = `https://api.github.com/repos/${ownerName}/${repoName}/branches`;
ApiService.getGithubRepoBranches(branchUrl).subscribe((res) => {
if (componentIsMounted.current) {
setRepoBranches(res.branches);
setBranch(res.branches[0].name);
setRepoBranchesLoading(false);
}
});
ApiService.getAllGithubAppInstallation().subscribe((res) => {
if (componentIsMounted.current) {
const repoOwners: any[] = res.installations.map((installation: any) => ({
name: installation.account.login,
avatar: installation.account.avatar_url,
installationId: installation.id,
}));
if (repoOwners.length) {
const newRepoOwner = repoOwners.filter(
(repoOwner) => repoOwner.name === ownerName,
)[0];
setInstallationId(newRepoOwner.installationId);
}
}
});
const framework = selectedProject.latestDeployment?.configuration.framework;
const protocol = selectedProject.latestDeployment?.configuration.protocol;
setFramework(framework ? framework : "");
setProtocol(protocol ? protocol : "");
}
}, [selectedProject]);
const addWebhook = () => {
setAddWebhookLoading(true);
const configuration = {
framework,
workspace,
packageManager,
buildCommand,
publishDir: publishDirectory,
branch,
protocol,
};
ApiService.createConfiguration(configuration).subscribe((confResult) => {
if (componentIsMounted.current) {
const webhook = {
orgId: selectedOrg?._id,
projectId: selectedProject?._id,
installationId,
};
ApiService.connectWebhook(webhook).subscribe((result) => {
if (componentIsMounted.current) {
const webhookMeta = {
orgId: selectedOrg?._id,
name,
projectId: selectedProject?._id,
configurationId: confResult._id,
installationId,
};
ApiService.createWebhook(webhookMeta).subscribe((result) => {
if (componentIsMounted.current) {
setName("");
setBranch(repoBranches[0].name);
setWorkspace("");
setFramework("static");
setPackageManager("npm");
setBuildCommand("");
setPublishDirectory("");
setProtocol("");
setAddWebhookLoading(false);
fetchProject(`${selectedProject?._id}`);
}
});
}
});
}
});
};
return (
<div className="ContinuousDeployment">
<ReactTooltip />
<div className="settings-right-container">
<div className="settings-project-details">
<div className="settings-project-header">Continuous Deployment</div>
<div className="settings-project-body">
<div className="settings-project-header-subtitle">
Settings for Continuous Deployment from a Git repository
</div>
<div className="settings-project-add-webhook-conf">
<div className="webhook-header">Add new</div>
<div className="deploy-site-item-form">
<div className="deploy-site-item-form-item">
<label>
Name
<span
className="tooltip"
data-tip="name of your CD pipeline (e.g. PROD, DEV, TESTING)."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<input
type="text"
className="deploy-site-item-input"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<div className="deploy-site-item-form-item">
<label>Branch to deploy</label>
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={branch}
onChange={(e) => setBranch(e.target.value)}
>
{repoBranches.map((branch, index) => (
<option value={branch.name} key={index}>
{branch.name}
</option>
))}
</select>
<span className="select-down-icon">
{!repoBranchesLoading ? (
<FontAwesomeIcon icon={faChevronDown} />
) : (
<BounceLoader size={20} color={"#0a3669"} loading={true} />
)}
</span>
</div>
</div>
<div className="deploy-site-item-form-item">
<label>
Protocol
<span
className="tooltip"
data-tip="The framework that your app is built upon."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={protocol}
onChange={(e) => setProtocol(e.target.value)}
>
<option value="arweave">Arweave</option>
<option value="skynet">Skynet</option>
<option value="ipfs-filecoin">IPFS-Filecoin</option>
<option value="ipfs-pinata">IPFS-Pinata</option>
</select>
<span className="select-down-icon">
<FontAwesomeIcon icon={faChevronDown} />
</span>
</div>
</div>
<div className="deploy-site-item-form-item">
<label>
Workspace to deploy
<span
className="tooltip"
data-tip="If your app is a monorepo, then you can specify your app directory you want to deploy using the workspace."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<input
type="text"
className="deploy-site-item-input"
value={workspace}
onChange={(e) => setWorkspace(e.target.value)}
/>
</div>
{framework !== "static" && (
<>
<div className="deploy-site-item-form-item">
<label>
Package Manager
<span
className="tooltip"
data-tip="The package manager that you want your app to be built with."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={packageManager}
onChange={(e) => setPackageManager(e.target.value)}
>
<option value="npm">NPM</option>
<option value="yarn">YARN</option>
</select>
<span className="select-down-icon">
<FontAwesomeIcon icon={faChevronDown} />
</span>
</div>
</div>
<div className="deploy-site-item-form-item">
<label>
Build command
<span
className="tooltip"
data-tip="The command your frontend framework provides for compiling your code."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
{framework !== "next" ? (
<div className="deploy-site-item-input-container">
<input
type="text"
className="deploy-site-item-input-disabled"
value={buildCommandPrefix}
disabled
/>
<input
type="text"
className="deploy-site-item-input-build"
value={buildCommand}
onChange={(e) => setBuildCommand(e.target.value)}
/>
</div>
) : (
<input
type="text"
className="deploy-site-item-input"
value={buildCommand}
onChange={(e) => setBuildCommand(e.target.value)}
/>
)}
</div>
<div className="deploy-site-item-form-item">
<label>
Publish directory
<span
className="tooltip"
data-tip="The directory in which your compiled frontend will be located."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<input
type="text"
className="deploy-site-item-input"
value={publishDirectory}
onChange={(e) => setPublishDirectory(e.target.value)}
/>
</div>
</>
)}
</div>
<div className="button-container">
<button
type="button"
className="primary-button"
onClick={addWebhook}
disabled={webhookDisabled}
>
{addWebhookLoading && (
<BounceLoader size={20} color={"#fff"} loading={true} />
)}
Add
</button>
</div>
</div>
<div>
{!projectLoading ? (
selectedProject?.webHooks.length ? (
<>
<div className="continuous-deployment-list-heading">
Your Configured Continuous Deployments
</div>
{selectedProject?.webHooks.map((hook) => (
<WebhookItem
type="filled"
id={hook._id}
name={hook.name}
branch={hook.branch}
protocol={hook.configurationId.protocol}
framework={hook.configurationId.framework}
workspace={hook.configurationId.workspace}
buildCommand={hook.configurationId.buildCommand}
publishDirectory={hook.configurationId.publishDir}
packageManager={hook.configurationId.packageManager}
selectedProject={selectedProject}
/>
))}
</>
) : null
) : (
<>
<div className="continuous-deployment-list-heading">
Your Configured Continuous Deployments
</div>
<WebhookItem
type="skeleton"
id={"1"}
name={""}
branch={""}
protocol={""}
framework={""}
workspace={""}
buildCommand={""}
publishDirectory={""}
packageManager={""}
selectedProject={selectedProject}
/>
</>
)}
</div>
</div>
</div>
</div>
</div>
);
}
Example #20
Source File: Deployment.tsx From argo-react with MIT License | 4 votes |
Deployment = () => { const timeAgo = new TimeAgo("en-US"); const history = useHistory(); const params = useParams<any>(); const defaultOptions = { loop: true, autoplay: true, animationData, rendererSettings: { preserveAspectRatio: "xMidYMid", }, }; const { currentSiteDeployConfig, currentSiteDeployLogs, selectedProject } = useContext<IStateModel>(StateContext); const { setLatestDeploymentLogs, setLatestDeploymentConfig, fetchProject } = useContext<IActionModel>(ActionContext); const [deploymentStatus, setDeploymentStatus] = useState<string>("pending"); const [buildTime, setBuildTime] = useState<{ min: number; sec: number }>({ min: 0, sec: 0, }); const [paymentStatus, setPaymentStatus] = useState<string>("waiting"); const [livePaymentStatus, setlivePaymentStatus] = useState<string>("waiting"); const [paymentMessage, setPaymentMessage] = useState<string>(""); const [paymentDetails, setPaymentDetails] = useState<{ providerFee: number; argoFee: number; discount: number; finalArgoFee: number; token: string; }>({ providerFee: 0, argoFee: 0, discount: 0, finalArgoFee: 0, token: "ARGO" }); const [deployedLink, setDeployedLink] = useState<string>(""); const [deploymentLoading, setDeploymentLoading] = useState<boolean>(true); const [confettiStart, setConfettiStart] = useState<boolean>(false); const [pinDetailLoading, setPinDetailLoading] = useState<boolean>(true); const [pinDetail, setPinDetail] = useState<any>({ cid: "N.A", isPinned: false }); const componentIsMounted = useRef(true); let socket: any = null; let deploymentSvc: any = null; useEffect(() => { fetchProject(params.siteid); deploymentStartup(); return () => { if (socket) { socket.disconnect(); } if (deploymentSvc) { deploymentSvc.unsubscribe(); } componentIsMounted.current = false; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const deploymentStartup = async () => { setDeploymentLoading(true); setLatestDeploymentLogs([]); setDeploymentStatus("pending"); setPaymentStatus("waiting"); setPaymentDetails({ providerFee: 0, argoFee: 0, discount: 0, finalArgoFee: 0, token: "ARGO", }); setBuildTime({ min: 0, sec: 0, }); socket = socketIOClient(config.urls.API_URL); deploymentSvc = ApiService.getDeployment(params.deploymentid).subscribe( (result) => { if (componentIsMounted.current) { const deployment = { githubUrl: result.deployment.project.githubUrl, branch: result.deployment.configuration.branch, createdAt: result.deployment.createdAt, updatedAt: result.deployment.updatedAt, protocol: result.deployment.configuration.protocol, commitHash: result.deployment.commitId, commitMessage: result.deployment.commitMessage, }; setLatestDeploymentConfig(deployment); currentSiteDeployLogs.splice(0, currentSiteDeployLogs.length); result.deployment.logs.forEach((logItem: any) => { logItem.log.split("\n").forEach((line: string) => { if (line.trim()) { currentSiteDeployLogs.push({ log: line, time: moment(logItem.time).format("hh:mm:ss A MM-DD-YYYY"), }); } }); setLatestDeploymentLogs(currentSiteDeployLogs); scrollToWithContainer(currentSiteDeployLogs.length - 1); }); if (result.deployment.status.toLowerCase() === "pending") { socket.on(`deployment.${result.deployment.topic}`, (stream: any) => { if (stream.type === 1) { stream.data.split("\n").forEach((line: string) => { if (line.trim()) { if ( currentSiteDeployLogs .map((l) => l.log) .indexOf(line.trim()) === -1 ) { currentSiteDeployLogs.push({ log: line, time: moment().format("hh:mm:ss A MM-DD-YYYY"), }); } } }); setDeploymentStatus("pending"); setLatestDeploymentLogs(currentSiteDeployLogs); scrollToWithContainer(currentSiteDeployLogs.length - 1); } else if (stream.type === 2) { const protocolLink = stream.data.logsToCapture.sitePreview; setDeployedLink(protocolLink); setDeploymentStatus(protocolLink ? "deployed" : "failed"); const buildMins = Number.parseInt(`${stream.data.buildTime / 60}`); const buildSecs = Number.parseInt(`${stream.data.buildTime % 60}`); setBuildTime({ min: buildMins, sec: buildSecs }); } else if (stream.type === 3) { setDeployedLink(""); setDeploymentStatus("failed"); setBuildTime({ min: 0, sec: 0 }); } }); } else { setDeployedLink(result.deployment.sitePreview); setDeploymentStatus(result.deployment.status.toLowerCase()); const buildMins = Number.parseInt(`${result.deployment.buildTime / 60}`); const buildSecs = Number.parseInt(`${result.deployment.buildTime % 60}`); setBuildTime({ min: buildMins, sec: buildSecs }); } const paymentSocketOpeningCondition = result.deployment.payment ? result.deployment.payment.status !== "success" && result.deployment.payment.status !== "failed" : true; if (paymentSocketOpeningCondition) { if (result.deployment.payment) { setPaymentStatus(result.deployment.payment.status); } socket.on(`payment.${result.deployment.topic}`, (stream: any) => { if (stream.type === 1) { setPaymentStatus("started"); } else if (stream.type === 2) { const paymentDetails = stream.payload; if (paymentDetails.status === "success") { setPaymentDetails(paymentDetails); setlivePaymentStatus("success"); } else { setPaymentMessage(paymentDetails.failedMessage); } setPaymentStatus(paymentDetails.status); } }); } else { if (result.deployment.payment.status === "success") { const paymentDetails = { providerFee: result.deployment.payment.providerFee, argoFee: result.deployment.payment.argoFee, discount: result.deployment.payment.discount, finalArgoFee: result.deployment.payment.finalArgoFee, token: result.deployment.payment.token, }; setPaymentDetails(paymentDetails); setPaymentStatus("success"); } else { setPaymentStatus("failed"); setPaymentMessage(result.deployment.payment.failedMessage); } } setDeploymentLoading(false); } }, ); }; useEffect(() => { if (deploymentStatus === "deployed" && livePaymentStatus === "success") { setConfettiStart(true); } }, [deploymentStatus, livePaymentStatus]); let displayGithubRepo = ""; let githubBranchLink = ""; let githubCommitLink = ""; if (currentSiteDeployConfig) { displayGithubRepo = currentSiteDeployConfig.githubUrl.substring( 19, currentSiteDeployConfig.githubUrl.length - 4, ); githubBranchLink = `${currentSiteDeployConfig.githubUrl.substring( 0, currentSiteDeployConfig.githubUrl.length - 4, )}/tree/${currentSiteDeployConfig.branch}`; githubCommitLink = `${currentSiteDeployConfig.githubUrl.substring( 0, currentSiteDeployConfig.githubUrl.length - 4, )}/commit/${currentSiteDeployConfig.commitHash}`; } const domains = selectedProject && deployedLink ? selectedProject.domains.filter((d) => deployedLink.indexOf(d.link) !== -1) : []; const subdomains = selectedProject && deployedLink ? selectedProject.subdomains.filter((d) => deployedLink.indexOf(d.link) !== -1) : []; const hnsDomains = selectedProject && deployedLink ? selectedProject.handshakeDomains.filter( (d) => deployedLink.indexOf(d.link) !== -1, ) : []; const hnsSubdomains = selectedProject && deployedLink ? selectedProject.handshakeSubdomains.filter( (d) => deployedLink.indexOf(d.link) !== -1, ) : []; const ensDomains = selectedProject && deployedLink ? selectedProject.ensDomains.filter((d) => deployedLink.indexOf(d.link) !== -1) : []; const isDomainOrSubPresent = [...domains, ...subdomains, ...hnsDomains, ...hnsSubdomains, ...ensDomains] .length > 0; const scrollToWithContainer = (index: number) => { window.scrollTo({ top: document.getElementById("deploy-logs-container")?.scrollHeight, left: 0, behavior: "smooth", }); var myElement = document.getElementById(`deploy-logs-items-${index}`); var topPos = myElement?.offsetTop; if (document && document.getElementById("deploy-logs-list")) { (document as any).getElementById("deploy-logs-list").scrollTop = topPos ? topPos : 0; } }; const showProtocolImage = (protocol: string) => { switch (protocol) { case "arweave": return ( <img src={require("../../../../assets/png/ar_light.png")} alt="arweave" className="site-deployment-logo" height={24} width={24} loading="lazy" /> ); case "skynet": return ( <img src={require("../../../../assets/png/skynet.png")} alt="skynet" className="site-deployment-logo" height={24} width={24} loading="lazy" /> ); case "ipfs-filecoin": return ( <img src={require("../../../../assets/png/filecoin.png")} alt="skynet" className="site-deployment-logo" height={24} width={24} loading="lazy" /> ); case "ipfs-pinata": return ( <img src={require("../../../../assets/svg/pinata.svg")} alt="skynet" className="site-deployment-logo" height={24} width={24} loading="lazy" /> ); case "neofs": return ( <img src={require("../../../../assets/png/neo-light.png")} alt="neofs" className="site-deployment-logo" height={24} width={24} loading="lazy" /> ); default: return ( <img src={require("../../../../assets/png/question_mark.png")} alt="?" className="site-deployment-logo" height={24} width={24} loading="lazy" /> ); } }; const showProtocolText = (protocol: string) => { switch (protocol) { case "arweave": return ( <span className="site-deployment-link"> Deploying on Arweave, Preview in a minute </span> ); case "skynet": return ( <span className="site-deployment-link"> Deploying on Skynet, Preview in a minute </span> ); case "ipfs-filecoin": return ( <span className="site-deployment-link"> Deploying on IPFS with Filecoin, Preview in a minute </span> ); case "ipfs-pinata": return ( <span className="site-deployment-link"> Deploying on IPFS with Pinata, Preview in a minute </span> ); case "neofs": return ( <span className="site-deployment-link"> Deploying on NeoFS, Preview in a minute </span> ); default: return ( <span className="site-deployment-link"> Cannot find Protocol to Deploy </span> ); } }; const showProtocolPrice = (protocol: string) => { switch (protocol) { case "arweave": return <span>{paymentDetails?.providerFee || 0} AR</span>; case "skynet": return <span>N.A</span>; case "neofs": return <span>{paymentDetails?.providerFee || 0} NEO</span>; case "ipfs-filecoin": return <span>{paymentDetails?.providerFee || 0} FIL</span>; case "ipfs-pinata": return <span>N.A</span>; default: return <span>{paymentDetails?.providerFee || 0} ?</span>; } }; useEffect(() => { if (deploymentStatus === "deployed") { if (currentSiteDeployConfig?.protocol === "ipfs-filecoin") { getFilecoinPinDetais(); } else if (currentSiteDeployConfig?.protocol === "ipfs-pinata") { getPinataPinDetais(); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [deploymentStatus, currentSiteDeployConfig?.protocol]); const getFilecoinPinDetais = async () => { setPinDetailLoading(true); if (deployedLink) { const cid = deployedLink.split("https://ipfs.infura.io/ipfs/")[1]; ApiService.getFilecoinPinDetails(cid).subscribe((data) => { if (componentIsMounted.current) { setPinDetail(data); setPinDetailLoading(false); } }); } else { setPinDetailLoading(false); } }; const getPinataPinDetais = async () => { setPinDetailLoading(true); if (deployedLink) { const cid = deployedLink.split("https://ipfs.infura.io/ipfs/")[1]; ApiService.getPinataPinDetails(cid).subscribe((data) => { if (componentIsMounted.current) { setPinDetail(data); setPinDetailLoading(false); } }); } else { setPinDetailLoading(false); } }; const [width, height] = useWindowSize(); const confettiStyles = { zIndex: 2, position: "fixed" as "fixed", pointerEvents: "none" as "none", top: 0, left: 0, bottom: 0, right: 0, }; return ( <div className="SiteDeployment"> {confettiStart && ( <div className="confetti-container"> <Confetti width={width} height={height} style={confettiStyles} numberOfPieces={700} recycle={false} /> </div> )} <div className="site-deployment-back" onClick={(e) => { fetchProject(params.siteid); history.push(`/org/${params.orgid}/sites/${params.siteid}/deployments/`); }} > <span> <FontAwesomeIcon icon={faChevronLeft} /> </span> <span>All Deploys</span> </div> <div className="site-deployment-card-container max-width-set"> <div className="site-deployment-card-header"> <h2 className="site-deployment-card-header-title"> {!deploymentLoading ? ( <> <span> {deploymentStatus === "pending" ? ( "Deploy in Progress" ) : deploymentStatus === "deployed" ? ( <div>Deployment successful</div> ) : ( "Deployment failed" )} </span> {deploymentStatus === "pending" ? ( <Lottie options={defaultOptions} height={54} width={76} /> ) : deploymentStatus === "deployed" ? ( <LazyLoadedImage height={24} once> <img src={require("../../../../assets/svg/rocket_background.svg")} alt="rocket" className="rocket-icon" height={24} width={24} loading="lazy" /> </LazyLoadedImage> ) : deploymentStatus === "failed" ? ( <LazyLoadedImage height={24} once> <img src={require("../../../../assets/svg/error.svg")} alt="rocket" className="rocket-icon" height={24} width={24} loading="lazy" /> </LazyLoadedImage> ) : null} </> ) : ( <Skeleton width={200} duration={2} /> )} </h2> <p className="site-deployment-card-header-description"> {!deploymentLoading ? ( <> <u>Production</u>: {currentSiteDeployConfig?.branch} {currentSiteDeployConfig.commitHash ? ( <> @ <a href={githubCommitLink} target="_blank" rel="noopener noreferrer" className="commit-link" > {currentSiteDeployConfig.commitHash.substr(0, 7)}{" "} {currentSiteDeployConfig.commitMessage ? `- ${currentSiteDeployConfig.commitMessage.substr( 0, 84, )}...` : ""} </a> </> ) : null} </> ) : ( <Skeleton width={400} duration={2} /> )} </p> <p className="site-deployment-card-header-description"> {!deploymentLoading ? ( <> {deploymentStatus === "pending" ? currentSiteDeployLogs[0]?.time ? `Deployment started ${timeAgo.format( moment(`${currentSiteDeployConfig.createdAt}`).toDate(), )}` : null : `Deployment done at ${moment( currentSiteDeployConfig.updatedAt, ).format("MMM DD, YYYY hh:mm a")}`} </> ) : ( <Skeleton width={400} duration={2} /> )} </p> </div> <div className="site-deployment-card-content"> {isDomainOrSubPresent && ( <div className="site-deployment-card-fields"> <span className="site-deployment-github-icon"> <FontAwesomeIcon icon={faGlobe} /> </span> {!deploymentLoading ? ( <> {domains.map((d: IDomain, i: number, a: IDomain[]) => ( <> <a href={`https://${d.name}`} className="site-deployment-link" target="_blank" rel="noopener noreferrer" > {d.name} </a> {(i !== a.length - 1 || subdomains.length > 0 || hnsDomains.length > 0 || hnsSubdomains.length > 0 || ensDomains.length > 0) && ( <span className="comma-sep">,</span> )} </> ))} {subdomains.map((s: IDomain, i: number, a: IDomain[]) => ( <> <a href={`https://${s.name}`} className="site-deployment-link" target="_blank" rel="noopener noreferrer" > {s.name} </a> {(i !== a.length - 1 || hnsDomains.length > 0 || hnsSubdomains.length > 0 || ensDomains.length > 0) && ( <span className="comma-sep">,</span> )} </> ))} {hnsDomains.map((s: IDomain, i: number, a: IDomain[]) => ( <> <a href={`http://${s.name}`} className="site-deployment-link" target="_blank" rel="noopener noreferrer" > {s.name} </a> {(i !== a.length - 1 || hnsSubdomains.length > 0 || ensDomains.length > 0) && ( <span className="comma-sep">,</span> )} </> ))} {hnsSubdomains.map((s: IDomain, i: number, a: IDomain[]) => ( <> <a href={`http://${s.name}`} className="site-deployment-link" target="_blank" rel="noopener noreferrer" > {s.name} </a> {(i !== a.length - 1 || ensDomains.length > 0) && ( <span className="comma-sep">,</span> )} </> ))} {ensDomains.map((s: IDomain, i: number, a: IDomain[]) => ( <> <a href={`http://${s.name}`} className="site-deployment-link" target="_blank" rel="noopener noreferrer" > {s.name} </a> {i !== a.length - 1 && <span className="comma-sep">,</span>} </> ))} </> ) : ( <Skeleton width={300} duration={2} /> )} </div> )} <div className="site-deployment-card-fields"> <span className="site-deployment-github-icon"> <FontAwesomeIcon icon={faGithub} /> </span> {!deploymentLoading ? ( <a href={githubBranchLink} className="site-deployment-link" target="_blank" rel="noopener noreferrer" > {displayGithubRepo} (branch: {currentSiteDeployConfig?.branch}) </a> ) : ( <Skeleton width={300} duration={2} /> )} </div> <div className="site-deployment-card-fields"> <LazyLoadedImage height={24} once> {showProtocolImage(currentSiteDeployConfig?.protocol)} </LazyLoadedImage> {!deploymentLoading ? ( deploymentStatus === "deployed" ? ( <a href={deployedLink} className="site-deployment-link" target="_blank" rel="noopener noreferrer" > Preview deploy </a> ) : deploymentStatus === "pending" ? ( showProtocolText(currentSiteDeployConfig?.protocol) ) : ( <span className="site-deployment-link"> Deploying failed, no link available </span> ) ) : ( <Skeleton width={200} duration={2} /> )} </div> {paymentStatus === "success" && deploymentStatus === "deployed" && ( <div className="site-deployment-card-fields"> <div className="button-container"> <SharePopup isOpen={confettiStart} link={deployedLink} protocol={currentSiteDeployConfig.protocol} paymentStatus={paymentStatus} /> </div> </div> )} </div> </div> {deploymentStatus !== "pending" && ( <div className="site-deployment-card-container deploy-container"> <div className="site-deployment-header-title">Deploy Summary</div> <div className="deploy-summary-item"> <div className="deploy-summary-item-info-icon"> <FontAwesomeIcon icon={faInfoCircle} /> </div> <div className="deploy-summary-item-info-container"> <div className="deploy-summary-item-info-title"> Total time to Build & Deploy: {buildTime?.min}m {buildTime?.sec}s </div> {(buildTime?.min !== 0 || buildTime?.sec !== 0) && ( <div className="deploy-summary-item-info-description"> Build started at {currentSiteDeployLogs[0]?.time} and ended at{" "} {currentSiteDeployLogs[currentSiteDeployLogs.length - 1]?.time}. </div> )} </div> </div> </div> )} {deploymentStatus !== "pending" && ( <div className="site-deployment-card-container deploy-container"> <div className="site-deployment-header-title">Payment Summary</div> <div className="site-deployment-body"> {paymentStatus === "waiting" && ( <div className="payment-loading"> <span> <PulseLoader size={20} color={"#3664ae"} /> </span> <span>Waiting for the payment to be processed...</span> </div> )} {paymentStatus === "started" && ( <div className="payment-loading"> <span> <PulseLoader size={20} color={"#3664ae"} /> </span> <span>Processing Payment...</span> </div> )} {paymentStatus === "failed" && ( <div className="payment-failed"> <span> <LazyLoadedImage height={24} once> <img src={require("../../../../assets/svg/error.svg")} alt="rocket" className="rocket-icon" height={36} width={36} loading="lazy" /> </LazyLoadedImage> </span> <span>{paymentMessage}</span> {paymentMessage === "Payment failed due to insufficient allowance." && ( <button className="set-allowance" onClick={() => history.push("/wallet/recharge")} > Set Allowance </button> )} </div> )} {paymentStatus === "success" && ( <> <div className="site-deployment-body-item"> <label>Build Time:</label> <span> {buildTime?.min}m {buildTime?.sec}s </span> </div> <div className="site-deployment-body-item"> <label>Provider Fee:</label> {showProtocolPrice(currentSiteDeployConfig?.protocol)} </div> <div className="site-deployment-body-item"> <label>Total Fee:</label> <span> {paymentDetails?.argoFee || 0} ${paymentDetails?.token || "ARGO"} </span> </div> <div className="site-deployment-body-item"> <label>Discount:</label> <span> {paymentDetails?.discount || 0} $ {paymentDetails?.token || "ARGO"} </span> </div> <div className="site-deployment-body-item"> <label>Final Payment:</label> <span> {paymentDetails?.finalArgoFee || 0} $ {paymentDetails?.token || "ARGO"} </span> </div> </> )} </div> </div> )} {deploymentStatus === "deployed" && currentSiteDeployConfig?.protocol === "ipfs-filecoin" && ( <div className="site-deployment-card-container deploy-container"> <div className="site-deployment-header-title"> Filecoin Pinning Details </div> <div className="site-deployment-body"> <div className="site-deployment-body-item"> <label>Filecoin CID:</label> <span> {!pinDetailLoading ? ( pinDetail.cid ) : ( <Skeleton width={200} duration={2} /> )} </span> </div> <div className="site-deployment-body-item"> <label>Filecoin Pinning Status:</label> <span> {!pinDetailLoading ? ( pinDetail.isPinned ? ( "Pinned" ) : ( "Not Pinned" ) ) : ( <Skeleton width={200} duration={2} /> )} </span> </div> {!pinDetailLoading && pinDetail.isPinned && ( <div className="site-deployment-body-item"> <label>Filecoin Pinned Date:</label> <span> {!pinDetailLoading ? ( moment(pinDetail.pinnedDate).format("MMM DD, YYYY hh:mm A") ) : ( <Skeleton width={200} duration={2} /> )} </span> </div> )} </div> </div> )} {deploymentStatus === "deployed" && currentSiteDeployConfig?.protocol === "ipfs-pinata" && ( <div className="site-deployment-card-container deploy-container"> <div className="site-deployment-header-title"> Pinata Pinning Details </div> <div className="site-deployment-body"> <div className="site-deployment-body-item"> <label>IPFS CID:</label> <span> {!pinDetailLoading ? ( pinDetail.cid ) : ( <Skeleton width={200} duration={2} /> )} </span> </div> <div className="site-deployment-body-item"> <label>IPFS Pinning Status:</label> <span> {!pinDetailLoading ? ( pinDetail.isPinned ? ( "Pinned" ) : ( "Not Pinned" ) ) : ( <Skeleton width={200} duration={2} /> )} </span> </div> {!pinDetailLoading && pinDetail.isPinned && ( <div className="site-deployment-body-item"> <label>IPFS Pinned Date:</label> <span> {!pinDetailLoading ? ( moment(pinDetail.pinnedDate).format("MMM DD, YYYY hh:mm A") ) : ( <Skeleton width={200} duration={2} /> )} </span> </div> )} </div> </div> )} <div className="site-deployment-card-container deploy-container" id="deploy-logs-container" > <div className="card-header-title deploy-logs-card-title"> <div className="card-header-deploy-title-container"> <div className="card-header-deploy-title">Deploy Logs</div> <div className="card-header-deploy-subtitle"> Please note that the realtime log streaming may not show all the logs based on your connection bandwidth. Please refresh if you don't see some logs </div> </div> {/* <button className="copy-to-clipboard-button">Copy to clipboard</button> */} <div className="refresh-control" onClick={deploymentStartup}> <FontAwesomeIcon icon={faSyncAlt}></FontAwesomeIcon> </div> </div> <div className="deploy-logs-container" id="deploy-logs-list"> { <div className="deploy-logs-items" id={`deploy-logs-items-${1}`} key={1}> {currentSiteDeployLogs?.map((currLog, i) => ( <div className="deploy-logs-items" id={`deploy-logs-items-${i}`} key={i} > {currLog.time}:{" "} {currLog.log.indexOf("https://arweave.net/") !== -1 || currLog.log.indexOf("https://siasky.net/") !== -1 || currLog.log.indexOf("https://http.fs.neo.org/") !== -1 || currLog.log.indexOf("https://ipfs.infura.io/ipfs/") !== -1 ? ( <a href={currLog.log.trim()} className="log-site-link" target="_blank" rel="noopener noreferrer" > {currLog.log} </a> ) : ( currLog.log )} </div> ))} </div> } </div> </div> </div> ); }
Example #21
Source File: DeploySiteConfig.tsx From argo-react with MIT License | 4 votes |
function DeploySiteConfig() {
const history = useHistory();
const {
user,
selectedOrg,
selectedRepoForTriggerDeployment,
orgLoading,
userLoading,
} = useContext<IStateModel>(StateContext);
const { setLatestDeploymentConfig, setSelectedOrganization } =
useContext<IActionModel>(ActionContext);
const [createDeployProgress, setCreateDeployProgress] = useState(1);
const [showRepoOrgDropdown, setShowRepoOrgDropdown] = useState<boolean>(false);
const [reposOwnerDetails, setReposOwnerDetails] = useState<any[]>([]);
const [reposSelectedOwnerRepoDetails, setReposSelectedOwnerRepoDetails] = useState<
any[]
>([]);
const [selectedRepoOwner, setSelectedRepoOwner] = useState<any>();
const [currentRepoOwner, setCurrentRepoOwner] = useState<string>("");
const [ownerLoading, setOwnerLoading] = useState<boolean>(true);
const [repoLoading, setRepoLoading] = useState<boolean>(true);
const [repoBranches, setRepoBranches] = useState<any[]>([]);
const [buildEnv, setBuildEnv] = useState<any[]>([]);
const [repoBranchesLoading, setRepoBranchesLoading] = useState<boolean>(true);
const [autoPublish, setAutoPublish] = useState<boolean>(true);
const [selectedRepo, setSelectedRepo] = useState<any>();
const [owner, setOwner] = useState<any>();
const [branch, setBranch] = useState<string>("master");
const [workspace, setWorkspace] = useState<string>();
const [framework, setFramework] = useState<string>("react");
const [packageManager, setPackageManager] = useState<string>("npm");
const [buildCommand, setBuildCommand] = useState<string>("");
const [publishDirectory, setPublishDirectory] = useState<string>("");
const [protocol, setProtocol] = useState<string>("");
const [startDeploymentLoading, setStartDeploymentLoading] =
useState<boolean>(false);
const [deployDisabled, setDeployDisabled] = useState<boolean>(false);
const [showGithubRepos, setShowGithubRepos] = useState<boolean>(false);
const [errorWarning, setErrorWarning] = useState<boolean>(false);
const [errorMessage, setErrorMessage] = useState<string>("");
const componentIsMounted = useRef(true);
useEffect(() => {
return () => {
componentIsMounted.current = false;
};
}, []);
useEffect(() => {
if (
selectedRepo &&
owner &&
branch &&
framework !== "static" &&
packageManager &&
buildCommand &&
publishDirectory &&
protocol &&
selectedOrg?.wallet &&
!orgLoading
) {
setDeployDisabled(false);
} else {
if (
selectedRepo &&
owner &&
branch &&
framework === "static" &&
protocol &&
selectedOrg?.wallet &&
!orgLoading
) {
setDeployDisabled(false);
} else {
setDeployDisabled(true);
}
}
}, [
selectedRepo,
owner,
branch,
framework,
packageManager,
buildCommand,
publishDirectory,
user,
selectedOrg,
orgLoading,
protocol,
]);
useEffect(() => {
if (framework === "static") {
setPackageManager("");
setBuildCommand("");
setPublishDirectory("");
} else if (framework === "react") {
setPackageManager("npm");
setBuildCommand("build");
setPublishDirectory("build");
} else if (framework === "vue") {
setPackageManager("npm");
setBuildCommand("build");
setPublishDirectory("dist");
} else if (framework === "angular") {
setPackageManager("npm");
setBuildCommand("build");
setPublishDirectory("dist/your-app-name");
} else if (framework === "next") {
setPackageManager("yarn");
setBuildCommand("next build && next export");
setPublishDirectory("out");
}
}, [framework]);
useEffect(() => {
if (selectedOrg) {
setOwner(selectedOrg);
} else if (user?.organizations && user.organizations[0]) {
setOwner(user.organizations[0]);
}
}, [user, selectedOrg]);
useEffect(() => {
if (selectedRepoForTriggerDeployment) {
const repoName = selectedRepoForTriggerDeployment.github_url
.substring(19, selectedRepoForTriggerDeployment.github_url.length - 4)
.split("/")[1];
const ownerName = selectedRepoForTriggerDeployment.github_url
.substring(19, selectedRepoForTriggerDeployment.github_url.length - 4)
.split("/")[0];
setSelectedRepo({
name: repoName,
clone_url: selectedRepoForTriggerDeployment.github_url,
});
setCurrentRepoOwner(ownerName);
setFramework(selectedRepoForTriggerDeployment.framework);
setWorkspace(selectedRepoForTriggerDeployment.workspace);
setPackageManager(selectedRepoForTriggerDeployment.package_manager);
setBuildCommand(selectedRepoForTriggerDeployment.build_command);
setPublishDirectory(selectedRepoForTriggerDeployment.publish_dir);
setProtocol(selectedRepoForTriggerDeployment.protocol);
setCreateDeployProgress(3);
const branchUrl = `https://api.github.com/repos/${ownerName}/${repoName}/branches`;
ApiService.getGithubRepoBranches(branchUrl).subscribe((res) => {
if (componentIsMounted.current) {
setRepoBranches(res.branches);
setBranch(selectedRepoForTriggerDeployment.branch);
setRepoBranchesLoading(false);
}
});
}
}, [selectedRepoForTriggerDeployment]);
useEffect(() => {
if (currentRepoOwner && selectedRepoForTriggerDeployment) {
ApiService.getAllGithubAppInstallation().subscribe((res) => {
if (componentIsMounted.current) {
const repoOwners: any[] = res.installations.map((installation: any) => ({
name: installation.account.login,
avatar: installation.account.avatar_url,
installationId: installation.id,
}));
if (repoOwners.length) {
const newRepoOwner = repoOwners.filter(
(repoOwner) => repoOwner.name === currentRepoOwner,
)[0];
setSelectedRepoOwner(newRepoOwner);
}
}
});
}
}, [currentRepoOwner, selectedRepoForTriggerDeployment]);
useEffect(() => {
const bc = new BroadcastChannel("github_app_auth");
bc.onmessage = (msg: string) => {
if (msg === "authorized") {
setShowGithubRepos(true);
getAllGithubInstallations();
}
};
return () => {
bc.close();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const getAllGithubInstallations = () => {
setOwnerLoading(true);
setRepoLoading(true);
ApiService.getAllGithubAppInstallation().subscribe((res) => {
if (componentIsMounted.current) {
const repoOwners: any[] = res.installations.map((installation: any) => ({
name: installation.account.login,
avatar: installation.account.avatar_url,
installationId: installation.id,
}));
setReposOwnerDetails(repoOwners);
if (repoOwners.length) {
let newRepoOwner = null;
if (selectedRepoOwner) {
newRepoOwner = repoOwners.filter(
(repoOwner) => repoOwner.name === selectedRepoOwner.name,
)[0];
} else {
newRepoOwner = repoOwners[0];
}
setSelectedRepoOwner(newRepoOwner);
setOwnerLoading(false);
getOwnerRepos(newRepoOwner.installationId);
} else {
setOwnerLoading(false);
}
}
});
};
const getOwnerRepos = (installationId: string) => {
setRepoLoading(true);
ApiService.getAllOwnerRepos(installationId).subscribe((res) => {
if (componentIsMounted.current) {
const repositories: any[] = res.repositories.map((repo: any) => ({
clone_url: repo.clone_url,
branches_url: repo.branches_url.split("{")[0],
name: repo.name,
fullName: repo.full_name,
private: repo.private,
repositoryId: repo.id,
}));
setReposSelectedOwnerRepoDetails(repositories);
setRepoLoading(false);
}
});
};
const selectRepoOwner = (repoOwner: any) => {
getOwnerRepos(repoOwner.installationId);
setSelectedRepoOwner(repoOwner);
setShowRepoOrgDropdown(false);
};
const selectRepositories = (repo: any) => {
setSelectedRepo(repo);
setCreateDeployProgress(2);
setRepoBranchesLoading(true);
ApiService.getGithubRepoBranches(repo.branches_url).subscribe((res) => {
if (componentIsMounted.current) {
setRepoBranches(res.branches);
setBranch(res.branches[0].name);
setRepoBranchesLoading(false);
}
});
};
const startDeployment = async () => {
setErrorWarning(false);
setErrorMessage("");
setStartDeploymentLoading(true);
const configuration = {
framework,
workspace,
packageManager,
buildCommand,
publishDir: publishDirectory,
branch,
protocol,
};
ApiService.createConfiguration(configuration).subscribe(
(result) => {
if (componentIsMounted.current) {
const uniqueTopicId = uuidv4();
const deployment = {
orgId: selectedOrg?._id,
githubUrl: selectedRepo.clone_url,
folderName: selectedRepo.name,
owner: selectedRepoOwner.name,
installationId: selectedRepoOwner.installationId,
repositoryId: selectedRepo.repositoryId,
organizationId: owner._id,
uniqueTopicId,
configurationId: result._id,
env: mapBuildEnv(buildEnv),
createDefaultWebhook: autoPublish,
};
ApiService.startDeployment(deployment).subscribe(
(result) => {
if (result.success) {
if (componentIsMounted.current) {
setLatestDeploymentConfig(deployment);
setStartDeploymentLoading(false);
history.push(
`/org/${selectedOrg?._id}/sites/${result.projectId}/deployments/${result.deploymentId}`,
);
}
} else {
setErrorMessage(result.message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
setStartDeploymentLoading(false);
}
},
(error) => {
setErrorMessage(error.message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
setStartDeploymentLoading(false);
},
);
}
},
(error) => {
setErrorMessage(error.message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
setStartDeploymentLoading(false);
},
);
};
const mapBuildEnv = (buildEnv: any[]): any => {
const buildEnvObj = {};
buildEnv.forEach((env) => {
Object.assign(buildEnvObj, { [env.key]: env.value });
});
return buildEnvObj;
};
const openGithubAppAuth = async () => {
const githubSignInUrl = `${window.location.origin}/#/github/app/${user?._id}`;
window.open(githubSignInUrl, "_blank");
};
const goBackAction = () => {
if (createDeployProgress === 1) {
history.goBack();
} else if (createDeployProgress === 2) {
setCreateDeployProgress(1);
} else {
setCreateDeployProgress(2);
}
};
let buildCommandPrefix: string = "";
if (packageManager === "npm") {
buildCommandPrefix = "npm run";
} else {
buildCommandPrefix = "yarn";
}
const selectProtocol = (selectedProtocol: string) => {
setProtocol(selectedProtocol);
setCreateDeployProgress(3);
};
const addBuildEnv = () => {
setBuildEnv([...buildEnv, { key: "", value: "" }]);
};
const removeBuildEnvItem = (id: number) => {
setBuildEnv(buildEnv.filter((item, i) => i !== id));
};
const fillEnvKey = (value: string, id: number) => {
setBuildEnv(
buildEnv.map((item, i) =>
i === id ? { key: value, value: item.value } : item,
),
);
};
const fillEnvValue = (value: string, id: number) => {
setBuildEnv(
buildEnv.map((item, i) => (i === id ? { key: item.key, value } : item)),
);
};
return (
<div className="DeploySiteConfig">
<RootHeader parent={"DeploySiteConfig"} />
<main className="app-main">
<div className="deploy-site-container">
<div className="deploy-site-card">
<div className="deploy-site-card-inner">
<div className="go-back" onClick={goBackAction}>
<span>
<FontAwesomeIcon icon={faArrowLeft} />
</span>
<span>Back</span>
</div>
<h1 className="deploy-site-title">Create a new site</h1>
<div className="deploy-site-subtitle">
Just follow these 2 step to deploy your website to ArGo
</div>
<div className="deploy-site-progress-bar">
<div className="deploy-site-progress-number-container">
{createDeployProgress <= 1 ? (
<div
className={`deploy-site-progress-number ${
createDeployProgress === 1 ? "active" : ""
}`}
>
1
</div>
) : (
<div className="deploy-site-progress-done">
<FontAwesomeIcon icon={faCheck} />
</div>
)}
<div
className={`deploy-site-progress-text ${
createDeployProgress === 1
? "deploy-site-progress-text-active"
: ""
}`}
>
Pick a repository
</div>
</div>
<div className="deploy-site-progress-number-container">
{createDeployProgress <= 2 ? (
<div
className={`deploy-site-progress-number ${
createDeployProgress === 2 ? "active" : ""
}`}
>
2
</div>
) : (
<div className="deploy-site-progress-done">
<FontAwesomeIcon icon={faCheck} />
</div>
)}
<div
className={`deploy-site-progress-text ${
createDeployProgress === 2
? "deploy-site-progress-text-active"
: ""
}`}
>
Pick a Protocol
</div>
</div>
<div className="deploy-site-progress-number-container">
{createDeployProgress <= 3 ? (
<div
className={`deploy-site-progress-number ${
createDeployProgress === 3 ? "active" : ""
}`}
>
3
</div>
) : (
<div className="deploy-site-progress-done">
<FontAwesomeIcon icon={faCheck} />
</div>
)}
<div
className={`deploy-site-progress-text ${
createDeployProgress === 3
? "deploy-site-progress-text-active"
: ""
}`}
>
Build options, and deploy!
</div>
</div>
</div>
<div className="deploy-site-form-container">
{createDeployProgress === 1 && (
<div className="deploy-site-form-item">
<label className="deploy-site-item-title">
{/* Continuous Deployment: GitHub Webhook */}
Choose repository
</label>
<label className="deploy-site-item-subtitle">
Choose the repository you want to link to your site on ArGo.
</label>
{!showGithubRepos ? (
<div className="deployment-provider-container">
<div className="deployment-provider-title">
Connect with your favorite provider
</div>
<div className="deployment-provider-buttons">
<button
className="github-button"
disabled={userLoading}
onClick={openGithubAppAuth}
>
<span className="github-icon">
<GithubIcon />
</span>
<span>Github</span>
</button>
</div>
</div>
) : reposOwnerDetails.length || ownerLoading ? (
<div className="deploy-site-item-repo-list-container">
<div className="deploy-site-item-repo-header">
<div
className="deploy-site-item-repo-header-left"
onClick={(e) =>
!ownerLoading ? setShowRepoOrgDropdown(true) : null
}
>
{!ownerLoading ? (
<LazyLoadedImage height={32} once>
<img
src={selectedRepoOwner.avatar}
alt="camera"
className="deploy-site-item-repo-org-avatar"
height={32}
width={32}
loading="lazy"
/>
</LazyLoadedImage>
) : (
<Skeleton
circle={true}
height={32}
width={32}
duration={2}
/>
)}
<span className="deploy-site-item-repo-org-name">
{!ownerLoading ? (
selectedRepoOwner.name
) : (
<Skeleton width={140} height={24} duration={2} />
)}
</span>
<span className="deploy-site-item-repo-down">
<FontAwesomeIcon
icon={
showRepoOrgDropdown ? faChevronUp : faChevronDown
}
/>
</span>
</div>
<div className="deploy-site-item-repo-header-right">
{/* <div className="deploy-site-item-repo-search-container">
<span className="deploy-site-item-repo-search-icon">
<FontAwesomeIcon icon={faSearch}></FontAwesomeIcon>
</span>
<input
type="text"
className="deploy-site-item-repo-search-input"
placeholder="Search repos"
/>
</div> */}
<div
className="refresh-control"
onClick={getAllGithubInstallations}
>
<FontAwesomeIcon icon={faSyncAlt}></FontAwesomeIcon>
</div>
</div>
{showRepoOrgDropdown && (
<MemoRepoOrgDropdown
setShowDropdown={setShowRepoOrgDropdown}
repoOwner={reposOwnerDetails}
selectedRepoOwner={selectedRepoOwner}
setSelectedRepoOwner={selectRepoOwner}
/>
)}
</div>
<div className="deploy-site-item-repo-body">
{!repoLoading ? (
reposSelectedOwnerRepoDetails.map(
(repo: any, index: number) => (
<MemoRepoItem
skeleton={false}
name={repo.fullName}
privateRepo={repo.private}
key={index}
onClick={() => selectRepositories(repo)}
/>
),
)
) : (
<>
<MemoRepoItem
skeleton={true}
name={""}
privateRepo={false}
onClick={() => null}
/>
<MemoRepoItem
skeleton={true}
name={""}
privateRepo={false}
onClick={() => null}
/>
</>
)}
</div>
<div className="deploy-site-item-repo-body">
Can’t see your repo here?
<a
href={`${config.urls.API_URL}/auth/github/app/new`}
// eslint-disable-next-line react/jsx-no-target-blank
target="_blank"
rel="noopener noreferrer"
>
Configure the ArGo app on GitHub.
</a>
</div>
</div>
) : (
<div className="deployment-provider-container">
<div className="deployment-provider-title">
You don't have any configured owner, Configure it now to
view your repositories
</div>
<div className="deployment-provider-buttons">
<button
className="github-button"
onClick={openGithubAppAuth}
>
<span className="github-icon">
<GithubIcon />
</span>
<span>Github</span>
</button>
</div>
</div>
)}
</div>
)}
{createDeployProgress === 2 && (
<>
<div className="deploy-site-form-item">
<label className="deploy-site-item-title">
Select the protocol to deploy {selectedRepo.name}
</label>
<label className="deploy-site-item-subtitle">
Click on the protocol in which you want ArGo to deploy your
site.
</label>
<div className="deploy-protocol-list-container">
<ul className="deploy-protocol-list">
<div
className="deploy-protocol-image"
onClick={(e) => selectProtocol("arweave")}
>
<LazyLoadedImage height={50} once>
<img
src={require("../../assets/png/arweave_logo.png")}
alt="Arweave"
className="deploy-protocol-item-avatar"
height={50}
width={200}
loading="lazy"
/>
</LazyLoadedImage>
</div>
<div
className="deploy-protocol-image"
onClick={(e) => selectProtocol("skynet")}
>
<LazyLoadedImage height={50} once>
<img
src={require("../../assets/png/skynet_logo.png")}
alt="Skynet"
className="deploy-protocol-item-avatar"
height={50}
width={200}
loading="lazy"
/>
</LazyLoadedImage>
<div className="new-protocol-tag">New</div>
</div>
<div
className="deploy-protocol-image"
onClick={(e) => selectProtocol("ipfs-filecoin")}
>
<LazyLoadedImage height={50} once>
<img
src={require("../../assets/png/filecoin-full.png")}
alt="filecoin"
className="deploy-protocol-item-avatar"
height={50}
width={200}
loading="lazy"
/>
</LazyLoadedImage>
<div className="new-protocol-tag">New</div>
</div>
<div
className="deploy-protocol-image"
onClick={(e) => selectProtocol("ipfs-pinata")}
>
<LazyLoadedImage height={50} once>
<img
src={require("../../assets/svg/pinata-full.svg")}
alt="filecoin"
className="deploy-protocol-item-avatar"
height={62}
width={220}
loading="lazy"
/>
</LazyLoadedImage>
<div className="new-protocol-tag">New</div>
</div>
{/* <div
className="deploy-protocol-image"
onClick={(e) => selectProtocol("neofs")}
>
<LazyLoadedImage height={50} once>
<img
src={require("../../assets/svg/neofs_logo.svg")}
alt="neoFS"
className="deploy-protocol-item-avatar"
height={50}
width={200}
loading="lazy"
/>
</LazyLoadedImage>
<div className="new-protocol-tag">New</div>
</div> */}
</ul>
</div>
</div>
<div className="button-container">
<button
type="button"
className="cancel-button"
onClick={(e) => setCreateDeployProgress(1)}
>
Back
</button>
</div>
</>
)}
{createDeployProgress === 3 && (
<>
<ReactTooltip />
<div className="deploy-site-form-item">
<label className="deploy-site-item-title">
Deploy settings for {selectedRepo.name}
</label>
<label className="deploy-site-item-subtitle">
Get more control over how ArGo builds and deploys your site
with these settings.
</label>
<div className="deploy-site-item-form">
<div className="deploy-site-item-form-item">
<label>Owner</label>
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={owner._id}
onChange={(e) => {
const selOrg = user
? user.organizations
? user.organizations.filter(
(org) => org._id === e.target.value,
)[0]
: null
: null;
setSelectedOrganization(selOrg as any);
setOwner(e.target.value);
}}
>
{user?.organizations &&
user?.organizations.map((organization, index) => (
<option value={organization._id} key={index}>
{organization.profile.name}
</option>
))}
</select>
<span className="select-down-icon">
<FontAwesomeIcon icon={faChevronDown} />
</span>
</div>
</div>
<div className="deploy-site-item-form-item">
<label>Branch to deploy</label>
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={branch}
onChange={(e) => setBranch(e.target.value)}
>
{repoBranches.map((branch, index) => (
<option value={branch.name} key={index}>
{branch.name}
</option>
))}
</select>
<span className="select-down-icon">
{!repoBranchesLoading ? (
<FontAwesomeIcon icon={faChevronDown} />
) : (
<BounceLoader
size={20}
color={"#0a3669"}
loading={true}
/>
)}
</span>
</div>
</div>
<div className="deploy-site-item-form-item">
<label>
Workspace to deploy
<span
className="tooltip"
data-tip="If your app is a monorepo, then you can specify your app directory you want to deploy using the workspace."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<input
type="text"
className="deploy-site-item-input"
value={workspace}
onChange={(e) => setWorkspace(e.target.value)}
/>
</div>
</div>
</div>
<div className="deploy-site-form-item">
<label className="deploy-site-item-title">
Basic build settings
</label>
<label className="deploy-site-item-subtitle">
If you’re using a static site generator or build tool, we’ll
need these settings to build your site.
</label>
<div className="deploy-site-item-form">
<div className="deploy-site-item-form-item">
<label>
Framework
<span
className="tooltip"
data-tip="The framework that your app is built upon."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={framework}
onChange={(e) => setFramework(e.target.value)}
>
<option value="static">
No Framework - Simple JavaScript App
</option>
<option value="react">Create React App</option>
<option value="vue">Vue App</option>
<option value="angular">Angular App</option>
{protocol !== "skynet" && (
<option value="next">Next.js App</option>
)}
</select>
<span className="select-down-icon">
<FontAwesomeIcon icon={faChevronDown} />
</span>
</div>
</div>
{framework !== "static" && (
<>
<div className="deploy-site-item-form-item">
<label>
Package Manager
<span
className="tooltip"
data-tip="The package manager that you want your app to be built with."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<div className="deploy-site-item-select-container">
<select
className="deploy-site-item-select"
value={packageManager}
onChange={(e) => setPackageManager(e.target.value)}
>
<option value="npm">NPM</option>
<option value="yarn">YARN</option>
</select>
<span className="select-down-icon">
<FontAwesomeIcon icon={faChevronDown} />
</span>
</div>
</div>
<div className="deploy-site-item-form-item">
<label>
Build command
<span
className="tooltip"
data-tip="The command your frontend framework provides for compiling your code."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
{framework !== "next" ? (
<div className="deploy-site-item-input-container">
<input
type="text"
className="deploy-site-item-input-disabled"
value={buildCommandPrefix}
disabled
/>
<input
type="text"
className="deploy-site-item-input-build"
value={buildCommand}
onChange={(e) => setBuildCommand(e.target.value)}
/>
</div>
) : (
<input
type="text"
className="deploy-site-item-input"
value={buildCommand}
onChange={(e) => setBuildCommand(e.target.value)}
/>
)}
</div>
<div className="deploy-site-item-form-item">
<label>
Publish directory
<span
className="tooltip"
data-tip="The directory in which your compiled frontend will be located."
>
<FontAwesomeIcon size="sm" icon={faInfoCircle} />
</span>
</label>
<input
type="text"
className="deploy-site-item-input"
value={publishDirectory}
onChange={(e) => setPublishDirectory(e.target.value)}
/>
</div>
</>
)}
</div>
</div>
<div className="deploy-site-form-item">
<label className="deploy-site-item-title">
Advanced build settings
</label>
<label className="deploy-site-item-subtitle">
Define environment variables for more control and flexibility
over your build.
</label>
<div className="deploy-site-item-form">
<div className="deploy-site-item-form-item">
<label>
Continuous Deployment{" "}
<span className="new-item-tag">NEW</span>
</label>
<label className="deploy-site-item-subtitle">
Enabling this will automatically create a production CD
pipeline for your selected branch. When you push any new
code to GitHub, we will run our build tool and deploy the
result.
</label>
</div>
<div className="webhook-confirm-container">
<span className="confirm-checkbox">
<input
type="checkbox"
checked={autoPublish}
onChange={(e) => setAutoPublish(e.target.checked)}
/>
</span>
<span>
<div className="webhook-title">
Do you want to enable Continuous Deployment?
</div>
<div className="webhook-note">
Note: If the project already has CD enabled, this won't
overwrite the existing configuration. To change this,
you have to go to Project Settings.
</div>
</span>
</div>
</div>
<div className="deploy-site-item-form">
<div className="deploy-site-item-form-item">
<label>Environment Variables</label>
<label className="deploy-site-item-subtitle">
Note that adding environment variables here won't work if
project already exists, you have to add environment
variables by going to your Project Settings {"->"}{" "}
Environment Variables
</label>
</div>
{buildEnv.length !== 0 && (
<div className="deploy-site-item-form-item">
<div className="deploy-site-env-title">
<label className="deploy-site-env-title-item">
Key
</label>
<label className="deploy-site-env-title-item">
Value
</label>
</div>
{buildEnv.map((env, i) => (
<div
className="deploy-site-item-env-container"
key={i}
>
<input
type="text"
className="deploy-site-env-input"
placeholder="VARIABLE_NAME"
value={env.key}
onChange={(e) => fillEnvKey(e.target.value, i)}
/>
<input
type="text"
className="deploy-site-env-input"
placeholder="somevalue"
value={env.value}
onChange={(e) => fillEnvValue(e.target.value, i)}
/>
<span
className="remove-env-item"
onClick={(e) => removeBuildEnvItem(i)}
>
<FontAwesomeIcon
icon={faTimesCircle}
></FontAwesomeIcon>
</span>
</div>
))}
</div>
)}
<button
type="button"
className="add-new-var-button"
onClick={(e) => addBuildEnv()}
>
New Variable
</button>
</div>
{!selectedOrg?.wallet && !orgLoading ? (
<div className="wallet-details-container">
<div className="wallet-details-items">
<span className="exclamation-icon">
<FontAwesomeIcon
icon={faExclamationCircle}
></FontAwesomeIcon>
</span>
<span>
You have to enable your organization wallet before you
can deploy your project.
<Link to="/dashboard/wallet">Enable now</Link>
</span>
</div>
</div>
) : null}
</div>
<div className="button-container">
<button
type="button"
className="primary-button"
onClick={startDeployment}
disabled={deployDisabled}
>
{startDeploymentLoading && (
<BounceLoader size={20} color={"#fff"} loading={true} />
)}
Deploy
</button>
<button
type="button"
className="cancel-button"
onClick={(e) => setCreateDeployProgress(2)}
>
Back
</button>
</div>
{errorWarning ? (
<div className="warning-container">
<div className="warning-header">
<FontAwesomeIcon icon={faExclamationCircle} />{" "}
{errorMessage}
</div>
</div>
) : null}
</>
)}
</div>
</div>
</div>
</div>
</main>
</div>
);
}
Example #22
Source File: Wallet.tsx From argo-react with MIT License | 4 votes |
Wallet = () => {
const history = useHistory();
const { userLoading, selectedOrg, orgLoading } =
useContext<IStateModel>(StateContext);
const { fetchUser } = useContext<IActionModel>(ActionContext);
const [paymentsLoading, setPaymentsLoading] = useState<boolean>(false);
const [walletLoading, setWalletLoading] = useState<boolean>(false);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [payments, setPayments] = useState<IPaymentModel[]>([]);
const [orgWallet, setOrgWallet] = useState<string>("");
const [wallet, setWallet] = useState<string>("");
const [walletBal, setWalletBal] = useState<number>(0);
const [argoAllowance, setArgoAllowance] = useState<number>(-1);
const [walletLoader, setWalletLoader] = useState<boolean>(false);
const [enableLoader, setEnableLoader] = useState<boolean>(false);
const [removalLoader, setRemovalLoader] = useState<boolean>(false);
const [errorWarning, setErrorWarning] = useState<boolean>(false);
const [errorMessage, setErrorMessage] = useState<string>("");
const componentIsMounted = useRef(true);
const isWalletPresent = !!selectedOrg?.wallet;
useEffect(() => {
if (selectedOrg && !orgLoading) {
setPaymentsLoading(true);
setWalletLoading(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
if (componentIsMounted.current) {
setOrgWallet(selectedOrg.wallet ? selectedOrg.wallet.address : "");
setWalletLoading(false);
setPayments(selectedOrg.payments || []);
setPaymentsLoading(false);
}
} else {
if (orgLoading) {
setPaymentsLoading(true);
setWalletLoading(true);
} else {
setPaymentsLoading(false);
setWalletLoading(false);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedOrg, orgLoading]);
useEffect(() => {
return () => {
componentIsMounted.current = false;
Web3Service.disconnectPolygon();
};
}, []);
const connectWallet = async () => {
setWalletLoader(true);
try {
const wallet = await Web3Service.getPolygonAccount();
setWallet(wallet);
let walletBal = 0;
walletBal = await Web3Service.getArgoBalance(wallet);
setWalletBal(walletBal);
setWalletLoader(false);
} catch (err) {
setErrorMessage((err as any).message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
setWalletLoader(false);
// eslint-disable-next-line no-console
console.log(err);
}
};
const checkAllowance = async () => {
setWalletLoader(true);
try {
await Web3Service.getPolygonAccount();
let walletApproval = 0;
walletApproval = await Web3Service.getArgoAllowances(orgWallet);
setArgoAllowance(walletApproval);
setWalletLoader(false);
} catch (err) {
setErrorMessage((err as any).message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
setWalletLoader(false);
// eslint-disable-next-line no-console
console.log(err);
}
};
const enableWallet = async () => {
setEnableLoader(true);
const walletBody = {
address: wallet,
orgId: selectedOrg?._id,
};
ApiService.enableWallet(walletBody).subscribe(
(res) => {
if (componentIsMounted.current) {
setEnableLoader(false);
fetchUser();
}
},
(err) => {
setErrorMessage((err as any).message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
},
);
};
const removeWallet = async () => {
setRemovalLoader(true);
try {
await Web3Service.getPolygonAccount();
const signature = await Web3Service.signRemoveWallet();
const removeBody = {
id: selectedOrg?.wallet._id,
signature,
};
ApiService.removeWallet(removeBody).subscribe(
(res) => {
if (componentIsMounted.current) {
setRemovalLoader(false);
fetchUser();
}
},
(err) => {
setErrorMessage((err as any).message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
},
);
} catch (err) {
setErrorMessage((err as any).message);
setErrorWarning(true);
setTimeout(() => {
setErrorWarning(false);
setErrorMessage("");
}, 5000);
setRemovalLoader(false);
// eslint-disable-next-line no-console
console.log(err);
}
};
const showProtocolPrice = (protocol: string) => {
switch (protocol) {
case "arweave":
return "AR";
case "skynet":
return "SC";
case "neofs":
return "NEO";
case "ipfs-filecoin":
return "FIL";
case "ipfs-pinata":
return "USD";
default:
}
};
return (
<div className="Wallet">
{errorWarning ? (
<div className="warning-container">
<div className="warning-header">
<FontAwesomeIcon icon={faExclamationCircle} /> {errorMessage}
</div>
</div>
) : null}
<div className="wallet-container">
<div className="wallet-details">
<div className="wallet-header">
<span>Organisation Wallet</span>
</div>
<div className="wallet-body">
{!isWalletPresent && !walletLoading ? (
<>
<div className="wallet-subtitle">
Enable your wallet for <b>{selectedOrg?.profile.name}</b>
</div>
<div className="wallet-info">
<FontAwesomeIcon
icon={faInfoCircle}
style={{ marginRight: 7 }}
></FontAwesomeIcon>
We currently support Matic Mumbai Testnet. Please add Matic Mumbai
chain in your metamask.
</div>
{!wallet ? (
<button
type="button"
className="primary-button"
disabled={userLoading}
onClick={connectWallet}
>
Connect
</button>
) : (
<div className="wallet-recharge-form">
<label className="wallet-recharge-form-title">
Wallet Details
</label>
<div className="wallet-details-container">
<div className="wallet-details-items">
<div className="wallet-details-item-title">
Wallet Address
</div>
<div className="wallet-details-item-desc">
{!walletLoader ? (
wallet
) : (
<Skeleton width={300} duration={2} />
)}
</div>
</div>
<div className="wallet-details-items">
<div className="wallet-details-item-title">ARGO Balance</div>
<div className="wallet-details-item-desc">
{!walletLoader ? (
`${walletBal} $ARGO`
) : (
<Skeleton width={150} duration={2} />
)}
</div>
</div>
</div>
<div className="wallet-details-button">
<button
type="button"
className="primary-button"
disabled={enableLoader}
onClick={enableWallet}
>
{enableLoader && (
<BounceLoader size={20} color={"#fff"} loading={true} />
)}
Save
</button>
</div>
</div>
)}
</>
) : (
<>
<div className="wallet-body-header">
<div>
<div className="wallet-body-title">Wallet Details</div>
<div className="wallet-note">
Note: Only owner of this wallet can increase allowance
</div>
</div>
<div className="button-container">
{!walletLoading && (
<>
<button
type="button"
className="primary-button remove-button"
disabled={walletLoading}
onClick={removeWallet}
>
{removalLoader && (
<BounceLoader size={20} color={"#fff"} loading={true} />
)}
Remove Wallet
</button>
<button
type="button"
className="primary-button"
disabled={walletLoading}
onClick={() => history.push("/wallet/recharge")}
>
Set Allowance
</button>
</>
)}
</div>
</div>
<div className="wallet-details-body">
<div className="wallet-details-item">
<label>Address</label>
<span>
{!walletLoading ? (
`${orgWallet}`
) : (
<Skeleton width={150} duration={2} />
)}
</span>
</div>
<div className="wallet-details-item">
<label>Allowance</label>
<span>
{!walletLoading ? (
<div>
{argoAllowance === -1 ? (
<button
type="button"
className="primary-button"
disabled={walletLoader}
onClick={checkAllowance}
>
{walletLoader && (
<BounceLoader
size={20}
color={"#fff"}
loading={true}
/>
)}
Check Allowance
</button>
) : (
`${argoAllowance} $ARGO`
)}
</div>
) : (
<Skeleton width={150} duration={2} />
)}
</span>
</div>
</div>
</>
)}
</div>
</div>
<div className="payment-details">
<div className="payment-header">
<span>Payments</span>
</div>
<div className="payment-body">
<div className="table">
<div className="thead">
<div className="tr">
<div className="th">Project Name</div>
<div className="th">Deployment Id</div>
<div className="th">Build Time</div>
<div className="th">Upload Fee</div>
<div className="th">Amount</div>
<div className="th">Date</div>
</div>
</div>
{!paymentsLoading ? (
<div className="tbody">
<ReactTooltip delayShow={50} />
{payments.length > 0 ? (
payments.map((payment: IPaymentModel, index: number) => (
<div className="tr" key={index}>
<div className="td">
<div className="user-container">
<div className="user-text">
<span
className="tooltip"
data-tip={payment?.projectName}
>
{payment?.projectName}
</span>
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<span
className="tooltip"
data-tip={payment?.deploymentId}
>
{payment?.deploymentId}
</span>
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">{payment?.buildTime} s</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<span
className="tooltip"
data-tip={`${
payment?.providerFee
} ${showProtocolPrice(payment?.protocol)}`}
>
{payment?.providerFee.toFixed(5)}{" "}
{showProtocolPrice(payment?.protocol)}
</span>
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<span
className="tooltip"
data-tip={`${payment?.finalArgoFee} $${payment.token}`}
>
{payment?.finalArgoFee.toFixed(3)} ${payment.token}
</span>
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
{moment(payment?.createdAt).format(
"DD-MM-YYYY hh:mm A",
)}
</div>
</div>
</div>
</div>
))
) : (
<div className="tr tr-center">No payments to show</div>
)}
</div>
) : (
<div className="tbody">
<div className="tr">
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={80} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={90} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={50} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={50} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={50} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={80} duration={2} />
</div>
</div>
</div>
</div>
<div className="tr">
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={80} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={90} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={50} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={50} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={50} duration={2} />
</div>
</div>
</div>
<div className="td">
<div className="user-container">
<div className="user-text">
<Skeleton width={80} duration={2} />
</div>
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
}
Example #23
Source File: BCInfo.tsx From devex with GNU General Public License v3.0 | 4 votes |
BCInfo: React.FC = () => {
const networkContext = useContext(NetworkContext)
const { dataService, networkUrl } = networkContext!
const [data, setData] = useState<BlockchainInfo | null>(null)
const [state, setState] = useState<BCInfoState>(defaultBCInfoState)
useEffect(() => { setData(null); setState(defaultBCInfoState) }, [networkUrl]) // Unset data on url change
useEffect(() => {
if (!data) return
setState((prevState: BCInfoState) => {
const newState: BCInfoState = { ...prevState }
if (!prevState.startTxBlock)
newState.startTxBlock = parseInt(data.NumTxBlocks, 10) - 1
if (!prevState.maxTPS || prevState.maxTPS <= data.TransactionRate) {
newState.maxTPS = data.TransactionRate
newState.maxTPSTxBlockNum = parseInt(data.NumTxBlocks, 10) - 1
}
if (!prevState.maxTxnCount || prevState.maxTxnCount <= parseInt(data.NumTxnsTxEpoch, 10)) {
newState.maxTxnCount = parseInt(data.NumTxnsTxEpoch, 10)
newState.maxTxnCountTxBlockNum = parseInt(data.NumTxBlocks, 10) - 1
}
return newState
})
}, [data])
// Fetch data
useEffect(() => {
let isCancelled = false
if (!dataService) return
let receivedData: BlockchainInfo
const getData = async () => {
try {
receivedData = await dataService.getBlockchainInfo()
if (!isCancelled && receivedData)
setData(receivedData)
} catch (e) {
if (!isCancelled)
console.log(e)
}
}
getData()
const getDataTimer = setInterval(async () => {
await getData()
}, refreshRate)
return () => {
isCancelled = true
clearInterval(getDataTimer)
}
}, [dataService])
return <>
<Card className='bcstats-card'>
<Card.Body>
{data
? <Container>
<Row className='mb-3'>
<Col>
<span className='subtext'>Current Tx Epoch:</span>
<br />
<span>{parseInt(data.NumTxBlocks).toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>Number of Transactions:</span>
<br />
<span>{parseInt(data.NumTransactions).toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>Peers:</span>
<br />
<span>{data.NumPeers.toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>Sharding Structure:</span>
<br />
<span>[{data.ShardingStructure && data.ShardingStructure.NumPeers
? data.ShardingStructure.NumPeers.toString()
: "no shards"}]</span>
</Col>
</Row>
<Row className='mb-3'>
<Col>
<span className='subtext'>Current DS Epoch:</span>
<br />
<span>{parseInt(data.CurrentDSEpoch).toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>DS Block Rate:</span>
<br />
<span>{data.DSBlockRate.toFixed(5)}</span>
</Col>
<Col>
<span className='subtext'>Tx Block Rate:</span>
<br />
<span>{data.TxBlockRate.toFixed(5)}</span>
</Col>
<Col>
<span className='subtext'>TPS:</span>
<br />
<span>{data.TransactionRate.toFixed(5)}</span>
</Col>
</Row>
<Row>
<Col>
<span className='subtext'>Number of Txns in DS Epoch:</span>
<br />
<span>{parseInt(data.NumTxnsDSEpoch).toLocaleString('en')}</span>
</Col>
<Col>
<span className='subtext'>Number of Txns in Txn Epoch:</span>
<br />
<span>{parseInt(data.NumTxnsTxEpoch).toLocaleString('en')}</span>
</Col>
<Col>
<OverlayTrigger placement='left'
overlay={<Tooltip id={'tt'}>This statistic is accurate from TxBlock {state.startTxBlock}. Requires user to stay on the Home Page</Tooltip>}>
<FontAwesomeIcon className='info-icon' icon={faInfoCircle} />
</OverlayTrigger>
{' '}
<span className='subtext'>Recent Max Observed TPS:</span>
<br />
<span>{state.maxTPS && state.maxTPS.toFixed(5)}</span>
<span>
{' '}
<small className='text-nowrap subtext'>
(on TxBlock <QueryPreservingLink to={`/txbk/${state.maxTPSTxBlockNum}`}>{state.maxTPSTxBlockNum}</QueryPreservingLink>)
</small>
</span>
</Col>
<Col>
<OverlayTrigger placement='left'
overlay={<Tooltip id={'tt'}>This statistic is accurate from TxBlock {state.startTxBlock}. Requires user to stay on the Home Page</Tooltip>}>
<FontAwesomeIcon className='info-icon' icon={faInfoCircle} />
</OverlayTrigger>
{' '}
<span className='subtext'>Recent Max Observed Txn Count:</span>
<br />
<span>{state.maxTxnCount}
{' '}
<small className='text-nowrap subtext'>
(on TxBlock <QueryPreservingLink to={`/txbk/${state.maxTxnCountTxBlockNum}`}>{state.maxTxnCountTxBlockNum}</QueryPreservingLink>)
</small>
</span>
</Col>
</Row>
</Container>
: <Spinner animation="border" role="status" />
}
</Card.Body>
</Card>
</>
}