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": { "project": {
"title": "Settings", "title": "Project Settings",
"description": "These settings only apply to the currently selected Project.", "description": "These settings only apply to the currently selected Project.",
"danger-zone": "Danger Zone", "danger-zone": "Danger Zone",
"delete-project": "Delete Project", "delete-project": "Delete Project",

View File

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

View File

@@ -601,7 +601,7 @@ export const Navbar = () => {
}} }}
> >
<UserPlusIcon className="inline-block size-3.5" /> <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> </Link>
) : null ) : null
} }
@@ -705,7 +705,7 @@ export const Navbar = () => {
}} }}
> >
<DropdownMenuItem icon={<FontAwesomeIcon icon={faUserPlus} />}> <DropdownMenuItem icon={<FontAwesomeIcon icon={faUserPlus} />}>
Invite Members Invite Users
</DropdownMenuItem> </DropdownMenuItem>
</Link> </Link>
) : null ) : null

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,10 @@
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; 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 { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types"; import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab"; import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -15,6 +18,7 @@ const tabs = [
export const SettingsPage = () => { export const SettingsPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentOrg } = useOrganization();
return ( return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white"> <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> <title>{t("common.head-title", { title: t("settings.project.title") })}</title>
</Helmet> </Helmet>
<div className="w-full max-w-8xl"> <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}> <Tabs orientation="vertical" defaultValue={tabs[0].key}>
<TabList> <TabList>
{tabs.map((tab) => ( {tabs.map((tab) => (

View File

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

View File

@@ -1,7 +1,10 @@
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; 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 { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types"; import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab"; import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -16,6 +19,8 @@ const tabs = [
export const SettingsPage = () => { export const SettingsPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentOrg } = useOrganization();
return ( return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white"> <div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<Helmet> <Helmet>
@@ -24,9 +29,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl"> <div className="w-full max-w-8xl">
<PageHeader <PageHeader
scope={ProjectType.KMS} scope={ProjectType.KMS}
title="Settings" title="Project Settings"
description="Configure general 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}> <Tabs orientation="vertical" defaultValue={tabs[0].key}>
<TabList> <TabList>
{tabs.map((tab) => ( {tabs.map((tab) => (

View File

@@ -83,7 +83,7 @@ export const AccessManagementPage = () => {
<div className="mx-auto mb-6 w-full max-w-8xl"> <div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader <PageHeader
scope={isSubOrganization ? "namespace" : "org"} 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." description="Manage fine-grained access for users, groups, roles, and machine identities within your organization resources."
/> />
{!currentOrg.shouldUseNewPrivilegeSystem && ( {!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-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="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex items-center gap-x-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" /> <DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/groups" />
</div> </div>
<OrgPermissionCan I={OrgPermissionGroupActions.Create} a={OrgPermissionSubjects.Groups}> <OrgPermissionCan I={OrgPermissionGroupActions.Create} a={OrgPermissionSubjects.Groups}>
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
colorSchema="secondary" variant="outline_bg"
type="submit" type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />} leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handleAddGroupModal()} onClick={() => handleAddGroupModal()}
isDisabled={!isAllowed} isDisabled={!isAllowed}
> >
Create Group Create Organization Group
</Button> </Button>
)} )}
</OrgPermissionCan> </OrgPermissionCan>

View File

@@ -159,7 +159,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => {
value={search} value={search}
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />} leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search groups..." placeholder="Search organization groups..."
/> />
<TableContainer className="mt-4"> <TableContainer className="mt-4">
<Table> <Table>
@@ -205,7 +205,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => {
</Th> </Th>
<Th> <Th>
<div className="flex items-center"> <div className="flex items-center">
Role Organization Role
<IconButton <IconButton
variant="plain" variant="plain"
className={`ml-2 ${orderBy === GroupsOrderBy.Role ? "" : "opacity-30"}`} 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="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="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex flex-1 items-center gap-x-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" /> <DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
@@ -129,7 +131,9 @@ export const IdentitySection = withPermission(
}} }}
isDisabled={!isAllowed} isDisabled={!isAllowed}
> >
Add Machine Identity {isSubOrganization
? "Add Machine Identity to Sub-Organization"
: "Create Organization Machine Identity"}
</Button> </Button>
)} )}
</OrgPermissionCan> </OrgPermissionCan>

View File

@@ -200,7 +200,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
</DropdownSubMenuTrigger> </DropdownSubMenuTrigger>
<DropdownSubMenuContent className="max-h-80 thin-scrollbar overflow-y-auto rounded-l-none"> <DropdownSubMenuContent className="max-h-80 thin-scrollbar overflow-y-auto rounded-l-none">
<DropdownMenuLabel className="sticky top-0 bg-mineshaft-900"> <DropdownMenuLabel className="sticky top-0 bg-mineshaft-900">
Filter Machine Identities by Role Filter Organization Machine Identities by Role
</DropdownMenuLabel> </DropdownMenuLabel>
{roles?.map(({ id, slug, name }) => ( {roles?.map(({ id, slug, name }) => (
<DropdownMenuItem <DropdownMenuItem
@@ -258,7 +258,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
</Th> </Th>
<Th> <Th>
<div className="flex items-center"> <div className="flex items-center">
Role Organization Role
<IconButton <IconButton
variant="plain" variant="plain"
className={`ml-2 ${orderBy === OrgIdentityOrderBy.Role ? "" : "opacity-30"}`} 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-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="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex items-center gap-x-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" /> <DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/user-identities" />
</div> </div>
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}> <OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
colorSchema="secondary" variant="outline_bg"
type="submit" type="submit"
leftIcon={<UserPlusIcon size={16} />} leftIcon={<UserPlusIcon size={16} />}
onClick={() => onClick={() =>
@@ -219,7 +219,9 @@ export const OrgMembersSection = () => {
} }
isDisabled={!isAllowed} isDisabled={!isAllowed}
> >
{isSubOrganization ? "Add Members" : "Invite Members"} {isSubOrganization
? "Add Users to Sub-Organization"
: "Invite Users to Organization"}
</Button> </Button>
)} )}
</OrgPermissionCan> </OrgPermissionCan>

View File

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

View File

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

View File

@@ -27,7 +27,7 @@ export const AppConnectionsPage = withPermission(
<PageHeader <PageHeader
scope={isSubOrganization ? "namespace" : "org"} scope={isSubOrganization ? "namespace" : "org"}
className="w-full" className="w-full"
title="App Connections" title={`${isSubOrganization ? "Sub-Organization" : "Organization"} App Connections`}
description="Manage 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"> <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"> <div className="w-full max-w-8xl">
<PageHeader <PageHeader
scope={isSubOrganization ? "namespace" : "org"} 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." description="Audit logs for security and compliance teams to monitor information access."
/> />
<LogsSection pageView /> <LogsSection pageView />

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,18 @@
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; 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 { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types"; import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab"; import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
export const SettingsPage = () => { export const SettingsPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentOrg } = useOrganization();
return ( return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white"> <div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<Helmet> <Helmet>
@@ -16,9 +21,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl"> <div className="w-full max-w-8xl">
<PageHeader <PageHeader
scope={ProjectType.PAM} scope={ProjectType.PAM}
title="Settings" title="Project Settings"
description="Configure your PAM project." 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"> <Tabs orientation="vertical" defaultValue="tab-project-general">
<TabList> <TabList>
<Tab variant="project" value="tab-project-general"> <Tab variant="project" value="tab-project-general">

View File

@@ -1,6 +1,7 @@
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; 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 { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization, useProject } from "@app/context"; import { useOrganization, useProject } from "@app/context";
@@ -43,9 +44,19 @@ const Page = () => {
<div className="mx-auto mb-6 w-full max-w-8xl"> <div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader <PageHeader
scope={currentProject.type} 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." 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}> <Tabs orientation="vertical" value={selectedTab} onValueChange={updateSelectedTab}>
<TabList> <TabList>
<Tab variant="project" value={ProjectAccessControlTabs.Member}> <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-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-x-2"> <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" /> <DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/groups#user-groups" />
</div> </div>
<ProjectPermissionCan I={ProjectPermissionActions.Create} a={ProjectPermissionSub.Groups}> <ProjectPermissionCan I={ProjectPermissionActions.Create} a={ProjectPermissionSub.Groups}>
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
colorSchema="secondary" variant="outline_bg"
type="submit" type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />} leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handleAddGroupModal()} onClick={() => handleAddGroupModal()}
isDisabled={!isAllowed} isDisabled={!isAllowed}
> >
Add Group Add Group to Project
</Button> </Button>
)} )}
</ProjectPermissionCan> </ProjectPermissionCan>

View File

@@ -122,7 +122,7 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => {
value={search} value={search}
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />} leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search members..." placeholder="Search project groups..."
/> />
<TableContainer className="mt-4"> <TableContainer className="mt-4">
<Table> <Table>
@@ -143,7 +143,7 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => {
</IconButton> </IconButton>
</div> </div>
</Th> </Th>
<Th>Role</Th> <Th>Project Role</Th>
<Th>Added on</Th> <Th>Added on</Th>
<Th className="w-5" /> <Th className="w-5" />
</Tr> </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-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-x-2"> <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" /> <DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
@@ -212,7 +212,7 @@ export const IdentityTab = withProjectPermission(
onClick={() => handlePopUpOpen("createIdentity")} onClick={() => handlePopUpOpen("createIdentity")}
isDisabled={!isAllowed} isDisabled={!isAllowed}
> >
Add Machine Identity Add Machine Identity to Project
</Button> </Button>
)} )}
</ProjectPermissionCan> </ProjectPermissionCan>
@@ -223,7 +223,7 @@ export const IdentityTab = withProjectPermission(
value={search} value={search}
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />} leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search machine identities by name..." placeholder="Search project machine identities by name..."
/> />
<TableContainer> <TableContainer>
<Table> <Table>
@@ -251,7 +251,7 @@ export const IdentityTab = withProjectPermission(
</IconButton> </IconButton>
</div> </div>
</Th> </Th>
<Th className="w-1/3">Role</Th> <Th className="w-1/3">Project Role</Th>
<Th>Managed by</Th> <Th>Managed by</Th>
<Th className="w-5">{isFetching ? <Spinner size="xs" /> : null}</Th> <Th className="w-5">{isFetching ? <Spinner size="xs" /> : null}</Th>
</Tr> </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-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-x-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">Project Users</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/user-identities" /> <DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/user-identities" />
</div> </div>
<ProjectPermissionCan I={ProjectPermissionActions.Create} a={ProjectPermissionSub.Member}> <ProjectPermissionCan I={ProjectPermissionActions.Create} a={ProjectPermissionSub.Member}>
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
colorSchema="secondary" variant="outline_bg"
type="submit" type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />} leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handlePopUpOpen("addMember")} onClick={() => handlePopUpOpen("addMember")}
isDisabled={!isAllowed} isDisabled={!isAllowed}
> >
Add Member Add Users to Project
</Button> </Button>
)} )}
</ProjectPermissionCan> </ProjectPermissionCan>

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,6 @@
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader } from "@app/components/v2"; import { PageHeader } from "@app/components/v2";
import { useProject } from "@app/context"; import { useProject } from "@app/context";
@@ -17,9 +19,19 @@ export const AuditLogsPage = () => {
<div className="w-full max-w-8xl"> <div className="w-full max-w-8xl">
<PageHeader <PageHeader
scope={currentProject.type} scope={currentProject.type}
title="Audit logs" title="Project Audit logs"
description="Audit logs for security and compliance teams to monitor information access." 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} /> <LogsSection pageView project={currentProject} />
</div> </div>
</div> </div>

View File

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

View File

@@ -57,7 +57,7 @@ export const IntegrationsListPage = () => {
<div className="mb-8"> <div className="mb-8">
<PageHeader <PageHeader
scope={ProjectType.SecretManager} scope={ProjectType.SecretManager}
title="Integrations" title="Project Integrations"
description="Manage integrations with third-party services." description="Manage integrations with third-party services."
/> />
<Tabs orientation="vertical" value={selectedTab} onValueChange={updateSelectedTab}> <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"> <div className="flex w-full items-baseline justify-between">
<PageHeader <PageHeader
scope={ProjectType.SecretManager} scope={ProjectType.SecretManager}
title="Overview" title="Project Overview"
description={ description={
<p className="text-md text-bunker-300"> <p className="text-md text-bunker-300">
Inject your secrets using Inject your secrets using
<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/cli/overview" href="https://infisical.com/docs/cli/overview"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -947,7 +947,7 @@ export const OverviewPage = () => {
</a> </a>
, ,
<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" href="https://infisical.com/docs/documentation/getting-started/api"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -956,7 +956,7 @@ export const OverviewPage = () => {
</a> </a>
, ,
<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" href="https://infisical.com/docs/sdks/overview"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -965,7 +965,7 @@ export const OverviewPage = () => {
</a> </a>
, and , and
<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/introduction" href="https://infisical.com/docs/documentation/getting-started/introduction"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"

View File

@@ -1,5 +1,7 @@
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; 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 { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useProject } from "@app/context"; import { useProject } from "@app/context";
@@ -43,9 +45,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl"> <div className="w-full max-w-8xl">
<PageHeader <PageHeader
scope={ProjectType.SecretManager} scope={ProjectType.SecretManager}
title="Settings" title="Project Settings"
description="Configure your secret manager's encryption, environments, webhooks and other configurations." 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}> <Tabs orientation="vertical" defaultValue={tabs[0].key}>
<TabList> <TabList>
{tabs {tabs

View File

@@ -1,9 +1,11 @@
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { ProjectPermissionCan } from "@app/components/permissions"; import { ProjectPermissionCan } from "@app/components/permissions";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; 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 { ProjectPermissionSecretScanningConfigActions } from "@app/context/ProjectPermissionContext/types";
import { ProjectType } from "@app/hooks/api/projects/types"; import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab"; import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -12,6 +14,7 @@ import { ProjectScanningConfigTab } from "./components/ProjectScanningConfigTab"
export const SettingsPage = () => { export const SettingsPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentOrg } = useOrganization();
return ( return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white"> <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"> <div className="w-full max-w-8xl">
<PageHeader <PageHeader
scope={ProjectType.SecretScanning} scope={ProjectType.SecretScanning}
title="Settings" title="Project Settings"
description="Configure your Secret Scanning product's configurations." 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"> <Tabs orientation="vertical" defaultValue="tab-project-general">
<TabList> <TabList>
<Tab variant="project" value="tab-project-general"> <Tab variant="project" value="tab-project-general">

View File

@@ -1,9 +1,11 @@
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { ProjectPermissionCan } from "@app/components/permissions"; import { ProjectPermissionCan } from "@app/components/permissions";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; 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 { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab"; import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -12,6 +14,8 @@ import { ProjectSshTab } from "./components/ProjectSshTab";
export const SettingsPage = () => { export const SettingsPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { currentOrg } = useOrganization();
return ( return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white"> <div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<Helmet> <Helmet>
@@ -20,9 +24,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl"> <div className="w-full max-w-8xl">
<PageHeader <PageHeader
scope={ProjectType.SSH} scope={ProjectType.SSH}
title="Settings" title="Project Settings"
description="Configure your SSH product's configurations." 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"> <Tabs orientation="vertical" defaultValue="tab-project-general">
<TabList> <TabList>
<Tab variant="project" value="tab-project-general"> <Tab variant="project" value="tab-project-general">