mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-08 17:08:17 +01:00
add ui for project level policy
This commit is contained in:
parent
367f447991
commit
69ffd7117c
@ -47,6 +47,7 @@ func initRouters() {
|
||||
beego.Router("/harbor/projects/:id/replications", &controllers.IndexController{})
|
||||
beego.Router("/harbor/projects/:id/members", &controllers.IndexController{})
|
||||
beego.Router("/harbor/projects/:id/logs", &controllers.IndexController{})
|
||||
beego.Router("/harbor/projects/:id/configs", &controllers.IndexController{})
|
||||
beego.Router("/harbor/tags/:id/*", &controllers.IndexController{})
|
||||
|
||||
beego.Router("/harbor/users", &controllers.IndexController{})
|
||||
|
@ -24,6 +24,7 @@ import { VULNERABILITY_DIRECTIVES } from './vulnerability-scanning/index';
|
||||
import { PUSH_IMAGE_BUTTON_DIRECTIVES } from './push-image/index';
|
||||
import { CONFIGURATION_DIRECTIVES } from './config/index';
|
||||
import { JOB_LOG_VIEWER_DIRECTIVES } from './job-log-viewer/index';
|
||||
import { PROJECT_POLICY_CONFIG_DIRECTIVES } from './project-policy-config/index';
|
||||
|
||||
import {
|
||||
SystemInfoService,
|
||||
@ -43,7 +44,9 @@ import {
|
||||
ConfigurationService,
|
||||
ConfigurationDefaultService,
|
||||
JobLogService,
|
||||
JobLogDefaultService
|
||||
JobLogDefaultService,
|
||||
ProjectService,
|
||||
ProjectDefaultService,
|
||||
} from './service/index';
|
||||
import {
|
||||
ErrorHandler,
|
||||
@ -68,6 +71,7 @@ export const DefaultServiceConfig: IServiceConfig = {
|
||||
replicationRuleEndpoint: "/api/policies/replication",
|
||||
replicationJobEndpoint: "/api/jobs/replication",
|
||||
vulnerabilityScanningBaseEndpoint: "/api/repositories",
|
||||
projectPolicyEndpoint: "/api/projects/configs",
|
||||
enablei18Support: false,
|
||||
defaultLang: DEFAULT_LANG,
|
||||
langCookieKey: DEFAULT_LANG_COOKIE_KEY,
|
||||
@ -118,7 +122,10 @@ export interface HarborModuleConfig {
|
||||
configService?: Provider,
|
||||
|
||||
//Service implementation for job log
|
||||
jobLogService?: Provider
|
||||
jobLogService?: Provider,
|
||||
|
||||
//Service implementation for project policy
|
||||
projectPolicyService?: Provider,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,7 +169,8 @@ export function initConfig(translateInitializer: TranslateServiceInitializer, co
|
||||
VULNERABILITY_DIRECTIVES,
|
||||
PUSH_IMAGE_BUTTON_DIRECTIVES,
|
||||
CONFIGURATION_DIRECTIVES,
|
||||
JOB_LOG_VIEWER_DIRECTIVES
|
||||
JOB_LOG_VIEWER_DIRECTIVES,
|
||||
PROJECT_POLICY_CONFIG_DIRECTIVES
|
||||
],
|
||||
exports: [
|
||||
LOG_DIRECTIVES,
|
||||
@ -183,7 +191,8 @@ export function initConfig(translateInitializer: TranslateServiceInitializer, co
|
||||
PUSH_IMAGE_BUTTON_DIRECTIVES,
|
||||
CONFIGURATION_DIRECTIVES,
|
||||
JOB_LOG_VIEWER_DIRECTIVES,
|
||||
TranslateModule
|
||||
TranslateModule,
|
||||
PROJECT_POLICY_CONFIG_DIRECTIVES
|
||||
],
|
||||
providers: []
|
||||
})
|
||||
@ -204,6 +213,7 @@ export class HarborLibraryModule {
|
||||
config.scanningService || { provide: ScanningResultService, useClass: ScanningResultDefaultService },
|
||||
config.configService || { provide: ConfigurationService, useClass: ConfigurationDefaultService },
|
||||
config.jobLogService || { provide: JobLogService, useClass: JobLogDefaultService },
|
||||
config.projectPolicyService || { provide: ProjectService, useClass: ProjectDefaultService },
|
||||
//Do initializing
|
||||
TranslateServiceInitializer,
|
||||
{
|
||||
@ -232,6 +242,7 @@ export class HarborLibraryModule {
|
||||
config.scanningService || { provide: ScanningResultService, useClass: ScanningResultDefaultService },
|
||||
config.configService || { provide: ConfigurationService, useClass: ConfigurationDefaultService },
|
||||
config.jobLogService || { provide: JobLogService, useClass: JobLogDefaultService },
|
||||
config.projectPolicyService || { provide: ProjectService, useClass: ProjectDefaultService },
|
||||
ChannelService
|
||||
]
|
||||
};
|
||||
|
@ -17,4 +17,5 @@ export * from './push-image/index';
|
||||
export * from './third-party/index';
|
||||
export * from './config/index';
|
||||
export * from './job-log-viewer/index';
|
||||
export * from './channel/index';
|
||||
export * from './channel/index';
|
||||
export * from './project-policy-config/index';
|
||||
|
8
src/ui_ng/lib/src/project-policy-config/index.ts
Normal file
8
src/ui_ng/lib/src/project-policy-config/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { Type } from '@angular/core';
|
||||
import { ProjectPolicyConfigComponent } from './project-policy-config.component';
|
||||
|
||||
export * from './project-policy-config.component'
|
||||
|
||||
export const PROJECT_POLICY_CONFIG_DIRECTIVES: Type<any>[] = [
|
||||
ProjectPolicyConfigComponent
|
||||
];
|
@ -0,0 +1,9 @@
|
||||
export const PROJECT_POLICY_CONFIG_STYLE = `#severity-blk div
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.select {
|
||||
width: 120px;
|
||||
}
|
||||
`;
|
@ -0,0 +1,51 @@
|
||||
export const PROJECT_POLICY_CONFIG_TEMPLATE = `
|
||||
<form #projectPolicyForm="ngForm">
|
||||
<section class="form-block">
|
||||
<div class="form-group">
|
||||
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.REGISTRY' | translate }}</label>
|
||||
<div class="form-content">
|
||||
<clr-checkbox [(ngModel)]="projectPolicy.Public" name="public"
|
||||
[clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.PUBLIC_TOGGLE' | translate }}</clr-checkbox>
|
||||
<div>
|
||||
<label> {{ 'PROJECT_CONFIG.PUBLIC_POLICY' | translate }} </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.SECURITY' | translate }}</label>
|
||||
<div class="form-content">
|
||||
<div>
|
||||
<clr-checkbox [(ngModel)]="projectPolicy.ContentTrust" name="content-trust"
|
||||
[clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.CONTENT_TRUST_TOGGLE' | translate }}</clr-checkbox>
|
||||
<div class="chk-explain"><label> {{ 'PROJECT_CONFIG.CONTENT_TRUST_POLCIY' | translate }} </label></div>
|
||||
</div>
|
||||
<div>
|
||||
<clr-checkbox [(ngModel)]="projectPolicy.PreventVulImg" name="prevent-vulenrability-image" [clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_TOGGLE' | translate }}</clr-checkbox>
|
||||
<div class="chk-explain">
|
||||
<label>
|
||||
<div id="severity-blk">
|
||||
<div>{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_1' | translate }}</div>
|
||||
<div class="select">
|
||||
<select id="severity" name="severity" [(ngModel)]="projectPolicy.PreventVulImgServerity" [disabled]="!projectPolicy.PreventVulImg">
|
||||
<option *ngFor='let s of severityOptions' [ngValue]="s.severity">{{ s.severityLevel | translate | uppercase }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div> {{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_2' | translate }} </div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.SCAN' | translate }}</label>
|
||||
<div class="form-content">
|
||||
<clr-checkbox [(ngModel)]="projectPolicy.ScanImgOnPush" name="scan-image-on-push" [clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.AUTOSCAN_TOGGLE' | translate }}</clr-checkbox>
|
||||
<div class="chk-explain"><label> {{ 'PROJECT_CONFIG.AUTOSCAN_POLICY' | translate }}</label></div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" (click)="save()" [disabled]="!isValid() || !hasChanges() || !hasProjectAdminRole">{{'BUTTON.SAVE' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="!isValid() || !hasChanges() || !hasProjectAdminRole">{{'BUTTON.CANCEL' | translate}}</button>
|
||||
<confirmation-dialog #cfgConfirmationDialog (confirmAction)="confirmCancel($event)"></confirmation-dialog>
|
||||
</section>
|
||||
</form>`;
|
@ -0,0 +1,45 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ErrorHandler } from '../error-handler/error-handler';
|
||||
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
|
||||
import { ProjectPolicyConfigComponent } from './project-policy-config.component';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { ProjectService, ProjectDefaultService} from '../service/project.service';
|
||||
import { SERVICE_CONFIG, IServiceConfig} from '../service.config';
|
||||
|
||||
describe('ProjectPolicyConfigComponent', () => {
|
||||
let component: ProjectPolicyConfigComponent;
|
||||
let fixture: ComponentFixture<ProjectPolicyConfigComponent>;
|
||||
|
||||
let config: IServiceConfig = {
|
||||
projectPolicyEndpoint: '/api/projects/testing/:id/'
|
||||
};
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [SharedModule],
|
||||
declarations: [
|
||||
ProjectPolicyConfigComponent,
|
||||
ConfirmationDialogComponent,
|
||||
ConfirmationDialogComponent,
|
||||
],
|
||||
providers: [
|
||||
ErrorHandler,
|
||||
{ provide: SERVICE_CONFIG, useValue: config },
|
||||
{ provide: ProjectService, useClass: ProjectDefaultService }
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProjectPolicyConfigComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.projectId = 1;
|
||||
component.hasProjectAdminRole = true;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,155 @@
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
|
||||
import { PROJECT_POLICY_CONFIG_TEMPLATE } from './project-policy-config.component.html';
|
||||
import { PROJECT_POLICY_CONFIG_STYLE } from './project-policy-config.component.css';
|
||||
import { toPromise, compareValue, clone } from '../utils';
|
||||
import { ProjectService } from '../service/project.service';
|
||||
import { ErrorHandler } from '../error-handler/error-handler';
|
||||
import { State } from 'clarity-angular';
|
||||
|
||||
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../shared/shared.const';
|
||||
import { ConfirmationMessage } from '../confirmation-dialog/confirmation-message';
|
||||
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
|
||||
import { ConfirmationAcknowledgement } from '../confirmation-dialog/confirmation-state-message';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { Project } from './project';
|
||||
|
||||
export class ProjectPolicy {
|
||||
Public: boolean;
|
||||
ContentTrust: boolean;
|
||||
PreventVulImg: boolean;
|
||||
PreventVulImgServerity: string;
|
||||
ScanImgOnPush: boolean;
|
||||
|
||||
constructor() {
|
||||
this.Public = false;
|
||||
this.ContentTrust = false;
|
||||
this.PreventVulImg = false;
|
||||
this.PreventVulImgServerity = 'low';
|
||||
this.ScanImgOnPush = false;
|
||||
}
|
||||
|
||||
initByProject(pro: Project) {
|
||||
this.Public = pro.metadata.public === 'true' ? true : false;
|
||||
this.ContentTrust = pro.metadata.enable_content_trust === 'true' ? true : false;
|
||||
this.PreventVulImg = pro.metadata.prevent_vul === 'true' ? true : false;
|
||||
if (pro.metadata.severity) { this.PreventVulImgServerity = pro.metadata.severity; };
|
||||
this.ScanImgOnPush = pro.metadata.auto_scan === 'true' ? true : false;
|
||||
};
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-project-policy-config',
|
||||
template: PROJECT_POLICY_CONFIG_TEMPLATE,
|
||||
styles: [PROJECT_POLICY_CONFIG_STYLE]
|
||||
})
|
||||
export class ProjectPolicyConfigComponent implements OnInit {
|
||||
onGoing = false;
|
||||
@Input() projectId: number;
|
||||
@Input() projectName = 'unknown';
|
||||
|
||||
@Input() hasSignedIn: boolean;
|
||||
@Input() hasProjectAdminRole: boolean;
|
||||
|
||||
@ViewChild('cfgConfirmationDialog') confirmationDlg: ConfirmationDialogComponent;
|
||||
|
||||
orgProjectPolicy = new ProjectPolicy();
|
||||
projectPolicy = new ProjectPolicy();
|
||||
|
||||
severityOptions = [
|
||||
{severity: 'high', severityLevel: 'VULNERABILITY.SEVERITY.HIGH'},
|
||||
{severity: 'medium', severityLevel: 'VULNERABILITY.SEVERITY.MEDIUM'},
|
||||
{severity: 'low', severityLevel: 'VULNERABILITY.SEVERITY.LOW'},
|
||||
{severity: 'negligible', severityLevel: 'VULNERABILITY.SEVERITY.NEGLIGIBLE'},
|
||||
];
|
||||
|
||||
constructor(
|
||||
private errorHandler: ErrorHandler,
|
||||
private translate: TranslateService,
|
||||
private projectService: ProjectService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.projectId) {
|
||||
this.errorHandler.error('Project ID cannot be unset.');
|
||||
return;
|
||||
}
|
||||
this.retrieve();
|
||||
}
|
||||
|
||||
retrieve(state?: State): any {
|
||||
toPromise<Project>(this.projectService.
|
||||
getProject(this.projectId))
|
||||
.then(
|
||||
response => {
|
||||
this.orgProjectPolicy.initByProject(response);
|
||||
this.projectPolicy.initByProject(response);
|
||||
},
|
||||
error => this.errorHandler.error(error)
|
||||
);
|
||||
}
|
||||
|
||||
updateProjectPolicy(projectId: string|number, pp: ProjectPolicy) {
|
||||
this.projectService.updateProjectPolicy(projectId, pp);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.retrieve();
|
||||
}
|
||||
|
||||
isValid() {
|
||||
let flag = false;
|
||||
if (!this.projectPolicy.PreventVulImg || this.severityOptions.some(x => x.severity === this.projectPolicy.PreventVulImgServerity)) {
|
||||
flag = true;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
hasChanges() {
|
||||
return compareValue(this.orgProjectPolicy, this.projectPolicy)
|
||||
}
|
||||
|
||||
save() {
|
||||
if (!this.hasChanges()) {
|
||||
return;
|
||||
}
|
||||
this.onGoing = true;
|
||||
toPromise<any>(this.projectService.updateProjectPolicy(this.projectId, this.projectPolicy))
|
||||
.then(() => {
|
||||
this.onGoing = false;
|
||||
|
||||
this.translate.get('CONFIG.SAVE_SUCCESS').subscribe((res: string) => {
|
||||
this.errorHandler.info(res);
|
||||
});
|
||||
this.refresh();
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
this.onGoing = false;
|
||||
this.errorHandler.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
let msg = new ConfirmationMessage(
|
||||
'CONFIG.CONFIRM_TITLE',
|
||||
'CONFIG.CONFIRM_SUMMARY',
|
||||
'',
|
||||
{},
|
||||
ConfirmationTargets.CONFIG
|
||||
);
|
||||
this.confirmationDlg.open(msg);
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.projectPolicy = clone(this.orgProjectPolicy);
|
||||
}
|
||||
|
||||
confirmCancel(ack: ConfirmationAcknowledgement): void {
|
||||
if (ack && ack.source === ConfirmationTargets.CONFIG &&
|
||||
ack.state === ConfirmationState.CONFIRMED) {
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
}
|
30
src/ui_ng/lib/src/project-policy-config/project.ts
Normal file
30
src/ui_ng/lib/src/project-policy-config/project.ts
Normal file
@ -0,0 +1,30 @@
|
||||
export class Project {
|
||||
project_id: number;
|
||||
owner_id: number;
|
||||
name: string;
|
||||
creation_time: Date;
|
||||
creation_time_str: string;
|
||||
deleted: number;
|
||||
owner_name: string;
|
||||
togglable: boolean;
|
||||
update_time: Date;
|
||||
current_user_role_id: number;
|
||||
repo_count: number;
|
||||
has_project_admin_role: boolean;
|
||||
is_member: boolean;
|
||||
role_name: string;
|
||||
metadata: {
|
||||
public: string | boolean;
|
||||
enable_content_trust: string | boolean;
|
||||
prevent_vul: string | boolean;
|
||||
severity: string;
|
||||
auto_scan: string | boolean;
|
||||
};
|
||||
constructor () {
|
||||
this.metadata.public = false;
|
||||
this.metadata.enable_content_trust = false;
|
||||
this.metadata.prevent_vul = false;
|
||||
this.metadata.severity = 'low';
|
||||
this.metadata.auto_scan = false;
|
||||
}
|
||||
}
|
@ -80,6 +80,14 @@ export interface IServiceConfig {
|
||||
*/
|
||||
vulnerabilityScanningBaseEndpoint?: string;
|
||||
|
||||
/**
|
||||
* The base endpoint of the service used to handle project policy.
|
||||
*
|
||||
* @type {string}
|
||||
* @memberOf IServiceConfig
|
||||
*/
|
||||
projectPolicyEndpoint?: string;
|
||||
|
||||
/**
|
||||
* To determine whether or not to enable the i18 multiple languages supporting.
|
||||
*
|
||||
|
@ -8,4 +8,5 @@ export * from './tag.service';
|
||||
export * from './RequestQueryParams';
|
||||
export * from './scanning.service';
|
||||
export * from './configuration.service';
|
||||
export * from './job-log.service';
|
||||
export * from './job-log.service';
|
||||
export * from './project.service';
|
||||
|
@ -242,4 +242,4 @@ export interface TagClickEvent {
|
||||
project_id: string | number;
|
||||
repository_name: string;
|
||||
tag_name: string;
|
||||
}
|
||||
}
|
||||
|
85
src/ui_ng/lib/src/service/project.service.ts
Normal file
85
src/ui_ng/lib/src/service/project.service.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Injectable, Inject } from '@angular/core';
|
||||
import 'rxjs/add/observable/of';
|
||||
import { Http, Headers, RequestOptions } from '@angular/http';
|
||||
import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
|
||||
|
||||
import { Project } from '../project-policy-config/project';
|
||||
import { ProjectPolicy } from '../project-policy-config/project-policy-config.component';
|
||||
|
||||
/**
|
||||
* Define the service methods to handle the Prject related things.
|
||||
*
|
||||
* @export
|
||||
* @abstract
|
||||
* @class ProjectService
|
||||
*/
|
||||
export abstract class ProjectService {
|
||||
/**
|
||||
* Get Infomations of a specific Project.
|
||||
*
|
||||
* @abstract
|
||||
* @param {string|number} [projectId]
|
||||
* @returns {(Observable<Project> | Promise<Project> | Project)}
|
||||
*
|
||||
* @memberOf ProjectService
|
||||
*/
|
||||
abstract getProject(projectId: number | string): Observable<Project> | Promise<Project> | Project;
|
||||
|
||||
/**
|
||||
* Update the specified project.
|
||||
*
|
||||
* @abstract
|
||||
* @param {(number | string)} projectId
|
||||
* @param {ProjectPolicy} projectPolicy
|
||||
* @returns {(Observable<any> | Promise<any> | any)}
|
||||
*
|
||||
* @memberOf EndpointService
|
||||
*/
|
||||
abstract updateProjectPolicy(projectId: number | string, projectPolicy: ProjectPolicy): Observable<any> | Promise<any> | any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement default service for project.
|
||||
*
|
||||
* @export
|
||||
* @class ProjectDefaultService
|
||||
* @extends {ProjectService}
|
||||
*/
|
||||
@Injectable()
|
||||
export class ProjectDefaultService extends ProjectService {
|
||||
|
||||
headers = new Headers({'Content-type': 'application/json'});
|
||||
options = new RequestOptions({'headers': this.headers});
|
||||
|
||||
constructor(
|
||||
private http: Http,
|
||||
@Inject(SERVICE_CONFIG) private config: IServiceConfig
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public getProject(projectId: number | string): Observable<Project> | Promise<Project> | Project {
|
||||
if (!projectId) {
|
||||
return Promise.reject('Bad argument');
|
||||
}
|
||||
|
||||
return this.http
|
||||
.get(`/api/projects/${projectId}`)
|
||||
.map(response => response.json())
|
||||
.catch(error => Observable.throw(error));
|
||||
}
|
||||
|
||||
public updateProjectPolicy(projectId: number | string, projectPolicy: ProjectPolicy): any {
|
||||
return this.http
|
||||
.put(`/api/projects/${projectId}`, { 'metadata': {
|
||||
'public': projectPolicy.Public ? 'true' : 'false',
|
||||
'enable_content_trust': projectPolicy.ContentTrust ? 'true' : 'false',
|
||||
'prevent_vul': projectPolicy.PreventVulImg ? 'true' : 'false',
|
||||
'severity': projectPolicy.PreventVulImgServerity,
|
||||
'auto_scan': projectPolicy.ScanImgOnPush ? 'true' : 'false'
|
||||
} }, this.options)
|
||||
.map(response => response.status)
|
||||
.catch(error => Observable.throw(error));
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@
|
||||
"clarity-icons": "^0.9.8",
|
||||
"clarity-ui": "^0.9.8",
|
||||
"core-js": "^2.4.1",
|
||||
"harbor-ui": "0.4.85",
|
||||
"harbor-ui": "0.4.91",
|
||||
"intl": "^1.2.5",
|
||||
"mutationobserver-shim": "^0.3.2",
|
||||
"ngx-cookie": "^1.0.0",
|
||||
|
@ -24,6 +24,7 @@ import { ConfigurationModule } from './config/config.module';
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { AppConfigService } from './app-config.service';
|
||||
import {SkinableConfig} from "./skinable-config.service";
|
||||
import { ProjectConfigComponent } from './project/project-config/project-config.component';
|
||||
|
||||
export function initConfig(configService: AppConfigService, skinableService: SkinableConfig) {
|
||||
return () => {
|
||||
@ -39,6 +40,7 @@ export function getCurrentLanguage(translateService: TranslateService) {
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
ProjectConfigComponent,
|
||||
],
|
||||
imports: [
|
||||
SharedModule,
|
||||
@ -49,10 +51,10 @@ export function getCurrentLanguage(translateService: TranslateService) {
|
||||
],
|
||||
providers: [
|
||||
AppConfigService,
|
||||
SkinableConfig,
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: initConfig,
|
||||
SkinableConfig,
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: initConfig,
|
||||
deps: [ AppConfigService, SkinableConfig],
|
||||
multi: true
|
||||
},
|
||||
|
@ -31,6 +31,7 @@ import { TagRepositoryComponent } from './repository/tag-repository/tag-reposito
|
||||
import { ReplicationPageComponent } from './replication/replication-page.component';
|
||||
import { MemberComponent } from './project/member/member.component';
|
||||
import { AuditLogComponent } from './log/audit-log.component';
|
||||
import { ProjectConfigComponent } from './project/project-config/project-config.component'
|
||||
|
||||
import { ProjectRoutingResolver } from './project/project-routing-resolver.service';
|
||||
import { SystemAdminGuard } from './shared/route/system-admin-activate.service';
|
||||
@ -133,6 +134,10 @@ const harborRoutes: Routes = [
|
||||
{
|
||||
path: 'logs',
|
||||
component: AuditLogComponent
|
||||
},
|
||||
{
|
||||
path: 'configs',
|
||||
component: ProjectConfigComponent
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -0,0 +1,5 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12" style="top: 8px;">
|
||||
<hbr-project-policy-config [projectId]="projectId" [projectName]="projectName" [hasSignedIn]="hasSignedIn" [hasProjectAdminRole]="hasProjectAdminRole"></hbr-project-policy-config>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProjectConfigComponent } from './project-config.component';
|
||||
|
||||
describe('ProjectConfigPageComponent', () => {
|
||||
let component: ProjectConfigComponent;
|
||||
let fixture: ComponentFixture<ProjectConfigComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ProjectConfigComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProjectConfigComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { SessionService } from '../../shared/session.service';
|
||||
import { SessionUser } from '../../shared/session-user';
|
||||
import { Project } from '../project';
|
||||
|
||||
@Component({
|
||||
selector: 'app-project-config',
|
||||
templateUrl: './project-config.component.html',
|
||||
styleUrls: ['./project-config.component.css']
|
||||
})
|
||||
export class ProjectConfigComponent implements OnInit {
|
||||
|
||||
projectId: number;
|
||||
projectName: string;
|
||||
currentUser: SessionUser;
|
||||
hasSignedIn: boolean;
|
||||
hasProjectAdminRole: boolean;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private session: SessionService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.projectId = +this.route.snapshot.parent.params['id'];
|
||||
this.currentUser = this.session.getCurrentUser();
|
||||
this.hasSignedIn = this.session.getCurrentUser() !== null;
|
||||
let resolverData = this.route.snapshot.parent.data;
|
||||
if (resolverData) {
|
||||
let pro: Project = <Project>resolverData['projectResolver'];
|
||||
this.hasProjectAdminRole = pro.has_project_admin_role;
|
||||
this.projectName = pro.name;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,9 @@
|
||||
<li class="nav-item" *ngIf="isSessionValid && isSystemAdmin">
|
||||
<a class="nav-link" routerLink="replications" routerLinkActive="active">{{'PROJECT_DETAIL.REPLICATION' | translate}}</a>
|
||||
</li>
|
||||
<li class="nav-item" *ngIf="isSessionValid && isSystemAdmin">
|
||||
<a class="nav-link" routerLink="configs" routerLinkActive="active">{{'PROJECT_DETAIL.CONFIG' | translate}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<router-outlet></router-outlet>
|
@ -23,14 +23,14 @@ import { RoleMapping } from '../../shared/shared.const';
|
||||
|
||||
@Component({
|
||||
selector: 'project-detail',
|
||||
templateUrl: "project-detail.component.html",
|
||||
templateUrl: 'project-detail.component.html',
|
||||
styleUrls: [ 'project-detail.component.css' ]
|
||||
})
|
||||
export class ProjectDetailComponent {
|
||||
|
||||
hasSignedIn: boolean;
|
||||
currentProject: Project;
|
||||
|
||||
|
||||
isMember: boolean;
|
||||
roleName: string;
|
||||
|
||||
@ -41,7 +41,7 @@ export class ProjectDetailComponent {
|
||||
private projectService: ProjectService) {
|
||||
|
||||
this.hasSignedIn = this.sessionService.getCurrentUser() !== null;
|
||||
this.route.data.subscribe(data=>{
|
||||
this.route.data.subscribe(data => {
|
||||
this.currentProject = <Project>data['projectResolver'];
|
||||
this.isMember = this.currentProject.is_member;
|
||||
this.roleName = RoleMapping[this.currentProject.role_name];
|
||||
|
@ -161,7 +161,22 @@
|
||||
"REPLICATION": "Replication",
|
||||
"USERS": "Members",
|
||||
"LOGS": "Logs",
|
||||
"PROJECTS": "Projects"
|
||||
"PROJECTS": "Projects",
|
||||
"CONFIG": "Configuration"
|
||||
},
|
||||
"PROJECT_CONFIG": {
|
||||
"REGISTRY": "Project registry",
|
||||
"PUBLIC_TOGGLE": "Public",
|
||||
"PUBLIC_POLICY": "Making a project registry public will make all repositories accessible to everyone.",
|
||||
"SECURITY": "Deployment security",
|
||||
"CONTENT_TRUST_TOGGLE": "Enable content trust",
|
||||
"CONTENT_TRUST_POLCIY": "Only allow verified images to be deployed.",
|
||||
"PREVENT_VULNERABLE_TOGGLE": "Prevent vulnerable images from running.",
|
||||
"PREVENT_VULNERABLE_1": "Prevent images with vulnerability serverity of",
|
||||
"PREVENT_VULNERABLE_2": "and above from being deployed.",
|
||||
"SCAN": "Vulnerability scanning",
|
||||
"AUTOSCAN_TOGGLE": "Automatically scan images on push",
|
||||
"AUTOSCAN_POLICY": "Automatically scan images when they are pushed to the project registry."
|
||||
},
|
||||
"MEMBER": {
|
||||
"NEW_MEMBER": "New Member",
|
||||
|
@ -161,7 +161,22 @@
|
||||
"REPLICATION": "Replicación",
|
||||
"USERS": "Miembros",
|
||||
"LOGS": "Logs",
|
||||
"PROJECTS": "Proyectos"
|
||||
"PROJECTS": "Proyectos",
|
||||
"CONFIG": "Configuración"
|
||||
},
|
||||
"PROJECT_CONFIG": {
|
||||
"REGISTRY": "Registro de proyectos",
|
||||
"PUBLIC_TOGGLE": "Público",
|
||||
"PUBLIC_POLICY": "Hacer público un registro de proyecto hará que todos los repositorios sean accesibles para todos.",
|
||||
"SECURITY": "Seguridad de despliegue",
|
||||
"CONTENT_TRUST_TOGGLE": "Habilitar la confianza de contenido",
|
||||
"CONTENT_TRUST_POLCIY": "Solo permita la implementación de imágenes verificadas.",
|
||||
"PREVENT_VULNERABLE_TOGGLE": "Evitar que se ejecuten imágenes vulnerables.",
|
||||
"PREVENT_VULNERABLE_1": "Impedir imágenes con la gravedad de la vulnerabilidad de",
|
||||
"PREVENT_VULNERABLE_2": "y más arriba de ser desplegado.",
|
||||
"SCAN": "Escaneo de vulnerabilidad",
|
||||
"AUTOSCAN_TOGGLE": "Escanee automáticamente las imágenes al instante",
|
||||
"AUTOSCAN_POLICY": "Escanee automáticamente las imágenes cuando son enviadas al registro del proyecto."
|
||||
},
|
||||
"MEMBER": {
|
||||
"NEW_MEMBER": "Nuevo miembro",
|
||||
|
@ -161,7 +161,22 @@
|
||||
"REPLICATION": "复制",
|
||||
"USERS": "成员",
|
||||
"LOGS": "日志",
|
||||
"PROJECTS": "项目"
|
||||
"PROJECTS": "项目",
|
||||
"CONFIG": "配置管理"
|
||||
},
|
||||
"PROJECT_CONFIG": {
|
||||
"REGISTRY": "项目仓库",
|
||||
"PUBLIC_TOGGLE": "公开",
|
||||
"PUBLIC_POLICY": "此项目的仓库对所有访客公开。",
|
||||
"SECURITY": "部署安全",
|
||||
"CONTENT_TRUST_TOGGLE": "内容信任",
|
||||
"CONTENT_TRUST_POLCIY": "仅允许部署通过认证的镜像。",
|
||||
"PREVENT_VULNERABLE_TOGGLE": "阻止潜在漏洞镜像",
|
||||
"PREVENT_VULNERABLE_1": "阻止危害级别",
|
||||
"PREVENT_VULNERABLE_2": "以上的镜像运行。",
|
||||
"SCAN": "漏洞扫描",
|
||||
"AUTOSCAN_TOGGLE": "自动扫描镜像",
|
||||
"AUTOSCAN_POLICY": "当镜像上传后,自动进行扫描"
|
||||
},
|
||||
"MEMBER": {
|
||||
"NEW_MEMBER": "新建成员",
|
||||
|
Loading…
Reference in New Issue
Block a user