mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 04:05:40 +01:00
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:
parent
efd9632e96
commit
6c1fbde2a8
@ -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,
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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' },
|
||||
|
@ -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);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user