mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 06:45:28 +00:00
feat(infisical-pg): changed frontend api types _id to normal id
This commit is contained in:
+28
-17
@@ -71,7 +71,7 @@ export const PreviewSection = () => {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
{subscription &&
|
||||
@@ -79,10 +79,15 @@ export const PreviewSection = () => {
|
||||
subscription?.slug !== "pro" &&
|
||||
subscription?.slug !== "pro-annual" && (
|
||||
<div className="flex flex-row space-x-6">
|
||||
<div className="p-4 rounded-lg flex-1 border border-primary/40 mb-6 flex items-center bg-primary/10">
|
||||
<div className="mb-6 flex flex-1 items-center rounded-lg border border-primary/40 bg-primary/10 p-4">
|
||||
<div className="flex-1">
|
||||
<h2 className="text-xl font-medium text-mineshaft-100">Unleash the full power of <span className="text-transparent font-semibold bg-clip-text bg-gradient-to-r from-primary-500 to-yellow">Infisical</span></h2>
|
||||
<p className="text-gray-400 mt-4">
|
||||
<h2 className="text-xl font-medium text-mineshaft-100">
|
||||
Unleash the full power of{" "}
|
||||
<span className="bg-gradient-to-r from-primary-500 to-yellow bg-clip-text font-semibold text-transparent">
|
||||
Infisical
|
||||
</span>
|
||||
</h2>
|
||||
<p className="mt-4 text-gray-400">
|
||||
Get unlimited members, projects, RBAC, smart alerts, and so much more.
|
||||
</p>
|
||||
</div>
|
||||
@@ -98,23 +103,29 @@ export const PreviewSection = () => {
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</div>
|
||||
<div className="flex flex-col max-w-[12rem] w-full items-start border border-mineshaft-600 mb-6 flex items-center bg-mineshaft-800 p-4 rounded-lg">
|
||||
<div className="mb-4 flex justify-center w-full font-semibold text-mineshaft-200">Want to learn more? </div>
|
||||
<div className="flex justify-center w-full">
|
||||
<div className="mb-6 flex flex w-full max-w-[12rem] flex-col items-start items-center rounded-lg border border-mineshaft-600 bg-mineshaft-800 p-4">
|
||||
<div className="mb-4 flex w-full justify-center font-semibold text-mineshaft-200">
|
||||
Want to learn more?{" "}
|
||||
</div>
|
||||
<div className="flex w-full justify-center">
|
||||
<Link href="https://infisical.com/schedule-demo">
|
||||
<span className="rounded-full px-4 py-2 bg-mineshaft-600 border border-mineshaft-500 hover:bg-primary/10 hover:border-primary/40 duration-200 cursor-pointer">
|
||||
Book a demo <FontAwesomeIcon icon={faArrowUpRightFromSquare} className="text-xs mb-[0.06rem] ml-1"/>
|
||||
<span className="cursor-pointer rounded-full border border-mineshaft-500 bg-mineshaft-600 px-4 py-2 duration-200 hover:border-primary/40 hover:bg-primary/10">
|
||||
Book a demo{" "}
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowUpRightFromSquare}
|
||||
className="mb-[0.06rem] ml-1 text-xs"
|
||||
/>
|
||||
</span>
|
||||
</Link>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!isLoading && subscription && data && (
|
||||
<div className="flex mb-6">
|
||||
<div className="p-4 bg-mineshaft-900 rounded-lg flex-1 mr-4 border border-mineshaft-600">
|
||||
<div className="mb-6 flex">
|
||||
<div className="mr-4 flex-1 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<p className="mb-2 text-gray-400">Current plan</p>
|
||||
<p className="text-2xl text-mineshaft-50 font-semibold mb-8">
|
||||
<p className="mb-8 text-2xl font-semibold text-mineshaft-50">
|
||||
{`${formatPlanSlug(subscription.slug)} ${
|
||||
subscription.status === "trialing" ? "(Trial)" : ""
|
||||
}`}
|
||||
@@ -136,17 +147,17 @@ export const PreviewSection = () => {
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</div>
|
||||
<div className="p-4 bg-mineshaft-900 rounded-lg flex-1 border border-mineshaft-600 mr-4">
|
||||
<div className="mr-4 flex-1 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<p className="mb-2 text-gray-400">Price</p>
|
||||
<p className="text-2xl mb-8 text-mineshaft-50 font-semibold">
|
||||
<p className="mb-8 text-2xl font-semibold text-mineshaft-50">
|
||||
{subscription.status === "trialing"
|
||||
? "$0.00 / month"
|
||||
: `${formatAmount(data.amount)} / ${data.interval}`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 bg-mineshaft-900 rounded-lg flex-1 border border-mineshaft-600">
|
||||
<div className="flex-1 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<p className="mb-2 text-gray-400">Subscription renews on</p>
|
||||
<p className="text-2xl mb-8 text-mineshaft-50 font-semibold">
|
||||
<p className="mb-8 text-2xl font-semibold text-mineshaft-50">
|
||||
{formatDate(data.currentPeriodEnd)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
+5
-5
@@ -24,7 +24,7 @@ export const CompanyNameSection = () => {
|
||||
},
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
const { data } = useGetOrgBillingDetails(currentOrg?._id ?? "");
|
||||
const { data } = useGetOrgBillingDetails(currentOrg?.id ?? "");
|
||||
const { mutateAsync, isLoading } = useUpdateOrgBillingDetails();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -37,11 +37,11 @@ export const CompanyNameSection = () => {
|
||||
|
||||
const onFormSubmit = async ({ name }: { name: string }) => {
|
||||
try {
|
||||
if (!currentOrg?._id) return;
|
||||
if (!currentOrg?.id) return;
|
||||
if (name === "") return;
|
||||
await mutateAsync({
|
||||
name,
|
||||
organizationId: currentOrg._id
|
||||
organizationId: currentOrg.id
|
||||
});
|
||||
|
||||
createNotification({
|
||||
@@ -60,9 +60,9 @@ export const CompanyNameSection = () => {
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600"
|
||||
className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
||||
>
|
||||
<h2 className="text-xl font-semibold flex-1 text-mineshaft-100 mb-8">Business name</h2>
|
||||
<h2 className="mb-8 flex-1 text-xl font-semibold text-mineshaft-100">Business name</h2>
|
||||
<div className="max-w-md">
|
||||
<Controller
|
||||
defaultValue=""
|
||||
|
||||
+5
-5
@@ -24,7 +24,7 @@ export const InvoiceEmailSection = () => {
|
||||
},
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
const { data } = useGetOrgBillingDetails(currentOrg?._id ?? "");
|
||||
const { data } = useGetOrgBillingDetails(currentOrg?.id ?? "");
|
||||
const { mutateAsync, isLoading } = useUpdateOrgBillingDetails();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -37,12 +37,12 @@ export const InvoiceEmailSection = () => {
|
||||
|
||||
const onFormSubmit = async ({ email }: { email: string }) => {
|
||||
try {
|
||||
if (!currentOrg?._id) return;
|
||||
if (!currentOrg?.id) return;
|
||||
if (email === "") return;
|
||||
|
||||
await mutateAsync({
|
||||
email,
|
||||
organizationId: currentOrg._id
|
||||
organizationId: currentOrg.id
|
||||
});
|
||||
|
||||
createNotification({
|
||||
@@ -61,9 +61,9 @@ export const InvoiceEmailSection = () => {
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600"
|
||||
className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
||||
>
|
||||
<h2 className="text-xl font-semibold flex-1 text-white mb-8">Invoice email recipient</h2>
|
||||
<h2 className="mb-8 flex-1 text-xl font-semibold text-white">Invoice email recipient</h2>
|
||||
<div className="max-w-md">
|
||||
<Controller
|
||||
defaultValue=""
|
||||
|
||||
+5
-5
@@ -13,9 +13,9 @@ export const PmtMethodsSection = () => {
|
||||
const { mutateAsync, isLoading } = useAddOrgPmtMethod();
|
||||
|
||||
const handleAddPmtMethodBtnClick = async () => {
|
||||
if (!currentOrg?._id) return;
|
||||
if (!currentOrg?.id) return;
|
||||
const url = await mutateAsync({
|
||||
organizationId: currentOrg._id,
|
||||
organizationId: currentOrg.id,
|
||||
success_url: window.location.href,
|
||||
cancel_url: window.location.href
|
||||
});
|
||||
@@ -24,9 +24,9 @@ export const PmtMethodsSection = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600">
|
||||
<div className="flex items-center mb-8">
|
||||
<h2 className="text-xl font-semibold flex-1 text-white">Payment methods</h2>
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-8 flex items-center">
|
||||
<h2 className="flex-1 text-xl font-semibold text-white">Payment methods</h2>
|
||||
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Billing}>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
|
||||
+6
-6
@@ -19,13 +19,13 @@ import { useDeleteOrgPmtMethod, useGetOrgPmtMethods } from "@app/hooks/api";
|
||||
|
||||
export const PmtMethodsTable = () => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { data, isLoading } = useGetOrgPmtMethods(currentOrg?._id ?? "");
|
||||
const { data, isLoading } = useGetOrgPmtMethods(currentOrg?.id ?? "");
|
||||
const deleteOrgPmtMethod = useDeleteOrgPmtMethod();
|
||||
|
||||
const handleDeletePmtMethodBtnClick = async (pmtMethodId: string) => {
|
||||
if (!currentOrg?._id) return;
|
||||
if (!currentOrg?.id) return;
|
||||
await deleteOrgPmtMethod.mutateAsync({
|
||||
organizationId: currentOrg._id,
|
||||
organizationId: currentOrg.id,
|
||||
pmtMethodId
|
||||
});
|
||||
};
|
||||
@@ -46,8 +46,8 @@ export const PmtMethodsTable = () => {
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data?.length > 0 &&
|
||||
data.map(({ _id, brand, exp_month, exp_year, funding, last4 }) => (
|
||||
<Tr key={`pmt-method-${_id}`} className="h-10">
|
||||
data.map(({ id, brand, exp_month, exp_year, funding, last4 }) => (
|
||||
<Tr key={`pmt-method-${id}`} className="h-10">
|
||||
<Td>{brand.charAt(0).toUpperCase() + brand.slice(1)}</Td>
|
||||
<Td>{funding.charAt(0).toUpperCase() + funding.slice(1)}</Td>
|
||||
<Td>{last4}</Td>
|
||||
@@ -60,7 +60,7 @@ export const PmtMethodsTable = () => {
|
||||
{(isAllowed) => (
|
||||
<IconButton
|
||||
onClick={async () => {
|
||||
await handleDeletePmtMethodBtnClick(_id);
|
||||
await handleDeletePmtMethodBtnClick(id);
|
||||
}}
|
||||
size="lg"
|
||||
isDisabled={!isAllowed}
|
||||
|
||||
+96
-109
@@ -1,4 +1,4 @@
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as yup from "yup";
|
||||
|
||||
@@ -69,10 +69,12 @@ const taxIDTypes = [
|
||||
{ label: "South Africa VAT", value: "za_vat" }
|
||||
];
|
||||
|
||||
const schema = yup.object({
|
||||
const schema = yup
|
||||
.object({
|
||||
type: yup.string().required("Tax ID type is required"),
|
||||
value: yup.string().required("Tax ID value is required")
|
||||
}).required();
|
||||
})
|
||||
.required();
|
||||
|
||||
export type AddTaxIDFormData = yup.InferType<typeof schema>;
|
||||
|
||||
@@ -82,115 +84,100 @@ type Props = {
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["addTaxID"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
export const TaxIDModal = ({
|
||||
popUp,
|
||||
handlePopUpClose,
|
||||
handlePopUpToggle
|
||||
}: Props) => {
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { currentOrg } = useOrganization();
|
||||
const addOrgTaxId = useAddOrgTaxId();
|
||||
export const TaxIDModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => {
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { currentOrg } = useOrganization();
|
||||
const addOrgTaxId = useAddOrgTaxId();
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting }
|
||||
} = useForm<AddTaxIDFormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting }
|
||||
} = useForm<AddTaxIDFormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
|
||||
const onTaxIDModalSubmit = async ({ type, value }: AddTaxIDFormData) => {
|
||||
try {
|
||||
if (!currentOrg?._id) return;
|
||||
await addOrgTaxId.mutateAsync({
|
||||
organizationId: currentOrg._id,
|
||||
type,
|
||||
value
|
||||
});
|
||||
const onTaxIDModalSubmit = async ({ type, value }: AddTaxIDFormData) => {
|
||||
try {
|
||||
if (!currentOrg?.id) return;
|
||||
await addOrgTaxId.mutateAsync({
|
||||
organizationId: currentOrg.id,
|
||||
type,
|
||||
value
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully added Tax ID",
|
||||
type: "success"
|
||||
});
|
||||
handlePopUpClose("addTaxID");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to add Tax ID",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
createNotification({
|
||||
text: "Successfully added Tax ID",
|
||||
type: "success"
|
||||
});
|
||||
handlePopUpClose("addTaxID");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to add Tax ID",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.addTaxID?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("addTaxID", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Add Tax ID">
|
||||
<form onSubmit={handleSubmit(onTaxIDModalSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="type"
|
||||
defaultValue="eu_vat"
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Type"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Select
|
||||
defaultValue={field.value}
|
||||
{...field}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
className="w-full"
|
||||
>
|
||||
{taxIDTypes.map(({ label, value }) => (
|
||||
<SelectItem value={String(value || "")} key={label}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="value"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Value"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder="DE000000000"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.addTaxID?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("addTaxID", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Add Tax ID">
|
||||
<form onSubmit={handleSubmit(onTaxIDModalSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="type"
|
||||
defaultValue="eu_vat"
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl label="Type" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Select
|
||||
defaultValue={field.value}
|
||||
{...field}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
className="w-full"
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
{taxIDTypes.map(({ label, value }) => (
|
||||
<SelectItem value={String(value || "")} key={label}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="value"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl label="Value" isError={Boolean(error)} errorText={error?.message}>
|
||||
<Input {...field} placeholder="DE000000000" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
+6
-6
@@ -72,13 +72,13 @@ const taxIDTypeLabelMap: { [key: string]: string } = {
|
||||
|
||||
export const TaxIDTable = () => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { data, isLoading } = useGetOrgTaxIds(currentOrg?._id ?? "");
|
||||
const { data, isLoading } = useGetOrgTaxIds(currentOrg?.id ?? "");
|
||||
const deleteOrgTaxId = useDeleteOrgTaxId();
|
||||
|
||||
const handleDeleteTaxIdBtnClick = async (taxId: string) => {
|
||||
if (!currentOrg?._id) return;
|
||||
if (!currentOrg?.id) return;
|
||||
await deleteOrgTaxId.mutateAsync({
|
||||
organizationId: currentOrg._id,
|
||||
organizationId: currentOrg.id,
|
||||
taxId
|
||||
});
|
||||
};
|
||||
@@ -97,8 +97,8 @@ export const TaxIDTable = () => {
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data?.length > 0 &&
|
||||
data.map(({ _id, type, value }) => (
|
||||
<Tr key={`tax-id-${_id}`} className="h-10">
|
||||
data.map(({ id, type, value }) => (
|
||||
<Tr key={`tax-id-${id}`} className="h-10">
|
||||
<Td>{taxIDTypeLabelMap[type]}</Td>
|
||||
<Td>{value}</Td>
|
||||
<Td>
|
||||
@@ -109,7 +109,7 @@ export const TaxIDTable = () => {
|
||||
{(isAllowed) => (
|
||||
<IconButton
|
||||
onClick={async () => {
|
||||
await handleDeleteTaxIdBtnClick(_id);
|
||||
await handleDeleteTaxIdBtnClick(id);
|
||||
}}
|
||||
size="lg"
|
||||
colorSchema="danger"
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ import { useGetOrgInvoices } from "@app/hooks/api";
|
||||
|
||||
export const InvoicesTable = () => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { data, isLoading } = useGetOrgInvoices(currentOrg?._id ?? "");
|
||||
const { data, isLoading } = useGetOrgInvoices(currentOrg?.id ?? "");
|
||||
return (
|
||||
<TableContainer className="mt-8">
|
||||
<Table>
|
||||
@@ -35,7 +35,7 @@ export const InvoicesTable = () => {
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data?.length > 0 &&
|
||||
data.map(({ _id, created, paid, number, total, invoice_pdf }) => {
|
||||
data.map(({ id, created, paid, number, total, invoice_pdf }) => {
|
||||
const formattedTotal = (Math.floor(total) / 100).toLocaleString("en-US", {
|
||||
style: "currency",
|
||||
currency: "USD"
|
||||
@@ -47,7 +47,7 @@ export const InvoicesTable = () => {
|
||||
const formattedDate: string = `${day}/${month}/${year}`;
|
||||
|
||||
return (
|
||||
<Tr key={`invoice-${_id}`} className="h-10">
|
||||
<Tr key={`invoice-${id}`} className="h-10">
|
||||
<Td>{number}</Td>
|
||||
<Td>{formattedDate}</Td>
|
||||
<Td>{paid ? "Paid" : "Not Paid"}</Td>
|
||||
|
||||
+47
-52
@@ -12,57 +12,52 @@ import {
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import {
|
||||
useGetOrgLicenses
|
||||
} from "@app/hooks/api";
|
||||
import { useGetOrgLicenses } from "@app/hooks/api";
|
||||
|
||||
export const LicensesSection = () => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { data, isLoading } = useGetOrgLicenses(currentOrg?.id ?? "");
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<h2 className="mb-8 flex-1 text-xl font-semibold text-white">Enterprise licenses</h2>
|
||||
<TableContainer className="mt-4">
|
||||
<Table>
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th>License Key</Th>
|
||||
<Th>Status</Th>
|
||||
<Th>Issued Date</Th>
|
||||
<Th>Expiry Date</Th>
|
||||
</Tr>
|
||||
</THead>
|
||||
<TBody>
|
||||
{!isLoading && data && data?.length > 0 && data.map(({
|
||||
id,
|
||||
licenseKey,
|
||||
isActivated,
|
||||
createdAt,
|
||||
expiresAt
|
||||
}) => {
|
||||
const formattedCreatedAt = new Date(createdAt).toISOString().split("T")[0];
|
||||
const formattedExpiresAt = new Date(expiresAt).toISOString().split("T")[0];
|
||||
return (
|
||||
<Tr key={`license-${id}`} className="h-10">
|
||||
<Td>{licenseKey}</Td>
|
||||
<Td>{isActivated ? "Active" : "Inactive"}</Td>
|
||||
<Td>{formattedCreatedAt}</Td>
|
||||
<Td>{formattedExpiresAt}</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
{isLoading && <TableSkeleton columns={4} innerKey="licenses" />}
|
||||
{!isLoading && data && data?.length === 0 && (
|
||||
<Tr>
|
||||
<Td colSpan={4}>
|
||||
<EmptyState title="No enterprise licenses on file" icon={faFileContract} />
|
||||
</Td>
|
||||
</Tr>
|
||||
)}
|
||||
</TBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const { currentOrg } = useOrganization();
|
||||
const { data, isLoading } = useGetOrgLicenses(currentOrg?.id ?? "");
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<h2 className="mb-8 flex-1 text-xl font-semibold text-white">Enterprise licenses</h2>
|
||||
<TableContainer className="mt-4">
|
||||
<Table>
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th>License Key</Th>
|
||||
<Th>Status</Th>
|
||||
<Th>Issued Date</Th>
|
||||
<Th>Expiry Date</Th>
|
||||
</Tr>
|
||||
</THead>
|
||||
<TBody>
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data?.length > 0 &&
|
||||
data.map(({ id, licenseKey, isActivated, createdAt, expiresAt }) => {
|
||||
const formattedCreatedAt = new Date(createdAt).toISOString().split("T")[0];
|
||||
const formattedExpiresAt = new Date(expiresAt).toISOString().split("T")[0];
|
||||
return (
|
||||
<Tr key={`license-${id}`} className="h-10">
|
||||
<Td>{licenseKey}</Td>
|
||||
<Td>{isActivated ? "Active" : "Inactive"}</Td>
|
||||
<Td>{formattedCreatedAt}</Td>
|
||||
<Td>{formattedExpiresAt}</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
{isLoading && <TableSkeleton columns={4} innerKey="licenses" />}
|
||||
{!isLoading && data && data?.length === 0 && (
|
||||
<Tr>
|
||||
<Td colSpan={4}>
|
||||
<EmptyState title="No enterprise licenses on file" icon={faFileContract} />
|
||||
</Td>
|
||||
</Tr>
|
||||
)}
|
||||
</TBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
+11
-11
@@ -82,9 +82,9 @@ export const OrgSSOSection = (): JSX.Element => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600">
|
||||
<div className="flex items-center mb-8">
|
||||
<h2 className="text-xl font-semibold flex-1 text-white">SAML SSO Configuration</h2>
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-8 flex items-center">
|
||||
<h2 className="flex-1 text-xl font-semibold text-white">SAML SSO Configuration</h2>
|
||||
{!isLoading && (
|
||||
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Sso}>
|
||||
{(isAllowed) => (
|
||||
@@ -117,24 +117,24 @@ export const OrgSSOSection = (): JSX.Element => {
|
||||
</div>
|
||||
)}
|
||||
<div className="mb-4">
|
||||
<h3 className="text-mineshaft-400 text-sm">SSO identifier</h3>
|
||||
<p className="text-gray-400 text-md">{data && data.id !== "" ? data.id : "-"}</p>
|
||||
<h3 className="text-sm text-mineshaft-400">SSO identifier</h3>
|
||||
<p className="text-md text-gray-400">{data && data.id !== "" ? data.id : "-"}</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-mineshaft-400 text-sm">Type</h3>
|
||||
<p className="text-gray-400 text-md">
|
||||
<h3 className="text-sm text-mineshaft-400">Type</h3>
|
||||
<p className="text-md text-gray-400">
|
||||
{data && data.authProvider !== "" ? ssoAuthProviderMap[data.authProvider] : "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-mineshaft-400 text-sm">Entrypoint</h3>
|
||||
<p className="text-gray-400 text-md">
|
||||
<h3 className="text-sm text-mineshaft-400">Entrypoint</h3>
|
||||
<p className="text-md text-gray-400">
|
||||
{data && data.entryPoint !== "" ? data.entryPoint : "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-mineshaft-400 text-sm">Issuer</h3>
|
||||
<p className="text-gray-400 text-md">{data && data.issuer !== "" ? data.issuer : "-"}</p>
|
||||
<h3 className="text-sm text-mineshaft-400">Issuer</h3>
|
||||
<p className="text-md text-gray-400">{data && data.issuer !== "" ? data.issuer : "-"}</p>
|
||||
</div>
|
||||
<SSOModal
|
||||
popUp={popUp}
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as yup from "yup";
|
||||
|
||||
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
Select,
|
||||
SelectItem,
|
||||
TextArea} from "@app/components/v2";
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
Select,
|
||||
SelectItem,
|
||||
TextArea
|
||||
} from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import {
|
||||
useCreateSSOConfig,
|
||||
useGetSSOConfig,
|
||||
useUpdateSSOConfig
|
||||
} from "@app/hooks/api";
|
||||
import { useCreateSSOConfig, useGetSSOConfig, useUpdateSSOConfig } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
enum AuthProvider {
|
||||
OKTA_SAML = "okta-saml",
|
||||
AZURE_SAML = "azure-saml",
|
||||
JUMPCLOUD_SAML = "jumpcloud-saml"
|
||||
OKTA_SAML = "okta-saml",
|
||||
AZURE_SAML = "azure-saml",
|
||||
JUMPCLOUD_SAML = "jumpcloud-saml"
|
||||
}
|
||||
|
||||
const ssoAuthProviders = [
|
||||
{ label: "Okta SAML", value: AuthProvider.OKTA_SAML },
|
||||
{ label: "Azure SAML", value: AuthProvider.AZURE_SAML },
|
||||
{ label: "JumpCloud SAML", value: AuthProvider.JUMPCLOUD_SAML }
|
||||
{ label: "Okta SAML", value: AuthProvider.OKTA_SAML },
|
||||
{ label: "Azure SAML", value: AuthProvider.AZURE_SAML },
|
||||
{ label: "JumpCloud SAML", value: AuthProvider.JUMPCLOUD_SAML }
|
||||
];
|
||||
|
||||
const schema = yup.object({
|
||||
const schema = yup
|
||||
.object({
|
||||
authProvider: yup.string().required("SSO Type is required"),
|
||||
entryPoint: yup.string().required("IdP entrypoint is required"),
|
||||
issuer: yup.string().required("Issuer string is required"),
|
||||
cert: yup.string().required("IdP's public signing certificate is required")
|
||||
}).required();
|
||||
})
|
||||
.required();
|
||||
|
||||
export type AddSSOFormData = yup.InferType<typeof schema>;
|
||||
|
||||
@@ -48,243 +47,221 @@ type Props = {
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["addSSO"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
export const SSOModal = ({
|
||||
popUp,
|
||||
handlePopUpClose,
|
||||
handlePopUpToggle
|
||||
}: Props) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { mutateAsync: createMutateAsync, isLoading: createIsLoading } = useCreateSSOConfig();
|
||||
const { mutateAsync: updateMutateAsync, isLoading: updateIsLoading } = useUpdateSSOConfig();
|
||||
const { data } = useGetSSOConfig(currentOrg?.id ?? "");
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset,
|
||||
watch,
|
||||
} = useForm<AddSSOFormData>({
|
||||
defaultValues: {
|
||||
authProvider: AuthProvider.OKTA_SAML
|
||||
},
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
reset({
|
||||
authProvider: data?.authProvider ?? "",
|
||||
entryPoint: data?.entryPoint ?? "",
|
||||
issuer: data?.issuer ?? "",
|
||||
cert: data?.cert ?? ""
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const onSSOModalSubmit = async ({
|
||||
authProvider,
|
||||
entryPoint,
|
||||
issuer,
|
||||
cert
|
||||
}: AddSSOFormData) => {
|
||||
try {
|
||||
if (!currentOrg) return;
|
||||
|
||||
if (!data) {
|
||||
await createMutateAsync({
|
||||
organizationId: currentOrg.id,
|
||||
authProvider,
|
||||
isActive: false,
|
||||
entryPoint,
|
||||
issuer,
|
||||
cert
|
||||
});
|
||||
} else {
|
||||
await updateMutateAsync({
|
||||
organizationId: currentOrg.id,
|
||||
authProvider,
|
||||
isActive: false,
|
||||
entryPoint,
|
||||
issuer,
|
||||
cert
|
||||
});
|
||||
}
|
||||
export const SSOModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { mutateAsync: createMutateAsync, isLoading: createIsLoading } = useCreateSSOConfig();
|
||||
const { mutateAsync: updateMutateAsync, isLoading: updateIsLoading } = useUpdateSSOConfig();
|
||||
const { data } = useGetSSOConfig(currentOrg?.id ?? "");
|
||||
|
||||
handlePopUpClose("addSSO");
|
||||
const { control, handleSubmit, reset, watch } = useForm<AddSSOFormData>({
|
||||
defaultValues: {
|
||||
authProvider: AuthProvider.OKTA_SAML
|
||||
},
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: `Successfully ${!data ? "added" : "updated"} SAML SSO configuration`,
|
||||
type: "success"
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: `Failed to ${!data ? "add" : "update"} SAML SSO configuration`,
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
reset({
|
||||
authProvider: data?.authProvider ?? "",
|
||||
entryPoint: data?.entryPoint ?? "",
|
||||
issuer: data?.issuer ?? "",
|
||||
cert: data?.cert ?? ""
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const renderLabels = (authProvider: string) => {
|
||||
switch (authProvider){
|
||||
case AuthProvider.OKTA_SAML:
|
||||
return ({
|
||||
acsUrl: "Single sign-on URL",
|
||||
entityId: "Audience URI (SP Entity ID)",
|
||||
entryPoint: "Identity Provider Single Sign-On URL",
|
||||
entryPointPlaceholder: "https://your-domain.okta.com/app/app-name/xxx/sso/saml",
|
||||
issuer: "Identity Provider Issuer",
|
||||
issuerPlaceholder: "http://www.okta.com/xxx"
|
||||
});
|
||||
case AuthProvider.AZURE_SAML:
|
||||
return ({
|
||||
acsUrl: "Reply URL (Assertion Consumer Service URL)",
|
||||
entityId: "Identifier (Entity ID)",
|
||||
entryPoint: "Login URL",
|
||||
entryPointPlaceholder: "https://login.microsoftonline.com/xxx/saml2",
|
||||
issuer: "Azure Application ID",
|
||||
issuerPlaceholder: "abc-def-ghi-jkl-mno"
|
||||
});
|
||||
case AuthProvider.JUMPCLOUD_SAML:
|
||||
return ({
|
||||
acsUrl: "ACS URL",
|
||||
entityId: "SP Entity ID",
|
||||
entryPoint: "IDP URL",
|
||||
entryPointPlaceholder: "https://sso.jumpcloud.com/saml2/xxx",
|
||||
issuer: "IdP Entity ID",
|
||||
issuerPlaceholder: "xxx"
|
||||
});
|
||||
|
||||
default:
|
||||
return ({
|
||||
acsUrl: "ACS URL",
|
||||
entityId: "Entity ID",
|
||||
entryPoint: "Entrypoint",
|
||||
entryPointPlaceholder: "Enter entrypoint...",
|
||||
issuer: "Issuer",
|
||||
issuerPlaceholder: "Enter placeholder..."
|
||||
});
|
||||
}
|
||||
const onSSOModalSubmit = async ({ authProvider, entryPoint, issuer, cert }: AddSSOFormData) => {
|
||||
try {
|
||||
if (!currentOrg) return;
|
||||
|
||||
if (!data) {
|
||||
await createMutateAsync({
|
||||
organizationId: currentOrg.id,
|
||||
authProvider,
|
||||
isActive: false,
|
||||
entryPoint,
|
||||
issuer,
|
||||
cert
|
||||
});
|
||||
} else {
|
||||
await updateMutateAsync({
|
||||
organizationId: currentOrg.id,
|
||||
authProvider,
|
||||
isActive: false,
|
||||
entryPoint,
|
||||
issuer,
|
||||
cert
|
||||
});
|
||||
}
|
||||
|
||||
handlePopUpClose("addSSO");
|
||||
|
||||
createNotification({
|
||||
text: `Successfully ${!data ? "added" : "updated"} SAML SSO configuration`,
|
||||
type: "success"
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: `Failed to ${!data ? "add" : "update"} SAML SSO configuration`,
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
|
||||
const authProvider = watch("authProvider");
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.addSSO?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("addSSO", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Add SSO">
|
||||
<form onSubmit={handleSubmit(onSSOModalSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="authProvider"
|
||||
defaultValue="okta-saml"
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Type"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Select
|
||||
defaultValue={field.value}
|
||||
{...field}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
className="w-full"
|
||||
>
|
||||
{ssoAuthProviders.map(({ label, value }) => (
|
||||
<SelectItem value={String(value || "")} key={label}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
const renderLabels = (authProvider: string) => {
|
||||
switch (authProvider) {
|
||||
case AuthProvider.OKTA_SAML:
|
||||
return {
|
||||
acsUrl: "Single sign-on URL",
|
||||
entityId: "Audience URI (SP Entity ID)",
|
||||
entryPoint: "Identity Provider Single Sign-On URL",
|
||||
entryPointPlaceholder: "https://your-domain.okta.com/app/app-name/xxx/sso/saml",
|
||||
issuer: "Identity Provider Issuer",
|
||||
issuerPlaceholder: "http://www.okta.com/xxx"
|
||||
};
|
||||
case AuthProvider.AZURE_SAML:
|
||||
return {
|
||||
acsUrl: "Reply URL (Assertion Consumer Service URL)",
|
||||
entityId: "Identifier (Entity ID)",
|
||||
entryPoint: "Login URL",
|
||||
entryPointPlaceholder: "https://login.microsoftonline.com/xxx/saml2",
|
||||
issuer: "Azure Application ID",
|
||||
issuerPlaceholder: "abc-def-ghi-jkl-mno"
|
||||
};
|
||||
case AuthProvider.JUMPCLOUD_SAML:
|
||||
return {
|
||||
acsUrl: "ACS URL",
|
||||
entityId: "SP Entity ID",
|
||||
entryPoint: "IDP URL",
|
||||
entryPointPlaceholder: "https://sso.jumpcloud.com/saml2/xxx",
|
||||
issuer: "IdP Entity ID",
|
||||
issuerPlaceholder: "xxx"
|
||||
};
|
||||
|
||||
default:
|
||||
return {
|
||||
acsUrl: "ACS URL",
|
||||
entityId: "Entity ID",
|
||||
entryPoint: "Entrypoint",
|
||||
entryPointPlaceholder: "Enter entrypoint...",
|
||||
issuer: "Issuer",
|
||||
issuerPlaceholder: "Enter placeholder..."
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const authProvider = watch("authProvider");
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.addSSO?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("addSSO", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Add SSO">
|
||||
<form onSubmit={handleSubmit(onSSOModalSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="authProvider"
|
||||
defaultValue="okta-saml"
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl label="Type" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Select
|
||||
defaultValue={field.value}
|
||||
{...field}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
className="w-full"
|
||||
>
|
||||
{ssoAuthProviders.map(({ label, value }) => (
|
||||
<SelectItem value={String(value || "")} key={label}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
{authProvider && data && (
|
||||
<>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm text-mineshaft-400">{renderLabels(authProvider).acsUrl}</h3>
|
||||
<p className="text-md break-all text-gray-400">{`${window.origin}/api/v1/sso/saml2/${data._id}`}</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-sm text-mineshaft-400">
|
||||
{renderLabels(authProvider).entityId}
|
||||
</h3>
|
||||
<p className="text-md text-gray-400">{window.origin}</p>
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="entryPoint"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label={renderLabels(authProvider).entryPoint}
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={renderLabels(authProvider).entryPointPlaceholder}
|
||||
/>
|
||||
{authProvider && data && (
|
||||
<>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-mineshaft-400 text-sm">{renderLabels(authProvider).acsUrl}</h3>
|
||||
<p className="text-gray-400 text-md break-all">{`${window.origin}/api/v1/sso/saml2/${data.id}`}</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-mineshaft-400 text-sm">{renderLabels(authProvider).entityId}</h3>
|
||||
<p className="text-gray-400 text-md">{window.origin}</p>
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="entryPoint"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label={renderLabels(authProvider).entryPoint}
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={renderLabels(authProvider).entryPointPlaceholder}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="issuer"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label={renderLabels(authProvider).issuer}
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={renderLabels(authProvider).issuerPlaceholder}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="cert"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Certificate"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<TextArea
|
||||
{...field}
|
||||
placeholder="-----BEGIN CERTIFICATE----- ..."
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={createIsLoading || updateIsLoading}
|
||||
>
|
||||
{!data ? "Add" : "Update"}
|
||||
</Button>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
variant="plain"
|
||||
onClick={() => handlePopUpClose("addSSO")}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="issuer"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label={renderLabels(authProvider).issuer}
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input {...field} placeholder={renderLabels(authProvider).issuerPlaceholder} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="cert"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Certificate"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<TextArea {...field} placeholder="-----BEGIN CERTIFICATE----- ..." />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={createIsLoading || updateIsLoading}
|
||||
>
|
||||
{!data ? "Add" : "Update"}
|
||||
</Button>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
variant="plain"
|
||||
onClick={() => handlePopUpClose("addSSO")}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
+2
-2
@@ -45,8 +45,8 @@ export const OrgDeleteSection = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-mineshaft-900 rounded-lg border border-mineshaft-600 mb-6">
|
||||
<p className="text-xl font-semibold text-mineshaft-100 mb-4">Danger Zone</p>
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<p className="mb-4 text-xl font-semibold text-mineshaft-100">Danger Zone</p>
|
||||
<Button
|
||||
isLoading={isLoading}
|
||||
colorSchema="danger"
|
||||
|
||||
+2
-2
@@ -51,9 +51,9 @@ export const OrgNameChangeSection = (): JSX.Element => {
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600"
|
||||
className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
||||
>
|
||||
<p className="text-xl font-semibold text-mineshaft-100 mb-4">Name</p>
|
||||
<p className="mb-4 text-xl font-semibold text-mineshaft-100">Name</p>
|
||||
<div className="mb-2 max-w-md">
|
||||
<Controller
|
||||
defaultValue=""
|
||||
|
||||
@@ -55,9 +55,9 @@ export const APIKeyTable = () => {
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data.length > 0 &&
|
||||
data.map(({ _id, name, createdAt, expiresAt, lastUsed }) => {
|
||||
data.map(({ id, name, createdAt, expiresAt, lastUsed }) => {
|
||||
return (
|
||||
<Tr className="h-10" key={`api-key-${_id}`}>
|
||||
<Tr className="h-10" key={`api-key-${id}`}>
|
||||
<Td>{name}</Td>
|
||||
<Td>{format(new Date(lastUsed), "yyyy-MM-dd")}</Td>
|
||||
<Td>{format(new Date(createdAt), "yyyy-MM-dd")}</Td>
|
||||
@@ -65,7 +65,7 @@ export const APIKeyTable = () => {
|
||||
<Td>
|
||||
<IconButton
|
||||
onClick={async () => {
|
||||
await handleDeleteAPIKeyDataClick(_id);
|
||||
await handleDeleteAPIKeyDataClick(id);
|
||||
}}
|
||||
size="lg"
|
||||
colorSchema="danger"
|
||||
|
||||
+88
-97
@@ -3,105 +3,96 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import {
|
||||
EmptyState,
|
||||
IconButton,
|
||||
Table,
|
||||
TableContainer,
|
||||
TableSkeleton,
|
||||
TBody,
|
||||
Td,
|
||||
Th,
|
||||
THead,
|
||||
Tr
|
||||
EmptyState,
|
||||
IconButton,
|
||||
Table,
|
||||
TableContainer,
|
||||
TableSkeleton,
|
||||
TBody,
|
||||
Td,
|
||||
Th,
|
||||
THead,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import {
|
||||
useGetMyAPIKeysV2
|
||||
} from "@app/hooks/api";
|
||||
import { useGetMyAPIKeysV2 } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
handlePopUpOpen: (
|
||||
popUpName: keyof UsePopUpState<["deleteAPIKeyV2", "apiKeyV2"]>,
|
||||
data?: {
|
||||
apiKeyDataId?: string;
|
||||
name?: string;
|
||||
}
|
||||
) => void;
|
||||
};
|
||||
handlePopUpOpen: (
|
||||
popUpName: keyof UsePopUpState<["deleteAPIKeyV2", "apiKeyV2"]>,
|
||||
data?: {
|
||||
apiKeyDataId?: string;
|
||||
name?: string;
|
||||
}
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const APIKeyV2Table = ({
|
||||
handlePopUpOpen
|
||||
}: Props) => {
|
||||
const { data, isLoading } = useGetMyAPIKeysV2();
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th className="">Name</Th>
|
||||
<Th className="">Last Used</Th>
|
||||
<Th className="">Created At</Th>
|
||||
<Th className="w-5" />
|
||||
</Tr>
|
||||
</THead>
|
||||
<TBody>
|
||||
{isLoading && <TableSkeleton columns={4} innerKey="api-keys-v2" />}
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data.length > 0 &&
|
||||
data.map(({
|
||||
id,
|
||||
name,
|
||||
lastUsed,
|
||||
createdAt
|
||||
}) => {
|
||||
return (
|
||||
<Tr className="h-10" key={`api-key-v2-${id}`}>
|
||||
<Td>{name}</Td>
|
||||
<Td>{lastUsed ? format(new Date(lastUsed), "yyyy-MM-dd") : "-"}</Td>
|
||||
<Td>{format(new Date(createdAt), "yyyy-MM-dd")}</Td>
|
||||
<Td className="flex justify-end">
|
||||
<IconButton
|
||||
onClick={async () => {
|
||||
handlePopUpOpen("apiKeyV2", {
|
||||
apiKeyDataId: id,
|
||||
name
|
||||
});
|
||||
}}
|
||||
size="lg"
|
||||
colorSchema="primary"
|
||||
variant="plain"
|
||||
ariaLabel="update"
|
||||
>
|
||||
<FontAwesomeIcon icon={faPencil} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
handlePopUpOpen("deleteAPIKeyV2", {
|
||||
apiKeyDataId: id
|
||||
});
|
||||
}}
|
||||
size="lg"
|
||||
colorSchema="danger"
|
||||
variant="plain"
|
||||
ariaLabel="update"
|
||||
className="ml-4"
|
||||
>
|
||||
<FontAwesomeIcon icon={faXmark} />
|
||||
</IconButton>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
{!isLoading && data && data?.length === 0 && (
|
||||
<Tr>
|
||||
<Td colSpan={4}>
|
||||
<EmptyState title="No API key v2 on file" icon={faKey} />
|
||||
</Td>
|
||||
</Tr>
|
||||
)}
|
||||
</TBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
}
|
||||
export const APIKeyV2Table = ({ handlePopUpOpen }: Props) => {
|
||||
const { data, isLoading } = useGetMyAPIKeysV2();
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th className="">Name</Th>
|
||||
<Th className="">Last Used</Th>
|
||||
<Th className="">Created At</Th>
|
||||
<Th className="w-5" />
|
||||
</Tr>
|
||||
</THead>
|
||||
<TBody>
|
||||
{isLoading && <TableSkeleton columns={4} innerKey="api-keys-v2" />}
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data.length > 0 &&
|
||||
data.map(({ id, name, lastUsed, createdAt }) => {
|
||||
return (
|
||||
<Tr className="h-10" key={`api-key-v2-${id}`}>
|
||||
<Td>{name}</Td>
|
||||
<Td>{lastUsed ? format(new Date(lastUsed), "yyyy-MM-dd") : "-"}</Td>
|
||||
<Td>{format(new Date(createdAt), "yyyy-MM-dd")}</Td>
|
||||
<Td className="flex justify-end">
|
||||
<IconButton
|
||||
onClick={async () => {
|
||||
handlePopUpOpen("apiKeyV2", {
|
||||
apiKeyDataId: id,
|
||||
name
|
||||
});
|
||||
}}
|
||||
size="lg"
|
||||
colorSchema="primary"
|
||||
variant="plain"
|
||||
ariaLabel="update"
|
||||
>
|
||||
<FontAwesomeIcon icon={faPencil} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
handlePopUpOpen("deleteAPIKeyV2", {
|
||||
apiKeyDataId: id
|
||||
});
|
||||
}}
|
||||
size="lg"
|
||||
colorSchema="danger"
|
||||
variant="plain"
|
||||
ariaLabel="update"
|
||||
className="ml-4"
|
||||
>
|
||||
<FontAwesomeIcon icon={faXmark} />
|
||||
</IconButton>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
{!isLoading && data && data?.length === 0 && (
|
||||
<Tr>
|
||||
<Td colSpan={4}>
|
||||
<EmptyState title="No API key v2 on file" icon={faKey} />
|
||||
</Td>
|
||||
</Tr>
|
||||
)}
|
||||
</TBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -43,9 +43,9 @@ export const SessionsTable = () => {
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data.length > 0 &&
|
||||
data.map(({ _id, createdAt, lastUsed, ip, userAgent }) => {
|
||||
data.map(({ id, createdAt, lastUsed, ip, userAgent }) => {
|
||||
return (
|
||||
<Tr className="h-10" key={`session-${_id}`}>
|
||||
<Tr className="h-10" key={`session-${id}`}>
|
||||
<Td>{formatDate(createdAt)}</Td>
|
||||
<Td>{formatDate(lastUsed)}</Td>
|
||||
<Td>{ip}</Td>
|
||||
|
||||
+22
-33
@@ -9,7 +9,7 @@ import { useUser } from "@app/context";
|
||||
import { useRenameUser } from "@app/hooks/api/users/queries";
|
||||
|
||||
const formSchema = yup.object({
|
||||
name: yup.string().required().label("User Name"),
|
||||
name: yup.string().required().label("User Name")
|
||||
});
|
||||
|
||||
type FormData = yup.InferType<typeof formSchema>;
|
||||
@@ -17,11 +17,7 @@ type FormData = yup.InferType<typeof formSchema>;
|
||||
export const UserNameSection = (): JSX.Element => {
|
||||
const { user } = useUser();
|
||||
const { createNotification } = useNotificationContext();
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
reset
|
||||
} = useForm<FormData>({ resolver: yupResolver(formSchema) });
|
||||
const { handleSubmit, control, reset } = useForm<FormData>({ resolver: yupResolver(formSchema) });
|
||||
const { mutateAsync, isLoading } = useRenameUser();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -32,10 +28,10 @@ export const UserNameSection = (): JSX.Element => {
|
||||
|
||||
const onFormSubmit = async ({ name }: FormData) => {
|
||||
try {
|
||||
if (!user?._id) return;
|
||||
if (!user?.id) return;
|
||||
if (name === "") return;
|
||||
|
||||
await mutateAsync({ newName: name});
|
||||
await mutateAsync({ newName: name });
|
||||
createNotification({
|
||||
text: "Successfully renamed user",
|
||||
type: "success"
|
||||
@@ -50,33 +46,26 @@ export const UserNameSection = (): JSX.Element => {
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
<form
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600"
|
||||
className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
||||
>
|
||||
<p className="text-xl font-semibold text-mineshaft-100 mb-4">
|
||||
Name
|
||||
</p>
|
||||
<div className="mb-2 max-w-md">
|
||||
<Controller
|
||||
defaultValue=""
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Input placeholder={`${user?.firstName} ${user?.lastName}`} {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="name"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
isLoading={isLoading}
|
||||
colorSchema="primary"
|
||||
variant="outline_bg"
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<p className="mb-4 text-xl font-semibold text-mineshaft-100">Name</p>
|
||||
<div className="mb-2 max-w-md">
|
||||
<Controller
|
||||
defaultValue=""
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Input placeholder={`${user?.firstName} ${user?.lastName}`} {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="name"
|
||||
/>
|
||||
</div>
|
||||
<Button isLoading={isLoading} colorSchema="primary" variant="outline_bg" type="submit">
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
+3
-3
@@ -14,10 +14,10 @@ export const AutoCapitalizationSection = () => {
|
||||
|
||||
const handleToggleCapitalizationToggle = async (state: boolean) => {
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
await mutateAsync({
|
||||
workspaceID: currentWorkspace._id,
|
||||
workspaceID: currentWorkspace.id,
|
||||
state
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ export const AutoCapitalizationSection = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6 p-4 bg-mineshaft-900 rounded-lg border border-mineshaft-600">
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<p className="mb-3 text-xl font-semibold">{t("settings.project.auto-capitalization")}</p>
|
||||
<ProjectPermissionCan I={ProjectPermissionActions.Edit} a={ProjectPermissionSub.Settings}>
|
||||
{(isAllowed) => (
|
||||
|
||||
+36
-41
@@ -2,10 +2,7 @@ import { useRouter } from "next/router";
|
||||
|
||||
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
} from "@app/components/v2";
|
||||
import { Button, DeleteActionModal } from "@app/components/v2";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
@@ -19,30 +16,30 @@ import { usePopUp } from "@app/hooks/usePopUp";
|
||||
export const DeleteProjectSection = () => {
|
||||
const router = useRouter();
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"deleteWorkspace"
|
||||
] as const);
|
||||
] as const);
|
||||
|
||||
const { currentOrg } = useOrganization();
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const [isDeleting, setIsDeleting] = useToggle();
|
||||
const deleteWorkspace = useDeleteWorkspace();
|
||||
|
||||
|
||||
const handleDeleteWorkspaceSubmit = async () => {
|
||||
setIsDeleting.on();
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
await deleteWorkspace.mutateAsync({
|
||||
workspaceID: currentWorkspace?._id
|
||||
workspaceID: currentWorkspace?.id
|
||||
});
|
||||
|
||||
|
||||
createNotification({
|
||||
text: "Successfully deleted project",
|
||||
type: "success"
|
||||
});
|
||||
|
||||
router.push(`/org/${currentOrg?._id}/overview`);
|
||||
|
||||
router.push(`/org/${currentOrg?.id}/overview`);
|
||||
handlePopUpClose("deleteWorkspace");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@@ -53,36 +50,34 @@ export const DeleteProjectSection = () => {
|
||||
} finally {
|
||||
setIsDeleting.off();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-mineshaft-900 rounded-lg border border-mineshaft-600 mb-6">
|
||||
<p className="text-xl font-semibold text-mineshaft-100 mb-4">
|
||||
Danger Zone
|
||||
</p>
|
||||
<ProjectPermissionCan I={ProjectPermissionActions.Delete} a={ProjectPermissionSub.Workspace}>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isLoading={isDeleting}
|
||||
isDisabled={!isAllowed || isDeleting}
|
||||
colorSchema="danger"
|
||||
variant="outline_bg"
|
||||
type="submit"
|
||||
onClick={() => handlePopUpOpen("deleteWorkspace")}
|
||||
>
|
||||
{`Delete ${currentWorkspace?.name}`}
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteWorkspace.isOpen}
|
||||
title="Are you sure want to delete this project?"
|
||||
subTitle={`Permanently delete ${currentWorkspace?.name} and all of its data. This action is not reversible, so please be careful.`}
|
||||
onChange={(isOpen) => handlePopUpToggle("deleteWorkspace", isOpen)}
|
||||
deleteKey="confirm"
|
||||
buttonText="Delete Project"
|
||||
onDeleteApproved={handleDeleteWorkspaceSubmit}
|
||||
/>
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<p className="mb-4 text-xl font-semibold text-mineshaft-100">Danger Zone</p>
|
||||
<ProjectPermissionCan I={ProjectPermissionActions.Delete} a={ProjectPermissionSub.Workspace}>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isLoading={isDeleting}
|
||||
isDisabled={!isAllowed || isDeleting}
|
||||
colorSchema="danger"
|
||||
variant="outline_bg"
|
||||
type="submit"
|
||||
onClick={() => handlePopUpOpen("deleteWorkspace")}
|
||||
>
|
||||
{`Delete ${currentWorkspace?.name}`}
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteWorkspace.isOpen}
|
||||
title="Are you sure want to delete this project?"
|
||||
subTitle={`Permanently delete ${currentWorkspace?.name} and all of its data. This action is not reversible, so please be careful.`}
|
||||
onChange={(isOpen) => handlePopUpToggle("deleteWorkspace", isOpen)}
|
||||
deleteKey="confirm"
|
||||
buttonText="Delete Project"
|
||||
onDeleteApproved={handleDeleteWorkspaceSubmit}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
+7
-7
@@ -9,9 +9,9 @@ import { useGetUserWsKey, useGetWorkspaceBot, useUpdateBotActiveStatus } from "@
|
||||
|
||||
export const E2EESection = () => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { data: bot } = useGetWorkspaceBot(currentWorkspace?._id ?? "");
|
||||
const { data: bot } = useGetWorkspaceBot(currentWorkspace?.id ?? "");
|
||||
const { mutateAsync: updateBotActiveStatus } = useUpdateBotActiveStatus();
|
||||
const { data: wsKey } = useGetUserWsKey(currentWorkspace?._id ?? "");
|
||||
const { data: wsKey } = useGetUserWsKey(currentWorkspace?.id ?? "");
|
||||
|
||||
/**
|
||||
* Activate bot for project by performing the following steps:
|
||||
@@ -23,7 +23,7 @@ export const E2EESection = () => {
|
||||
const toggleBotActivate = async () => {
|
||||
let botKey;
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
if (bot && wsKey) {
|
||||
// case: there is a bot
|
||||
@@ -56,17 +56,17 @@ export const E2EESection = () => {
|
||||
};
|
||||
|
||||
await updateBotActiveStatus({
|
||||
workspaceId: currentWorkspace._id,
|
||||
workspaceId: currentWorkspace.id,
|
||||
botKey,
|
||||
isActive: true,
|
||||
botId: bot._id
|
||||
botId: bot.id
|
||||
});
|
||||
} else {
|
||||
// bot is active -> deactivate bot
|
||||
await updateBotActiveStatus({
|
||||
isActive: false,
|
||||
botId: bot._id,
|
||||
workspaceId: currentWorkspace._id
|
||||
botId: bot.id,
|
||||
workspaceId: currentWorkspace.id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+87
-104
@@ -3,21 +3,15 @@ import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as yup from "yup";
|
||||
|
||||
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
} from "@app/components/v2";
|
||||
import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useCreateWsEnvironment } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
popUp: UsePopUpState<["createEnv"]>;
|
||||
handlePopUpClose: (popUpName: keyof UsePopUpState<["createEnv"]>) => void;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["createEnv"]>, state?: boolean) => void;
|
||||
popUp: UsePopUpState<["createEnv"]>;
|
||||
handlePopUpClose: (popUpName: keyof UsePopUpState<["createEnv"]>) => void;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["createEnv"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
const schema = yup.object({
|
||||
@@ -27,106 +21,95 @@ const schema = yup.object({
|
||||
|
||||
export type FormData = yup.InferType<typeof schema>;
|
||||
|
||||
export const AddEnvironmentModal = ({
|
||||
popUp,
|
||||
handlePopUpClose,
|
||||
handlePopUpToggle
|
||||
}: Props) => {
|
||||
export const AddEnvironmentModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => {
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { mutateAsync, isLoading } = useCreateWsEnvironment();
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset
|
||||
} = useForm<FormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
const { mutateAsync, isLoading } = useCreateWsEnvironment();
|
||||
const { control, handleSubmit, reset } = useForm<FormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
|
||||
const onFormSubmit = async ({
|
||||
const onFormSubmit = async ({ environmentName, environmentSlug }: FormData) => {
|
||||
try {
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
await mutateAsync({
|
||||
workspaceID: currentWorkspace.id,
|
||||
environmentName,
|
||||
environmentSlug
|
||||
}: FormData) => {
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
});
|
||||
|
||||
await mutateAsync({
|
||||
workspaceID: currentWorkspace._id,
|
||||
environmentName,
|
||||
environmentSlug
|
||||
});
|
||||
createNotification({
|
||||
text: "Successfully created environment",
|
||||
type: "success"
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully created environment",
|
||||
type: "success"
|
||||
});
|
||||
|
||||
handlePopUpClose("createEnv");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to create environment",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
handlePopUpClose("createEnv");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to create environment",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.createEnv?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("createEnv", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Create a new environment">
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="environmentName"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Environment Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="environmentSlug"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Environment Slug"
|
||||
helperText="Slugs are shorthands used in cli to access environment"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isLoading}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.createEnv?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("createEnv", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Create a new environment">
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="environmentName"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Environment Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="environmentSlug"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Environment Slug"
|
||||
helperText="Slugs are shorthands used in cli to access environment"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isLoading}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
+5
-5
@@ -40,10 +40,10 @@ export const EnvironmentSection = () => {
|
||||
|
||||
const onEnvDeleteSubmit = async (environmentSlug: string) => {
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
await deleteWsEnvironment.mutateAsync({
|
||||
workspaceID: currentWorkspace._id,
|
||||
workspaceID: currentWorkspace.id,
|
||||
environmentSlug
|
||||
});
|
||||
|
||||
@@ -63,8 +63,8 @@ export const EnvironmentSection = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6 p-4 bg-mineshaft-900 rounded-lg border border-mineshaft-600">
|
||||
<div className="flex justify-between mb-8">
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-8 flex justify-between">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">Environments</p>
|
||||
<div>
|
||||
<ProjectPermissionCan
|
||||
@@ -90,7 +90,7 @@ export const EnvironmentSection = () => {
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-gray-400 mb-8">
|
||||
<p className="mb-8 text-gray-400">
|
||||
Choose which environments will show up in your dashboard like development, staging,
|
||||
production
|
||||
</p>
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
|
||||
|
||||
const handleReorderEnv = async (shouldMoveUp: boolean, name: string, slug: string) => {
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
const indexOfEnv = currentWorkspace.environments.findIndex(
|
||||
(env) => env.name === name && env.slug === slug
|
||||
@@ -56,7 +56,7 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
|
||||
const indexToSwap = shouldMoveUp ? indexOfEnv - 1 : indexOfEnv + 1;
|
||||
|
||||
await reorderWsEnvironment.mutateAsync({
|
||||
workspaceID: currentWorkspace._id,
|
||||
workspaceID: currentWorkspace.id,
|
||||
environmentSlug: slug,
|
||||
environmentName: name,
|
||||
otherEnvironmentSlug: currentWorkspace.environments[indexToSwap].slug,
|
||||
|
||||
+92
-109
@@ -3,21 +3,15 @@ import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as yup from "yup";
|
||||
|
||||
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
} from "@app/components/v2";
|
||||
import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useUpdateWsEnvironment } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
popUp: UsePopUpState<["updateEnv"]>;
|
||||
handlePopUpClose: (popUpName: keyof UsePopUpState<["updateEnv"]>) => void;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["updateEnv"]>, state?: boolean) => void;
|
||||
popUp: UsePopUpState<["updateEnv"]>;
|
||||
handlePopUpClose: (popUpName: keyof UsePopUpState<["updateEnv"]>) => void;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["updateEnv"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
const schema = yup.object({
|
||||
@@ -27,109 +21,98 @@ const schema = yup.object({
|
||||
|
||||
export type FormData = yup.InferType<typeof schema>;
|
||||
|
||||
export const UpdateEnvironmentModal = ({
|
||||
popUp,
|
||||
handlePopUpClose,
|
||||
handlePopUpToggle
|
||||
}: Props) => {
|
||||
export const UpdateEnvironmentModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => {
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { mutateAsync, isLoading } = useUpdateWsEnvironment();
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset
|
||||
} = useForm<FormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
const { mutateAsync, isLoading } = useUpdateWsEnvironment();
|
||||
const { control, handleSubmit, reset } = useForm<FormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
|
||||
const oldEnvironmentSlug = (popUp?.updateEnv?.data as { slug: string })?.slug;
|
||||
|
||||
const onFormSubmit = async ({
|
||||
const oldEnvironmentSlug = (popUp?.updateEnv?.data as { slug: string })?.slug;
|
||||
|
||||
const onFormSubmit = async ({ environmentName, environmentSlug }: FormData) => {
|
||||
try {
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
await mutateAsync({
|
||||
workspaceID: currentWorkspace.id,
|
||||
environmentName,
|
||||
environmentSlug
|
||||
}: FormData) => {
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
|
||||
await mutateAsync({
|
||||
workspaceID: currentWorkspace._id,
|
||||
environmentName,
|
||||
environmentSlug,
|
||||
oldEnvironmentSlug
|
||||
});
|
||||
environmentSlug,
|
||||
oldEnvironmentSlug
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully updated environment",
|
||||
type: "success"
|
||||
});
|
||||
|
||||
handlePopUpClose("updateEnv");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to update environment",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
createNotification({
|
||||
text: "Successfully updated environment",
|
||||
type: "success"
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.updateEnv?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("updateEnv", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Update environment">
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="environmentName"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Environment Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="environmentSlug"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Environment Slug"
|
||||
helperText="Slugs are shorthands used in cli to access environment"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isLoading}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
Update
|
||||
</Button>
|
||||
handlePopUpClose("updateEnv");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to update environment",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.updateEnv?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("updateEnv", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Update environment">
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="environmentName"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Environment Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="environmentSlug"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Environment Slug"
|
||||
helperText="Slugs are shorthands used in cli to access environment"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isLoading}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
Update
|
||||
</Button>
|
||||
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
+4
-4
@@ -32,10 +32,10 @@ export const ProjectNameChangeSection = () => {
|
||||
|
||||
const onFormSubmit = async ({ name }: FormData) => {
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
await mutateAsync({
|
||||
workspaceID: currentWorkspace._id,
|
||||
workspaceID: currentWorkspace.id,
|
||||
newWorkspaceName: name
|
||||
});
|
||||
|
||||
@@ -55,9 +55,9 @@ export const ProjectNameChangeSection = () => {
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600"
|
||||
className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
||||
>
|
||||
<h2 className="text-xl font-semibold flex-1 text-mineshaft-100 mb-8">Project Name</h2>
|
||||
<h2 className="mb-8 flex-1 text-xl font-semibold text-mineshaft-100">Project Name</h2>
|
||||
<div className="max-w-md">
|
||||
<Controller
|
||||
defaultValue=""
|
||||
|
||||
+87
-99
@@ -3,120 +3,108 @@ import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as yup from "yup";
|
||||
|
||||
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
Modal,
|
||||
ModalClose,
|
||||
ModalContent
|
||||
} from "@app/components/v2";
|
||||
import { Button, FormControl, Input, Modal, ModalClose, ModalContent } from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useCreateWsTag } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
const schema = yup.object({
|
||||
name: yup.string().required().label("Tag Name")
|
||||
name: yup.string().required().label("Tag Name")
|
||||
});
|
||||
|
||||
export type FormData = yup.InferType<typeof schema>;
|
||||
|
||||
type Props = {
|
||||
popUp: UsePopUpState<["CreateSecretTag", "deleteTagConfirmation"]>;
|
||||
handlePopUpClose: (popUpName: keyof UsePopUpState<["CreateSecretTag", "deleteTagConfirmation"]>) => void;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["CreateSecretTag", "deleteTagConfirmation"]>, state?: boolean) => void;
|
||||
popUp: UsePopUpState<["CreateSecretTag", "deleteTagConfirmation"]>;
|
||||
handlePopUpClose: (
|
||||
popUpName: keyof UsePopUpState<["CreateSecretTag", "deleteTagConfirmation"]>
|
||||
) => void;
|
||||
handlePopUpToggle: (
|
||||
popUpName: keyof UsePopUpState<["CreateSecretTag", "deleteTagConfirmation"]>,
|
||||
state?: boolean
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const AddSecretTagModal = ({
|
||||
popUp,
|
||||
handlePopUpClose,
|
||||
handlePopUpToggle
|
||||
}: Props) => {
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { currentWorkspace }= useWorkspace();
|
||||
const createWsTag = useCreateWsTag();
|
||||
const {
|
||||
control,
|
||||
reset,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting }
|
||||
} = useForm<FormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
|
||||
const onFormSubmit = async ({
|
||||
name
|
||||
}: FormData) => {
|
||||
try {
|
||||
if (!currentWorkspace?._id) return;
|
||||
export const AddSecretTagModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => {
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const createWsTag = useCreateWsTag();
|
||||
const {
|
||||
control,
|
||||
reset,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting }
|
||||
} = useForm<FormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
|
||||
await createWsTag.mutateAsync({
|
||||
workspaceID: currentWorkspace?._id,
|
||||
tagName: name,
|
||||
tagSlug: name.replace(/\s+/g, " ").replace(" ", "_"),
|
||||
tagColor: ""
|
||||
});
|
||||
const onFormSubmit = async ({ name }: FormData) => {
|
||||
try {
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
handlePopUpClose("CreateSecretTag");
|
||||
await createWsTag.mutateAsync({
|
||||
workspaceID: currentWorkspace?.id,
|
||||
tagName: name,
|
||||
tagSlug: name.replace(/\s+/g, " ").replace(" ", "_"),
|
||||
tagColor: ""
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully created a tag",
|
||||
type: "success"
|
||||
});
|
||||
reset()
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to create a tag",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
handlePopUpClose("CreateSecretTag");
|
||||
|
||||
createNotification({
|
||||
text: "Successfully created a tag",
|
||||
type: "success"
|
||||
});
|
||||
reset();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to create a tag",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.CreateSecretTag?.isOpen}
|
||||
onOpenChange={(open) => {
|
||||
handlePopUpToggle("CreateSecretTag", open);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent
|
||||
title={`Add a tag for ${currentWorkspace?.name ?? ""}`}
|
||||
subTitle="Specify your tag name, and the slug will be created automatically."
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.CreateSecretTag?.isOpen}
|
||||
onOpenChange={(open) => {
|
||||
handlePopUpToggle("CreateSecretTag", open);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent
|
||||
title={`Add a tag for ${currentWorkspace?.name ?? ""}`}
|
||||
subTitle="Specify your tag name, and the slug will be created automatically."
|
||||
>
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="name"
|
||||
defaultValue=""
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl label="Tag Name" isError={Boolean(error)} errorText={error?.message}>
|
||||
<Input {...field} placeholder="Type your tag name" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
type="submit"
|
||||
isDisabled={isSubmitting}
|
||||
isLoading={isSubmitting}
|
||||
>
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="name"
|
||||
defaultValue=""
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Tag Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="Type your tag name" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
type="submit"
|
||||
isDisabled={isSubmitting}
|
||||
isLoading={isSubmitting}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
<ModalClose asChild>
|
||||
<Button variant="plain" colorSchema="secondary">
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalClose>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Create
|
||||
</Button>
|
||||
<ModalClose asChild>
|
||||
<Button variant="plain" colorSchema="secondary">
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalClose>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
+3
-3
@@ -33,7 +33,7 @@ type Props = {
|
||||
|
||||
export const SecretTagsTable = ({ handlePopUpOpen }: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { data, isLoading } = useGetWsTags(currentWorkspace?._id ?? "");
|
||||
const { data, isLoading } = useGetWsTags(currentWorkspace?.id ?? "");
|
||||
|
||||
return (
|
||||
<TableContainer className="mt-4">
|
||||
@@ -49,7 +49,7 @@ export const SecretTagsTable = ({ handlePopUpOpen }: Props) => {
|
||||
{isLoading && <TableSkeleton columns={3} innerKey="secret-tags" />}
|
||||
{!isLoading &&
|
||||
data &&
|
||||
data.map(({ _id, name, slug }) => (
|
||||
data.map(({ id, name, slug }) => (
|
||||
<Tr key={name}>
|
||||
<Td>{name}</Td>
|
||||
<Td>{slug}</Td>
|
||||
@@ -63,7 +63,7 @@ export const SecretTagsTable = ({ handlePopUpOpen }: Props) => {
|
||||
onClick={() =>
|
||||
handlePopUpOpen("deleteTagConfirmation", {
|
||||
name,
|
||||
id: _id
|
||||
id
|
||||
})
|
||||
}
|
||||
colorSchema="danger"
|
||||
|
||||
+2
-2
@@ -36,7 +36,7 @@ export const WebhooksTab = withProjectPermission(
|
||||
const { t } = useTranslation();
|
||||
const { createNotification } = useNotificationContext();
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const workspaceId = currentWorkspace?._id || "";
|
||||
const workspaceId = currentWorkspace?.id || "";
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([
|
||||
"addWebhook",
|
||||
"deleteWebhook"
|
||||
@@ -182,7 +182,7 @@ export const WebhooksTab = withProjectPermission(
|
||||
{!isWebhooksLoading &&
|
||||
webhooks?.map(
|
||||
({
|
||||
_id: id,
|
||||
id,
|
||||
url,
|
||||
environment,
|
||||
secretPath,
|
||||
|
||||
Reference in New Issue
Block a user