Fix: Format entire frontend properly

This commit is contained in:
Daniel Hougaard
2024-03-18 16:00:03 +01:00
parent 1ede551c3e
commit 9002e6cb33
230 changed files with 2752 additions and 2941 deletions

View File

@@ -1,7 +1,7 @@
/* eslint-disable */
import { PostHog } from 'posthog-js';
import { initPostHog } from '@app/components/analytics/posthog';
import { ENV } from '@app/components/utilities/config';
import { PostHog } from "posthog-js";
import { initPostHog } from "@app/components/analytics/posthog";
import { ENV } from "@app/components/utilities/config";
declare let TELEMETRY_CAPTURING_ENABLED: any;
@@ -13,23 +13,23 @@ class Capturer {
}
capture(item: string) {
if (ENV === 'production' && TELEMETRY_CAPTURING_ENABLED === "true") {
if (ENV === "production" && TELEMETRY_CAPTURING_ENABLED === "true") {
try {
this.api.capture(item);
} catch (error) {
console.error('PostHog', error);
console.error("PostHog", error);
}
}
}
identify(id: string, email?: string) {
if (ENV === 'production' && TELEMETRY_CAPTURING_ENABLED === "true") {
if (ENV === "production" && TELEMETRY_CAPTURING_ENABLED === "true") {
try {
this.api.identify(id, {
email: email
});
} catch (error) {
console.error('PostHog', error);
console.error("PostHog", error);
}
}
}

View File

@@ -14,7 +14,7 @@ type Story = StoryObj<typeof Accordion>;
export const Basic: Story = {
render: (args) => (
<div className="flex justify-center w-full">
<div className="flex w-full justify-center">
<Accordion {...args}>
<AccordionItem value="section-1">
<AccordionTrigger>Section 1</AccordionTrigger>

View File

@@ -8,7 +8,7 @@ export const AccordionItem = forwardRef<HTMLDivElement, AccordionPrimitive.Accor
({ children, className, ...props }, forwardedRef) => (
<AccordionPrimitive.Item
className={twMerge(
"mt-px overflow-hidden first:mt-0 data-[state=open]:border-l data-[state=open]:border-primary transition-all border-transparent",
"mt-px overflow-hidden border-transparent transition-all first:mt-0 data-[state=open]:border-l data-[state=open]:border-primary",
className
)}
{...props}
@@ -27,7 +27,7 @@ export const AccordionTrigger = forwardRef<
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
className={twMerge(
"py-2 px-4 group data-[state=open]:text-primary h-11 hover:text-primary flex flex-1 outline-none items-center justify-between ",
"group flex h-11 flex-1 items-center justify-between py-2 px-4 outline-none hover:text-primary data-[state=open]:text-primary ",
className
)}
{...props}
@@ -36,7 +36,7 @@ export const AccordionTrigger = forwardRef<
{children}
<FontAwesomeIcon
icon={faChevronDown}
className="ease-[cubic-bezier(0.87,_0,_0.13,_1)] transition-transform duration-300 group-data-[state=open]:rotate-180 text-sm"
className="text-sm transition-transform duration-300 ease-[cubic-bezier(0.87,_0,_0.13,_1)] group-data-[state=open]:rotate-180"
aria-hidden
/>
</AccordionPrimitive.Trigger>
@@ -51,13 +51,13 @@ export const AccordionContent = forwardRef<
>(({ children, className, ...props }, forwardedRef) => (
<AccordionPrimitive.Content
className={twMerge(
"data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp overflow-hidden",
"overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp",
className
)}
{...props}
ref={forwardedRef}
>
<div className="text-sm py-2 px-4">{children}</div>
<div className="py-2 px-4 text-sm">{children}</div>
</AccordionPrimitive.Content>
));

View File

@@ -1 +1 @@
export { Accordion, AccordionContent, AccordionItem,AccordionTrigger } from "./Accordion";
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "./Accordion";

View File

@@ -10,7 +10,7 @@ export type CardTitleProps = {
export const CardTitle = ({ children, className, subTitle }: CardTitleProps) => (
<div
className={twMerge(
"px-6 py-4 mb-5 font-sans text-lg font-normal border-b border-mineshaft-600 break-words",
"mb-5 break-words border-b border-mineshaft-600 px-6 py-4 font-sans text-lg font-normal",
className
)}
>

View File

@@ -30,7 +30,7 @@ export const Checkbox = ({
<div className="flex items-center font-inter text-bunker-300">
<CheckboxPrimitive.Root
className={twMerge(
"flex items-center flex-shrink-0 justify-center w-4 h-4 transition-all rounded shadow border border-mineshaft-400 hover:bg-mineshaft-500 bg-mineshaft-600",
"flex h-4 w-4 flex-shrink-0 items-center justify-center rounded border border-mineshaft-400 bg-mineshaft-600 shadow transition-all hover:bg-mineshaft-500",
isDisabled && "bg-bunker-400 hover:bg-bunker-400",
isChecked && "bg-primary hover:bg-primary",
Boolean(children) && "mr-3",
@@ -46,7 +46,7 @@ export const Checkbox = ({
<FontAwesomeIcon icon={faCheck} size="sm" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
<label className="text-sm whitespace-nowrap truncate" htmlFor={id}>
<label className="truncate whitespace-nowrap text-sm" htmlFor={id}>
{children}
{isRequired && <span className="pl-1 text-red">*</span>}
</label>

View File

@@ -58,7 +58,7 @@ export const DeleteActionModal = ({
title={title}
subTitle={subTitle}
footerContent={
<div className="flex items-center mx-2">
<div className="mx-2 flex items-center">
<Button
className="mr-4"
colorSchema="danger"
@@ -91,7 +91,11 @@ export const DeleteActionModal = ({
}
className="mb-0"
>
<Input value={inputData} onChange={(e) => setInputData(e.target.value)} placeholder="Type to delete..." />
<Input
value={inputData}
onChange={(e) => setInputData(e.target.value)}
placeholder="Type to delete..."
/>
</FormControl>
</form>
</ModalContent>

View File

@@ -45,7 +45,7 @@ export const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
ref={forwardedRef}
className={twMerge(drawerContentVariation({ direction, className }))}
>
<Card isRounded={false} className="h-full w-full dark">
<Card isRounded={false} className="dark h-full w-full">
{title && (
<CardTitle subTitle={subTitle} className="px-4">
{title}

View File

@@ -1 +1 @@
export { Drawer, DrawerClose,DrawerContent, DrawerTrigger } from "./Drawer";
export { Drawer, DrawerClose, DrawerContent, DrawerTrigger } from "./Drawer";

View File

@@ -25,7 +25,7 @@ type Story = StoryObj<typeof DropdownMenuContent>;
export const Basic: Story = {
render: (args) => (
<div className="flex justify-center w-full">
<div className="flex w-full justify-center">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton ariaLabel="add">
@@ -43,7 +43,7 @@ export const Basic: Story = {
export const Icons: Story = {
render: (args) => (
<div className="flex justify-center w-full">
<div className="flex w-full justify-center">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton ariaLabel="add">
@@ -65,7 +65,7 @@ export const Icons: Story = {
export const WithDivider: Story = {
render: (args) => (
<div className="flex justify-center w-full">
<div className="flex w-full justify-center">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton ariaLabel="add">
@@ -86,7 +86,7 @@ export const WithDivider: Story = {
export const Group: Story = {
render: (args) => (
<div className="flex justify-center w-full">
<div className="flex w-full justify-center">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton ariaLabel="add">

View File

@@ -24,7 +24,7 @@ export const DropdownMenuContent = forwardRef<HTMLDivElement, DropdownMenuConten
{...props}
ref={forwardedRef}
className={twMerge(
"min-w-[220px] z-30 bg-mineshaft-900 border border-mineshaft-600 will-change-auto text-bunker-300 rounded-md shadow data-[side=top]:animate-slideDownAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade",
"z-30 min-w-[220px] rounded-md border border-mineshaft-600 bg-mineshaft-900 text-bunker-300 shadow will-change-auto data-[side=top]:animate-slideDownAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade",
className
)}
>
@@ -48,7 +48,7 @@ export const DropdownSubMenuContent = forwardRef<HTMLDivElement, DropdownSubMenu
{...props}
ref={forwardedRef}
className={twMerge(
"min-w-[220px] z-30 bg-mineshaft-900 border border-mineshaft-600 will-change-auto text-bunker-300 rounded-md shadow data-[side=top]:animate-slideDownAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade",
"z-30 min-w-[220px] rounded-md border border-mineshaft-600 bg-mineshaft-900 text-bunker-300 shadow will-change-auto data-[side=top]:animate-slideDownAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade",
className
)}
>
@@ -66,7 +66,7 @@ export type DropdownLabelProps = DropdownMenuPrimitive.MenuLabelProps;
export const DropdownMenuLabel = ({ className, ...props }: DropdownLabelProps) => (
<DropdownMenuPrimitive.Label
{...props}
className={twMerge("text-xs text-bunker-400 px-4 pt-2 pb-1", className)}
className={twMerge("px-4 pt-2 pb-1 text-xs text-bunker-400", className)}
/>
);
@@ -91,14 +91,14 @@ export const DropdownMenuItem = <T extends ElementType = "button">({
<DropdownMenuPrimitive.Item
{...props}
className={twMerge(
"text-xs text-mineshaft-200 block font-inter px-4 py-2 data-[highlighted]:bg-mineshaft-700 rounded-sm outline-none cursor-pointer",
"block cursor-pointer rounded-sm px-4 py-2 font-inter text-xs text-mineshaft-200 outline-none data-[highlighted]:bg-mineshaft-700",
className
)}
>
<Item type="button" role="menuitem" className="flex w-full items-center" ref={inputRef}>
{icon && iconPos === "left" && <span className="flex items-center mr-2">{icon}</span>}
{icon && iconPos === "left" && <span className="mr-2 flex items-center">{icon}</span>}
<span className="flex-grow text-left">{children}</span>
{icon && iconPos === "right" && <span className="flex items-center ml-2">{icon}</span>}
{icon && iconPos === "right" && <span className="ml-2 flex items-center">{icon}</span>}
</Item>
</DropdownMenuPrimitive.Item>
);
@@ -124,14 +124,14 @@ export const DropdownSubMenuTrigger = <T extends ElementType = "button">({
<DropdownMenuPrimitive.SubTrigger
{...props}
className={twMerge(
"text-xs text-mineshaft-200 block font-inter px-4 py-2 data-[highlighted]:bg-mineshaft-700 rounded-sm outline-none cursor-pointer",
"block cursor-pointer rounded-sm px-4 py-2 font-inter text-xs text-mineshaft-200 outline-none data-[highlighted]:bg-mineshaft-700",
className
)}
>
<Item type="button" role="menuitem" className="flex w-full items-center" ref={inputRef}>
{icon && iconPos === "left" && <span className="flex items-center mr-2">{icon}</span>}
{icon && iconPos === "left" && <span className="mr-2 flex items-center">{icon}</span>}
<span className="flex-grow text-left">{children}</span>
{icon && iconPos === "right" && <span className="flex items-center ml-2">{icon}</span>}
{icon && iconPos === "right" && <span className="ml-2 flex items-center">{icon}</span>}
</Item>
</DropdownMenuPrimitive.SubTrigger>
);
@@ -143,7 +143,7 @@ export const DropdownMenuGroup = forwardRef<HTMLDivElement, DropdownMenuGroupPro
({ ...props }, ref) => (
<DropdownMenuPrimitive.Group
{...props}
className={twMerge("text-xs py-2 pl-3", props.className)}
className={twMerge("py-2 pl-3 text-xs", props.className)}
ref={ref}
/>
)
@@ -159,7 +159,7 @@ export const DropdownMenuSeparator = forwardRef<
<DropdownMenuPrimitive.Separator
ref={ref}
{...props}
className={twMerge("h-[1px] bg-gray-700 m-1", className)}
className={twMerge("m-1 h-[1px] bg-gray-700", className)}
/>
));

View File

@@ -10,9 +10,10 @@ export const EmailServiceSetupModal = ({ isOpen, onOpenChange }: Props): JSX.Ele
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
<ModalContent title="Email service not configured">
<p className="mb-4 text-bunker-300">
The administrators of this Infisical instance have not yet set up an email service provider required to perform this action
The administrators of this Infisical instance have not yet set up an email service provider
required to perform this action
</p>
<a href="https://infisical.com/docs/self-hosting/configuration/email">
<Button className="mr-4">Learn more</Button>
</a>

View File

@@ -23,7 +23,7 @@ export const FormLabel = ({ id, label, isRequired, icon, className }: FormLabelP
{label}
{isRequired && <span className="ml-1 text-red">*</span>}
{icon && (
<span className="ml-2 text-mineshaft-300 hover:text-mineshaft-200 cursor-default">
<span className="ml-2 cursor-default text-mineshaft-300 hover:text-mineshaft-200">
{icon}
</span>
)}

View File

@@ -10,22 +10,16 @@ type Props = {
export type HoverCardProps = Props;
export const HoverObject = ({
text,
icon,
color
}: Props): JSX.Element => (
export const HoverObject = ({ text, icon, color }: Props): JSX.Element => (
<HoverCard.Root openDelay={50}>
<HoverCard.Trigger asChild>
<a
className="ImageTrigger z-20"
>
<a className="ImageTrigger z-20">
<FontAwesomeIcon icon={icon} className={`text-${color}`} />
</a>
</HoverCard.Trigger>
<HoverCard.Portal>
<HoverCard.Content className="HoverCardContent z-[300]" sideOffset={5}>
<div className='bg-bunker-700 border border-mineshaft-600 p-2 rounded-md drop-shadow-xl text-bunker-300'>
<div className="rounded-md border border-mineshaft-600 bg-bunker-700 p-2 text-bunker-300 drop-shadow-xl">
<div style={{ display: "flex", flexDirection: "column", gap: 15 }}>
<div>
<div className="Text bold">{text}</div>

View File

@@ -1 +1 @@
export { HoverCard,HoverCardContent, HoverCardTrigger } from "./HoverCardv2";
export { HoverCard, HoverCardContent, HoverCardTrigger } from "./HoverCardv2";

View File

@@ -29,7 +29,7 @@ export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
<Card
isRounded
className={twMerge(
"fixed top-1/2 left-1/2 z-30 dark:[color-scheme:dark] max-h-screen thin-scrollbar max-w-xl -translate-y-2/4 -translate-x-2/4 animate-popIn border border-mineshaft-600 drop-shadow-2xl",
"thin-scrollbar fixed top-1/2 left-1/2 z-30 max-h-screen max-w-xl -translate-y-2/4 -translate-x-2/4 animate-popIn border border-mineshaft-600 drop-shadow-2xl dark:[color-scheme:dark]",
className
)}
>

View File

@@ -44,7 +44,7 @@ export const Pagination = ({
return (
<div
className={twMerge(
"flex items-center justify-end text-white w-full py-3 px-4 bg-mineshaft-800",
"flex w-full items-center justify-end bg-mineshaft-800 py-3 px-4 text-white",
className
)}
>

View File

@@ -3,39 +3,42 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as Popover from "@radix-ui/react-popover";
type Props = {
children: any;
text: string;
onChangeHandler: (value: string, id: string) => void;
children: any;
text: string;
onChangeHandler: (value: string, id: string) => void;
id: string;
};
export type PopoverProps = Props;
export const PopoverObject = ({children, text, onChangeHandler, id}: Props) => (
export const PopoverObject = ({ children, text, onChangeHandler, id }: Props) => (
<Popover.Root>
<Popover.Trigger asChild className='data-[state=open]:outline data-[state=open]:outline-primary data-[state=closed]:hover:outline data-[state=closed]:hover:outline-mineshaft-400'>
<Popover.Trigger
asChild
className="data-[state=open]:outline data-[state=open]:outline-primary data-[state=closed]:hover:outline data-[state=closed]:hover:outline-mineshaft-400"
>
{children}
</Popover.Trigger>
<Popover.Portal>
<Popover.Content
className="rounded z-[100] p-3 w-[460px] min-h-fit border border-chicago-700 bg-mineshaft-600 shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2)] focus:shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2),0_0_0_2px_theme(colors.violet7)] will-change-[transform,opacity] data-[state=open]:data-[side=top]:animate-slideDownAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade"
className="z-[100] min-h-fit w-[460px] rounded border border-chicago-700 bg-mineshaft-600 p-3 shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2)] will-change-[transform,opacity] focus:shadow-[0_10px_38px_-10px_hsla(206,22%,7%,.35),0_10px_20px_-15px_hsla(206,22%,7%,.2),0_0_0_2px_theme(colors.violet7)] data-[state=open]:data-[side=top]:animate-slideDownAndFade data-[state=open]:data-[side=right]:animate-slideLeftAndFade data-[state=open]:data-[side=bottom]:animate-slideUpAndFade data-[state=open]:data-[side=left]:animate-slideRightAndFade"
sideOffset={5}
hideWhenDetached
side="left"
>
<div className="flex flex-col pt-2 dark">
<p className="text-bunker-200 text-[15px] leading-[0px] font-medium mb-5">Comment</p>
<div className="dark flex flex-col pt-2">
<p className="mb-5 text-[15px] font-medium leading-[0px] text-bunker-200">Comment</p>
<textarea
onChange={(e) => onChangeHandler(e.target.value, id)}
// type={type}
value={text}
className='z-10 dark:[color-scheme:dark] peer h-[20rem] ph-no-capture bg-bunker-600 border border-mineshaft-500 rounded-md py-2.5 caret-bunker-200 text-sm px-2 w-full outline-none text-bunker-300 focus:text-bunker-100 placeholder:text-bunker-400 placeholder:focus:text-transparent placeholder duration-200'
className="ph-no-capture placeholder peer z-10 h-[20rem] w-full rounded-md border border-mineshaft-500 bg-bunker-600 py-2.5 px-2 text-sm text-bunker-300 caret-bunker-200 outline-none duration-200 placeholder:text-bunker-400 focus:text-bunker-100 placeholder:focus:text-transparent dark:[color-scheme:dark]"
spellCheck="false"
placeholder='–'
placeholder="–"
/>
</div>
<Popover.Close
className="rounded-full h-[25px] w-[25px] inline-flex items-center justify-center text-bunker-300 hover:text-white absolute top-[5px] right-[5px] hover:bg-violet4 focus:shadow-[0_0_0_2px] focus:shadow-violet7 outline-none cursor-default"
className="hover:bg-violet4 focus:shadow-violet7 absolute top-[5px] right-[5px] inline-flex h-[25px] w-[25px] cursor-default items-center justify-center rounded-full text-bunker-300 outline-none hover:text-white focus:shadow-[0_0_0_2px]"
aria-label="Close"
>
<FontAwesomeIcon icon={faXmark} />

View File

@@ -1 +1 @@
export { Popover,PopoverContent, PopoverTrigger } from "./Popoverv2";
export { Popover, PopoverContent, PopoverTrigger } from "./Popoverv2";

View File

@@ -6,35 +6,35 @@ export type RadioGroupProps = RadioGroupPrimitive.RadioGroupProps;
// Note this component is not customizable (Heroku integration and potentially other pages depend on it)
export const RadioGroup = ({ className, children, ...props }: RadioGroupProps) => (
<RadioGroupPrimitive.Root
className={twMerge("flex flex-row gap-5 px-6 mb-6", className)}
<RadioGroupPrimitive.Root
className={twMerge("mb-6 flex flex-row gap-5 px-6", className)}
defaultValue="App"
aria-label="View density"
{...props}
>
>
<div className="flex items-center">
<RadioGroupPrimitive.Item
className="bg-bunker-400/20 w-[20px] h-[20px] rounded-full hover:bg-bunker-400/40 border border-bunker-400/60 duration-200 outline-none cursor-default"
className="h-[20px] w-[20px] cursor-default rounded-full border border-bunker-400/60 bg-bunker-400/20 outline-none duration-200 hover:bg-bunker-400/40"
value="App"
id="r1"
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center w-full h-full relative after:content-[''] after:block after:w-[11px] after:h-[11px] after:rounded-[50%] after:bg-primary" />
<RadioGroupPrimitive.Indicator className="relative flex h-full w-full items-center justify-center after:block after:h-[11px] after:w-[11px] after:rounded-[50%] after:bg-primary after:content-['']" />
</RadioGroupPrimitive.Item>
<label className="text-bunker-200 text-sm leading-none pl-2" htmlFor="r1">
<label className="pl-2 text-sm leading-none text-bunker-200" htmlFor="r1">
App
</label>
</div>
<div className="flex items-center">
<RadioGroupPrimitive.Item
className="bg-bunker-400/20 w-[22px] h-[22px] rounded-full hover:bg-bunker-400/40 border border-bunker-400/60 duration-200 outline-none cursor-default"
className="h-[22px] w-[22px] cursor-default rounded-full border border-bunker-400/60 bg-bunker-400/20 outline-none duration-200 hover:bg-bunker-400/40"
value="Pipeline"
id="r2"
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center w-full h-full relative after:content-[''] after:block after:w-[13px] after:h-[13px] after:rounded-[50%] after:bg-primary" />
<RadioGroupPrimitive.Indicator className="relative flex h-full w-full items-center justify-center after:block after:h-[13px] after:w-[13px] after:rounded-[50%] after:bg-primary after:content-['']" />
</RadioGroupPrimitive.Item>
<label className="text-bunker-200 text-sm leading-none pl-2" htmlFor="r2">
<label className="pl-2 text-sm leading-none text-bunker-200" htmlFor="r2">
Pipeline
</label>
</div>
</RadioGroupPrimitive.Root>
);
);

View File

@@ -1,6 +1,6 @@
import { forwardRef, ReactNode } from "react";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { faCaretDown, faCaretUp,faCheck } from "@fortawesome/free-solid-svg-icons";
import { faCaretDown, faCaretUp, faCheck } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as SelectPrimitive from "@radix-ui/react-select";
import { twMerge } from "tailwind-merge";
@@ -57,7 +57,7 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
<SelectPrimitive.Portal>
<SelectPrimitive.Content
className={twMerge(
"relative top-1 z-[100] overflow-hidden rounded-md bg-mineshaft-900 border border-mineshaft-600 font-inter text-bunker-100 shadow-md",
"relative top-1 z-[100] overflow-hidden rounded-md border border-mineshaft-600 bg-mineshaft-900 font-inter text-bunker-100 shadow-md",
dropdownContainerClassName
)}
position={position}

View File

@@ -20,7 +20,7 @@ export const Spinner = ({ className, size = "md" }: Props): JSX.Element => {
<svg
aria-hidden="true"
className={twMerge(
"text-gray-200 animate-spin dark:text-gray-600 fill-primary m-1",
"m-1 animate-spin fill-primary text-gray-200 dark:text-gray-600",
sizeChart[size],
className
)}

View File

@@ -14,7 +14,7 @@ export const Stepper = ({ activeStep, children, direction, className }: StepperP
return (
<div
className={twMerge(
"flex items-center w-full space-x-3 p-2 border border-bunker-300/30 rounded-md",
"flex w-full items-center space-x-3 rounded-md border border-bunker-300/30 p-2",
className
)}
>
@@ -25,15 +25,15 @@ export const Stepper = ({ activeStep, children, direction, className }: StepperP
return (
<div
className={twMerge(
"flex items-center space-x-3 flex-shrink-0",
"flex flex-shrink-0 items-center space-x-3",
isNotLast && "flex-grow"
)}
>
<div className="flex items-center space-x-2 flex-shrink-0">
<div className="flex flex-shrink-0 items-center space-x-2">
<div
className={twMerge(
"w-7 h-7 flex items-center justify-center font-medium text-mineshaft-800 text-sm rounded-full transition-all",
isCompleted ? "bg-primary" : "border text-bunker-300 border-primary/30",
"flex h-7 w-7 items-center justify-center rounded-full text-sm font-medium text-mineshaft-800 transition-all",
isCompleted ? "bg-primary" : "border border-primary/30 text-bunker-300",
isActive && "bg-primary text-mineshaft-800"
)}
>
@@ -71,7 +71,7 @@ export type StepProps = {
export const Step = ({ title, description }: StepProps) => {
return (
<div className="flex flex-col text-gray-300">
<div className="font-medium text-sm">{title}</div>
<div className="text-sm font-medium">{title}</div>
{description && <div className="text-xs">{description}</div>}
</div>
);

View File

@@ -1,2 +1,2 @@
export type { StepperProps,StepProps } from "./Stepper";
export { Step,Stepper } from "./Stepper";
export type { StepperProps, StepProps } from "./Stepper";
export { Step, Stepper } from "./Stepper";

View File

@@ -6,5 +6,6 @@ export type {
TFootProps,
THeadProps,
ThProps,
TrProps} from "./Table";
export { Table, TableContainer, TableSkeleton, TBody, Td, TFoot,Th, THead, Tr } from "./Table";
TrProps
} from "./Table";
export { Table, TableContainer, TableSkeleton, TBody, Td, TFoot, Th, THead, Tr } from "./Table";

View File

@@ -13,7 +13,7 @@ export type TabListProps = TabsPrimitive.TabsListProps;
export const TabList = ({ className, children, ...props }: TabListProps) => (
<TabsPrimitive.List
className={twMerge("flex-shrink-0 flex border-b-2 border-mineshaft-800", className)}
className={twMerge("flex flex-shrink-0 border-b-2 border-mineshaft-800", className)}
{...props}
>
{children}
@@ -25,7 +25,7 @@ export type TabProps = TabsPrimitive.TabsTriggerProps;
export const Tab = ({ className, children, ...props }: TabProps) => (
<TabsPrimitive.Trigger
className={twMerge(
"px-3 h-10 font-medium text-sm flex items-center justify-center select-none first:rounded-tl-md last:rounded-tr-md hover:text-mineshaft-200 text-mineshaft-400 transition-all data-[state=active]:text-white data-[state=active]:border-b data-[state=active]:border-primary",
"flex h-10 select-none items-center justify-center px-3 text-sm font-medium text-mineshaft-400 transition-all first:rounded-tl-md last:rounded-tr-md hover:text-mineshaft-200 data-[state=active]:border-b data-[state=active]:border-primary data-[state=active]:text-white",
className
)}
{...props}
@@ -38,7 +38,7 @@ export type TabPanelProps = TabsPrimitive.TabsContentProps;
export const TabPanel = ({ className, children, ...props }: TabPanelProps) => (
<TabsPrimitive.Content
className={twMerge("outline-none flex-grow py-5 rounded-bl-md rounded-br-md", className)}
className={twMerge("flex-grow rounded-bl-md rounded-br-md py-5 outline-none", className)}
{...props}
>
{children}

View File

@@ -1,2 +1,2 @@
export type { TabListProps,TabPanelProps, TabProps, TabsProps } from "./Tabs";
export type { TabListProps, TabPanelProps, TabProps, TabsProps } from "./Tabs";
export { Tab, TabList, TabPanel, Tabs } from "./Tabs";

View File

@@ -39,7 +39,7 @@ export const AuthProvider = ({ children }: Props): JSX.Element => {
// wait for app to load the auth state
if (isLoading || !isReady) {
return (
<div className="flex items-center justify-center w-screen h-screen bg-bunker-800">
<div className="flex h-screen w-screen items-center justify-center bg-bunker-800">
<img
src="/images/loading/loading.gif"
height={70}

View File

@@ -1,3 +1,3 @@
export { ProjectPermissionProvider, useProjectPermission } from "./ProjectPermissionContext";
export type { ProjectPermissionSet, TProjectPermission } from "./types";
export { ProjectPermissionActions,ProjectPermissionSub } from "./types";
export { ProjectPermissionActions, ProjectPermissionSub } from "./types";

View File

@@ -38,22 +38,31 @@ export const ServerConfigProvider = ({ children }: Props): JSX.Element => {
<div className="relative mx-auto flex h-screen w-full flex-col items-center justify-center space-y-8 bg-bunker-800 px-8 text-mineshaft-50 dark:[color-scheme:dark]">
<Head>
<title>Infisical Maintenance Mode</title>
<link rel='icon' href='/infisical.ico' />
<link rel="icon" href="/infisical.ico" />
</Head>
<img src="/images/maintenance.png" height={175} width={300} alt="maintenance mode" className="w-[40rem]"/>
<img
src="/images/maintenance.png"
height={175}
width={300}
alt="maintenance mode"
className="w-[40rem]"
/>
<p className="mx-8 mb-4 flex justify-center bg-gradient-to-tr from-mineshaft-300 to-white bg-clip-text text-4xl font-bold text-transparent md:mx-16">
Scheduled Maintenance
</p>
<div className="mt-2 text-center text-lg text-bunker-300">
Infisical is undergoing planned maintenance. <br /> No action is required on your end — your applications will continue to fetch secrets.
<br /> If you have questions, please <a
className="text-bunker-300 underline underline-offset-4 decoration-primary-800 hover:decoration-primary-600 hover:text-mineshaft-100 duration-200"
Infisical is undergoing planned maintenance. <br /> No action is required on your end —
your applications will continue to fetch secrets.
<br /> If you have questions, please{" "}
<a
className="text-bunker-300 underline decoration-primary-800 underline-offset-4 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
href="https://infisical.com/slack"
target="_blank"
rel="noopener noreferrer"
>
join our Slack community
</a>.
</a>
.
</div>
</div>
);

View File

@@ -1 +1 @@
export { ServerConfigProvider,useServerConfig } from "./ServerConfigContext";
export { ServerConfigProvider, useServerConfig } from "./ServerConfigContext";

View File

@@ -14,7 +14,7 @@ export {
ProjectPermissionSub,
useProjectPermission
} from "./ProjectPermissionContext";
export { ServerConfigProvider,useServerConfig } from "./ServerConfigContext";
export { ServerConfigProvider, useServerConfig } from "./ServerConfigContext";
export { SubscriptionProvider, useSubscription } from "./SubscriptionContext";
export { UserProvider, useUser } from "./UserContext";
export { useWorkspace, WorkspaceProvider } from "./WorkspaceContext";

View File

@@ -15,7 +15,7 @@ const updateUserProjectPermission = async ({
denials: {
ability: string;
environmentSlug: string;
}[]
}[];
}) =>
SecurityClient.fetchCall(`/api/v1/membership/${membershipId}/deny-permissions`, {
method: "POST",

View File

@@ -4,32 +4,30 @@
* @returns {String} text - how much time has passed since a certain timestamp
*/
function timeSince(date: Date) {
const seconds = Math.floor(
((new Date() as any) - (date as any)) / 1000
) as number;
const seconds = Math.floor(((new Date() as any) - (date as any)) / 1000) as number;
let interval = seconds / 31536000;
if (interval > 1) {
return `${Math.floor(interval) } years ago`;
return `${Math.floor(interval)} years ago`;
}
interval = seconds / 2592000;
if (interval > 1) {
return `${Math.floor(interval) } months ago`;
return `${Math.floor(interval)} months ago`;
}
interval = seconds / 86400;
if (interval > 1) {
return `${Math.floor(interval) } days ago`;
return `${Math.floor(interval)} days ago`;
}
interval = seconds / 3600;
if (interval > 1) {
return `${Math.floor(interval) } hours ago`;
return `${Math.floor(interval)} hours ago`;
}
interval = seconds / 60;
if (interval > 1) {
return `${Math.floor(interval) } minutes ago`;
return `${Math.floor(interval)} minutes ago`;
}
return `${Math.floor(seconds) } seconds ago`;
return `${Math.floor(seconds)} seconds ago`;
}
export default timeSince;

View File

@@ -14,73 +14,71 @@ import { deriveArgonKey } from "@app/components/utilities/cryptography/crypto";
* @param {String} obj.protectedKeyTag
*/
const decryptPrivateKeyHelper = async ({
encryptionVersion,
encryptedPrivateKey,
iv,
tag,
password,
salt,
protectedKey,
protectedKeyIV,
protectedKeyTag,
encryptionVersion,
encryptedPrivateKey,
iv,
tag,
password,
salt,
protectedKey,
protectedKeyIV,
protectedKeyTag
}: {
encryptionVersion: number;
encryptedPrivateKey: string;
iv: string;
tag: string;
password: string;
salt: string;
protectedKey?: string;
protectedKeyIV?: string;
protectedKeyTag?: string;
encryptionVersion: number;
encryptedPrivateKey: string;
iv: string;
tag: string;
password: string;
salt: string;
protectedKey?: string;
protectedKeyIV?: string;
protectedKeyTag?: string;
}) => {
let privateKey;
try {
if (encryptionVersion === 1) {
privateKey = Aes256Gcm.decrypt({
ciphertext: encryptedPrivateKey,
iv,
tag,
secret: password
.slice(0, 32)
.padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), "0")
});
} else if (encryptionVersion === 2 && protectedKey && protectedKeyIV && protectedKeyTag) {
const derivedKey = await deriveArgonKey({
password,
salt,
mem: 65536,
time: 3,
parallelism: 1,
hashLen: 32
});
if (!derivedKey) throw new Error("Failed to generate derived key");
let privateKey;
try {
if (encryptionVersion === 1) {
privateKey = Aes256Gcm.decrypt({
ciphertext: encryptedPrivateKey,
iv,
tag,
secret: password
.slice(0, 32)
.padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), "0")
});
} else if (encryptionVersion === 2 && protectedKey && protectedKeyIV && protectedKeyTag) {
const derivedKey = await deriveArgonKey({
password,
salt,
mem: 65536,
time: 3,
parallelism: 1,
hashLen: 32
});
const key = Aes256Gcm.decrypt({
ciphertext: protectedKey,
iv: protectedKeyIV,
tag: protectedKeyTag,
secret: Buffer.from(derivedKey.hash)
});
// decrypt back the private key
privateKey = Aes256Gcm.decrypt({
ciphertext: encryptedPrivateKey,
iv,
tag,
secret: Buffer.from(key, "hex")
});
} else {
throw new Error("Insufficient details to decrypt private key");
}
} catch (err) {
throw new Error("Failed to decrypt private key");
if (!derivedKey) throw new Error("Failed to generate derived key");
const key = Aes256Gcm.decrypt({
ciphertext: protectedKey,
iv: protectedKeyIV,
tag: protectedKeyTag,
secret: Buffer.from(derivedKey.hash)
});
// decrypt back the private key
privateKey = Aes256Gcm.decrypt({
ciphertext: encryptedPrivateKey,
iv,
tag,
secret: Buffer.from(key, "hex")
});
} else {
throw new Error("Insufficient details to decrypt private key");
}
} catch (err) {
throw new Error("Failed to decrypt private key");
}
return privateKey;
}
return privateKey;
};
export {
decryptPrivateKeyHelper
};
export { decryptPrivateKeyHelper };

View File

@@ -29,13 +29,13 @@ export const withPermission = <T extends {}, J extends TOrgPermission>(
return (
<div
className={twMerge(
"container h-full mx-auto flex justify-center items-center",
"container mx-auto flex h-full items-center justify-center",
containerClassName
)}
>
<div
className={twMerge(
"rounded-md bg-mineshaft-800 text-bunker-300 p-16 flex space-x-12 items-end",
"flex items-end space-x-12 rounded-md bg-mineshaft-800 p-16 text-bunker-300",
className
)}
>
@@ -43,7 +43,7 @@ export const withPermission = <T extends {}, J extends TOrgPermission>(
<FontAwesomeIcon icon={faLock} size="6x" />
</div>
<div>
<div className="text-4xl font-medium mb-2">Access Restricted</div>
<div className="mb-2 text-4xl font-medium">Access Restricted</div>
<div className="text-sm">
Your role has limited permissions, please <br /> contact your admin to gain access
</div>

View File

@@ -1,4 +1 @@
export {
useCreateAPIKeyV2,
useDeleteAPIKeyV2,
useUpdateAPIKeyV2} from "./queries";
export { useCreateAPIKeyV2, useDeleteAPIKeyV2, useUpdateAPIKeyV2 } from "./queries";

View File

@@ -8,14 +8,13 @@ import {
CreateAPIKeyDataV2DTO,
CreateServiceTokenDataV3Res,
DeleteAPIKeyDataV2DTO,
UpdateAPIKeyDataV2DTO} from "./types";
UpdateAPIKeyDataV2DTO
} from "./types";
export const useCreateAPIKeyV2 = () => {
const queryClient = useQueryClient();
return useMutation<CreateServiceTokenDataV3Res, {}, CreateAPIKeyDataV2DTO>({
mutationFn: async ({
name
}) => {
mutationFn: async ({ name }) => {
const { data } = await apiRequest.post("/api/v3/api-key", {
name
});
@@ -31,11 +30,10 @@ export const useCreateAPIKeyV2 = () => {
export const useUpdateAPIKeyV2 = () => {
const queryClient = useQueryClient();
return useMutation<APIKeyDataV2, {}, UpdateAPIKeyDataV2DTO>({
mutationFn: async ({
apiKeyDataId,
name
}) => {
const { data: { apiKeyData } } = await apiRequest.patch(`/api/v3/api-key/${apiKeyDataId}`, {
mutationFn: async ({ apiKeyDataId, name }) => {
const {
data: { apiKeyData }
} = await apiRequest.patch(`/api/v3/api-key/${apiKeyDataId}`, {
name
});
return apiKeyData;
@@ -49,14 +47,14 @@ export const useUpdateAPIKeyV2 = () => {
export const useDeleteAPIKeyV2 = () => {
const queryClient = useQueryClient();
return useMutation<APIKeyDataV2, {}, DeleteAPIKeyDataV2DTO>({
mutationFn: async ({
apiKeyDataId
}) => {
const { data: { apiKeyData } } = await apiRequest.delete(`/api/v3/api-key/${apiKeyDataId}`);
mutationFn: async ({ apiKeyDataId }) => {
const {
data: { apiKeyData }
} = await apiRequest.delete(`/api/v3/api-key/${apiKeyDataId}`);
return apiKeyData;
},
onSuccess: () => {
queryClient.invalidateQueries(userKeys.myAPIKeysV2);
}
});
};
};

View File

@@ -1,57 +1,57 @@
import { EventType, UserAgentType } from "./enums";
export const eventToNameMap: { [K in EventType]: string } = {
[EventType.GET_SECRETS]: "List secrets",
[EventType.GET_SECRET]: "Read secret",
[EventType.CREATE_SECRET]: "Create secret",
[EventType.UPDATE_SECRET]: "Update secret",
[EventType.DELETE_SECRET]: "Delete secret",
[EventType.GET_WORKSPACE_KEY]: "Read project key",
[EventType.AUTHORIZE_INTEGRATION]: "Authorize integration",
[EventType.UNAUTHORIZE_INTEGRATION]: "Unauthorize integration",
[EventType.CREATE_INTEGRATION]: "Create integration",
[EventType.DELETE_INTEGRATION]: "Delete integration",
[EventType.ADD_TRUSTED_IP]: "Add trusted IP",
[EventType.UPDATE_TRUSTED_IP]: "Update trusted IP",
[EventType.DELETE_TRUSTED_IP]: "Delete trusted IP",
[EventType.CREATE_SERVICE_TOKEN]: "Create service token",
[EventType.DELETE_SERVICE_TOKEN]: "Delete service token",
[EventType.CREATE_IDENTITY]: "Create identity",
[EventType.UPDATE_IDENTITY]: "Update identity",
[EventType.DELETE_IDENTITY]: "Delete identity",
[EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH]: "Login via universal auth",
[EventType.ADD_IDENTITY_UNIVERSAL_AUTH]: "Add universal auth",
[EventType.UPDATE_IDENTITY_UNIVERSAL_AUTH]: "Update universal auth",
[EventType.GET_IDENTITY_UNIVERSAL_AUTH]: "Get universal auth",
[EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET]: "Create universal auth client secret",
[EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET]: "Revoke universal auth client secret",
[EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS]: "Get universal auth client secrets",
[EventType.GET_IDENTITY_UNIVERSAL_AUTH]: "Get universal auth",
[EventType.CREATE_ENVIRONMENT]: "Create environment",
[EventType.UPDATE_ENVIRONMENT]: "Update environment",
[EventType.DELETE_ENVIRONMENT]: "Delete environment",
[EventType.ADD_WORKSPACE_MEMBER]: "Add member",
[EventType.REMOVE_WORKSPACE_MEMBER]: "Remove member",
[EventType.CREATE_FOLDER]: "Create folder",
[EventType.UPDATE_FOLDER]: "Update folder",
[EventType.DELETE_FOLDER]: "Delete folder",
[EventType.CREATE_WEBHOOK]: "Create webhook",
[EventType.UPDATE_WEBHOOK_STATUS]: "Update webhook status",
[EventType.DELETE_WEBHOOK]: "Delete webhook",
[EventType.GET_SECRET_IMPORTS]: "List secret imports",
[EventType.CREATE_SECRET_IMPORT]: "Create secret import",
[EventType.UPDATE_SECRET_IMPORT]: "Update secret import",
[EventType.DELETE_SECRET_IMPORT]: "Delete secret import",
[EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS]: "Update denied permissions",
[EventType.UPDATE_USER_WORKSPACE_ROLE]: "Update user role"
[EventType.GET_SECRETS]: "List secrets",
[EventType.GET_SECRET]: "Read secret",
[EventType.CREATE_SECRET]: "Create secret",
[EventType.UPDATE_SECRET]: "Update secret",
[EventType.DELETE_SECRET]: "Delete secret",
[EventType.GET_WORKSPACE_KEY]: "Read project key",
[EventType.AUTHORIZE_INTEGRATION]: "Authorize integration",
[EventType.UNAUTHORIZE_INTEGRATION]: "Unauthorize integration",
[EventType.CREATE_INTEGRATION]: "Create integration",
[EventType.DELETE_INTEGRATION]: "Delete integration",
[EventType.ADD_TRUSTED_IP]: "Add trusted IP",
[EventType.UPDATE_TRUSTED_IP]: "Update trusted IP",
[EventType.DELETE_TRUSTED_IP]: "Delete trusted IP",
[EventType.CREATE_SERVICE_TOKEN]: "Create service token",
[EventType.DELETE_SERVICE_TOKEN]: "Delete service token",
[EventType.CREATE_IDENTITY]: "Create identity",
[EventType.UPDATE_IDENTITY]: "Update identity",
[EventType.DELETE_IDENTITY]: "Delete identity",
[EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH]: "Login via universal auth",
[EventType.ADD_IDENTITY_UNIVERSAL_AUTH]: "Add universal auth",
[EventType.UPDATE_IDENTITY_UNIVERSAL_AUTH]: "Update universal auth",
[EventType.GET_IDENTITY_UNIVERSAL_AUTH]: "Get universal auth",
[EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET]: "Create universal auth client secret",
[EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET]: "Revoke universal auth client secret",
[EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS]: "Get universal auth client secrets",
[EventType.GET_IDENTITY_UNIVERSAL_AUTH]: "Get universal auth",
[EventType.CREATE_ENVIRONMENT]: "Create environment",
[EventType.UPDATE_ENVIRONMENT]: "Update environment",
[EventType.DELETE_ENVIRONMENT]: "Delete environment",
[EventType.ADD_WORKSPACE_MEMBER]: "Add member",
[EventType.REMOVE_WORKSPACE_MEMBER]: "Remove member",
[EventType.CREATE_FOLDER]: "Create folder",
[EventType.UPDATE_FOLDER]: "Update folder",
[EventType.DELETE_FOLDER]: "Delete folder",
[EventType.CREATE_WEBHOOK]: "Create webhook",
[EventType.UPDATE_WEBHOOK_STATUS]: "Update webhook status",
[EventType.DELETE_WEBHOOK]: "Delete webhook",
[EventType.GET_SECRET_IMPORTS]: "List secret imports",
[EventType.CREATE_SECRET_IMPORT]: "Create secret import",
[EventType.UPDATE_SECRET_IMPORT]: "Update secret import",
[EventType.DELETE_SECRET_IMPORT]: "Delete secret import",
[EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS]: "Update denied permissions",
[EventType.UPDATE_USER_WORKSPACE_ROLE]: "Update user role"
};
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
[UserAgentType.WEB]: "Web",
[UserAgentType.CLI]: "CLI",
[UserAgentType.K8_OPERATOR]: "K8s operator",
[UserAgentType.TERRAFORM]: "Terraform",
[UserAgentType.NODE_SDK]: "InfisicalNodeSDK",
[UserAgentType.PYTHON_SDK]: "InfisicalPythonSDK",
[UserAgentType.OTHER]: "Other",
};
[UserAgentType.WEB]: "Web",
[UserAgentType.CLI]: "CLI",
[UserAgentType.K8_OPERATOR]: "K8s operator",
[UserAgentType.TERRAFORM]: "Terraform",
[UserAgentType.NODE_SDK]: "InfisicalNodeSDK",
[UserAgentType.PYTHON_SDK]: "InfisicalPythonSDK",
[UserAgentType.OTHER]: "Other"
};

View File

@@ -38,7 +38,7 @@ export enum EventType {
UPDATE_IDENTITY_UNIVERSAL_AUTH = "update-identity-universal-auth",
GET_IDENTITY_UNIVERSAL_AUTH = "get-identity-universal-auth",
CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret",
CREATE_ENVIRONMENT = "create-environment",
UPDATE_ENVIRONMENT = "update-environment",
@@ -57,4 +57,4 @@ export enum EventType {
DELETE_SECRET_IMPORT = "delete-secret-import",
UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role",
UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions"
}
}

View File

@@ -1 +1 @@
export * from "./queries";
export * from "./queries";

View File

@@ -4,12 +4,12 @@ export type GetAuthTokenAPI = {
export type SendMfaTokenDTO = {
email: string;
}
};
export type VerifyMfaTokenDTO = {
email: string;
mfaCode: string;
}
};
export type VerifyMfaTokenRes = {
encryptionVersion: number;
@@ -21,24 +21,24 @@ export type VerifyMfaTokenRes = {
encryptedPrivateKey: string;
iv: string;
tag: string;
}
};
export type Login1DTO = {
email: string;
clientPublicKey: string;
providerAuthToken?: string;
}
};
export type Login2DTO = {
email: string;
clientProof: string;
providerAuthToken?: string;
}
};
export type Login1Res = {
serverPublicKey: string;
salt: string;
}
};
export type Login2Res = {
mfaEnabled: boolean;
@@ -51,26 +51,26 @@ export type Login2Res = {
encryptedPrivateKey?: string;
iv?: string;
tag?: string;
}
};
export type LoginLDAPDTO = {
organizationSlug: string;
username: string;
password: string;
}
};
export type LoginLDAPRes = {
nextUrl: string;
}
};
export type SRP1DTO = {
clientPublicKey: string;
}
};
export type SRPR1Res = {
serverPublicKey: string;
salt: string;
}
};
export type CompleteAccountDTO = {
email: string;
@@ -85,19 +85,19 @@ export type CompleteAccountDTO = {
encryptedPrivateKeyTag: string;
salt: string;
verifier: string;
}
};
export type CompleteAccountSignupDTO = CompleteAccountDTO & {
providerAuthToken?: string;
attributionSource?: string;
organizationName: string;
}
};
export type VerifySignupInviteDTO = {
email: string;
code: string;
organizationId: string;
}
};
export type ChangePasswordDTO = {
clientProof: string;
@@ -109,7 +109,7 @@ export type ChangePasswordDTO = {
encryptedPrivateKeyTag: string;
salt: string;
verifier: string;
}
};
export type ResetPasswordDTO = {
protectedKey: string;
@@ -121,7 +121,7 @@ export type ResetPasswordDTO = {
salt: string;
verifier: string;
verificationToken: string;
}
};
export type IssueBackupPrivateKeyDTO = {
encryptedPrivateKey: string;
@@ -130,8 +130,8 @@ export type IssueBackupPrivateKeyDTO = {
salt: string;
verifier: string;
clientProof: string;
}
};
export type GetBackupEncryptedPrivateKeyDTO = {
verificationToken: string;
}
};

View File

@@ -12,7 +12,9 @@ export const useGetWorkspaceBot = (workspaceId: string) =>
useQuery({
queryKey: queryKeys.getBot(workspaceId),
queryFn: async () => {
const { data: { bot } } = await apiRequest.get<{ bot: TBot }>(`/api/v1/bot/${workspaceId}`);
const {
data: { bot }
} = await apiRequest.get<{ bot: TBot }>(`/api/v1/bot/${workspaceId}`);
return bot;
},
enabled: Boolean(workspaceId)

View File

@@ -1,5 +1,5 @@
import { IdentityAuthMethod } from "./enums";
export const identityAuthToNameMap: { [I in IdentityAuthMethod]: string } = {
[IdentityAuthMethod.UNIVERSAL_AUTH]: "Universal Auth"
};
[IdentityAuthMethod.UNIVERSAL_AUTH]: "Universal Auth"
};

View File

@@ -1,14 +1,12 @@
export { identityAuthToNameMap } from "./constants";
export { IdentityAuthMethod } from "./enums";
export {
useAddIdentityUniversalAuth,
useCreateIdentity,
useCreateIdentityUniversalAuthClientSecret,
useDeleteIdentity,
useRevokeIdentityUniversalAuthClientSecret,
useUpdateIdentity,
useUpdateIdentityUniversalAuth} from "./mutations";
export {
useGetIdentityUniversalAuth,
useGetIdentityUniversalAuthClientSecrets
} from "./queries";
useAddIdentityUniversalAuth,
useCreateIdentity,
useCreateIdentityUniversalAuthClientSecret,
useDeleteIdentity,
useRevokeIdentityUniversalAuthClientSecret,
useUpdateIdentity,
useUpdateIdentityUniversalAuth
} from "./mutations";
export { useGetIdentityUniversalAuth, useGetIdentityUniversalAuthClientSecrets } from "./queries";

View File

@@ -4,161 +4,168 @@ import { apiRequest } from "@app/config/request";
import { organizationKeys } from "../organization/queries";
import { identitiesKeys } from "./queries";
import {
AddIdentityUniversalAuthDTO,
ClientSecretData,
CreateIdentityDTO,
CreateIdentityUniversalAuthClientSecretDTO,
CreateIdentityUniversalAuthClientSecretRes,
DeleteIdentityDTO,
DeleteIdentityUniversalAuthClientSecretDTO,
Identity,
IdentityUniversalAuth,
UpdateIdentityDTO,
UpdateIdentityUniversalAuthDTO} from "./types";
import {
AddIdentityUniversalAuthDTO,
ClientSecretData,
CreateIdentityDTO,
CreateIdentityUniversalAuthClientSecretDTO,
CreateIdentityUniversalAuthClientSecretRes,
DeleteIdentityDTO,
DeleteIdentityUniversalAuthClientSecretDTO,
Identity,
IdentityUniversalAuth,
UpdateIdentityDTO,
UpdateIdentityUniversalAuthDTO
} from "./types";
export const useCreateIdentity = () => {
const queryClient = useQueryClient();
return useMutation<Identity, {}, CreateIdentityDTO>({
mutationFn: async (body) => {
const { data: { identity } } = await apiRequest.post("/api/v1/identities/", body);
return identity;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
const queryClient = useQueryClient();
return useMutation<Identity, {}, CreateIdentityDTO>({
mutationFn: async (body) => {
const {
data: { identity }
} = await apiRequest.post("/api/v1/identities/", body);
return identity;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
};
export const useUpdateIdentity = () => {
const queryClient = useQueryClient();
return useMutation<Identity, {}, UpdateIdentityDTO>({
mutationFn: async ({
identityId,
name,
role
}) => {
const { data: { identity } } = await apiRequest.patch(`/api/v1/identities/${identityId}`, {
name,
role
});
const queryClient = useQueryClient();
return useMutation<Identity, {}, UpdateIdentityDTO>({
mutationFn: async ({ identityId, name, role }) => {
const {
data: { identity }
} = await apiRequest.patch(`/api/v1/identities/${identityId}`, {
name,
role
});
return identity;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
}
return identity;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
};
export const useDeleteIdentity = () => {
const queryClient = useQueryClient();
return useMutation<Identity, {}, DeleteIdentityDTO>({
mutationFn: async ({
identityId,
}) => {
const { data: { identity } } = await apiRequest.delete(`/api/v1/identities/${identityId}`);
return identity;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
const queryClient = useQueryClient();
return useMutation<Identity, {}, DeleteIdentityDTO>({
mutationFn: async ({ identityId }) => {
const {
data: { identity }
} = await apiRequest.delete(`/api/v1/identities/${identityId}`);
return identity;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
};
// TODO: move these to /auth
export const useAddIdentityUniversalAuth = () => {
const queryClient = useQueryClient();
return useMutation<IdentityUniversalAuth, {}, AddIdentityUniversalAuthDTO>({
mutationFn: async ({
identityId,
clientSecretTrustedIps,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps,
}) => {
const { data: { identityUniversalAuth } } = await apiRequest.post(`/api/v1/auth/universal-auth/identities/${identityId}`,
{
clientSecretTrustedIps,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps,
}
);
return identityUniversalAuth;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
const queryClient = useQueryClient();
return useMutation<IdentityUniversalAuth, {}, AddIdentityUniversalAuthDTO>({
mutationFn: async ({
identityId,
clientSecretTrustedIps,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
}) => {
const {
data: { identityUniversalAuth }
} = await apiRequest.post(`/api/v1/auth/universal-auth/identities/${identityId}`, {
clientSecretTrustedIps,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
});
return identityUniversalAuth;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
};
export const useUpdateIdentityUniversalAuth = () => {
const queryClient = useQueryClient();
return useMutation<IdentityUniversalAuth, {}, UpdateIdentityUniversalAuthDTO>({
mutationFn: async ({
identityId,
clientSecretTrustedIps,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps,
}) => {
const { data: { identityUniversalAuth } } = await apiRequest.patch(`/api/v1/auth/universal-auth/identities/${identityId}`,
{
clientSecretTrustedIps,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps,
}
);
return identityUniversalAuth;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
const queryClient = useQueryClient();
return useMutation<IdentityUniversalAuth, {}, UpdateIdentityUniversalAuthDTO>({
mutationFn: async ({
identityId,
clientSecretTrustedIps,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
}) => {
const {
data: { identityUniversalAuth }
} = await apiRequest.patch(`/api/v1/auth/universal-auth/identities/${identityId}`, {
clientSecretTrustedIps,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
});
return identityUniversalAuth;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
}
});
};
export const useCreateIdentityUniversalAuthClientSecret = () => {
const queryClient = useQueryClient();
return useMutation<CreateIdentityUniversalAuthClientSecretRes, {}, CreateIdentityUniversalAuthClientSecretDTO>({
mutationFn: async ({
identityId,
description,
ttl,
numUsesLimit
}) => {
const { data } = await apiRequest.post(`/api/v1/auth/universal-auth/identities/${identityId}/client-secrets`, {
description,
ttl,
numUsesLimit
});
return data;
},
onSuccess: (_, { identityId }) => {
queryClient.invalidateQueries(identitiesKeys.getIdentityUniversalAuthClientSecrets(identityId));
const queryClient = useQueryClient();
return useMutation<
CreateIdentityUniversalAuthClientSecretRes,
{},
CreateIdentityUniversalAuthClientSecretDTO
>({
mutationFn: async ({ identityId, description, ttl, numUsesLimit }) => {
const { data } = await apiRequest.post(
`/api/v1/auth/universal-auth/identities/${identityId}/client-secrets`,
{
description,
ttl,
numUsesLimit
}
});
);
return data;
},
onSuccess: (_, { identityId }) => {
queryClient.invalidateQueries(
identitiesKeys.getIdentityUniversalAuthClientSecrets(identityId)
);
}
});
};
export const useRevokeIdentityUniversalAuthClientSecret = () => {
const queryClient = useQueryClient();
return useMutation<ClientSecretData, {}, DeleteIdentityUniversalAuthClientSecretDTO>({
mutationFn: async ({
identityId,
clientSecretId
}) => {
const { data: { clientSecretData } } = await apiRequest.post<{ clientSecretData: ClientSecretData }>(`/api/v1/auth/universal-auth/identities/${identityId}/client-secrets/${clientSecretId}/revoke`);
return clientSecretData;
},
onSuccess: (_, { identityId }) => {
queryClient.invalidateQueries(identitiesKeys.getIdentityUniversalAuthClientSecrets(identityId));
}
});
};
const queryClient = useQueryClient();
return useMutation<ClientSecretData, {}, DeleteIdentityUniversalAuthClientSecretDTO>({
mutationFn: async ({ identityId, clientSecretId }) => {
const {
data: { clientSecretData }
} = await apiRequest.post<{ clientSecretData: ClientSecretData }>(
`/api/v1/auth/universal-auth/identities/${identityId}/client-secrets/${clientSecretId}/revoke`
);
return clientSecretData;
},
onSuccess: (_, { identityId }) => {
queryClient.invalidateQueries(
identitiesKeys.getIdentityUniversalAuthClientSecrets(identityId)
);
}
});
};

View File

@@ -2,39 +2,45 @@ import { useQuery } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { ClientSecretData , IdentityUniversalAuth } from "./types";
import { ClientSecretData, IdentityUniversalAuth } from "./types";
export const identitiesKeys = {
getIdentityUniversalAuth: (identityId: string) => [{ identityId }, "identity-universal-auth"] as const,
getIdentityUniversalAuthClientSecrets: (identityId: string) => [{ identityId }, "identity-universal-auth-client-secrets"] as const
}
getIdentityUniversalAuth: (identityId: string) =>
[{ identityId }, "identity-universal-auth"] as const,
getIdentityUniversalAuthClientSecrets: (identityId: string) =>
[{ identityId }, "identity-universal-auth-client-secrets"] as const
};
export const useGetIdentityUniversalAuth = (identityId: string) => {
return useQuery({
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId),
queryFn: async () => {
if (identityId === "") throw new Error("Identity ID is required");
return useQuery({
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId),
queryFn: async () => {
if (identityId === "") throw new Error("Identity ID is required");
const { data: { identityUniversalAuth } } = await apiRequest.get<{ identityUniversalAuth: IdentityUniversalAuth }>(
`/api/v1/auth/universal-auth/identities/${identityId}`
);
return identityUniversalAuth;
}
});
}
const {
data: { identityUniversalAuth }
} = await apiRequest.get<{ identityUniversalAuth: IdentityUniversalAuth }>(
`/api/v1/auth/universal-auth/identities/${identityId}`
);
return identityUniversalAuth;
}
});
};
export const useGetIdentityUniversalAuthClientSecrets = (identityId: string) => {
return useQuery({
queryKey: identitiesKeys.getIdentityUniversalAuthClientSecrets(identityId),
queryFn: async () => {
if (identityId === "") return [];
return useQuery({
queryKey: identitiesKeys.getIdentityUniversalAuthClientSecrets(identityId),
queryFn: async () => {
if (identityId === "") return [];
const { data: { clientSecretData } } = await apiRequest.get<{ clientSecretData: ClientSecretData[] }>(
`/api/v1/auth/universal-auth/identities/${identityId}/client-secrets`
);
return clientSecretData;
}
});
}
const {
data: { clientSecretData }
} = await apiRequest.get<{ clientSecretData: ClientSecretData[] }>(
`/api/v1/auth/universal-auth/identities/${identityId}/client-secrets`
);
return clientSecretData;
}
});
};

View File

@@ -1,4 +1,4 @@
export * from "./admin"
export * from "./admin";
export * from "./apiKeys";
export * from "./auditLogs";
export * from "./auth";
@@ -27,4 +27,4 @@ export * from "./tags";
export * from "./trustedIps";
export * from "./users";
export * from "./webhooks";
export * from "./workspace";
export * from "./workspace";

View File

@@ -15,4 +15,4 @@ export {
useGetIntegrationAuthTeams,
useGetIntegrationAuthVercelBranches,
useSaveIntegrationAccessToken
} from "./queries";
} from "./queries";

View File

@@ -68,8 +68,8 @@ const integrationAuthKeys = {
environmentId: string;
scope: "job" | "application" | "container";
}) => [{ integrationAuthId, environmentId, scope }, "integrationAuthQoveryScopes"] as const,
getIntegrationAuthHerokuPipelines: ({ integrationAuthId }: { integrationAuthId: string; }) =>
[{ integrationAuthId}, "integrationAuthHerokuPipelines"] as const,
getIntegrationAuthHerokuPipelines: ({ integrationAuthId }: { integrationAuthId: string }) =>
[{ integrationAuthId }, "integrationAuthHerokuPipelines"] as const,
getIntegrationAuthRailwayEnvironments: ({
integrationAuthId,
appId
@@ -322,8 +322,10 @@ const fetchIntegrationAuthQoveryScopes = async ({
return undefined;
};
const fetchIntegrationAuthHerokuPipelines = async ({ integrationAuthId }: {
integrationAuthId: string;
const fetchIntegrationAuthHerokuPipelines = async ({
integrationAuthId
}: {
integrationAuthId: string;
}) => {
const {
data: { pipelines }

View File

@@ -1,5 +1 @@
export {
useCreateIntegration,
useDeleteIntegration,
useGetCloudIntegrations
} from "./queries";
export { useCreateIntegration, useDeleteIntegration, useGetCloudIntegrations } from "./queries";

View File

@@ -63,9 +63,11 @@ export const useCreateIntegration = () => {
secretSuffix?: string;
initialSyncBehavior?: string;
shouldAutoRedeploy?: boolean;
}
};
}) => {
const { data: { integration } } = await apiRequest.post("/api/v1/integration", {
const {
data: { integration }
} = await apiRequest.post("/api/v1/integration", {
integrationAuthId,
isActive,
app,
@@ -101,4 +103,4 @@ export const useDeleteIntegration = () => {
queryClient.invalidateQueries(workspaceKeys.getWorkspaceAuthorization(workspaceId));
}
});
};
};

View File

@@ -1,5 +1 @@
export {
useCreateLDAPConfig,
useGetLDAPConfig,
useUpdateLDAPConfig
} from "./queries";
export { useCreateLDAPConfig, useGetLDAPConfig, useUpdateLDAPConfig } from "./queries";

View File

@@ -3,27 +3,42 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
const ldapConfigKeys = {
getLDAPConfig: (orgId: string) => [{ orgId }, "organization-ldap"] as const,
}
getLDAPConfig: (orgId: string) => [{ orgId }, "organization-ldap"] as const
};
export const useGetLDAPConfig = (organizationId: string) => {
return useQuery({
queryKey: ldapConfigKeys.getLDAPConfig(organizationId),
queryFn: async () => {
const { data } = await apiRequest.get(
`/api/v1/ldap/config?organizationId=${organizationId}`
);
const { data } = await apiRequest.get(`/api/v1/ldap/config?organizationId=${organizationId}`);
return data;
},
enabled: true
});
}
};
export const useCreateLDAPConfig = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
organizationId,
isActive,
url,
bindDN,
bindPass,
searchBase,
caCert
}: {
organizationId: string;
isActive: boolean;
url: string;
bindDN: string;
bindPass: string;
searchBase: string;
caCert?: string;
}) => {
const { data } = await apiRequest.post("/api/v1/ldap/config", {
organizationId,
isActive,
url,
@@ -31,28 +46,8 @@ export const useCreateLDAPConfig = () => {
bindPass,
searchBase,
caCert
}: {
organizationId: string;
isActive: boolean;
url: string;
bindDN: string;
bindPass: string;
searchBase: string;
caCert?: string;
}) => {
const { data } = await apiRequest.post(
"/api/v1/ldap/config",
{
organizationId,
isActive,
url,
bindDN,
bindPass,
searchBase,
caCert
}
);
});
return data;
},
onSuccess(_, dto) {
@@ -65,6 +60,23 @@ export const useUpdateLDAPConfig = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
organizationId,
isActive,
url,
bindDN,
bindPass,
searchBase,
caCert
}: {
organizationId: string;
isActive?: boolean;
url?: string;
bindDN?: string;
bindPass?: string;
searchBase?: string;
caCert?: string;
}) => {
const { data } = await apiRequest.patch("/api/v1/ldap/config", {
organizationId,
isActive,
url,
@@ -72,32 +84,12 @@ export const useUpdateLDAPConfig = () => {
bindPass,
searchBase,
caCert
}: {
organizationId: string;
isActive?: boolean;
url?: string;
bindDN?: string;
bindPass?: string;
searchBase?: string;
caCert?: string;
}) => {
const { data } = await apiRequest.patch(
"/api/v1/ldap/config",
{
organizationId,
isActive,
url,
bindDN,
bindPass,
searchBase,
caCert
}
);
});
return data;
},
onSuccess(_, dto) {
queryClient.invalidateQueries(ldapConfigKeys.getLDAPConfig(dto.organizationId));
}
});
};
};

View File

@@ -1,22 +1,22 @@
export {
useAddOrgPmtMethod,
useAddOrgTaxId,
useCreateCustomerPortalSession,
useCreateOrg,
useDeleteOrgById,
useDeleteOrgPmtMethod,
useDeleteOrgTaxId,
useGetIdentityMembershipOrgs,
useGetOrganizations,
useGetOrgBillingDetails,
useGetOrgInvoices,
useGetOrgLicenses,
useGetOrgPlanBillingInfo,
useGetOrgPlansTable,
useGetOrgPlanTable,
useGetOrgPmtMethods,
useGetOrgTaxIds,
useGetOrgTrialUrl,
useUpdateOrg,
useUpdateOrgBillingDetails
useAddOrgPmtMethod,
useAddOrgTaxId,
useCreateCustomerPortalSession,
useCreateOrg,
useDeleteOrgById,
useDeleteOrgPmtMethod,
useDeleteOrgTaxId,
useGetIdentityMembershipOrgs,
useGetOrganizations,
useGetOrgBillingDetails,
useGetOrgInvoices,
useGetOrgLicenses,
useGetOrgPlanBillingInfo,
useGetOrgPlansTable,
useGetOrgPlanTable,
useGetOrgPmtMethods,
useGetOrgTaxIds,
useGetOrgTrialUrl,
useUpdateOrg,
useUpdateOrgBillingDetails
} from "./queries";

View File

@@ -1,5 +1,2 @@
export {
useCreateScimToken,
useDeleteScimToken
} from "./mutations";
export { useGetScimTokens } from "./queries";
export { useCreateScimToken, useDeleteScimToken } from "./mutations";
export { useGetScimTokens } from "./queries";

View File

@@ -3,43 +3,35 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { scimKeys } from "./queries";
import {
CreateScimTokenDTO,
CreateScimTokenRes,
DeleteScimTokenDTO
} from "./types";
import { CreateScimTokenDTO, CreateScimTokenRes, DeleteScimTokenDTO } from "./types";
export const useCreateScimToken = () => {
const queryClient = useQueryClient();
return useMutation<CreateScimTokenRes, {}, CreateScimTokenDTO>({
mutationFn: async ({
organizationId,
description,
ttlDays
}) => {
const { data } = await apiRequest.post("/api/v1/scim/scim-tokens", {
organizationId,
description,
ttlDays
});
return data;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(scimKeys.getScimTokens(organizationId));
}
});
const queryClient = useQueryClient();
return useMutation<CreateScimTokenRes, {}, CreateScimTokenDTO>({
mutationFn: async ({ organizationId, description, ttlDays }) => {
const { data } = await apiRequest.post("/api/v1/scim/scim-tokens", {
organizationId,
description,
ttlDays
});
return data;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(scimKeys.getScimTokens(organizationId));
}
});
};
export const useDeleteScimToken = () => {
const queryClient = useQueryClient();
return useMutation<CreateScimTokenRes, {}, DeleteScimTokenDTO>({
mutationFn: async ({ scimTokenId }) => {
const { data } = await apiRequest.delete(`/api/v1/scim/scim-tokens/${scimTokenId}`);
return data;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(scimKeys.getScimTokens(organizationId));
}
});
};
const queryClient = useQueryClient();
return useMutation<CreateScimTokenRes, {}, DeleteScimTokenDTO>({
mutationFn: async ({ scimTokenId }) => {
const { data } = await apiRequest.delete(`/api/v1/scim/scim-tokens/${scimTokenId}`);
return data;
},
onSuccess: (_, { organizationId }) => {
queryClient.invalidateQueries(scimKeys.getScimTokens(organizationId));
}
});
};

View File

@@ -5,21 +5,25 @@ import { apiRequest } from "@app/config/request";
import { ScimTokenData } from "./types";
export const scimKeys = {
getScimTokens: (orgId: string) => [{ orgId }, "organization-scim-token"] as const,
getScimTokens: (orgId: string) => [{ orgId }, "organization-scim-token"] as const
};
export const useGetScimTokens = (organizationId: string) => {
return useQuery({
queryKey: scimKeys.getScimTokens(organizationId),
queryFn: async () => {
if (organizationId === "") {
return undefined;
}
const { data: { scimTokens } } = await apiRequest.get<{ scimTokens: ScimTokenData[] }>(`/api/v1/scim/scim-tokens?organizationId=${organizationId}`);
return scimTokens;
},
enabled: true
});
};
return useQuery({
queryKey: scimKeys.getScimTokens(organizationId),
queryFn: async () => {
if (organizationId === "") {
return undefined;
}
const {
data: { scimTokens }
} = await apiRequest.get<{ scimTokens: ScimTokenData[] }>(
`/api/v1/scim/scim-tokens?organizationId=${organizationId}`
);
return scimTokens;
},
enabled: true
});
};

View File

@@ -1,24 +1,24 @@
export type ScimTokenData = {
id: string;
ttlDays: number;
description: string;
tokenSuffix: string;
orgId: string;
createdAt: string;
updatedAt: string;
id: string;
ttlDays: number;
description: string;
tokenSuffix: string;
orgId: string;
createdAt: string;
updatedAt: string;
};
export type CreateScimTokenDTO = {
organizationId: string;
description?: string;
ttlDays?: number;
}
organizationId: string;
description?: string;
ttlDays?: number;
};
export type DeleteScimTokenDTO = {
organizationId: string;
scimTokenId: string;
}
organizationId: string;
scimTokenId: string;
};
export type CreateScimTokenRes = {
scimToken: string;
}
scimToken: string;
};

View File

@@ -1 +1 @@
export { useFetchServerStatus } from "./queries"
export { useFetchServerStatus } from "./queries";

View File

@@ -1,4 +1,4 @@
import {useQuery } from "@tanstack/react-query";
import { useQuery } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
@@ -10,10 +10,10 @@ const serverStatusKeys = {
};
const fetchServerStatus = async () => {
const {data} = await apiRequest.get<ServerStatus>("/api/status");
const { data } = await apiRequest.get<ServerStatus>("/api/status");
return data;
};
export const useFetchServerStatus= () => {
export const useFetchServerStatus = () => {
return useQuery({ queryKey: serverStatusKeys.serverStatus, queryFn: fetchServerStatus });
}
};

View File

@@ -2,6 +2,6 @@ export type ServerStatus = {
date: string;
message: string;
emailConfigured: boolean;
secretScanningConfigured: boolean
redisConfigured: boolean
secretScanningConfigured: boolean;
redisConfigured: boolean;
};

View File

@@ -1,4 +1,4 @@
export enum Permission {
READ = "read",
WRITE = "write"
}
READ = "read",
WRITE = "write"
}

View File

@@ -1,5 +1 @@
export {
useCreateServiceToken,
useDeleteServiceToken,
useGetUserWsServiceTokens,
} from "./queries";
export { useCreateServiceToken, useDeleteServiceToken, useGetUserWsServiceTokens } from "./queries";

View File

@@ -1,5 +1 @@
export {
useCreateSSOConfig,
useGetSSOConfig,
useUpdateSSOConfig
} from "./queries";
export { useCreateSSOConfig, useGetSSOConfig, useUpdateSSOConfig } from "./queries";

View File

@@ -87,7 +87,7 @@ export const useUpdateSSOConfig = () => {
if (isActive === false) {
queryClient.invalidateQueries(organizationKeys.getUserOrganizations);
}
queryClient.invalidateQueries(ssoConfigKeys.getSSOConfig(organizationId));
}
});

View File

@@ -1,5 +1,6 @@
export {
useAddTrustedIp,
useDeleteTrustedIp,
useGetTrustedIps,
useUpdateTrustedIp} from "./queries";
useAddTrustedIp,
useDeleteTrustedIp,
useGetTrustedIps,
useUpdateTrustedIp
} from "./queries";

View File

@@ -2,107 +2,104 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import {
TrustedIp
} from "./types";
import { TrustedIp } from "./types";
const trustedIps = {
getTrustedIps: (workspaceId: string) => [{ workspaceId }, "trusted-ips"] as const
}
getTrustedIps: (workspaceId: string) => [{ workspaceId }, "trusted-ips"] as const
};
export const useGetTrustedIps = (workspaceId: string) => {
return useQuery({
queryKey: trustedIps.getTrustedIps(workspaceId),
queryFn: async () => {
const { data } = await apiRequest.get<{ trustedIps: TrustedIp[] }>(`/api/v1/workspace/${workspaceId}/trusted-ips`);
return useQuery({
queryKey: trustedIps.getTrustedIps(workspaceId),
queryFn: async () => {
const { data } = await apiRequest.get<{ trustedIps: TrustedIp[] }>(
`/api/v1/workspace/${workspaceId}/trusted-ips`
);
return data.trustedIps;
}
});
}
return data.trustedIps;
}
});
};
export const useAddTrustedIp = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
workspaceId,
ipAddress,
comment,
isActive
}: {
workspaceId: string;
ipAddress: string;
comment?: string;
isActive: boolean;
}) => {
const { data } = await apiRequest.post(
`/api/v1/workspace/${workspaceId}/trusted-ips`,
{
ipAddress,
...(comment ? { comment } : {}),
isActive
}
);
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
workspaceId,
ipAddress,
comment,
isActive
}: {
workspaceId: string;
ipAddress: string;
comment?: string;
isActive: boolean;
}) => {
const { data } = await apiRequest.post(`/api/v1/workspace/${workspaceId}/trusted-ips`, {
ipAddress,
...(comment ? { comment } : {}),
isActive
});
return data;
},
onSuccess(_, dto) {
queryClient.invalidateQueries(trustedIps.getTrustedIps(dto.workspaceId));
}
});
return data;
},
onSuccess(_, dto) {
queryClient.invalidateQueries(trustedIps.getTrustedIps(dto.workspaceId));
}
});
};
export const useUpdateTrustedIp = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
workspaceId,
trustedIpId,
ipAddress,
comment,
isActive
}: {
workspaceId: string;
trustedIpId: string;
ipAddress: string;
comment?: string;
isActive: boolean;
}) => {
const { data } = await apiRequest.patch(
`/api/v1/workspace/${workspaceId}/trusted-ips/${trustedIpId}`,
{
ipAddress,
...(comment ? { comment } : {}),
isActive
}
);
return data;
},
onSuccess(_, dto) {
queryClient.invalidateQueries(trustedIps.getTrustedIps(dto.workspaceId));
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
workspaceId,
trustedIpId,
ipAddress,
comment,
isActive
}: {
workspaceId: string;
trustedIpId: string;
ipAddress: string;
comment?: string;
isActive: boolean;
}) => {
const { data } = await apiRequest.patch(
`/api/v1/workspace/${workspaceId}/trusted-ips/${trustedIpId}`,
{
ipAddress,
...(comment ? { comment } : {}),
isActive
}
});
);
return data;
},
onSuccess(_, dto) {
queryClient.invalidateQueries(trustedIps.getTrustedIps(dto.workspaceId));
}
});
};
export const useDeleteTrustedIp = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
workspaceId,
trustedIpId,
}: {
workspaceId: string;
trustedIpId: string;
}) => {
const { data } = await apiRequest.delete(
`/api/v1/workspace/${workspaceId}/trusted-ips/${trustedIpId}`
);
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
workspaceId,
trustedIpId
}: {
workspaceId: string;
trustedIpId: string;
}) => {
const { data } = await apiRequest.delete(
`/api/v1/workspace/${workspaceId}/trusted-ips/${trustedIpId}`
);
return data;
},
onSuccess(_, dto) {
queryClient.invalidateQueries(trustedIps.getTrustedIps(dto.workspaceId));
}
});
};
return data;
},
onSuccess(_, dto) {
queryClient.invalidateQueries(trustedIps.getTrustedIps(dto.workspaceId));
}
});
};

View File

@@ -325,7 +325,13 @@ export const useDeleteUserFromWorkspace = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ usernames, workspaceId }: { workspaceId: string; usernames: string[] }) => {
mutationFn: async ({
usernames,
workspaceId
}: {
workspaceId: string;
usernames: string[];
}) => {
const {
data: { deletedMembership }
} = await apiRequest.delete(`/api/v2/workspace/${workspaceId}/memberships`, {
@@ -391,11 +397,7 @@ export const useAddIdentityToWorkspace = () => {
export const useUpdateIdentityWorkspaceRole = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
identityId,
workspaceId,
roles
}:TUpdateWorkspaceIdentityRoleDTO)=> {
mutationFn: async ({ identityId, workspaceId, roles }: TUpdateWorkspaceIdentityRoleDTO) => {
const {
data: { identityMembership }
} = await apiRequest.patch(

View File

@@ -82,16 +82,16 @@ export type TUpdateWorkspaceUserRoleDTO = {
workspaceId: string;
roles: (
| {
role: string;
isTemporary?: false;
}
role: string;
isTemporary?: false;
}
| {
role: string;
isTemporary: true;
temporaryMode: ProjectUserMembershipTemporaryMode;
temporaryRange: string;
temporaryAccessStartTime: string;
}
role: string;
isTemporary: true;
temporaryMode: ProjectUserMembershipTemporaryMode;
temporaryRange: string;
temporaryAccessStartTime: string;
}
)[];
};
@@ -100,15 +100,15 @@ export type TUpdateWorkspaceIdentityRoleDTO = {
workspaceId: string;
roles: (
| {
role: string;
isTemporary?: false;
}
role: string;
isTemporary?: false;
}
| {
role: string;
isTemporary: true;
temporaryMode: ProjectUserMembershipTemporaryMode;
temporaryRange: string;
temporaryAccessStartTime: string;
}
role: string;
isTemporary: true;
temporaryMode: ProjectUserMembershipTemporaryMode;
temporaryRange: string;
temporaryAccessStartTime: string;
}
)[];
};

View File

@@ -19,7 +19,7 @@ i18n
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
lng:"en",
lng: "en",
fallbackLng: "en",
// supportedLngs: ["en", "ko", "fr", "pt-BR", "pt-PT", "es"],
debug: process.env.NODE_ENV === "development",

View File

@@ -4,12 +4,12 @@
* each item in that group.
*/
export const groupBy = <T, Key extends string | number | symbol>(
array: readonly T[],
getGroupId: (item: T) => Key
array: readonly T[],
getGroupId: (item: T) => Key
): Record<Key, T[]> =>
array.reduce((acc, item) => {
const groupId = getGroupId(item);
if (!acc[groupId]) acc[groupId] = [];
acc[groupId].push(item);
return acc;
}, {} as Record<Key, T[]>);
array.reduce((acc, item) => {
const groupId = getGroupId(item);
if (!acc[groupId]) acc[groupId] = [];
acc[groupId].push(item);
return acc;
}, {} as Record<Key, T[]>);

View File

@@ -4,34 +4,31 @@ import Link from "next/link";
export default function Custom404() {
return (
<div className='bg-bunker-800 md:h-screen flex flex-col justify-between'>
<div className="flex flex-col justify-between bg-bunker-800 md:h-screen">
<Head>
<title>Infisical | Page Not Found</title>
<link rel='icon' href='/infisical.ico' />
<link rel="icon" href="/infisical.ico" />
</Head>
<div className='flex flex-col items-center justify-center text-gray-200 h-screen w-screen'>
<p className='text-4xl mt-32'>Oops, something went wrong</p>
<p className='mt-2 mb-1 text-lg'>
<div className="flex h-screen w-screen flex-col items-center justify-center text-gray-200">
<p className="mt-32 text-4xl">Oops, something went wrong</p>
<p className="mt-2 mb-1 text-lg">
Think this is a mistake? Email{" "}
<a
className='text-primary underline underline-offset-4'
href='mailto:team@infisical.com'
>
<a className="text-primary underline underline-offset-4" href="mailto:team@infisical.com">
team@infisical.com
</a>{" "}
and we`ll fix it!{" "}
</p>
<Link href='/dashboard'>
<div className="mt-8 bg-mineshaft-500 py-2 px-4 rounded-md hover:bg-primary diration-200 hover:text-black font-semibold cursor-default">
<Link href="/dashboard">
<div className="diration-200 mt-8 cursor-default rounded-md bg-mineshaft-500 py-2 px-4 font-semibold hover:bg-primary hover:text-black">
Go to Dashboard
</div>
</Link>
<Image
src='/images/dragon-404.svg'
src="/images/dragon-404.svg"
height={554}
width={942}
alt='infisical dragon - page not found'
/>
alt="infisical dragon - page not found"
/>
</div>
</div>
);

View File

@@ -7,7 +7,7 @@ export default function LoginPage() {
const { t } = useTranslation();
return (
<div className="flex min-h-screen max-h-screen overflow-y-auto flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6">
<div className="flex max-h-screen min-h-screen flex-col justify-center overflow-y-auto bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6">
<Head>
<title>{t("common.head-title", { title: t("signup.title") })}</title>
<link rel="icon" href="/infisical.ico" />

View File

@@ -11,6 +11,6 @@ const checkAuth = async () => {
"Content-Type": "application/json"
}
}).then((res) => res);
}
};
export default checkAuth;

View File

@@ -2,7 +2,7 @@ import SecurityClient from "@app/components/utilities/SecurityClient";
/**
* Will create a new integration session and return it for the given org
* @returns
* @returns
*/
const linkGitAppInstallationWithOrganization = (installationId: string, sessionId: string) =>
SecurityClient.fetchCall("/api/v1/secret-scanning/link-installation", {
@@ -16,7 +16,7 @@ const linkGitAppInstallationWithOrganization = (installationId: string, sessionI
})
}).then(async (res) => {
if (res && res.status === 200) {
return true
return true;
}
console.log("Failed to link installation to organization");
return undefined;

View File

@@ -4,25 +4,26 @@ export enum RiskStatus {
RESOLVED_FALSE_POSITIVE = "RESOLVED_FALSE_POSITIVE",
RESOLVED_REVOKED = "RESOLVED_REVOKED",
RESOLVED_NOT_REVOKED = "RESOLVED_NOT_REVOKED",
UNRESOLVED = "UNRESOLVED",
UNRESOLVED = "UNRESOLVED"
}
/**
* Will create a new integration session and return it for the given org
* @returns
* @returns
*/
const updateRiskStatus = (organizationId: string, riskId: string, status: RiskStatus) =>
SecurityClient.fetchCall(`/api/v1/secret-scanning/organization/${organizationId}/risks/${riskId}/status`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
status
})
}).then(async (res) => {
SecurityClient.fetchCall(
`/api/v1/secret-scanning/organization/${organizationId}/risks/${riskId}/status`,
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
status
})
}
).then(async (res) => {
if (res && res.status === 200) {
return res.json();
}

View File

@@ -3,17 +3,19 @@ import Image from "next/image";
export default function CliRedirect() {
return (
<div className='bg-bunker-800 md:h-screen flex flex-col justify-between'>
<div className="flex flex-col justify-between bg-bunker-800 md:h-screen">
<Head>
<title>Infisical CLI | Login Successful!</title>
<link rel='icon' href='/infisical.ico' />
<link rel="icon" href="/infisical.ico" />
</Head>
<div className='flex flex-col items-center justify-center text-gray-200 h-screen w-screen'>
<div className="flex h-screen w-screen flex-col items-center justify-center text-gray-200">
<div className="mb-8 flex justify-center">
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical Logo" />
</div>
<p className='text-3xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center'>Head back to your terminal</p>
<p className='mb-1 text-lg text-light text-mineshaft-400'>
<p className="bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-3xl font-medium text-transparent">
Head back to your terminal
</p>
<p className="text-light mb-1 text-lg text-mineshaft-400">
You&apos;ve successfully logged in to the Infisical CLI
</p>
</div>

View File

@@ -3,16 +3,16 @@ import Head from "next/head";
export default function EmailNotFeriviedPage() {
return (
<div className="bg-bunker-800 md:h-screen flex flex-col justify-between">
<div className="flex flex-col justify-between bg-bunker-800 md:h-screen">
<Head>
<title>Request a New Invite</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<div className="flex flex-col items-center justify-center text-gray-200 h-screen w-screen">
<div className="flex h-screen w-screen flex-col items-center justify-center text-gray-200">
<p className="text-6xl">Oops.</p>
<p className="mt-2 mb-1 text-xl">Your email was not verified. </p>
<p className="text-xl">Please try again.</p>
<p className="text-md mt-8 text-gray-600 max-w-sm text-center">
<p className="text-md mt-8 max-w-sm text-center text-gray-600">
Note: If it still doesn&apos;t work, please reach out to us at support@infisical.com
</p>
</div>

View File

@@ -9,5 +9,5 @@ export default function Home() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return <div className="bg-bunker-800 w-screen" />;
return <div className="w-screen bg-bunker-800" />;
}

View File

@@ -1,92 +1,87 @@
import { useState } from "react";
import { useRouter } from "next/router";
import {
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { useSaveIntegrationAccessToken } from "@app/hooks/api";
import { Button,Card, CardTitle, FormControl, Input } from "../../../components/v2";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
export default function CloudflarePagesIntegrationPage() {
const router = useRouter();
const { mutateAsync } = useSaveIntegrationAccessToken();
const router = useRouter();
const { mutateAsync } = useSaveIntegrationAccessToken();
const [accessKey, setAccessKey] = useState("");
const [accessKeyErrorText, setAccessKeyErrorText] = useState("");
const [accountId, setAccountId] = useState("");
const [accountIdErrorText, setAccountIdErrorText] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [accessKey, setAccessKey] = useState("");
const [accessKeyErrorText, setAccessKeyErrorText] = useState("");
const [accountId, setAccountId] = useState("");
const [accountIdErrorText, setAccountIdErrorText] = useState("");
const [isLoading, setIsLoading] = useState(false);
const handleButtonClick = async () => {
try {
setAccessKeyErrorText("");
setAccountIdErrorText("");
if (accessKey.length === 0 || accountId.length === 0) {
if (accessKey.length === 0) setAccessKeyErrorText("API token cannot be blank!");
if (accountId.length === 0) setAccountIdErrorText("Account ID cannot be blank!");
return;
}
const handleButtonClick = async () => {
try {
setAccessKeyErrorText("");
setAccountIdErrorText("");
if (accessKey.length === 0 || accountId.length === 0) {
if (accessKey.length === 0) setAccessKeyErrorText("API token cannot be blank!");
if (accountId.length === 0) setAccountIdErrorText("Account ID cannot be blank!");
return;
}
setIsLoading(true);
setIsLoading(true);
const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"),
integration: "cloudflare-pages",
accessId: accountId,
accessToken: accessKey
});
const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"),
integration: "cloudflare-pages",
accessId: accountId,
accessToken: accessKey
});
setAccessKey("");
setAccountId("");
setIsLoading(false);
setAccessKey("");
setAccountId("");
setIsLoading(false);
router.push(`/integrations/cloudflare-pages/create?integrationAuthId=${integrationAuth.id}`);
} catch (err) {
console.error(err);
}
router.push(`/integrations/cloudflare-pages/create?integrationAuthId=${integrationAuth.id}`);
} catch (err) {
console.error(err);
}
};
return (
<div className="flex h-full w-full items-center justify-center">
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle className="text-left px-6" subTitle="After adding your API-key, you will be prompted to set up an integration for a particular Infisical project and environment.">Cloudflare Pages Integration</CardTitle>
<FormControl
label="Cloudflare Pages API token"
errorText={accessKeyErrorText}
isError={accessKeyErrorText !== "" ?? false}
className="mx-6"
>
<Input
placeholder=""
value={accessKey}
onChange={(e) => setAccessKey(e.target.value)}
/>
</FormControl>
<FormControl
label="Cloudflare Pages Account ID"
errorText={accountIdErrorText}
isError={accountIdErrorText !== "" ?? false}
className="mx-6"
>
<Input
placeholder=""
value={accountId}
onChange={(e) => setAccountId(e.target.value)}
/>
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isFullWidth={false}
isLoading={isLoading}
>
Connect to Cloudflare Pages
</Button>
</Card>
</div>
);
return (
<div className="flex h-full w-full items-center justify-center">
<Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="px-6 text-left"
subTitle="After adding your API-key, you will be prompted to set up an integration for a particular Infisical project and environment."
>
Cloudflare Pages Integration
</CardTitle>
<FormControl
label="Cloudflare Pages API token"
errorText={accessKeyErrorText}
isError={accessKeyErrorText !== "" ?? false}
className="mx-6"
>
<Input placeholder="" value={accessKey} onChange={(e) => setAccessKey(e.target.value)} />
</FormControl>
<FormControl
label="Cloudflare Pages Account ID"
errorText={accountIdErrorText}
isError={accountIdErrorText !== "" ?? false}
className="mx-6"
>
<Input placeholder="" value={accountId} onChange={(e) => setAccountId(e.target.value)} />
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isFullWidth={false}
isLoading={isLoading}
>
Connect to Cloudflare Pages
</Button>
</Card>
</div>
);
}
CloudflarePagesIntegrationPage.requireAuth = true;
CloudflarePagesIntegrationPage.requireAuth = true;

View File

@@ -6,7 +6,15 @@ import queryString from "query-string";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { useCreateIntegration, useGetWorkspaceById } from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input, Select, SelectItem } from "../../../components/v2";
import {
Button,
Card,
CardTitle,
FormControl,
Input,
Select,
SelectItem
} from "../../../components/v2";
import {
useGetIntegrationAuthApps,
useGetIntegrationAuthById

View File

@@ -4,11 +4,11 @@ import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
// faCircleInfo
import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs
// faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
@@ -34,13 +34,16 @@ import {
useGetIntegrationAuthApps,
useGetIntegrationAuthById
} from "../../../hooks/api/integrationAuth";
import {
// useCreateWsEnvironment,
useGetWorkspaceById
import {
// useCreateWsEnvironment,
useGetWorkspaceById
} from "../../../hooks/api/workspace";
const initialSyncBehaviors = [
{ label: "No Import - Overwrite all values in Heroku", value: IntegrationSyncBehavior.OVERWRITE_TARGET },
{
label: "No Import - Overwrite all values in Heroku",
value: IntegrationSyncBehavior.OVERWRITE_TARGET
},
{ label: "Import - Prefer values from Heroku", value: IntegrationSyncBehavior.PREFER_TARGET },
{ label: "Import - Prefer values from Infisical", value: IntegrationSyncBehavior.PREFER_SOURCE }
];
@@ -51,7 +54,10 @@ const schema = yup.object({
targetApp: yup.string().required("Heroku app is required"),
initialSyncBehavior: yup
.string()
.oneOf(initialSyncBehaviors.map((b) => b.value), "Invalid initial sync behavior")
.oneOf(
initialSyncBehaviors.map((b) => b.value),
"Invalid initial sync behavior"
)
.required("Initial sync behavior is required")
});
@@ -59,7 +65,7 @@ type FormData = yup.InferType<typeof schema>;
export default function HerokuCreateIntegrationPage() {
const router = useRouter();
const { control, handleSubmit, setValue, watch } = useForm<FormData>({
resolver: yupResolver(schema),
defaultValues: {
@@ -70,7 +76,6 @@ export default function HerokuCreateIntegrationPage() {
const selectedSourceEnvironment = watch("selectedSourceEnvironment");
const { mutateAsync } = useCreateIntegration();
// const { mutateAsync: mutateAsyncEnv } = useCreateWsEnvironment();
@@ -78,19 +83,20 @@ export default function HerokuCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
// const { data: integrationAuthPipelineCouplings } = useGetIntegrationAuthHerokuPipelines({
// integrationAuthId: (integrationAuthId as string) ?? ""
// });
// const [uniquePipelines, setUniquePipelines] = useState<Pipeline[]>();
// const [selectedPipeline, setSelectedPipeline] = useState("");
// const [selectedPipelineApps, setSelectedPipelineApps] = useState<App[]>();
// const [integrationType, setIntegrationType] = useState("App");
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
@@ -110,7 +116,7 @@ export default function HerokuCreateIntegrationPage() {
// }))
// .map((obj) => JSON.stringify(obj))
// )).map((str) => JSON.parse(str)) as { pipelineId: string; name: string }[]
// [... (new Set())]
// setUniquePipelines(uniquePipelinesConst);
// if (uniquePipelinesConst) {
@@ -181,11 +187,7 @@ export default function HerokuCreateIntegrationPage() {
// }
// };
const onFormSubmit = async ({
secretPath,
targetApp,
initialSyncBehavior,
}: FormData) => {
const onFormSubmit = async ({ secretPath, targetApp, initialSyncBehavior }: FormData) => {
try {
if (!integrationAuth?.id) return;
@@ -207,13 +209,10 @@ export default function HerokuCreateIntegrationPage() {
} catch (err) {
console.error(err);
}
}
};
return integrationAuth &&
workspace &&
selectedSourceEnvironment &&
integrationAuthApps ? (
<div className="flex flex-col h-full w-full items-center justify-center">
return integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps ? (
<div className="flex h-full w-full flex-col items-center justify-center">
<Head>
<title>Set Up Heroku Integration</title>
<link rel="icon" href="/infisical.ico" />
@@ -280,11 +279,7 @@ export default function HerokuCreateIntegrationPage() {
defaultValue=""
name="secretPath"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secrets Path"
isError={Boolean(error)}
errorText={error?.message}
>
<FormControl label="Secrets Path" isError={Boolean(error)} errorText={error?.message}>
<Input {...field} placeholder="/" />
</FormControl>
)}
@@ -294,11 +289,7 @@ export default function HerokuCreateIntegrationPage() {
name="targetApp"
render={({ field: { onChange, ...field }, fieldState: { error } }) => {
return (
<FormControl
label="Heroku App"
errorText={error?.message}
isError={Boolean(error)}
>
<FormControl label="Heroku App" errorText={error?.message} isError={Boolean(error)}>
<Select
{...field}
onValueChange={(e) => {

View File

@@ -114,7 +114,9 @@ export default function RailwayCreateIntegrationPage() {
}
};
const filteredTargetServices = targetServices ? [ { name: "", serviceId: "none" }, ...targetServices ] : [ { name: "", serviceId: "none" } ];
const filteredTargetServices = targetServices
? [{ name: "", serviceId: "none" }, ...targetServices]
: [{ name: "", serviceId: "none" }];
return workspace &&
selectedSourceEnvironment &&
@@ -201,14 +203,14 @@ export default function RailwayCreateIntegrationPage() {
className="w-full border border-mineshaft-500"
isDisabled={targetServices.length === 0}
>
{filteredTargetServices.map((targetService) => (
<SelectItem
value={targetService.serviceId as string}
key={`target-service-${targetService.serviceId as string}`}
>
{targetService.name}
</SelectItem>
))}
{filteredTargetServices.map((targetService) => (
<SelectItem
value={targetService.serviceId as string}
key={`target-service-${targetService.serviceId as string}`}
>
{targetService.name}
</SelectItem>
))}
</Select>
</FormControl>
<Button

View File

@@ -45,7 +45,7 @@ type FormData = yup.InferType<typeof schema>;
export default function RenderCreateIntegrationPage() {
const router = useRouter();
const { mutateAsync } = useCreateIntegration();
const { control, handleSubmit, setValue, watch } = useForm<FormData>({
resolver: yupResolver(schema),
defaultValues: {
@@ -84,12 +84,8 @@ export default function RenderCreateIntegrationPage() {
}
}
}, [integrationAuthApps]);
const onFormSubmit = async ({
secretPath,
targetAppId,
shouldAutoRedeploy
}: FormData) => {
const onFormSubmit = async ({ secretPath, targetAppId, shouldAutoRedeploy }: FormData) => {
try {
if (!integrationAuth?.id) return;
@@ -115,13 +111,10 @@ export default function RenderCreateIntegrationPage() {
} catch (err) {
console.error(err);
}
}
};
return integrationAuth &&
workspace &&
selectedSourceEnvironment &&
integrationAuthApps ? (
<form
return integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps ? (
<form
onSubmit={handleSubmit(onFormSubmit)}
className="flex h-full w-full flex-col items-center justify-center"
>
@@ -191,11 +184,7 @@ export default function RenderCreateIntegrationPage() {
defaultValue=""
name="secretPath"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secrets Path"
isError={Boolean(error)}
errorText={error?.message}
>
<FormControl label="Secrets Path" isError={Boolean(error)} errorText={error?.message}>
<Input {...field} placeholder="/" />
</FormControl>
)}
@@ -256,7 +245,7 @@ export default function RenderCreateIntegrationPage() {
<Button
colorSchema="primary"
variant="outline_bg"
className="mb-8 ml-auto mr-6 w-min mt-4"
className="mb-8 ml-auto mr-6 mt-4 w-min"
size="sm"
type="submit"
isLoading={isLoading}

View File

@@ -9,7 +9,7 @@ export default function LoginPage() {
const { t } = useTranslation();
return (
<div className="flex min-h-screen max-h-screen overflow-y-auto flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6">
<div className="flex max-h-screen min-h-screen flex-col justify-center overflow-y-auto bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6">
<Head>
<title>{t("common.head-title", { title: t("login.title") })}</title>
<link rel="icon" href="/infisical.ico" />
@@ -23,7 +23,7 @@ export default function LoginPage() {
</div>
</Link>
<Login />
<div className="pb-28"/>
<div className="pb-28" />
</div>
);
}

View File

@@ -1,10 +1,10 @@
import { useEffect } from "react";
export default function LoginProviderError() {
useEffect(() => {
window.localStorage.setItem("PROVIDER_AUTH_ERROR", "err");
window.close();
}, [])
useEffect(() => {
window.localStorage.setItem("PROVIDER_AUTH_ERROR", "err");
window.close();
}, []);
return <div />
return <div />;
}

View File

@@ -1,16 +1,16 @@
import { useEffect } from "react";
import { useRouter } from "next/router"
import { useRouter } from "next/router";
import SecurityClient from "@app/components/utilities/SecurityClient";
export default function LoginProviderSuccess() {
const router = useRouter();
const router = useRouter();
useEffect(() => {
const { token } = router.query;
SecurityClient.setProviderAuthToken(token as string);
window.close();
}, [])
useEffect(() => {
const { token } = router.query;
SecurityClient.setProviderAuthToken(token as string);
window.close();
}, []);
return <div />
return <div />;
}

View File

@@ -2,30 +2,30 @@ import { useTranslation } from "react-i18next";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router"
import { useRouter } from "next/router";
import { LoginSSO } from "@app/views/Login";
export default function LoginSSOPage() {
const { t } = useTranslation();
const router = useRouter();
const token = router.query.token as string;
const { t } = useTranslation();
const router = useRouter();
const token = router.query.token as string;
return (
<div className="flex h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 ">
<Head>
<title>{t("common.head-title", { title: t("login.title") })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
<meta property="og:title" content={t("login.og-title") ?? ""} />
<meta name="og:description" content={t("login.og-description") ?? ""} />
</Head>
<Link href="/">
<div className="mb-4 mt-20 flex justify-center">
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" />
</div>
</Link>
<LoginSSO providerAuthToken={token} />
return (
<div className="flex h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 ">
<Head>
<title>{t("common.head-title", { title: t("login.title") })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
<meta property="og:title" content={t("login.og-title") ?? ""} />
<meta name="og:description" content={t("login.og-description") ?? ""} />
</Head>
<Link href="/">
<div className="mb-4 mt-20 flex justify-center">
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical logo" />
</div>
</Link>
<LoginSSO providerAuthToken={token} />
</div>
);
}
);
}

View File

@@ -18,4 +18,4 @@ export default function SettingsOrg() {
);
}
SettingsOrg.requireAuth = true;
SettingsOrg.requireAuth = true;

View File

@@ -454,7 +454,12 @@ const LearningItemSquare = ({
};
const formSchema = yup.object({
name: yup.string().required().label("Project Name").trim().max(64, "Too long, maximum length is 64 characters"),
name: yup
.string()
.required()
.label("Project Name")
.trim()
.max(64, "Too long, maximum length is 64 characters"),
addMembers: yup.bool().required().label("Add Members")
});

View File

@@ -5,16 +5,16 @@ import Head from "next/head";
import { NonePage } from "@app/views/Org/NonePage";
export default function NoneOrganization() {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.org.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<NonePage />
</>
);
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.org.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<NonePage />
</>
);
}
NoneOrganization.requireAuth = true;
NoneOrganization.requireAuth = true;

View File

@@ -308,64 +308,58 @@ export default function PasswordReset() {
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div
className={`${passwordErrorNoNumOrSpecialChar ? "text-gray-400" : "text-gray-600"} text-sm`}
className={`${
passwordErrorNoNumOrSpecialChar ? "text-gray-400" : "text-gray-600"
} text-sm`}
>
at least 1 number or special character
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
{passwordErrorRepeatedChar ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div
className={`${
passwordErrorRepeatedChar ? "text-gray-400" : "text-gray-600"
} text-sm`}
>
at most 3 repeated, consecutive characters
</div>
{passwordErrorRepeatedChar ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div
className={`${passwordErrorRepeatedChar ? "text-gray-400" : "text-gray-600"} text-sm`}
>
at most 3 repeated, consecutive characters
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
{passwordErrorEscapeChar ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div
className={`${
passwordErrorEscapeChar ? "text-gray-400" : "text-gray-600"
} text-sm`}
>
No escape characters allowed.
</div>
{passwordErrorEscapeChar ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div
className={`${passwordErrorEscapeChar ? "text-gray-400" : "text-gray-600"} text-sm`}
>
No escape characters allowed.
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
{passwordErrorLowEntropy ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div
className={`${passwordErrorLowEntropy ? "text-gray-400" : "text-gray-600"} text-sm`}
>
Password contains personal info.
</div>
{passwordErrorLowEntropy ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div
className={`${passwordErrorLowEntropy ? "text-gray-400" : "text-gray-600"} text-sm`}
>
Password contains personal info.
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
{passwordErrorBreached ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div
className={`${
passwordErrorBreached ? "text-gray-400" : "text-gray-600"
} text-sm`}
>
Password was found in a data breach.
</div>
{passwordErrorBreached ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
)}
<div className={`${passwordErrorBreached ? "text-gray-400" : "text-gray-600"} text-sm`}>
Password was found in a data breach.
</div>
</div>
</div>
) : (

View File

@@ -7,7 +7,7 @@ export default function PersonalSettings() {
const { t } = useTranslation();
return (
<div className="bg-bunker-800 text-white h-full">
<div className="h-full bg-bunker-800 text-white">
<Head>
<title>{t("common.head-title", { title: t("settings.personal.title") })}</title>
<link rel="icon" href="/infisical.ico" />

View File

@@ -4,18 +4,18 @@ import Head from "next/head";
import { IPAllowlistPage } from "@app/views/Project/IPAllowListPage";
const ProjectAllowlist = () => {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<IPAllowlistPage />
</>
);
}
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<IPAllowlistPage />
</>
);
};
export default ProjectAllowlist;
ProjectAllowlist.requireAuth = true;
ProjectAllowlist.requireAuth = true;

View File

@@ -4,20 +4,20 @@ import Head from "next/head";
import { AuditLogsPage } from "@app/views/Project/AuditLogsPage";
const Logs = () => {
const { t } = useTranslation();
const { t } = useTranslation();
return (
<div className="h-full bg-bunker-800">
<Head>
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
</Head>
<AuditLogsPage />
return (
<div className="h-full bg-bunker-800">
<Head>
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
</Head>
<AuditLogsPage />
</div>
);
}
);
};
export default Logs;
Logs.requireAuth = true;
Logs.requireAuth = true;

View File

@@ -7,20 +7,25 @@ import Image from "next/image";
*/
export default function RequestNewInvite() {
return (
<div className="bg-bunker-700 md:h-screen flex flex-col justify-between">
<div className="flex flex-col justify-between bg-bunker-700 md:h-screen">
<Head>
<title>Request a New Invite</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<div className="flex flex-col items-center justify-center text-bunker-200 h-screen w-screen mt-8">
<div className="mt-8 flex h-screen w-screen flex-col items-center justify-center text-bunker-200">
<p className="text-4xl text-primary-100">Oops, your invite has expired.</p>
<p className="text-lg my-4">Ask your admin for a new one.</p>
<p className="text-sm text-bunker-400 max-w-xs px-7 text-center leading-tight">
<span className="bg-primary-500/40 text-black px-1 rounded-md">Note:</span> If it still
<p className="my-4 text-lg">Ask your admin for a new one.</p>
<p className="max-w-xs px-7 text-center text-sm leading-tight text-bunker-400">
<span className="rounded-md bg-primary-500/40 px-1 text-black">Note:</span> If it still
doesn&apos;t work, please reach out to us at support@infisical.com
</p>
<div className="">
<Image src="/images/invitation-expired.svg" height={500} width={800} alt="invitation expired illustration" />
<Image
src="/images/invitation-expired.svg"
height={500}
width={800}
alt="invitation expired illustration"
/>
</div>
</div>
</div>

View File

@@ -1,15 +1,18 @@
import { useEffect } from "react";
import { useRouter } from "next/router"
import { useRouter } from "next/router";
export default function SecretScanning() {
const router = useRouter();
useEffect(()=>{
router.push(`${router.asPath.split("secret-scanning")[0]}/org/${localStorage.getItem("orgData.id")}/secret-scanning${router.asPath.split("secret-scanning")[1]}`)
}, [])
useEffect(() => {
router.push(
`${router.asPath.split("secret-scanning")[0]}/org/${localStorage.getItem(
"orgData.id"
)}/secret-scanning${router.asPath.split("secret-scanning")[1]}`
);
}, []);
return <div/>;
return <div />;
}
SecretScanning.requireAuth = true;
SecretScanning.requireAuth = true;

View File

@@ -1,28 +1,28 @@
import { useTranslation } from "react-i18next";
import Head from "next/head";
import Image from "next/image";
import { useRouter } from "next/router"
import { useRouter } from "next/router";
import { SignupSSO } from "@app/views/Signup";
export default function SignupSSOPage() {
const { t } = useTranslation();
const router = useRouter();
const token = router.query.token as string;
const { t } = useTranslation();
const router = useRouter();
const token = router.query.token as string;
return (
<div className="flex min-h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 ">
<Head>
<title>{t("common.head-title", { title: t("signup.title") })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
<meta property="og:title" content={t("signup.og-title") as string} />
<meta name="og:description" content={t("signup.og-description") as string} />
</Head>
<div className="mb-4 mt-20 flex justify-center">
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical Logo" />
</div>
<SignupSSO providerAuthToken={token} />
</div>
);
}
return (
<div className="flex min-h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 ">
<Head>
<title>{t("common.head-title", { title: t("signup.title") })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
<meta property="og:title" content={t("signup.og-title") as string} />
<meta name="og:description" content={t("signup.og-description") as string} />
</Head>
<div className="mb-4 mt-20 flex justify-center">
<Image src="/images/gradientLogo.svg" height={90} width={120} alt="Infisical Logo" />
</div>
<SignupSSO providerAuthToken={token} />
</div>
);
}

View File

@@ -59,7 +59,10 @@ export default function VerifyEmail() {
</div>
</Link>
{step === 1 && (
<form onSubmit={onSubmit} className="h-7/12 mx-auto w-full max-w-md rounded-xl bg-bunker px-6 py-4 pt-8 drop-shadow-xl">
<form
onSubmit={onSubmit}
className="h-7/12 mx-auto w-full max-w-md rounded-xl bg-bunker px-6 py-4 pt-8 drop-shadow-xl"
>
<p className="mx-auto mb-6 flex w-max justify-center text-2xl font-semibold text-bunker-100 md:text-3xl">
Forgot your password?
</p>
@@ -81,7 +84,13 @@ export default function VerifyEmail() {
</div>
<div className="mx-auto mt-4 flex max-h-20 w-full max-w-md flex-col items-center justify-center text-sm md:p-2">
<div className="text-l m-8 mt-6 px-8 py-3 text-lg">
<Button type="submit" text="Continue" size="lg" onButtonPressed={() => {}} loading={loading} />
<Button
type="submit"
text="Continue"
size="lg"
onButtonPressed={() => {}}
loading={loading}
/>
</div>
</div>
</form>

Some files were not shown because too many files have changed in this diff Show More