Refactor UI routing and remove redundant code (#14166)

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Will Sun 2021-02-18 09:12:23 +08:00 committed by GitHub
parent 51c8375425
commit 2d84b62fe2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
796 changed files with 4041 additions and 7447 deletions

View File

@ -0,0 +1,17 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.

View File

@ -2,4 +2,100 @@
Harbor UI Harbor UI
============ ============
This is the project based on Clarity and Angular to build Harbor UI. This is the project based on Clarity and Angular to build Harbor UI.
Start
============
1. npm install (should trigger 'npm postinstall')
2. npm run postinstall (if not triggered, manually run this step)
3. create "proxy.config.json" file with below content under "portal" directory, and replace "hostname" with an available Harbor hostname
4. npm run start
5. open your browser on https://localhost:4200
```json
{
"/api/*": {
"target": "https://hostname",
"secure": false,
"changeOrigin": true,
"logLevel": "debug"
},
"/service/*": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/c/login": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/c/oidc/login": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/sign_in": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/c/log_out": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/sendEmail": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/language": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/reset": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/c/userExists": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/reset_password": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/i18n/lang/*.json": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug",
"pathRewrite": { "^/src$": "" }
},
"/swagger.json": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/swagger2.json": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/chartrepo/*": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
},
"/LICENSE": {
"target": "https://hostname",
"secure": false,
"logLevel": "debug"
}
}
```

View File

@ -11,10 +11,15 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"allowedCommonJsDependencies": [
"swagger-ui",
"js-yaml"
],
"outputPath": "dist", "outputPath": "dist",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"extractCss": true, "extractCss": true,
"assets": [ "assets": [
"src/images", "src/images",
@ -31,12 +36,12 @@
{ {
"input": "src/css/dark-theme.scss", "input": "src/css/dark-theme.scss",
"bundleName": "dark-theme", "bundleName": "dark-theme",
"lazy": true "inject": false
}, },
{ {
"input": "src/css/light-theme.scss", "input": "src/css/light-theme.scss",
"bundleName": "light-theme", "bundleName": "light-theme",
"lazy": true "inject": false
} }
], ],
"scripts": [ "scripts": [
@ -92,9 +97,10 @@
"test": { "test": {
"builder": "@angular-devkit/build-angular:karma", "builder": "@angular-devkit/build-angular:karma",
"options": { "options": {
"tsConfig": "src/tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"main": "src/test.ts", "main": "src/test.ts",
"karmaConfig": "./karma.conf.js", "polyfills": "src/polyfills.ts",
"karmaConfig": "karma.conf.js",
"scripts": [ "scripts": [
"node_modules/core-js/client/shim.min.js", "node_modules/core-js/client/shim.min.js",
"node_modules/mutationobserver-shim/dist/mutationobserver.min.js", "node_modules/mutationobserver-shim/dist/mutationobserver.min.js",

View File

@ -1,11 +0,0 @@
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
#
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -2448,33 +2448,19 @@
} }
}, },
"@ngx-translate/core": { "@ngx-translate/core": {
"version": "10.0.2", "version": "13.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-10.0.2.tgz", "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-13.0.0.tgz",
"integrity": "sha512-7nM3DrJaqKswwtJlbu2kuKNl+hE8Isr18sKsKvGGpSxQk+G0gO0reDlx2PhUNus7TJTkA1C59vU/JoN8hIvZ4g==", "integrity": "sha512-+tzEp8wlqEnw0Gc7jtVRAJ6RteUjXw6JJR4O65KlnxOmJrCGPI0xjV/lKRnQeU0w4i96PQs/jtpL921Wrb7PWg==",
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^2.0.0"
},
"dependencies": {
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
}
} }
}, },
"@ngx-translate/http-loader": { "@ngx-translate/http-loader": {
"version": "3.0.1", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-3.0.1.tgz", "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-6.0.0.tgz",
"integrity": "sha1-ILD5i8bCUyESnT4zAqs8xInApCo=", "integrity": "sha512-LCekn6qCbeXWlhESCxU1rAbZz33WzDG0lI7Ig0pYC1o5YxJWrkU9y3Y4tNi+jakQ7R6YhTR2D3ox6APxDtA0wA==",
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^2.0.0"
},
"dependencies": {
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
}
} }
}, },
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {

View File

@ -1,6 +1,6 @@
{ {
"name": "harbor", "name": "harbor",
"version": "2.2.0", "version": "2.3.0",
"description": "Harbor UI with Clarity", "description": "Harbor UI with Clarity",
"angular-cli": {}, "angular-cli": {},
"scripts": { "scripts": {
@ -39,8 +39,8 @@
"@clr/ui": "^4.0.2", "@clr/ui": "^4.0.2",
"@fortawesome/fontawesome-free": "^5.1.0-4", "@fortawesome/fontawesome-free": "^5.1.0-4",
"@ng-bootstrap/ng-bootstrap": "^7.0.0", "@ng-bootstrap/ng-bootstrap": "^7.0.0",
"@ngx-translate/core": "^10.0.2", "@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^3.0.1", "@ngx-translate/http-loader": "^6.0.0",
"@types/jquery": "^2.0.41", "@types/jquery": "^2.0.41",
"@webcomponents/custom-elements": "^1.0.0", "@webcomponents/custom-elements": "^1.0.0",
"@webcomponents/webcomponentsjs": "^2.0.0", "@webcomponents/webcomponentsjs": "^2.0.0",

View File

@ -3,6 +3,7 @@
*/ */
const fs = require('fs'); const fs = require('fs');
const data = fs.readFileSync('src/environments/environment.prod.ts', 'utf8').split('\n'); const data = fs.readFileSync('src/environments/environment.prod.ts', 'utf8').split('\n');
const timestamp = new Date().getTime();
let buildTimestampIndex = 0; let buildTimestampIndex = 0;
data.forEach((item,index) => { data.forEach((item,index) => {
@ -10,10 +11,29 @@ data.forEach((item,index) => {
buildTimestampIndex = index; buildTimestampIndex = index;
} }
}); });
// modify buildTimestamp value in src/environments/environment.prod.ts file
if (buildTimestampIndex > 0) { if (buildTimestampIndex > 0) {
const timestamp = new Date().getTime();
data[buildTimestampIndex] = ` buildTimestamp: ${timestamp},`; data[buildTimestampIndex] = ` buildTimestamp: ${timestamp},`;
fs.writeFileSync('src/environments/environment.prod.ts', data.join('\n'), 'utf8'); fs.writeFileSync('src/environments/environment.prod.ts', data.join('\n'), 'utf8');
} }
// modify below lines in src/index.html to add buildTimestamp query string, in case of css cache in different builds
// <link rel="preload" as="style" href="./light-theme.css">
// <link rel="preload" as="style" href="./dark-theme.css">
const indexHtmlData = fs.readFileSync('src/index.html', 'utf8').split('\n');
let lightIndex = 0;
let darkIndex =0;
indexHtmlData.forEach((item,index) => {
if(item.indexOf('light-theme.css') !== -1) {
lightIndex = index;
}
if(item.indexOf('dark-theme.css') !== -1) {
darkIndex = index;
}
});
if (lightIndex > 0 && darkIndex > 0) {
indexHtmlData[lightIndex] = ` <link rel="preload" as="style" href="./light-theme.css?buildTimestamp=${timestamp}">`;
indexHtmlData[darkIndex] = ` <link rel="preload" as="style" href="./dark-theme.css?buildTimestamp=${timestamp}">`;
fs.writeFileSync('src/index.html', indexHtmlData.join('\n'), 'utf8');
}

View File

@ -1,4 +1,4 @@
import { Scanner } from '../../src/app/config/scanner/scanner'; import { Scanner } from '../../src/app/base/left-side-nav/interrogation-services/scanner/scanner';
import { Request, Response } from "express"; import { Request, Response } from "express";

View File

@ -1,7 +1,7 @@
import express from "express"; import express from "express";
import { Express } from 'express'; import { Express } from 'express';
import * as Controllers from '../controllers'; import * as Controllers from '../controllers';
import { CURRENT_BASE_HREF } from "../../src/lib/utils/utils"; import { CURRENT_BASE_HREF } from "../../src/app/shared/units/utils";
const mockApi: Express = express(); const mockApi: Express = express();

View File

@ -12,40 +12,35 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { CoreModule } from '../core/core.module';
import { SharedModule } from '../shared/shared.module'; import { SharedModule } from '../shared/shared.module';
import { PasswordSettingComponent } from './password-setting/password-setting.component';
import { AccountSettingsModalComponent } from './account-settings/account-settings-modal.component';
import { SignUpComponent } from './sign-up/sign-up.component'; import { SignUpComponent } from './sign-up/sign-up.component';
import { ForgotPasswordComponent } from './password-setting/forgot-password/forgot-password.component';
import { ResetPasswordComponent } from './password-setting/reset-password/reset-password.component';
import { SignUpPageComponent } from './sign-up/sign-up-page.component'; import { SignUpPageComponent } from './sign-up/sign-up-page.component';
import { PasswordSettingService } from './password-setting/password-setting.service'; import { SignInComponent } from "./sign-in/sign-in.component";
import { AccountSettingsModalService } from './account-settings/account-settings-modal-service.service'; import { SignInGuard } from "../shared/router-guard/sign-in-guard-activate.service";
import { TopRepoService } from "./sign-in/top-repo/top-repository.service";
import { TopRepoComponent } from "./sign-in/top-repo/top-repo.component";
const routes: Routes = [
{
path: 'sign-in',
canActivate: [SignInGuard],
component: SignInComponent
}
];
@NgModule({ @NgModule({
imports: [ imports: [
CoreModule, RouterModule.forChild(routes),
RouterModule,
SharedModule, SharedModule,
], ],
declarations: [ declarations: [
PasswordSettingComponent,
AccountSettingsModalComponent,
SignUpComponent, SignUpComponent,
ForgotPasswordComponent, SignUpPageComponent,
ResetPasswordComponent, SignInComponent,
SignUpPageComponent], TopRepoComponent,
exports: [ ],
PasswordSettingComponent, providers: [
AccountSettingsModalComponent, TopRepoService
ForgotPasswordComponent, ]
ResetPasswordComponent,
SignUpComponent,
SignUpPageComponent],
providers: [PasswordSettingService, AccountSettingsModalService]
}) })
export class AccountModule { } export class AccountModule { }

View File

@ -1,40 +0,0 @@
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="true" [clrModalClosable]="false">
<h3 class="modal-title">{{'RESET_PWD.TITLE' | translate}}</h3>
<label class="modal-title reset-modal-title-override">{{'RESET_PWD.CAPTION2' | translate}}</label>
<inline-alert class="modal-title"></inline-alert>
<div class="modal-body body-format">
<form #resetPwdForm="ngForm" class="form">
<section class="form-block">
<div class="form-group">
<label for="newPassword" class="form-group-label-override">{{'CHANGE_PWD.NEW_PWD' | translate}}</label>
<label for="newPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left"
[class.invalid]='!getValidationState("newPassword")'>
<input [disabled]="resetOk" type="password" id="newPassword" placeholder='{{"PLACEHOLDER.NEW_PWD" | translate}}' required
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,128}$" name="newPassword" [(ngModel)]="password"
#newPassInput="ngModel" size="25" (input)='handleValidation("newPassword", false)' (blur)='handleValidation("newPassword", true)'>
<span class="tooltip-content">
{{'TOOLTIP.PASSWORD' | translate}}
</span>
</label>
</div>
<div class="form-group">
<label for="reNewPassword" class="form-group-label-override">{{'CHANGE_PWD.CONFIRM_PWD' | translate}}</label>
<label for="reNewPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left"
[class.invalid]='!getValidationState("reNewPassword")'>
<input [disabled]="resetOk" type="password" id="reNewPassword" placeholder='{{"PLACEHOLDER.CONFIRM_PWD" | translate}}' required
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,128}$" name="reNewPassword" [(ngModel)]="confirmPwd"
#reNewPassInput size="25" (input)='handleValidation("reNewPassword", false)' (blur)='handleValidation("reNewPassword", true)'>
<span class="tooltip-content">
{{'TOOLTIP.CONFIRM_PWD' | translate}}
</span>
</label>
</div>
</section>
</form>
</div>
<div class="modal-footer">
<span class="spinner spinner-inline loading-top" [hidden]="showProgress === false"></span>
<button type="button" class="btn" [class.btn-outline]="!resetOk" [class.btn-primary]="resetOk" (click)="close()">{{btnCancelCaption | translate}}</button>
<button *ngIf="!resetOk" type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.OK' | translate}}</button>
</div>
</clr-modal>

View File

@ -1,51 +0,0 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { ResetPasswordComponent } from './reset-password.component';
import { FormsModule } from '@angular/forms';
import { PasswordSettingService } from '../password-setting.service';
import { RouterTestingModule } from '@angular/router/testing';
import { MessageHandlerService } from '../../../shared/message-handler/message-handler.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ClarityModule } from '@clr/angular';
import { InlineAlertComponent } from '../../../shared/inline-alert/inline-alert.component';
import { ErrorHandler } from '../../../../lib/utils/error-handler';
describe('ResetPasswordComponent', () => {
let component: ResetPasswordComponent;
let fixture: ComponentFixture<ResetPasswordComponent>;
let fakePasswordSettingService = null;
let fakeMessageHandlerService = null;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
FormsModule,
RouterTestingModule,
BrowserAnimationsModule,
ClarityModule
],
declarations: [ResetPasswordComponent, InlineAlertComponent],
providers: [
TranslateService,
{ provide: PasswordSettingService, useValue: fakePasswordSettingService },
{ provide: MessageHandlerService, useValue: fakeMessageHandlerService },
ErrorHandler
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ResetPasswordComponent);
component = fixture.componentInstance;
component.inlineAlert = TestBed.createComponent(InlineAlertComponent).componentInstance;
component.open();
fixture.autoDetectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,155 +0,0 @@
// Copyright Project Harbor Authors
//
// 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, ViewChild, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { NgForm } from '@angular/forms';
import { PasswordSettingService } from '../password-setting.service';
import { InlineAlertComponent } from '../../../shared/inline-alert/inline-alert.component';
import { MessageHandlerService } from '../../../shared/message-handler/message-handler.service';
import { CommonRoutes } from "../../../../lib/entities/shared.const";
@Component({
selector: 'reset-password',
templateUrl: "reset-password.component.html",
styleUrls: ['./reset-password.component.scss', '../password-setting.component.scss', '../../../common.scss']
})
export class ResetPasswordComponent implements OnInit {
opened: boolean = true;
onGoing: boolean = false;
password: string = "";
private validationState: any = {
"newPassword": true,
"reNewPassword": true
};
resetUuid: string = "";
resetOk: boolean = false;
confirmPwd: string = "";
@ViewChild("resetPwdForm", {static: true}) resetPwdForm: NgForm;
@ViewChild(InlineAlertComponent)
inlineAlert: InlineAlertComponent;
constructor(
private pwdService: PasswordSettingService,
private route: ActivatedRoute,
private msgHandler: MessageHandlerService,
private router: Router) { }
ngOnInit(): void {
this.route.queryParams.subscribe(params => this.resetUuid = params["reset_uuid"] || "");
}
public get showProgress(): boolean {
return this.onGoing;
}
public get isValid(): boolean {
return this.resetPwdForm && this.resetPwdForm.valid && this.samePassword();
}
public get btnCancelCaption(): string {
if (!this.resetOk) {
return 'BUTTON.CANCEL';
} else {
return 'BUTTON.CLOSE';
}
}
public getValidationState(key: string): boolean {
return this.validationState &&
this.validationState[key];
}
public open(): void {
this.resetOk = false;
this.onGoing = false;
this.validationState = {
"newPassword": true,
"reNewPassword": true
};
this.resetPwdForm.resetForm();
this.inlineAlert.close();
this.opened = true;
}
public close(): void {
// If already reset password ok, navigator to sign-in
if (this.resetOk) {
this.router.navigateByUrl(CommonRoutes.EMBEDDED_SIGN_IN);
}
this.opened = false;
}
public send(): void {
// Double confirm to avoid improper situations
if (!this.password) {
return;
}
if (!this.isValid) {
return;
}
this.onGoing = true;
this.pwdService.resetPassword(this.resetUuid, this.password)
.subscribe(() => {
this.onGoing = false;
this.resetOk = true;
this.inlineAlert.showInlineSuccess({ message: 'RESET_PWD.RESET_OK' });
}, error => {
this.onGoing = false;
if (this.msgHandler.isAppLevel(error)) {
this.close();
} else {
this.inlineAlert.showInlineError(error);
}
});
}
public handleValidation(key: string, flag: boolean): void {
if (!flag) {
this.validationState[key] = true;
} else {
this.validationState[key] = this.getControlValidationState(key);
if (this.validationState[key]) {
this.validationState["reNewPassword"] = this.samePassword();
}
}
}
getControlValidationState(key: string): boolean {
if (this.resetPwdForm) {
let control = this.resetPwdForm.controls[key];
if (control) {
return control.valid;
}
}
return false;
}
samePassword(): boolean {
if (this.resetPwdForm) {
let control1 = this.resetPwdForm.controls["newPassword"];
let control2 = this.resetPwdForm.controls["reNewPassword"];
if (control1 && control2) {
return control1.value === control2.value;
}
}
return false;
}
}

View File

@ -1,11 +1,11 @@
import { waitForAsync, ComponentFixture, getTestBed, inject, TestBed } from '@angular/core/testing'; import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { SignInComponent } from './sign-in.component'; import { SignInComponent } from './sign-in.component';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { AppConfigService } from '../services/app-config.service'; import { AppConfigService } from '../../services/app-config.service';
import { SessionService } from '../shared/session.service'; import { SessionService } from '../../shared/services/session.service';
import { CookieService } from 'ngx-cookie'; import { CookieService } from 'ngx-cookie';
import { SkinableConfig } from "../services/skinable-config.service"; import { SkinableConfig } from "../../services/skinable-config.service";
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { ClarityModule } from "@clr/angular"; import { ClarityModule } from "@clr/angular";
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';

View File

@ -15,19 +15,19 @@ import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router'; import { Router, ActivatedRoute } from '@angular/router';
import { Input, ViewChild, AfterViewChecked } from '@angular/core'; import { Input, ViewChild, AfterViewChecked } from '@angular/core';
import { NgForm } from '@angular/forms'; import { NgForm } from '@angular/forms';
import { SessionService } from '../shared/session.service'; import { SessionService } from '../../shared/services/session.service';
import { SignInCredential } from '../shared/sign-in-credential'; import { SignUpComponent } from '../sign-up/sign-up.component';
import { SignUpComponent } from '../account/sign-up/sign-up.component'; import { ForgotPasswordComponent } from '../../base/password-setting/forgot-password/forgot-password.component';
import { ForgotPasswordComponent } from '../account/password-setting/forgot-password/forgot-password.component'; import { AppConfigService } from '../../services/app-config.service';
import { AppConfigService } from '../services/app-config.service'; import { AppConfig } from '../../services/app-config';
import { AppConfig } from '../services/app-config'; import { User } from '../../base/left-side-nav/user/user';
import { User } from '../user/user';
import { CookieService, CookieOptions } from 'ngx-cookie'; import { CookieService, CookieOptions } from 'ngx-cookie';
import { SkinableConfig } from "../services/skinable-config.service"; import { SkinableConfig } from "../../services/skinable-config.service";
import {ModalEvent} from "../base/modal-event"; import {ModalEvent} from "../../base/modal-event";
import {modalEvents} from "../base/modal-events.const"; import {modalEvents} from "../../base/modal-events.const";
import {AboutDialogComponent} from "../shared/about-dialog/about-dialog.component"; import {AboutDialogComponent} from "../../shared/components/about-dialog/about-dialog.component";
import { CommonRoutes, CONFIG_AUTH_MODE } from "../../lib/entities/shared.const"; import { CommonRoutes, CONFIG_AUTH_MODE } from "../../shared/entities/shared.const";
import { SignInCredential } from "./sign-in-credential";
// Define status flags for signing in states // Define status flags for signing in states
export const signInStatusNormal = 0; export const signInStatusNormal = 0;
@ -247,7 +247,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
// Remeber me // Remeber me
this.remeberMe(); this.remeberMe();
// Redirect to the right route // Redirect to the right router-guard
if (this.redirectUrl === "") { if (this.redirectUrl === "") {
// Routing to the default location // Routing to the default location
this.router.navigateByUrl(CommonRoutes.HARBOR_DEFAULT); this.router.navigateByUrl(CommonRoutes.HARBOR_DEFAULT);

View File

@ -13,10 +13,10 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http'; import { HttpClient, HttpParams } from '@angular/common/http';
import { SignInCredential } from '../shared/sign-in-credential';
import { map, catchError } from "rxjs/operators"; import { map, catchError } from "rxjs/operators";
import { Observable, throwError as observableThrowError } from "rxjs"; import { Observable, throwError as observableThrowError } from "rxjs";
import { HTTP_FORM_OPTIONS } from "../../lib/utils/utils"; import { HTTP_FORM_OPTIONS } from "../../shared/units/utils";
import { SignInCredential } from "./sign-in-credential";
const signInUrl = '/c/login'; const signInUrl = '/c/login';
/** /**
* *

View File

@ -8,7 +8,7 @@ import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../shared/services/message-handler.service';
import { TopRepoService } from './top-repository.service'; import { TopRepoService } from './top-repository.service';
describe('TopRepoComponent', () => { describe('TopRepoComponent', () => {
let component: TopRepoComponent; let component: TopRepoComponent;

View File

@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../shared/services/message-handler.service';
import { TopRepoService } from './top-repository.service'; import { TopRepoService } from './top-repository.service';
import { Repository } from "../../../../ng-swagger-gen/models/repository"; import { Repository } from "../../../../../ng-swagger-gen/models/repository";
import { ListMode } from "../../../lib/entities/shared.const"; import { ListMode } from "../../../shared/entities/shared.const";
@Component({ @Component({

View File

@ -15,8 +15,8 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { map, catchError } from "rxjs/operators"; import { map, catchError } from "rxjs/operators";
import { Observable, throwError as observableThrowError } from "rxjs"; import { Observable, throwError as observableThrowError } from "rxjs";
import { Repository } from "../../../../ng-swagger-gen/models/repository"; import { Repository } from "../../../../../ng-swagger-gen/models/repository";
import { CURRENT_BASE_HREF, HTTP_GET_OPTIONS } from "../../../lib/utils/utils"; import { CURRENT_BASE_HREF, HTTP_GET_OPTIONS } from "../../../shared/units/utils";
export const topRepoEndpoint = CURRENT_BASE_HREF + "/repositories/top"; export const topRepoEndpoint = CURRENT_BASE_HREF + "/repositories/top";
/** /**

View File

@ -1,13 +1,13 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { UserService } from '../../user/user.service'; import { UserService } from '../../base/left-side-nav/user/user.service';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { MessageService } from '../../global-message/message.service'; import { MessageService } from '../../shared/components/global-message/message.service';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { SignUpPageComponent } from './sign-up-page.component'; import { SignUpPageComponent } from './sign-up-page.component';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { NewUserFormComponent } from '../../shared/new-user-form/new-user-form.component'; import { NewUserFormComponent } from '../../shared/components/new-user-form/new-user-form.component';
import { SessionService } from '../../shared/session.service'; import { SessionService } from '../../shared/services/session.service';
describe('SignUpPageComponent', () => { describe('SignUpPageComponent', () => {
let component: SignUpPageComponent; let component: SignUpPageComponent;

View File

@ -14,11 +14,11 @@
import { Component, ViewChild, OnInit } from '@angular/core'; import { Component, ViewChild, OnInit } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { NewUserFormComponent } from '../../shared/new-user-form/new-user-form.component'; import { NewUserFormComponent } from '../../shared/components/new-user-form/new-user-form.component';
import { User } from '../../user/user'; import { User } from '../../base/left-side-nav/user/user';
import { UserService } from '../../user/user.service'; import { UserService } from '../../base/left-side-nav/user/user.service';
import { AlertType } from '../../shared/shared.const'; import { MessageService } from '../../shared/components/global-message/message.service';
import { MessageService } from '../../global-message/message.service'; import { AlertType } from "../../shared/entities/shared.const";
@Component({ @Component({
selector: 'sign-up-page', selector: 'sign-up-page',

View File

@ -1,16 +1,16 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { ClarityModule } from "@clr/angular"; import { ClarityModule } from "@clr/angular";
import { SignUpComponent } from './sign-up.component'; import { SignUpComponent } from './sign-up.component';
import { SessionService } from '../../shared/session.service'; import { SessionService } from '../../shared/services/session.service';
import { UserService } from '../../user/user.service'; import { UserService } from '../../base/left-side-nav/user/user.service';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { NewUserFormComponent } from '../../shared/new-user-form/new-user-form.component'; import { NewUserFormComponent } from '../../shared/components/new-user-form/new-user-form.component';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { ErrorHandler } from '../../../lib/utils/error-handler'; import { ErrorHandler } from '../../shared/units/error-handler';
import { InlineAlertComponent } from "../../shared/components/inline-alert/inline-alert.component";
describe('SignUpComponent', () => { describe('SignUpComponent', () => {
let component: SignUpComponent; let component: SignUpComponent;

View File

@ -12,14 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, Output, ViewChild, EventEmitter } from '@angular/core'; import { Component, Output, ViewChild, EventEmitter } from '@angular/core';
import { Modal } from '../../../lib/services/interface'; import { Modal } from '../../shared/services/interface';
import { NewUserFormComponent } from '../../shared/components/new-user-form/new-user-form.component';
import { NewUserFormComponent } from '../../shared/new-user-form/new-user-form.component'; import { User } from '../../base/left-side-nav/user/user';
import { User } from '../../user/user'; import { SessionService } from '../../shared/services/session.service';
import { SessionService } from '../../shared/session.service'; import { UserService } from '../../base/left-side-nav/user/user.service';
import { UserService } from '../../user/user.service'; import { InlineAlertComponent } from "../../shared/components/inline-alert/inline-alert.component";
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
@Component({ @Component({
selector: 'sign-up', selector: 'sign-up',

View File

@ -1,16 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SelectArtifactIconPipe } from './select-artifact-icon/select-artifact-icon.pipe';
@NgModule({
declarations: [SelectArtifactIconPipe],
imports: [
CommonModule
],
exports: [
SelectArtifactIconPipe
]
})
export class AllPipesModule { }

View File

@ -1,19 +0,0 @@
import { SelectArtifactIconPipe } from './select-artifact-icon.pipe';
describe('SelectArtifactIconPipe', () => {
let mockTypeImage = "IMAGE";
let mockTypeChart = "CHART";
let mockTypecnab = "CNAB";
it('create an instance', () => {
const pipe = new SelectArtifactIconPipe();
expect(pipe).toBeTruthy();
});
it('it should success get adress of icon', () => {
const pipe = new SelectArtifactIconPipe();
expect(pipe.transform(mockTypeImage, '')).toBe('images/artifact-image.svg');
expect(pipe.transform(mockTypeChart, '')).toBe('images/artifact-chart.svg');
expect(pipe.transform(mockTypecnab, '')).toBe('images/artifact-cnab.svg');
expect(pipe.transform("", '')).toBe('images/artifact-default.svg');
});
});

View File

@ -1,18 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { artifactImages, artifactDefault } from '../../project/repository/artifact/artifact';
@Pipe({
name: 'selectArtifactIcon'
})
export class SelectArtifactIconPipe implements PipeTransform {
transform(value: string, ...args: any[]): any {
if (artifactImages.some(image => image === value)) {
return 'images/artifact-' + value.toLowerCase() + '.svg';
} else {
return artifactDefault;
}
}
}

View File

@ -18,7 +18,7 @@ import { Title } from '@angular/platform-browser';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { CookieService } from 'ngx-cookie'; import { CookieService } from 'ngx-cookie';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { SessionService } from './shared/session.service'; import { SessionService } from './shared/services/session.service';
import { AppConfigService } from './services/app-config.service'; import { AppConfigService } from './services/app-config.service';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { ClarityModule } from "@clr/angular"; import { ClarityModule } from "@clr/angular";

View File

@ -13,15 +13,13 @@
// limitations under the License. // limitations under the License.
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CookieService } from 'ngx-cookie';
import { SessionService } from './shared/session.service';
import { AppConfigService } from './services/app-config.service'; import { AppConfigService } from './services/app-config.service';
import { ThemeService } from './services/theme.service'; import { ThemeService } from './services/theme.service';
import { THEME_ARRAY, ThemeInterface } from './services/theme'; import { THEME_ARRAY, ThemeInterface } from './services/theme';
import { clone } from '../lib/utils/utils'; import { clone } from './shared/units/utils';
import { DEFAULT_LANG_LOCALSTORAGE_KEY, DeFaultLang, supportedLangs } from "./shared/entities/shared.const";
import { forkJoin, Observable } from "rxjs";
const HAS_STYLE_MODE: string = 'styleModeLocal'; const HAS_STYLE_MODE: string = 'styleModeLocal';
@ -31,17 +29,16 @@ const HAS_STYLE_MODE: string = 'styleModeLocal';
}) })
export class AppComponent { export class AppComponent {
themeArray: ThemeInterface[] = clone(THEME_ARRAY); themeArray: ThemeInterface[] = clone(THEME_ARRAY);
styleMode: string = this.themeArray[0].showStyle; styleMode: string = this.themeArray[0].showStyle;
constructor( constructor(
private translate: TranslateService, private translate: TranslateService,
private cookie: CookieService,
private session: SessionService,
private appConfigService: AppConfigService, private appConfigService: AppConfigService,
private titleService: Title, private titleService: Title,
public theme: ThemeService public theme: ThemeService
) { ) {
// init language
this.initLanguage();
// Override page title // Override page title
let key: string = "APP_TITLE.HARBOR"; let key: string = "APP_TITLE.HARBOR";
if (this.appConfigService.isIntegrationMode()) { if (this.appConfigService.isIntegrationMode()) {
@ -67,4 +64,37 @@ export class AppComponent {
} }
}); });
} }
initLanguage() {
/**
* due to the bug(https://github.com/ngx-translate/core/issues/1258) of translate module
* we have to call use method for all supported languages
* use method will load related language json from backend server
*/
const usedLangs: Array<Observable<any>> = [];
supportedLangs.forEach(lang => {
usedLangs.push(this.translate.use(lang));
});
forkJoin(usedLangs).subscribe(() => { // use target lang after all langs json loaded
this.translate.addLangs(supportedLangs);
this.translate.setDefaultLang(DeFaultLang);
let selectedLang: string = DeFaultLang;
if (localStorage && localStorage.getItem(DEFAULT_LANG_LOCALSTORAGE_KEY)) {// If user has selected lang, then directly use it
selectedLang = localStorage.getItem(DEFAULT_LANG_LOCALSTORAGE_KEY);
} else {// If user has not selected lang, then use browser language(if contained in supportedLangs)
const browserCultureLang: string = this.translate
.getBrowserCultureLang()
.toLowerCase();
if (browserCultureLang && browserCultureLang.trim() !== "") {
if (supportedLangs && supportedLangs.length > 0) {
if (supportedLangs.find(lang => lang === browserCultureLang)) {
selectedLang = browserCultureLang;
}
}
}
}
localStorage.setItem(DEFAULT_LANG_LOCALSTORAGE_KEY, selectedLang);
this.translate.use(selectedLang);
}
);
}
} }

View File

@ -12,86 +12,68 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER, LOCALE_ID, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { NgModule, APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { InterceptHttpService } from './services/intercept-http.service'; import { InterceptHttpService } from './services/intercept-http.service';
import { BaseModule } from './base/base.module';
import { HarborRoutingModule } from './harbor-routing.module'; import { HarborRoutingModule } from './harbor-routing.module';
import { SharedModule } from './shared/shared.module';
import { AccountModule } from './account/account.module';
import { SignInModule } from './sign-in/sign-in.module';
import { ConfigurationModule } from './config/config.module';
import { DeveloperCenterModule } from './dev-center/dev-center.module';
import { registerLocaleData } from '@angular/common';
import { TranslateService } from "@ngx-translate/core";
import { AppConfigService } from './services/app-config.service'; import { AppConfigService } from './services/app-config.service';
import { SkinableConfig } from "./services/skinable-config.service"; import { SkinableConfig } from "./services/skinable-config.service";
import { ProjectConfigComponent } from './project/project-config/project-config.component'; import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { CookieModule } from "ngx-cookie";
import {
MissingTranslationHandler,
MissingTranslationHandlerParams,
TranslateLoader,
TranslateModule
} from "@ngx-translate/core";
import {
ProjectDefaultService,
ProjectService,
UserPermissionDefaultService,
UserPermissionService
} from "./shared/services";
import { ErrorHandler } from "./shared/units/error-handler";
import { MessageHandlerService } from "./shared/services/message-handler.service";
import { HarborTranslateLoaderService } from "./services/harbor-translate-loader.service";
import zh from '@angular/common/locales/zh-Hans'; function initConfig(configService: AppConfigService, skinableService: SkinableConfig) {
import es from '@angular/common/locales/es';
import localeFr from '@angular/common/locales/fr';
import localePt from '@angular/common/locales/pt-PT';
import localeTr from '@angular/common/locales/tr';
import { DevCenterComponent } from './dev-center/dev-center.component';
import { VulnerabilityPageComponent } from './vulnerability-page/vulnerability-page.component';
import { GcPageComponent } from './gc-page/gc-page.component';
import { OidcOnboardModule } from './oidc-onboard/oidc-onboard.module';
import { LicenseModule } from './license/license.module';
import { InterrogationServicesComponent } from "./interrogation-services/interrogation-services.component";
import { LabelsComponent } from './labels/labels.component';
import { ProjectQuotasComponent } from './project-quotas/project-quotas.component';
import { HarborLibraryModule } from "../lib/harbor-library.module";
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AllPipesModule } from './all-pipes/all-pipes.module';
import { DistributionModule } from './distribution/distribution.module';
import { SystemRobotAccountsModule } from './system-robot-accounts/system-robot-accounts.module';
registerLocaleData(zh, 'zh-cn');
registerLocaleData(es, 'es-es');
registerLocaleData(localeFr, 'fr-fr');
registerLocaleData(localePt, 'pt-br');
registerLocaleData(localeTr, 'tr-tr');
export function initConfig(configService: AppConfigService, skinableService: SkinableConfig) {
return () => { return () => {
skinableService.getCustomFile().subscribe(); skinableService.getCustomFile().subscribe();
configService.load().subscribe(); configService.load().subscribe();
}; };
} }
export function getCurrentLanguage(translateService: TranslateService) { class MyMissingTranslationHandler implements MissingTranslationHandler {
return translateService.currentLang; handle(params: MissingTranslationHandlerParams) {
const missingText: string = "{Harbor}";
return params.key || missingText;
}
} }
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
ProjectConfigComponent,
VulnerabilityPageComponent,
GcPageComponent,
InterrogationServicesComponent,
LabelsComponent,
ProjectQuotasComponent
], ],
imports: [ imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: HarborTranslateLoaderService
},
missingTranslationHandler: {
provide: MissingTranslationHandler,
useClass: MyMissingTranslationHandler
}
}),
BrowserModule, BrowserModule,
SharedModule, BrowserAnimationsModule,
BaseModule, HttpClientModule,
AccountModule,
SignInModule,
HarborRoutingModule, HarborRoutingModule,
ConfigurationModule, CookieModule.forRoot(),
DeveloperCenterModule,
OidcOnboardModule,
LicenseModule,
HarborLibraryModule,
AllPipesModule,
DistributionModule,
SystemRobotAccountsModule
],
exports: [
], ],
providers: [ providers: [
AppConfigService, AppConfigService,
@ -102,9 +84,10 @@ export function getCurrentLanguage(translateService: TranslateService) {
deps: [AppConfigService, SkinableConfig], deps: [AppConfigService, SkinableConfig],
multi: true multi: true
}, },
{ provide: LOCALE_ID, useValue: "en-US" }, { provide: HTTP_INTERCEPTORS, useClass: InterceptHttpService, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: InterceptHttpService, multi: true } { provide: ProjectService, useClass: ProjectDefaultService },
{ provide: ErrorHandler, useClass: MessageHandlerService },
{ provide: UserPermissionService, useClass: UserPermissionDefaultService },
], ],
schemas: [ schemas: [
CUSTOM_ELEMENTS_SCHEMA CUSTOM_ELEMENTS_SCHEMA

View File

@ -2,12 +2,14 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { catchError, map } from 'rxjs/operators'; import { catchError, map } from 'rxjs/operators';
import { throwError as observableThrowError, Observable } from 'rxjs'; import { throwError as observableThrowError, Observable } from 'rxjs';
import { CURRENT_BASE_HREF } from "../../../lib/utils/utils"; import { CURRENT_BASE_HREF } from "../../shared/units/utils";
@Injectable() @Injectable({
providedIn: 'root'
})
export class AccountSettingsModalService { export class AccountSettingsModalService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }

View File

@ -1,23 +1,23 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { AccountSettingsModalComponent } from './account-settings-modal.component'; import { AccountSettingsModalComponent } from './account-settings-modal.component';
import { SessionService } from "../../shared/session.service"; import { SessionService } from "../../shared/services/session.service";
import { MessageHandlerService } from "../../shared/message-handler/message-handler.service"; import { MessageHandlerService } from "../../shared/services/message-handler.service";
import { SearchTriggerService } from "../../base/global-search/search-trigger.service"; import { SearchTriggerService } from "../../shared/components/global-search/search-trigger.service";
import { AccountSettingsModalService } from './account-settings-modal-service.service'; import { AccountSettingsModalService } from './account-settings-modal-service.service';
import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef } from '@angular/core';
import { ClarityModule } from "@clr/angular"; import { ClarityModule } from "@clr/angular";
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { clone } from '../../../lib/utils/utils'; import { clone } from '../../shared/units/utils';
import { ConfirmationDialogComponent } from '../../shared/confirmation-dialog/confirmation-dialog.component'; import { ErrorHandler } from '../../shared/units/error-handler';
import { ConfirmationDialogService } from '../../shared/confirmation-dialog/confirmation-dialog.service'; import { ConfirmationDialogComponent } from "../../shared/components/confirmation-dialog";
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message'; import { InlineAlertComponent } from "../../shared/components/inline-alert/inline-alert.component";
import { ErrorHandler } from '../../../lib/utils/error-handler'; import { ConfirmationDialogService } from "../global-confirmation-dialog/confirmation-dialog.service";
import { ConfirmationMessage } from "../global-confirmation-dialog/confirmation-message";
describe('AccountSettingsModalComponent', () => { describe('AccountSettingsModalComponent', () => {
let component: AccountSettingsModalComponent; let component: AccountSettingsModalComponent;

View File

@ -1,4 +1,3 @@
import { ChangeDetectorRef } from '@angular/core';
// Copyright Project Harbor Authors // Copyright Project Harbor Authors
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -12,26 +11,24 @@ import { ChangeDetectorRef } from '@angular/core';
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { ChangeDetectorRef } from '@angular/core';
import { Component, OnInit, ViewChild, AfterViewChecked } from "@angular/core"; import { Component, OnInit, ViewChild, AfterViewChecked } from "@angular/core";
import { NgForm } from "@angular/forms"; import { NgForm } from "@angular/forms";
import { Router, NavigationExtras } from "@angular/router"; import { Router, NavigationExtras } from "@angular/router";
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message'; import { SessionUser } from "../../shared/entities/session-user";
import { SessionService } from "../../shared/services/session.service";
import { SessionUser } from "../../shared/session-user"; import { MessageHandlerService } from "../../shared/services/message-handler.service";
import { SessionService } from "../../shared/session.service"; import { SearchTriggerService } from "../../shared/components/global-search/search-trigger.service";
import { InlineAlertComponent } from "../../shared/inline-alert/inline-alert.component";
import { MessageHandlerService } from "../../shared/message-handler/message-handler.service";
import { SearchTriggerService } from "../../base/global-search/search-trigger.service";
import { AccountSettingsModalService } from './account-settings-modal-service.service'; import { AccountSettingsModalService } from './account-settings-modal-service.service';
import { ConfirmationDialogComponent } from "../../shared/confirmation-dialog/confirmation-dialog.component"; import { randomWord } from '../../shared/units/shared.utils';
import {
ConfirmationTargets,
ConfirmationButtons
} from "../../shared/shared.const";
import { randomWord } from '../../shared/shared.utils';
import { ResetSecret } from './account'; import { ResetSecret } from './account';
import { CopyInputComponent } from "../../../lib/components/push-image/copy-input.component"; import { CopyInputComponent } from "../../shared/components/push-image/copy-input.component";
import { CommonRoutes } from "../../../lib/entities/shared.const"; import { CommonRoutes, ConfirmationButtons, ConfirmationTargets } from "../../shared/entities/shared.const";
import { ConfirmationDialogComponent } from "../../shared/components/confirmation-dialog";
import { InlineAlertComponent } from "../../shared/components/inline-alert/inline-alert.component";
import { ConfirmationMessage } from "../global-confirmation-dialog/confirmation-message";
@Component({ @Component({
selector: "account-settings-modal", selector: "account-settings-modal",
templateUrl: "account-settings-modal.component.html", templateUrl: "account-settings-modal.component.html",
@ -224,7 +221,7 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
// Log out system // Log out system
logOut(): void { logOut(): void {
// Naviagte to the sign in route // Naviagte to the sign in router-guard
// Appending 'signout' means destroy session cache // Appending 'signout' means destroy session cache
let navigatorExtra: NavigationExtras = { let navigatorExtra: NavigationExtras = {
queryParams: { signout: true } queryParams: { signout: true }

View File

@ -13,37 +13,127 @@
// limitations under the License. // limitations under the License.
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module'; import { SharedModule } from '../shared/shared.module';
import { RouterModule } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { ProjectModule } from '../project/project.module';
import { UserModule } from '../user/user.module';
import { AccountModule } from '../account/account.module';
import { GroupModule } from '../group/group.module';
import { NavigatorComponent } from './navigator/navigator.component';
import { GlobalSearchComponent } from './global-search/global-search.component';
import { FooterComponent } from './footer/footer.component';
import { HarborShellComponent } from './harbor-shell/harbor-shell.component'; import { HarborShellComponent } from './harbor-shell/harbor-shell.component';
import { SearchResultComponent } from './global-search/search-result.component'; import { SystemAdminGuard } from "../shared/router-guard/system-admin-activate.service";
import { MemberGuard } from "../shared/router-guard/member-guard-activate.service";
import { SearchTriggerService } from './global-search/search-trigger.service'; import { ProjectRoutingResolver } from "../services/routing-resolvers/project-routing-resolver.service";
import { PasswordSettingComponent } from "./password-setting/password-setting.component";
import { AccountSettingsModalComponent } from "./account-settings/account-settings-modal.component";
import { ForgotPasswordComponent } from "./password-setting/forgot-password/forgot-password.component";
import { GlobalConfirmationDialogComponent } from "./global-confirmation-dialog/global-confirmation-dialog.component";
const routes: Routes = [
{
path: '',
component: HarborShellComponent,
children: [
{ path: '', redirectTo: 'projects', pathMatch: 'full' },
{
path: 'projects',
loadChildren: () => import('./left-side-nav/projects/projects.module').then(m => m.ProjectsModule)
},
{
path: 'logs',
loadChildren: () => import('./left-side-nav/log/log.module').then(m => m.LogModule)
},
{
path: 'users',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/user/user.module').then(m => m.UserModule)
},
{
path: 'robot-accounts',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/system-robot-accounts/system-robot-accounts.module')
.then(m => m.SystemRobotAccountsModule)
},
{
path: 'groups',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/group/group.module').then(m => m.GroupModule)
},
{
path: 'registries',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/registries/endpoint.module').then(m => m.EndpointModule)
},
{
path: 'replications',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/replication/replication.module').then(m => m.ReplicationModule)
},
{
path: 'distribution',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/distribution/distribution.module').then(m => m.DistributionModule)
},
{
path: 'interrogation-services',
canActivate: [SystemAdminGuard],
loadChildren: () =>
import('./left-side-nav/interrogation-services/interrogation-services.module')
.then(m => m.InterrogationServicesModule)
},
{
path: 'labels',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/labels/labels.module').then(m => m.LabelsModule)
},
{
path: 'project-quotas',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/project-quotas/project-quotas.module').then(m => m.ProjectQuotasModule)
},
{
path: 'gc',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/gc-page/gc.module').then(m => m.GcModule)
},
{
path: 'configs',
canActivate: [SystemAdminGuard],
loadChildren: () => import('./left-side-nav/config/config.module').then(m => m.ConfigurationModule)
},
{
path: 'projects/:id',
loadChildren: () => import('./project/project.module').then(m => m.ProjectModule),
canActivate: [MemberGuard],
resolve: {
projectResolver: ProjectRoutingResolver
}
},
{
path: 'projects/:id/repositories',
loadChildren: () => import('./project/repository/artifact/artifact.module').then(m => m.ArtifactModule),
canActivate: [MemberGuard],
resolve: {
projectResolver: ProjectRoutingResolver
}
},
{
path: 'projects/:id/helm-charts',
canActivate: [MemberGuard],
resolve: {
projectResolver: ProjectRoutingResolver
},
loadChildren: () => import('./project/helm-chart/helm-chart-detail/helm-chart-detail.module').then(m => m.HelmChartListModule),
},
]
}
];
@NgModule({ @NgModule({
imports: [ imports: [
SharedModule, SharedModule,
ProjectModule, RouterModule.forChild(routes),
UserModule,
AccountModule,
RouterModule,
GroupModule
], ],
declarations: [ declarations: [
NavigatorComponent,
GlobalSearchComponent,
FooterComponent,
HarborShellComponent, HarborShellComponent,
SearchResultComponent, PasswordSettingComponent,
], AccountSettingsModalComponent,
exports: [ HarborShellComponent, NavigatorComponent, SearchResultComponent ], ForgotPasswordComponent,
providers: [SearchTriggerService] GlobalConfirmationDialogComponent
]
}) })
export class BaseModule { export class BaseModule {

View File

@ -1,25 +0,0 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { FooterComponent } from './footer.component';
describe('FooterComponent', () => {
let component: FooterComponent;
let fixture: ComponentFixture<FooterComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [FooterComponent]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FooterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -17,7 +17,9 @@ import { Subject } from "rxjs";
import { ConfirmationMessage } from './confirmation-message'; import { ConfirmationMessage } from './confirmation-message';
import { ConfirmationAcknowledgement } from './confirmation-state-message'; import { ConfirmationAcknowledgement } from './confirmation-state-message';
@Injectable() @Injectable({
providedIn: 'root',
})
export class ConfirmationDialogService { export class ConfirmationDialogService {
confirmationAnnoucedSource = new Subject<ConfirmationMessage>(); confirmationAnnoucedSource = new Subject<ConfirmationMessage>();
confirmationConfirmSource = new Subject<ConfirmationAcknowledgement>(); confirmationConfirmSource = new Subject<ConfirmationAcknowledgement>();

View File

@ -14,7 +14,7 @@
import { import {
ConfirmationTargets, ConfirmationTargets,
ConfirmationButtons ConfirmationButtons
} from "../../entities/shared.const"; } from "../../shared/entities/shared.const";
export class ConfirmationMessage { export class ConfirmationMessage {
public constructor( public constructor(

View File

@ -11,7 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { ConfirmationState, ConfirmationTargets } from '../shared.const'; import { ConfirmationState, ConfirmationTargets } from '../../shared/entities/shared.const';
export class ConfirmationAcknowledgement { export class ConfirmationAcknowledgement {
constructor(state: ConfirmationState, data: any, source: ConfirmationTargets) { constructor(state: ConfirmationState, data: any, source: ConfirmationTargets) {

View File

@ -1,6 +1,5 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { ConfirmationDialogComponent } from './confirmation-dialog.component';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ClarityModule } from '@clr/angular'; import { ClarityModule } from '@clr/angular';
@ -9,10 +8,11 @@ import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ConfirmationDialogService } from './confirmation-dialog.service'; import { ConfirmationDialogService } from './confirmation-dialog.service';
import { GlobalConfirmationDialogComponent } from "./global-confirmation-dialog.component";
describe('ConfirmationDialogComponent', () => { describe('ConfirmationDialogComponent', () => {
let component: ConfirmationDialogComponent; let component: GlobalConfirmationDialogComponent;
let fixture: ComponentFixture<ConfirmationDialogComponent>; let fixture: ComponentFixture<GlobalConfirmationDialogComponent>;
const mockConfirmationDialogService = { const mockConfirmationDialogService = {
confirmationAnnouced$: of({ confirmationAnnouced$: of({
title: "title", title: "title",
@ -36,7 +36,7 @@ describe('ConfirmationDialogComponent', () => {
NoopAnimationsModule, NoopAnimationsModule,
HttpClientTestingModule HttpClientTestingModule
], ],
declarations: [ConfirmationDialogComponent], declarations: [GlobalConfirmationDialogComponent],
providers: [ providers: [
TranslateService, TranslateService,
{ provide: ConfirmationDialogService, useValue: mockConfirmationDialogService }, { provide: ConfirmationDialogService, useValue: mockConfirmationDialogService },
@ -46,7 +46,7 @@ describe('ConfirmationDialogComponent', () => {
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ConfirmationDialogComponent); fixture = TestBed.createComponent(GlobalConfirmationDialogComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@ -14,19 +14,19 @@
import { Component, OnDestroy } from '@angular/core'; import { Component, OnDestroy } from '@angular/core';
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { ConfirmationDialogService } from './confirmation-dialog.service';
import { ConfirmationMessage } from './confirmation-message'; import { ConfirmationMessage } from './confirmation-message';
import { ConfirmationAcknowledgement } from './confirmation-state-message'; import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from "../../shared/entities/shared.const";
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../shared.const'; import { ConfirmationDialogService } from "./confirmation-dialog.service";
import { ConfirmationAcknowledgement } from "./confirmation-state-message";
@Component({ @Component({
selector: 'confiramtion-dialog', selector: 'global-confirmation-dialog',
templateUrl: 'confirmation-dialog.component.html', templateUrl: 'global-confirmation-dialog.component.html',
styleUrls: ['confirmation-dialog.component.scss'] styleUrls: ['global-confirmation-dialog.component.scss']
}) })
export class ConfirmationDialogComponent implements OnDestroy { export class GlobalConfirmationDialogComponent implements OnDestroy {
opened: boolean = false; opened: boolean = false;
dialogTitle: string = ""; dialogTitle: string = "";
dialogContent: string = ""; dialogContent: string = "";

View File

@ -111,5 +111,5 @@
</clr-main-container> </clr-main-container>
<account-settings-modal></account-settings-modal> <account-settings-modal></account-settings-modal>
<password-setting></password-setting> <password-setting></password-setting>
<confiramtion-dialog></confiramtion-dialog> <global-confirmation-dialog></global-confirmation-dialog>
<about-dialog></about-dialog> <about-dialog></about-dialog>

View File

@ -1,26 +1,26 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SessionService } from '../../shared/session.service'; import { SessionService } from '../../shared/services/session.service';
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { SearchTriggerService } from '../global-search/search-trigger.service'; import { SearchTriggerService } from '../../shared/components/global-search/search-trigger.service';
import { HarborShellComponent } from './harbor-shell.component'; import { HarborShellComponent } from './harbor-shell.component';
import { ClarityModule } from "@clr/angular"; import { ClarityModule } from "@clr/angular";
import { of } from 'rxjs'; import { of } from 'rxjs';
import { ConfigScannerService } from "../../config/scanner/config-scanner.service"; import { ConfigScannerService } from "../left-side-nav/interrogation-services/scanner/config-scanner.service";
import { modalEvents } from '../modal-events.const'; import { modalEvents } from '../modal-events.const';
import { AccountSettingsModalComponent } from '../../account/account-settings/account-settings-modal.component'; import { PasswordSettingComponent } from '../password-setting/password-setting.component';
import { PasswordSettingComponent } from '../../account/password-setting/password-setting.component'; import { AboutDialogComponent } from '../../shared/components/about-dialog/about-dialog.component';
import { AboutDialogComponent } from '../../shared/about-dialog/about-dialog.component';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../shared/services/message-handler.service';
import { AccountSettingsModalService } from '../../account/account-settings/account-settings-modal-service.service'; import { PasswordSettingService } from '../password-setting/password-setting.service';
import { PasswordSettingService } from '../../account/password-setting/password-setting.service';
import { SkinableConfig } from '../../services/skinable-config.service'; import { SkinableConfig } from '../../services/skinable-config.service';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { AppConfigService } from "../../services/app-config.service"; import { AppConfigService } from "../../services/app-config.service";
import { ErrorHandler } from '../../../lib/utils/error-handler'; import { ErrorHandler } from '../../shared/units/error-handler';
import { AccountSettingsModalComponent } from "../account-settings/account-settings-modal.component";
import { InlineAlertComponent } from "../../shared/components/inline-alert/inline-alert.component";
import { AccountSettingsModalService } from "../account-settings/account-settings-modal-service.service";
describe('HarborShellComponent', () => { describe('HarborShellComponent', () => {
let component: HarborShellComponent; let component: HarborShellComponent;

View File

@ -15,21 +15,19 @@ import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router'; import { Router, ActivatedRoute } from '@angular/router';
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { AppConfigService } from '../../services/app-config.service'; import { AppConfigService } from '../../services/app-config.service';
import { ModalEvent } from '../modal-event'; import { ModalEvent } from '../modal-event';
import { modalEvents } from '../modal-events.const'; import { modalEvents } from '../modal-events.const';
import { PasswordSettingComponent } from '../password-setting/password-setting.component';
import { AccountSettingsModalComponent } from '../../account/account-settings/account-settings-modal.component'; import { NavigatorComponent } from '../../shared/components/navigator/navigator.component';
import { PasswordSettingComponent } from '../../account/password-setting/password-setting.component'; import { SessionService } from '../../shared/services/session.service';
import { NavigatorComponent } from '../navigator/navigator.component'; import { AboutDialogComponent } from '../../shared/components/about-dialog/about-dialog.component';
import { SessionService } from '../../shared/session.service'; import { SearchTriggerService } from '../../shared/components/global-search/search-trigger.service';
import { AboutDialogComponent } from '../../shared/about-dialog/about-dialog.component'; import { CommonRoutes } from "../../shared/entities/shared.const";
import { SearchTriggerService } from '../global-search/search-trigger.service'; import { ConfigScannerService, SCANNERS_DOC } from "../left-side-nav/interrogation-services/scanner/config-scanner.service";
import { CommonRoutes } from "../../../lib/entities/shared.const";
import { ConfigScannerService, SCANNERS_DOC } from "../../config/scanner/config-scanner.service";
import { THEME_ARRAY, ThemeInterface } from "../../services/theme"; import { THEME_ARRAY, ThemeInterface } from "../../services/theme";
import { clone } from "../../../lib/utils/utils"; import { clone } from "../../shared/units/utils";
import { ThemeService } from "../../services/theme.service"; import { ThemeService } from "../../services/theme.service";
import { AccountSettingsModalComponent } from "../account-settings/account-settings-modal.component";
const HAS_SHOWED_SCANNER_INFO: string = 'hasShowScannerInfo'; const HAS_SHOWED_SCANNER_INFO: string = 'hasShowScannerInfo';
const YES: string = 'yes'; const YES: string = 'yes';

View File

@ -1,17 +1,17 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service';
import { ConfirmMessageHandler } from '../config.msg.utils'; import { ConfirmMessageHandler } from '../config.msg.utils';
import { AppConfigService } from '../../services/app-config.service'; import { AppConfigService } from '../../../../services/app-config.service';
import { ConfigurationService } from '../config.service'; import { ConfigurationService } from '../../../../services/config.service';
import { ConfigurationAuthComponent } from './config-auth.component'; import { ConfigurationAuthComponent } from './config-auth.component';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA, SimpleChange } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { ErrorHandler } from "../../../lib/utils/error-handler"; import { ErrorHandler } from "../../../../shared/units/error-handler";
import { SystemInfoService } from "../../../lib/services"; import { SystemInfoService } from "../../../../shared/services";
import { clone } from '../../../lib/utils/utils'; import { clone } from '../../../../shared/units/utils';
import { CONFIG_AUTH_MODE } from '../../../lib/entities/shared.const'; import { CONFIG_AUTH_MODE } from '../../../../shared/entities/shared.const';
describe('ConfigurationAuthComponent', () => { describe('ConfigurationAuthComponent', () => {
let component: ConfigurationAuthComponent; let component: ConfigurationAuthComponent;

View File

@ -14,17 +14,16 @@
import { Component, Input, ViewChild, SimpleChanges, OnChanges, OnInit, Output, EventEmitter } from '@angular/core'; import { Component, Input, ViewChild, SimpleChanges, OnChanges, OnInit, Output, EventEmitter } from '@angular/core';
import { NgForm } from '@angular/forms'; import { NgForm } from '@angular/forms';
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service';
import { ConfirmMessageHandler } from '../config.msg.utils'; import { ConfirmMessageHandler } from '../config.msg.utils';
import { AppConfigService } from '../../services/app-config.service'; import { AppConfigService } from '../../../../services/app-config.service';
import { ConfigurationService } from '../config.service'; import { ConfigurationService } from '../../../../services/config.service';
import { Configuration } from "../../../lib/components/config/config"; import { ErrorHandler } from "../../../../shared/units/error-handler";
import { ErrorHandler } from "../../../lib/utils/error-handler"; import { SystemInfoService } from "../../../../shared/services";
import { errorHandler as errorHandlerFn } from "../../../lib/utils/shared/shared.utils"; import { clone, isEmpty, getChanges as getChangesFunc } from "../../../../shared/units/utils";
import { CONFIG_AUTH_MODE } from "../../../../shared/entities/shared.const";
import { SystemInfoService } from "../../../lib/services"; import { errorHandler } from "../../../../shared/units/shared.utils";
import { clone, isEmpty, getChanges as getChangesFunc } from "../../../lib/utils/utils"; import { Configuration } from "../config";
import { CONFIG_AUTH_MODE } from "../../../lib/entities/shared.const";
const fakePass = 'aWpLOSYkIzJTTU4wMDkx'; const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
@Component({ @Component({
@ -49,7 +48,7 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit {
private appConfigService: AppConfigService, private appConfigService: AppConfigService,
private confirmMessageHandler: ConfirmMessageHandler, private confirmMessageHandler: ConfirmMessageHandler,
private systemInfo: SystemInfoService, private systemInfo: SystemInfoService,
private errorHandler: ErrorHandler, private errorHandlerEntity: ErrorHandler,
) { ) {
} }
ngOnInit() { ngOnInit() {
@ -58,7 +57,7 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit {
getSystemInfo(): void { getSystemInfo(): void {
this.systemInfo.getSystemInfo() this.systemInfo.getSystemInfo()
.subscribe(systemInfo => (this.redirectUrl = systemInfo.external_url) .subscribe(systemInfo => (this.redirectUrl = systemInfo.external_url)
, error => this.errorHandler.error(error)); , error => this.errorHandlerEntity.error(error));
} }
get checkable() { get checkable() {
return this.currentConfig && return this.currentConfig &&
@ -144,7 +143,7 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit {
this.msgHandler.showSuccess('CONFIG.TEST_LDAP_SUCCESS'); this.msgHandler.showSuccess('CONFIG.TEST_LDAP_SUCCESS');
}, error => { }, error => {
this.testingOnGoing = false; this.testingOnGoing = false;
let err = errorHandlerFn(error); let err = errorHandler(error);
if (!err || !err.trim()) { if (!err || !err.trim()) {
err = 'UNKNOWN'; err = 'UNKNOWN';
} }
@ -165,10 +164,9 @@ export class ConfigurationAuthComponent implements OnChanges, OnInit {
this.msgHandler.showSuccess('CONFIG.TEST_OIDC_SUCCESS'); this.msgHandler.showSuccess('CONFIG.TEST_OIDC_SUCCESS');
}, error => { }, error => {
this.testingOnGoing = false; this.testingOnGoing = false;
this.errorHandler.error(error); this.errorHandlerEntity.error(error);
}); });
} }
} }
public get showTestingServerBtn(): boolean { public get showTestingServerBtn(): boolean {

View File

@ -1,17 +1,17 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { SessionService } from '../shared/session.service'; import { SessionService } from '../../../shared/services/session.service';
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service'; import { MessageHandlerService } from '../../../shared/services/message-handler.service';
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ClarityModule } from "@clr/angular"; import { ClarityModule } from "@clr/angular";
import { AppConfigService } from '../services/app-config.service'; import { AppConfigService } from '../../../services/app-config.service';
import { ConfigurationService } from './config.service'; import { ConfigurationService } from '../../../services/config.service';
import { ConfigurationComponent } from './config.component'; import { ConfigurationComponent } from './config.component';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { ConfirmationAcknowledgement } from '../shared/confirmation-dialog/confirmation-state-message'; import { Configuration } from './config';
import { ConfirmationState, ConfirmationTargets } from '../shared/shared.const'; import { ConfirmationState, ConfirmationTargets } from "../../../shared/entities/shared.const";
import { Configuration } from '../../lib/components/config/config'; import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service";
import { ConfirmationAcknowledgement } from "../../global-confirmation-dialog/confirmation-state-message";
describe('ConfigurationComponent', () => { describe('ConfigurationComponent', () => {
let component: ConfigurationComponent; let component: ConfigurationComponent;

View File

@ -13,17 +13,17 @@
// limitations under the License. // limitations under the License.
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { ConfirmationTargets, ConfirmationState } from '../shared/shared.const'; import { SessionService } from '../../../shared/services/session.service';
import { SessionService } from '../shared/session.service'; import { MessageHandlerService } from '../../../shared/services/message-handler.service';
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service'; import { AppConfigService } from '../../../services/app-config.service';
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
import { AppConfigService } from '../services/app-config.service';
import { ConfigurationAuthComponent } from './auth/config-auth.component'; import { ConfigurationAuthComponent } from './auth/config-auth.component';
import { ConfigurationEmailComponent } from './email/config-email.component'; import { ConfigurationEmailComponent } from './email/config-email.component';
import { ConfigurationService } from './config.service'; import { ConfigurationService } from '../../../services/config.service';
import { Configuration, StringValueItem } from "../../lib/components/config/config"; import { Configuration, StringValueItem } from "./config";
import { SystemSettingsComponent } from "../../lib/components/config/system/system-settings.component"; import { SystemSettingsComponent } from "./system/system-settings.component";
import { clone, isEmpty } from "../../lib/utils/utils"; import { clone, isEmpty } from "../../../shared/units/utils";
import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service";
import { ConfirmationState, ConfirmationTargets } from "../../../shared/entities/shared.const";
const fakePass = 'aWpLOSYkIzJTTU4wMDkx'; const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
const TabLinkContentMap = { const TabLinkContentMap = {

View File

@ -13,37 +13,33 @@
// limitations under the License. // limitations under the License.
import { NgModule } from "@angular/core"; import { NgModule } from "@angular/core";
import { CoreModule } from "../core/core.module"; import { SharedModule } from "../../../shared/shared.module";
import { SharedModule } from "../shared/shared.module";
import { ConfigurationComponent } from "./config.component"; import { ConfigurationComponent } from "./config.component";
import { ConfigurationService } from "./config.service";
import { ConfirmMessageHandler } from "./config.msg.utils"; import { ConfirmMessageHandler } from "./config.msg.utils";
import { ConfigurationAuthComponent } from "./auth/config-auth.component"; import { ConfigurationAuthComponent } from "./auth/config-auth.component";
import { ConfigurationEmailComponent } from "./email/config-email.component"; import { ConfigurationEmailComponent } from "./email/config-email.component";
import { ConfigurationScannerComponent } from "./scanner/config-scanner.component"; import { SystemSettingsComponent } from "./system/system-settings.component";
import { NewScannerModalComponent } from "./scanner/new-scanner-modal/new-scanner-modal.component"; import { RouterModule, Routes } from "@angular/router";
import { NewScannerFormComponent } from "./scanner/new-scanner-form/new-scanner-form.component";
import { ConfigScannerService } from "./scanner/config-scanner.service";
import { ScannerMetadataComponent } from "./scanner/scanner-metadata/scanner-metadata.component";
const routes: Routes = [
{
path: '',
component: ConfigurationComponent
}
];
@NgModule({ @NgModule({
imports: [CoreModule, SharedModule], imports: [
SharedModule,
RouterModule.forChild(routes)
],
declarations: [ declarations: [
ConfigurationComponent, ConfigurationComponent,
ConfigurationAuthComponent, ConfigurationAuthComponent,
ConfigurationEmailComponent, ConfigurationEmailComponent,
ConfigurationScannerComponent, SystemSettingsComponent
NewScannerModalComponent,
NewScannerFormComponent,
ScannerMetadataComponent
], ],
exports: [ConfigurationComponent],
providers: [ providers: [
ConfigurationService,
ConfirmMessageHandler, ConfirmMessageHandler,
ConfigScannerService,
] ]
}) })
export class ConfigurationModule { export class ConfigurationModule {

View File

@ -1,7 +1,7 @@
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service';
import { ConfirmationMessage } from '../shared/confirmation-dialog/confirmation-message';
import { ConfirmationTargets } from '../shared/shared.const';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service";
import { ConfirmationTargets } from "../../../shared/entities/shared.const";
import { ConfirmationMessage } from "../../global-confirmation-dialog/confirmation-message";
@Injectable() @Injectable()
export class ConfirmMessageHandler { export class ConfirmMessageHandler {

View File

@ -1,12 +1,12 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service';
import { ConfirmMessageHandler } from '../config.msg.utils'; import { ConfirmMessageHandler } from '../config.msg.utils';
import { ConfigurationService } from '../config.service'; import { ConfigurationService } from '../../../../services/config.service';
import { ConfigurationEmailComponent } from './config-email.component'; import { ConfigurationEmailComponent } from './config-email.component';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { clone } from '../../../lib/utils/utils'; import { clone } from '../../../../shared/units/utils';
import { of } from 'rxjs'; import { of } from 'rxjs';
describe('ConfigurationEmailComponent', () => { describe('ConfigurationEmailComponent', () => {

View File

@ -13,13 +13,13 @@
// limitations under the License. // limitations under the License.
import { Component, Input, ViewChild, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core'; import { Component, Input, ViewChild, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core';
import { NgForm } from '@angular/forms'; import { NgForm } from '@angular/forms';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service';
import { ConfirmMessageHandler } from '../config.msg.utils'; import { ConfirmMessageHandler } from '../config.msg.utils';
import { ConfigurationService } from '../config.service'; import { ConfigurationService } from '../../../../services/config.service';
import { Configuration } from "../../../lib/components/config/config"; import { Configuration } from "../config";
import { isEmpty, getChanges as getChangesFunc, clone } from "../../../lib/utils/utils"; import { isEmpty, getChanges as getChangesFunc, clone } from "../../../../shared/units/utils";
import { errorHandler } from "../../../lib/utils/shared/shared.utils"; import { errorHandler } from "../../../../shared/units/shared.utils";
const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
@Component({ @Component({
selector: 'config-email', selector: 'config-email',
templateUrl: "config-email.component.html", templateUrl: "config-email.component.html",

View File

@ -112,3 +112,27 @@
transform: translateY(-50%); transform: translateY(-50%);
} }
} }
.info-tips-icon {
color: grey;
}
.info-tips-icon:hover {
color: #007CBB;
}
.replication-config {
margin-top: 0;
margin-bottom: 0;
}
.replication-text {
font-size: 14px;
font-weight: 600;
}
.replication-tooltip {
top: -8px;
}
.margin-top-3px {
margin-top: 3px;
}

View File

@ -1,19 +1,14 @@
import { ComponentFixture, ComponentFixtureAutoDetect, TestBed } from '@angular/core/testing'; import { ComponentFixture, ComponentFixtureAutoDetect, TestBed } from '@angular/core/testing';
import { HarborLibraryModule } from "../../../harbor-library.module";
import { IServiceConfig, SERVICE_CONFIG } from "../../../entities/service.config";
import { SystemSettingsComponent } from "./system-settings.component"; import { SystemSettingsComponent } from "./system-settings.component";
import { ConfigurationService, SystemInfoService } from "../../../services"; import { SystemInfoService } from "../../../../shared/services";
import { ErrorHandler } from "../../../utils/error-handler"; import { ErrorHandler } from "../../../../shared/units/error-handler";
import { of } from "rxjs"; import { of } from "rxjs";
import { StringValueItem } from "../config"; import { StringValueItem } from "../config";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { CURRENT_BASE_HREF } from "../../../utils/utils"; import { SharedTestingModule } from "../../../../shared/shared.module";
describe('SystemSettingsComponent', () => { describe('SystemSettingsComponent', () => {
let component: SystemSettingsComponent; let component: SystemSettingsComponent;
let fixture: ComponentFixture<SystemSettingsComponent>; let fixture: ComponentFixture<SystemSettingsComponent>;
const config: IServiceConfig = {
baseEndpoint: CURRENT_BASE_HREF + "/testing"
};
const mockedAllowlist = { const mockedAllowlist = {
id: 1, id: 1,
project_id: 1, project_id: 1,
@ -41,17 +36,18 @@ describe('SystemSettingsComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
HarborLibraryModule, SharedTestingModule,
BrowserAnimationsModule BrowserAnimationsModule
], ],
providers: [ providers: [
ConfigurationService,
{ provide: ErrorHandler, useValue: fakedErrorHandler }, { provide: ErrorHandler, useValue: fakedErrorHandler },
{ provide: SystemInfoService, useValue: fakedSystemInfoService }, { provide: SystemInfoService, useValue: fakedSystemInfoService },
{ provide: SERVICE_CONFIG, useValue: config },
// open auto detect // open auto detect
{ provide: ComponentFixtureAutoDetect, useValue: true } { provide: ComponentFixtureAutoDetect, useValue: true }
] ],
declarations: [
SystemSettingsComponent
]
}); });
}); });
beforeEach(() => { beforeEach(() => {

View File

@ -5,24 +5,22 @@ import {
Output, Output,
EventEmitter, EventEmitter,
ViewChild, ViewChild,
Inject,
OnChanges, OnChanges,
SimpleChanges, SimpleChanges,
ElementRef ElementRef
} from '@angular/core'; } from '@angular/core';
import {NgForm} from '@angular/forms'; import {NgForm} from '@angular/forms';
import {Configuration, StringValueItem} from '../config'; import {Configuration, StringValueItem} from '../config';
import {SERVICE_CONFIG, IServiceConfig} from '../../../entities/service.config'; import { clone, isEmpty, getChanges, compareValue, CURRENT_BASE_HREF } from '../../../../shared/units/utils';
import {clone, isEmpty, getChanges, compareValue} from '../../../utils/utils'; import {ErrorHandler} from '../../../../shared/units/error-handler';
import {ErrorHandler} from '../../../utils/error-handler'; import {ConfirmationMessage} from '../../../global-confirmation-dialog/confirmation-message';
import {ConfirmationMessage} from '../../confirmation-dialog/confirmation-message'; import {ConfirmationDialogComponent} from '../../../../shared/components/confirmation-dialog';
import {ConfirmationDialogComponent} from '../../confirmation-dialog/confirmation-dialog.component'; import {ConfirmationState, ConfirmationTargets} from '../../../../shared/entities/shared.const';
import {ConfirmationState, ConfirmationTargets} from '../../../entities/shared.const'; import {ConfirmationAcknowledgement} from '../../../global-confirmation-dialog/confirmation-state-message';
import {ConfirmationAcknowledgement} from '../../confirmation-dialog/confirmation-state-message'; import { SystemCVEAllowlist, SystemInfo, SystemInfoService,
import { } from '../../../../shared/services';
ConfigurationService, SystemCVEAllowlist, SystemInfo, SystemInfoService, VulnerabilityItem
} from '../../../services';
import {forkJoin} from "rxjs"; import {forkJoin} from "rxjs";
import { ConfigurationService } from "../../../../services/config.service";
const fakePass = 'aWpLOSYkIzJTTU4wMDkx'; const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
const ONE_THOUSAND: number = 1000; const ONE_THOUSAND: number = 1000;
@ -32,7 +30,7 @@ const TARGET_BLANK = "_blank";
@Component({ @Component({
selector: 'system-settings', selector: 'system-settings',
templateUrl: './system-settings.component.html', templateUrl: './system-settings.component.html',
styleUrls: ['./system-settings.component.scss', '../registry-config.component.scss'] styleUrls: ['./system-settings.component.scss']
}) })
export class SystemSettingsComponent implements OnChanges, OnInit { export class SystemSettingsComponent implements OnChanges, OnInit {
config: Configuration = new Configuration(); config: Configuration = new Configuration();
@ -161,7 +159,7 @@ export class SystemSettingsComponent implements OnChanges, OnInit {
this.onGoing = true; this.onGoing = true;
let observables = []; let observables = [];
if (!isEmpty(changes)) { if (!isEmpty(changes)) {
observables.push(this.configService.saveConfigurations(changes)); observables.push(this.configService.saveConfiguration(changes));
} }
if (!compareValue(this.systemAllowlistOrigin, this.systemAllowlist)) { if (!compareValue(this.systemAllowlistOrigin, this.systemAllowlist)) {
observables.push(this.systemInfoService.updateSystemAllowlist(this.systemAllowlist)); observables.push(this.systemInfoService.updateSystemAllowlist(this.systemAllowlist));
@ -197,7 +195,7 @@ export class SystemSettingsComponent implements OnChanges, OnInit {
retrieveConfig(): void { retrieveConfig(): void {
this.onGoing = true; this.onGoing = true;
this.configService.getConfigurations() this.configService.getConfiguration()
.subscribe((configurations: Configuration) => { .subscribe((configurations: Configuration) => {
this.onGoing = false; this.onGoing = false;
// Add two password fields // Add two password fields
@ -263,13 +261,11 @@ export class SystemSettingsComponent implements OnChanges, OnInit {
} }
} }
constructor(@Inject(SERVICE_CONFIG) private configInfo: IServiceConfig, constructor(
private configService: ConfigurationService, private configService: ConfigurationService,
private errorHandler: ErrorHandler, private errorHandler: ErrorHandler,
private systemInfoService: SystemInfoService) { private systemInfoService: SystemInfoService) {
if (this.configInfo && this.configInfo.systemInfoEndpoint) { this.downloadLink = CURRENT_BASE_HREF + "/systeminfo/getcert";
this.downloadLink = this.configInfo.systemInfoEndpoint + "/getcert";
}
} }
ngOnInit() { ngOnInit() {

View File

@ -1,4 +1,4 @@
@import "../base.scss"; @import "../base";
$refrsh-btn-color: #007CBB; $refrsh-btn-color: #007CBB;
.refresh-btn { .refresh-btn {
@include refresh-button @include refresh-button

View File

@ -1,16 +1,16 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { ClarityModule } from '@clr/angular'; import { ClarityModule } from '@clr/angular';
import { SharedModule } from '../../shared/shared.module'; import { SharedTestingModule } from '../../../../shared/shared.module';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing';
import { DistributionInstancesComponent } from './distribution-instances.component'; import { DistributionInstancesComponent } from './distribution-instances.component';
import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service"; import { PreheatService } from "../../../../../../ng-swagger-gen/services/preheat.service";
import { Instance } from '../../../../ng-swagger-gen/models/instance'; import { Instance } from '../../../../../../ng-swagger-gen/models/instance';
import { HttpHeaders, HttpResponse } from '@angular/common/http'; import { HttpHeaders, HttpResponse } from '@angular/common/http';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { delay } from 'rxjs/operators'; import { delay } from 'rxjs/operators';
import { Metadata } from '../../../../ng-swagger-gen/models/metadata'; import { Metadata } from '../../../../../../ng-swagger-gen/models/metadata';
import { DistributionSetupModalComponent } from '../distribution-setup-modal/distribution-setup-modal.component'; import { DistributionSetupModalComponent } from '../distribution-setup-modal/distribution-setup-modal.component';
describe('DistributionInstanceComponent', () => { describe('DistributionInstanceComponent', () => {
@ -101,7 +101,7 @@ describe('DistributionInstanceComponent', () => {
imports: [ imports: [
ClarityModule, ClarityModule,
TranslateModule, TranslateModule,
SharedModule, SharedTestingModule,
HttpClientTestingModule HttpClientTestingModule
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],

View File

@ -1,4 +1,4 @@
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service';
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { import {
Subscription, Subscription,
@ -7,28 +7,24 @@ import {
throwError as observableThrowError throwError as observableThrowError
} from 'rxjs'; } from 'rxjs';
import { DistributionSetupModalComponent } from '../distribution-setup-modal/distribution-setup-modal.component'; import { DistributionSetupModalComponent } from '../distribution-setup-modal/distribution-setup-modal.component';
import { OperationService } from '../../../lib/components/operation/operation.service'; import { OperationService } from '../../../../shared/components/operation/operation.service';
import {
ConfirmationState,
ConfirmationTargets,
ConfirmationButtons
} from '../../shared/shared.const';
import { ConfirmationDialogService } from '../../shared/confirmation-dialog/confirmation-dialog.service';
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message';
import { import {
operateChanges, operateChanges,
OperateInfo, OperateInfo,
OperationState OperationState
} from '../../../lib/components/operation/operate'; } from '../../../../shared/components/operation/operate';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { map, catchError, finalize } from 'rxjs/operators'; import { map, catchError, finalize } from 'rxjs/operators';
import { errorHandler } from '../../../lib/utils/shared/shared.utils'; import { clone, DEFAULT_PAGE_SIZE } from '../../../../shared/units/utils';
import { clone, DEFAULT_PAGE_SIZE } from '../../../lib/utils/utils'; import { Instance } from "../../../../../../ng-swagger-gen/models/instance";
import { Instance } from "../../../../ng-swagger-gen/models/instance"; import { PreheatService } from "../../../../../../ng-swagger-gen/services/preheat.service";
import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service"; import { Metadata } from '../../../../../../ng-swagger-gen/models/metadata';
import { Metadata } from '../../../../ng-swagger-gen/models/metadata';
import { FrontInstance, HEALTHY, UNHEALTHY } from '../distribution-interface'; import { FrontInstance, HEALTHY, UNHEALTHY } from '../distribution-interface';
import { ClrDatagridStateInterface } from '@clr/angular'; import { ClrDatagridStateInterface } from '@clr/angular';
import { ConfirmationDialogService } from "../../../global-confirmation-dialog/confirmation-dialog.service";
import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from "../../../../shared/entities/shared.const";
import { errorHandler } from "../../../../shared/units/shared.utils";
import { ConfirmationMessage } from "../../../global-confirmation-dialog/confirmation-message";
interface MultiOperateData { interface MultiOperateData {
operation: string; operation: string;

View File

@ -1,4 +1,4 @@
import { Instance } from '../../../ng-swagger-gen/models/instance'; import { Instance } from '../../../../../ng-swagger-gen/models/instance';
export class AuthMode { export class AuthMode {
static NONE = 'NONE'; static NONE = 'NONE';

View File

@ -1,12 +1,12 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { ClarityModule } from '@clr/angular'; import { ClarityModule } from '@clr/angular';
import { SharedModule } from '../../shared/shared.module'; import { SharedTestingModule } from '../../../../shared/shared.module';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing';
import { DistributionSetupModalComponent } from './distribution-setup-modal.component'; import { DistributionSetupModalComponent } from './distribution-setup-modal.component';
import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service"; import { PreheatService } from "../../../../../../ng-swagger-gen/services/preheat.service";
import { Instance } from '../../../../ng-swagger-gen/models/instance'; import { Instance } from '../../../../../../ng-swagger-gen/models/instance';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { delay } from 'rxjs/operators'; import { delay } from 'rxjs/operators';
@ -37,7 +37,7 @@ describe('DistributionSetupModalComponent', () => {
imports: [ imports: [
ClarityModule, ClarityModule,
TranslateModule, TranslateModule,
SharedModule, SharedTestingModule,
HttpClientTestingModule HttpClientTestingModule
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],

View File

@ -1,4 +1,4 @@
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../../../shared/services/message-handler.service';
import { import {
Component, Component,
EventEmitter, EventEmitter,
@ -10,18 +10,18 @@ import {
} from '@angular/core'; } from '@angular/core';
import { NgForm } from '@angular/forms'; import { NgForm } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { errorHandler } from '../../../lib/utils/shared/shared.utils'; import { PreheatService } from '../../../../../../ng-swagger-gen/services/preheat.service';
import { PreheatService } from '../../../../ng-swagger-gen/services/preheat.service'; import { Instance } from '../../../../../../ng-swagger-gen/models/instance';
import { Instance } from '../../../../ng-swagger-gen/models/instance';
import { AuthMode, FrontInstance } from '../distribution-interface'; import { AuthMode, FrontInstance } from '../distribution-interface';
import { clone } from '../../../lib/utils/utils'; import { clone } from '../../../../shared/units/utils';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { ClrLoadingState } from '@clr/angular'; import { ClrLoadingState } from '@clr/angular';
import { Metadata } from '../../../../ng-swagger-gen/models/metadata'; import { Metadata } from '../../../../../../ng-swagger-gen/models/metadata';
import { operateChanges, OperateInfo, OperationState } from '../../../lib/components/operation/operate'; import { operateChanges, OperateInfo, OperationState } from '../../../../shared/components/operation/operate';
import { OperationService } from '../../../lib/components/operation/operation.service'; import { OperationService } from '../../../../shared/components/operation/operation.service';
import { debounceTime, distinctUntilChanged, filter, finalize, switchMap } from 'rxjs/operators'; import { debounceTime, distinctUntilChanged, filter, finalize, switchMap } from 'rxjs/operators';
import { Subject, Subscription } from 'rxjs'; import { Subject, Subscription } from 'rxjs';
import { InlineAlertComponent } from "../../../../shared/components/inline-alert/inline-alert.component";
import { errorHandler } from "../../../../shared/units/shared.utils";
const DEFAULT_PROVIDER: string = 'dragonfly'; const DEFAULT_PROVIDER: string = 'dragonfly';

View File

@ -1,11 +1,21 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DistributionInstancesComponent } from './distribution-instances/distribution-instances.component'; import { DistributionInstancesComponent } from './distribution-instances/distribution-instances.component';
import { DistributionSetupModalComponent } from './distribution-setup-modal/distribution-setup-modal.component'; import { DistributionSetupModalComponent } from './distribution-setup-modal/distribution-setup-modal.component';
import { SharedModule } from '../shared/shared.module'; import { SharedModule } from '../../../shared/shared.module';
import { RouterModule, Routes } from "@angular/router";
const routes: Routes = [
{
path: 'instances',
component: DistributionInstancesComponent
},
{ path: '', redirectTo: 'instances', pathMatch: 'full' },
];
@NgModule({ @NgModule({
imports: [CommonModule, SharedModule], imports: [
SharedModule,
RouterModule.forChild(routes)
],
declarations: [ declarations: [
DistributionSetupModalComponent, DistributionSetupModalComponent,
DistributionInstancesComponent DistributionInstancesComponent

View File

@ -2,7 +2,7 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { ClarityModule } from '@clr/angular'; import { ClarityModule } from '@clr/angular';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { SessionService } from "../shared/session.service"; import { SessionService } from "../../../shared/services/session.service";
import { GcPageComponent } from './gc-page.component'; import { GcPageComponent } from './gc-page.component';
describe('GcPageComponent', () => { describe('GcPageComponent', () => {

View File

@ -1,5 +1,5 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { SessionService } from "../shared/session.service"; import { SessionService } from "../../../shared/services/session.service";
@Component({ @Component({
selector: "app-gc-page", selector: "app-gc-page",

View File

@ -0,0 +1,33 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { GcPageComponent } from "./gc-page.component";
import { GcComponent } from "./gc/gc.component";
import { GcHistoryComponent } from "./gc/gc-history/gc-history.component";
import { GcRepoService } from "./gc/gc.service";
import { SharedModule } from "../../../shared/shared.module";
import { GcApiDefaultRepository, GcApiRepository } from "./gc/gc.api.repository";
import { GcViewModelFactory } from "./gc/gc.viewmodel.factory";
const routes: Routes = [
{
path: '',
component: GcPageComponent
}
];
@NgModule({
imports: [
SharedModule,
RouterModule.forChild(routes)
],
declarations: [
GcPageComponent,
GcComponent,
GcHistoryComponent
],
providers: [
GcRepoService,
{provide: GcApiRepository, useClass: GcApiDefaultRepository },
GcViewModelFactory
]
})
export class GcModule {}

View File

@ -1,19 +1,17 @@
import { import {
ComponentFixture, ComponentFixture,
ComponentFixtureAutoDetect, ComponentFixtureAutoDetect,
fakeAsync,
TestBed, TestBed,
tick,
waitForAsync waitForAsync
} from '@angular/core/testing'; } from '@angular/core/testing';
import { SharedModule } from '../../../../utils/shared/shared.module';
import { GcRepoService } from "../gc.service"; import { GcRepoService } from "../gc.service";
import { of } from 'rxjs'; import { of } from 'rxjs';
import { GcViewModelFactory } from "../gc.viewmodel.factory"; import { GcViewModelFactory } from "../gc.viewmodel.factory";
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { ErrorHandler } from '../../../../utils/error-handler'; import { ErrorHandler } from '../../../../../shared/units/error-handler';
import { GcHistoryComponent } from './gc-history.component'; import { GcHistoryComponent } from './gc-history.component';
import { GcJobData } from "../gcLog"; import { GcJobData } from "../gcLog";
import { SharedTestingModule } from "../../../../../shared/shared.module";
describe('GcHistoryComponent', () => { describe('GcHistoryComponent', () => {
let component: GcHistoryComponent; let component: GcHistoryComponent;
@ -64,7 +62,7 @@ describe('GcHistoryComponent', () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [GcHistoryComponent], declarations: [GcHistoryComponent],
imports: [ imports: [
SharedModule, SharedTestingModule,
TranslateModule.forRoot() TranslateModule.forRoot()
], ],
providers: [ providers: [

View File

@ -2,9 +2,9 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
import { GcRepoService } from "../gc.service"; import { GcRepoService } from "../gc.service";
import { GcJobViewModel } from "../gcLog"; import { GcJobViewModel } from "../gcLog";
import { GcViewModelFactory } from "../gc.viewmodel.factory"; import { GcViewModelFactory } from "../gc.viewmodel.factory";
import { ErrorHandler } from "../../../../utils/error-handler"; import { ErrorHandler } from "../../../../../shared/units/error-handler";
import { Subscription, timer } from "rxjs"; import { Subscription, timer } from "rxjs";
import { REFRESH_TIME_DIFFERENCE } from '../../../../entities/shared.const'; import { REFRESH_TIME_DIFFERENCE } from '../../../../../shared/entities/shared.const';
const JOB_STATUS = { const JOB_STATUS = {
PENDING: "pending", PENDING: "pending",
RUNNING: "running" RUNNING: "running"

Some files were not shown because too many files have changed in this diff Show More