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