diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.html
index 046a9c16d..b994abfc7 100644
--- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.html
+++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.html
@@ -1,5 +1,5 @@
-
+
-
+
+
+
+
{{repoName}}
+ {{artifactDigest | slice:0:15}}
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.spec.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.spec.ts
index 175086d35..4d7311124 100644
--- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.spec.ts
+++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.spec.ts
@@ -1,39 +1,13 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ArtifactListPageComponent } from './artifact-list-page.component';
-import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { of } from 'rxjs';
-import { ActivatedRoute, Router } from '@angular/router';
-import { SessionService } from "../../../../../shared/services/session.service";
-import { AppConfigService } from "../../../../../services/app-config.service";
-import { ArtifactService } from "../artifact.service";
+import { ActivatedRoute } from '@angular/router';
import { SharedTestingModule } from "../../../../../shared/shared.module";
+import { ArtifactListPageService } from './artifact-list-page.service';
describe('ArtifactListPageComponent', () => {
let component: ArtifactListPageComponent;
let fixture: ComponentFixture
;
- const mockSessionService = {
- getCurrentUser: () => { }
- };
- const mockAppConfigService = {
- getConfig: () => {
- return {
- project_creation_restriction: "",
- with_chartmuseum: "",
- with_notary: "",
- with_trivy: "",
- with_admiral: "",
- registry_url: "",
- };
- }
- };
- const mockRouter = {
- navigate: () => { }
- };
- const mockArtifactService = {
- triggerUploadArtifact: {
- next: () => {}
- }
- };
const mockActivatedRoute = {
RouterparamMap: of({ get: (key) => 'value' }),
snapshot: {
@@ -65,19 +39,13 @@ describe('ArtifactListPageComponent', () => {
};
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
- schemas: [
- CUSTOM_ELEMENTS_SCHEMA
- ],
imports: [
SharedTestingModule
],
declarations: [ArtifactListPageComponent],
providers: [
- { provide: SessionService, useValue: mockSessionService },
- { provide: AppConfigService, useValue: mockAppConfigService },
- { provide: Router, useValue: mockRouter },
+ ArtifactListPageService,
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
- { provide: ArtifactService, useValue: mockArtifactService },
]
})
.compileComponents();
@@ -92,4 +60,10 @@ describe('ArtifactListPageComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
+
+ it('should have two tabs', async () => {
+ await fixture.whenStable();
+ const tabs = fixture.nativeElement.querySelectorAll('.nav-item');
+ expect(tabs.length).toEqual(2);
+ });
});
diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.ts
index 70d4dc941..081ef1d55 100644
--- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.ts
+++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.component.ts
@@ -11,13 +11,10 @@
// 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, ViewChild } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
-import { ArtifactListComponent } from "./artifact-list/artifact-list.component";
-import { ArtifactService } from "../artifact.service";
-import { AppConfigService } from "../../../../../services/app-config.service";
-import { SessionService } from "../../../../../shared/services/session.service";
import { Project } from "../../../project";
+import { ArtifactListPageService } from "./artifact-list-page.service";
@Component({
selector: 'artifact-list-page',
@@ -26,29 +23,25 @@ import { Project } from "../../../project";
})
export class ArtifactListPageComponent implements OnInit {
- projectId: number;
+ projectId: string;
projectName: string;
- projectMemberRoleId: number;
repoName: string;
referArtifactNameArray: string[] = [];
- hasProjectAdminRole: boolean = false;
- isGuest: boolean;
- registryUrl: string;
-
- @ViewChild(ArtifactListComponent)
- repositoryComponent: ArtifactListComponent;
depth: string;
+ artifactDigest: string;
constructor(
private route: ActivatedRoute,
private router: Router,
- private artifactService: ArtifactService,
- private appConfigService: AppConfigService,
- private session: SessionService) {
+ private artifactListPageService: ArtifactListPageService) {
this.route.params.subscribe(params => {
this.depth = this.route.snapshot.params['depth'];
if (this.depth) {
const arr: string[] = this.depth.split('-');
this.referArtifactNameArray = arr.slice(0, arr.length - 1);
+ this.artifactDigest = this.depth.split('-')[arr.length - 1];
+ } else {
+ this.referArtifactNameArray = [];
+ this.artifactDigest = null;
}
});
}
@@ -58,28 +51,11 @@ export class ArtifactListPageComponent implements OnInit {
let resolverData = this.route.snapshot.parent.data;
if (resolverData) {
this.projectName = (resolverData['projectResolver']).name;
- this.hasProjectAdminRole = (resolverData['projectResolver']).has_project_admin_role;
- this.isGuest = (resolverData['projectResolver']).current_user_role_id === 3;
- this.projectMemberRoleId = (resolverData['projectResolver']).current_user_role_id;
}
this.repoName = this.route.snapshot.params['repo'];
- this.registryUrl = this.appConfigService.getConfig().registry_url;
+ this.artifactListPageService.init(+this.projectId);
}
- get withNotary(): boolean {
- return this.appConfigService.getConfig().with_notary;
- }
- get withAdmiral(): boolean {
- return this.appConfigService.getConfig().with_admiral;
- }
-
- get hasSignedIn(): boolean {
- return this.session.getCurrentUser() !== null;
- }
-
- hasChanges(): boolean {
- return this.repositoryComponent.hasChanges();
- }
watchGoBackEvt(projectId: string| number): void {
this.router.navigate(["harbor", "projects", projectId, "repositories"]);
}
@@ -92,7 +68,7 @@ export class ArtifactListPageComponent implements OnInit {
jumpDigest(index: number) {
const arr: string[] = this.referArtifactNameArray.slice(0, index + 1 );
if ( arr && arr.length) {
- this.router.navigate(["harbor", "projects", this.projectId, "repositories", this.repoName, "depth", arr.join('-')]);
+ this.router.navigate(["harbor", "projects", this.projectId, "repositories", this.repoName, "artifacts-tab", "depth", arr.join('-')]);
} else {
this.router.navigate(["harbor", "projects", this.projectId, "repositories", this.repoName]);
}
diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.spec.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.spec.ts
new file mode 100644
index 000000000..64591f23a
--- /dev/null
+++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.spec.ts
@@ -0,0 +1,21 @@
+import { inject, TestBed } from '@angular/core/testing';
+import { ArtifactListPageService } from './artifact-list-page.service';
+import { SharedTestingModule } from '../../../../../shared/shared.module';
+
+describe('ArtifactListPageService', () => {
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ SharedTestingModule,
+ ],
+ providers: [
+ ArtifactListPageService
+ ]
+ });
+ });
+
+ it('should be initialized', inject([ArtifactListPageService], (service: ArtifactListPageService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.ts
new file mode 100644
index 000000000..2d9d74ba8
--- /dev/null
+++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.ts
@@ -0,0 +1,184 @@
+import { Injectable } from "@angular/core";
+import { ClrLoadingState } from "@clr/angular";
+import { ScanningResultService, UserPermissionService, USERSTATICPERMISSION } from "../../../../../shared/services";
+import { LabelState } from "./artifact-list/artifact-list-tab/artifact-list-tab.component";
+import { forkJoin, Observable } from "rxjs";
+import { LabelService } from "ng-swagger-gen/services/label.service";
+import { Label } from "ng-swagger-gen/models/label";
+import { ErrorHandler } from "../../../../../shared/units/error-handler";
+import { clone } from "../../../../../shared/units/utils";
+
+const PAGE_SIZE: number = 100;
+
+@Injectable()
+export class ArtifactListPageService {
+ private _scanBtnState: ClrLoadingState;
+ private _allLabels: LabelState[] = [];
+ imageStickLabels: LabelState[] = [];
+ imageFilterLabels: LabelState[] = [];
+ private _hasEnabledScanner: boolean = false;
+ private _hasAddLabelImagePermission: boolean = false;
+ private _hasRetagImagePermission: boolean = false;
+ private _hasDeleteImagePermission: boolean = false;
+ private _hasScanImagePermission: boolean = false;
+
+ constructor(private scanningService: ScanningResultService,
+ private labelService: LabelService,
+ private userPermissionService: UserPermissionService,
+ private errorHandlerService: ErrorHandler) {
+
+ }
+ resetClonedLabels() {
+ this.imageStickLabels = clone(this._allLabels);
+ this.imageFilterLabels = clone(this._allLabels);
+ }
+ getScanBtnState(): ClrLoadingState {
+ return this._scanBtnState;
+ }
+
+ hasEnabledScanner(): boolean {
+ return this._hasEnabledScanner;
+ }
+
+ hasAddLabelImagePermission(): boolean {
+ return this._hasAddLabelImagePermission;
+ }
+
+ hasRetagImagePermission(): boolean {
+ return this._hasRetagImagePermission;
+ }
+
+ hasDeleteImagePermission(): boolean {
+ return this._hasDeleteImagePermission;
+ }
+
+ hasScanImagePermission(): boolean {
+ return this._hasScanImagePermission;
+ }
+
+ init(projectId: number) {
+ this._getProjectScanner(projectId);
+ this._getPermissionRule(projectId);
+ }
+
+ private _getProjectScanner(projectId: number): void {
+ this._hasEnabledScanner = false;
+ this._scanBtnState = ClrLoadingState.LOADING;
+ this.scanningService.getProjectScanner(projectId)
+ .subscribe(response => {
+ if (response && "{}" !== JSON.stringify(response) && !response.disabled
+ && response.health === "healthy") {
+ this._scanBtnState = ClrLoadingState.SUCCESS;
+ this._hasEnabledScanner = true;
+ } else {
+ this._scanBtnState = ClrLoadingState.ERROR;
+ }
+ }, error => {
+ this._scanBtnState = ClrLoadingState.ERROR;
+ });
+ }
+
+ private _getAllLabels(projectId: number): void {
+ // get all project labels
+ this.labelService.ListLabelsResponse({
+ pageSize: PAGE_SIZE,
+ page: 1,
+ scope: 'p',
+ projectId: projectId
+ }).subscribe(res => {
+ if (res.headers) {
+ const xHeader: string = res.headers.get("X-Total-Count");
+ const totalCount = parseInt(xHeader, 0);
+ let arr = res.body || [];
+ if (totalCount <= PAGE_SIZE) { // already gotten all project labels
+ if (arr && arr.length) {
+ arr.forEach(data => {
+ this._allLabels.push({'iconsShow': false, 'label': data, 'show': true});
+ });
+ this.resetClonedLabels();
+ }
+ } else { // get all the project labels in specified times
+ const times: number = Math.ceil(totalCount / PAGE_SIZE);
+ const observableList: Observable