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
============
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": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"allowedCommonJsDependencies": [
"swagger-ui",
"js-yaml"
],
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"extractCss": true,
"assets": [
"src/images",
@ -31,12 +36,12 @@
{
"input": "src/css/dark-theme.scss",
"bundleName": "dark-theme",
"lazy": true
"inject": false
},
{
"input": "src/css/light-theme.scss",
"bundleName": "light-theme",
"lazy": true
"inject": false
}
],
"scripts": [
@ -92,9 +97,10 @@
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "src/tsconfig.spec.json",
"tsConfig": "tsconfig.spec.json",
"main": "src/test.ts",
"karmaConfig": "./karma.conf.js",
"polyfills": "src/polyfills.ts",
"karmaConfig": "karma.conf.js",
"scripts": [
"node_modules/core-js/client/shim.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": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-10.0.2.tgz",
"integrity": "sha512-7nM3DrJaqKswwtJlbu2kuKNl+hE8Isr18sKsKvGGpSxQk+G0gO0reDlx2PhUNus7TJTkA1C59vU/JoN8hIvZ4g==",
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-13.0.0.tgz",
"integrity": "sha512-+tzEp8wlqEnw0Gc7jtVRAJ6RteUjXw6JJR4O65KlnxOmJrCGPI0xjV/lKRnQeU0w4i96PQs/jtpL921Wrb7PWg==",
"requires": {
"tslib": "^1.9.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=="
}
"tslib": "^2.0.0"
}
},
"@ngx-translate/http-loader": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-3.0.1.tgz",
"integrity": "sha1-ILD5i8bCUyESnT4zAqs8xInApCo=",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-6.0.0.tgz",
"integrity": "sha512-LCekn6qCbeXWlhESCxU1rAbZz33WzDG0lI7Ig0pYC1o5YxJWrkU9y3Y4tNi+jakQ7R6YhTR2D3ox6APxDtA0wA==",
"requires": {
"tslib": "^1.9.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=="
}
"tslib": "^2.0.0"
}
},
"@nodelib/fs.scandir": {

View File

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

View File

@ -3,6 +3,7 @@
*/
const fs = require('fs');
const data = fs.readFileSync('src/environments/environment.prod.ts', 'utf8').split('\n');
const timestamp = new Date().getTime();
let buildTimestampIndex = 0;
data.forEach((item,index) => {
@ -10,10 +11,29 @@ data.forEach((item,index) => {
buildTimestampIndex = index;
}
});
// modify buildTimestamp value in src/environments/environment.prod.ts file
if (buildTimestampIndex > 0) {
const timestamp = new Date().getTime();
data[buildTimestampIndex] = ` buildTimestamp: ${timestamp},`;
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";

View File

@ -1,7 +1,7 @@
import express from "express";
import { Express } from 'express';
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();

View File

@ -12,40 +12,35 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { CoreModule } from '../core/core.module';
import { RouterModule, Routes } from '@angular/router';
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 { 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 { PasswordSettingService } from './password-setting/password-setting.service';
import { AccountSettingsModalService } from './account-settings/account-settings-modal-service.service';
import { SignInComponent } from "./sign-in/sign-in.component";
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({
imports: [
CoreModule,
RouterModule,
RouterModule.forChild(routes),
SharedModule,
],
declarations: [
PasswordSettingComponent,
AccountSettingsModalComponent,
SignUpComponent,
ForgotPasswordComponent,
ResetPasswordComponent,
SignUpPageComponent],
exports: [
PasswordSettingComponent,
AccountSettingsModalComponent,
ForgotPasswordComponent,
ResetPasswordComponent,
SignUpComponent,
SignUpPageComponent],
providers: [PasswordSettingService, AccountSettingsModalService]
SignUpPageComponent,
SignInComponent,
TopRepoComponent,
],
providers: [
TopRepoService
]
})
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 { TranslateModule, TranslateService } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { AppConfigService } from '../services/app-config.service';
import { SessionService } from '../shared/session.service';
import { AppConfigService } from '../../services/app-config.service';
import { SessionService } from '../../shared/services/session.service';
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 { ClarityModule } from "@clr/angular";
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 { Input, ViewChild, AfterViewChecked } from '@angular/core';
import { NgForm } from '@angular/forms';
import { SessionService } from '../shared/session.service';
import { SignInCredential } from '../shared/sign-in-credential';
import { SignUpComponent } from '../account/sign-up/sign-up.component';
import { ForgotPasswordComponent } from '../account/password-setting/forgot-password/forgot-password.component';
import { AppConfigService } from '../services/app-config.service';
import { AppConfig } from '../services/app-config';
import { User } from '../user/user';
import { SessionService } from '../../shared/services/session.service';
import { SignUpComponent } from '../sign-up/sign-up.component';
import { ForgotPasswordComponent } from '../../base/password-setting/forgot-password/forgot-password.component';
import { AppConfigService } from '../../services/app-config.service';
import { AppConfig } from '../../services/app-config';
import { User } from '../../base/left-side-nav/user/user';
import { CookieService, CookieOptions } from 'ngx-cookie';
import { SkinableConfig } from "../services/skinable-config.service";
import {ModalEvent} from "../base/modal-event";
import {modalEvents} from "../base/modal-events.const";
import {AboutDialogComponent} from "../shared/about-dialog/about-dialog.component";
import { CommonRoutes, CONFIG_AUTH_MODE } from "../../lib/entities/shared.const";
import { SkinableConfig } from "../../services/skinable-config.service";
import {ModalEvent} from "../../base/modal-event";
import {modalEvents} from "../../base/modal-events.const";
import {AboutDialogComponent} from "../../shared/components/about-dialog/about-dialog.component";
import { CommonRoutes, CONFIG_AUTH_MODE } from "../../shared/entities/shared.const";
import { SignInCredential } from "./sign-in-credential";
// Define status flags for signing in states
export const signInStatusNormal = 0;
@ -247,7 +247,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
// Remeber me
this.remeberMe();
// Redirect to the right route
// Redirect to the right router-guard
if (this.redirectUrl === "") {
// Routing to the default location
this.router.navigateByUrl(CommonRoutes.HARBOR_DEFAULT);

View File

@ -13,10 +13,10 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { SignInCredential } from '../shared/sign-in-credential';
import { map, catchError } from "rxjs/operators";
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';
/**
*

View File

@ -8,7 +8,7 @@ import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs';
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';
describe('TopRepoComponent', () => {
let component: TopRepoComponent;

View File

@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
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 { Repository } from "../../../../ng-swagger-gen/models/repository";
import { ListMode } from "../../../lib/entities/shared.const";
import { Repository } from "../../../../../ng-swagger-gen/models/repository";
import { ListMode } from "../../../shared/entities/shared.const";
@Component({

View File

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

View File

@ -1,13 +1,13 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
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 { MessageService } from '../../global-message/message.service';
import { MessageService } from '../../shared/components/global-message/message.service';
import { RouterTestingModule } from '@angular/router/testing';
import { SignUpPageComponent } from './sign-up-page.component';
import { FormsModule } from '@angular/forms';
import { NewUserFormComponent } from '../../shared/new-user-form/new-user-form.component';
import { SessionService } from '../../shared/session.service';
import { NewUserFormComponent } from '../../shared/components/new-user-form/new-user-form.component';
import { SessionService } from '../../shared/services/session.service';
describe('SignUpPageComponent', () => {
let component: SignUpPageComponent;

View File

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

View File

@ -1,16 +1,16 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { ClarityModule } from "@clr/angular";
import { SignUpComponent } from './sign-up.component';
import { SessionService } from '../../shared/session.service';
import { UserService } from '../../user/user.service';
import { SessionService } from '../../shared/services/session.service';
import { UserService } from '../../base/left-side-nav/user/user.service';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/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 { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
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', () => {
let component: SignUpComponent;

View File

@ -12,14 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Output, ViewChild, EventEmitter } from '@angular/core';
import { Modal } from '../../../lib/services/interface';
import { NewUserFormComponent } from '../../shared/new-user-form/new-user-form.component';
import { User } from '../../user/user';
import { SessionService } from '../../shared/session.service';
import { UserService } from '../../user/user.service';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { Modal } from '../../shared/services/interface';
import { NewUserFormComponent } from '../../shared/components/new-user-form/new-user-form.component';
import { User } from '../../base/left-side-nav/user/user';
import { SessionService } from '../../shared/services/session.service';
import { UserService } from '../../base/left-side-nav/user/user.service';
import { InlineAlertComponent } from "../../shared/components/inline-alert/inline-alert.component";
@Component({
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 { CookieService } from 'ngx-cookie';
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 { AppComponent } from './app.component';
import { ClarityModule } from "@clr/angular";

View File

@ -13,15 +13,13 @@
// limitations under the License.
import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
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 { ThemeService } from './services/theme.service';
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';
@ -31,17 +29,16 @@ const HAS_STYLE_MODE: string = 'styleModeLocal';
})
export class AppComponent {
themeArray: ThemeInterface[] = clone(THEME_ARRAY);
styleMode: string = this.themeArray[0].showStyle;
constructor(
private translate: TranslateService,
private cookie: CookieService,
private session: SessionService,
private appConfigService: AppConfigService,
private titleService: Title,
public theme: ThemeService
) {
// init language
this.initLanguage();
// Override page title
let key: string = "APP_TITLE.HARBOR";
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
// limitations under the License.
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 { InterceptHttpService } from './services/intercept-http.service';
import { BaseModule } from './base/base.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 { 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';
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) {
function initConfig(configService: AppConfigService, skinableService: SkinableConfig) {
return () => {
skinableService.getCustomFile().subscribe();
configService.load().subscribe();
};
}
export function getCurrentLanguage(translateService: TranslateService) {
return translateService.currentLang;
class MyMissingTranslationHandler implements MissingTranslationHandler {
handle(params: MissingTranslationHandlerParams) {
const missingText: string = "{Harbor}";
return params.key || missingText;
}
}
@NgModule({
declarations: [
AppComponent,
ProjectConfigComponent,
VulnerabilityPageComponent,
GcPageComponent,
InterrogationServicesComponent,
LabelsComponent,
ProjectQuotasComponent
],
imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: HarborTranslateLoaderService
},
missingTranslationHandler: {
provide: MissingTranslationHandler,
useClass: MyMissingTranslationHandler
}
}),
BrowserModule,
SharedModule,
BaseModule,
AccountModule,
SignInModule,
BrowserAnimationsModule,
HttpClientModule,
HarborRoutingModule,
ConfigurationModule,
DeveloperCenterModule,
OidcOnboardModule,
LicenseModule,
HarborLibraryModule,
AllPipesModule,
DistributionModule,
SystemRobotAccountsModule
],
exports: [
CookieModule.forRoot(),
],
providers: [
AppConfigService,
@ -102,9 +84,10 @@ export function getCurrentLanguage(translateService: TranslateService) {
deps: [AppConfigService, SkinableConfig],
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: [
CUSTOM_ELEMENTS_SCHEMA

View File

@ -2,12 +2,14 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { catchError, map } from 'rxjs/operators';
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 {
constructor(private http: HttpClient) { }

View File

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

View File

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

View File

@ -13,37 +13,127 @@
// limitations under the License.
import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module';
import { RouterModule } 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 { RouterModule, Routes } from '@angular/router';
import { HarborShellComponent } from './harbor-shell/harbor-shell.component';
import { SearchResultComponent } from './global-search/search-result.component';
import { SearchTriggerService } from './global-search/search-trigger.service';
import { SystemAdminGuard } from "../shared/router-guard/system-admin-activate.service";
import { MemberGuard } from "../shared/router-guard/member-guard-activate.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({
imports: [
SharedModule,
ProjectModule,
UserModule,
AccountModule,
RouterModule,
GroupModule
RouterModule.forChild(routes),
],
declarations: [
NavigatorComponent,
GlobalSearchComponent,
FooterComponent,
HarborShellComponent,
SearchResultComponent,
],
exports: [ HarborShellComponent, NavigatorComponent, SearchResultComponent ],
providers: [SearchTriggerService]
PasswordSettingComponent,
AccountSettingsModalComponent,
ForgotPasswordComponent,
GlobalConfirmationDialogComponent
]
})
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 { ConfirmationAcknowledgement } from './confirmation-state-message';
@Injectable()
@Injectable({
providedIn: 'root',
})
export class ConfirmationDialogService {
confirmationAnnoucedSource = new Subject<ConfirmationMessage>();
confirmationConfirmSource = new Subject<ConfirmationAcknowledgement>();

View File

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

View File

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

View File

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

View File

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

View File

@ -1,26 +1,26 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
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 { 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 { ClarityModule } from "@clr/angular";
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 { AccountSettingsModalComponent } from '../../account/account-settings/account-settings-modal.component';
import { PasswordSettingComponent } from '../../account/password-setting/password-setting.component';
import { AboutDialogComponent } from '../../shared/about-dialog/about-dialog.component';
import { PasswordSettingComponent } from '../password-setting/password-setting.component';
import { AboutDialogComponent } from '../../shared/components/about-dialog/about-dialog.component';
import { FormsModule } from '@angular/forms';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
import { AccountSettingsModalService } from '../../account/account-settings/account-settings-modal-service.service';
import { PasswordSettingService } from '../../account/password-setting/password-setting.service';
import { MessageHandlerService } from '../../shared/services/message-handler.service';
import { PasswordSettingService } from '../password-setting/password-setting.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 { 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', () => {
let component: HarborShellComponent;

View File

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

View File

@ -1,17 +1,17 @@
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 { AppConfigService } from '../../services/app-config.service';
import { ConfigurationService } from '../config.service';
import { AppConfigService } from '../../../../services/app-config.service';
import { ConfigurationService } from '../../../../services/config.service';
import { ConfigurationAuthComponent } from './config-auth.component';
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 { of } from 'rxjs';
import { ErrorHandler } from "../../../lib/utils/error-handler";
import { SystemInfoService } from "../../../lib/services";
import { clone } from '../../../lib/utils/utils';
import { CONFIG_AUTH_MODE } from '../../../lib/entities/shared.const';
import { ErrorHandler } from "../../../../shared/units/error-handler";
import { SystemInfoService } from "../../../../shared/services";
import { clone } from '../../../../shared/units/utils';
import { CONFIG_AUTH_MODE } from '../../../../shared/entities/shared.const';
describe('ConfigurationAuthComponent', () => {
let component: ConfigurationAuthComponent;

View File

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

View File

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

View File

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

View File

@ -13,37 +13,33 @@
// limitations under the License.
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 { ConfigurationService } from "./config.service";
import { ConfirmMessageHandler } from "./config.msg.utils";
import { ConfigurationAuthComponent } from "./auth/config-auth.component";
import { ConfigurationEmailComponent } from "./email/config-email.component";
import { ConfigurationScannerComponent } from "./scanner/config-scanner.component";
import { NewScannerModalComponent } from "./scanner/new-scanner-modal/new-scanner-modal.component";
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";
import { SystemSettingsComponent } from "./system/system-settings.component";
import { RouterModule, Routes } from "@angular/router";
const routes: Routes = [
{
path: '',
component: ConfigurationComponent
}
];
@NgModule({
imports: [CoreModule, SharedModule],
imports: [
SharedModule,
RouterModule.forChild(routes)
],
declarations: [
ConfigurationComponent,
ConfigurationAuthComponent,
ConfigurationEmailComponent,
ConfigurationScannerComponent,
NewScannerModalComponent,
NewScannerFormComponent,
ScannerMetadataComponent
SystemSettingsComponent
],
exports: [ConfigurationComponent],
providers: [
ConfigurationService,
ConfirmMessageHandler,
ConfigScannerService,
]
})
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 { ConfirmationDialogService } from "../../global-confirmation-dialog/confirmation-dialog.service";
import { ConfirmationTargets } from "../../../shared/entities/shared.const";
import { ConfirmationMessage } from "../../global-confirmation-dialog/confirmation-message";
@Injectable()
export class ConfirmMessageHandler {

View File

@ -1,12 +1,12 @@
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 { ConfigurationService } from '../config.service';
import { ConfigurationService } from '../../../../services/config.service';
import { ConfigurationEmailComponent } from './config-email.component';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { clone } from '../../../lib/utils/utils';
import { clone } from '../../../../shared/units/utils';
import { of } from 'rxjs';
describe('ConfigurationEmailComponent', () => {

View File

@ -13,13 +13,13 @@
// limitations under the License.
import { Component, Input, ViewChild, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core';
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 { ConfigurationService } from '../config.service';
import { Configuration } from "../../../lib/components/config/config";
import { isEmpty, getChanges as getChangesFunc, clone } from "../../../lib/utils/utils";
import { errorHandler } from "../../../lib/utils/shared/shared.utils";
const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
import { ConfigurationService } from '../../../../services/config.service';
import { Configuration } from "../config";
import { isEmpty, getChanges as getChangesFunc, clone } from "../../../../shared/units/utils";
import { errorHandler } from "../../../../shared/units/shared.utils";
@Component({
selector: 'config-email',
templateUrl: "config-email.component.html",

View File

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

View File

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

View File

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

View File

@ -1,16 +1,16 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
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 { HttpClientTestingModule } from '@angular/common/http/testing';
import { DistributionInstancesComponent } from './distribution-instances.component';
import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service";
import { Instance } from '../../../../ng-swagger-gen/models/instance';
import { PreheatService } from "../../../../../../ng-swagger-gen/services/preheat.service";
import { Instance } from '../../../../../../ng-swagger-gen/models/instance';
import { HttpHeaders, HttpResponse } from '@angular/common/http';
import { of } from 'rxjs';
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';
describe('DistributionInstanceComponent', () => {
@ -101,7 +101,7 @@ describe('DistributionInstanceComponent', () => {
imports: [
ClarityModule,
TranslateModule,
SharedModule,
SharedTestingModule,
HttpClientTestingModule
],
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 {
Subscription,
@ -7,28 +7,24 @@ import {
throwError as observableThrowError
} from 'rxjs';
import { DistributionSetupModalComponent } from '../distribution-setup-modal/distribution-setup-modal.component';
import { OperationService } from '../../../lib/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 { OperationService } from '../../../../shared/components/operation/operation.service';
import {
operateChanges,
OperateInfo,
OperationState
} from '../../../lib/components/operation/operate';
} from '../../../../shared/components/operation/operate';
import { TranslateService } from '@ngx-translate/core';
import { map, catchError, finalize } from 'rxjs/operators';
import { errorHandler } from '../../../lib/utils/shared/shared.utils';
import { clone, DEFAULT_PAGE_SIZE } from '../../../lib/utils/utils';
import { Instance } from "../../../../ng-swagger-gen/models/instance";
import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service";
import { Metadata } from '../../../../ng-swagger-gen/models/metadata';
import { clone, DEFAULT_PAGE_SIZE } from '../../../../shared/units/utils';
import { Instance } from "../../../../../../ng-swagger-gen/models/instance";
import { PreheatService } from "../../../../../../ng-swagger-gen/services/preheat.service";
import { Metadata } from '../../../../../../ng-swagger-gen/models/metadata';
import { FrontInstance, HEALTHY, UNHEALTHY } from '../distribution-interface';
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 {
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 {
static NONE = 'NONE';

View File

@ -1,12 +1,12 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
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 { HttpClientTestingModule } from '@angular/common/http/testing';
import { DistributionSetupModalComponent } from './distribution-setup-modal.component';
import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service";
import { Instance } from '../../../../ng-swagger-gen/models/instance';
import { PreheatService } from "../../../../../../ng-swagger-gen/services/preheat.service";
import { Instance } from '../../../../../../ng-swagger-gen/models/instance';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
@ -37,7 +37,7 @@ describe('DistributionSetupModalComponent', () => {
imports: [
ClarityModule,
TranslateModule,
SharedModule,
SharedTestingModule,
HttpClientTestingModule
],
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,
EventEmitter,
@ -10,18 +10,18 @@ import {
} from '@angular/core';
import { NgForm } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { errorHandler } from '../../../lib/utils/shared/shared.utils';
import { PreheatService } from '../../../../ng-swagger-gen/services/preheat.service';
import { Instance } from '../../../../ng-swagger-gen/models/instance';
import { PreheatService } from '../../../../../../ng-swagger-gen/services/preheat.service';
import { Instance } from '../../../../../../ng-swagger-gen/models/instance';
import { AuthMode, FrontInstance } from '../distribution-interface';
import { clone } from '../../../lib/utils/utils';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { clone } from '../../../../shared/units/utils';
import { ClrLoadingState } from '@clr/angular';
import { Metadata } from '../../../../ng-swagger-gen/models/metadata';
import { operateChanges, OperateInfo, OperationState } from '../../../lib/components/operation/operate';
import { OperationService } from '../../../lib/components/operation/operation.service';
import { Metadata } from '../../../../../../ng-swagger-gen/models/metadata';
import { operateChanges, OperateInfo, OperationState } from '../../../../shared/components/operation/operate';
import { OperationService } from '../../../../shared/components/operation/operation.service';
import { debounceTime, distinctUntilChanged, filter, finalize, switchMap } from 'rxjs/operators';
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';

View File

@ -1,11 +1,21 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DistributionInstancesComponent } from './distribution-instances/distribution-instances.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({
imports: [CommonModule, SharedModule],
imports: [
SharedModule,
RouterModule.forChild(routes)
],
declarations: [
DistributionSetupModalComponent,
DistributionInstancesComponent

View File

@ -2,7 +2,7 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { ClarityModule } from '@clr/angular';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/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';
describe('GcPageComponent', () => {

View File

@ -1,5 +1,5 @@
import { Component, OnInit } from "@angular/core";
import { SessionService } from "../shared/session.service";
import { SessionService } from "../../../shared/services/session.service";
@Component({
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 {
ComponentFixture,
ComponentFixtureAutoDetect,
fakeAsync,
TestBed,
tick,
waitForAsync
} from '@angular/core/testing';
import { SharedModule } from '../../../../utils/shared/shared.module';
import { GcRepoService } from "../gc.service";
import { of } from 'rxjs';
import { GcViewModelFactory } from "../gc.viewmodel.factory";
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 { GcJobData } from "../gcLog";
import { SharedTestingModule } from "../../../../../shared/shared.module";
describe('GcHistoryComponent', () => {
let component: GcHistoryComponent;
@ -64,7 +62,7 @@ describe('GcHistoryComponent', () => {
TestBed.configureTestingModule({
declarations: [GcHistoryComponent],
imports: [
SharedModule,
SharedTestingModule,
TranslateModule.forRoot()
],
providers: [

View File

@ -2,9 +2,9 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
import { GcRepoService } from "../gc.service";
import { GcJobViewModel } from "../gcLog";
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 { REFRESH_TIME_DIFFERENCE } from '../../../../entities/shared.const';
import { REFRESH_TIME_DIFFERENCE } from '../../../../../shared/entities/shared.const';
const JOB_STATUS = {
PENDING: "pending",
RUNNING: "running"

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