Developer role should be able to view tag-retention rules (#17138)

Developer role should be able to view tag-rerention rules

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Shijun Sun 2022-07-08 11:38:54 +08:00 committed by GitHub
parent efd9632e96
commit 6c1fbde2a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 168 additions and 65 deletions

View File

@ -73,6 +73,7 @@ export class ProjectDetailComponent
hasConfigurationListPermission: boolean;
hasRobotListPermission: boolean;
hasTagRetentionPermission: boolean;
hasTagImmutablePermission: boolean;
hasWebhookListPermission: boolean;
hasScannerReadPermission: boolean;
hasP2pProviderReadPermission: boolean;
@ -128,7 +129,9 @@ export class ProjectDetailComponent
linkName: 'tag-strategy',
tabLinkInOverflow: false,
showTabName: 'PROJECT_DETAIL.POLICY',
permissions: () => this.hasTagRetentionPermission,
permissions: () =>
this.hasTagRetentionPermission ||
this.hasTagImmutablePermission,
},
{
linkName: 'robot-account',
@ -297,6 +300,13 @@ export class ProjectDetailComponent
USERSTATICPERMISSION.TAG_RETENTION.VALUE.READ
)
);
permissionsList.push(
this.userPermissionService.getPermission(
projectId,
USERSTATICPERMISSION.IMMUTABLE_TAG.KEY,
USERSTATICPERMISSION.IMMUTABLE_TAG.VALUE.LIST
)
);
permissionsList.push(
this.userPermissionService.getPermission(
projectId,
@ -339,6 +349,7 @@ export class ProjectDetailComponent
this.hasRobotListPermission,
this.hasLabelCreatePermission,
this.hasTagRetentionPermission,
this.hasTagImmutablePermission,
this.hasWebhookListPermission,
this.hasScannerReadPermission,
this.hasP2pProviderReadPermission,

View File

@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
} from '@angular/router';
import { Observable } from 'rxjs';
import { UserPrivilegeServeItem } from 'src/app/shared/services/interface';
import { MemberPermissionGuard } from '../../../shared/router-guard/member-permission-guard-activate.service';
@Injectable({
providedIn: 'root',
})
export class TagFeatureGuardService implements CanActivate {
constructor(private memberPermissionGuard: MemberPermissionGuard) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | boolean {
const projectId = route.parent.parent.parent.params['id'];
const permission = route.data.permissionParam as UserPrivilegeServeItem;
return this.memberPermissionGuard.checkPermission(
projectId,
permission
);
}
}

View File

@ -1,21 +1,19 @@
<div class="btn-group btn-tag-integration">
<div
class="radio btn"
<button
[disabled]="!hasTagRetentionPermission"
routerLink="tag-retention"
routerLinkActive="checked">
<input type="radio" name="btn-group-demo-radios" id="btn-retention" />
<label class="strategy-nav-link" for="btn-retention">{{
'TAG_RETENTION.TAG_RETENTION' | translate
}}</label>
</div>
<div
class="radio btn"
routerLinkActive="btn-primary"
class="btn"
id="btn-retention">
{{ 'TAG_RETENTION.TAG_RETENTION' | translate }}
</button>
<button
[disabled]="!hasTagImmutablePermission"
routerLink="immutable-tag"
routerLinkActive="checked">
<input type="radio" name="btn-group-demo-radios" id="btn-immutable" />
<label class="strategy-nav-link" for="btn-immutable">{{
'PROJECT_DETAIL.IMMUTABLE_TAG' | translate
}}</label>
</div>
routerLinkActive="btn-primary"
class="btn"
id="btn-immutable">
{{ 'PROJECT_DETAIL.IMMUTABLE_TAG' | translate }}
</button>
</div>
<router-outlet></router-outlet>

View File

@ -1,17 +1,4 @@
.btn-tag-integration {
margin-top: 1.5rem;
margin-bottom: 1rem;
.strategy-nav-link {
height: 100%;
width: 100%;
display: inline-block;
padding-left: 0.5rem;
padding-right: 0.5rem;
text-decoration: none;
}
}
.checked {
color: #fff;
}

View File

@ -1,15 +1,42 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TagFeatureIntegrationComponent } from './tag-feature-integration.component';
import { SharedTestingModule } from '../../../shared/shared.module';
import { UserPermissionService } from '../../../shared/services';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
describe('TagFeatureIntegrationComponent', () => {
let component: TagFeatureIntegrationComponent;
let fixture: ComponentFixture<TagFeatureIntegrationComponent>;
const mockActivatedRoute = {
snapshot: {
parent: {
parent: {
params: { id: 1 },
},
},
},
};
const mockUserPermissionService = {
getPermission() {
return of(true);
},
};
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [TagFeatureIntegrationComponent],
imports: [SharedTestingModule],
providers: [
{
provide: UserPermissionService,
useValue: mockUserPermissionService,
},
{
provide: ActivatedRoute,
useValue: mockActivatedRoute,
},
],
}).compileComponents();
});
@ -22,4 +49,11 @@ describe('TagFeatureIntegrationComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
it('should get project id and permissions', async () => {
await fixture.whenStable();
expect(component.projectId).toEqual(1);
expect(component.hasTagImmutablePermission).toBeTruthy();
expect(component.hasTagRetentionPermission).toBeTruthy();
});
});

View File

@ -1,10 +1,44 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import {
UserPermissionService,
USERSTATICPERMISSION,
} from '../../../shared/services';
import { forkJoin, Observable } from 'rxjs';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-tag-feature-integration',
templateUrl: './tag-feature-integration.component.html',
styleUrls: ['./tag-feature-integration.component.scss'],
})
export class TagFeatureIntegrationComponent {
constructor() {}
export class TagFeatureIntegrationComponent implements OnInit {
projectId: number;
hasTagRetentionPermission: boolean;
hasTagImmutablePermission: boolean;
constructor(
private userPermissionService: UserPermissionService,
private route: ActivatedRoute
) {}
ngOnInit() {
this.projectId = this.route.snapshot.parent.parent.params['id'];
const permissionsList: Array<Observable<boolean>> = [];
permissionsList.push(
this.userPermissionService.getPermission(
this.projectId,
USERSTATICPERMISSION.TAG_RETENTION.KEY,
USERSTATICPERMISSION.TAG_RETENTION.VALUE.READ
)
);
permissionsList.push(
this.userPermissionService.getPermission(
this.projectId,
USERSTATICPERMISSION.IMMUTABLE_TAG.KEY,
USERSTATICPERMISSION.IMMUTABLE_TAG.VALUE.LIST
)
);
forkJoin(permissionsList).subscribe(Rules => {
[this.hasTagRetentionPermission, this.hasTagImmutablePermission] =
Rules;
});
}
}

View File

@ -9,6 +9,8 @@ import { ImmutableTagComponent } from './immutable-tag/immutable-tag.component';
import { ImmutableTagService } from './immutable-tag/immutable-tag.service';
import { AddImmutableRuleComponent } from './immutable-tag/add-rule/add-immutable-rule.component';
import { TagRetentionTasksComponent } from './tag-retention/tag-retention-tasks/tag-retention-tasks/tag-retention-tasks.component';
import { USERSTATICPERMISSION } from '../../../shared/services';
import { TagFeatureGuardService } from './tag-feature-guard.service';
const routes: Routes = [
{
@ -17,10 +19,24 @@ const routes: Routes = [
children: [
{
path: 'tag-retention',
canActivate: [TagFeatureGuardService],
data: {
permissionParam: {
resource: USERSTATICPERMISSION.TAG_RETENTION.KEY,
action: USERSTATICPERMISSION.TAG_RETENTION.VALUE.READ,
},
},
component: TagRetentionComponent,
},
{
path: 'immutable-tag',
canActivate: [TagFeatureGuardService],
data: {
permissionParam: {
resource: USERSTATICPERMISSION.IMMUTABLE_TAG.KEY,
action: USERSTATICPERMISSION.IMMUTABLE_TAG.VALUE.LIST,
},
},
component: ImmutableTagComponent,
},
{ path: '', redirectTo: 'tag-retention', pathMatch: 'full' },

View File

@ -27,27 +27,7 @@ export class MemberPermissionGuard implements CanActivate, CanActivateChild {
): Observable<boolean> | boolean {
const projectId = route.parent.params['id'];
const permission = route.data.permissionParam as UserPrivilegeServeItem;
return new Observable(observer => {
this.userPermission
.getPermission(
projectId,
permission.resource,
permission.action
)
.subscribe(
permissionRouter => {
if (!permissionRouter) {
this.router.navigate([CommonRoutes.HARBOR_DEFAULT]);
}
observer.next(permissionRouter);
},
error => {
this.router.navigate([CommonRoutes.HARBOR_DEFAULT]);
observer.next(false);
this.errorHandler.error(error);
}
);
});
return this.checkPermission(projectId, permission);
}
canActivateChild(
@ -56,4 +36,30 @@ export class MemberPermissionGuard implements CanActivate, CanActivateChild {
): Observable<boolean> | boolean {
return this.canActivate(route, state);
}
checkPermission(
projectId: number,
permission: UserPrivilegeServeItem
): Observable<boolean> {
return new Observable(observer => {
this.userPermission
.getPermission(
projectId,
permission.resource,
permission.action
)
.subscribe({
next: permissionRouter => {
if (!permissionRouter) {
this.router.navigate([CommonRoutes.HARBOR_DEFAULT]);
}
observer.next(permissionRouter);
},
error: error => {
this.router.navigate([CommonRoutes.HARBOR_DEFAULT]);
observer.next(false);
this.errorHandler.error(error);
},
});
});
}
}

View File

@ -159,13 +159,6 @@ hbr-tag {
background-image: linear-gradient(180deg,$selectBox-option-hover-bg-color-start 0,$selectBox-option-hover-bg-color-end) !important;
}
.btn-tag-integration {
.active {
background: $btn-tag-integration-active-bg-color;
color: $btn-tag-integration-active-color;
}
}
hbr-result-tip-histogram {
.inner {
background-color: $hbr-result-tip-histogram-inner-bg-color;

View File

@ -28,8 +28,6 @@ $filter-divider-bg-color: #495865;
/* stylelint-disable */
$selectBox-option-hover-bg-color-start: #4aaed9;
$selectBox-option-hover-bg-color-end: #0077b8;
$btn-tag-integration-active-bg-color: #4aaed9;
$btn-tag-integration-active-color: #000;
$hbr-result-tip-histogram-inner-bg-color: #21333b;
$harbor-icon-translate-x: 0;
$harbor-icon-drop-shadow-x: 58px;

View File

@ -29,8 +29,6 @@ $filter-divider-bg-color: #ccc;
/* stylelint-disable */
$selectBox-option-hover-bg-color-start: #f5f5f5;
$selectBox-option-hover-bg-color-end: #e8e8e8;
$btn-tag-integration-active-bg-color: #0077b8;
$btn-tag-integration-active-color: #fff;
$hbr-result-tip-histogram-inner-bg-color: #fff;
$harbor-icon-translate-x: 100%;
$harbor-icon-drop-shadow-x: -56px;