Files
Kavita/UI/Web/src/libs/action-utils.ts
T
2026-03-07 07:36:02 -08:00

54 lines
1.7 KiB
TypeScript

import {ActionItem} from "../app/_models/actionables/action-item";
import {User} from "../app/_models/user/user";
import {AccountService} from "../app/_services/account.service";
/**
* Determines if a single action should render for the given user.
*/
export function willRenderAction<T>(
action: ActionItem<T>,
entity: T,
user: User,
accountService: AccountService
): boolean {
const hasValidRole = !action.requiredRoles?.length || accountService.hasAnyRole(user, action.requiredRoles);
return hasValidRole && action.shouldRender(action, entity, user);
}
/**
* Recursively filters an action tree, removing actions the user cannot see.
* Submenu parents with no visible children are also removed.
*/
export function filterActionTree<T>(
actions: ActionItem<T>[],
entity: T,
user: User,
accountService: AccountService
): ActionItem<T>[] {
return actions.reduce<ActionItem<T>[]>((acc, action) => {
// Submenu parent (has static children, no dynamicList)
if (action.children?.length > 0 && !action.dynamicList) {
const filteredChildren = filterActionTree(action.children, entity, user, accountService);
if (filteredChildren.length > 0) {
acc.push({...action, children: filteredChildren});
}
return acc;
}
// Leaf action
if (willRenderAction(action, entity, user, accountService)) {
acc.push(action);
}
return acc;
}, []);
}
/**
* Checks whether a submenu should render based on its dynamic list state.
*/
export function shouldRenderSubMenu(action: ActionItem<any>, dynamicList: null | Array<any>): boolean {
const firstChild = action.children?.[0];
return (firstChild?.dynamicList == null) || (dynamicList != null && dynamicList.length > 0);
}