mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 19:28:09 +00:00
fix: review changes
This commit is contained in:
@@ -58,15 +58,10 @@ export const loginLDAPRedirect = async (loginLDAPDetails: LoginLDAPDTO) => {
|
||||
return data;
|
||||
};
|
||||
|
||||
export type SelectOrganizationParams =
|
||||
| {
|
||||
organizationId: string;
|
||||
userAgent?: UserAgentType;
|
||||
}
|
||||
| {
|
||||
subOrganizationId: string;
|
||||
userAgent?: UserAgentType;
|
||||
};
|
||||
export type SelectOrganizationParams = {
|
||||
organizationId: string;
|
||||
userAgent?: UserAgentType;
|
||||
};
|
||||
|
||||
export const selectOrganization = async (data: SelectOrganizationParams) => {
|
||||
const { data: res } = await apiRequest.post<{
|
||||
|
||||
@@ -11,10 +11,7 @@ export const useCreateSubOrganization = () => {
|
||||
mutationFn: async (dto: TCreateSubOrganizationDTO) => {
|
||||
const { data } = await apiRequest.post<{ organization: TSubOrganization }>(
|
||||
"/api/v1/sub-organizations",
|
||||
dto,
|
||||
{
|
||||
headers: { "x-root-org": "discard" } // akhi/scott: this just tells the request to use the root org ID header
|
||||
}
|
||||
dto
|
||||
);
|
||||
return data;
|
||||
},
|
||||
|
||||
@@ -62,11 +62,7 @@ import {
|
||||
useGetOrgTrialUrl,
|
||||
useLogoutUser
|
||||
} from "@app/hooks/api";
|
||||
import {
|
||||
authKeys,
|
||||
selectOrganization,
|
||||
type SelectOrganizationParams
|
||||
} from "@app/hooks/api/auth/queries";
|
||||
import { authKeys, selectOrganization } from "@app/hooks/api/auth/queries";
|
||||
import { MfaMethod } from "@app/hooks/api/auth/types";
|
||||
import { getAuthToken } from "@app/hooks/api/reactQuery";
|
||||
import { Organization, SubscriptionPlan } from "@app/hooks/api/types";
|
||||
@@ -197,26 +193,18 @@ export const Navbar = () => {
|
||||
|
||||
const handleOrgSelection = async ({
|
||||
organizationId,
|
||||
subOrganizationId,
|
||||
navigateTo,
|
||||
onSuccess
|
||||
}: {
|
||||
organizationId?: string;
|
||||
subOrganizationId?: string;
|
||||
navigateTo?: string;
|
||||
onSuccess?: () => void | Promise<void>;
|
||||
}) => {
|
||||
if (!organizationId && !subOrganizationId) return;
|
||||
if (!organizationId) return;
|
||||
|
||||
const targetId = subOrganizationId ?? organizationId;
|
||||
if (organizationId === currentOrg.id) return;
|
||||
|
||||
if (targetId === currentOrg.id) return;
|
||||
|
||||
const selectionPayload: SelectOrganizationParams = subOrganizationId
|
||||
? { subOrganizationId }
|
||||
: { organizationId: organizationId as string };
|
||||
|
||||
const { token, isMfaEnabled, mfaMethod } = await selectOrganization(selectionPayload);
|
||||
const { token, isMfaEnabled, mfaMethod } = await selectOrganization({ organizationId });
|
||||
|
||||
if (isMfaEnabled) {
|
||||
SecurityClient.setMfaToken(token);
|
||||
@@ -225,7 +213,7 @@ export const Navbar = () => {
|
||||
}
|
||||
toggleShowMfa.on();
|
||||
setMfaSuccessCallback(() => async () => {
|
||||
await handleOrgSelection({ organizationId, subOrganizationId, onSuccess });
|
||||
await handleOrgSelection({ organizationId, onSuccess });
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -234,11 +222,12 @@ export const Navbar = () => {
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
queryClient.removeQueries({ queryKey: authKeys.getAuthToken });
|
||||
queryClient.removeQueries({ queryKey: projectKeys.getAllUserProjects() });
|
||||
|
||||
await router.invalidate();
|
||||
await navigateUserToOrg({ navigate, organizationId: targetId, navigateTo });
|
||||
queryClient.removeQueries({ queryKey: subOrgQuery.queryKey });
|
||||
|
||||
await queryClient.refetchQueries({ queryKey: authKeys.getAuthToken });
|
||||
|
||||
await navigateUserToOrg({ navigate, organizationId, navigateTo });
|
||||
|
||||
if (onSuccess) {
|
||||
await onSuccess();
|
||||
}
|
||||
@@ -387,14 +376,17 @@ export const Navbar = () => {
|
||||
<button
|
||||
className="flex cursor-pointer items-center gap-x-2 truncate whitespace-nowrap"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onClick={async () => {
|
||||
if (isSubOrganization) {
|
||||
handleOrgSelection({ organizationId: currentOrg.rootOrgId as string });
|
||||
await handleOrgSelection({
|
||||
organizationId: currentOrg.rootOrgId as string
|
||||
});
|
||||
} else {
|
||||
navigate({
|
||||
to: "/organizations/$orgId/projects",
|
||||
params: { orgId: currentOrg.id }
|
||||
});
|
||||
}
|
||||
navigate({
|
||||
to: "/organizations/$orgId/projects",
|
||||
params: { orgId: currentOrg.id }
|
||||
});
|
||||
}}
|
||||
>
|
||||
<OrgIcon className={twMerge("size-[14px] shrink-0 text-org")} />
|
||||
@@ -471,7 +463,7 @@ export const Navbar = () => {
|
||||
</div>
|
||||
{subOrganizations.map((subOrg) => (
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleOrgSelection({ subOrganizationId: subOrg.id })}
|
||||
onClick={() => handleOrgSelection({ organizationId: subOrg.id })}
|
||||
className="cursor-pointer font-normal"
|
||||
key={subOrg.id}
|
||||
>
|
||||
@@ -486,18 +478,16 @@ export const Navbar = () => {
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
{Boolean(subOrganizations.length && !isSubOrganization) && (
|
||||
{Boolean(subOrganizations.length) && (
|
||||
<div className="mt-1 h-1 border-t border-mineshaft-600" />
|
||||
)}
|
||||
{!isSubOrganization && (
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
icon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => setShowSubOrgForm(true)}
|
||||
>
|
||||
New Sub-Organization
|
||||
</DropdownMenuItem>
|
||||
)}{" "}
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
icon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => setShowSubOrgForm(true)}
|
||||
>
|
||||
New Sub-Organization
|
||||
</DropdownMenuItem>
|
||||
</DropdownSubMenuContent>
|
||||
</DropdownSubMenu>
|
||||
);
|
||||
@@ -590,7 +580,7 @@ export const Navbar = () => {
|
||||
</div>
|
||||
{subOrganizations.map((subOrg) => (
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleOrgSelection({ subOrganizationId: subOrg.id })}
|
||||
onClick={() => handleOrgSelection({ organizationId: subOrg.id })}
|
||||
className="cursor-pointer font-normal"
|
||||
key={subOrg.id}
|
||||
>
|
||||
@@ -602,18 +592,16 @@ export const Navbar = () => {
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
{Boolean(subOrganizations.length && !isSubOrganization) && (
|
||||
{Boolean(subOrganizations.length) && (
|
||||
<div className="mt-1 h-1 border-t border-mineshaft-600" />
|
||||
)}
|
||||
{!isSubOrganization && (
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
icon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => setShowSubOrgForm(true)}
|
||||
>
|
||||
New Sub-Organization
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
icon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => setShowSubOrgForm(true)}
|
||||
>
|
||||
New Sub-Organization
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
+12
-1
@@ -7,6 +7,7 @@ import { z } from "zod";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import SecurityClient from "@app/components/utilities/SecurityClient";
|
||||
import { Button, FormControl, Input } from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import { projectKeys, subOrganizationsQuery, useCreateSubOrganization } from "@app/hooks/api";
|
||||
import { authKeys, selectOrganization } from "@app/hooks/api/auth/queries";
|
||||
import { slugSchema } from "@app/lib/schemas";
|
||||
@@ -23,6 +24,7 @@ const AddOrgSchema = z.object({
|
||||
type FormData = z.infer<typeof AddOrgSchema>;
|
||||
|
||||
export const NewSubOrganizationForm = ({ onClose }: ContentProps) => {
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
const createSubOrg = useCreateSubOrganization();
|
||||
const subOrgQuery = subOrganizationsQuery.list({ limit: 500, isAccessible: true });
|
||||
const queryClient = useQueryClient();
|
||||
@@ -42,6 +44,15 @@ export const NewSubOrganizationForm = ({ onClose }: ContentProps) => {
|
||||
const router = useRouter();
|
||||
|
||||
const onSubmit = async ({ name }: FormData) => {
|
||||
if (isSubOrganization && currentOrg.rootOrgId) {
|
||||
const { token } = await selectOrganization({
|
||||
organizationId: currentOrg.rootOrgId
|
||||
});
|
||||
|
||||
SecurityClient.setToken(token);
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
}
|
||||
|
||||
const { organization } = await createSubOrg.mutateAsync({
|
||||
name
|
||||
});
|
||||
@@ -53,7 +64,7 @@ export const NewSubOrganizationForm = ({ onClose }: ContentProps) => {
|
||||
onClose();
|
||||
|
||||
const { token } = await selectOrganization({
|
||||
subOrganizationId: organization.id
|
||||
organizationId: organization.id
|
||||
});
|
||||
|
||||
SecurityClient.setToken(token);
|
||||
|
||||
@@ -18,7 +18,7 @@ const tabs = [
|
||||
|
||||
export const SettingsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentOrg } = useOrganization();
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
|
||||
@@ -34,7 +34,8 @@ export const SettingsPage = () => {
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for organization settings?
|
||||
<InfoIcon size={12} /> Looking for {isSubOrganization ? "sub-" : ""}organization
|
||||
settings?
|
||||
</Link>
|
||||
</PageHeader>
|
||||
<Tabs orientation="vertical" defaultValue={tabs[0].key}>
|
||||
|
||||
@@ -19,7 +19,7 @@ const tabs = [
|
||||
export const SettingsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { currentOrg } = useOrganization();
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
|
||||
@@ -39,7 +39,8 @@ export const SettingsPage = () => {
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for organization settings?
|
||||
<InfoIcon size={12} /> Looking for {isSubOrganization ? "sub-" : ""}organization
|
||||
settings?
|
||||
</Link>
|
||||
</PageHeader>
|
||||
<Tabs orientation="vertical" defaultValue={tabs[0].key}>
|
||||
|
||||
@@ -73,6 +73,11 @@ export const Route = createFileRoute("/_authenticate")({
|
||||
});
|
||||
});
|
||||
|
||||
return { organizationId: data.organizationId as string, isAuthenticated: true, user };
|
||||
const isSubOrganization = !!data.subOrganizationId;
|
||||
return {
|
||||
organizationId: isSubOrganization ? data.subOrganizationId : (data.organizationId as string),
|
||||
isAuthenticated: true,
|
||||
user
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import SecurityClient from "@app/components/utilities/SecurityClient";
|
||||
import { authKeys, fetchAuthToken, selectOrganization } from "@app/hooks/api/auth/queries";
|
||||
import { fetchOrganizationById, organizationKeys } from "@app/hooks/api/organization/queries";
|
||||
import { projectKeys } from "@app/hooks/api/projects";
|
||||
import { fetchUserOrgPermissions, roleQueryKeys } from "@app/hooks/api/roles/queries";
|
||||
import { subOrganizationsQuery } from "@app/hooks/api/subOrganizations";
|
||||
import { fetchOrgSubscription, subscriptionQueryKeys } from "@app/hooks/api/subscriptions/queries";
|
||||
|
||||
// Route context to fill in organization's data like details, subscription etc
|
||||
@@ -15,6 +19,33 @@ export const Route = createFileRoute("/_authenticate/_inject-org-details")({
|
||||
organizationId = context.organizationId!;
|
||||
}
|
||||
|
||||
if ((params as { orgId?: string })?.orgId && context.organizationId) {
|
||||
const urlOrgId = (params as { orgId: string }).orgId;
|
||||
const currentTokenOrgId = context.organizationId;
|
||||
|
||||
if (urlOrgId !== currentTokenOrgId) {
|
||||
try {
|
||||
const { token, isMfaEnabled } = await selectOrganization({ organizationId: urlOrgId });
|
||||
|
||||
if (!isMfaEnabled && token) {
|
||||
SecurityClient.setToken(token);
|
||||
SecurityClient.setProviderAuthToken("");
|
||||
|
||||
context.queryClient.removeQueries({ queryKey: authKeys.getAuthToken });
|
||||
context.queryClient.removeQueries({ queryKey: projectKeys.getAllUserProjects() });
|
||||
context.queryClient.removeQueries({ queryKey: subOrganizationsQuery.allKey() });
|
||||
|
||||
await context.queryClient.fetchQuery({
|
||||
queryKey: authKeys.getAuthToken,
|
||||
queryFn: fetchAuthToken
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Failed to automatically exchange token for organization:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await context.queryClient.ensureQueryData({
|
||||
queryKey: organizationKeys.getOrgById(organizationId),
|
||||
queryFn: () => fetchOrganizationById(organizationId)
|
||||
|
||||
@@ -3,7 +3,8 @@ import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useNavigate, useSearch } from "@tanstack/react-router";
|
||||
import { Link, useNavigate, useSearch } from "@tanstack/react-router";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
|
||||
import { OrgPermissionGuardBanner } from "@app/components/permissions/OrgPermissionCan";
|
||||
import { Button, PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
||||
@@ -85,7 +86,19 @@ export const AccessManagementPage = () => {
|
||||
scope={isSubOrganization ? "namespace" : "org"}
|
||||
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} Access Control`}
|
||||
description="Manage fine-grained access for users, groups, roles, and machine identities within your organization resources."
|
||||
/>
|
||||
>
|
||||
{isSubOrganization && (
|
||||
<Link
|
||||
to="/organizations/$orgId/access-management"
|
||||
params={{
|
||||
orgId: currentOrg.rootOrgId ?? ""
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for root organization access control?
|
||||
</Link>
|
||||
)}
|
||||
</PageHeader>
|
||||
{!currentOrg.shouldUseNewPrivilegeSystem && (
|
||||
<div className="mt-4 mb-4 flex flex-col rounded-r border-l-2 border-l-primary bg-mineshaft-300/5 px-4 py-2.5">
|
||||
<div className="mb-1 flex items-center text-sm">
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
@@ -6,7 +8,7 @@ import { useOrganization } from "@app/context";
|
||||
import { LogsSection } from "./components";
|
||||
|
||||
export const AuditLogsPage = () => {
|
||||
const { isSubOrganization } = useOrganization();
|
||||
const { isSubOrganization, currentOrg } = useOrganization();
|
||||
|
||||
return (
|
||||
<div className="h-full bg-bunker-800">
|
||||
@@ -21,7 +23,19 @@ export const AuditLogsPage = () => {
|
||||
scope={isSubOrganization ? "namespace" : "org"}
|
||||
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} Audit Logs`}
|
||||
description="Audit logs for security and compliance teams to monitor information access."
|
||||
/>
|
||||
>
|
||||
{isSubOrganization && (
|
||||
<Link
|
||||
to="/organizations/$orgId/audit-logs"
|
||||
params={{
|
||||
orgId: currentOrg.rootOrgId ?? ""
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for root organization audit logs?
|
||||
</Link>
|
||||
)}
|
||||
</PageHeader>
|
||||
<LogsSection pageView />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
@@ -8,7 +10,7 @@ import { OrgTabGroup } from "./components";
|
||||
|
||||
export const SettingsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { isSubOrganization } = useOrganization();
|
||||
const { isSubOrganization, currentOrg } = useOrganization();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -21,7 +23,19 @@ export const SettingsPage = () => {
|
||||
scope={isSubOrganization ? "namespace" : "org"}
|
||||
description="Configure organization-wide settings"
|
||||
title={isSubOrganization ? "Sub-Organization Settings" : "Organization Settings"}
|
||||
/>
|
||||
>
|
||||
{isSubOrganization && (
|
||||
<Link
|
||||
to="/organizations/$orgId/settings"
|
||||
params={{
|
||||
orgId: currentOrg.rootOrgId ?? ""
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for root organization settings?
|
||||
</Link>
|
||||
)}
|
||||
</PageHeader>
|
||||
<OrgTabGroup />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/Pr
|
||||
export const SettingsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { currentOrg } = useOrganization();
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
|
||||
@@ -31,7 +31,8 @@ export const SettingsPage = () => {
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for organization settings?
|
||||
<InfoIcon size={12} /> Looking for {isSubOrganization ? "sub-" : ""}organization
|
||||
settings?
|
||||
</Link>
|
||||
</PageHeader>
|
||||
<Tabs orientation="vertical" defaultValue="tab-project-general">
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
|
||||
const Page = () => {
|
||||
const navigate = useNavigate();
|
||||
const { currentOrg } = useOrganization();
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
const { currentProject } = useProject();
|
||||
const selectedTab = useSearch({
|
||||
strict: false,
|
||||
@@ -54,7 +54,8 @@ const Page = () => {
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for organization access control?
|
||||
<InfoIcon size={12} /> Looking for {isSubOrganization ? "sub-" : ""}organization access
|
||||
control?
|
||||
</Link>
|
||||
</PageHeader>
|
||||
<Tabs orientation="vertical" value={selectedTab} onValueChange={updateSelectedTab}>
|
||||
|
||||
@@ -3,12 +3,12 @@ import { Link } from "@tanstack/react-router";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
|
||||
import { PageHeader } from "@app/components/v2";
|
||||
import { useProject } from "@app/context";
|
||||
import { useOrganization, useProject } from "@app/context";
|
||||
import { LogsSection } from "@app/pages/organization/AuditLogsPage/components";
|
||||
|
||||
export const AuditLogsPage = () => {
|
||||
const { currentProject } = useProject();
|
||||
|
||||
const { isSubOrganization } = useOrganization();
|
||||
return (
|
||||
<div className="mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||
<Helmet>
|
||||
@@ -29,7 +29,8 @@ export const AuditLogsPage = () => {
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for organization audit logs?
|
||||
<InfoIcon size={12} /> Looking for {isSubOrganization ? "sub-" : ""}organization audit
|
||||
logs?
|
||||
</Link>
|
||||
</PageHeader>
|
||||
<LogsSection pageView project={currentProject} />
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Link } from "@tanstack/react-router";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
|
||||
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
||||
import { useProject } from "@app/context";
|
||||
import { useOrganization, useProject } from "@app/context";
|
||||
import { ProjectType, ProjectVersion } from "@app/hooks/api/projects/types";
|
||||
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
|
||||
|
||||
@@ -15,6 +15,8 @@ import { WorkflowIntegrationTab } from "./components/WorkflowIntegrationSection"
|
||||
|
||||
export const SettingsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { isSubOrganization } = useOrganization();
|
||||
|
||||
const { currentProject } = useProject();
|
||||
const tabs = [
|
||||
{ name: "General", key: "tab-project-general", Component: ProjectGeneralTab },
|
||||
@@ -55,7 +57,8 @@ export const SettingsPage = () => {
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for organization settings?
|
||||
<InfoIcon size={12} /> Looking for {isSubOrganization ? "sub-" : ""}organization
|
||||
settings?
|
||||
</Link>
|
||||
</PageHeader>
|
||||
<Tabs orientation="vertical" defaultValue={tabs[0].key}>
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ProjectScanningConfigTab } from "./components/ProjectScanningConfigTab"
|
||||
|
||||
export const SettingsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentOrg } = useOrganization();
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
|
||||
@@ -34,7 +34,8 @@ export const SettingsPage = () => {
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for organization settings?
|
||||
<InfoIcon size={12} /> Looking for {isSubOrganization ? "sub-" : ""}organization
|
||||
settings?
|
||||
</Link>
|
||||
</PageHeader>
|
||||
<Tabs orientation="vertical" defaultValue="tab-project-general">
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ProjectSshTab } from "./components/ProjectSshTab";
|
||||
export const SettingsPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { currentOrg } = useOrganization();
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
|
||||
@@ -34,7 +34,8 @@ export const SettingsPage = () => {
|
||||
}}
|
||||
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
|
||||
>
|
||||
<InfoIcon size={12} /> Looking for organization settings?
|
||||
<InfoIcon size={12} /> Looking for {isSubOrganization ? "sub-" : ""}organization
|
||||
settings?
|
||||
</Link>
|
||||
</PageHeader>
|
||||
<Tabs orientation="vertical" defaultValue="tab-project-general">
|
||||
|
||||
Reference in New Issue
Block a user