Requested changes

This commit is contained in:
Daniel Hougaard
2024-09-10 23:29:23 +04:00
parent 372b6cbaea
commit 4dda270e8e
5 changed files with 43 additions and 146 deletions

View File

@@ -1,9 +1,10 @@
import { useState } from "react";
import Link from "next/link";
import { faFilter } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconButton, Tooltip } from "@app/components/v2";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
import { EmptyState, IconButton, Tooltip } from "@app/components/v2";
import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context";
import { withPermission } from "@app/hoc";
import { OrgUser } from "@app/hooks/api/types";
import { LogsSection } from "@app/views/Project/AuditLogsPage/components";
@@ -15,8 +16,10 @@ type Props = {
export const UserAuditLogsSection = withPermission(
({ orgMembership }: Props) => {
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="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>
@@ -43,7 +46,39 @@ export const UserAuditLogsSection = withPermission(
isOrgAuditLogs
/>
</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 }
);

View File

@@ -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>
);
};

View File

@@ -4,39 +4,21 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
import { TGroupWithProjectMemberships } from "@app/hooks/api/groups/types";
import { OrgUser } from "@app/hooks/api/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { UserGroupsProjectsModalData } from "./UserGroupProjectsModal";
type Props = {
group: TGroupWithProjectMemberships;
orgMembership: OrgUser;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["removeUserFromGroup", "userGroupsProjects"]>,
data?: {}
) => void;
handlePopUpOpen: (popUpName: keyof UsePopUpState<["removeUserFromGroup"]>, data?: {}) => void;
};
export const UserGroupsRow = ({ group, orgMembership, handlePopUpOpen }: Props) => {
export const UserGroupsRow = ({ group, handlePopUpOpen }: Props) => {
return (
<>
<Tr
className="group h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
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.projectMemberships.length} Project
{group.projectMemberships.length > 1 || group.projectMemberships.length === 0 ? "s" : ""}
</Td>
<Td>
{true && (
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">

View File

@@ -6,7 +6,6 @@ import { useRemoveUserFromGroup } from "@app/hooks/api";
import { OrgUser } from "@app/hooks/api/users/types";
import { usePopUp } from "@app/hooks/usePopUp";
import { UserGroupsProjectsModal } from "./UserGroupProjectsModal";
import { UserGroupsTable } from "./UserGroupsTable";
type Props = {
@@ -15,8 +14,7 @@ type Props = {
export const UserGroupsSection = ({ orgMembership }: Props) => {
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
"removeUserFromGroup",
"userGroupsProjects"
"removeUserFromGroup"
] as const);
const { mutateAsync: removeUserFromGroup } = useRemoveUserFromGroup();
@@ -65,8 +63,6 @@ export const UserGroupsSection = ({ orgMembership }: Props) => {
return handleRemoveUserFromGroup(popupData.groupSlug);
}}
/>
<UserGroupsProjectsModal handlePopUpToggle={handlePopUpToggle} popUp={popUp} />
</>
);
};

View File

@@ -9,10 +9,7 @@ import { UserGroupsRow } from "./UserGroupsRow";
type Props = {
orgMembership: OrgUser;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["removeUserFromGroup", "userGroupsProjects"]>,
data?: {}
) => void;
handlePopUpOpen: (popUpName: keyof UsePopUpState<["removeUserFromGroup"]>, data?: {}) => void;
};
export const UserGroupsTable = ({ handlePopUpOpen, orgMembership }: Props) => {
@@ -24,14 +21,12 @@ export const UserGroupsTable = ({ handlePopUpOpen, orgMembership }: Props) => {
<THead>
<Tr>
<Th>Name</Th>
<Th>Projects</Th>
<Th className="w-5" />
</Tr>
</THead>
<TBody>
{groups?.map((group) => (
<UserGroupsRow
orgMembership={orgMembership}
key={`user-group-${group.id}`}
group={group}
handlePopUpOpen={handlePopUpOpen}