Merge pull request #4934 from Infisical/ENG-4198

improvements: styling and labeling additions to improve scope context
This commit is contained in:
Scott Wilson
2025-11-25 16:11:39 -08:00
committed by GitHub
44 changed files with 226 additions and 124 deletions

View File

@@ -289,7 +289,7 @@
}
},
"project": {
"title": "Settings",
"title": "Project Settings",
"description": "These settings only apply to the currently selected Project.",
"danger-zone": "Danger Zone",
"delete-project": "Delete Project",

View File

@@ -3,14 +3,7 @@ import { ReactNode } from "@tanstack/react-router";
import { LucideIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import {
Badge,
InstanceIcon,
OrgIcon,
ProjectIcon,
SubOrgIcon,
TBadgeProps
} from "@app/components/v3";
import { InstanceIcon, OrgIcon, ProjectIcon, SubOrgIcon } from "@app/components/v3";
import { ProjectType } from "@app/hooks/api/projects/types";
type Props = {
@@ -21,41 +14,40 @@ type Props = {
scope: "org" | "namespace" | "instance" | ProjectType | null;
};
const SCOPE_NAME: Record<NonNullable<Props["scope"]>, { label: string; icon: LucideIcon }> = {
org: { label: "Organization", icon: OrgIcon },
[ProjectType.SecretManager]: { label: "Project", icon: ProjectIcon },
[ProjectType.CertificateManager]: { label: "Project", icon: ProjectIcon },
[ProjectType.SSH]: { label: "Project", icon: ProjectIcon },
[ProjectType.KMS]: { label: "Project", icon: ProjectIcon },
[ProjectType.PAM]: { label: "Project", icon: ProjectIcon },
[ProjectType.SecretScanning]: { label: "Project", icon: ProjectIcon },
namespace: { label: "Sub-Organization", icon: SubOrgIcon },
instance: { label: "Server", icon: InstanceIcon }
};
const SCOPE_VARIANT: Record<NonNullable<Props["scope"]>, TBadgeProps["variant"]> = {
org: "org",
[ProjectType.SecretManager]: "project",
[ProjectType.CertificateManager]: "project",
[ProjectType.SSH]: "project",
[ProjectType.KMS]: "project",
[ProjectType.PAM]: "project",
[ProjectType.SecretScanning]: "project",
namespace: "sub-org",
instance: "neutral"
const SCOPE_BADGE: Record<NonNullable<Props["scope"]>, { icon: LucideIcon; className: string }> = {
org: { className: "text-org", icon: OrgIcon },
[ProjectType.SecretManager]: { className: "text-project", icon: ProjectIcon },
[ProjectType.CertificateManager]: { className: "text-project", icon: ProjectIcon },
[ProjectType.SSH]: { className: "text-project", icon: ProjectIcon },
[ProjectType.KMS]: { className: "text-project", icon: ProjectIcon },
[ProjectType.PAM]: { className: "text-project", icon: ProjectIcon },
[ProjectType.SecretScanning]: { className: "text-project", icon: ProjectIcon },
namespace: { className: "text-sub-org", icon: SubOrgIcon },
instance: { className: "text-neutral", icon: InstanceIcon }
};
export const PageHeader = ({ title, description, children, className, scope }: Props) => (
<div className={twMerge("mb-10 w-full", className)}>
<div className="flex w-full justify-between">
<div className="mr-4 flex w-full items-center">
<h1 className="text-3xl font-medium text-white capitalize">{title}</h1>
{scope && (
<Badge variant={SCOPE_VARIANT[scope]} className="mt-1 ml-2.5">
{createElement(SCOPE_NAME[scope].icon)}
{SCOPE_NAME[scope].label}
</Badge>
)}
<h1
className={twMerge(
"text-3xl font-medium text-white capitalize underline decoration-2 underline-offset-4",
scope === "org" && "decoration-org/90",
scope === "instance" && "decoration-neutral/90",
scope === "namespace" && "decoration-sub-org/90",
Object.values(ProjectType).includes((scope as ProjectType) ?? "") &&
"decoration-project/90",
!scope && "no-underline"
)}
>
{scope &&
createElement(SCOPE_BADGE[scope].icon, {
size: 26,
className: twMerge(SCOPE_BADGE[scope].className, "mr-3 mb-1 inline-block")
})}
{title}
</h1>
</div>
<div className="flex items-center gap-2">{children}</div>
</div>

View File

@@ -601,7 +601,7 @@ export const Navbar = () => {
}}
>
<UserPlusIcon className="inline-block size-3.5" />
<span className="ml-2 hidden md:inline-block">Invite Members</span>
<span className="ml-2 hidden md:inline-block">Invite Users</span>
</Link>
) : null
}
@@ -705,7 +705,7 @@ export const Navbar = () => {
}}
>
<DropdownMenuItem icon={<FontAwesomeIcon icon={faUserPlus} />}>
Invite Members
Invite Users
</DropdownMenuItem>
</Link>
) : null

View File

@@ -17,7 +17,7 @@ export const AccessManagementPage = () => {
<div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader
scope="instance"
title="Access Control"
title="Server Admin Access Control"
description="Manage server admins within your Infisical instance."
/>
<ServerAdminsTable />

View File

@@ -350,8 +350,8 @@ const ViewMembersModalContent = ({
className="my-auto bg-mineshaft-700"
title={
members.length
? "No organization members match search..."
: "No organization members found"
? "No organization users match search..."
: "No organization users found"
}
icon={faUsers}
/>

View File

@@ -49,7 +49,7 @@ export const IntegrationsListPage = () => {
<div className="mb-8">
<PageHeader
scope={ProjectType.CertificateManager}
title="Integrations"
title="Project Integrations"
description="Manage integrations with third-party certificate services."
/>
<Tabs orientation="vertical" value={currentTab} onValueChange={updateSelectedTab}>

View File

@@ -1,7 +1,10 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -15,6 +18,7 @@ const tabs = [
export const SettingsPage = () => {
const { t } = useTranslation();
const { currentOrg } = useOrganization();
return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
@@ -22,7 +26,17 @@ export const SettingsPage = () => {
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
</Helmet>
<div className="w-full max-w-8xl">
<PageHeader scope={ProjectType.CertificateManager} title={t("settings.project.title")} />
<PageHeader scope={ProjectType.CertificateManager} title={t("settings.project.title")}>
<Link
to="/organizations/$orgId/settings"
params={{
orgId: currentOrg.id
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization settings?
</Link>
</PageHeader>
<Tabs orientation="vertical" defaultValue={tabs[0].key}>
<TabList>
{tabs.map((tab) => (

View File

@@ -20,7 +20,7 @@ export const OverviewPage = () => {
<div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader
scope={ProjectType.KMS}
title="Overview"
title="Project Overview"
description="Manage keys and perform cryptographic operations."
/>
<ProjectPermissionCan

View File

@@ -1,7 +1,10 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -16,6 +19,8 @@ const tabs = [
export const SettingsPage = () => {
const { t } = useTranslation();
const { currentOrg } = useOrganization();
return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<Helmet>
@@ -24,9 +29,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={ProjectType.KMS}
title="Settings"
title="Project Settings"
description="Configure general project settings"
/>
>
<Link
to="/organizations/$orgId/settings"
params={{
orgId: currentOrg.id
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization settings?
</Link>
</PageHeader>
<Tabs orientation="vertical" defaultValue={tabs[0].key}>
<TabList>
{tabs.map((tab) => (

View File

@@ -83,7 +83,7 @@ export const AccessManagementPage = () => {
<div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
title="Access Control"
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} Access Control`}
description="Manage fine-grained access for users, groups, roles, and machine identities within your organization resources."
/>
{!currentOrg.shouldUseNewPrivilegeSystem && (

View File

@@ -51,19 +51,19 @@ export const OrgGroupsSection = () => {
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Groups</p>
<p className="text-xl font-medium text-mineshaft-100">Organization Groups</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/groups" />
</div>
<OrgPermissionCan I={OrgPermissionGroupActions.Create} a={OrgPermissionSubjects.Groups}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handleAddGroupModal()}
isDisabled={!isAllowed}
>
Create Group
Create Organization Group
</Button>
)}
</OrgPermissionCan>

View File

@@ -159,7 +159,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => {
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search groups..."
placeholder="Search organization groups..."
/>
<TableContainer className="mt-4">
<Table>
@@ -205,7 +205,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => {
</Th>
<Th>
<div className="flex items-center">
Role
Organization Role
<IconButton
variant="plain"
className={`ml-2 ${orderBy === GroupsOrderBy.Role ? "" : "opacity-30"}`}

View File

@@ -99,7 +99,9 @@ export const IdentitySection = withPermission(
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex flex-1 items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Machine Identities</p>
<p className="text-xl font-medium text-mineshaft-100">
Organization Machine Identities
</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
</div>
<div className="flex items-center">
@@ -129,7 +131,9 @@ export const IdentitySection = withPermission(
}}
isDisabled={!isAllowed}
>
Add Machine Identity
{isSubOrganization
? "Add Machine Identity to Sub-Organization"
: "Create Organization Machine Identity"}
</Button>
)}
</OrgPermissionCan>

View File

@@ -200,7 +200,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
</DropdownSubMenuTrigger>
<DropdownSubMenuContent className="max-h-80 thin-scrollbar overflow-y-auto rounded-l-none">
<DropdownMenuLabel className="sticky top-0 bg-mineshaft-900">
Filter Machine Identities by Role
Filter Organization Machine Identities by Role
</DropdownMenuLabel>
{roles?.map(({ id, slug, name }) => (
<DropdownMenuItem
@@ -258,7 +258,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
</Th>
<Th>
<div className="flex items-center">
Role
Organization Role
<IconButton
variant="plain"
className={`ml-2 ${orderBy === OrgIdentityOrderBy.Role ? "" : "opacity-30"}`}

View File

@@ -205,13 +205,13 @@ export const OrgMembersSection = () => {
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Users</p>
<p className="text-xl font-medium text-mineshaft-100">Organization Users</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/user-identities" />
</div>
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<UserPlusIcon size={16} />}
onClick={() =>
@@ -219,7 +219,9 @@ export const OrgMembersSection = () => {
}
isDisabled={!isAllowed}
>
{isSubOrganization ? "Add Members" : "Invite Members"}
{isSubOrganization
? "Add Users to Sub-Organization"
: "Invite Users to Organization"}
</Button>
)}
</OrgPermissionCan>

View File

@@ -336,7 +336,7 @@ export const OrgMembersTable = ({
</DropdownSubMenuTrigger>
<DropdownSubMenuContent className="max-h-80 thin-scrollbar overflow-y-auto rounded-l-none">
<DropdownMenuLabel className="sticky top-0 bg-mineshaft-900">
Apply Roles to Filter Users
Filter Organization Users by Role
</DropdownMenuLabel>
{roles?.map(({ id, slug, name }) => (
<DropdownMenuItem
@@ -365,7 +365,7 @@ export const OrgMembersTable = ({
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search members..."
placeholder="Search organization users..."
/>
</div>
<TableContainer className="mt-4">
@@ -434,7 +434,7 @@ export const OrgMembersTable = ({
</Th>
<Th className="w-1/3">
<div className="flex items-center">
Role
Organization Role
<IconButton
variant="plain"
className={`ml-2 ${orderBy === OrgMembersOrderBy.Role ? "" : "opacity-30"}`}
@@ -727,8 +727,8 @@ export const OrgMembersTable = ({
<EmptyState
title={
members.length
? "No organization members match search..."
: "No organization members found"
? "No organization users match search..."
: "No organization users found"
}
icon={members.length ? faSearch : faUsers}
/>

View File

@@ -199,7 +199,7 @@ export const OrgRoleTable = () => {
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Role}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
@@ -207,7 +207,7 @@ export const OrgRoleTable = () => {
}}
isDisabled={!isAllowed}
>
Add Role
Add Organization Role
</Button>
)}
</OrgPermissionCan>
@@ -216,7 +216,7 @@ export const OrgRoleTable = () => {
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search roles..."
placeholder="Search organization roles..."
className="flex-1"
containerClassName="mb-4"
/>
@@ -441,7 +441,7 @@ export const OrgRoleTable = () => {
<EmptyState
title={
roles?.length
? "No roles match search..."
? "No organization roles match search..."
: "This organization does not have any roles"
}
icon={roles?.length ? faSearch : undefined}

View File

@@ -27,7 +27,7 @@ export const AppConnectionsPage = withPermission(
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
className="w-full"
title="App Connections"
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} App Connections`}
description="Manage organization App Connections"
/>
<div className="mb-4 flex w-full flex-col rounded-md border border-blue-500/50 bg-blue-500/30 px-4 py-2 text-sm text-blue-200">

View File

@@ -19,7 +19,7 @@ export const AuditLogsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
title="Audit Logs"
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} Audit Logs`}
description="Audit logs for security and compliance teams to monitor information access."
/>
<LogsSection pageView />

View File

@@ -88,7 +88,7 @@ const Page = () => {
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Groups
Organization Groups
</Link>
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}

View File

@@ -82,7 +82,7 @@ const Page = () => {
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Machine Identities
Organization Machine Identities
</Link>
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}

View File

@@ -81,7 +81,7 @@ export const ProjectsPage = () => {
</Helmet>
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
title="Overview"
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} Overview`}
description="Your team's complete security toolkit - organized and ready when you need them."
/>
{projectListView === ProjectListView.MyProjects ? (

View File

@@ -20,7 +20,7 @@ export const SettingsPage = () => {
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
description="Configure organization-wide settings"
title={t("settings.org.title")}
title={isSubOrganization ? "Sub-Organization Settings" : "Organization Settings"}
/>
<OrgTabGroup />
</div>

View File

@@ -112,7 +112,7 @@ const Page = withPermission(
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Users
Organization Users
</Link>
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}

View File

@@ -1,13 +1,18 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
export const SettingsPage = () => {
const { t } = useTranslation();
const { currentOrg } = useOrganization();
return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<Helmet>
@@ -16,9 +21,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={ProjectType.PAM}
title="Settings"
title="Project Settings"
description="Configure your PAM project."
/>
>
<Link
to="/organizations/$orgId/settings"
params={{
orgId: currentOrg.id
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization settings?
</Link>
</PageHeader>
<Tabs orientation="vertical" defaultValue="tab-project-general">
<TabList>
<Tab variant="project" value="tab-project-general">

View File

@@ -1,6 +1,7 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { useNavigate, useSearch } from "@tanstack/react-router";
import { Link, useNavigate, useSearch } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization, useProject } from "@app/context";
@@ -43,9 +44,19 @@ const Page = () => {
<div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader
scope={currentProject.type}
title="Access Control"
title="Project Access Control"
description="Manage fine-grained access for users, groups, roles, and machine identities within your project resources."
/>
>
<Link
to="/organizations/$orgId/access-management"
params={{
orgId: currentOrg.id
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization access control?
</Link>
</PageHeader>
<Tabs orientation="vertical" value={selectedTab} onValueChange={updateSelectedTab}>
<TabList>
<Tab variant="project" value={ProjectAccessControlTabs.Member}>

View File

@@ -59,19 +59,19 @@ export const GroupsSection = () => {
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">User Groups</p>
<p className="text-xl font-medium text-mineshaft-100">Project Groups</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/groups#user-groups" />
</div>
<ProjectPermissionCan I={ProjectPermissionActions.Create} a={ProjectPermissionSub.Groups}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handleAddGroupModal()}
isDisabled={!isAllowed}
>
Add Group
Add Group to Project
</Button>
)}
</ProjectPermissionCan>

View File

@@ -122,7 +122,7 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => {
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search members..."
placeholder="Search project groups..."
/>
<TableContainer className="mt-4">
<Table>
@@ -143,7 +143,7 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => {
</IconButton>
</div>
</Th>
<Th>Role</Th>
<Th>Project Role</Th>
<Th>Added on</Th>
<Th className="w-5" />
</Tr>

View File

@@ -197,7 +197,7 @@ export const IdentityTab = withProjectPermission(
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Machine Identities</p>
<p className="text-xl font-medium text-mineshaft-100">Project Machine Identities</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
</div>
<div className="flex items-center">
@@ -212,7 +212,7 @@ export const IdentityTab = withProjectPermission(
onClick={() => handlePopUpOpen("createIdentity")}
isDisabled={!isAllowed}
>
Add Machine Identity
Add Machine Identity to Project
</Button>
)}
</ProjectPermissionCan>
@@ -223,7 +223,7 @@ export const IdentityTab = withProjectPermission(
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search machine identities by name..."
placeholder="Search project machine identities by name..."
/>
<TableContainer>
<Table>
@@ -251,7 +251,7 @@ export const IdentityTab = withProjectPermission(
</IconButton>
</div>
</Th>
<Th className="w-1/3">Role</Th>
<Th className="w-1/3">Project Role</Th>
<Th>Managed by</Th>
<Th className="w-5">{isFetching ? <Spinner size="xs" /> : null}</Th>
</Tr>

View File

@@ -49,19 +49,19 @@ export const MembersSection = () => {
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Users</p>
<p className="text-xl font-medium text-mineshaft-100">Project Users</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/user-identities" />
</div>
<ProjectPermissionCan I={ProjectPermissionActions.Create} a={ProjectPermissionSub.Member}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handlePopUpOpen("addMember")}
isDisabled={!isAllowed}
>
Add Member
Add Users to Project
</Button>
)}
</ProjectPermissionCan>

View File

@@ -208,7 +208,7 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => {
</DropdownSubMenuTrigger>
<DropdownSubMenuContent className="max-h-80 thin-scrollbar overflow-y-auto rounded-l-none">
<DropdownMenuLabel className="sticky top-0 bg-mineshaft-900">
Apply Roles to Filter Users
Filter Project Users by Role
</DropdownMenuLabel>
{projectRoles?.map(({ id, slug, name }) => (
<DropdownMenuItem
@@ -237,7 +237,7 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => {
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search members..."
placeholder="Search project users..."
/>
</div>
<TableContainer className="mt-4">
@@ -282,7 +282,7 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => {
</IconButton>
</div>
</Th>
<Th>Role</Th>
<Th>Project Role</Th>
<Th className="w-5" />
</Tr>
</THead>
@@ -462,9 +462,7 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => {
)}
{!isMembersLoading && !filteredUsers?.length && (
<EmptyState
title={
members.length ? "No project members match search..." : "No project members found"
}
title={members.length ? "No project users match search..." : "No project users found"}
icon={members.length ? faSearch : faUsers}
/>
)}

View File

@@ -170,13 +170,13 @@ export const ProjectRoleList = () => {
<ProjectPermissionCan I={ProjectPermissionActions.Create} a={ProjectPermissionSub.Role}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handlePopUpOpen("role")}
isDisabled={!isAllowed}
>
Add Role
Add Project Role
</Button>
)}
</ProjectPermissionCan>

View File

@@ -57,7 +57,7 @@ export const ServiceTokenSection = withProjectPermission(
>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
handlePopUpOpen("createAPIToken");

View File

@@ -25,7 +25,7 @@ export const AppConnectionsPage = withProjectPermission(
<PageHeader
scope={currentProject.type}
className="w-full"
title="App Connections"
title="Project App Connections"
description="Manage project App Connections"
/>

View File

@@ -1,4 +1,6 @@
import { Helmet } from "react-helmet";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader } from "@app/components/v2";
import { useProject } from "@app/context";
@@ -17,9 +19,19 @@ export const AuditLogsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={currentProject.type}
title="Audit logs"
title="Project Audit logs"
description="Audit logs for security and compliance teams to monitor information access."
/>
>
<Link
to="/organizations/$orgId/audit-logs"
params={{
orgId: currentProject.orgId
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization audit logs?
</Link>
</PageHeader>
<LogsSection pageView project={currentProject} />
</div>
</div>

View File

@@ -57,7 +57,7 @@ const Page = () => {
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Groups
Project Groups
</Link>
<PageHeader
scope={currentProject.type}

View File

@@ -149,7 +149,7 @@ const Page = () => {
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Machine Identities
Project Machine Identities
</Link>
<PageHeader
scope={currentProject.type}

View File

@@ -128,7 +128,7 @@ export const Page = () => {
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Users
Project Users
</Link>
<PageHeader
scope={currentProject.type}

View File

@@ -104,7 +104,7 @@ const Page = () => {
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Roles
Project Roles
</Link>
<PageHeader
scope={currentProject.type}

View File

@@ -57,7 +57,7 @@ export const IntegrationsListPage = () => {
<div className="mb-8">
<PageHeader
scope={ProjectType.SecretManager}
title="Integrations"
title="Project Integrations"
description="Manage integrations with third-party services."
/>
<Tabs orientation="vertical" value={selectedTab} onValueChange={updateSelectedTab}>

View File

@@ -933,12 +933,12 @@ export const OverviewPage = () => {
<div className="flex w-full items-baseline justify-between">
<PageHeader
scope={ProjectType.SecretManager}
title="Overview"
title="Project Overview"
description={
<p className="text-md text-bunker-300">
Inject your secrets using
<a
className="ml-1 text-mineshaft-300 underline decoration-primary-800 underline-offset-4 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
className="ml-1 text-mineshaft-200 underline decoration-mineshaft-400/65 underline-offset-3 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
href="https://infisical.com/docs/cli/overview"
target="_blank"
rel="noopener noreferrer"
@@ -947,7 +947,7 @@ export const OverviewPage = () => {
</a>
,
<a
className="ml-1 text-mineshaft-300 underline decoration-primary-800 underline-offset-4 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
className="ml-1 text-mineshaft-200 underline decoration-mineshaft-400/65 underline-offset-3 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
href="https://infisical.com/docs/documentation/getting-started/api"
target="_blank"
rel="noopener noreferrer"
@@ -956,7 +956,7 @@ export const OverviewPage = () => {
</a>
,
<a
className="ml-1 text-mineshaft-300 underline decoration-primary-800 underline-offset-4 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
className="ml-1 text-mineshaft-200 underline decoration-mineshaft-400/65 underline-offset-3 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
href="https://infisical.com/docs/sdks/overview"
target="_blank"
rel="noopener noreferrer"
@@ -965,7 +965,7 @@ export const OverviewPage = () => {
</a>
, and
<a
className="ml-1 text-mineshaft-300 underline decoration-primary-800 underline-offset-4 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
className="ml-1 text-mineshaft-200 underline decoration-mineshaft-400/65 underline-offset-3 duration-200 hover:text-mineshaft-100 hover:decoration-primary-600"
href="https://infisical.com/docs/documentation/getting-started/introduction"
target="_blank"
rel="noopener noreferrer"

View File

@@ -1,5 +1,7 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useProject } from "@app/context";
@@ -43,9 +45,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={ProjectType.SecretManager}
title="Settings"
title="Project Settings"
description="Configure your secret manager's encryption, environments, webhooks and other configurations."
/>
>
<Link
to="/organizations/$orgId/settings"
params={{
orgId: currentProject.orgId
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization settings?
</Link>
</PageHeader>
<Tabs orientation="vertical" defaultValue={tabs[0].key}>
<TabList>
{tabs

View File

@@ -1,9 +1,11 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { ProjectPermissionCan } from "@app/components/permissions";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ProjectPermissionSub } from "@app/context";
import { ProjectPermissionSub, useOrganization } from "@app/context";
import { ProjectPermissionSecretScanningConfigActions } from "@app/context/ProjectPermissionContext/types";
import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -12,6 +14,7 @@ import { ProjectScanningConfigTab } from "./components/ProjectScanningConfigTab"
export const SettingsPage = () => {
const { t } = useTranslation();
const { currentOrg } = useOrganization();
return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
@@ -21,9 +24,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={ProjectType.SecretScanning}
title="Settings"
title="Project Settings"
description="Configure your Secret Scanning product's configurations."
/>
>
<Link
to="/organizations/$orgId/settings"
params={{
orgId: currentOrg.id
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization settings?
</Link>
</PageHeader>
<Tabs orientation="vertical" defaultValue="tab-project-general">
<TabList>
<Tab variant="project" value="tab-project-general">

View File

@@ -1,9 +1,11 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { ProjectPermissionCan } from "@app/components/permissions";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
import { ProjectPermissionActions, ProjectPermissionSub, useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -12,6 +14,8 @@ import { ProjectSshTab } from "./components/ProjectSshTab";
export const SettingsPage = () => {
const { t } = useTranslation();
const { currentOrg } = useOrganization();
return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<Helmet>
@@ -20,9 +24,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={ProjectType.SSH}
title="Settings"
title="Project Settings"
description="Configure your SSH product's configurations."
/>
>
<Link
to="/organizations/$orgId/settings"
params={{
orgId: currentOrg.id
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization settings?
</Link>
</PageHeader>
<Tabs orientation="vertical" defaultValue="tab-project-general">
<TabList>
<Tab variant="project" value="tab-project-general">