correction in Role
This commit is contained in:
@@ -56,6 +56,32 @@ export default function NewRoleForm() {
|
||||
const [fetching, setFetching] = useState(isEdit);
|
||||
const [fetchError, setFetchError] = useState<string | null>(null);
|
||||
|
||||
const [selectedGroup, setSelectedGroup] = useState<string>(() => {
|
||||
return localStorage.getItem("pim_roles_last_group_filter") || "all";
|
||||
});
|
||||
|
||||
const parentGroups = nodes.filter(
|
||||
(node) =>
|
||||
node.node_type === "group" ||
|
||||
(node.node_type === "feature" && (node.parent_id === null || node.parent_id === undefined))
|
||||
);
|
||||
const featureNodes = nodes.filter((node) => node.node_type === "feature" || !node.node_type);
|
||||
|
||||
const handleGroupSelect = (groupId: string) => {
|
||||
setSelectedGroup(groupId);
|
||||
localStorage.setItem("pim_roles_last_group_filter", groupId);
|
||||
};
|
||||
|
||||
const filteredNodes = selectedGroup === "all"
|
||||
? featureNodes
|
||||
: featureNodes.filter((node) => {
|
||||
const selectedNode = nodes.find((n) => String(n.id) === selectedGroup);
|
||||
if (selectedNode?.node_type === "group") {
|
||||
return String(node.parent_id) === selectedGroup;
|
||||
}
|
||||
return String(node.id) === selectedGroup;
|
||||
});
|
||||
|
||||
const setValuesRef = useRef<((values: any) => void) | null>(null);
|
||||
|
||||
const formik = useFormik({
|
||||
@@ -467,8 +493,61 @@ export default function NewRoleForm() {
|
||||
className="bg-surface rounded-lg border border-primary/10 shadow-sm overflow-hidden flex flex-col"
|
||||
style={{ height: "520px" }}
|
||||
>
|
||||
<div className="shrink-0">
|
||||
<style>{`
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(4px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.animate-fade-in {
|
||||
animation: fadeIn 0.25s ease-out forwards;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
<div className="shrink-0 border-b border-border bg-surface">
|
||||
<CardHeader title="Permissions Matrix" subtitle="Configure granular access levels for each module" />
|
||||
|
||||
{!nodesLoading && !nodesError && parentGroups.length > 0 && (
|
||||
<div
|
||||
role="tablist"
|
||||
aria-label="Filter Permissions by Category"
|
||||
className="flex items-center gap-2 px-6 py-3 border-t border-border overflow-x-auto scrollbar-none sticky top-0 bg-surface z-20"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected={selectedGroup === "all"}
|
||||
onClick={() => handleGroupSelect("all")}
|
||||
className={`px-3 py-1.5 rounded-lg text-xs font-semibold tracking-wide transition-all duration-200 cursor-pointer ${
|
||||
selectedGroup === "all"
|
||||
? "bg-primary text-white shadow-sm shadow-primary/20 scale-102"
|
||||
: "bg-primary/5 hover:bg-primary-ghost text-subtle-foreground hover:text-primary-dark"
|
||||
}`}
|
||||
>
|
||||
All ({featureNodes.length})
|
||||
</button>
|
||||
{parentGroups.map((g) => {
|
||||
const count = g.node_type === "group"
|
||||
? featureNodes.filter((node) => String(node.parent_id) === String(g.id)).length
|
||||
: 1;
|
||||
return (
|
||||
<button
|
||||
key={g.id}
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected={selectedGroup === String(g.id)}
|
||||
onClick={() => handleGroupSelect(String(g.id))}
|
||||
className={`px-3 py-1.5 rounded-lg text-xs font-semibold tracking-wide transition-all duration-200 cursor-pointer ${
|
||||
selectedGroup === String(g.id)
|
||||
? "bg-primary text-white shadow-sm shadow-primary/20 scale-102"
|
||||
: "bg-primary/5 hover:bg-primary-ghost text-subtle-foreground hover:text-primary-dark"
|
||||
}`}
|
||||
>
|
||||
{g.node_name} ({count})
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{nodesLoading && (
|
||||
@@ -493,10 +572,11 @@ export default function NewRoleForm() {
|
||||
|
||||
{!nodesLoading && !nodesError && (
|
||||
<div
|
||||
className="flex-1 overflow-y-auto divide-y divide-border"
|
||||
key={selectedGroup}
|
||||
className="flex-1 overflow-y-auto divide-y divide-border animate-fade-in"
|
||||
style={{ scrollbarWidth: "none" }}
|
||||
>
|
||||
{nodes.map((node) => {
|
||||
{filteredNodes.map((node) => {
|
||||
const perm = permissions[node.id];
|
||||
const supportedActions = getSupportedActions(node);
|
||||
|
||||
@@ -547,6 +627,12 @@ export default function NewRoleForm() {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{filteredNodes.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<p className="text-sm text-muted-foreground font-medium">No permissions available.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -40,10 +40,10 @@ export interface SidebarItem {
|
||||
}
|
||||
|
||||
export const sidebarConfig: SidebarItem[] = [
|
||||
{
|
||||
label: 'Dashboard',
|
||||
href: '/dashboard',
|
||||
icon: LayoutDashboard
|
||||
{
|
||||
label: 'Dashboard',
|
||||
href: '/dashboard',
|
||||
icon: LayoutDashboard
|
||||
},
|
||||
{
|
||||
label: 'Products',
|
||||
@@ -101,9 +101,9 @@ export const sidebarConfig: SidebarItem[] = [
|
||||
{ label: 'Asset Families', href: '/asset-families', icon: Layers },
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Workflow & Approvals',
|
||||
href: '/workflow',
|
||||
{
|
||||
label: 'Workflow & Approvals',
|
||||
href: '/workflow',
|
||||
icon: Workflow
|
||||
},
|
||||
{
|
||||
@@ -116,24 +116,25 @@ export const sidebarConfig: SidebarItem[] = [
|
||||
{ label: 'Integration Hub', href: '/integrations', icon: Plug, permission: 'settings.integrations' },
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Users & Roles',
|
||||
href: '/users',
|
||||
icon: Users,
|
||||
{
|
||||
label: 'Users & Roles',
|
||||
href: '/users',
|
||||
icon: Users,
|
||||
children: [
|
||||
{ label: 'Users', href: '/users', icon: Users, permission: 'settings.users' },
|
||||
{ label: 'Tenants', href: '/users/tenants', icon: Database, permission: 'settings.tenants' },
|
||||
{ label: 'Roles', href: '/users/roles', icon: Users, permission: 'settings.roles' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Reports',
|
||||
href: '/reports',
|
||||
icon: BarChart
|
||||
{
|
||||
label: 'Reports',
|
||||
href: '/reports',
|
||||
icon: BarChart,
|
||||
permission: 'reports'
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
href: '/settings',
|
||||
{
|
||||
label: 'Settings',
|
||||
href: '/settings',
|
||||
icon: Settings
|
||||
},
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ export interface NodePermissions {
|
||||
|
||||
export type PermissionPayload = Record<string, NodePermissions>;
|
||||
|
||||
export type PermissionNodes =
|
||||
export type PermissionNodes =
|
||||
| 'products.items'
|
||||
| 'products.families'
|
||||
| 'products.categories'
|
||||
@@ -27,7 +27,6 @@ export type PermissionNodes =
|
||||
| 'settings.users'
|
||||
| 'settings.roles'
|
||||
| 'settings.integrations'
|
||||
| 'reports.sales'
|
||||
| 'reports.inventory';
|
||||
| 'reports';
|
||||
|
||||
export type PermissionAction = keyof NodePermissions;
|
||||
|
||||
Reference in New Issue
Block a user