feat(infisical-pg): removed _id with id for new backend

This commit is contained in:
Akhil Mohan
2024-01-27 12:38:22 +05:30
parent fbe5a1adb0
commit fadb36edb8
17 changed files with 2107 additions and 2277 deletions
+5 -5
View File
@@ -2,14 +2,14 @@ import { TRole } from "../roles/types";
import { IdentityAuthMethod } from "./enums"; import { IdentityAuthMethod } from "./enums";
export type IdentityTrustedIp = { export type IdentityTrustedIp = {
_id: string; id: string;
ipAddress: string; ipAddress: string;
type: "ipv4" | "ipv6"; type: "ipv4" | "ipv6";
prefix?: number; prefix?: number;
} }
export type Identity = { export type Identity = {
_id: string; id: string;
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
createdAt: string; createdAt: string;
@@ -17,7 +17,7 @@ export type Identity = {
}; };
export type IdentityMembershipOrg = { export type IdentityMembershipOrg = {
_id: string; id: string;
identity: Identity; identity: Identity;
organization: string; organization: string;
role: "admin" | "member" | "viewer" | "no-access" | "custom"; role: "admin" | "member" | "viewer" | "no-access" | "custom";
@@ -27,7 +27,7 @@ export type IdentityMembershipOrg = {
} }
export type IdentityMembership = { export type IdentityMembership = {
_id: string; id: string;
identity: Identity; identity: Identity;
organization: string; organization: string;
role: "admin" | "member" | "viewer" | "no-access" | "custom"; role: "admin" | "member" | "viewer" | "no-access" | "custom";
@@ -100,7 +100,7 @@ export type CreateIdentityUniversalAuthClientSecretDTO = {
} }
export type ClientSecretData = { export type ClientSecretData = {
_id: string; id: string;
identityUniversalAuth: string; identityUniversalAuth: string;
isClientSecretRevoked: boolean; isClientSecretRevoked: boolean;
description: string; description: string;
@@ -324,7 +324,7 @@ export const Navbar = () => {
// direct user to start pro trial // direct user to start pro trial
const url = await mutateAsync({ const url = await mutateAsync({
orgId: currentOrg._id, orgId: currentOrg.id,
success_url: window.location.href success_url: window.location.href
}); });
@@ -36,7 +36,7 @@ export default function RenderCreateIntegrationPage() {
setIsLoading(false); setIsLoading(false);
router.push(`/integrations/render/create?integrationAuthId=${integrationAuth._id}`); router.push(`/integrations/render/create?integrationAuthId=${integrationAuth.id}`);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
@@ -46,12 +46,12 @@ export default function CloudflareWorkersIntegrationPage() {
const handleButtonClick = async () => { const handleButtonClick = async () => {
try { try {
if (!integrationAuth?._id) return; if (!integrationAuth?.id) return;
setIsLoading(true); setIsLoading(true);
await mutateAsync({ await mutateAsync({
integrationAuthId: integrationAuth?._id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: targetAppId, appId: targetAppId,
@@ -14,18 +14,16 @@ import {
SelectItem SelectItem
} from "@app/components/v2"; } from "@app/components/v2";
import { useOrganization } from "@app/context"; import { useOrganization } from "@app/context";
import { import { useCreateIdentity, useGetRoles, useUpdateIdentity } from "@app/hooks/api";
useCreateIdentity,
useGetRoles,
useUpdateIdentity
} from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
const schema = yup.object({ const schema = yup
.object({
name: yup.string().required("MI name is required"), name: yup.string().required("MI name is required"),
role: yup.string(), role: yup.string()
}).required(); })
.required();
export type FormData = yup.InferType<typeof schema>; export type FormData = yup.InferType<typeof schema>;
@@ -42,15 +40,11 @@ type Props = {
handlePopUpToggle: (popUpName: keyof UsePopUpState<["identity"]>, state?: boolean) => void; handlePopUpToggle: (popUpName: keyof UsePopUpState<["identity"]>, state?: boolean) => void;
}; };
export const IdentityModal = ({ export const IdentityModal = ({ popUp, handlePopUpOpen, handlePopUpToggle }: Props) => {
popUp,
handlePopUpOpen,
handlePopUpToggle
}: Props) => {
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?._id || ""; const orgId = currentOrg?.id || "";
const { data: roles } = useGetRoles({ const { data: roles } = useGetRoles({
orgId orgId
@@ -72,7 +66,6 @@ export const IdentityModal = ({
}); });
useEffect(() => { useEffect(() => {
const identity = popUp?.identity?.data as { const identity = popUp?.identity?.data as {
identityId: string; identityId: string;
name: string; name: string;
@@ -98,12 +91,8 @@ export const IdentityModal = ({
} }
}, [popUp?.identity?.data, roles]); }, [popUp?.identity?.data, roles]);
const onFormSubmit = async ({ const onFormSubmit = async ({ name, role }: FormData) => {
name,
role,
}: FormData) => {
try { try {
const identity = popUp?.identity?.data as { const identity = popUp?.identity?.data as {
identityId: string; identityId: string;
name: string; name: string;
@@ -125,7 +114,7 @@ export const IdentityModal = ({
// create // create
const { const {
_id: createdId, id: createdId,
name: createdName, name: createdName,
authMethod authMethod
} = await createMutateAsync({ } = await createMutateAsync({
@@ -151,15 +140,16 @@ export const IdentityModal = ({
} catch (err) { } catch (err) {
console.error(err); console.error(err);
const error = err as any; const error = err as any;
const text = error?.response?.data?.message const text =
?? `Failed to ${popUp?.identity?.data ? "updated" : "created"} identity`; error?.response?.data?.message ??
`Failed to ${popUp?.identity?.data ? "updated" : "created"} identity`;
createNotification({ createNotification({
text, text,
type: "error" type: "error"
}); });
} }
} };
return ( return (
<Modal <Modal
@@ -176,15 +166,8 @@ export const IdentityModal = ({
defaultValue="" defaultValue=""
name="name" name="name"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl label="Name" isError={Boolean(error)} errorText={error?.message}>
label="Name" <Input {...field} placeholder="Machine 1" />
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="Machine 1"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -236,4 +219,4 @@ export const IdentityModal = ({
</ModalContent> </ModalContent>
</Modal> </Modal>
); );
} };
@@ -4,14 +4,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { OrgPermissionCan } from "@app/components/permissions"; import { OrgPermissionCan } from "@app/components/permissions";
import { import { Button, DeleteActionModal } from "@app/components/v2";
Button, import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
DeleteActionModal
} from "@app/components/v2";
import {
OrgPermissionActions,
OrgPermissionSubjects,
useOrganization} from "@app/context";
import { withPermission } from "@app/hoc"; import { withPermission } from "@app/hoc";
import { useDeleteIdentity } from "@app/hooks/api"; import { useDeleteIdentity } from "@app/hooks/api";
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
@@ -24,7 +18,7 @@ import { IdentityUniversalAuthClientSecretModal } from "./IdentityUniversalAuthC
export const IdentitySection = withPermission( export const IdentitySection = withPermission(
() => { () => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?._id || ""; const orgId = currentOrg?.id || "";
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { mutateAsync: deleteMutateAsync } = useDeleteIdentity(); const { mutateAsync: deleteMutateAsync } = useDeleteIdentity();
@@ -39,7 +33,6 @@ export const IdentitySection = withPermission(
const onDeleteIdentitySubmit = async (identityId: string) => { const onDeleteIdentitySubmit = async (identityId: string) => {
try { try {
await deleteMutateAsync({ await deleteMutateAsync({
identityId, identityId,
organizationId: orgId organizationId: orgId
@@ -54,33 +47,35 @@ export const IdentitySection = withPermission(
} catch (err) { } catch (err) {
console.error(err); console.error(err);
const error = err as any; const error = err as any;
const text = error?.response?.data?.message const text = error?.response?.data?.message ?? "Failed to delete identity";
?? "Failed to delete identity"
createNotification({ createNotification({
text, text,
type: "error" type: "error"
}); });
} }
} };
return ( return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"> <div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="flex justify-between mb-4"> <div className="mb-4 flex justify-between">
<p className="text-xl font-semibold text-mineshaft-100"> <p className="text-xl font-semibold text-mineshaft-100">Identities</p>
Identities <div className="flex w-full justify-end pr-4">
</p>
<div className="flex justify-end w-full pr-4">
<Link href="https://infisical.com/docs/documentation/platform/identities/overview"> <Link href="https://infisical.com/docs/documentation/platform/identities/overview">
<a target="_blank" rel="noopener noreferrer" className="rounded-md px-4 py-2 w-max text-mineshaft-200 hover:text-white bg-mineshaft-600 border border-mineshaft-500 hover:bg-primary/10 hover:border-primary/40 duration-200 cursor-pointer"> <a
Documentation <FontAwesomeIcon icon={faArrowUpRightFromSquare} className="text-xs mb-[0.06rem] ml-1"/> target="_blank"
rel="noopener noreferrer"
className="w-max cursor-pointer rounded-md border border-mineshaft-500 bg-mineshaft-600 px-4 py-2 text-mineshaft-200 duration-200 hover:border-primary/40 hover:bg-primary/10 hover:text-white"
>
Documentation{" "}
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.06rem] ml-1 text-xs"
/>
</a> </a>
</Link> </Link>
</div> </div>
<OrgPermissionCan <OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Identity}>
I={OrgPermissionActions.Create}
a={OrgPermissionSubjects.Identity}
>
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
colorSchema="primary" colorSchema="primary"
@@ -18,14 +18,8 @@ import {
Tooltip, Tooltip,
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
OrgPermissionActions, import { useGetIdentityMembershipOrgs, useGetRoles, useUpdateIdentity } from "@app/hooks/api";
OrgPermissionSubjects,
useOrganization} from "@app/context";
import {
useGetIdentityMembershipOrgs,
useGetRoles,
useUpdateIdentity} from "@app/hooks/api";
import { IdentityAuthMethod, identityAuthToNameMap } from "@app/hooks/api/identities"; import { IdentityAuthMethod, identityAuthToNameMap } from "@app/hooks/api/identities";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
@@ -33,7 +27,9 @@ import { UsePopUpState } from "@app/hooks/usePopUp";
type Props = { type Props = {
handlePopUpOpen: ( handlePopUpOpen: (
popUpName: keyof UsePopUpState<["deleteIdentity", "identity", "universalAuthClientSecret", "identityAuthMethod"]>, popUpName: keyof UsePopUpState<
["deleteIdentity", "identity", "universalAuthClientSecret", "identityAuthMethod"]
>,
data?: { data?: {
identityId?: string; identityId?: string;
name?: string; name?: string;
@@ -47,12 +43,10 @@ type Props = {
) => void; ) => void;
}; };
export const IdentityTable = ({ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
handlePopUpOpen
}: Props) => {
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?._id || ""; const orgId = currentOrg?.id || "";
const { mutateAsync: updateMutateAsync } = useUpdateIdentity(); const { mutateAsync: updateMutateAsync } = useUpdateIdentity();
const { data, isLoading } = useGetIdentityMembershipOrgs(orgId); const { data, isLoading } = useGetIdentityMembershipOrgs(orgId);
@@ -61,15 +55,8 @@ export const IdentityTable = ({
orgId orgId
}); });
const handleChangeRole = async ({ const handleChangeRole = async ({ identityId, role }: { identityId: string; role: string }) => {
identityId,
role
}: {
identityId: string;
role: string;
}) => {
try { try {
await updateMutateAsync({ await updateMutateAsync({
identityId, identityId,
role, role,
@@ -83,14 +70,14 @@ export const IdentityTable = ({
} catch (err) { } catch (err) {
console.error(err); console.error(err);
const error = err as any; const error = err as any;
const text = error?.response?.data?.message ?? "Failed to update identity role" const text = error?.response?.data?.message ?? "Failed to update identity role";
createNotification({ createNotification({
text, text,
type: "error" type: "error"
}); });
} }
} };
return ( return (
<TableContainer> <TableContainer>
@@ -109,19 +96,11 @@ export const IdentityTable = ({
{!isLoading && {!isLoading &&
data && data &&
data.length > 0 && data.length > 0 &&
data.map(({ data.map(({ identity: { id, name, authMethod }, role, customRole }) => {
identity: {
_id,
name,
authMethod
},
role,
customRole
}) => {
return ( return (
<Tr className="h-10" key={`identity-${_id}`}> <Tr className="h-10" key={`identity-${id}`}>
<Td>{name}</Td> <Td>{name}</Td>
<Td>{_id}</Td> <Td>{id}</Td>
<Td> <Td>
<OrgPermissionCan <OrgPermissionCan
I={OrgPermissionActions.Edit} I={OrgPermissionActions.Edit}
@@ -130,21 +109,18 @@ export const IdentityTable = ({
{(isAllowed) => { {(isAllowed) => {
return ( return (
<Select <Select
value={ value={role === "custom" ? (customRole?.slug as string) : role}
role === "custom" ? (customRole?.slug as string) : role
}
isDisabled={!isAllowed} isDisabled={!isAllowed}
className="w-40 bg-mineshaft-600" className="w-40 bg-mineshaft-600"
dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800" dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800"
onValueChange={(selectedRole) => onValueChange={(selectedRole) =>
handleChangeRole({ handleChangeRole({
identityId: _id, identityId: id,
role: selectedRole role: selectedRole
}) })
} }
> >
{(roles || []) {(roles || []).map(({ slug, name: roleName }) => (
.map(({ slug, name: roleName }) => (
<SelectItem value={slug} key={`owner-option-${slug}`}> <SelectItem value={slug} key={`owner-option-${slug}`}>
{roleName} {roleName}
</SelectItem> </SelectItem>
@@ -156,13 +132,13 @@ export const IdentityTable = ({
</Td> </Td>
<Td>{authMethod ? identityAuthToNameMap[authMethod] : "Not configured"}</Td> <Td>{authMethod ? identityAuthToNameMap[authMethod] : "Not configured"}</Td>
<Td> <Td>
<div className="flex justify-end items-center"> <div className="flex items-center justify-end">
{authMethod === IdentityAuthMethod.UNIVERSAL_AUTH && ( {authMethod === IdentityAuthMethod.UNIVERSAL_AUTH && (
<Tooltip content="Manage client ID/secrets"> <Tooltip content="Manage client ID/secrets">
<IconButton <IconButton
onClick={async () => { onClick={async () => {
handlePopUpOpen("universalAuthClientSecret", { handlePopUpOpen("universalAuthClientSecret", {
identityId: _id, identityId: id,
name name
}); });
}} }}
@@ -185,7 +161,7 @@ export const IdentityTable = ({
<IconButton <IconButton
onClick={async () => { onClick={async () => {
handlePopUpOpen("identityAuthMethod", { handlePopUpOpen("identityAuthMethod", {
identityId: _id, identityId: id,
name, name,
authMethod authMethod
}); });
@@ -210,7 +186,7 @@ export const IdentityTable = ({
<IconButton <IconButton
onClick={async () => { onClick={async () => {
handlePopUpOpen("identity", { handlePopUpOpen("identity", {
identityId: _id, identityId: id,
name, name,
role, role,
customRole customRole
@@ -235,7 +211,7 @@ export const IdentityTable = ({
<IconButton <IconButton
onClick={() => { onClick={() => {
handlePopUpOpen("deleteIdentity", { handlePopUpOpen("deleteIdentity", {
identityId: _id, identityId: id,
name name
}); });
}} }}
@@ -258,7 +234,10 @@ export const IdentityTable = ({
{!isLoading && data && data?.length === 0 && ( {!isLoading && data && data?.length === 0 && (
<Tr> <Tr>
<Td colSpan={4}> <Td colSpan={4}>
<EmptyState title="No identities have been created in this organization" icon={faServer} /> <EmptyState
title="No identities have been created in this organization"
icon={faServer}
/>
</Td> </Td>
</Tr> </Tr>
)} )}
@@ -266,4 +245,4 @@ export const IdentityTable = ({
</Table> </Table>
</TableContainer> </TableContainer>
); );
} };
@@ -24,13 +24,15 @@ import {
Td, Td,
Th, Th,
THead, THead,
Tr, Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { useToggle } from "@app/hooks"; import { useToggle } from "@app/hooks";
import { import {
useCreateIdentityUniversalAuthClientSecret, useCreateIdentityUniversalAuthClientSecret,
useGetIdentityUniversalAuth, useGetIdentityUniversalAuth,
useGetIdentityUniversalAuthClientSecrets, useRevokeIdentityUniversalAuthClientSecret} from "@app/hooks/api"; useGetIdentityUniversalAuthClientSecrets,
useRevokeIdentityUniversalAuthClientSecret
} from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
const schema = yup.object({ const schema = yup.object({
@@ -50,7 +52,12 @@ type Props = {
clientSecretId: string; clientSecretId: string;
} }
) => void; ) => void;
handlePopUpToggle: (popUpName: keyof UsePopUpState<["universalAuthClientSecret", "deleteUniversalAuthClientSecret"]>, state?: boolean) => void; handlePopUpToggle: (
popUpName: keyof UsePopUpState<
["universalAuthClientSecret", "deleteUniversalAuthClientSecret"]
>,
state?: boolean
) => void;
}; };
export const IdentityUniversalAuthClientSecretModal = ({ export const IdentityUniversalAuthClientSecretModal = ({
@@ -64,16 +71,18 @@ export const IdentityUniversalAuthClientSecretModal = ({
const [isClientSecretCopied, setIsClientSecretCopied] = useToggle(false); const [isClientSecretCopied, setIsClientSecretCopied] = useToggle(false);
const [isClientIdCopied, setIsClientIdCopied] = useToggle(false); const [isClientIdCopied, setIsClientIdCopied] = useToggle(false);
const popUpData = (popUp?.universalAuthClientSecret?.data as { const popUpData = popUp?.universalAuthClientSecret?.data as {
identityId?: string; identityId?: string;
name?: string; name?: string;
}); };
const { data, isLoading } = useGetIdentityUniversalAuthClientSecrets(popUpData?.identityId ?? ""); const { data, isLoading } = useGetIdentityUniversalAuthClientSecrets(popUpData?.identityId ?? "");
const { data: identityUniversalAuth } = useGetIdentityUniversalAuth(popUpData?.identityId ?? ""); const { data: identityUniversalAuth } = useGetIdentityUniversalAuth(popUpData?.identityId ?? "");
const { mutateAsync: createClientSecretMutateAsync } = useCreateIdentityUniversalAuthClientSecret(); const { mutateAsync: createClientSecretMutateAsync } =
const { mutateAsync: revokeClientSecretMutateAsync } = useRevokeIdentityUniversalAuthClientSecret(); useCreateIdentityUniversalAuthClientSecret();
const { mutateAsync: revokeClientSecretMutateAsync } =
useRevokeIdentityUniversalAuthClientSecret();
const { const {
control, control,
@@ -107,13 +116,8 @@ export const IdentityUniversalAuthClientSecretModal = ({
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [isClientIdCopied]); }, [isClientIdCopied]);
const onFormSubmit = async ({ const onFormSubmit = async ({ description, ttl, numUsesLimit }: FormData) => {
description,
ttl,
numUsesLimit
}: FormData) => {
try { try {
if (!popUpData?.identityId) return; if (!popUpData?.identityId) return;
const { clientSecret } = await createClientSecretMutateAsync({ const { clientSecret } = await createClientSecretMutateAsync({
@@ -136,7 +140,7 @@ export const IdentityUniversalAuthClientSecretModal = ({
type: "error" type: "error"
}); });
} }
} };
const onDeleteClientSecretSubmit = async ({ const onDeleteClientSecretSubmit = async ({
clientSecretId, clientSecretId,
@@ -146,7 +150,6 @@ export const IdentityUniversalAuthClientSecretModal = ({
clientSecretPrefix: string; clientSecretPrefix: string;
}) => { }) => {
try { try {
if (!popUpData?.identityId) return; if (!popUpData?.identityId) return;
await revokeClientSecretMutateAsync({ await revokeClientSecretMutateAsync({
@@ -171,9 +174,8 @@ export const IdentityUniversalAuthClientSecretModal = ({
text: "Failed to delete client secret", text: "Failed to delete client secret",
type: "error" type: "error"
}); });
}
} }
};
const hasToken = Boolean(token); const hasToken = Boolean(token);
@@ -195,7 +197,7 @@ export const IdentityUniversalAuthClientSecretModal = ({
colorSchema="secondary" colorSchema="secondary"
className="group relative" className="group relative"
onClick={() => { onClick={() => {
navigator.clipboard.writeText(identityUniversalAuth?.clientId ?? "") navigator.clipboard.writeText(identityUniversalAuth?.clientId ?? "");
setIsClientIdCopied.on(); setIsClientIdCopied.on();
}} }}
> >
@@ -240,10 +242,7 @@ export const IdentityUniversalAuthClientSecretModal = ({
</div> </div>
</div> </div>
) : ( ) : (
<form <form onSubmit={handleSubmit(onFormSubmit)} className="mb-8">
onSubmit={handleSubmit(onFormSubmit)}
className="mb-8"
>
<Controller <Controller
control={control} control={control}
defaultValue="" defaultValue=""
@@ -254,10 +253,7 @@ export const IdentityUniversalAuthClientSecretModal = ({
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="Description" />
{...field}
placeholder="Description"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -273,14 +269,7 @@ export const IdentityUniversalAuthClientSecretModal = ({
errorText={error?.message} errorText={error?.message}
> >
<div className="flex"> <div className="flex">
<Input <Input {...field} placeholder="0" type="number" min="0" step="1" />
{...field}
placeholder="0"
type="number"
min="0"
step="1"
/>
</div> </div>
</FormControl> </FormControl>
)} )}
@@ -297,13 +286,7 @@ export const IdentityUniversalAuthClientSecretModal = ({
className="ml-4" className="ml-4"
> >
<div className="flex"> <div className="flex">
<Input <Input {...field} placeholder="0" type="number" min="0" step="1" />
{...field}
placeholder="0"
type="number"
min="0"
step="1"
/>
<Button <Button
className="ml-4" className="ml-4"
size="sm" size="sm"
@@ -337,8 +320,9 @@ export const IdentityUniversalAuthClientSecretModal = ({
{!isLoading && {!isLoading &&
data && data &&
data.length > 0 && data.length > 0 &&
data.map(({ data.map(
_id, ({
id,
description, description,
clientSecretTTL, clientSecretTTL,
clientSecretPrefix, clientSecretPrefix,
@@ -352,9 +336,11 @@ export const IdentityUniversalAuthClientSecretModal = ({
} }
return ( return (
<Tr className="h-10 items-center" key={`mi-client-secret-${_id}`}> <Tr className="h-10 items-center" key={`mi-client-secret-${id}`}>
<Td>{description === "" ? "-" : description}</Td> <Td>{description === "" ? "-" : description}</Td>
<Td>{`${clientSecretNumUses}${clientSecretNumUsesLimit ? `/${clientSecretNumUsesLimit}` : ""}`}</Td> <Td>{`${clientSecretNumUses}${
clientSecretNumUsesLimit ? `/${clientSecretNumUsesLimit}` : ""
}`}</Td>
<Td>{expiresAt ? format(expiresAt, "yyyy-MM-dd") : "-"}</Td> <Td>{expiresAt ? format(expiresAt, "yyyy-MM-dd") : "-"}</Td>
<Td>{`${clientSecretPrefix}****`}</Td> <Td>{`${clientSecretPrefix}****`}</Td>
<Td> <Td>
@@ -362,7 +348,7 @@ export const IdentityUniversalAuthClientSecretModal = ({
onClick={() => { onClick={() => {
handlePopUpOpen("deleteUniversalAuthClientSecret", { handlePopUpOpen("deleteUniversalAuthClientSecret", {
clientSecretPrefix, clientSecretPrefix,
clientSecretId: _id clientSecretId: id
}); });
}} }}
size="lg" size="lg"
@@ -375,11 +361,15 @@ export const IdentityUniversalAuthClientSecretModal = ({
</Td> </Td>
</Tr> </Tr>
); );
})} }
)}
{!isLoading && data && data?.length === 0 && ( {!isLoading && data && data?.length === 0 && (
<Tr> <Tr>
<Td colSpan={5}> <Td colSpan={5}>
<EmptyState title="No client secrets have been created for this identity yet" icon={faKey} /> <EmptyState
title="No client secrets have been created for this identity yet"
icon={faKey}
/>
</Td> </Td>
</Tr> </Tr>
)} )}
@@ -389,15 +379,16 @@ export const IdentityUniversalAuthClientSecretModal = ({
<DeleteActionModal <DeleteActionModal
isOpen={popUp.deleteUniversalAuthClientSecret.isOpen} isOpen={popUp.deleteUniversalAuthClientSecret.isOpen}
title={`Are you sure want to delete the client secret ${ title={`Are you sure want to delete the client secret ${
(popUp?.deleteUniversalAuthClientSecret?.data as { clientSecretPrefix: string })?.clientSecretPrefix || "" (popUp?.deleteUniversalAuthClientSecret?.data as { clientSecretPrefix: string })
?.clientSecretPrefix || ""
}************?`} }************?`}
onChange={(isOpen) => handlePopUpToggle("deleteUniversalAuthClientSecret", isOpen)} onChange={(isOpen) => handlePopUpToggle("deleteUniversalAuthClientSecret", isOpen)}
deleteKey="confirm" deleteKey="confirm"
onDeleteApproved={() => { onDeleteApproved={() => {
const deleteClientSecretData = (popUp?.deleteUniversalAuthClientSecret?.data as { const deleteClientSecretData = popUp?.deleteUniversalAuthClientSecret?.data as {
clientSecretId: string; clientSecretId: string;
clientSecretPrefix: string; clientSecretPrefix: string;
}); };
return onDeleteClientSecretSubmit({ return onDeleteClientSecretSubmit({
clientSecretId: deleteClientSecretData.clientSecretId, clientSecretId: deleteClientSecretData.clientSecretId,
@@ -408,4 +399,4 @@ export const IdentityUniversalAuthClientSecretModal = ({
</ModalContent> </ModalContent>
</Modal> </Modal>
); );
} };
@@ -6,16 +6,8 @@ import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup"; import * as yup from "yup";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { import { Button, FormControl, IconButton, Input } from "@app/components/v2";
Button, import { useOrganization, useSubscription } from "@app/context";
FormControl,
IconButton,
Input,
} from "@app/components/v2";
import {
useOrganization,
useSubscription
} from "@app/context";
import { import {
useAddIdentityUniversalAuth, useAddIdentityUniversalAuth,
useGetIdentityUniversalAuth, useGetIdentityUniversalAuth,
@@ -25,16 +17,11 @@ import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
const schema = yup.object({ const schema = yup
accessTokenTTL: yup .object({
.string() accessTokenTTL: yup.string().required("Access Token TTL is required"),
.required("Access Token TTL is required"), accessTokenMaxTTL: yup.string().required("Access Max Token TTL is required"),
accessTokenMaxTTL: yup accessTokenNumUsesLimit: yup.string().required("Access Token Max Number of Uses is required"),
.string()
.required("Access Max Token TTL is required"),
accessTokenNumUsesLimit: yup
.string()
.required("Access Token Max Number of Uses is required"),
clientSecretTrustedIps: yup clientSecretTrustedIps: yup
.array( .array(
yup.object({ yup.object({
@@ -53,19 +40,23 @@ const schema = yup.object({
.min(1) .min(1)
.required() .required()
.label("Access Token Trusted IP") .label("Access Token Trusted IP")
}).required(); })
.required();
export type FormData = yup.InferType<typeof schema>; export type FormData = yup.InferType<typeof schema>;
type Props = { type Props = {
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void; handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
handlePopUpToggle: (popUpName: keyof UsePopUpState<["identityAuthMethod"]>, state?: boolean) => void; handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData: { identityAuthMethodData: {
identityId: string; identityId: string;
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
} };
} };
export const IdentityUniversalAuthForm = ({ export const IdentityUniversalAuthForm = ({
handlePopUpOpen, handlePopUpOpen,
@@ -74,7 +65,7 @@ export const IdentityUniversalAuthForm = ({
}: Props) => { }: Props) => {
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?._id || ""; const orgId = currentOrg?.id || "";
const { subscription } = useSubscription(); const { subscription } = useSubscription();
const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth(); const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityUniversalAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityUniversalAuth();
@@ -91,14 +82,8 @@ export const IdentityUniversalAuthForm = ({
accessTokenTTL: "2592000", accessTokenTTL: "2592000",
accessTokenMaxTTL: "2592000", accessTokenMaxTTL: "2592000",
accessTokenNumUsesLimit: "0", accessTokenNumUsesLimit: "0",
clientSecretTrustedIps: [ clientSecretTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }],
{ ipAddress: "0.0.0.0/0" }, accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]
{ ipAddress: "::/0" }
],
accessTokenTrustedIps: [
{ ipAddress: "0.0.0.0/0" },
{ ipAddress: "::/0" }
],
} }
}); });
@@ -119,36 +104,28 @@ export const IdentityUniversalAuthForm = ({
accessTokenTTL: String(data.accessTokenTTL), accessTokenTTL: String(data.accessTokenTTL),
accessTokenMaxTTL: String(data.accessTokenMaxTTL), accessTokenMaxTTL: String(data.accessTokenMaxTTL),
accessTokenNumUsesLimit: String(data.accessTokenNumUsesLimit), accessTokenNumUsesLimit: String(data.accessTokenNumUsesLimit),
clientSecretTrustedIps: data.clientSecretTrustedIps.map(({ clientSecretTrustedIps: data.clientSecretTrustedIps.map(
ipAddress, ({ ipAddress, prefix }: IdentityTrustedIp) => {
prefix return {
}: IdentityTrustedIp) => {
return ({
ipAddress: `${ipAddress}${prefix !== undefined ? `/${prefix}` : ""}` ipAddress: `${ipAddress}${prefix !== undefined ? `/${prefix}` : ""}`
}); };
}), }
accessTokenTrustedIps: data.accessTokenTrustedIps.map(({ ),
ipAddress, accessTokenTrustedIps: data.accessTokenTrustedIps.map(
prefix ({ ipAddress, prefix }: IdentityTrustedIp) => {
}: IdentityTrustedIp) => { return {
return ({
ipAddress: `${ipAddress}${prefix !== undefined ? `/${prefix}` : ""}` ipAddress: `${ipAddress}${prefix !== undefined ? `/${prefix}` : ""}`
}); };
}) }
)
}); });
} else { } else {
reset({ reset({
accessTokenTTL: "2592000", accessTokenTTL: "2592000",
accessTokenMaxTTL: "2592000", accessTokenMaxTTL: "2592000",
accessTokenNumUsesLimit: "0", accessTokenNumUsesLimit: "0",
clientSecretTrustedIps: [ clientSecretTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }],
{ ipAddress: "0.0.0.0/0" }, accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]
{ ipAddress: "::/0" }
],
accessTokenTrustedIps: [
{ ipAddress: "0.0.0.0/0" },
{ ipAddress: "::/0" }
]
}); });
} }
}, [data]); }, [data]);
@@ -161,7 +138,6 @@ export const IdentityUniversalAuthForm = ({
accessTokenTrustedIps accessTokenTrustedIps
}: FormData) => { }: FormData) => {
try { try {
if (!identityAuthMethodData) return; if (!identityAuthMethodData) return;
if (data) { if (data) {
@@ -173,9 +149,8 @@ export const IdentityUniversalAuthForm = ({
accessTokenTTL: Number(accessTokenTTL), accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL), accessTokenMaxTTL: Number(accessTokenMaxTTL),
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit), accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
accessTokenTrustedIps, accessTokenTrustedIps
}); });
} else { } else {
// create new universal auth configuration // create new universal auth configuration
@@ -186,14 +161,16 @@ export const IdentityUniversalAuthForm = ({
accessTokenTTL: Number(accessTokenTTL), accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL), accessTokenMaxTTL: Number(accessTokenMaxTTL),
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit), accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
accessTokenTrustedIps, accessTokenTrustedIps
}); });
} }
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${identityAuthMethodData?.authMethod ? "updated" : "configured"} auth method`, text: `Successfully ${
identityAuthMethodData?.authMethod ? "updated" : "configured"
} auth method`,
type: "success" type: "success"
}); });
@@ -201,15 +178,16 @@ export const IdentityUniversalAuthForm = ({
} catch (err) { } catch (err) {
console.error(err); console.error(err);
const error = err as any; const error = err as any;
const text = error?.response?.data?.message const text =
?? `Failed to ${identityAuthMethodData?.authMethod ? "update" : "configure"} identity`; error?.response?.data?.message ??
`Failed to ${identityAuthMethodData?.authMethod ? "update" : "configure"} identity`;
createNotification({ createNotification({
text, text,
type: "error" type: "error"
}); });
} }
} };
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
@@ -223,13 +201,7 @@ export const IdentityUniversalAuthForm = ({
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
{...field}
placeholder="2592000"
type="number"
min="1"
step="1"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -243,13 +215,7 @@ export const IdentityUniversalAuthForm = ({
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
{...field}
placeholder="2592000"
type="number"
min="1"
step="1"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -263,18 +229,12 @@ export const IdentityUniversalAuthForm = ({
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="0" type="number" min="0" step="1" />
{...field}
placeholder="0"
type="number"
min="0"
step="1"
/>
</FormControl> </FormControl>
)} )}
/> />
{clientSecretTrustedIpsFields.map(({ id }, index) => ( {clientSecretTrustedIpsFields.map(({ id }, index) => (
<div className="flex items-end space-x-2 mb-3" key={id}> <div className="mb-3 flex items-end space-x-2" key={id}>
<Controller <Controller
control={control} control={control}
name={`clientSecretTrustedIps.${index}.ipAddress`} name={`clientSecretTrustedIps.${index}.ipAddress`}
@@ -329,7 +289,7 @@ export const IdentityUniversalAuthForm = ({
if (subscription?.ipAllowlisting) { if (subscription?.ipAllowlisting) {
appendClientSecretTrustedIp({ appendClientSecretTrustedIp({
ipAddress: "0.0.0.0/0" ipAddress: "0.0.0.0/0"
}) });
return; return;
} }
@@ -342,7 +302,7 @@ export const IdentityUniversalAuthForm = ({
</Button> </Button>
</div> </div>
{accessTokenTrustedIpsFields.map(({ id }, index) => ( {accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="flex items-end space-x-2 mb-3" key={id}> <div className="mb-3 flex items-end space-x-2" key={id}>
<Controller <Controller
control={control} control={control}
name={`accessTokenTrustedIps.${index}.ipAddress`} name={`accessTokenTrustedIps.${index}.ipAddress`}
@@ -397,7 +357,7 @@ export const IdentityUniversalAuthForm = ({
if (subscription?.ipAllowlisting) { if (subscription?.ipAllowlisting) {
appendAccessTokenTrustedIp({ appendAccessTokenTrustedIp({
ipAddress: "0.0.0.0/0" ipAddress: "0.0.0.0/0"
}) });
return; return;
} }
@@ -429,4 +389,4 @@ export const IdentityUniversalAuthForm = ({
</div> </div>
</form> </form>
); );
} };
@@ -1,27 +1,14 @@
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
faCheck,
faCopy,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup"; import * as yup from "yup";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { import { Button, FormControl, IconButton, Input, Modal, ModalContent } from "@app/components/v2";
Button,
FormControl,
IconButton,
Input,
Modal,
ModalContent,
} from "@app/components/v2";
import { useOrganization } from "@app/context"; import { useOrganization } from "@app/context";
import { useToggle } from "@app/hooks"; import { useToggle } from "@app/hooks";
import { import { useAddUserToOrg, useFetchServerStatus } from "@app/hooks/api";
useAddUserToOrg,
useFetchServerStatus
} from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
const addMemberFormSchema = yup.object({ const addMemberFormSchema = yup.object({
@@ -59,11 +46,11 @@ export const AddOrgMemberModal = ({
} = useForm<TAddMemberForm>({ resolver: yupResolver(addMemberFormSchema) }); } = useForm<TAddMemberForm>({ resolver: yupResolver(addMemberFormSchema) });
const onAddMember = async ({ email }: TAddMemberForm) => { const onAddMember = async ({ email }: TAddMemberForm) => {
if (!currentOrg?._id) return; if (!currentOrg?.id) return;
try { try {
const { data } = await addUserMutateAsync({ const { data } = await addUserMutateAsync({
organizationId: currentOrg?._id, organizationId: currentOrg?.id,
inviteeEmail: email inviteeEmail: email
}); });
@@ -173,4 +160,4 @@ export const AddOrgMemberModal = ({
</ModalContent> </ModalContent>
</Modal> </Modal>
); );
} };
@@ -14,12 +14,9 @@ import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
useOrganization, useOrganization,
useSubscription, useSubscription
} from "@app/context"; } from "@app/context";
import { import { useDeleteOrgMembership, useGetSSOConfig } from "@app/hooks/api";
useDeleteOrgMembership,
useGetSSOConfig,
} from "@app/hooks/api";
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
import { AddOrgMemberModal } from "./AddOrgMemberModal"; import { AddOrgMemberModal } from "./AddOrgMemberModal";
@@ -29,7 +26,7 @@ export const OrgMembersSection = () => {
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { subscription } = useSubscription(); const { subscription } = useSubscription();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?._id ?? ""; const orgId = currentOrg?.id ?? "";
const [completeInviteLink, setCompleteInviteLink] = useState<string>(""); const [completeInviteLink, setCompleteInviteLink] = useState<string>("");
@@ -63,7 +60,7 @@ export const OrgMembersSection = () => {
} else { } else {
handlePopUpOpen("addMember"); handlePopUpOpen("addMember");
} }
} };
const onRemoveMemberSubmit = async (orgMembershipId: string) => { const onRemoveMemberSubmit = async (orgMembershipId: string) => {
try { try {
@@ -85,18 +82,13 @@ export const OrgMembersSection = () => {
} }
handlePopUpClose("removeMember"); handlePopUpClose("removeMember");
} };
return ( return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"> <div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="flex justify-between mb-4"> <div className="mb-4 flex justify-between">
<p className="text-xl font-semibold text-mineshaft-100"> <p className="text-xl font-semibold text-mineshaft-100">Members</p>
Members <OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
</p>
<OrgPermissionCan
I={OrgPermissionActions.Create}
a={OrgPermissionSubjects.Member}
>
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
colorSchema="primary" colorSchema="primary"
@@ -144,4 +136,4 @@ export const OrgMembersSection = () => {
/> />
</div> </div>
); );
} };
@@ -1,9 +1,5 @@
import { useCallback, useMemo, useState } from "react"; import { useCallback, useMemo, useState } from "react";
import { import { faMagnifyingGlass, faUsers, faXmark } from "@fortawesome/free-solid-svg-icons";
faMagnifyingGlass,
faUsers,
faXmark
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
@@ -22,14 +18,15 @@ import {
Td, Td,
Th, Th,
THead, THead,
Tr, Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
useOrganization, useOrganization,
useSubscription, useSubscription,
useUser} from "@app/context"; useUser
} from "@app/context";
import { import {
useAddUserToOrg, useAddUserToOrg,
useFetchServerStatus, useFetchServerStatus,
@@ -51,16 +48,13 @@ type Props = {
setCompleteInviteLink: (link: string) => void; setCompleteInviteLink: (link: string) => void;
}; };
export const OrgMembersTable = ({ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLink }: Props) => {
handlePopUpOpen,
setCompleteInviteLink
}: Props) => {
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { subscription } = useSubscription(); const { subscription } = useSubscription();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const { user } = useUser(); const { user } = useUser();
const userId = user?._id || ""; const userId = user?.id || "";
const orgId = currentOrg?._id || ""; const orgId = currentOrg?.id || "";
const { data: roles, isLoading: isRolesLoading } = useGetRoles({ const { data: roles, isLoading: isRolesLoading } = useGetRoles({
orgId orgId
@@ -75,7 +69,7 @@ export const OrgMembersTable = ({
const { mutateAsync: updateUserOrgRole } = useUpdateOrgUserRole(); const { mutateAsync: updateUserOrgRole } = useUpdateOrgUserRole();
const onRoleChange = async (membershipId: string, role: string) => { const onRoleChange = async (membershipId: string, role: string) => {
if (!currentOrg?._id) return; if (!currentOrg?.id) return;
try { try {
// TODO: replace hardcoding default role // TODO: replace hardcoding default role
@@ -89,8 +83,9 @@ export const OrgMembersTable = ({
} }
await updateUserOrgRole({ await updateUserOrgRole({
organizationId: currentOrg?._id, organizationId: currentOrg?.id,
membershipId, role membershipId,
role
}); });
createNotification({ createNotification({
@@ -108,7 +103,6 @@ export const OrgMembersTable = ({
const onResendInvite = async (email: string) => { const onResendInvite = async (email: string) => {
try { try {
const { data } = await addUserMutateAsync({ const { data } = await addUserMutateAsync({
organizationId: orgId, organizationId: orgId,
inviteeEmail: email inviteeEmail: email
@@ -129,18 +123,18 @@ export const OrgMembersTable = ({
type: "error" type: "error"
}); });
} }
} };
const isLoading = isMembersLoading || isRolesLoading; const isLoading = isMembersLoading || isRolesLoading;
const isIamOwner = useMemo( const isIamOwner = useMemo(
() => members?.find(({ user: u }) => userId === u?._id)?.role === "owner", () => members?.find(({ user: u }) => userId === u?.id)?.role === "owner",
[userId, members] [userId, members]
); );
const findRoleFromId = useCallback( const findRoleFromId = useCallback(
(roleId: string) => { (roleId: string) => {
return (roles || []).find(({ _id: id }) => id === roleId); return (roles || []).find(({ id }) => id === roleId);
}, },
[roles] [roles]
); );
@@ -179,7 +173,7 @@ export const OrgMembersTable = ({
{isLoading && <TableSkeleton columns={5} innerKey="org-members" />} {isLoading && <TableSkeleton columns={5} innerKey="org-members" />}
{!isLoading && {!isLoading &&
filterdUser?.map( filterdUser?.map(
({ user: u, inviteEmail, role, customRole, _id: orgMembershipId, status }) => { ({ user: u, inviteEmail, role, customRole, id: orgMembershipId, status }) => {
const name = u ? `${u.firstName} ${u.lastName}` : "-"; const name = u ? `${u.firstName} ${u.lastName}` : "-";
const email = u?.email || inviteEmail; const email = u?.email || inviteEmail;
return ( return (
@@ -198,7 +192,7 @@ export const OrgMembersTable = ({
value={ value={
role === "custom" ? findRoleFromId(customRole)?.slug : role role === "custom" ? findRoleFromId(customRole)?.slug : role
} }
isDisabled={userId === u?._id || !isAllowed} isDisabled={userId === u?.id || !isAllowed}
className="w-40 bg-mineshaft-600" className="w-40 bg-mineshaft-600"
dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800" dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800"
onValueChange={(selectedRole) => onValueChange={(selectedRole) =>
@@ -233,7 +227,7 @@ export const OrgMembersTable = ({
</OrgPermissionCan> </OrgPermissionCan>
</Td> </Td>
<Td> <Td>
{userId !== u?._id && ( {userId !== u?.id && (
<OrgPermissionCan <OrgPermissionCan
I={OrgPermissionActions.Delete} I={OrgPermissionActions.Delete}
a={OrgPermissionSubjects.Member} a={OrgPermissionSubjects.Member}
@@ -241,7 +235,7 @@ export const OrgMembersTable = ({
{(isAllowed) => ( {(isAllowed) => (
<IconButton <IconButton
onClick={() => { onClick={() => {
handlePopUpOpen("removeMember", { orgMembershipId, email }) handlePopUpOpen("removeMember", { orgMembershipId, email });
}} }}
size="lg" size="lg"
colorSchema="danger" colorSchema="danger"
@@ -266,7 +260,6 @@ export const OrgMembersTable = ({
<EmptyState title="No project members found" icon={faUsers} /> <EmptyState title="No project members found" icon={faUsers} />
)} )}
</TableContainer> </TableContainer>
</div> </div>
); );
} };
@@ -158,21 +158,21 @@ export const LogsTableRow = ({ auditLog }: Props) => {
<p>{`Name: ${event.metadata.name}`}</p> <p>{`Name: ${event.metadata.name}`}</p>
</Td> </Td>
); );
case EventType.CREATE_IDENTITY: case EventType.CREATEidENTITY:
return ( return (
<Td> <Td>
<p>{`ID: ${event.metadata.identityId}`}</p> <p>{`ID: ${event.metadata.identityId}`}</p>
<p>{`Name: ${event.metadata.name}`}</p> <p>{`Name: ${event.metadata.name}`}</p>
</Td> </Td>
); );
case EventType.UPDATE_IDENTITY: case EventType.UPDATEidENTITY:
return ( return (
<Td> <Td>
<p>{`ID: ${event.metadata.identityId}`}</p> <p>{`ID: ${event.metadata.identityId}`}</p>
<p>{`Name: ${event.metadata.name}`}</p> <p>{`Name: ${event.metadata.name}`}</p>
</Td> </Td>
); );
case EventType.DELETE_IDENTITY: case EventType.DELETEidENTITY:
return ( return (
<Td> <Td>
<p>{`ID: ${event.metadata.identityId}`}</p> <p>{`ID: ${event.metadata.identityId}`}</p>
@@ -5,18 +5,8 @@ import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup"; import * as yup from "yup";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { import { Button, FormControl, Modal, ModalContent, Select, SelectItem } from "@app/components/v2";
Button, import { useOrganization, useWorkspace } from "@app/context";
FormControl,
Modal,
ModalContent,
Select,
SelectItem,
} from "@app/components/v2";
import {
useOrganization,
useWorkspace
} from "@app/context";
import { import {
useAddIdentityToWorkspace, useAddIdentityToWorkspace,
useGetIdentityMembershipOrgs, useGetIdentityMembershipOrgs,
@@ -25,10 +15,12 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
const schema = yup.object({ const schema = yup
.object({
identityId: yup.string().required("Identity id is required"), identityId: yup.string().required("Identity id is required"),
role: yup.string() role: yup.string()
}).required(); })
.required();
export type FormData = yup.InferType<typeof schema>; export type FormData = yup.InferType<typeof schema>;
@@ -37,17 +29,13 @@ type Props = {
handlePopUpToggle: (popUpName: keyof UsePopUpState<["identity"]>, state?: boolean) => void; handlePopUpToggle: (popUpName: keyof UsePopUpState<["identity"]>, state?: boolean) => void;
}; };
export const IdentityModal = ({ export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
popUp,
handlePopUpToggle
}: Props) => {
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const orgId = currentOrg?._id || ""; const orgId = currentOrg?.id || "";
const workspaceId = currentWorkspace?._id || ""; const workspaceId = currentWorkspace?.id || "";
const { data: identityMembershipOrgs } = useGetIdentityMembershipOrgs(orgId); const { data: identityMembershipOrgs } = useGetIdentityMembershipOrgs(orgId);
const { data: identityMemberships } = useGetWorkspaceIdentityMemberships(workspaceId); const { data: identityMemberships } = useGetWorkspaceIdentityMemberships(workspaceId);
@@ -63,12 +51,10 @@ export const IdentityModal = ({
const wsIdentityIds = new Map(); const wsIdentityIds = new Map();
identityMemberships?.forEach((identityMembership) => { identityMemberships?.forEach((identityMembership) => {
wsIdentityIds.set(identityMembership.identity._id, true); wsIdentityIds.set(identityMembership.identity.id, true);
}); });
return (identityMembershipOrgs || []).filter( return (identityMembershipOrgs || []).filter(({ identity: i }) => !wsIdentityIds.has(i.id));
({ identity: i }) => !wsIdentityIds.has(i._id)
);
}, [identityMembershipOrgs, identityMemberships]); }, [identityMembershipOrgs, identityMemberships]);
const { const {
@@ -80,12 +66,8 @@ export const IdentityModal = ({
resolver: yupResolver(schema) resolver: yupResolver(schema)
}); });
const onFormSubmit = async ({ const onFormSubmit = async ({ identityId, role }: FormData) => {
identityId,
role
}: FormData) => {
try { try {
await addIdentityToWorkspaceMutateAsync({ await addIdentityToWorkspaceMutateAsync({
workspaceId, workspaceId,
identityId, identityId,
@@ -102,15 +84,14 @@ export const IdentityModal = ({
} catch (err) { } catch (err) {
console.error(err); console.error(err);
const error = err as any; const error = err as any;
const text = error?.response?.data?.message const text = error?.response?.data?.message ?? "Failed to add identity to project";
?? "Failed to add identity to project";
createNotification({ createNotification({
text, text,
type: "error" type: "error"
}); });
} }
} };
return ( return (
<Modal <Modal
@@ -126,13 +107,9 @@ export const IdentityModal = ({
<Controller <Controller
control={control} control={control}
name="identityId" name="identityId"
defaultValue={filteredIdentityMembershipOrgs?.[0]?._id} defaultValue={filteredIdentityMembershipOrgs?.[0]?.id}
render={({ field: { onChange, ...field }, fieldState: { error } }) => ( render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl <FormControl label="Identity" errorText={error?.message} isError={Boolean(error)}>
label="Identity"
errorText={error?.message}
isError={Boolean(error)}
>
<Select <Select
defaultValue={field.value} defaultValue={field.value}
{...field} {...field}
@@ -140,7 +117,7 @@ export const IdentityModal = ({
className="w-full" className="w-full"
> >
{filteredIdentityMembershipOrgs.map(({ identity }) => ( {filteredIdentityMembershipOrgs.map(({ identity }) => (
<SelectItem value={identity._id} key={`org-identity-${identity._id}`}> <SelectItem value={identity.id} key={`org-identity-${identity.id}`}>
{identity.name} {identity.name}
</SelectItem> </SelectItem>
))} ))}
@@ -191,7 +168,9 @@ export const IdentityModal = ({
</form> </form>
) : ( ) : (
<div className="flex flex-col space-y-4"> <div className="flex flex-col space-y-4">
<div className="text-sm">All identities in your organization have already been added to this project.</div> <div className="text-sm">
All identities in your organization have already been added to this project.
</div>
<Link href={`/org/${currentWorkspace?.organization}/members`}> <Link href={`/org/${currentWorkspace?.organization}/members`}>
<Button variant="outline_bg">Create a new identity</Button> <Button variant="outline_bg">Create a new identity</Button>
</Link> </Link>
@@ -200,4 +179,4 @@ export const IdentityModal = ({
</ModalContent> </ModalContent>
</Modal> </Modal>
); );
} };
@@ -4,14 +4,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { ProjectPermissionCan } from "@app/components/permissions"; import { ProjectPermissionCan } from "@app/components/permissions";
import { import { Button, DeleteActionModal } from "@app/components/v2";
Button, import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
DeleteActionModal
} from "@app/components/v2";
import {
ProjectPermissionActions,
ProjectPermissionSub,
useWorkspace} from "@app/context";
import { withProjectPermission } from "@app/hoc"; import { withProjectPermission } from "@app/hoc";
import { useDeleteIdentityFromWorkspace } from "@app/hooks/api"; import { useDeleteIdentityFromWorkspace } from "@app/hooks/api";
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
@@ -24,7 +18,7 @@ export const IdentitySection = withProjectPermission(
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const workspaceId = currentWorkspace?._id ?? ""; const workspaceId = currentWorkspace?.id ?? "";
const { mutateAsync: deleteMutateAsync } = useDeleteIdentityFromWorkspace(); const { mutateAsync: deleteMutateAsync } = useDeleteIdentityFromWorkspace();
@@ -36,7 +30,6 @@ export const IdentitySection = withProjectPermission(
const onRemoveIdentitySubmit = async (identityId: string) => { const onRemoveIdentitySubmit = async (identityId: string) => {
try { try {
await deleteMutateAsync({ await deleteMutateAsync({
identityId, identityId,
workspaceId workspaceId
@@ -51,25 +44,27 @@ export const IdentitySection = withProjectPermission(
} catch (err) { } catch (err) {
console.error(err); console.error(err);
const error = err as any; const error = err as any;
const text = error?.response?.data?.message ?? "Failed to remove identity from project" const text = error?.response?.data?.message ?? "Failed to remove identity from project";
createNotification({ createNotification({
text, text,
type: "error" type: "error"
}); });
} }
} };
return ( return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"> <div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="flex justify-between items-center mb-4"> <div className="mb-4 flex items-center justify-between">
<p className="text-xl font-semibold text-mineshaft-100"> <p className="text-xl font-semibold text-mineshaft-100">Identities</p>
Identities <div className="flex w-full justify-end pr-4">
</p>
<div className="flex justify-end w-full pr-4">
<Link href="https://infisical.com/docs/documentation/platform/identities/overview"> <Link href="https://infisical.com/docs/documentation/platform/identities/overview">
<span className="rounded-md px-4 py-2 w-max text-mineshaft-200 hover:text-white bg-mineshaft-600 border border-mineshaft-500 hover:bg-primary/10 hover:border-primary/40 duration-200 cursor-pointer"> <span className="w-max cursor-pointer rounded-md border border-mineshaft-500 bg-mineshaft-600 px-4 py-2 text-mineshaft-200 duration-200 hover:border-primary/40 hover:bg-primary/10 hover:text-white">
Documentation <FontAwesomeIcon icon={faArrowUpRightFromSquare} className="text-xs mb-[0.06rem] ml-1"/> Documentation{" "}
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.06rem] ml-1 text-xs"
/>
</span> </span>
</Link> </Link>
</div> </div>
@@ -90,13 +85,8 @@ export const IdentitySection = withProjectPermission(
)} )}
</ProjectPermissionCan> </ProjectPermissionCan>
</div> </div>
<IdentityTable <IdentityTable handlePopUpOpen={handlePopUpOpen} />
handlePopUpOpen={handlePopUpOpen} <IdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
/>
<IdentityModal
popUp={popUp}
handlePopUpToggle={handlePopUpToggle}
/>
<DeleteActionModal <DeleteActionModal
isOpen={popUp.deleteIdentity.isOpen} isOpen={popUp.deleteIdentity.isOpen}
title={`Are you sure want to remove ${ title={`Are you sure want to remove ${
@@ -22,12 +22,13 @@ import {
ProjectPermissionActions, ProjectPermissionActions,
ProjectPermissionSub, ProjectPermissionSub,
useOrganization, useOrganization,
useWorkspace, useWorkspace
} from "@app/context"; } from "@app/context";
import { import {
useGetRoles, useGetRoles,
useGetWorkspaceIdentityMemberships, useGetWorkspaceIdentityMemberships,
useUpdateIdentityWorkspaceRole} from "@app/hooks/api"; useUpdateIdentityWorkspaceRole
} from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
type Props = { type Props = {
@@ -40,15 +41,13 @@ type Props = {
) => void; ) => void;
}; };
export const IdentityTable = ({ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
handlePopUpOpen
}: Props) => {
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const orgId = currentOrg?._id || ""; const orgId = currentOrg?.id || "";
const workspaceId = currentWorkspace?._id || ""; const workspaceId = currentWorkspace?.id || "";
const { data, isLoading } = useGetWorkspaceIdentityMemberships(currentWorkspace?._id || ""); const { data, isLoading } = useGetWorkspaceIdentityMemberships(currentWorkspace?.id || "");
const { data: roles } = useGetRoles({ const { data: roles } = useGetRoles({
orgId, orgId,
@@ -57,15 +56,8 @@ export const IdentityTable = ({
const { mutateAsync: updateMutateAsync } = useUpdateIdentityWorkspaceRole(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityWorkspaceRole();
const handleChangeRole = async ({ const handleChangeRole = async ({ identityId, role }: { identityId: string; role: string }) => {
identityId,
role
}: {
identityId: string;
role: string;
}) => {
try { try {
await updateMutateAsync({ await updateMutateAsync({
identityId, identityId,
workspaceId, workspaceId,
@@ -79,14 +71,14 @@ export const IdentityTable = ({
} catch (err) { } catch (err) {
console.error(err); console.error(err);
const error = err as any; const error = err as any;
const text = error?.response?.data?.message ?? "Failed to update identity role" const text = error?.response?.data?.message ?? "Failed to update identity role";
createNotification({ createNotification({
text, text,
type: "error" type: "error"
}); });
} }
} };
return ( return (
<TableContainer> <TableContainer>
@@ -104,17 +96,9 @@ export const IdentityTable = ({
{!isLoading && {!isLoading &&
data && data &&
data.length > 0 && data.length > 0 &&
data.map(({ data.map(({ identity: { id, name }, role, customRole, createdAt }) => {
identity: {
_id,
name
},
role,
customRole,
createdAt
}) => {
return ( return (
<Tr className="h-10" key={`st-v3-${_id}`}> <Tr className="h-10" key={`st-v3-${id}`}>
<Td>{name}</Td> <Td>{name}</Td>
<Td> <Td>
<ProjectPermissionCan <ProjectPermissionCan
@@ -124,21 +108,18 @@ export const IdentityTable = ({
{(isAllowed) => { {(isAllowed) => {
return ( return (
<Select <Select
value={ value={role === "custom" ? (customRole?.slug as string) : role}
role === "custom" ? (customRole?.slug as string) : role
}
isDisabled={!isAllowed} isDisabled={!isAllowed}
className="w-40 bg-mineshaft-600" className="w-40 bg-mineshaft-600"
dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800" dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800"
onValueChange={(selectedRole) => onValueChange={(selectedRole) =>
handleChangeRole({ handleChangeRole({
identityId: _id, identityId: id,
role: selectedRole role: selectedRole
}) })
} }
> >
{(roles || []) {(roles || []).map(({ slug, name: roleName }) => (
.map(({ slug, name: roleName }) => (
<SelectItem value={slug} key={`owner-option-${slug}`}> <SelectItem value={slug} key={`owner-option-${slug}`}>
{roleName} {roleName}
</SelectItem> </SelectItem>
@@ -158,7 +139,7 @@ export const IdentityTable = ({
<IconButton <IconButton
onClick={() => { onClick={() => {
handlePopUpOpen("deleteIdentity", { handlePopUpOpen("deleteIdentity", {
identityId: _id, identityId: id,
name name
}); });
}} }}
@@ -188,4 +169,4 @@ export const IdentityTable = ({
</Table> </Table>
</TableContainer> </TableContainer>
); );
} };
@@ -190,7 +190,7 @@ export const SSOModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props)
<> <>
<div className="mb-4"> <div className="mb-4">
<h3 className="text-sm text-mineshaft-400">{renderLabels(authProvider).acsUrl}</h3> <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> <p className="text-md break-all text-gray-400">{`${window.origin}/api/v1/sso/saml2/${data.id}`}</p>
</div> </div>
<div className="mb-4"> <div className="mb-4">
<h3 className="text-sm text-mineshaft-400"> <h3 className="text-sm text-mineshaft-400">