fix: Actions V2 improve deleted target handling in executions (#9822)

# Which Problems Are Solved
Previously, if a target was deleted but still referenced by an
execution, it became impossible to load the executions.

# How the Problems Are Solved
Missing targets in the execution table are now gracefully ignored,
allowing executions to load without errors.

# Additional Changes
Enhanced permission handling in the settings sidenav to ensure users
have the correct access rights.
This commit is contained in:
Ramon
2025-04-30 14:22:27 +02:00
committed by GitHub
parent 002c3eb025
commit 48c1f7e49f
4 changed files with 20 additions and 15 deletions

View File

@@ -24,8 +24,8 @@
<th mat-header-cell *matHeaderCellDef>{{ 'ACTIONSTWO.EXECUTION.TABLE.TARGET' | translate }}</th> <th mat-header-cell *matHeaderCellDef>{{ 'ACTIONSTWO.EXECUTION.TABLE.TARGET' | translate }}</th>
<td mat-cell *cnslCellDef="let row; dataSource: dataSource"> <td mat-cell *cnslCellDef="let row; dataSource: dataSource">
<div class="target-key"> <div class="target-key">
<cnsl-project-role-chip *ngFor="let target of row.mappedTargets; trackBy: trackTarget" [roleName]="target.name" <cnsl-project-role-chip *ngFor="let target of row.mappedTargets; trackBy: trackTarget" [roleName]="target.name">
>{{ target.name }} {{ target.name }}
</cnsl-project-role-chip> </cnsl-project-role-chip>
</div> </div>
</td> </td>

View File

@@ -55,13 +55,9 @@ export class ActionsTwoActionsTableComponent {
} }
return executions.map((execution) => { return executions.map((execution) => {
const mappedTargets = execution.targets.map((target) => { const mappedTargets = execution.targets
const targetType = targetsMap.get(target); .map((target) => targetsMap.get(target))
if (!targetType) { .filter((target): target is NonNullable<typeof target> => !!target);
throw new Error(`Target with id ${target} not found`);
}
return targetType;
});
return { execution, mappedTargets }; return { execution, mappedTargets };
}); });
}); });

View File

@@ -228,8 +228,7 @@ export const ACTIONS: SidenavSetting = {
i18nKey: 'SETTINGS.LIST.ACTIONS', i18nKey: 'SETTINGS.LIST.ACTIONS',
groupI18nKey: 'SETTINGS.GROUPS.ACTIONS', groupI18nKey: 'SETTINGS.GROUPS.ACTIONS',
requiredRoles: { requiredRoles: {
// todo: figure out roles [PolicyComponentServiceType.ADMIN]: ['action.execution.write', 'action.target.write'],
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
}, },
beta: true, beta: true,
}; };
@@ -239,8 +238,7 @@ export const ACTIONS_TARGETS: SidenavSetting = {
i18nKey: 'SETTINGS.LIST.TARGETS', i18nKey: 'SETTINGS.LIST.TARGETS',
groupI18nKey: 'SETTINGS.GROUPS.ACTIONS', groupI18nKey: 'SETTINGS.GROUPS.ACTIONS',
requiredRoles: { requiredRoles: {
// todo: figure out roles [PolicyComponentServiceType.ADMIN]: ['action.execution.write', 'action.target.write'],
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
}, },
beta: true, beta: true,
}; };

View File

@@ -1,7 +1,18 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { SortDirection } from '@angular/material/sort'; import { SortDirection } from '@angular/material/sort';
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';
import { BehaviorSubject, combineLatestWith, EMPTY, mergeWith, NEVER, Observable, of, shareReplay, Subject } from 'rxjs'; import {
BehaviorSubject,
combineLatestWith,
EMPTY,
identity,
mergeWith,
NEVER,
Observable,
of,
shareReplay,
Subject,
} from 'rxjs';
import { catchError, distinctUntilChanged, filter, finalize, map, startWith, switchMap, tap, timeout } from 'rxjs/operators'; import { catchError, distinctUntilChanged, filter, finalize, map, startWith, switchMap, tap, timeout } from 'rxjs/operators';
import { import {
@@ -326,7 +337,7 @@ export class GrpcAuthService {
return new RegExp(reqRegexp).test(role); return new RegExp(reqRegexp).test(role);
}); });
const allCheck = requestedRoles.map(test).every((x) => !!x); const allCheck = requestedRoles.map(test).every(identity);
const oneCheck = requestedRoles.some(test); const oneCheck = requestedRoles.some(test);
return requiresAll ? allCheck : oneCheck; return requiresAll ? allCheck : oneCheck;