@chakra-ui/react#Alert TypeScript Examples
The following examples show how to use
@chakra-ui/react#Alert.
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: PermissionsWalkthrough.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
PermissionsWalkthrough = (): JSX.Element => {
return (
<SlideFade in={true} offsetY='150px'>
<Box px={5}>
<Text fontSize='4xl'>Permissions</Text>
<Text fontSize='md' mt={5}>
Before setting up BlueBubbles, we need to make sure that the app is given the correct permissions
so that it can operate. The main permission that is required is the <strong>Full Disk Access</strong>
permission. This will allow BlueBubbles to read the iMessage database and provide notifications for
new messages.
</Text>
<Alert status='info' mt={2}>
<AlertIcon />
If you are on macOS Monterey, you will also need to enable <strong>Accessibility</strong> permissions
for BlueBubbles.
</Alert>
<Text fontSize='md' mt={5}>
Here is an evaluation of your current permissions. If Full Disk Access is not enabled, you will not be
able to use BlueBubbles
</Text>
<Box my={3} />
<PermissionRequirements />
<Text fontSize='lg' my={5}>Quick Guide</Text>
<Text fontSize='md' mt={5}>Open System Preferences, then the following:</Text>
<Image src={SystemPreferencesImage} borderRadius='lg' my={2} />
<Image src={FullDiskImage} borderRadius='lg' my={2} />
</Box>
</SlideFade>
);
}
Example #2
Source File: UrlField.tsx From calories-in with MIT License | 6 votes |
function UrlField({ canEdit, food }: Props) {
const { register } = useFormContext<FoodForm>()
return (
<Flex minHeight={canEdit ? '200px' : undefined} flexDirection="column">
{canEdit && (
<Alert status="info" mb={3}>
<AlertIcon color="teal.400" />
Add a link will open a web page when the food is clicked. This is
useful if you want to show a specific product.
</Alert>
)}
<FormControl id="email">
<Flex alignItems="center">
<FormLabel mb={0} flexShrink={0}>
Link:
</FormLabel>
{canEdit ? (
<Input
{...register('url')}
placeholder="http://example.com"
type="email"
/>
) : (
<Link
href={food?.url}
target="_blank"
noOfLines={1}
color="teal.500"
>
{food?.url}
</Link>
)}
</Flex>
</FormControl>
</Flex>
)
}
Example #3
Source File: index.tsx From calories-in with MIT License | 6 votes |
function Exporter({ onUpdate }: Props) {
const { isLoading, error } = usePdfExport({ onUpdate })
if (isLoading) {
return <Loader label="Exporting..." />
}
return (
<Alert
status={error ? 'error' : 'success'}
variant="subtle"
flexDirection="column"
alignItems="center"
justifyContent="center"
textAlign="center"
height="200px"
bg="white"
>
<AlertIcon color={error ? 'red.400' : 'teal.400'} boxSize="40px" mr={0} />
<AlertTitle mt={4} mb={1} fontSize="lg">
{error
? 'Something went wrong while creating your pdf file'
: 'Your PDF file is ready'}
</AlertTitle>
{!error && (
<AlertDescription maxWidth="sm">
Downloading this plan will allow you to import it later if you need to
update it.
</AlertDescription>
)}
</Alert>
)
}
Example #4
Source File: ErrorAlert.tsx From takeout-app with MIT License | 6 votes |
ErrorAlert: React.FC<Props> = ({error}) => {
return <>
<Alert status="error">
<AlertIcon />
<AlertTitle mr={2}>{error.name}</AlertTitle>
<AlertDescription>{error.message}</AlertDescription>
</Alert>
</>;
}
Example #5
Source File: AppVersionAlert.tsx From takeout-app with MIT License | 6 votes |
AppVersionAlert: React.FC = () => {
const { data: appVersion } = Api.useAppVersion();
return appVersion && appVersion.commit !== COMMIT ? (
<Alert status="info" mt={1}>
<AlertIcon />
New app version available;
<Link textDecoration="underline" onClick={() => window.location.reload()} ml={1}>
Reload?
</Link>
</Alert>
) : null;
}
Example #6
Source File: AlertPreview.tsx From openchakra with MIT License | 6 votes |
AlertPreview: React.FC<IPreviewProps> = ({ component }) => {
const acceptedTypes = [
'AlertIcon',
'AlertTitle',
'AlertDescription',
] as ComponentType[]
const { props, ref } = useInteractive(component, false)
const { drop, isOver } = useDropComponent(component.id, acceptedTypes)
let boxProps: any = {}
if (isOver) {
props.bg = 'teal.50'
}
return (
<Box ref={drop(ref)} {...boxProps}>
<Alert {...props}>
{component.children.map((key: string) => (
<ComponentPreview key={key} componentName={key} />
))}
</Alert>
</Box>
)
}
Example #7
Source File: AddNewFeedForm.tsx From nextjs-hasura-boilerplate with MIT License | 5 votes |
AddNewFeedForm = () => {
const [body, setBody] = useState("");
const [session] = useSession();
const [
insertFeed,
{ loading: insertFeedFetching, error: insertFeedError },
] = useInsertFeedMutation();
if (!session) {
return (
<AccessDeniedIndicator message="You need to be signed in to add a new feed!" />
);
}
const handleSubmit = async () => {
await insertFeed({
variables: {
author_id: session.id,
body,
},
});
setBody("");
};
const errorNode = () => {
if (!insertFeedError) {
return false;
}
return (
<Alert status="error">
<AlertIcon />
<AlertTitle>{insertFeedError}</AlertTitle>
<CloseButton position="absolute" right="8px" top="8px" />
</Alert>
);
};
return (
<Stack spacing={4}>
{errorNode()}
<Box p={4} shadow="lg" rounded="lg">
<Stack spacing={4}>
<FormControl isRequired>
<FormLabel htmlFor="body">What's on your mind?</FormLabel>
<Textarea
id="body"
value={body}
onChange={(e: ChangeEvent<HTMLTextAreaElement>) =>
setBody(e.currentTarget.value)
}
isDisabled={insertFeedFetching}
/>
</FormControl>
<FormControl>
<Button
loadingText="Posting..."
onClick={handleSubmit}
isLoading={insertFeedFetching}
isDisabled={!body.trim()}
>
Post
</Button>
</FormControl>
</Stack>
</Box>
</Stack>
);
}
Example #8
Source File: VolumeFormFields.tsx From calories-in with MIT License | 5 votes |
function VolumeFields({ canEdit, food }: Props) {
const { register } = useFormContext<FoodForm>()
const { portionsById, volumeBasedPortions } = usePortions()
const portion = food?.volume ? portionsById[food.volume.portionId] : undefined
return (
<Flex minHeight={canEdit ? '200px' : undefined} flexDirection="column">
{canEdit && (
<Alert status="info" mb={3}>
<AlertIcon color="teal.400" />
Enter the food weight in grams per some volume measurement if you want
to convert between weight and volume (for example: between grams and
cups).
</Alert>
)}
<HStack spacing={2}>
{canEdit && <Text fontWeight="medium">1 x</Text>}
{canEdit ? (
<PortionsSelect
width="200px"
portions={volumeBasedPortions}
{...register('volumeForm.portionId')}
/>
) : (
<Text fontWeight="medium">
1 x {`${portion?.singular} (${portion?.millilitersPerAmount} ml)`}
</Text>
)}
<Text fontWeight="medium">=</Text>
<HStack spacing={1} alignItems="center">
{canEdit ? (
<Controller
name="volumeForm.weightInGrams"
render={({ field }) => (
<AmountInput value={field.value} onChange={field.onChange} />
)}
/>
) : (
<Text>{food?.volume?.weightInGrams}g</Text>
)}
{canEdit && <Text textColor="gray.500">g</Text>}
</HStack>
</HStack>
</Flex>
)
}
Example #9
Source File: mdxComponents.tsx From lucide with ISC License | 5 votes |
components = {
h1: (props) => (
<HeadingAnchored as="h1" size="xl" mb={4} {...props}/>
),
h2: ({children, ...rest}) => (
<HeadingAnchored as="h2" size="lg" py={4} { ...rest}>
{children}
<Divider mt={4}/>
</HeadingAnchored>
),
h3: (props) => (
<HeadingAnchored as="h3" size="md" pt={4} mb={4} {...props}/>
),
h4: (props) => (
<HeadingAnchored as="h4" size="sm" pt={4} mb={4} {...props}/>
),
h5: (props) => (
<HeadingAnchored as="h5" size="xs" pt={2} mb={1} {...props}/>
),
h6: (props) => (
<HeadingAnchored as="h6" size="xs" pt={2} mb={1} opacity={.75} {...props}/>
),
ul: (props) => <UnorderedList my={2}>{props.children}</UnorderedList>,
ol: (props) => <OrderedList my={2}>{props.children}</OrderedList>,
li: (props) => <ListItem my={1}>{props.children}</ListItem>,
p: (props) => <Text my={4}>{props.children}</Text>,
img: ({ children, ...rest }) => <Image {...rest} borderRadius={4} my={2}>{children}</Image>,
code: ({ className, children: code }) => {
const language = className.replace('language-', '');
return (
<CodeBlock
//@ts-ignore
my={6}
code={code}
language={language}
/>
)
},
table: (props) => <Table {...props} rounded={4} mb={4}/>,
thead: Thead,
tbody: Tbody,
tr: Tr,
th: Th,
td: Td,
blockquote: (props) => (
<Alert
mt="4"
role="none"
status="warning"
variant="left-accent"
as="blockquote"
rounded={4}
my="1.5rem"
{...props}
/>
),
inlineCode: InlineCode,
hr: (props) => <Divider my={4}/>,
a: ({children, href, ...rest}) => {
let link = href
const isExternal = link.startsWith('http')
if(link.startsWith('packages/')) {
link = href.replace('packages/', '')
}
link = link.replace('.md', '')
return (
<NextLink
href={isExternal ? href : `/docs/${link}`}
{...rest}
passHref
>
<Link isExternal={isExternal} color='#F56565'>{children}</Link>
</NextLink>
)
}
}
Example #10
Source File: index.tsx From nextjs-hasura-boilerplate with MIT License | 5 votes |
MyAccountPageComponent = ({ user }) => {
const [name, setName] = useState(user.name);
const [session] = useSession();
const [updateUser, { loading: updateUserFetching, error: updateUserError }] =
useUpdateUserMutation();
const handleSubmit = () => {
updateUser({
variables: {
userId: session.id,
name,
},
});
};
const errorNode = () => {
if (!updateUserError) {
return false;
}
return (
<Alert status="error">
<AlertIcon />
<AlertTitle>{updateUserError}</AlertTitle>
<CloseButton position="absolute" right="8px" top="8px" />
</Alert>
);
};
return (
<Stack spacing={8}>
<Heading>My Account</Heading>
{errorNode()}
<Box shadow="lg" rounded="lg" p={4}>
<Stack spacing={4}>
<FormControl isRequired>
<FormLabel htmlFor="name">Name</FormLabel>
<Input
type="text"
id="name"
value={name}
onChange={(e: FormEvent<HTMLInputElement>) =>
setName(e.currentTarget.value)
}
isDisabled={updateUserFetching}
/>
</FormControl>
<FormControl>
<Button
loadingText="Saving..."
onClick={handleSubmit}
isLoading={updateUserFetching}
isDisabled={!name.trim()}
>
Save
</Button>
</FormControl>
</Stack>
</Box>
</Stack>
);
}
Example #11
Source File: ConnectionWalkthrough.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
ConnectionWalkthrough = (): JSX.Element => {
const proxyService: string = (useAppSelector(state => state.config.proxy_service) ?? '').toLowerCase().replace(' ', '-');
return (
<SlideFade in={true} offsetY='150px'>
<Box px={5}>
<Text fontSize='4xl'>Connection Setup</Text>
<Text fontSize='md' mt={5}>
In order for you to be able to connect to this BlueBubbles server from the internet, you'll need
to either setup a Dynamic DNS or use one of the integrated proxy services. Proxy services create
a tunnel from your macOS device to your BlueBubbles clients. It does this by routing all communications
from your BlueBubbles server, through the proxy service's servers, and to your BlueBubbles client. Without
this, your BlueBubbles server will only be accessible on your local network.
</Text>
<Text fontSize='md' mt={5}>
Now, we also do not want anyone else to be able to access your BlueBubbles server except you, so we have
setup password-based authentication. All clients will be required to provide the password in order to
interact with the BlueBubbles Server's API.
</Text>
<Text fontSize='md' mt={5}>
Below, you'll be asked to set a password, as well as select the proxy service that you would like to use.
Just note, by
</Text>
<Text fontSize='3xl' mt={5}>Configurations</Text>
<Alert status='info' mt={2}>
<AlertIcon />
You must <i>at minimum</i> set a password and a proxy service
</Alert>
<Stack direction='column' p={5}>
<ServerPasswordField />
<ProxyServiceField />
{(proxyService === 'ngrok') ? (
<>
<NgrokAuthTokenField />
<NgrokRegionField />
</>
): null}
</Stack>
</Box>
</SlideFade>
);
}
Example #12
Source File: unbundle-success.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
UnbundleSuccess = () => {
const [gangstaParty, setGangstaParty] = useState(false);
const image = gangstaParty ? 'bridge_with_hustlers.png' : 'bridge_no_hustlers.png';
return (
<>
<Head title="Bridging and unbundling items to Optimism" />
<ScreenSaver image={image}>
{gangstaParty && (
<>
<PlugContainer>
<Image src="/images/masthead/ogs.svg" alt="DOPE OGS" />
<ul>
{PLUGS.sort(() => Math.random() - 0.5).map((plug, index) => {
return (
<li key={`plug-${index}`}>
<a href={plug.link} target={plug.name}>
{plug.prefix ? <div className="prefix">"{plug.prefix}"</div> : ''}
{plug.name}
{plug.suffix ? <div className="suffix">"{plug.suffix}"</div> : ''}
</a>
</li>
);
})}
</ul>
</PlugContainer>
<WebAmpPlayer />
</>
)}
{!gangstaParty && (
<>
<MastheadContainer>
<Image src={randomMast()} alt="Dope." />
</MastheadContainer>
<AlertContainer>
<Alert status="success">
<div>
<p>
Your Gear is making its way to the Optimism network.
<br />
<br />
It could take up to 15 minutes for that to happen. In the meantime, lets get it
crackin homie…
</p>
<Button
onClick={() => {
setGangstaParty(true);
}}
>
Gangsta Party
</Button>
</div>
</Alert>
</AlertContainer>
</>
)}
</ScreenSaver>
<HStack
m={4}
gridGap={1}
bottom={0}
right={0}
position="absolute"
width="100%"
justifyContent="end"
>
<Link href="/inventory?section=Dope" passHref>
<Button variant="primary">Unbundle More</Button>
</Link>
</HStack>
</>
);
}
Example #13
Source File: ApprovePaper.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
ApprovePaper = ({
address,
children,
isApproved,
onApprove,
}: {
address: string;
children: ReactNode;
isApproved: boolean | undefined;
onApprove: (isApproved: boolean) => void;
}) => {
const { account } = useWeb3React();
const paper = usePaper();
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (account) {
paper
.allowance(account, address)
.then((allowance: BigNumber) => onApprove(allowance.gte('12500000000000000000000')));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [account, address, paper]);
if (isApproved === undefined) {
return <Spinner />;
}
if (isApproved) {
return (
<Alert status="success">
<AlertIcon />
$PAPER Spend Approved
</Alert>
);
}
return (
<PanelContainer>
<PanelTitleHeader>Approve $PAPER Spend</PanelTitleHeader>
<PanelBody>
<p>{children}</p>
</PanelBody>
<PanelFooter stacked>
<Button
onClick={async () => {
setIsLoading(true);
try {
const txn = await paper.approve(address, constants.MaxUint256);
await txn.wait(1);
onApprove(true);
} catch (error) {
} finally {
setIsLoading(false);
}
}}
disabled={isLoading}
>
{isLoading ? <Spinner /> : 'Approve $PAPER Spend'}
</Button>
</PanelFooter>
</PanelContainer>
);
}
Example #14
Source File: InitiationInfo.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
InitiationInfo = () => {
return (
<VerticalPanelStack>
<PanelContainer>
<PanelTitleBar>
<div>Info</div>
</PanelTitleBar>
<PanelBody>
<h3>Initiation</h3>
<p>
Hustlers are the in-game representation of characters inside DOPE WARS. Each Hustler
gains RESPECT based on the amount of time passed since their Initiation. RESPECT will be
useful in the upcoming DOPE WARS game, and provide your Hustler with certain advantages.
</p>
<p>
A Hustler’s appearance is customizable, based on the items in their inventory and
attributes you select. All Hustler artwork is stored on the Ethereum blockchain, with a
next-level technical approach that few projects can match.
</p>
<h3>Claiming Gear</h3>
<p>
Initiating a Hustler will Claim Gear and create 9 new Item NFTs from one DOPE NFT, and
equip them on your Hustler. Because each of these new items become their own separate
NFT, they’re also tradeable on the secondary market.
</p>
<p>
Soon™ you’ll be able to upgrade your Hustler by mixing-and-matching items from multiple
DOPE NFT bundles – with over ONE BILLION possible combinations.
</p>
<p>
Gear from each DOPE NFT can only be claimed once. The DOPE NFT remains in your wallet
and still serves as the governance token for DopeWars DAO. Expect each DOPE NFT to have
more utility developed for it in the future.
</p>
<h3>More Info</h3>
<ul className="normal">
<li>
<Link href="https://dope-wars.notion.site/Hustler-Minting-and-Unbundling-25c6dfb9dca64196aedf8def6297c51a">
<a className="primary">The Dope Wars Hustler Guide</a>
</Link>
</li>
<li>
<Link href="/inventory">
<a className="primary">Gangsta Party</a>
</Link>
</li>
</ul>
</PanelBody>
<div></div>
</PanelContainer>
<Alert
status="info"
css={css`
max-height: 100px;
border: 2px solid black;
`}
>
<AlertIcon />
<div>
All OGs have been Initiated, but Hustlers are an infinite mint! Make as many as you want.
</div>
</Alert>
</VerticalPanelStack>
);
}
Example #15
Source File: PrivateApiWalkthrough.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
PrivateApiWalkthrough = (): JSX.Element => {
return (
<SlideFade in={true} offsetY='150px'>
<Box px={5}>
<Text fontSize='4xl'>Private API Setup (Advanced)</Text>
<Text fontSize='md' mt={5}>
You may already know this, but BlueBubbles is one of the only cross-platform iMessage solution that
supports sending reactions, replies, subjects, and effects. This is because we developed an Objective-C
library that allows us to interface with Apple's "private APIs". Normally, this is not possible, however,
after disabling your macOS device's SIP controls, these private APIs are made accessible.
</Text>
<Text fontSize='md' mt={5}>
If you would like to find out more information, please go to the link below:
</Text>
<LinkBox as='article' maxW='sm' px='5' pb={5} pt={2} mt={5} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://docs.bluebubbles.app/private-api/
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://bluebubbles.app/donate' target='_blank'>
Private API Documentation
</LinkOverlay>
</Heading>
<Text>
This documentation will go over the pros and cons to setting up the Private API. It will speak to
the risks of disabling SIP controls, as well as the full feature set that uses the Private API
</Text>
</LinkBox>
<Text fontSize='3xl' mt={5}>Configurations</Text>
<Alert status='info' mt={2}>
<AlertIcon />
Unless you know what you're doing, please make sure the following Private API Requirements all pass
before enabling the setting. Enabling this will automatically attempt to install the helper bundle
into MacForge or MySIMBL.
</Alert>
<Box mt={4} />
<PrivateApiField
helpText={'Note: If the plugins folder is missing, you may need to manually install the helper bundle'}
/>
</Box>
</SlideFade>
);
}
Example #16
Source File: InterestRates.tsx From rari-dApp with GNU Affero General Public License v3.0 | 5 votes |
export default function InterestRates() {
const isMobile = useIsSmallScreen();
const { isAuthed } = useRari();
const { t } = useTranslation();
return (
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="center"
color="#FFFFFF"
mx="auto"
width="100%"
height="100%"
px={4}
>
<Header isAuthed={isAuthed} />
<Alert colorScheme="green" borderRadius={5} mt="5">
<AlertIcon />
<span style={{ color: "#2F855A" }}>
{t(
"This page is currently in beta. If you notice any issues, please"
)}{" "}
<Link
isExternal={true}
href="https://discord.gg/3uWWeQGq"
textDecoration="underline"
>
{t("let us know!")}
</Link>
</span>
</Alert>
{isMobile ? (
<Alert colorScheme="orange" borderRadius={5} mt={5}>
<AlertIcon />
<span style={{ color: "#C05621" }}>
{t(
"This page is not optimized for use on smaller screens. Sorry for the inconvenience!"
)}
</span>
</Alert>
) : null}
<InterestRatesView />
<Footer />
</Column>
);
}
Example #17
Source File: home.tsx From ledokku with MIT License | 4 votes |
Home = () => {
const toast = useToast();
const history = useHistory();
const { loggedIn, login } = useAuth();
const { data, loading, error } = useSetupQuery({});
const [
registerGithubAppMutation,
{ loading: registerGithubAppLoading },
] = useRegisterGithubAppMutation();
const [
loginWithGithubMutation,
{ loading: loginWithGithubLoading },
] = useLoginWithGithubMutation();
const [showAppSuccessAlert, setShowAppSuccessAlert] = useState(false);
// On mount we check if there is a github code present
useEffect(() => {
const codeToLogin = async () => {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const githubCode = urlParams.get('code');
const githubState = urlParams.get('state');
// In case of login state is empty
if (githubState === 'github_login' && githubCode) {
// Remove hash in url
window.history.replaceState({}, document.title, '.');
try {
const data = await loginWithGithubMutation({
variables: { code: githubCode },
});
if (data.data?.loginWithGithub) {
login(data.data.loginWithGithub.token);
history.push('/dashboard');
}
} catch (error) {
toast.error(error.message);
}
return;
}
if (githubState === 'github_application_setup' && githubCode) {
// Remove hash in url
window.history.replaceState({}, document.title, '.');
try {
const data = await registerGithubAppMutation({
variables: { code: githubCode },
update: (cache, { data }) => {
cache.modify({
fields: {
setup: (existingSetup) => {
if (data?.registerGithubApp?.githubAppClientId) {
// Change the local cache so we don't have to call the server again
const newSetup = {
...existingSetup,
isGithubAppSetup: true,
};
return newSetup;
}
return existingSetup;
},
},
});
},
});
if (data.data?.registerGithubApp?.githubAppClientId) {
// Manually set the config so we don't have to reload the page
config.githubClientId =
data.data?.registerGithubApp?.githubAppClientId;
setShowAppSuccessAlert(true);
}
} catch (error) {
toast.error(error.message);
}
}
};
codeToLogin();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleLogin = () => {
// The redirect_uri parameter should only be used on production,
// on dev env we force the redirection to localhost
window.location.replace(
`https://github.com/login/oauth/authorize?client_id=${config.githubClientId}&state=github_login`
);
};
// We check if the user is connected, if yes we need to redirect him to the dashboard
if (loggedIn) {
return <Redirect to="dashboard" />;
}
return (
<Container maxW="5xl">
<Box
display="flex"
flexDirection="column"
alignItems="center"
justifyContent="center"
minHeight="100vh"
>
<Heading as="h2" size="lg">
Ledokku
</Heading>
{error && (
<Text mt={4} color="red.500">
{error.message}
</Text>
)}
{(loading || registerGithubAppLoading || loginWithGithubLoading) && (
<Spinner mt={4} />
)}
{data?.setup.canConnectSsh === false && (
<>
<Text mt={4}>
In order to setup the ssh connection, run the following command on
your Dokku server.
</Text>
<Terminal wordBreak="break-all">
{`echo "${data.setup.sshPublicKey}" | dokku ssh-keys:add ledokku`}
</Terminal>
<Text mt={3}>Once you are done, just refresh this page.</Text>
</>
)}
{data?.setup.canConnectSsh === true &&
data?.setup.isGithubAppSetup === false &&
!registerGithubAppLoading && (
<Box
maxWidth="xl"
display="flex"
flexDirection="column"
alignItems="center"
justifyContent="center"
>
<Text mt={4} textAlign="center">
In order to be able to login and interact with the Github API,
let's create a new Github Application.
</Text>
<form
action="https://github.com/settings/apps/new?state=github_application_setup"
method="post"
>
<input
type="text"
name="manifest"
id="manifest"
defaultValue={data.setup.githubAppManifest}
style={{ display: 'none' }}
/>
<Button
mt={4}
colorScheme="gray"
type="submit"
leftIcon={<FiGithub size={18} />}
size="lg"
>
Create Github Application
</Button>
</form>
</Box>
)}
{data?.setup.canConnectSsh === true &&
data?.setup.isGithubAppSetup === true &&
!loginWithGithubLoading && (
<Box
maxWidth="2xl"
display="flex"
flexDirection="column"
alignItems="center"
justifyContent="center"
>
{showAppSuccessAlert ? (
<Alert
mt={4}
status="success"
variant="top-accent"
flexDirection="column"
alignItems="flex-start"
borderBottomRadius="base"
boxShadow="md"
>
<AlertTitle mr={2}>
Github application successfully created
</AlertTitle>
<AlertDescription>
You can now login to create your first user.
</AlertDescription>
</Alert>
) : null}
<Button
mt={4}
colorScheme="gray"
onClick={handleLogin}
leftIcon={<FiGithub size={18} />}
size="lg"
>
Log in with Github
</Button>
</Box>
)}
</Box>
</Container>
);
}
Example #18
Source File: NotificationsWalkthrough.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
NotificationsWalkthrough = (): JSX.Element => {
const dispatch = useAppDispatch();
const alertRef = useRef(null);
const serverLoaded = (useAppSelector(state => state.config.fcm_server !== null) ?? false);
const clientLoaded = (useAppSelector(state => state.config.fcm_client !== null) ?? false);
const [isDragging, setDragging] = useBoolean();
const [errors, setErrors] = useState([] as Array<ErrorItem>);
const alertOpen = errors.length > 0;
const onDrop = async (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
dragCounter = 0;
setDragging.off();
// I'm not sure why, but we need to copy the file data _before_ we read it using the file reader.
// If we do not, the data transfer file list gets set to empty after reading the first file.
const listCopy: Array<Blob> = [];
for (let i = 0; i < e.dataTransfer.files.length; i++) {
listCopy.push(e.dataTransfer.files.item(i) as Blob);
}
// Actually read the files
const errors: Array<ErrorItem> = [];
for (let i = 0; i < listCopy.length; i++) {
try {
const fileStr = await readFile(listCopy[i]);
const validClient = isValidClientConfig(fileStr);
const validServer = isValidServerConfig(fileStr);
const jsonData = JSON.parse(fileStr);
if (validClient) {
const test = isValidFirebaseUrl(jsonData);
if (test) {
await saveFcmClient(jsonData);
dispatch(setConfig({ name: 'fcm_client', 'value': jsonData }));
} else {
throw new Error(
'Your Firebase setup does not have a real-time database enabled. ' +
'Please enable the real-time database in your Firebase Console.'
);
}
} else if (validServer) {
await saveFcmServer(jsonData);
dispatch(setConfig({ name: 'fcm_server', 'value': jsonData }));
} else {
throw new Error('Invalid Google FCM File!');
}
} catch (ex: any) {
errors.push({ id: String(i), message: ex?.message ?? String(ex) });
}
}
if (errors.length > 0) {
setErrors(errors);
}
};
const onDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
if (dragCounter === 0) {
setDragging.on();
}
dragCounter += 1;
};
const onDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.stopPropagation();
e.preventDefault();
};
const onDragLeave = () => {
dragCounter -= 1;
if (dragCounter === 0) {
setDragging.off();
}
};
const closeAlert = () => {
setErrors([]);
};
return (
<SlideFade in={true} offsetY='150px'>
<Box
px={5}
onDragEnter={(e) => onDragEnter(e)}
onDragLeave={() => onDragLeave()}
onDragOver={(e) => onDragOver(e)}
onDrop={(e) => onDrop(e)}
>
<Text fontSize='4xl'>Notifications & Firebase</Text>
<Text fontSize='md' mt={5}>
BlueBubbles utilizes Google FCM (Firebase Cloud Messaging) to deliver notifications to your devices.
We do this so the client do not need to hold a connection to the server at all times. As a result,
BlueBubbles can deliver notifications even when the app is running in the background. It also means
BlueBubbles will use less battery when running in the background.
</Text>
<Alert status='info' mt={5}>
<AlertIcon />
If you do not complete this setup, you will not receive notifications!
</Alert>
<Text fontSize='md' mt={5}>
The setup with Google FCM is a bit tedious, but it is a "set it and forget it" feature. Follow the
instructions here: <Link
as='span'
href='https://bluebubbles.app/install/'
color='brand.primary'
target='_blank'>https://bluebubbles.app/install</Link>
</Text>
<Text fontSize='3xl' mt={5}>Firebase Configurations</Text>
<SimpleGrid columns={2} spacing={5} mt={5}>
<DropZone
text="Drag n' Drop google-services.json"
loadedText="google-services.json Successfully Loaded!"
isDragging={isDragging}
isLoaded={serverLoaded}
/>
<DropZone
text="Drag n' Drop *-firebase-adminsdk-*.json"
loadedText="*-firebase-adminsdk-*.json Successfully Loaded!"
isDragging={isDragging}
isLoaded={clientLoaded}
/>
</SimpleGrid>
</Box>
<ErrorDialog
errors={errors}
modalRef={alertRef}
onClose={() => closeAlert()}
isOpen={alertOpen}
/>
</SlideFade>
);
}
Example #19
Source File: BaseTokenOracleConfig.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
BaseTokenOracleConfig = () => {
const { t } = useTranslation();
const { address } = useRari();
const {
mode,
oracleData,
uniV3BaseTokenAddress,
uniV3BaseTokenOracle,
setUniV3BaseTokenOracle,
baseTokenActiveOracleName,
setBaseTokenActiveOracleName,
} = useAddAssetContext();
const isUserAdmin = address === oracleData?.admin ?? false;
// We get all oracle options.
const options = useGetOracleOptions(oracleData, uniV3BaseTokenAddress);
console.log("helo there", { options });
// If we're editing the asset, show master price oracle as a default.
// Should run only once, when component renders.
useEffect(() => {
if (
mode === "Editing" &&
baseTokenActiveOracleName === "" &&
options &&
options["Current_Price_Oracle"]
)
setBaseTokenActiveOracleName("Current_Price_Oracle");
}, [mode, baseTokenActiveOracleName, options, setBaseTokenActiveOracleName]);
// This will update the oracle address, after user chooses which options they want to use.
// If option is Custom_Oracle oracle address is typed in by user, so we dont trigger this.
useEffect(() => {
if (
!!baseTokenActiveOracleName &&
baseTokenActiveOracleName !== "Custom_Oracle" &&
options
)
setUniV3BaseTokenOracle(options[baseTokenActiveOracleName]);
}, [baseTokenActiveOracleName, options, setUniV3BaseTokenOracle]);
return (
<>
<Row
crossAxisAlignment="center"
mainAxisAlignment="center"
width="100%"
my={2}
>
<Alert status="info" width="80%" height="50px" borderRadius={5} my={1}>
<AlertIcon />
<Text fontSize="sm" align="center" color="black">
{"This Uniswap V3 TWAP Oracle needs an oracle for the BaseToken."}
</Text>
</Alert>
</Row>
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="center"
w="100%"
h="100%"
>
<Column
my={4}
width="100%"
crossAxisAlignment="center"
mainAxisAlignment="space-between"
>
<Column
mainAxisAlignment="center"
crossAxisAlignment="center"
height="50%"
justifyContent="space-around"
>
<CTokenIcon address={uniV3BaseTokenAddress} boxSize={"50px"} />
<SimpleTooltip
label={t("Choose the best price oracle for this BaseToken.")}
>
<Text fontWeight="bold" fontSize="sm" align="center">
{t("BaseToken Price Oracle")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
</Column>
{options ? (
<Box alignItems="center" height="50%">
<Select
{...DASHBOARD_BOX_PROPS}
ml="auto"
my={2}
borderRadius="7px"
_focus={{ outline: "none" }}
width="260px"
placeholder={
baseTokenActiveOracleName.length === 0
? t("Choose Oracle")
: baseTokenActiveOracleName.replaceAll("_", " ")
}
value={baseTokenActiveOracleName.toLowerCase()}
disabled={
!isUserAdmin ||
(!oracleData?.adminOverwrite &&
!options.Current_Price_Oracle === null)
}
onChange={(event) =>
setBaseTokenActiveOracleName(event.target.value)
}
>
{Object.entries(options).map(([key, value]) =>
value !== null &&
value !== undefined &&
key !== "Uniswap_V3_Oracle" &&
key !== "Uniswap_V2_Oracle" ? (
<option className="black-bg-option" value={key} key={key}>
{key.replaceAll("_", " ")}
</option>
) : null
)}
</Select>
{baseTokenActiveOracleName.length > 0 ? (
<Input
width="100%"
textAlign="center"
height="40px"
variant="filled"
size="sm"
mt={2}
mb={2}
value={uniV3BaseTokenOracle}
onChange={(event) => {
const address = event.target.value;
setUniV3BaseTokenOracle(address);
}}
disabled={
baseTokenActiveOracleName === "Custom_Oracle" ? false : true
}
{...DASHBOARD_BOX_PROPS}
_placeholder={{ color: "#e0e0e0" }}
_focus={{ bg: "#121212" }}
_hover={{ bg: "#282727" }}
bg="#282727"
/>
) : null}
</Box>
) : null}
</Column>
</Column>
</>
);
}
Example #20
Source File: UniswapV3PriceOracleConfigurator.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
UniswapV3PriceOracleConfigurator = () => {
const { t } = useTranslation();
const {
setFeeTier,
tokenAddress,
setOracleAddress,
setUniV3BaseTokenAddress,
activeUniSwapPair,
setActiveUniSwapPair,
} = useAddAssetContext();
// We get a list of whitelistedPools from uniswap-v3's the graph.
const { data: liquidity, error } = useQuery(
"UniswapV3 pool liquidity for " + tokenAddress,
async () =>
(
await axios.post(
"https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3",
{
query: `{
token(id:"${tokenAddress.toLowerCase()}") {
whitelistPools {
id,
feeTier,
volumeUSD,
totalValueLockedUSD,
token0 {
symbol,
id,
name
},
token1 {
symbol,
id,
name
}
}
}
}`,
}
)
).data,
{ refetchOnMount: false }
);
// When user selects an option this function will be called.
// Active pool, fee Tier, and base token are updated and we set the oracle address to the address of the pool we chose.
const updateBoth = (value: string) => {
const uniPool = liquidity.data.token.whitelistPools[value];
const baseToken: string =
uniPool.token0.id.toLowerCase() === tokenAddress.toLocaleLowerCase()
? uniPool.token1.id
: uniPool.token0.id;
setActiveUniSwapPair(value);
setFeeTier(uniPool.feeTier);
setOracleAddress(uniPool.id);
setUniV3BaseTokenAddress(baseToken);
};
// If liquidity is undefined, theres an error or theres no token found return nothing.
if (liquidity === undefined || liquidity.data === undefined)
return null;
// Sort whitelisted pools by TVL. Greatest to smallest. Greater TVL is safer for users so we show it first.
// Filter out pools where volume is less than $100,000
const liquiditySorted = liquidity.data.token.whitelistPools.sort(
(a: any, b: any): any =>
parseInt(a.totalValueLockedUSD) > parseInt(b.totalValueLockedUSD) ? -1 : 1
);
// .filter((pool: any) => pool.volumeUSD >= 100000);
const selectedOracle = liquidity.data.token.whitelistPools[activeUniSwapPair];
console.log({ selectedOracle });
// const warning = useMemo(() => {
// if (selectedOracle.liquidityProviderCount <=100)
// }, [selectedOracle]);
return (
<>
<Column
crossAxisAlignment="flex-start"
mainAxisAlignment="flex-start"
width={"100%"}
my={2}
px={4}
ml={"auto"}
// bg="aqua"
id="UNIv3COLUMN"
>
<Row
crossAxisAlignment="center"
mainAxisAlignment="space-between"
w="100%"
// bg="green"
>
<SimpleTooltip
label={t(
"This field will determine which pool your oracle reads from. Its safer with more liquidity."
)}
>
<Text fontWeight="bold">
{t("Pool:")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
<Select
{...DASHBOARD_BOX_PROPS}
ml={2}
mb={2}
width="180px"
borderRadius="7px"
value={activeUniSwapPair}
_focus={{ outline: "none" }}
placeholder={
activeUniSwapPair === "" ? t("Choose Pool") : activeUniSwapPair
}
onChange={(event) => {
updateBoth(event.target.value);
}}
>
{typeof liquidity !== undefined
? Object.entries(liquiditySorted).map(([key, value]: any[]) =>
value.totalValueLockedUSD !== null &&
value.totalValueLockedUSD !== undefined &&
value.totalValueLockedUSD >= 100 ? (
<option
className="black-bg-option"
value={key}
key={value.id}
>
{`${value.token0.symbol} / ${
value.token1.symbol
} (${shortUsdFormatter(value.totalValueLockedUSD)})`}
</option>
) : null
)
: null}
</Select>
</Row>
{activeUniSwapPair !== "" ? (
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-start"
>
<Row mainAxisAlignment="flex-start" crossAxisAlignment="flex-start">
<Alert
status="warning"
width="100%"
height="70px"
borderRadius={5}
my={1}
>
<AlertIcon />
<Text fontSize="sm" align="center" color="black">
{
"Make sure this Uniswap V3 Pool has full-range liquidity. If not, your pool could be compromised."
}
</Text>
</Alert>
</Row>
<Row
mainAxisAlignment="space-between"
crossAxisAlignment="center"
my={2}
w="100%"
// bg="pink"
>
<SimpleTooltip label={t("TVL in pool as of this moment.")}>
<Text fontWeight="bold">
{t("Liquidity:")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
<h1>
{activeUniSwapPair !== ""
? shortUsdFormatter(
liquidity.data.token.whitelistPools[activeUniSwapPair]
.totalValueLockedUSD
)
: null}
</h1>
</Row>
<Row
mainAxisAlignment="space-between"
crossAxisAlignment="center"
my={2}
w="100%"
// bg="pink"
>
<SimpleTooltip label={t("Volume of pool.")}>
<Text fontWeight="bold">
{t("Volume:")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
<h1>
{activeUniSwapPair !== ""
? shortUsdFormatter(
liquidity.data.token.whitelistPools[activeUniSwapPair]
.volumeUSD
)
: null}
</h1>
</Row>
{/* <Row
mainAxisAlignment="space-between"
crossAxisAlignment="center"
my={2}
w="100%"
// bg="pink"
>
<SimpleTooltip
label={t(
"The fee percentage for the pool on Uniswap (0.05%, 0.3%, 1%)"
)}
>
<Text fontWeight="bold">
{t("Fee Tier:")} <QuestionIcon ml={1} mb="4px" />
</Text>
</SimpleTooltip>
<Text>
%
{activeUniSwapPair !== ""
? liquidity.data.token.whitelistPools[activeUniSwapPair]
.feeTier / 10000
: null}
</Text>
</Row> */}
<Row
crossAxisAlignment="center"
mainAxisAlignment="center"
width="260px"
my={0}
>
<Link
href={`https://info.uniswap.org/#/pools/${liquidity.data.token.whitelistPools[activeUniSwapPair].id}`}
isExternal
>
Visit Pool in Uniswap
</Link>
</Row>
</Column>
) : null}
</Column>
</>
);
}
Example #21
Source File: ChatForm.tsx From takeout-app with MIT License | 4 votes |
ChatForm: React.FC<Props> = ({ track, channel }) => {
const chat = useChat();
const { data: session } = Api.useSession();
const isStaff = session?.attendee?.is_staff;
const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
const [isRequesting, setIsRequesting] = React.useState<boolean>(false);
const { register, handleSubmit, reset, setFocus, watch } = useForm<{
message: string;
asAdmin: boolean;
}>({
defaultValues: {
message: "",
asAdmin: false,
},
});
const asAdmin = watch("asAdmin");
const onSubmit = handleSubmit(async (data) => {
if (!chat.session || !channel) return;
if (isRequesting) return;
setIsRequesting(true);
setErrorAlert(null);
try {
if (data.asAdmin && isStaff) {
await Api.sendChatMessage(track.slug, data.message, true);
} else {
// Workaround: aws-sdk-v3 sigv4 fails to generate correct signature for payload containing emoji...
if (/\p{Extended_Pictographic}/u.test(data.message)) {
await Api.sendChatMessage(track.slug, data.message, false);
} else {
await chat.session.postMessage(channel, data.message);
}
}
reset({ message: "", asAdmin: false });
} catch (e) {
setErrorAlert(
<Box my={2}>
<ErrorAlert error={e} />
</Box>,
);
}
setFocus("message");
setIsRequesting(false);
});
const shouldDisable = !session?.attendee || !chat.session || !channel;
// TODO: errorAlert to toast
return (
<Box p="16px" bgColor="#ffffff" borderTop="1px solid" borderColor={Colors.chatBorder}>
{errorAlert}
<form onSubmit={onSubmit}>
<VStack w="100%">
{session && !session.attendee?.is_ready ? (
<Box w="100%">
<Alert status="warning">
<AlertIcon />
<Text as="span">
Set your name at{" "}
<Link as={RouterLink} to="/attendee" textDecoration="underline">
Settings
</Link>{" "}
page
</Text>
</Alert>
</Box>
) : null}
<Box w="100%">
<Textarea
as={TextareaAutoSize}
{...register("message")}
size="sm"
placeholder={asAdmin ? "SAY SOMETHING AS ADMIN..." : "Send a message"}
isRequired
isDisabled={shouldDisable}
autoComplete="off"
rows={1}
minRows={1}
maxRows={4}
onKeyPress={(e) => {
if (e.key == "Enter") {
e.preventDefault();
onSubmit();
}
}}
css={{ resize: "none" }}
/>
</Box>
<Flex w="100%" alignItems="flex-end" direction="row-reverse" justifyContent="space-between">
<IconButton
icon={<SendIcon boxSize="14px" />}
minW="30px"
w="30px"
h="30px"
aria-label="Send"
type="submit"
isLoading={isRequesting}
isDisabled={shouldDisable}
/>
{isStaff ? (
<Tooltip label="Send as an official announcement" aria-label="">
<FormControl display="flex" alignSelf="center" h="30px">
<FormLabel htmlFor="ChatForm__asAdmin" aria-hidden="true" m={0} mr={1}>
<CampaignIcon w="24px" h="24px" />
</FormLabel>
<Switch
aria-label="Send as an official announcement"
id="ChatForm__asAdmin"
size="sm"
isChecked={asAdmin}
isDisabled={shouldDisable}
{...register("asAdmin")}
/>
</FormControl>
</Tooltip>
) : null}
</Flex>
</VStack>
</form>
</Box>
);
}
Example #22
Source File: Screen2.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
Screen2 = ({ mode }: { mode: string }) => {
const {
feeTier,
poolOracleModel,
oracleData,
setFeeTier,
activeOracleModel,
tokenAddress,
oracleAddress,
oracleTouched,
uniV3BaseTokenAddress,
setOracleTouched,
activeUniSwapPair,
setOracleAddress,
setActiveOracleModel,
setUniV3BaseTokenAddress,
poolOracleAddress,
setActiveUniSwapPair,
uniV3BaseTokenOracle,
setUniV3BaseTokenOracle,
baseTokenActiveOracleName,
setBaseTokenActiveOracleName,
shouldShowUniV3BaseTokenOracleForm,
// New stuff -skip oracle step with default oracle
hasPriceForAsset,
hasDefaultOracle,
hasCustomOracleForToken,
priceForAsset,
defaultOracle,
customOracleForToken,
} = useAddAssetContext();
if (
poolOracleModel === "MasterOracleV1" ||
poolOracleModel === "ChainlinkPriceOracle"
)
return (
<LegacyOracle
tokenAddress={tokenAddress}
poolOracleModel={poolOracleModel}
setActiveOracleModel={setActiveOracleModel}
poolOracleAddress={poolOracleAddress}
setOracleAddress={setOracleAddress}
/>
);
// If it has a default oracle and the user hasn't edited to be outside the default oracle
const hasDefaultOraclePriceAndHasntEdited =
hasDefaultOracle && hasPriceForAsset && oracleAddress === defaultOracle;
return (
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment="flex-start"
h="100%"
w="100%"
// bg="aqua"
>
{hasDefaultOraclePriceAndHasntEdited && (
<Row
mainAxisAlignment="center"
crossAxisAlignment="center"
w="100%"
h="30%"
// bg="red"
>
<Alert status="info" width="80%" height="50px" borderRadius={5}>
<AlertIcon />
<Text fontSize="sm" align="center" color="black">
This asset already has a price from the Pool's Default Oracle, but
you can change this asset's oracle if you want.
</Text>
</Alert>
</Row>
)}
<Row
mainAxisAlignment={
mode === "Adding" && !shouldShowUniV3BaseTokenOracleForm
? "center"
: "flex-start"
}
crossAxisAlignment={
mode === "Adding" && !shouldShowUniV3BaseTokenOracleForm
? "center"
: "flex-start"
}
h="100%"
w="100%"
>
<Column
mainAxisAlignment="flex-start"
crossAxisAlignment={
shouldShowUniV3BaseTokenOracleForm ? "flex-start" : "center"
}
maxHeight="100%"
height="100%"
maxWidth="100%"
width={
mode === "Adding" && !shouldShowUniV3BaseTokenOracleForm
? "50%"
: "100%"
}
>
<OracleConfig />
</Column>
{shouldShowUniV3BaseTokenOracleForm ? (
<Column
width="50%"
minW="50%"
height="100%"
mainAxisAlignment="center"
crossAxisAlignment="center"
>
<BaseTokenOracleConfig />
</Column>
) : null}
</Row>
</Column>
);
}
Example #23
Source File: RenderDetail.tsx From ke with MIT License | 4 votes |
RenderDetail = (props: RenderDetailProps): JSX.Element => {
/*
Entry point for displaying components in https://myspa.com/some-url/100500 route format.
Here we fetch data from the backend using the url that we specified in a
admin class.
After that we mounts the widgets of a particular view type. At the moment there are two:
- Detail View (see mountDetailFields for detail)
- Wizard View (see mountWizards for detail)
*/
const [mainDetailObject, setMainDetailObject] = useState<Model>()
const [needRefreshDetailObject, setNeedRefreshDetailObject] = useState<boolean>(true)
const { id } = useParams<{ id: string }>()
const { resourceName, admin, provider, notifier } = props
const toast = useToast()
const detailNotifier = notifier || new ChakraUINotifier(toast)
const [isLoading, setIsLoading] = useState<boolean>(true)
const [loadError, setLoadError] = useState<LoadError | null>(null)
const activeWizardRef = useRef<WizardControl>()
let title = `${admin.verboseName} # ${id}`
if (admin.getPageTitle) {
const pageTitle = admin.getPageTitle(mainDetailObject)
if (pageTitle) {
title = pageTitle
}
}
document.title = title
let favicon = admin.favicon || ''
if (admin.getPageFavicon) {
const favIconSource = admin.getPageFavicon(mainDetailObject)
if (favIconSource) {
favicon = favIconSource
}
}
setFavicon(favicon)
const refreshMainDetailObject = (): void => {
setNeedRefreshDetailObject(true)
}
useEffect(() => {
const backendResourceUrl = admin.getResource(id)
if (needRefreshDetailObject) {
provider
.getObject(backendResourceUrl)
.then(async (res) => {
setNeedRefreshDetailObject(false)
setMainDetailObject(res)
if (admin?.onDetailObjectLoaded !== undefined) {
await admin.onDetailObjectLoaded({
mainDetailObject: res,
provider,
context: containerStore,
setInitialValue,
})
}
})
.catch((er: LoadError) => {
setLoadError(er)
})
.finally(() => setIsLoading(false))
}
}, [id, provider, admin, needRefreshDetailObject, props, mainDetailObject])
const { getDataTestId } = useCreateTestId({ name: admin.name })
useEffect(() => {
admin.onMount()
return () => admin.onUnmount()
}, [admin])
return (
<SaveEventProvider>
<Row>
<Col xs={12} xsOffset={0} md={10} mdOffset={1}>
<Box padding="8px 0px">
<ToListViewLink name={resourceName} />
</Box>
</Col>
</Row>
<Row {...getDataTestId()}>
<Col xs={12} xsOffset={0} md={10} mdOffset={1}>
{isLoading ? <Spinner /> : ''}
{!isLoading && !loadError
? Object.entries(getContainersToMount()).map(([elementsKey, container]: [string, Function]) => {
const elements = admin[elementsKey as keyof typeof admin]
if (!elements) return []
return (
<ErrorBoundary>
{container({
mainDetailObject,
setMainDetailObject,
ViewType,
elements,
elementsKey,
refreshMainDetailObject,
activeWizardRef,
...props,
notifier: detailNotifier,
})}
</ErrorBoundary>
)
})
: ''}
{!isLoading && loadError ? (
<Alert status="error" {...getDataTestId({ postfix: '--loadingError' })}>
<AlertIcon />
<AlertTitle mr={2}>Ошибка при выполнении запроса</AlertTitle>
<AlertDescription>{loadError.response?.data?.message}</AlertDescription>
</Alert>
) : (
''
)}
</Col>
</Row>
</SaveEventProvider>
)
}
Example #24
Source File: ApprovePanelOwnedDope.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
ApprovePanelOwnedDope = ({hustlerConfig, setHustlerConfig}: StepsProps) => {
const [mintTo, setMintTo] = useState(hustlerConfig.mintAddress != null);
const [canMint, setCanMint] = useState(false);
const { account } = useWeb3React();
const [hasEnoughPaper, setHasEnoughPaper] = useState<boolean>();
const [isPaperApproved, setIsPaperApproved] = useState<boolean>();
const isContract = useIsContract(account);
const dispatchHustler = useDispatchHustler();
const initiator = useInitiator();
// Set PAPER cost based on contract amount due to "halvening"
const [paperCost, setPaperCost] = useState<BigNumber>();
useEffect(() => {
let isMounted = true;
initiator.cost().then(setPaperCost);
return () => { isMounted = false };
}, [initiator]);
// Has enough paper?
const paper = usePaper();
useEffect(() => {
if (account && paperCost) {
paper
.balanceOf(account)
.then(balance => setHasEnoughPaper(balance.gte(paperCost)));
}
}, [account, paper, paperCost]);
// Can we mint?
useEffect(() => {
if (isPaperApproved && hasEnoughPaper && (!mintTo || (mintTo && hustlerConfig.mintAddress))) {
setCanMint(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isPaperApproved, hasEnoughPaper, isContract, hustlerConfig.mintAddress, hustlerConfig.body]);
const mintHustler = () => {
if (!account) {
return;
}
const config = createConfig(hustlerConfig)
const {
dopeId,
mintAddress,
} = hustlerConfig;
initiator
.mintFromDopeTo(dopeId, mintAddress ? mintAddress : account, config, '0x', 1500000)
.then(() =>
dispatchHustler({
type: 'GO_TO_FINALIZE_STEP',
}),
);
};
const setMintAddress = useCallback(
(value: string) => {
setHustlerConfig({ ...hustlerConfig, mintAddress: value });
},
[hustlerConfig, setHustlerConfig],
);
return(
<Stack>
{!isPaperApproved &&
<ApprovePaper
address={initiator.address}
isApproved={isPaperApproved}
onApprove={approved => setIsPaperApproved(approved)}
>
We need you to allow our Swap Meet to spend <ReceiptItemPaper amount={paperCost} hideUnderline /> to Claim Gear of DOPE NFT #{hustlerConfig.dopeId}.
</ApprovePaper>
}
{isPaperApproved &&
<PanelContainer justifyContent="flex-start">
<PanelTitleHeader>Transaction Details</PanelTitleHeader>
<PanelBody>
<h4>You Use</h4>
<hr className="onColor" />
<ReceiptItemDope dopeId={hustlerConfig.dopeId} hideUnderline />
<br/>
<h4>You Pay</h4>
<hr className="onColor" />
<ReceiptItemPaper amount={paperCost} hideUnderline />
{!hasEnoughPaper && (
<Alert status="error">
<AlertIcon />
Not enough $PAPER
</Alert>
)}
<br/>
<h4>You Receive</h4>
<hr className="onColor" />
<ReceiptItemHustler hustlerConfig={hustlerConfig} />
<ReceiptItemGear hideUnderline />
</PanelBody>
<PanelFooter
css={css`
padding: 1em;
position: relative;
`}
>
<DisconnectAndQuitButton returnToPath='/inventory?section=Dope' />
{/* <MintTo
mintTo={mintTo}
setMintTo={setMintTo}
mintAddress={hustlerConfig.mintAddress}
setMintAddress={setMintAddress}
/> */}
<Button variant="primary" onClick={mintHustler} disabled={!canMint} autoFocus>
✨ Mint Hustler ✨
</Button>
</PanelFooter>
</PanelContainer>
}
</Stack>
);
}
Example #25
Source File: logs.tsx From ledokku with MIT License | 4 votes |
Logs = () => {
const { id: databaseId } = useParams<{ id: string }>();
const { data, loading /* error */ } = useDatabaseByIdQuery({
variables: {
databaseId,
},
});
const {
data: databaseLogsData,
error: databaseLogsError,
loading: databaseLogsLoading,
} = useDatabaseLogsQuery({
variables: {
databaseId,
},
pollInterval: 15000,
});
if (!data) {
return null;
}
// // TODO display error
if (loading) {
// TODO nice loading
return <p>Loading...</p>;
}
const { database } = data;
if (!database) {
// TODO nice 404
return <p>App not found.</p>;
}
return (
<div>
<HeaderContainer>
<Header />
<DatabaseHeaderInfo database={database} />
<DatabaseHeaderTabNav database={database} />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<Heading as="h2" size="md" py={5}>
Logs
</Heading>
{databaseLogsLoading ? (
<Text fontSize="sm" color="gray.400">
Loading...
</Text>
) : null}
{databaseLogsError ? (
<Alert
status="error"
variant="top-accent"
borderBottomRadius="base"
boxShadow="md"
>
<AlertDescription>{databaseLogsError.message}</AlertDescription>
</Alert>
) : null}
{!databaseLogsLoading && !databaseLogsError && databaseLogsData ? (
<Terminal mb="8">
{databaseLogsData.databaseLogs.logs.map((dblog, index) => (
<React.Fragment key={index}>
{dblog ? <p>{dblog}</p> : <p> </p>}
</React.Fragment>
))}
</Terminal>
) : null}
</Container>
</div>
);
}
Example #26
Source File: create-database.tsx From ledokku with MIT License | 4 votes |
CreateDatabase = () => {
const location = useLocation();
const history = useHistory();
const toast = useToast();
const { data: dataDb } = useDatabaseQuery();
const [arrayOfCreateDbLogs, setArrayofCreateDbLogs] = useState<RealTimeLog[]>(
[]
);
const [isTerminalVisible, setIsTerminalVisible] = useState(false);
const [createDatabaseMutation] = useCreateDatabaseMutation();
const [
isDbCreationSuccess,
setIsDbCreationSuccess,
] = useState<DbCreationStatus>();
useCreateDatabaseLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.createDatabaseLogs;
if (logsExist) {
setArrayofCreateDbLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (logsExist.type === 'end:success') {
setIsDbCreationSuccess(DbCreationStatus.SUCCESS);
} else if (logsExist.type === 'end:failure') {
setIsDbCreationSuccess(DbCreationStatus.FAILURE);
}
}
},
});
const createDatabaseSchema = yup.object({
type: yup
.string()
.oneOf(['POSTGRESQL', 'MYSQL', 'MONGODB', 'REDIS'])
.required(),
name: yup.string().when('type', (type: DatabaseTypes) => {
return yup
.string()
.required('Database name is required')
.matches(/^[a-z0-9-]+$/)
.test(
'Name already exists',
`You already have created ${type} database with this name`,
(name) =>
!dataDb?.databases.find(
(db) => db.name === name && type === db.type
)
);
}),
});
const [
isDokkuPluginInstalled,
{ data, loading, error: isDokkuPluginInstalledError },
] = useIsPluginInstalledLazyQuery({
// we poll every 5 sec
pollInterval: 5000,
});
const formik = useFormik<{ name: string; type: DatabaseTypes }>({
initialValues: {
name: location.state ? (location.state as string) : '',
type: 'POSTGRESQL',
},
validateOnChange: true,
validationSchema: createDatabaseSchema,
onSubmit: async (values) => {
try {
await createDatabaseMutation({
variables: {
input: { name: values.name, type: values.type },
},
});
setIsTerminalVisible(true);
trackGoal(trackingGoals.createDatabase, 0);
} catch (error) {
toast.error(error.message);
}
},
});
const isPluginInstalled = data?.isPluginInstalled.isPluginInstalled;
const handleNext = () => {
setIsTerminalVisible(false);
const dbId = arrayOfCreateDbLogs[arrayOfCreateDbLogs.length - 1].message;
history.push(`database/${dbId}`);
};
// Effect for checking whether plugin is installed
useEffect(() => {
isDokkuPluginInstalled({
variables: {
pluginName: dbTypeToDokkuPlugin(formik.values.type),
},
});
}, [formik.values.type, isPluginInstalled, isDokkuPluginInstalled]);
// Effect for db creation
useEffect(() => {
isDbCreationSuccess === DbCreationStatus.FAILURE
? toast.error('Failed to create database')
: isDbCreationSuccess === DbCreationStatus.SUCCESS &&
toast.success('Database created successfully');
}, [isDbCreationSuccess, toast]);
return (
<>
<HeaderContainer>
<Header />
</HeaderContainer>
<Container maxW="5xl" my="4">
<Heading as="h2" size="md">
Create a new database
</Heading>
<Box mt="12">
{isTerminalVisible ? (
<>
<Text mb="2">
Creating <b>{formik.values.type}</b> database{' '}
<b>{formik.values.name}</b>
</Text>
<Text mb="2" color="gray.500">
Creating database usually takes a couple of minutes. Breathe in,
breathe out, logs are about to appear below:
</Text>
<Terminal>
{arrayOfCreateDbLogs.map((log) => (
<Text key={arrayOfCreateDbLogs.indexOf(log)} size="small">
{log.message}
</Text>
))}
</Terminal>
{!!isDbCreationSuccess &&
isDbCreationSuccess === DbCreationStatus.SUCCESS ? (
<Box mt="12" display="flex" justifyContent="flex-end">
<Button
onClick={() => handleNext()}
rightIcon={<FiArrowRight size={20} />}
>
Next
</Button>
</Box>
) : !!isDbCreationSuccess &&
isDbCreationSuccess === DbCreationStatus.FAILURE ? (
<Box mt="12" display="flex" justifyContent="flex-end">
<Button
onClick={() => {
setIsTerminalVisible(false);
formik.resetForm();
}}
rightIcon={<FiArrowLeft size={20} />}
>
Back
</Button>
</Box>
) : null}
</>
) : (
<Box mt="8">
<form onSubmit={formik.handleSubmit}>
<Box mt="12">
{loading && (
<Center>
<Spinner />
</Center>
)}
{isDokkuPluginInstalledError ? (
<Alert
status="error"
variant="top-accent"
flexDirection="column"
alignItems="flex-start"
borderBottomRadius="base"
boxShadow="md"
>
<AlertTitle mr={2}>Request failed</AlertTitle>
<AlertDescription>
{isDokkuPluginInstalledError.message}
</AlertDescription>
</Alert>
) : null}
{data?.isPluginInstalled.isPluginInstalled === false &&
!loading && (
<>
<Text mt="3">
Before creating a{' '}
<b>{formik.values.type.toLowerCase()}</b> database,
you will need to run this command on your dokku
server.
</Text>
<Terminal>{`sudo dokku plugin:install https://github.com/dokku/dokku-${dbTypeToDokkuPlugin(
formik.values.type
)}.git ${dbTypeToDokkuPlugin(
formik.values.type
)}`}</Terminal>
<Text mt="3">
Couple of seconds later you will be able to proceed
further.
</Text>
</>
)}
{data?.isPluginInstalled.isPluginInstalled === true &&
!loading && (
<SimpleGrid columns={{ sm: 1, md: 3 }}>
<FormControl
id="name"
isInvalid={Boolean(
formik.errors.name && formik.touched.name
)}
>
<FormLabel>Database name</FormLabel>
<Input
autoComplete="off"
id="name"
name="name"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<FormErrorMessage>
{formik.errors.name}
</FormErrorMessage>
</FormControl>
</SimpleGrid>
)}
</Box>
<Box mt="12">
<Text mb="2">Choose your database</Text>
<Grid
templateColumns={{
base: 'repeat(2, minmax(0, 1fr))',
md: 'repeat(4, minmax(0, 1fr))',
}}
gap="4"
>
<DatabaseBox
selected={formik.values.type === 'POSTGRESQL'}
label="PostgreSQL"
icon={<PostgreSQLIcon size={40} />}
onClick={() => formik.setFieldValue('type', 'POSTGRESQL')}
/>
<DatabaseBox
selected={formik.values.type === 'MYSQL'}
label="MySQL"
icon={<MySQLIcon size={40} />}
onClick={() => formik.setFieldValue('type', 'MYSQL')}
/>
<DatabaseBox
selected={formik.values.type === 'MONGODB'}
label="Mongo"
icon={<MongoIcon size={40} />}
onClick={() => formik.setFieldValue('type', 'MONGODB')}
/>
<DatabaseBox
selected={formik.values.type === 'REDIS'}
label="Redis"
icon={<RedisIcon size={40} />}
onClick={() => formik.setFieldValue('type', 'REDIS')}
/>
</Grid>
</Box>
<Box mt="12" display="flex" justifyContent="flex-end">
<Button
isLoading={formik.isSubmitting}
disabled={
data?.isPluginInstalled.isPluginInstalled === false ||
!formik.values.name ||
!!formik.errors.name ||
!dataDb?.databases
}
rightIcon={<FiArrowRight size={20} />}
type="submit"
>
Create
</Button>
</Box>
</form>
</Box>
)}
</Box>
</Container>
</>
);
}
Example #27
Source File: create-app-github.tsx From ledokku with MIT License | 4 votes |
CreateAppGithub = () => {
const history = useHistory();
const toast = useToast();
const { user } = useAuth();
const { data: dataApps } = useAppsQuery();
const [isNewWindowClosed, setIsNewWindowClosed] = useState(false);
const [selectedRepo, setSelectedRepo] = useState<Repository>();
const [selectedBranch, setSelectedBranch] = useState('');
const [isProceedModalOpen, setIsProceedModalOpen] = useState(false);
const {
data: installationData,
loading: installationLoading,
} = useGithubInstallationIdQuery({ fetchPolicy: 'network-only' });
const [
getRepos,
{ data: reposData, loading: reposLoading },
] = useRepositoriesLazyQuery({ fetchPolicy: 'network-only' });
const [
getBranches,
{ data: branchesData, loading: branchesLoading },
] = useBranchesLazyQuery({ fetchPolicy: 'network-only' });
const [arrayOfCreateAppLogs, setArrayOfCreateAppLogs] = useState<
RealTimeLog[]
>([]);
const [isTerminalVisible, setIsTerminalVisible] = useState(false);
const [isToastShown, setIsToastShown] = useState(false);
const [createAppGithubMutation, { loading }] = useCreateAppGithubMutation();
const [
isAppCreationSuccess,
setIsAppCreationSuccess,
] = useState<AppCreationStatus>();
useAppCreateLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.appCreateLogs;
if (logsExist) {
setArrayOfCreateAppLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (logsExist.type === 'end:success') {
setIsAppCreationSuccess(AppCreationStatus.SUCCESS);
} else if (logsExist.type === 'end:failure') {
setIsAppCreationSuccess(AppCreationStatus.FAILURE);
}
}
},
});
const createAppGithubSchema = yup.object().shape({
name: yup
.string()
.required('App name is required')
.matches(/^[a-z0-9-]+$/)
.test(
'Name exists',
'App with this name already exists',
(val) => !dataApps?.apps.find((app) => app.name === val)
),
repo: yup.object({
fullName: yup.string().required(),
id: yup.string().required(),
name: yup.string().required(),
}),
installationId: yup.string().required(),
gitBranch: yup.string().optional(),
});
const formik = useFormik<{
name: string;
repo: {
fullName: string;
id: string;
name: string;
};
installationId: string;
gitBranch: string;
}>({
initialValues: {
name: '',
repo: {
fullName: '',
id: '',
name: '',
},
installationId: '',
gitBranch: '',
},
validateOnChange: true,
validationSchema: createAppGithubSchema,
onSubmit: async (values) => {
if (installationData) {
try {
await createAppGithubMutation({
variables: {
input: {
name: values.name,
gitRepoFullName: values.repo.fullName,
branchName: values.gitBranch,
gitRepoId: values.repo.id,
githubInstallationId: values.installationId,
},
},
});
setIsTerminalVisible(true);
} catch (error) {
error.message === 'Not Found'
? toast.error(`Repository : ${values.repo.fullName} not found`)
: toast.error(error.message);
}
}
},
});
const handleNext = () => {
setIsTerminalVisible(false);
const appId = arrayOfCreateAppLogs[arrayOfCreateAppLogs.length - 1].message;
history.push(`app/${appId}`, 'new');
trackGoal(trackingGoals.createAppGithub, 0);
};
const handleOpen = () => {
const newWindow = window.open(
`https://github.com/apps/${config.githubAppName}/installations/new`,
'Install App',
'resizable=1, scrollbars=1, fullscreen=0, height=1000, width=1020,top=' +
window.screen.width +
', left=' +
window.screen.width +
', toolbar=0, menubar=0, status=0'
);
const timer = setInterval(async () => {
if (newWindow && newWindow.closed) {
setIsNewWindowClosed(true);
clearInterval(timer);
}
}, 100);
};
useEffect(() => {
if (!installationLoading && installationData && isNewWindowClosed) {
getRepos({
variables: {
installationId: installationData.githubInstallationId.id,
},
});
setIsNewWindowClosed(false);
}
}, [
installationData,
installationLoading,
isNewWindowClosed,
setIsNewWindowClosed,
getRepos,
]);
useEffect(() => {
if (
!installationLoading &&
installationData &&
!reposLoading &&
reposData &&
selectedRepo
) {
getBranches({
variables: {
installationId: installationData.githubInstallationId.id,
repositoryName: selectedRepo.name,
},
});
}
}, [
installationData,
installationLoading,
reposData,
reposLoading,
getBranches,
selectedRepo?.name,
selectedRepo,
]);
const handleChangeRepo = (active: RepoOption) => {
setSelectedRepo(active.value);
setSelectedBranch('');
if (installationData) {
formik.setValues({
name: active.value.name,
installationId: installationData?.githubInstallationId.id,
repo: {
fullName: active.value.fullName,
name: active.value.name,
id: active.value.id,
},
gitBranch: '',
});
}
};
const handleChangeBranch = (active: BranchOption) => {
setSelectedBranch(active.value.name);
formik.setFieldValue('gitBranch', active.value.name);
};
const repoOptions: RepoOption[] = [];
if (reposData && !reposLoading) {
reposData?.repositories.map((r) =>
repoOptions.push({ value: r, label: r.fullName })
);
}
let branchOptions: BranchOption[] = [];
if (branchesData && !branchesLoading) {
branchesData.branches.map((b) =>
branchOptions.push({ value: b, label: b.name })
);
}
useEffect(() => {
if (installationData && !installationLoading) {
getRepos({
variables: {
installationId: installationData?.githubInstallationId.id,
},
});
}
}, [installationLoading, getRepos, installationData]);
useEffect(() => {
if (selectedRepo && installationData) {
getBranches({
variables: {
installationId: installationData?.githubInstallationId.id,
repositoryName: selectedRepo.name,
},
});
}
}, [selectedRepo, getBranches, installationData]);
// Effect for app creation
useEffect(() => {
isAppCreationSuccess === AppCreationStatus.FAILURE && !isToastShown
? toast.error('Failed to create an app') && setIsToastShown(true)
: isAppCreationSuccess === AppCreationStatus.SUCCESS &&
!isToastShown &&
toast.success('App created successfully') &&
setIsToastShown(true);
}, [isToastShown, isAppCreationSuccess, toast]);
return (
<>
<HeaderContainer>
<Header />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
{isTerminalVisible ? (
<>
<p className="mb-2 ">
Creating <b>{formik.values.name}</b> app from{' '}
<b>{formik.values.repo.name}</b>
</p>
<p className="text-gray-500 mb-2">
Creating app usually takes a couple of minutes. Breathe in,
breathe out, logs are about to appear below:
</p>
<Terminal className={'w-6/6'}>
{arrayOfCreateAppLogs.map((log) => (
<p
key={arrayOfCreateAppLogs.indexOf(log)}
className={'text-s leading-5'}
>
{log.message?.replaceAll('[1G', '')}
</p>
))}
</Terminal>
{!!isAppCreationSuccess &&
isAppCreationSuccess === AppCreationStatus.SUCCESS ? (
<div className="mt-12 flex justify-end">
<Button
onClick={() => handleNext()}
color="grey"
iconEnd={<FiArrowRight size={20} />}
>
Next
</Button>
</div>
) : !!isAppCreationSuccess &&
isAppCreationSuccess === AppCreationStatus.FAILURE ? (
<div className="mt-12 flex justify-start">
<Button
onClick={() => {
setIsTerminalVisible(false);
formik.resetForm();
}}
color="grey"
iconEnd={<FiArrowLeft size={20} />}
>
Back
</Button>
</div>
) : null}
</>
) : (
<>
<Heading as="h2" size="md">
Create a new GitHub application
</Heading>
{installationData &&
!installationLoading &&
reposData &&
!reposLoading ? (
<>
<Text color="gray.400">
When you push to Git, your application will be redeployed
automatically.
</Text>
<Grid
templateColumns={{
sm: 'repeat(1, 1fr)',
md: 'repeat(3, 1fr)',
}}
>
<GridItem colSpan={2}>
<Flex alignItems="center" mt="12">
<Avatar
size="sm"
name={user?.userName}
src={user?.avatarUrl}
/>
<Text ml="2" fontWeight="bold">
{user?.userName}
</Text>
</Flex>
<form onSubmit={formik.handleSubmit}>
<Box mt="8">
<FormLabel>Repository</FormLabel>
<Select
placeholder="Select repository"
isSearchable={false}
onChange={handleChangeRepo}
options={repoOptions}
/>
</Box>
<Text mt="1" color="gray.400" fontSize="sm">
Can't see your repo in the list?{' '}
<Link
onClick={() => setIsProceedModalOpen(true)}
textDecoration="underline"
>
Configure the GitHub app.
</Link>
</Text>
<Box mt="8">
<FormLabel>Branch to deploy</FormLabel>
<Select
placeholder="Select branch"
isSearchable={false}
disabled={
!branchesData ||
branchesLoading ||
reposLoading ||
!reposData
}
onChange={handleChangeBranch}
options={branchOptions}
/>
</Box>
<Box mt="8" display="flex" justifyContent="flex-end">
<Button
type="submit"
color="grey"
disabled={!selectedBranch || !selectedRepo}
isLoading={loading}
>
Create
</Button>
</Box>
</form>
</GridItem>
</Grid>
</>
) : !reposLoading && !installationLoading && !reposData ? (
<>
<Alert mb="4" mt="4" w="65%" status="info">
<AlertIcon />
<Box flex="1">
<AlertTitle>Set up repository permissions</AlertTitle>
<AlertDescription display="block">
First you will need to set up permissions for repositories
that you would like to use with Ledokku. Once that's done,
it's time to choose repo and branch that you would like to
create app from and off we go.
</AlertDescription>
</Box>
</Alert>
<Button
color="grey"
onClick={() => setIsProceedModalOpen(true)}
>
Set up permissions
</Button>
</>
) : (
<Spinner />
)}
</>
)}
<Modal
isOpen={isProceedModalOpen}
onClose={() => setIsProceedModalOpen(false)}
isCentered
>
<ModalOverlay />
<ModalContent>
<ModalHeader>Github setup info</ModalHeader>
<ModalCloseButton />
<ModalBody>
New window is about to open. After you are done selecting github
repos, close the window and refresh page.
</ModalBody>
<ModalFooter>
<Button
color="grey"
variant="outline"
className="mr-3"
onClick={() => setIsProceedModalOpen(false)}
>
Cancel
</Button>
<Button
color="grey"
onClick={() => {
handleOpen();
setIsProceedModalOpen(false);
}}
>
Proceed
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Container>
</>
);
}
Example #28
Source File: logs.tsx From ledokku with MIT License | 4 votes |
Logs = () => {
const { id: appId } = useParams<{ id: string }>();
const { data, loading /* error */ } = useAppByIdQuery({
variables: {
appId,
},
});
const {
data: appLogsData,
loading: appLogsLoading,
error: appLogsError,
} = useAppLogsQuery({
variables: {
appId,
},
// we fetch status every 2 min 30 sec
pollInterval: 15000,
});
const memoizedLogsHtml = useMemo(() => {
if (!appLogsData?.appLogs.logs) {
return null;
}
const data = appLogsData.appLogs.logs.map((log) => {
const ansiIUp = new AnsiUp();
const html = ansiIUp.ansi_to_html(log);
return html;
});
return data;
}, [appLogsData]);
if (!data) {
return null;
}
// // TODO display error
if (loading) {
// TODO nice loading
return <p>Loading...</p>;
}
const { app } = data;
if (!app) {
// TODO nice 404
return <p>App not found.</p>;
}
return (
<div>
<HeaderContainer>
<Header />
<AppHeaderInfo app={app} />
<AppHeaderTabNav app={app} />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<Heading as="h2" size="md" py={5}>
Logs for {app.name} app:
</Heading>
{appLogsLoading ? (
<Text fontSize="sm" color="gray.400">
Loading...
</Text>
) : null}
{appLogsError ? (
<Alert
status="error"
variant="top-accent"
borderBottomRadius="base"
boxShadow="md"
>
<AlertDescription>{appLogsError.message}</AlertDescription>
</Alert>
) : null}
{!appLogsLoading && !appLogsError && !appLogsData ? (
<Alert
status="info"
variant="top-accent"
borderBottomRadius="base"
boxShadow="md"
>
<AlertDescription>
There are no logs for {app.name}.
<br />
App is not deployed or still deploying.
</AlertDescription>
</Alert>
) : null}
{memoizedLogsHtml ? (
<Terminal mb="8">
{memoizedLogsHtml.map((html, index) => (
<p key={index} dangerouslySetInnerHTML={{ __html: html }}></p>
))}
</Terminal>
) : null}
</Container>
</div>
);
}
Example #29
Source File: mint-success.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
MintSuccess = () => {
const { account } = useWeb3React();
const [hasTransfered, setHasTransfered] = useState(false);
const hustler = useHustler();
const controller = useController();
const [gangstaParty, setGangstaParty] = useState(false);
const image = gangstaParty ? 'bridge_with_hustlers.png' : 'bridge_no_hustlers.png';
const listener = useCallback(() => {
setHasTransfered(true);
}, []);
// TransferSingle(operator, from, to, id, value)
const filter = hustler.filters.TransferSingle(controller.address, controller.address, account);
useEffect(() => {
hustler.on(filter, listener);
return () => {
hustler.off(filter, listener);
};
}, [hustler, listener, filter]);
return (
<>
<Head title="Bridging Hustler to Optimism" />
<ScreenSaver image={image}>
{gangstaParty && (
<>
<PlugContainer>
<Image src="/images/masthead/ogs.svg" alt="DOPE OGS" />
<ul>
{PLUGS.sort(() => Math.random() - 0.5).map((plug, index) => {
return (
<li key={`plug-${index}`}>
<a href={plug.link} target={plug.name}>
{plug.prefix ? <div className="prefix">"{plug.prefix}"</div> : ''}
{plug.name}
{plug.suffix ? <div className="suffix">"{plug.suffix}"</div> : ''}
</a>
</li>
);
})}
</ul>
</PlugContainer>
<WebAmpPlayer />
</>
)}
{!gangstaParty && (
<>
<MastheadContainer>
<Image src={randomMast()} alt="Dope." />
</MastheadContainer>
<AlertContainer>
<Alert status="success">
<div>
{hasTransfered ? (
<p>Your Hustler has made its way to the Optimism network!</p>
) : (
<p>
Your Hustler is making their way to the Optimism network.
<br />
<br />
It could take up to 15 minutes for that to happen. In the meantime, lets get
it crackin homie…
</p>
)}
<Button
onClick={() => {
setGangstaParty(true);
}}
>
Gangsta Party
</Button>
</div>
</Alert>
</AlertContainer>
</>
)}
</ScreenSaver>
<HStack
m={4}
gridGap={1}
bottom={0}
right={0}
position="absolute"
width="100%"
justifyContent="end"
>
<Link href="/inventory" passHref>
<a target="your-squad" rel="noreferrer">
<Button>Peep Your Squad</Button>
</a>
</Link>
<Link href="/dope" passHref>
<Button variant="primary">Initiate Another Hustler</Button>
</Link>
</HStack>
</>
);
}