mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Requested changes
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
import { faFilter } from "@fortawesome/free-solid-svg-icons";
|
import { faFilter } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import { IconButton, Tooltip } from "@app/components/v2";
|
import { EmptyState, IconButton, Tooltip } from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context";
|
||||||
import { withPermission } from "@app/hoc";
|
import { withPermission } from "@app/hoc";
|
||||||
import { OrgUser } from "@app/hooks/api/types";
|
import { OrgUser } from "@app/hooks/api/types";
|
||||||
import { LogsSection } from "@app/views/Project/AuditLogsPage/components";
|
import { LogsSection } from "@app/views/Project/AuditLogsPage/components";
|
||||||
@@ -15,8 +16,10 @@ type Props = {
|
|||||||
export const UserAuditLogsSection = withPermission(
|
export const UserAuditLogsSection = withPermission(
|
||||||
({ orgMembership }: Props) => {
|
({ orgMembership }: Props) => {
|
||||||
const [showFilter, setShowFilter] = useState(false);
|
const [showFilter, setShowFilter] = useState(false);
|
||||||
|
const { subscription, isLoading } = useSubscription();
|
||||||
|
|
||||||
return (
|
// eslint-disable-next-line no-nested-ternary
|
||||||
|
return subscription?.auditLogs ? (
|
||||||
<div className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
<div className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
<div className="mb-4 flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
<div className="mb-4 flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||||
<p className="text-lg font-semibold text-gray-200">Audit Logs</p>
|
<p className="text-lg font-semibold text-gray-200">Audit Logs</p>
|
||||||
@@ -43,7 +46,39 @@ export const UserAuditLogsSection = withPermission(
|
|||||||
isOrgAuditLogs
|
isOrgAuditLogs
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
) : !isLoading ? (
|
||||||
|
<div className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4 opacity-50">
|
||||||
|
<div className="mb-4 flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||||
|
<p className="text-lg font-semibold text-gray-200">Audit Logs</p>
|
||||||
|
</div>
|
||||||
|
<EmptyState
|
||||||
|
className="rounded-lg"
|
||||||
|
title={
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Please{" "}
|
||||||
|
<Link
|
||||||
|
href={
|
||||||
|
subscription && subscription.slug !== null
|
||||||
|
? `/org/${orgMembership.organization}/billing`
|
||||||
|
: "https://infisical.com/scheduledemo"
|
||||||
|
}
|
||||||
|
passHref
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
className="cursor-pointer font-medium text-primary-500 transition-all hover:text-primary-600"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
upgrade your subscription
|
||||||
|
</a>
|
||||||
|
</Link>{" "}
|
||||||
|
to view audit logs.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
},
|
},
|
||||||
{ action: OrgPermissionActions.Read, subject: OrgPermissionSubjects.Member }
|
{ action: OrgPermissionActions.Read, subject: OrgPermissionSubjects.Member }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
import { useMemo, useState } from "react";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { faFolder, faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
||||||
|
|
||||||
import {
|
|
||||||
EmptyState,
|
|
||||||
Input,
|
|
||||||
Modal,
|
|
||||||
ModalContent,
|
|
||||||
Table,
|
|
||||||
TableContainer,
|
|
||||||
TBody,
|
|
||||||
Td,
|
|
||||||
Th,
|
|
||||||
THead,
|
|
||||||
Tooltip,
|
|
||||||
Tr
|
|
||||||
} from "@app/components/v2";
|
|
||||||
import { TGroupWithProjectMemberships } from "@app/hooks/api/groups/types";
|
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
|
||||||
|
|
||||||
export type UserGroupsProjectsModalData = {
|
|
||||||
group: TGroupWithProjectMemberships;
|
|
||||||
groupSlug: string;
|
|
||||||
username: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const UserGroupsProjectsModal = ({
|
|
||||||
popUp,
|
|
||||||
handlePopUpToggle
|
|
||||||
}: {
|
|
||||||
popUp: UsePopUpState<["userGroupsProjects"]>;
|
|
||||||
handlePopUpToggle: (
|
|
||||||
popUpName: keyof UsePopUpState<["userGroupsProjects"]>,
|
|
||||||
state?: boolean
|
|
||||||
) => void;
|
|
||||||
}) => {
|
|
||||||
const popupData = popUp.userGroupsProjects.data as UserGroupsProjectsModalData;
|
|
||||||
|
|
||||||
const [filteredProjectName, setFilteredProjectName] = useState("");
|
|
||||||
|
|
||||||
const filteredMemberships = useMemo(() => {
|
|
||||||
if (!popupData?.group) return [];
|
|
||||||
|
|
||||||
return popupData.group.projectMemberships.filter(({ project }) => {
|
|
||||||
return project.name.toLowerCase().includes(filteredProjectName.toLowerCase());
|
|
||||||
});
|
|
||||||
}, [filteredProjectName, popupData?.group?.projectMemberships]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
isOpen={popUp.userGroupsProjects.isOpen}
|
|
||||||
onOpenChange={(open) => {
|
|
||||||
handlePopUpToggle("userGroupsProjects", open);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ModalContent
|
|
||||||
title="View group projects"
|
|
||||||
subTitle="View which projects this group has access to"
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
value={filteredProjectName}
|
|
||||||
onChange={(e) => setFilteredProjectName(e.target.value)}
|
|
||||||
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
|
|
||||||
placeholder="Search projects..."
|
|
||||||
/>
|
|
||||||
<TableContainer className="mt-4">
|
|
||||||
<Table>
|
|
||||||
<THead>
|
|
||||||
<Tr>
|
|
||||||
<Th>Project</Th>
|
|
||||||
<Th>Roles</Th>
|
|
||||||
</Tr>
|
|
||||||
</THead>
|
|
||||||
<TBody className="w-full">
|
|
||||||
{filteredMemberships?.map(({ project, roles }) => {
|
|
||||||
return (
|
|
||||||
<Tr className="" key={`group-project-${project.id}`}>
|
|
||||||
<Td>
|
|
||||||
<Link href={`/project/${project.id}/secrets/overview`}>
|
|
||||||
<p className="cursor-pointer font-medium capitalize transition-all hover:text-primary-500">
|
|
||||||
{project.name}
|
|
||||||
</p>
|
|
||||||
</Link>
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<Tooltip
|
|
||||||
isDisabled={roles.length === 1}
|
|
||||||
content={roles
|
|
||||||
.map((role) => role.role.charAt(0).toUpperCase() + role.role.slice(1))
|
|
||||||
.join(", ")}
|
|
||||||
>
|
|
||||||
<p className="w-fit capitalize">
|
|
||||||
{roles.length === 1
|
|
||||||
? roles[0].role
|
|
||||||
: `${roles[0].role} (+${roles.length - 1} more)`}
|
|
||||||
</p>
|
|
||||||
</Tooltip>
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TBody>
|
|
||||||
</Table>
|
|
||||||
{!filteredMemberships.length && <EmptyState title="No projects found" icon={faFolder} />}
|
|
||||||
</TableContainer>
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -4,39 +4,21 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
|
|
||||||
import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
|
import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
|
||||||
import { TGroupWithProjectMemberships } from "@app/hooks/api/groups/types";
|
import { TGroupWithProjectMemberships } from "@app/hooks/api/groups/types";
|
||||||
import { OrgUser } from "@app/hooks/api/types";
|
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
import { UserGroupsProjectsModalData } from "./UserGroupProjectsModal";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
group: TGroupWithProjectMemberships;
|
group: TGroupWithProjectMemberships;
|
||||||
orgMembership: OrgUser;
|
handlePopUpOpen: (popUpName: keyof UsePopUpState<["removeUserFromGroup"]>, data?: {}) => void;
|
||||||
handlePopUpOpen: (
|
|
||||||
popUpName: keyof UsePopUpState<["removeUserFromGroup", "userGroupsProjects"]>,
|
|
||||||
data?: {}
|
|
||||||
) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserGroupsRow = ({ group, orgMembership, handlePopUpOpen }: Props) => {
|
export const UserGroupsRow = ({ group, handlePopUpOpen }: Props) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tr
|
<Tr
|
||||||
className="group h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
className="group h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
||||||
key={`user-project-membership-${group.id}`}
|
key={`user-project-membership-${group.id}`}
|
||||||
onClick={() => {
|
|
||||||
handlePopUpOpen("userGroupsProjects", {
|
|
||||||
groupSlug: group.slug,
|
|
||||||
username: orgMembership.user.username,
|
|
||||||
group
|
|
||||||
} as UserGroupsProjectsModalData);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Td>{group.name}</Td>
|
<Td>{group.name}</Td>
|
||||||
<Td>
|
|
||||||
{group.projectMemberships.length} Project
|
|
||||||
{group.projectMemberships.length > 1 || group.projectMemberships.length === 0 ? "s" : ""}
|
|
||||||
</Td>
|
|
||||||
<Td>
|
<Td>
|
||||||
{true && (
|
{true && (
|
||||||
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { useRemoveUserFromGroup } from "@app/hooks/api";
|
|||||||
import { OrgUser } from "@app/hooks/api/users/types";
|
import { OrgUser } from "@app/hooks/api/users/types";
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
import { UserGroupsProjectsModal } from "./UserGroupProjectsModal";
|
|
||||||
import { UserGroupsTable } from "./UserGroupsTable";
|
import { UserGroupsTable } from "./UserGroupsTable";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -15,8 +14,7 @@ type Props = {
|
|||||||
|
|
||||||
export const UserGroupsSection = ({ orgMembership }: Props) => {
|
export const UserGroupsSection = ({ orgMembership }: Props) => {
|
||||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||||
"removeUserFromGroup",
|
"removeUserFromGroup"
|
||||||
"userGroupsProjects"
|
|
||||||
] as const);
|
] as const);
|
||||||
|
|
||||||
const { mutateAsync: removeUserFromGroup } = useRemoveUserFromGroup();
|
const { mutateAsync: removeUserFromGroup } = useRemoveUserFromGroup();
|
||||||
@@ -65,8 +63,6 @@ export const UserGroupsSection = ({ orgMembership }: Props) => {
|
|||||||
return handleRemoveUserFromGroup(popupData.groupSlug);
|
return handleRemoveUserFromGroup(popupData.groupSlug);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UserGroupsProjectsModal handlePopUpToggle={handlePopUpToggle} popUp={popUp} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ import { UserGroupsRow } from "./UserGroupsRow";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
orgMembership: OrgUser;
|
orgMembership: OrgUser;
|
||||||
handlePopUpOpen: (
|
handlePopUpOpen: (popUpName: keyof UsePopUpState<["removeUserFromGroup"]>, data?: {}) => void;
|
||||||
popUpName: keyof UsePopUpState<["removeUserFromGroup", "userGroupsProjects"]>,
|
|
||||||
data?: {}
|
|
||||||
) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserGroupsTable = ({ handlePopUpOpen, orgMembership }: Props) => {
|
export const UserGroupsTable = ({ handlePopUpOpen, orgMembership }: Props) => {
|
||||||
@@ -24,14 +21,12 @@ export const UserGroupsTable = ({ handlePopUpOpen, orgMembership }: Props) => {
|
|||||||
<THead>
|
<THead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>Name</Th>
|
<Th>Name</Th>
|
||||||
<Th>Projects</Th>
|
|
||||||
<Th className="w-5" />
|
<Th className="w-5" />
|
||||||
</Tr>
|
</Tr>
|
||||||
</THead>
|
</THead>
|
||||||
<TBody>
|
<TBody>
|
||||||
{groups?.map((group) => (
|
{groups?.map((group) => (
|
||||||
<UserGroupsRow
|
<UserGroupsRow
|
||||||
orgMembership={orgMembership}
|
|
||||||
key={`user-group-${group.id}`}
|
key={`user-group-${group.id}`}
|
||||||
group={group}
|
group={group}
|
||||||
handlePopUpOpen={handlePopUpOpen}
|
handlePopUpOpen={handlePopUpOpen}
|
||||||
|
|||||||
Reference in New Issue
Block a user