feat: completed request list page

This commit is contained in:
=
2025-12-06 14:10:56 +05:30
parent f6180f8c12
commit 9b1dee101d
16 changed files with 485 additions and 19 deletions

View File

@@ -68,6 +68,12 @@ export const ROUTE_PATHS = Object.freeze({
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/networking"
)
},
Pam: {
ApprovalRequestDetailPage: setRoute(
"/organizations/$orgId/projects/pam/$projectId/approval-requests/$approvalRequestId",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/approval-requests/$approvalRequestId"
)
},
SecretManager: {
ApprovalPage: setRoute(
"/organizations/$orgId/projects/secret-management/$projectId/approval",

View File

@@ -23,7 +23,7 @@ export type PamAccessPolicyConditions = {
}[];
export type PamAccessPolicyConstraints = {
requestDurationHours: {
requestDurationSeconds: {
min: number;
max: number;
};

View File

@@ -0,0 +1,3 @@
export const ApprovalRequestDetailPage = () => {
return <div>Request detail</div>;
};

View File

@@ -0,0 +1,19 @@
import { createFileRoute } from "@tanstack/react-router";
import { ApprovalRequestDetailPage } from "./ApprovalRequestDetailPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/approval-requests/$approvalRequestId"
)({
component: ApprovalRequestDetailPage,
beforeLoad: ({ context }) => {
return {
breadcrumbs: [
...context.breadcrumbs,
{
label: "Approval Request"
}
]
};
}
});

View File

@@ -5,6 +5,7 @@ import { useOrganization, useProject } from "@app/context";
import { ApprovalControlTabs } from "@app/types/project";
import { useNavigate, useSearch } from "@tanstack/react-router";
import { PolicyTab } from "./components/PolicyTab";
import { ApprovalRequestTab } from "./components/ApprovalRequestTab";
const Page = () => {
const navigate = useNavigate();
@@ -47,7 +48,7 @@ const Page = () => {
</Tab>
</TabList>
<TabPanel value={ApprovalControlTabs.Requests}>
<div>Hello</div>
<ApprovalRequestTab />
</TabPanel>
<TabPanel value={ApprovalControlTabs.Policies}>
<PolicyTab />

View File

@@ -0,0 +1,5 @@
import { RequestsSection } from "./components";
export const ApprovalRequestTab = () => {
return <RequestsSection />;
};

View File

@@ -0,0 +1,12 @@
import { RequestsTable } from "./RequestsTable";
export const RequestsSection = () => {
return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-center justify-between">
<p className="text-xl font-medium text-mineshaft-100">Approval Requests</p>
</div>
<RequestsTable />
</div>
);
};

View File

@@ -0,0 +1,387 @@
import { useCallback, useMemo, useState } from "react";
import {
faCheckCircle,
faChevronRight,
faExclamationCircle,
faFileCircleQuestion,
faFilter,
faMagnifyingGlass,
faSearch
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { useQuery } from "@tanstack/react-query";
import { formatDistance } from "date-fns";
import { twMerge } from "tailwind-merge";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuTrigger,
DropdownSubMenu,
DropdownSubMenuContent,
DropdownSubMenuTrigger,
EmptyState,
IconButton,
Input,
Pagination,
Table,
TableContainer,
TableSkeleton,
TBody,
Td,
Th,
THead,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useOrganization, useProject, useUser } from "@app/context";
import { usePagination } from "@app/hooks";
import { ApprovalPolicyType } from "@app/hooks/api/approvalPolicies";
import {
approvalRequestQuery,
ApprovalRequestStatus,
ApprovalRequestStepStatus,
TApprovalRequest
} from "@app/hooks/api/approvalRequests";
import { ApproverType } from "@app/hooks/api/approvalPolicies";
type Filter = {
status: "open" | "closed";
closedStatuses: ApprovalRequestStatus[];
};
const getStatusBadgeColor = (status: ApprovalRequestStatus) => {
switch (status) {
case ApprovalRequestStatus.Pending:
return "project";
case ApprovalRequestStatus.Approved:
return "success";
case ApprovalRequestStatus.Rejected:
return "danger";
case ApprovalRequestStatus.Expired:
return "neutral";
default:
return "neutral";
}
};
const formatDuration = (seconds: number) => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
if (hours > 0) {
return `${hours}h${minutes > 0 ? ` ${minutes}m` : ""}`;
}
return `${minutes}m`;
};
const checkIfUserNeedsToApprove = (request: TApprovalRequest, userId: string): boolean => {
const currentStep = request.steps.find(
(step) => step.status === ApprovalRequestStepStatus.InProgress
);
if (!currentStep) return false;
const isApprover = currentStep.approvers.some(
(approver) => approver.type === ApproverType.User && approver.id === userId
);
if (!isApprover) return false;
const hasAlreadyApproved = currentStep.approvals.some(
(approval) => approval.approverId === userId
);
return !hasAlreadyApproved;
};
export const RequestsTable = () => {
const navigate = useNavigate();
const { currentOrg } = useOrganization();
const { currentProject } = useProject();
const { user } = useUser();
const [search, setSearch] = useState("");
const [filter, setFilter] = useState<Filter>({
status: "open",
closedStatuses: []
});
const projectId = currentProject?.id || "";
const userId = user?.id || "";
const { data: requests = [], isPending: isRequestsLoading } = useQuery(
approvalRequestQuery.list({
policyType: ApprovalPolicyType.PamAccess,
projectId
})
);
const { page, perPage, setPage, setPerPage, offset } = usePagination();
const filteredRequests = useMemo(() => {
let filtered = requests;
// Apply search filter
if (search) {
filtered = filtered.filter(
(request) =>
request.requesterName?.toLowerCase().includes(search.toLowerCase()) ||
request.requesterEmail?.toLowerCase().includes(search.toLowerCase()) ||
request.justification?.toLowerCase().includes(search.toLowerCase()) ||
request.requestData.requestData.resourceId.toLowerCase().includes(search.toLowerCase()) ||
request.requestData.requestData.accountPath.toLowerCase().includes(search.toLowerCase())
);
}
// Apply open/closed filter
if (filter.status === "open") {
filtered = filtered.filter((req) => req.status === ApprovalRequestStatus.Pending);
} else {
const closedStatuses = [
ApprovalRequestStatus.Approved,
ApprovalRequestStatus.Rejected,
ApprovalRequestStatus.Expired
];
filtered = filtered.filter((req) => closedStatuses.includes(req.status));
// Apply specific closed status filter
if (filter.closedStatuses.length > 0) {
filtered = filtered.filter((req) => filter.closedStatuses.includes(req.status));
}
}
return filtered;
}, [requests, search, filter]);
const paginatedRequests = useMemo(
() => filteredRequests.slice(offset, offset + perPage),
[filteredRequests, offset, perPage]
);
const handleRowClick = (requestId: string) => {
navigate({
to: "/organizations/$orgId/projects/pam/$projectId/approval-requests/$approvalRequestId",
params: {
orgId: currentOrg.id,
projectId: currentProject.id,
approvalRequestId: requestId
}
});
};
const handleStatusFilterToggle = useCallback(
() =>
setFilter((state) => ({
...state,
status: state.status === "open" ? "closed" : "open",
closedStatuses: []
})),
[]
);
const handleClosedStatusToggle = useCallback(
(status: ApprovalRequestStatus) =>
setFilter((state) => {
const closedStatuses = state.closedStatuses || [];
if (closedStatuses.includes(status)) {
return { ...state, closedStatuses: closedStatuses.filter((s) => s !== status) };
}
return { ...state, closedStatuses: [...closedStatuses, status] };
}),
[]
);
const isTableFiltered = filter.status === "closed" || filter.closedStatuses.length > 0;
return (
<div>
<div className="flex gap-2">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton
ariaLabel="Filter Requests"
variant="plain"
size="sm"
className={twMerge(
"flex h-9.5 w-[2.6rem] items-center justify-center overflow-hidden border border-mineshaft-600 bg-mineshaft-800 p-0 transition-all hover:border-primary/60 hover:bg-primary/10",
isTableFiltered && "border-primary/50 text-primary"
)}
>
<FontAwesomeIcon icon={faFilter} />
</IconButton>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="p-0">
<DropdownMenuLabel>Filter By</DropdownMenuLabel>
<DropdownMenuItem
onClick={(evt) => {
evt.preventDefault();
handleStatusFilterToggle();
}}
icon={filter.status === "open" && <FontAwesomeIcon icon={faCheckCircle} />}
iconPos="right"
>
Open Requests
</DropdownMenuItem>
<DropdownSubMenu>
<DropdownSubMenuTrigger
iconPos="right"
icon={<FontAwesomeIcon icon={faChevronRight} size="sm" />}
>
Closed Requests
</DropdownSubMenuTrigger>
<DropdownSubMenuContent className="max-h-80 thin-scrollbar overflow-y-auto rounded-l-none">
<DropdownMenuLabel className="sticky top-0 bg-mineshaft-900">
Filter by Status
</DropdownMenuLabel>
<DropdownMenuItem
onClick={(evt) => {
evt.preventDefault();
handleClosedStatusToggle(ApprovalRequestStatus.Approved);
}}
icon={
filter.closedStatuses.includes(ApprovalRequestStatus.Approved) && (
<FontAwesomeIcon icon={faCheckCircle} />
)
}
iconPos="right"
>
Approved
</DropdownMenuItem>
<DropdownMenuItem
onClick={(evt) => {
evt.preventDefault();
handleClosedStatusToggle(ApprovalRequestStatus.Rejected);
}}
icon={
filter.closedStatuses.includes(ApprovalRequestStatus.Rejected) && (
<FontAwesomeIcon icon={faCheckCircle} />
)
}
iconPos="right"
>
Rejected
</DropdownMenuItem>
<DropdownMenuItem
onClick={(evt) => {
evt.preventDefault();
handleClosedStatusToggle(ApprovalRequestStatus.Expired);
}}
icon={
filter.closedStatuses.includes(ApprovalRequestStatus.Expired) && (
<FontAwesomeIcon icon={faCheckCircle} />
)
}
iconPos="right"
>
Expired
</DropdownMenuItem>
</DropdownSubMenuContent>
</DropdownSubMenu>
</DropdownMenuContent>
</DropdownMenu>
<Input
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search approval requests..."
/>
</div>
<TableContainer className="mt-4">
<Table>
<THead>
<Tr>
<Th>Requester</Th>
<Th>Resource / Path</Th>
<Th>Duration</Th>
<Th>Status</Th>
<Th>Requested</Th>
</Tr>
</THead>
<TBody>
{isRequestsLoading && <TableSkeleton columns={5} innerKey="approval-requests" />}
{!isRequestsLoading &&
paginatedRequests.map((request) => {
const needsApproval = checkIfUserNeedsToApprove(request, userId);
const { resourceId, accountPath, requestDurationSeconds } =
request.requestData.requestData;
return (
<Tr
key={request.id}
className={twMerge(
"cursor-pointer transition-colors hover:bg-mineshaft-700",
needsApproval && "bg-primary/5 hover:bg-primary/10"
)}
onClick={() => handleRowClick(request.id)}
>
<Td>
<div>
<div className="text-sm font-medium text-mineshaft-100">
{request.requesterName || "Unknown"}
</div>
<div className="text-xs text-mineshaft-400">{request.requesterEmail}</div>
</div>
</Td>
<Td>
<div>
<div className="text-sm text-mineshaft-200">{accountPath}</div>
<div className="font-mono text-xs text-mineshaft-400">
{resourceId.slice(0, 8)}...
</div>
</div>
</Td>
<Td>
<span className="text-sm text-mineshaft-200">
{formatDuration(requestDurationSeconds)}
</span>
</Td>
<Td>
<div className="flex items-center gap-2">
<Badge variant={getStatusBadgeColor(request.status)}>
{request.status}
</Badge>
{needsApproval && (
<div className="flex items-center gap-1 rounded bg-primary/20 px-2 py-0.5 text-xs text-primary">
<FontAwesomeIcon icon={faExclamationCircle} className="h-3 w-3" />
<span>Approval Required</span>
</div>
)}
</div>
</Td>
<Td>
<span className="text-sm text-mineshaft-400">
{formatDistance(new Date(request.createdAt), new Date(), {
addSuffix: true
})}
</span>
</Td>
</Tr>
);
})}
</TBody>
</Table>
{Boolean(filteredRequests.length) && (
<Pagination
count={filteredRequests.length}
page={page}
perPage={perPage}
onChangePage={setPage}
onChangePerPage={setPerPage}
/>
)}
{!isRequestsLoading && !filteredRequests?.length && (
<EmptyState
title={
requests.length ? "No approval requests match search..." : "No approval requests found"
}
icon={requests.length ? faSearch : faFileCircleQuestion}
/>
)}
</TableContainer>
</div>
);
};

View File

@@ -0,0 +1,2 @@
export { RequestsSection } from "./RequestsSection";
export { RequestsTable } from "./RequestsTable";

View File

@@ -0,0 +1 @@
export { ApprovalRequestTab } from "./ApprovalRequestTab";

View File

@@ -48,9 +48,9 @@ export const PolicyModal = ({ popUp, handlePopUpToggle }: Props) => {
maxRequestTtlSeconds: null,
conditions: [{ resourceIds: [], accountPaths: [] }],
constraints: {
requestDurationHours: {
min: 1,
max: 24
requestDurationSeconds: {
min: 30,
max: 604800
}
},
steps: [
@@ -88,9 +88,9 @@ export const PolicyModal = ({ popUp, handlePopUpToggle }: Props) => {
maxRequestTtlSeconds: null,
conditions: [{ resourceIds: [], accountPaths: [] }],
constraints: {
requestDurationHours: {
min: 1,
max: 24
requestDurationSeconds: {
min: 30,
max: 604800
}
},
steps: [

View File

@@ -12,9 +12,9 @@ export const PolicyFormSchema = z.object({
.array()
.min(1, "At least one condition is required"),
constraints: z.object({
requestDurationHours: z.object({
min: z.number().min(0).max(168),
max: z.number().min(1).max(168)
requestDurationSeconds: z.object({
min: z.number().min(0).max(604800),
max: z.number().min(1).max(604800)
})
}),
steps: z

View File

@@ -51,19 +51,19 @@ export const PolicyDetailsStep = () => {
Request Duration Constraints
</p>
<p className="text-xs text-mineshaft-400">
Set minimum and maximum duration (in hours) for access requests
Set minimum and maximum duration (in seconds) for access requests
</p>
</div>
<div className="grid grid-cols-2 gap-4">
<Controller
control={control}
name="constraints.requestDurationHours.min"
name="constraints.requestDurationSeconds.min"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Minimum Hours"
isError={Boolean(error)}
errorText={error?.message}
helperText="0-168 hours"
helperText="30-604800 hours"
>
<Input
{...field}
@@ -77,13 +77,13 @@ export const PolicyDetailsStep = () => {
/>
<Controller
control={control}
name="constraints.requestDurationHours.max"
name="constraints.requestDurationSeconds.max"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Maximum Hours"
isError={Boolean(error)}
errorText={error?.message}
helperText="1-168 hours (7 days)"
helperText="30-604800 hours (7 days)"
>
<Input
{...field}

View File

@@ -70,11 +70,11 @@ export const PolicyReviewStep = () => {
<div className="space-y-2">
<ReviewField
label="Minimum Duration"
value={`${constraints.requestDurationHours.min} hour${constraints.requestDurationHours.min !== 1 ? "s" : ""}`}
value={`${constraints.requestDurationSeconds.min} second${constraints.requestDurationSeconds.min !== 1 ? "s" : ""}`}
/>
<ReviewField
label="Maximum Duration"
value={`${constraints.requestDurationHours.max} hour${constraints.requestDurationHours.max !== 1 ? "s" : ""}`}
value={`${constraints.requestDurationSeconds.max} second${constraints.requestDurationSeconds.max !== 1 ? "s" : ""}`}
/>
</div>
</div>

View File

@@ -151,6 +151,7 @@ import { Route as secretManagerSecretDashboardPageRouteImport } from './pages/se
import { Route as secretManagerIntegrationsSelectIntegrationAuthPageRouteImport } from './pages/secret-manager/integrations/SelectIntegrationAuthPage/route'
import { Route as secretManagerIntegrationsDetailsByIDPageRouteImport } from './pages/secret-manager/IntegrationsDetailsByIDPage/route'
import { Route as pamPamSessionsByIDPageRouteImport } from './pages/pam/PamSessionsByIDPage/route'
import { Route as pamApprovalRequestDetailPageRouteImport } from './pages/pam/ApprovalRequestDetailPage/route'
import { Route as certManagerPkiSubscriberDetailsByIDPageRouteImport } from './pages/cert-manager/PkiSubscriberDetailsByIDPage/route'
import { Route as certManagerPkiSyncDetailsByIDPageRouteImport } from './pages/cert-manager/PkiSyncDetailsByIDPage/route'
import { Route as certManagerCertAuthDetailsByIDPageRouteImport } from './pages/cert-manager/CertAuthDetailsByIDPage/route'
@@ -1504,6 +1505,13 @@ const pamPamSessionsByIDPageRouteRoute =
AuthenticateInjectOrgDetailsOrgLayoutOrganizationsOrgIdProjectsPamProjectIdPamLayoutSessionsRoute,
} as any)
const pamApprovalRequestDetailPageRouteRoute =
pamApprovalRequestDetailPageRouteImport.update({
id: '/approval-requests/$approvalRequestId',
path: '/approval-requests/$approvalRequestId',
getParentRoute: () => pamLayoutRoute,
} as any)
const certManagerPkiSubscriberDetailsByIDPageRouteRoute =
certManagerPkiSubscriberDetailsByIDPageRouteImport.update({
id: '/$subscriberName',
@@ -3217,6 +3225,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof certManagerPkiSubscriberDetailsByIDPageRouteImport
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationsOrgIdProjectsCertManagementProjectIdCertManagerLayoutSubscribersImport
}
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/approval-requests/$approvalRequestId': {
id: '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/approval-requests/$approvalRequestId'
path: '/approval-requests/$approvalRequestId'
fullPath: '/organizations/$orgId/projects/pam/$projectId/approval-requests/$approvalRequestId'
preLoaderRoute: typeof pamApprovalRequestDetailPageRouteImport
parentRoute: typeof pamLayoutImport
}
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions/$sessionId': {
id: '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions/$sessionId'
path: '/$sessionId'
@@ -4234,6 +4249,7 @@ interface pamLayoutRouteChildren {
projectAccessControlPageRoutePamRoute: typeof projectAccessControlPageRoutePamRoute
projectAuditLogsPageRoutePamRoute: typeof projectAuditLogsPageRoutePamRoute
AuthenticateInjectOrgDetailsOrgLayoutOrganizationsOrgIdProjectsPamProjectIdPamLayoutSessionsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationsOrgIdProjectsPamProjectIdPamLayoutSessionsRouteWithChildren
pamApprovalRequestDetailPageRouteRoute: typeof pamApprovalRequestDetailPageRouteRoute
projectGroupDetailsByIDPageRoutePamRoute: typeof projectGroupDetailsByIDPageRoutePamRoute
projectIdentityDetailsByIDPageRoutePamRoute: typeof projectIdentityDetailsByIDPageRoutePamRoute
projectMemberDetailsByIDPageRoutePamRoute: typeof projectMemberDetailsByIDPageRoutePamRoute
@@ -4249,6 +4265,8 @@ const pamLayoutRouteChildren: pamLayoutRouteChildren = {
projectAuditLogsPageRoutePamRoute: projectAuditLogsPageRoutePamRoute,
AuthenticateInjectOrgDetailsOrgLayoutOrganizationsOrgIdProjectsPamProjectIdPamLayoutSessionsRoute:
AuthenticateInjectOrgDetailsOrgLayoutOrganizationsOrgIdProjectsPamProjectIdPamLayoutSessionsRouteWithChildren,
pamApprovalRequestDetailPageRouteRoute:
pamApprovalRequestDetailPageRouteRoute,
projectGroupDetailsByIDPageRoutePamRoute:
projectGroupDetailsByIDPageRoutePamRoute,
projectIdentityDetailsByIDPageRoutePamRoute:
@@ -5219,6 +5237,7 @@ export interface FileRoutesByFullPath {
'/organizations/$orgId/projects/cert-management/$projectId/ca/$caId': typeof certManagerCertAuthDetailsByIDPageRouteRoute
'/organizations/$orgId/projects/cert-management/$projectId/integrations/$syncId': typeof certManagerPkiSyncDetailsByIDPageRouteRoute
'/organizations/$orgId/projects/cert-management/$projectId/subscribers/$subscriberName': typeof certManagerPkiSubscriberDetailsByIDPageRouteRoute
'/organizations/$orgId/projects/pam/$projectId/approval-requests/$approvalRequestId': typeof pamApprovalRequestDetailPageRouteRoute
'/organizations/$orgId/projects/pam/$projectId/sessions/$sessionId': typeof pamPamSessionsByIDPageRouteRoute
'/organizations/$orgId/projects/secret-management/$projectId/integrations/$integrationId': typeof secretManagerIntegrationsDetailsByIDPageRouteRoute
'/organizations/$orgId/projects/secret-management/$projectId/integrations/select-integration-auth': typeof secretManagerIntegrationsSelectIntegrationAuthPageRouteRoute
@@ -5450,6 +5469,7 @@ export interface FileRoutesByTo {
'/organizations/$orgId/projects/cert-management/$projectId/ca/$caId': typeof certManagerCertAuthDetailsByIDPageRouteRoute
'/organizations/$orgId/projects/cert-management/$projectId/integrations/$syncId': typeof certManagerPkiSyncDetailsByIDPageRouteRoute
'/organizations/$orgId/projects/cert-management/$projectId/subscribers/$subscriberName': typeof certManagerPkiSubscriberDetailsByIDPageRouteRoute
'/organizations/$orgId/projects/pam/$projectId/approval-requests/$approvalRequestId': typeof pamApprovalRequestDetailPageRouteRoute
'/organizations/$orgId/projects/pam/$projectId/sessions/$sessionId': typeof pamPamSessionsByIDPageRouteRoute
'/organizations/$orgId/projects/secret-management/$projectId/integrations/$integrationId': typeof secretManagerIntegrationsDetailsByIDPageRouteRoute
'/organizations/$orgId/projects/secret-management/$projectId/integrations/select-integration-auth': typeof secretManagerIntegrationsSelectIntegrationAuthPageRouteRoute
@@ -5704,6 +5724,7 @@ export interface FileRoutesById {
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/ca/$caId': typeof certManagerCertAuthDetailsByIDPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/integrations/$syncId': typeof certManagerPkiSyncDetailsByIDPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/subscribers/$subscriberName': typeof certManagerPkiSubscriberDetailsByIDPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/approval-requests/$approvalRequestId': typeof pamApprovalRequestDetailPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions/$sessionId': typeof pamPamSessionsByIDPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/$integrationId': typeof secretManagerIntegrationsDetailsByIDPageRouteRoute
'/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/select-integration-auth': typeof secretManagerIntegrationsSelectIntegrationAuthPageRouteRoute
@@ -5950,6 +5971,7 @@ export interface FileRouteTypes {
| '/organizations/$orgId/projects/cert-management/$projectId/ca/$caId'
| '/organizations/$orgId/projects/cert-management/$projectId/integrations/$syncId'
| '/organizations/$orgId/projects/cert-management/$projectId/subscribers/$subscriberName'
| '/organizations/$orgId/projects/pam/$projectId/approval-requests/$approvalRequestId'
| '/organizations/$orgId/projects/pam/$projectId/sessions/$sessionId'
| '/organizations/$orgId/projects/secret-management/$projectId/integrations/$integrationId'
| '/organizations/$orgId/projects/secret-management/$projectId/integrations/select-integration-auth'
@@ -6180,6 +6202,7 @@ export interface FileRouteTypes {
| '/organizations/$orgId/projects/cert-management/$projectId/ca/$caId'
| '/organizations/$orgId/projects/cert-management/$projectId/integrations/$syncId'
| '/organizations/$orgId/projects/cert-management/$projectId/subscribers/$subscriberName'
| '/organizations/$orgId/projects/pam/$projectId/approval-requests/$approvalRequestId'
| '/organizations/$orgId/projects/pam/$projectId/sessions/$sessionId'
| '/organizations/$orgId/projects/secret-management/$projectId/integrations/$integrationId'
| '/organizations/$orgId/projects/secret-management/$projectId/integrations/select-integration-auth'
@@ -6432,6 +6455,7 @@ export interface FileRouteTypes {
| '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/ca/$caId'
| '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/integrations/$syncId'
| '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/subscribers/$subscriberName'
| '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/approval-requests/$approvalRequestId'
| '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions/$sessionId'
| '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/$integrationId'
| '/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/select-integration-auth'
@@ -7086,6 +7110,7 @@ export const routeTree = rootRoute
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/access-management",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/audit-logs",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/approval-requests/$approvalRequestId",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/groups/$groupId",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/identities/$identityId",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/members/$membershipId",
@@ -7454,6 +7479,10 @@ export const routeTree = rootRoute
"filePath": "cert-manager/PkiSubscriberDetailsByIDPage/route.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/subscribers"
},
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/approval-requests/$approvalRequestId": {
"filePath": "pam/ApprovalRequestDetailPage/route.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout"
},
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions/$sessionId": {
"filePath": "pam/PamSessionsByIDPage/route.tsx",
"parent": "/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions"

View File

@@ -358,10 +358,11 @@ const pamRoutes = route("/organizations/$orgId/projects/pam/$projectId", [
route("/resources", "pam/PamResourcesPage/route.tsx"),
route("/audit-logs", "project/AuditLogsPage/route-pam.tsx"),
route("/settings", "pam/SettingsPage/route.tsx"),
route("/approvals", "pam/ApprovalsPage/route.tsx"),
route("/approval-requests/$approvalRequestId", "pam/ApprovalRequestDetailPage/route.tsx"),
// Access Management
route("/access-management", "project/AccessControlPage/route-pam.tsx"),
route("/approvals", "pam/ApprovalsPage/route.tsx"),
route("/roles/$roleSlug", "project/RoleDetailsBySlugPage/route-pam.tsx"),
route("/identities/$identityId", "project/IdentityDetailsByIDPage/route-pam.tsx"),
route("/members/$membershipId", "project/MemberDetailsByIDPage/route-pam.tsx"),