mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-08 23:18:05 -05:00
Merge pull request #4934 from Infisical/ENG-4198
improvements: styling and labeling additions to improve scope context
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
@@ -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) => (
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) => (
|
||||||
|
|||||||
@@ -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 && (
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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"}`}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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"}`}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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"}
|
||||||
|
|||||||
@@ -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"}
|
||||||
|
|||||||
@@ -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 ? (
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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"}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user