Files
prowler/ui/app/(prowler)/manage-groups/page.tsx
Alan Buscaglia 4d5676f00e feat: upgrade to React 19, Next.js 15, React Compiler, HeroUI and Tailwind 4 (#8748)
Co-authored-by: Alan Buscaglia <alanbuscaglia@MacBook-Pro.local>
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
Co-authored-by: César Arroba <cesar@prowler.com>
Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
2025-09-30 09:59:51 +02:00

198 lines
6.0 KiB
TypeScript

import { Divider } from "@heroui/divider";
import { Spacer } from "@heroui/spacer";
import { redirect } from "next/navigation";
import React, { Suspense } from "react";
import {
getProviderGroupInfoById,
getProviderGroups,
} from "@/actions/manage-groups/manage-groups";
import { getProviders } from "@/actions/providers";
import { getRoles } from "@/actions/roles";
import { FilterControls } from "@/components/filters/filter-controls";
import { AddGroupForm, EditGroupForm } from "@/components/manage-groups/forms";
import { SkeletonManageGroups } from "@/components/manage-groups/skeleton-manage-groups";
import { ColumnGroups } from "@/components/manage-groups/table";
import { DataTable } from "@/components/ui/table";
import { ProviderProps, Role, SearchParamsProps } from "@/types";
export default async function ManageGroupsPage({
searchParams,
}: {
searchParams: Promise<SearchParamsProps>;
}) {
const resolvedSearchParams = await searchParams;
const searchParamsKey = JSON.stringify(resolvedSearchParams);
const providerGroupId = resolvedSearchParams.groupId;
return (
<div className="grid min-h-[70vh] grid-cols-1 items-center justify-center gap-4 md:grid-cols-12">
<div className="col-span-1 flex justify-end md:col-span-4">
<Suspense key={searchParamsKey} fallback={<SkeletonManageGroups />}>
{providerGroupId ? (
<SSRDataEditGroup searchParams={resolvedSearchParams} />
) : (
<div className="flex flex-col">
<h1 className="mb-2 text-xl font-medium" id="getting-started">
Create a new provider group
</h1>
<p className="text-small text-default-500 mb-5">
Create a new provider group to manage the providers and roles.
</p>
<SSRAddGroupForm />
</div>
)}
</Suspense>
</div>
<Divider orientation="vertical" className="mx-auto h-full" />
<div className="col-span-1 flex-col justify-start md:col-span-6">
<FilterControls />
<Spacer y={8} />
<h3 className="mb-4 text-sm font-bold uppercase">Provider Groups</h3>
<Suspense key={searchParamsKey} fallback={<SkeletonManageGroups />}>
<SSRDataTable searchParams={resolvedSearchParams} />
</Suspense>
</div>
</div>
);
}
const SSRAddGroupForm = async () => {
const providersResponse = await getProviders({ pageSize: 50 });
const rolesResponse = await getRoles({});
const providersData =
providersResponse?.data?.map((provider: ProviderProps) => ({
id: provider.id,
name: provider.attributes.alias || provider.attributes.uid,
})) || [];
const rolesData =
rolesResponse?.data?.map((role: Role) => ({
id: role.id,
name: role.attributes.name,
})) || [];
return <AddGroupForm providers={providersData} roles={rolesData} />;
};
const SSRDataEditGroup = async ({
searchParams,
}: {
searchParams: SearchParamsProps;
}) => {
const providerGroupId = searchParams.groupId;
// Redirect if no group ID is provided or if the parameter is invalid
if (!providerGroupId || Array.isArray(providerGroupId)) {
redirect("/manage-groups");
}
// Fetch the provider group details
const providerGroupData = await getProviderGroupInfoById(providerGroupId);
if (!providerGroupData || providerGroupData.error) {
return <div>Provider group not found</div>;
}
const providersResponse = await getProviders({ pageSize: 50 });
const rolesResponse = await getRoles({});
const providersList =
providersResponse?.data?.map((provider: ProviderProps) => ({
id: provider.id,
name: provider.attributes.alias || provider.attributes.uid,
})) || [];
const rolesList =
rolesResponse?.data?.map((role: Role) => ({
id: role.id,
name: role.attributes.name,
})) || [];
const { attributes, relationships } = providerGroupData.data;
const associatedProviders = relationships.providers?.data.map(
(provider: ProviderProps) => {
const matchingProvider = providersList.find(
(p: { id: string; name: string }) => p.id === provider.id,
);
return {
id: provider.id,
name: matchingProvider?.name || "Unavailable for your role",
};
},
);
const associatedRoles = relationships.roles?.data.map((role: Role) => {
const matchingRole = rolesList.find((r: Role) => r.id === role.id);
return {
id: role.id,
name: matchingRole?.name || "Unavailable for your role",
};
});
const formData = {
name: attributes.name,
providers: associatedProviders,
roles: associatedRoles,
};
return (
<div className="flex flex-col">
<h1 className="mb-2 text-xl font-medium" id="getting-started">
Edit provider group
</h1>
<p className="text-small text-default-500 mb-5">
Edit the provider group to manage the providers and roles.
</p>
<EditGroupForm
providerGroupId={providerGroupId}
providerGroupData={formData}
allProviders={providersList}
allRoles={rolesList}
/>
</div>
);
};
const SSRDataTable = async ({
searchParams,
}: {
searchParams: SearchParamsProps;
}) => {
const page = parseInt(searchParams.page?.toString() || "1", 10);
const sort = searchParams.sort?.toString();
const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10);
// Convert filters to the correct type
const filters: Record<string, string> = {};
Object.entries(searchParams)
.filter(([key]) => key.startsWith("filter["))
.forEach(([key, value]) => {
filters[key] = value?.toString() || "";
});
const query = (filters["filter[search]"] as string) || "";
const providerGroupsData = await getProviderGroups({
query,
page,
sort,
filters,
pageSize,
});
return (
<>
<DataTable
key={`groups-${Date.now()}`}
columns={ColumnGroups}
data={providerGroupsData?.data || []}
metadata={providerGroupsData?.meta}
/>
</>
);
};