Update org settings > general tab ui

This commit is contained in:
Tuan Dang
2024-03-12 16:18:17 -07:00
parent a6d7d32156
commit 2ca03abec2
17 changed files with 129 additions and 196 deletions
@@ -21,10 +21,10 @@ import {
import { UsePopUpState } from "@app/hooks/usePopUp";
const LDAPFormSchema = z.object({
url: z.string().min(1, "URL is requiredx"),
bindDN: z.string().min(1, "Bind DN is requiredx"),
bindPass: z.string().min(1, "Bind Pass is required"),
searchBase: z.string().min(1, "Search Base is required"),
url: z.string().default(""),
bindDN: z.string().default(""),
bindPass: z.string().default(""),
searchBase: z.string().default(""),
caCert: z.string().optional()
});
@@ -122,7 +122,7 @@ export const LDAPModal = ({
reset();
}}
>
<ModalContent title="Add LDAP">
<ModalContent title="Manage LDAP configuration">
<form onSubmit={handleSubmit(onSSOModalSubmit)}>
<Controller
control={control}
@@ -60,7 +60,7 @@ export const OrgGeneralAuthSection = () => {
return (
<>
<div className="py-4">
{/* <div className="py-4">
<div className="mb-2 flex justify-between">
<h3 className="text-md text-mineshaft-100">Allow users to send invites</h3>
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Sso}>
@@ -75,7 +75,7 @@ export const OrgGeneralAuthSection = () => {
</OrgPermissionCan>
</div>
<p className="text-sm text-mineshaft-300">Allow members to invite new users to this organization</p>
</div>
</div> */}
<div className="py-4">
<div className="mb-2 flex justify-between">
<h3 className="text-md text-mineshaft-100">Enforce SAML SSO</h3>
@@ -104,24 +104,26 @@ export const OrgLDAPSection = (): JSX.Element => {
</div>
<p className="text-sm text-mineshaft-300">Manage LDAP authentication configuration</p>
</div>
<div className="py-4">
<div className="mb-2 flex items-center justify-between">
<h2 className="text-md text-mineshaft-100">Enable LDAP</h2>
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Ldap}>
{(isAllowed) => (
<Switch
id="enable-saml-sso"
onCheckedChange={(value) => handleLDAPToggle(value)}
isChecked={data ? data.isActive : false}
isDisabled={!isAllowed}
>
Enable
</Switch>
)}
</OrgPermissionCan>
{data && (
<div className="py-4">
<div className="mb-2 flex items-center justify-between">
<h2 className="text-md text-mineshaft-100">Enable LDAP</h2>
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Ldap}>
{(isAllowed) => (
<Switch
id="enable-saml-sso"
onCheckedChange={(value) => handleLDAPToggle(value)}
isChecked={data ? data.isActive : false}
isDisabled={!isAllowed}
>
Enable
</Switch>
)}
</OrgPermissionCan>
</div>
<p className="text-sm text-mineshaft-300">Allow members to authenticate into Infisical with LDAP</p>
</div>
<p className="text-sm text-mineshaft-300">Allow members to authenticate into Infisical with LDAP</p>
</div>
)}
<LDAPModal
popUp={popUp}
handlePopUpClose={handlePopUpClose}
@@ -1,7 +1,7 @@
import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import {
@@ -32,16 +32,16 @@ const ssoAuthProviders = [
{ label: "Google SAML", value: AuthProvider.GOOGLE_SAML }
];
const schema = yup
const schema = z
.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")
authProvider: z.string().min(1, "SSO Type is required"),
entryPoint: z.string().default(""),
issuer: z.string().default(""),
cert: z.string().default("")
})
.required();
export type AddSSOFormData = yup.InferType<typeof schema>;
export type AddSSOFormData = z.infer<typeof schema>;
type Props = {
popUp: UsePopUpState<["addSSO"]>;
@@ -60,7 +60,7 @@ export const SSOModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props)
defaultValues: {
authProvider: AuthProvider.OKTA_SAML
},
resolver: yupResolver(schema)
resolver: zodResolver(schema)
});
useEffect(() => {
@@ -173,7 +173,7 @@ export const SSOModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props)
reset();
}}
>
<ModalContent title="Add SSO">
<ModalContent title="Manage SAML configuration">
<form onSubmit={handleSubmit(onSSOModalSubmit)}>
<Controller
control={control}
@@ -45,18 +45,21 @@ export const OrgDeleteSection = () => {
};
return (
<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"
variant="outline_bg"
type="submit"
onClick={() => handlePopUpOpen("deleteOrg")}
isDisabled={Boolean(membership && membership.role !== "admin")}
>
{`Delete ${currentOrg?.name}`}
</Button>
<>
<hr className="border-mineshaft-600" />
<div className="py-4">
<p className="mb-4 text-md text-mineshaft-100">Danger Zone</p>
<Button
isLoading={isLoading}
colorSchema="danger"
variant="outline_bg"
type="submit"
onClick={() => handlePopUpOpen("deleteOrg")}
isDisabled={Boolean(membership && membership.role !== "admin")}
>
{`Delete ${currentOrg?.name}`}
</Button>
</div>
<DeleteActionModal
isOpen={popUp.deleteOrg.isOpen}
title="Are you sure want to delete this organization?"
@@ -65,6 +68,6 @@ export const OrgDeleteSection = () => {
deleteKey="confirm"
onDeleteApproved={handleDeleteOrgSubmit}
/>
</div>
</>
);
};
@@ -3,15 +3,12 @@ import { useOrgPermission } from "@app/context";
import { OrgDeleteSection } from "../OrgDeleteSection";
import { OrgIncidentContactsSection } from "../OrgIncidentContactsSection";
import { OrgNameChangeSection } from "../OrgNameChangeSection";
import { OrgSlugChangeSection } from "../OrgSlugChangeSection";
export const OrgGeneralTab = () => {
const { membership } = useOrgPermission();
return (
<div>
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
<OrgNameChangeSection />
<OrgSlugChangeSection />
<OrgIncidentContactsSection />
{membership && membership.role === "admin" && <OrgDeleteSection />}
</div>
@@ -18,9 +18,10 @@ export const OrgIncidentContactsSection = () => {
const { permission } = useOrgPermission();
return (
<div className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600">
<div className="flex justify-between mb-4">
<p className="min-w-max text-xl font-semibold">{t("section.incident.incident-contacts")}</p>
<>
<hr className="border-mineshaft-600" />
<div className="flex items-center justify-between pt-4">
<p className="text-md text-mineshaft-100">{t("section.incident.incident-contacts")}</p>
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.IncidentAccount}>
{(isAllowed) => (
<Button
@@ -35,16 +36,18 @@ export const OrgIncidentContactsSection = () => {
)}
</OrgPermissionCan>
</div>
{permission.can(OrgPermissionActions.Read, OrgPermissionSubjects.IncidentAccount) ? (
<OrgIncidentContactsTable />
) : (
<PermissionDeniedBanner />
)}
<div className="py-4">
{permission.can(OrgPermissionActions.Read, OrgPermissionSubjects.IncidentAccount) ? (
<OrgIncidentContactsTable />
) : (
<PermissionDeniedBanner />
)}
</div>
<AddOrgIncidentContactModal
popUp={popUp}
handlePopUpClose={handlePopUpClose}
handlePopUpToggle={handlePopUpToggle}
/>
</div>
</>
);
};
@@ -10,7 +10,12 @@ import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@a
import { useUpdateOrg } from "@app/hooks/api";
const formSchema = yup.object({
name: yup.string().required().label("Project Name")
name: yup.string().required().label("Organization Name"),
slug: yup
.string()
.matches(/^[a-zA-Z0-9-]+$/, "Name must only contain alphanumeric characters or hyphens")
.required()
.label("Organization Slug")
});
type FormData = yup.InferType<typeof formSchema>;
@@ -25,40 +30,44 @@ export const OrgNameChangeSection = (): JSX.Element => {
useEffect(() => {
if (currentOrg) {
reset({ name: currentOrg.name });
reset({
name: currentOrg.name,
slug: currentOrg.slug
});
}
}, [currentOrg]);
const onFormSubmit = async ({ name }: FormData) => {
const onFormSubmit = async ({ name, slug }: FormData) => {
try {
if (!currentOrg?.id) return;
if (name === "") return;
await mutateAsync({ orgId: currentOrg?.id, name });
await mutateAsync({
orgId: currentOrg?.id,
name,
slug
});
createNotification({
text: "Successfully renamed organization",
text: "Successfully updated organization details",
type: "success"
});
} catch (error) {
console.error(error);
createNotification({
text: "Failed to rename organization",
text: "Failed to update organization details",
type: "error"
});
}
};
return (
<form
onSubmit={handleSubmit(onFormSubmit)}
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">Organization Name</p>
<div className="mb-2 max-w-md">
<form onSubmit={handleSubmit(onFormSubmit)} className="py-4">
<div className="">
<h2 className="mb-2 text-md text-mineshaft-100">Organization Name</h2>
<Controller
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl isError={Boolean(error)} errorText={error?.message}>
<FormControl isError={Boolean(error)} errorText={error?.message} className="max-w-md">
<Input placeholder="Acme Corp" {...field} />
</FormControl>
)}
@@ -66,6 +75,19 @@ export const OrgNameChangeSection = (): JSX.Element => {
name="name"
/>
</div>
<div className="py-4">
<h2 className="mb-2 text-md text-mineshaft-100">Organization Slug</h2>
<Controller
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl isError={Boolean(error)} errorText={error?.message} className="max-w-md">
<Input placeholder="acme" {...field} />
</FormControl>
)}
control={control}
name="slug"
/>
</div>
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<Button
@@ -81,4 +103,4 @@ export const OrgNameChangeSection = (): JSX.Element => {
</OrgPermissionCan>
</form>
);
};
};
@@ -1,88 +0,0 @@
import { useEffect } from "react";
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 { OrgPermissionCan } from "@app/components/permissions";
import { Button, FormControl, Input } from "@app/components/v2";
import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
import { useUpdateOrg } from "@app/hooks/api";
const formSchema = yup.object({
slug: yup
.string()
.matches(/^[a-zA-Z0-9-]+$/, "Name must only contain alphanumeric characters or hyphens")
.required()
.label("Project Slug")
});
type FormData = yup.InferType<typeof formSchema>;
export const OrgSlugChangeSection = (): JSX.Element => {
const { currentOrg } = useOrganization();
const { createNotification } = useNotificationContext();
const { handleSubmit, control, reset } = useForm<FormData>({
resolver: yupResolver(formSchema)
});
const { mutateAsync, isLoading } = useUpdateOrg();
useEffect(() => {
if (currentOrg) {
reset({ slug: currentOrg.slug });
}
}, [currentOrg]);
const onFormSubmit = async ({ slug }: FormData) => {
try {
if (!currentOrg?.id) return;
if (slug === "") return;
await mutateAsync({ orgId: currentOrg?.id, slug });
createNotification({
text: "Successfully updated organization slug",
type: "success"
});
} catch (error) {
console.error(error);
createNotification({
text: "Failed to update organization slug",
type: "error"
});
}
};
return (
<form
onSubmit={handleSubmit(onFormSubmit)}
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">Organization Slug</p>
<div className="mb-2 max-w-md">
<Controller
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl isError={Boolean(error)} errorText={error?.message}>
<Input placeholder="acme" {...field} />
</FormControl>
)}
control={control}
name="slug"
/>
</div>
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Settings}>
{(isAllowed) => (
<Button
isLoading={isLoading}
isDisabled={!isAllowed}
colorSchema="primary"
variant="outline_bg"
type="submit"
>
Save
</Button>
)}
</OrgPermissionCan>
</form>
);
}
@@ -1 +0,0 @@
export { OrgSlugChangeSection } from "./OrgSlugChangeSection";