Activities of "alexander.nikonov"

So far I have not found a better approach than hiding (setting invisible to an item with requiredPolicy and moduleId) in the createTree method) the items prior to removing or showing them inside subcription of combineLatest.

UPDATE: i've checked this approach and it has some drawbacks - after filtering the menu structure is broken (some intermediate parent nodes disappeared) and I cannot navigate to the displayed pages with "no matching route" error. I don't know if I am doing something wrong or it is bad idea to override RoutesService and hide the items in the createTree call.

Anjali, do you know where should I put my "hide" method? The small issue now is that initially the menu is shown fully - pause for API mapping call - and then it is filtered out accordingly. I want the menu was shown after it has been filtered out...

this.currentUser$.subscribe(currentUser => {
  if (currentUser?.isAuthenticated) {
    ...
    this.modulePermissionHandler.init(); // it is too late :(
    ...
});

I've tried to replace RoutesService:

export class AbxRoutesService extends AbstractNavTreeService<ABP.Route>

and make filtration inside

public override createTree(items: ABP.Route[]): TreeNode<ABP.Route>[]

But this method is synchronous and I cannot await mapping API call result. On other hand, I don't want to do something about flat$ getter, because the filtration needs to be done just before building the tree.

It is so frustrating...

Hi. Seems like I have eventually nailed it. My steps were:

  1. adding moduleId to non-lazy node collection in route.provider.ts(I copied the corresponding values from lazy-loading nodes (path: '' in the routing module). I applied your as any recipe, thank you;

  2. returning the following multiple permission result from back-end to be able to handle (hide) nodes in Angular app using mapping from back-end:

     public override Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
     {
         var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToList();
         Check.NotNullOrEmpty(permissionNames, nameof(permissionNames));
    
         return Task.FromResult(new MultiplePermissionGrantResult(permissionNames.ToArray(), PermissionGrantResult.Granted));
     }
    
  3. making API request retrieving the mapping between moduleId (or all simple roles) and their permissions for a current user (modulePermissionMap$);

  4. filtering out all the menu items which need to be hidden based on modulePermissionMap$, RoutersService.flat$ (combineLatest) and eventually applying RoutersService.remove method;

I will keep the ticket opened so far - in case our testing team finds something wrong during the nearest time...

Ok, I see. So RoutersService does not fit me. Still, I need some mechanism to show or not to show the specific lazy-loaded nodes based on their "moduleId". I need to do this before the menu is displayed, of course: How do I do this? Probably some Router events are in use here...

Hmm, probably it would work this way. I would give it a try. However, I just discovered I was not right in my suggestions. ABP RoutesService does not return all nodes in the menu - it returns only non-lazy nodes. So what I need is to load a whole structure of my menu into a variable and then check each node module ID inside the loop. The question is - what is a proper way to load all the nodes? Are there ready ABP methods for it? Or I need to use Angular methods? Or I need to create my own recursive method? I know it won't be complex, but don't want to re-invent a wheel...

I need to receive all nodes which are present in the menu, both lazy and non-lazy. And obtain data property of each node. Angular Router config DOES return data, but it does not return lazy nodes. ABP RoutesService flat$ / tree$ / visible$ DOES return all nodes, but it does not return data. So I need something which would return BOTH.

The problem is that this.router.config does not return lazy-loading routing module nodes where actually my data with moduleId resides. It only returns the ordinary nodes.

You can still use the RoutesService to modify the menu anytime and anywhere in the app you can use it in the app.component.ts.

Hi. I am aware about this. But what I actually need is to retrieve information about data of my route items. As I mentioned, RoutersService does not provide this information.

I heard the idea of Permission Guard earlier in this thread and I wrote about it in my previous message:

However I've just checked out that canActivate is not triggered when I reload my root page

I.e. when I navigate to the root page (https://localhost:4200/) of the site (not a specific page) - this guard is not triggered. And the site menu is not checked against available module ID permissions, so all the pages are shown, even those which need to be hidden according to the available module ID permissions. So I asked what needs to be overriden in the given case - definitely it is not a Permission Guard. Actually I do not need "403" error if there is no permission: this is already handled by back-end method public override async Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context) What I need now is to HIDE the page if there is no permission assigned to its module ID. I prepared API call with module ID mappings which returns the following structure: "moduleID1" => ["permissionA", "permissionX"], "moduleID2" => ["permissionY", "permissionX"], If the page has moduleId="moduleID1" and "permissionB" as a requiredPolicy, it needs to be hidden from the menu, since mapping for "moduleID1" does not contain "permissionB"

So I just need to know what is ABP code where I can put this check. Please, reply ASAP. Probably it needs to happen inside this.route.visible$.subscribe(visibleRoute => { ... }) of app.component.ts, but I need to be sure there is one and only one place which controls menu item visibility and it does not make conflict with other relevant ABP code.

UPDATE: here is another problem - the ABP getters below do not store data attribute, so they do not return this information:

this.route.flat$.subscribe((flatRoute: ABP.Route[]) => {
  //PROBLEM: flatRoute does not contain `data`, so we cannot retrieve `moduleId`
  flatRoute.filter(x => x.requiredPolicy).forEach(routeItemWithPolicy => {
    console.log(routeItemWithPolicy);
  });

Thank you for reply. However I've just checked out that canActivate is not triggered when I reload my root page, i.e. it is not responsible for showing/hiding menu items:

Question 1) what ABP service/method is actually used to decide what to show or hide in the menu? Question 2) meanwhile to save time while waiting for your reply I decided to make a server method (the result is supposed to be cached in Angular client) which returns mapping between module IDs and their permissions. Is it a correct approach? I've tried to use PermissionAppService.GetAsync() directly inside the loop, but it is very slow:

    public virtual async Task&lt;Dictionary&lt;string, IEnumerable&lt;string&gt;>> GetModuleRolePermissionMapAsync()
    {
        var moduleRoleNames = await _modulePermissionChecker.GetModuleRoleNamesAsync(CurrentTenant.Id, CurrentUser.Id, CurrentUser.IsAuthenticated);

        var result = new Dictionary&lt;string, IEnumerable&lt;string&gt;>();

        using (CurrentTenant.Change(null))
        {
            var permissionGrants = await _permissionGrantRepository.GetListAsync();

            result = moduleRoleNames.GroupJoin
            (
                permissionGrants.Where(pg => pg.ProviderName == RolePermissionValueProvider.ProviderName),
                moduleRoleName => moduleRoleName,
                permissionGrant => permissionGrant.ProviderKey,
                (moduleRoleName, permissionGrants) => (moduleRoleName, permissionGrantNames: permissionGrants.Select(x => x.Name))
            )
            .ToDictionary(x => x.moduleRoleName, x => x.permissionGrantNames);
        }

        return result;
    }
Showing 121 to 130 of 276 entries
Made with ❤️ on ABP v9.0.0-preview Updated on September 20, 2024, 08:30