Merge pull request #2112 from vmware/master-ui-aot

Updates for AoT building.
This commit is contained in:
kun wang 2017-04-24 17:22:32 +08:00 committed by GitHub
commit 6acf49581c
96 changed files with 580 additions and 478 deletions

10
.gitignore vendored
View File

@ -29,6 +29,16 @@ src/ui_ng/typings/
**/node_modules **/node_modules
**/ssl/ **/ssl/
**/proxy.config.json **/proxy.config.json
src/ui_ng/src/**/*.js
src/ui_ng/src/**/*.js.map
src/ui_ng/src/**/*.json
**/npm*.log **/npm*.log
src/ui_ng/aot/**/*.js
src/ui_ng/aot/**/*.js.map
src/ui_ng/aot/**/*.json
**/*ngsummary.json **/*ngsummary.json
**/*ngfactory.ts **/*ngfactory.ts

View File

@ -97,7 +97,7 @@ script:
- docker-compose -f make/docker-compose.test.yml down - docker-compose -f make/docker-compose.test.yml down
- sudo rm -rf /data/config/* - sudo rm -rf /data/config/*
- ls /data/cert - ls /data/cert
- sudo make install GOBUILDIMAGE=golang:1.7.3 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:0.8.4 NOTARYFLAG=true - sudo make install GOBUILDIMAGE=golang:1.7.3 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.1.0 NOTARYFLAG=true
- docker ps - docker ps
- ./tests/notarytest.sh - ./tests/notarytest.sh

View File

@ -86,6 +86,8 @@ NOTARYVERSION=server-0.5.0
NOTARYSIGNERVERSION=signer-0.5.0 NOTARYSIGNERVERSION=signer-0.5.0
MARIADBVERSION=mariadb-10.1.10 MARIADBVERSION=mariadb-10.1.10
HTTPPROXY= HTTPPROXY=
REBUILDCLARITYFLAG=false
NEWCLARITYVERSION=
#clarity parameters #clarity parameters
CLARITYIMAGE=vmware/harbor-clarity-ui-builder[:tag] CLARITYIMAGE=vmware/harbor-clarity-ui-builder[:tag]
@ -149,6 +151,7 @@ MAKEFILEPATH_PHOTON=$(MAKEPATH)/photon
DOCKERFILEPATH_COMMON=$(MAKEPATH)/common DOCKERFILEPATH_COMMON=$(MAKEPATH)/common
DOCKERFILEPATH_DB=$(DOCKERFILEPATH_COMMON)/db DOCKERFILEPATH_DB=$(DOCKERFILEPATH_COMMON)/db
DOCKERFILENAME_DB=Dockerfile DOCKERFILENAME_DB=Dockerfile
DOCKERFILE_CLARITY=$(MAKEPATH)/dev/nodeclarity/Dockerfile
# docker image name # docker image name
DOCKERIMAGENAME_ADMINSERVER=vmware/harbor-adminserver DOCKERIMAGENAME_ADMINSERVER=vmware/harbor-adminserver
@ -156,6 +159,7 @@ DOCKERIMAGENAME_UI=vmware/harbor-ui
DOCKERIMAGENAME_JOBSERVICE=vmware/harbor-jobservice DOCKERIMAGENAME_JOBSERVICE=vmware/harbor-jobservice
DOCKERIMAGENAME_LOG=vmware/harbor-log DOCKERIMAGENAME_LOG=vmware/harbor-log
DOCKERIMAGENAME_DB=vmware/harbor-db DOCKERIMAGENAME_DB=vmware/harbor-db
DOCKERIMAGENAME_CLATIRY=vmware/harbor-clarity-ui-builder
# docker-compose files # docker-compose files
DOCKERCOMPOSEFILEPATH=$(MAKEPATH) DOCKERCOMPOSEFILEPATH=$(MAKEPATH)
@ -354,6 +358,24 @@ package_offline: compile build modify_sourcefiles modify_composefile
@rm -rf $(HARBORPKG) @rm -rf $(HARBORPKG)
@echo "Done." @echo "Done."
refresh_clarity_builder:
@if [ "$(REBUILDCLIATRYFLAG)" = "true" ] ; then \
echo "set http proxy.."; \
if [ "$(HTTPPROXY)" != "" ] ; then \
$(SEDCMD) -i 's/__proxy__/--proxy $(HTTPPROXY)/g' $(DOCKERFILE_CLARITY) ; \
else \
$(SEDCMD) -i 's/__proxy__/ /g' $(DOCKERFILE_CLARITY) ; \
fi ; \
echo "build new clarity image.."; \
$(DOCKERBUILD) -f $(DOCKERFILE_CLARITY) -t $(DOCKERIMAGENAME_CLATIRY):$(NEWCLARITYVERSION) . ; \
echo "push clarity image.."; \
$(DOCKERTAG) $(DOCKERIMAGENAME_CLATIRY):$(NEWCLARITYVERSION) $(DOCKERIMAGENAME_CLATIRY):$(NEWCLARITYVERSION); \
$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_CLATIRY):$(NEWCLARITYVERSION) \
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER); \
echo "remove local clarity image.."; \
$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_ADMINSERVER):$(NEWCLARITYVERSION); \
fi
pushimage: pushimage:
@echo "pushing harbor images ..." @echo "pushing harbor images ..."

View File

@ -9,10 +9,12 @@ COPY src/ui_ng/yarn.lock /clarity-seed
COPY make/dev/nodeclarity/angular-cli.json /clarity-seed COPY make/dev/nodeclarity/angular-cli.json /clarity-seed
COPY make/dev/nodeclarity/entrypoint.sh / COPY make/dev/nodeclarity/entrypoint.sh /
COPY src/ui_ng/tsconfig-aot.json /clarity-seed
COPY src/ui_ng/rollup-config.js /clarity-seed
WORKDIR /clarity-seed WORKDIR /clarity-seed
RUN npm install -g @angular/cli && \ RUN npm __proxy__ install -g @angular/cli && \
npm install && \ npm __proxy__ install && \
chmod u+x /entrypoint.sh chmod u+x /entrypoint.sh
VOLUME ["/clarity-seed", "/clarity-seed/dist"]
VOLUME ["/clarity-seed", "/clarity-seed/dist"]

View File

@ -19,7 +19,17 @@ if [ ! -z "$npm_proxy" -a "$npm_proxy" != " " ]; then
fi fi
npm install npm install
ng build
./node_modules/.bin/ngc -p tsconfig-aot.json
sed -i 's/* as//g' src/app/shared/gauge/gauge.component.js
./node_modules/.bin/rollup -c rollup-config.js
cp -r ./src/i18n/ dist/ cp -r ./src/i18n/ dist/
cp ./src/styles.css dist/
cp ./node_modules/clarity-icons/clarity-icons.min.css dist/
cp ./node_modules/mutationobserver-shim/dist/mutationobserver.min.js dist/
cp ./node_modules/@webcomponents/custom-elements/custom-elements.min.js dist/
cp ./node_modules/clarity-icons/clarity-icons.min.js dist/
cp ./node_modules/clarity-ui/clarity-ui.min.css dist/
cp -r ./node_modules/clarity-icons/shapes/ dist/

View File

@ -15,13 +15,16 @@
Loading... Loading...
</div> </div>
</harbor-app> </harbor-app>
<script type="text/javascript" src="/static/inline.bundle.js"></script>
<script type="text/javascript" src="/static/scripts.bundle.js"> <link rel="stylesheet" href="/static/clarity-ui.min.css">
</script> <link rel="stylesheet" href="/static/clarity-icons.min.css">
<script type="text/javascript" src="/static/styles.bundle.js"> <link rel="stylesheet" href="/static/styles.css">
</script>
<script type="text/javascript" src="/static/vendor.bundle.js"></script> <script src="/static/mutationobserver.min.js"></script>
<script type="text/javascript" src="/static/main.bundle.js"></script> <script src="/static/custom-elements.min.js"></script>
<script src="/static/clarity-icons.min.js"></script>
<script src="/static/build.min.js"></script>
</body> </body>
</html> </html>

View File

@ -1,63 +1,70 @@
{ {
"name": "harbor", "name": "harbor",
"version": "0.6.0", "version": "1.1.0",
"description": "Harbor UI with Clarity", "description": "Harbor UI with Clarity",
"angular-cli": {}, "angular-cli": {},
"scripts": { "scripts": {
"start": "ng serve --ssl 1 --ssl-key ssl/server.key --ssl-cert ssl/server.crt --host 0.0.0.0 --proxy-config proxy.config.json", "start": "ng serve --ssl 1 --ssl-key ssl/server.key --ssl-cert ssl/server.crt --host 0.0.0.0 --proxy-config proxy.config.json",
"lint": "tslint \"src/**/*.ts\"", "lint": "tslint \"src/**/*.ts\"",
"test": "ng test --single-run", "test": "ng test --single-run",
"pree2e": "webdriver-manager update", "pree2e": "webdriver-manager update",
"e2e": "protractor" "e2e": "protractor"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/common": "^2.4.1", "@angular/animations": "^4.0.1",
"@angular/compiler": "^2.4.1", "@angular/common": "^4.0.1",
"@angular/core": "^2.4.1", "@angular/compiler": "^4.0.1",
"@angular/forms": "^2.4.1", "@angular/compiler-cli": "^4.0.2",
"@angular/http": "^2.4.1", "@angular/core": "^4.0.1",
"@angular/platform-browser": "^2.4.1", "@angular/forms": "^4.0.1",
"@angular/platform-browser-dynamic": "^2.4.1", "@angular/http": "^4.0.1",
"@angular/router": "^3.4.1", "@angular/platform-browser": "^4.0.1",
"@ngx-translate/core": "^6.0.0", "@angular/platform-browser-dynamic": "^4.0.1",
"@ngx-translate/http-loader": "0.0.3", "@angular/platform-server": "^4.0.2",
"@webcomponents/custom-elements": "1.0.0-alpha.3", "@angular/router": "^4.0.1",
"angular2-cookie": "^1.2.6", "@ngx-translate/core": "^6.0.0",
"clarity-angular": "0.8.7", "@ngx-translate/http-loader": "0.0.3",
"clarity-icons": "0.8.7", "@types/jquery": "^2.0.41",
"clarity-ui": "0.8.7", "@webcomponents/custom-elements": "1.0.0-alpha.3",
"core-js": "^2.4.1", "angular2-cookie": "^1.2.6",
"fs": "0.0.1-security", "clarity-angular": "^0.9.0",
"jquery": "^2.2.4", "clarity-icons": "^0.9.0",
"mutationobserver-shim": "^0.3.2", "clarity-ui": "^0.9.0",
"rxjs": "^5.0.1", "core-js": "^2.4.1",
"ts-helpers": "^1.1.1", "mutationobserver-shim": "^0.3.2",
"web-animations-js": "^2.2.1", "ngx-cookie": "^1.0.0",
"zone.js": "^0.7.2" "rxjs": "^5.0.1",
}, "ts-helpers": "^1.1.1",
"devDependencies": { "web-animations-js": "^2.2.1",
"@angular/compiler-cli": "^2.4.1", "zone.js": "^0.8.4"
"@angular/cli": "^1.0.0", },
"@types/core-js": "^0.9.34", "devDependencies": {
"@types/jasmine": "^2.2.30", "@angular/cli": "^1.0.0",
"@types/node": "^6.0.42", "@angular/compiler-cli": "^4.0.1",
"bootstrap": "4.0.0-alpha.5", "@types/core-js": "^0.9.34",
"codelyzer": "~1.0.0-beta.3", "@types/jasmine": "~2.2.30",
"enhanced-resolve": "^3.0.0", "@types/node": "^6.0.42",
"jasmine-core": "2.4.1", "bootstrap": "4.0.0-alpha.5",
"jasmine-spec-reporter": "2.5.0", "codelyzer": "~2.0.0-beta.4",
"karma": "1.2.0", "enhanced-resolve": "^3.0.0",
"karma-cli": "^1.0.1", "jasmine-core": "2.4.1",
"karma-jasmine": "^1.0.2", "jasmine-spec-reporter": "2.5.0",
"karma-mocha-reporter": "^2.2.1", "karma": "1.2.0",
"karma-phantomjs-launcher": "^1.0.0", "karma-cli": "^1.0.1",
"karma-remap-istanbul": "^0.2.1", "karma-jasmine": "^1.0.2",
"protractor": "4.0.9", "karma-mocha-reporter": "^2.2.1",
"ts-node": "1.2.1", "karma-phantomjs-launcher": "^1.0.0",
"tslint": "^4.1.1", "karma-remap-istanbul": "^0.2.1",
"typescript": "~2.2.1", "protractor": "4.0.9",
"typings": "^1.4.0", "rollup": "^0.41.6",
"webdriver-manager": "10.2.5" "rollup-plugin-commonjs": "^8.0.2",
} "rollup-plugin-node-resolve": "^3.0.0",
} "rollup-plugin-uglify": "^1.0.1",
"ts-node": "1.2.1",
"tslint": "^4.1.1",
"typescript": "~2.2.0",
"typings": "^1.4.0",
"webdriver-manager": "10.2.5"
}
}

View File

@ -0,0 +1,28 @@
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify';
export default {
entry: 'src/main-aot.js',
dest: 'dist/build.min.js', // output a single application compressed file.
sourceMap: false,
format: 'iife',
onwarn: function(warning) {
// Skip certain warnings
// should intercept ... but doesn't in some rollup versions
if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
// intercepts in some rollup versions
if ( typeof warning === 'string' && warning.indexOf("The 'this' keyword is equivalent to 'undefined'") > -1 ) { return; }
// console.warn everything else
console.warn( warning.message );
},
plugins: [
nodeResolve({jsnext: true, module: true, browser: true}),
commonjs({
include: ['node_modules/**']
}),
uglify()
]
}

View File

@ -31,21 +31,21 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
account: SessionUser; account: SessionUser;
error: any = null; error: any = null;
originalStaticData: SessionUser; originalStaticData: SessionUser;
private emailTooltip: string = 'TOOLTIP.EMAIL'; emailTooltip: string = 'TOOLTIP.EMAIL';
private validationStateMap: any = { private validationStateMap: any = {
"account_settings_email": true, "account_settings_email": true,
"account_settings_full_name": true "account_settings_full_name": true
}; };
private mailAlreadyChecked = {}; mailAlreadyChecked = {};
private isOnCalling: boolean = false; isOnCalling: boolean = false;
private formValueChanged: boolean = false; formValueChanged: boolean = false;
private checkOnGoing: boolean = false; checkOnGoing: boolean = false;
accountFormRef: NgForm; accountFormRef: NgForm;
@ViewChild("accountSettingsFrom") accountForm: NgForm; @ViewChild("accountSettingsFrom") accountForm: NgForm;
@ViewChild(InlineAlertComponent) @ViewChild(InlineAlertComponent)
private inlineAlert: InlineAlertComponent; inlineAlert: InlineAlertComponent;
constructor( constructor(
private session: SessionService, private session: SessionService,
@ -56,11 +56,11 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
this.account = Object.assign({}, this.session.getCurrentUser()); this.account = Object.assign({}, this.session.getCurrentUser());
} }
private getValidationState(key: string): boolean { getValidationState(key: string): boolean {
return this.validationStateMap[key]; return this.validationStateMap[key];
} }
private handleValidation(key: string, flag: boolean): void { handleValidation(key: string, flag: boolean): void {
if (flag) { if (flag) {
//Checking //Checking
let cont = this.accountForm.controls[key]; let cont = this.accountForm.controls[key];
@ -104,7 +104,7 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
} }
} }
private isUserDataChange(): boolean { isUserDataChange(): boolean {
if (!this.originalStaticData || !this.account) { if (!this.originalStaticData || !this.account) {
return false; return false;
} }
@ -215,7 +215,7 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
}); });
} }
confirmCancel(): void { confirmCancel($event: any): void {
this.inlineAlert.close(); this.inlineAlert.close();
this.opened = false; this.opened = false;
} }

View File

@ -25,14 +25,14 @@ import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.com
}) })
export class ForgotPasswordComponent { export class ForgotPasswordComponent {
opened: boolean = false; opened: boolean = false;
private onGoing: boolean = false; onGoing: boolean = false;
private email: string = ""; email: string = "";
private validationState: boolean = true; validationState: boolean = true;
private isSuccess: boolean = false; isSuccess: boolean = false;
@ViewChild("forgotPasswordFrom") forgotPwdForm: NgForm; @ViewChild("forgotPasswordFrom") forgotPwdForm: NgForm;
@ViewChild(InlineAlertComponent) @ViewChild(InlineAlertComponent)
private inlineAlert: InlineAlertComponent; inlineAlert: InlineAlertComponent;
constructor(private pwdService: PasswordSettingService) { } constructor(private pwdService: PasswordSettingService) { }

View File

@ -33,8 +33,8 @@ export class PasswordSettingComponent implements AfterViewChecked {
reNewPwd: string = ""; reNewPwd: string = "";
error: any = null; error: any = null;
private formValueChanged: boolean = false; formValueChanged: boolean = false;
private onCalling: boolean = false; onCalling: boolean = false;
private validationStateMap: any = { private validationStateMap: any = {
"newPassword": true, "newPassword": true,
"reNewPassword": true "reNewPassword": true
@ -43,7 +43,7 @@ export class PasswordSettingComponent implements AfterViewChecked {
pwdFormRef: NgForm; pwdFormRef: NgForm;
@ViewChild("changepwdForm") pwdForm: NgForm; @ViewChild("changepwdForm") pwdForm: NgForm;
@ViewChild(InlineAlertComponent) @ViewChild(InlineAlertComponent)
private inlineAlert: InlineAlertComponent; inlineAlert: InlineAlertComponent;
constructor( constructor(
private passwordService: PasswordSettingService, private passwordService: PasswordSettingService,
@ -68,11 +68,11 @@ export class PasswordSettingComponent implements AfterViewChecked {
return this.onCalling; return this.onCalling;
} }
private getValidationState(key: string): boolean { getValidationState(key: string): boolean {
return this.validationStateMap[key]; return this.validationStateMap[key];
} }
private handleValidation(key: string, flag: boolean): void { handleValidation(key: string, flag: boolean): void {
if (flag) { if (flag) {
//Checking //Checking
let cont = this.pwdForm.controls[key]; let cont = this.pwdForm.controls[key];
@ -139,7 +139,7 @@ export class PasswordSettingComponent implements AfterViewChecked {
} }
} }
confirmCancel(): void { confirmCancel($event: any): void {
this.opened = false; this.opened = false;
} }

View File

@ -23,11 +23,11 @@ const resetPasswordEndpoint = "/reset";
@Injectable() @Injectable()
export class PasswordSettingService { export class PasswordSettingService {
private headers: Headers = new Headers({ headers: Headers = new Headers({
"Accept": 'application/json', "Accept": 'application/json',
"Content-Type": 'application/json' "Content-Type": 'application/json'
}); });
private options: RequestOptions = new RequestOptions({ options: RequestOptions = new RequestOptions({
'headers': this.headers 'headers': this.headers
}); });

View File

@ -27,19 +27,19 @@ import { CommonRoutes } from '../../shared/shared.const';
}) })
export class ResetPasswordComponent implements OnInit { export class ResetPasswordComponent implements OnInit {
opened: boolean = true; opened: boolean = true;
private onGoing: boolean = false; onGoing: boolean = false;
private password: string = ""; password: string = "";
private validationState: any = { private validationState: any = {
"newPassword": true, "newPassword": true,
"reNewPassword": true "reNewPassword": true
}; };
private resetUuid: string = ""; resetUuid: string = "";
private resetOk: boolean = false; resetOk: boolean = false;
confirmPwd: string = ""; confirmPwd: string = "";
@ViewChild("resetPwdForm") resetPwdForm: NgForm; @ViewChild("resetPwdForm") resetPwdForm: NgForm;
@ViewChild(InlineAlertComponent) @ViewChild(InlineAlertComponent)
private inlineAlert: InlineAlertComponent; inlineAlert: InlineAlertComponent;
constructor( constructor(
private pwdService: PasswordSettingService, private pwdService: PasswordSettingService,
@ -131,7 +131,7 @@ export class ResetPasswordComponent implements OnInit {
} }
} }
private getControlValidationState(key: string): boolean { getControlValidationState(key: string): boolean {
if (this.resetPwdForm) { if (this.resetPwdForm) {
let control = this.resetPwdForm.controls[key]; let control = this.resetPwdForm.controls[key];
if (control) { if (control) {
@ -142,7 +142,7 @@ export class ResetPasswordComponent implements OnInit {
return false; return false;
} }
private samePassword(): boolean { samePassword(): boolean {
if (this.resetPwdForm) { if (this.resetPwdForm) {
let control1 = this.resetPwdForm.controls["newPassword"]; let control1 = this.resetPwdForm.controls["newPassword"];
let control2 = this.resetPwdForm.controls["reNewPassword"]; let control2 = this.resetPwdForm.controls["reNewPassword"];

View File

@ -27,7 +27,7 @@ import { AppConfigService } from '../../app-config.service';
import { AppConfig } from '../../app-config'; import { AppConfig } from '../../app-config';
import { User } from '../../user/user'; import { User } from '../../user/user';
import { CookieService, CookieOptions } from 'angular2-cookie/core'; import { CookieService, CookieOptions } from 'ngx-cookie';
//Define status flags for signing in states //Define status flags for signing in states
export const signInStatusNormal = 0; export const signInStatusNormal = 0;
@ -43,11 +43,11 @@ const expireDays = 10;
}) })
export class SignInComponent implements AfterViewChecked, OnInit { export class SignInComponent implements AfterViewChecked, OnInit {
private redirectUrl: string = ""; redirectUrl: string = "";
private appConfig: AppConfig = new AppConfig(); appConfig: AppConfig = new AppConfig();
//Remeber me indicator //Remeber me indicator
private rememberMe: boolean = false; rememberMe: boolean = false;
private rememberedName: string = ""; rememberedName: string = "";
//Form reference //Form reference
signInForm: NgForm; signInForm: NgForm;
@ViewChild('signInForm') currentForm: NgForm; @ViewChild('signInForm') currentForm: NgForm;
@ -126,7 +126,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
return this.appConfig.auth_mode != 'ldap_auth'; return this.appConfig.auth_mode != 'ldap_auth';
} }
private clickRememberMe($event): void { clickRememberMe($event: any): void {
if ($event && $event.target) { if ($event && $event.target) {
this.rememberMe = $event.target.checked; this.rememberMe = $event.target.checked;
if (!this.rememberMe) { if (!this.rememberMe) {
@ -137,23 +137,23 @@ export class SignInComponent implements AfterViewChecked, OnInit {
} }
} }
private remeberMe(): void { remeberMe(): void {
if (this.rememberMe) { if (this.rememberMe) {
if (this.rememberedName != this.signInCredential.principal) { if (this.rememberedName != this.signInCredential.principal) {
//Set expire time //Set expire time
let expires: number = expireDays * 3600 * 24 * 1000; let expires: number = expireDays * 3600 * 24 * 1000;
let date = new Date(Date.now() + expires); let date = new Date(Date.now() + expires);
let cookieptions = new CookieOptions({ let cookieptions: CookieOptions = {
path: "/", path: "/",
expires: date expires: date
}); };
this.cookie.put(remCookieKey, this.signInCredential.principal, cookieptions); this.cookie.put(remCookieKey, this.signInCredential.principal, cookieptions);
} }
} }
} }
//General error handler //General error handler
private handleError(error) { handleError(error: any) {
//Set error status //Set error status
this.signInStatus = signInStatusError; this.signInStatus = signInStatusError;
@ -162,7 +162,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
} }
//Hande form values changes //Hande form values changes
private formChanged() { formChanged() {
if (this.currentForm === this.signInForm) { if (this.currentForm === this.signInForm) {
return; return;
} }
@ -177,7 +177,7 @@ export class SignInComponent implements AfterViewChecked, OnInit {
} }
//Fill the new user info into the sign in form //Fill the new user info into the sign in form
private handleUserCreation(user: User): void { handleUserCreation(user: User): void {
if (user) { if (user) {
this.currentForm.setValue({ this.currentForm.setValue({
"login_username": user.username, "login_username": user.username,

View File

@ -27,14 +27,14 @@ const signInUrl = '/login';
*/ */
@Injectable() @Injectable()
export class SignInService { export class SignInService {
private headers = new Headers({ headers = new Headers({
"Content-Type": 'application/x-www-form-urlencoded' "Content-Type": 'application/x-www-form-urlencoded'
}); });
constructor(private http: Http) {} constructor(private http: Http) {}
//Handle the related exceptions //Handle the related exceptions
private handleError(error: any): Promise<any>{ handleError(error: any): Promise<any>{
return Promise.reject(error.message || error); return Promise.reject(error.message || error);
} }

View File

@ -29,9 +29,9 @@ import { MessageService } from '../../global-message/message.service';
templateUrl: "sign-up-page.component.html" templateUrl: "sign-up-page.component.html"
}) })
export class SignUpPageComponent implements OnInit { export class SignUpPageComponent implements OnInit {
private error: any; error: any;
private onGoing: boolean = false; onGoing: boolean = false;
private formValueChanged: boolean = false; formValueChanged: boolean = false;
constructor( constructor(
private userService: UserService, private userService: UserService,
@ -39,9 +39,9 @@ export class SignUpPageComponent implements OnInit {
private router: Router) { } private router: Router) { }
@ViewChild(NewUserFormComponent) @ViewChild(NewUserFormComponent)
private newUserForm: NewUserFormComponent; newUserForm: NewUserFormComponent;
private getNewUser(): User { getNewUser(): User {
return this.newUserForm.getData(); return this.newUserForm.getData();
} }

View File

@ -30,9 +30,9 @@ import { Modal } from 'clarity-angular';
export class SignUpComponent { export class SignUpComponent {
opened: boolean = false; opened: boolean = false;
staticBackdrop: boolean = true; staticBackdrop: boolean = true;
private error: any; error: any;
private onGoing: boolean = false; onGoing: boolean = false;
private formValueChanged: boolean = false; formValueChanged: boolean = false;
@Output() userCreation = new EventEmitter<User>(); @Output() userCreation = new EventEmitter<User>();
@ -41,15 +41,15 @@ export class SignUpComponent {
private userService: UserService) { } private userService: UserService) { }
@ViewChild(NewUserFormComponent) @ViewChild(NewUserFormComponent)
private newUserForm: NewUserFormComponent; newUserForm: NewUserFormComponent;
@ViewChild(InlineAlertComponent) @ViewChild(InlineAlertComponent)
private inlienAlert: InlineAlertComponent; inlienAlert: InlineAlertComponent;
@ViewChild(Modal) @ViewChild(Modal)
private modal: Modal; modal: Modal;
private getNewUser(): User { getNewUser(): User {
return this.newUserForm.getData(); return this.newUserForm.getData();
} }
@ -97,7 +97,7 @@ export class SignUpComponent {
} }
} }
confirmCancel(): void { confirmCancel($event: any): void {
this.opened = false; this.opened = false;
this.modal.close(); this.modal.close();
} }

View File

@ -16,7 +16,7 @@ import { Headers, Http, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/toPromise'; import 'rxjs/add/operator/toPromise';
import { AppConfig } from './app-config'; import { AppConfig } from './app-config';
import { CookieService } from 'angular2-cookie/core'; import { CookieService } from 'ngx-cookie';
import { CookieKeyOfAdmiral, HarborQueryParamKey } from './shared/shared.const'; import { CookieKeyOfAdmiral, HarborQueryParamKey } from './shared/shared.const';
import { maintainUrlQueryParmas } from './shared/shared.utils'; import { maintainUrlQueryParmas } from './shared/shared.utils';
@ -30,15 +30,15 @@ export const systemInfoEndpoint = "/api/systeminfo";
*/ */
@Injectable() @Injectable()
export class AppConfigService { export class AppConfigService {
private headers = new Headers({ headers = new Headers({
"Content-Type": 'application/json' "Content-Type": 'application/json'
}); });
private options = new RequestOptions({ options = new RequestOptions({
headers: this.headers headers: this.headers
}); });
//Store the application configuration //Store the application configuration
private configurations: AppConfig = new AppConfig(); configurations: AppConfig = new AppConfig();
constructor( constructor(
private http: Http, private http: Http,

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, ReflectiveInjector, LOCALE_ID } from '@angular/core'; import { Component, ReflectiveInjector, LOCALE_ID } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CookieService } from 'angular2-cookie/core'; import { CookieService } from 'ngx-cookie';
import { supportedLangs, enLang } from './shared/shared.const'; import { supportedLangs, enLang } from './shared/shared.const';
import { SessionService } from './shared/session.service'; import { SessionService } from './shared/session.service';
@ -43,8 +43,7 @@ export class AppComponent {
} }
let selectedLang = this.isLangMatch(langSetting, supportedLangs) ? langSetting : enLang; let selectedLang = this.isLangMatch(langSetting, supportedLangs) ? langSetting : enLang;
translate.use(selectedLang); translate.use(selectedLang);
//this.session.switchLanguage(selectedLang).catch(error => console.error(error));
//Override page title //Override page title
let key: string = "APP_TITLE.HARBOR"; let key: string = "APP_TITLE.HARBOR";
@ -57,7 +56,7 @@ export class AppComponent {
}); });
} }
private isLangMatch(browserLang: string, supportedLangs: string[]) { isLangMatch(browserLang: string, supportedLangs: string[]) {
if (supportedLangs && supportedLangs.length > 0) { if (supportedLangs && supportedLangs.length > 0) {
return supportedLangs.find(lang => lang === browserLang); return supportedLangs.find(lang => lang === browserLang);
} }

View File

@ -32,15 +32,15 @@ const deBounceTime = 500; //ms
}) })
export class GlobalSearchComponent implements OnInit, OnDestroy { export class GlobalSearchComponent implements OnInit, OnDestroy {
//Keep search term as Subject //Keep search term as Subject
private searchTerms = new Subject<string>(); searchTerms = new Subject<string>();
//Keep subscription for future use //Keep subscription for future use
private searchSub: Subscription; searchSub: Subscription;
private closeSub: Subscription; closeSub: Subscription;
//To indicate if the result panel is opened //To indicate if the result panel is opened
private isResPanelOpened: boolean = false; isResPanelOpened: boolean = false;
private searchTerm: string = ""; searchTerm: string = "";
//Placeholder text //Placeholder text
placeholderText: string = "GLOBAL_SEARCH.PLACEHOLDER"; placeholderText: string = "GLOBAL_SEARCH.PLACEHOLDER";

View File

@ -27,10 +27,10 @@ const searchEndpoint = "/api/search";
*/ */
@Injectable() @Injectable()
export class GlobalSearchService { export class GlobalSearchService {
private headers = new Headers({ headers = new Headers({
"Content-Type": 'application/json' "Content-Type": 'application/json'
}); });
private options = new RequestOptions({ options = new RequestOptions({
headers: this.headers headers: this.headers
}); });

View File

@ -30,22 +30,22 @@ import { MessageHandlerService } from '../../shared/message-handler/message-hand
}) })
export class SearchResultComponent implements OnInit, OnDestroy { export class SearchResultComponent implements OnInit, OnDestroy {
private searchResults: SearchResults = new SearchResults(); searchResults: SearchResults = new SearchResults();
private originalCopy: SearchResults; originalCopy: SearchResults;
private currentTerm: string = ""; currentTerm: string = "";
//Open or close //Open or close
private stateIndicator: boolean = false; stateIndicator: boolean = false;
//Search in progress //Search in progress
private onGoing: boolean = false; onGoing: boolean = false;
//Whether or not mouse point is onto the close indicator //Whether or not mouse point is onto the close indicator
private mouseOn: boolean = false; mouseOn: boolean = false;
//Watch message channel //Watch message channel
private searchSub: Subscription; searchSub: Subscription;
private closeSearchSub: Subscription; closeSearchSub: Subscription;
constructor( constructor(
private search: GlobalSearchService, private search: GlobalSearchService,
@ -71,7 +71,7 @@ export class SearchResultComponent implements OnInit, OnDestroy {
} }
} }
private clone(src: SearchResults): SearchResults { clone(src: SearchResults): SearchResults {
let res: SearchResults = new SearchResults(); let res: SearchResults = new SearchResults();
if (src) { if (src) {

View File

@ -18,9 +18,9 @@ import { AlertType } from '../../shared/shared.const';
@Injectable() @Injectable()
export class SearchTriggerService { export class SearchTriggerService {
private searchTriggerSource = new Subject<string>(); searchTriggerSource = new Subject<string>();
private searchCloseSource = new Subject<boolean>(); searchCloseSource = new Subject<boolean>();
private searchClearSource = new Subject<boolean>(); searchClearSource = new Subject<boolean>();
searchTriggerChan$ = this.searchTriggerSource.asObservable(); searchTriggerChan$ = this.searchTriggerSource.asObservable();
searchCloseChan$ = this.searchCloseSource.asObservable(); searchCloseChan$ = this.searchCloseSource.asObservable();
@ -37,7 +37,7 @@ export class SearchTriggerService {
} }
//Clear search term //Clear search term
clear(event): void { clear(event: any): void {
this.searchClearSource.next(event); this.searchClearSource.next(event);
} }

View File

@ -39,23 +39,23 @@ import { CommonRoutes } from '../../shared/shared.const';
export class HarborShellComponent implements OnInit, OnDestroy { export class HarborShellComponent implements OnInit, OnDestroy {
@ViewChild(AccountSettingsModalComponent) @ViewChild(AccountSettingsModalComponent)
private accountSettingsModal: AccountSettingsModalComponent; accountSettingsModal: AccountSettingsModalComponent;
@ViewChild(PasswordSettingComponent) @ViewChild(PasswordSettingComponent)
private pwdSetting: PasswordSettingComponent; pwdSetting: PasswordSettingComponent;
@ViewChild(NavigatorComponent) @ViewChild(NavigatorComponent)
private navigator: NavigatorComponent; navigator: NavigatorComponent;
@ViewChild(AboutDialogComponent) @ViewChild(AboutDialogComponent)
private aboutDialog: AboutDialogComponent; aboutDialog: AboutDialogComponent;
//To indicator whwther or not the search results page is displayed //To indicator whwther or not the search results page is displayed
//We need to use this property to do some overriding work //We need to use this property to do some overriding work
private isSearchResultsOpened: boolean = false; isSearchResultsOpened: boolean = false;
private searchSub: Subscription; searchSub: Subscription;
private searchCloseSub: Subscription; searchCloseSub: Subscription;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,

View File

@ -20,7 +20,7 @@ import { modalEvents } from '../modal-events.const';
import { SessionUser } from '../../shared/session-user'; import { SessionUser } from '../../shared/session-user';
import { SessionService } from '../../shared/session.service'; import { SessionService } from '../../shared/session.service';
import { CookieService, CookieOptions } from 'angular2-cookie/core'; import { CookieService, CookieOptions } from 'ngx-cookie';
import { supportedLangs, enLang, languageNames, CommonRoutes } from '../../shared/shared.const'; import { supportedLangs, enLang, languageNames, CommonRoutes } from '../../shared/shared.const';
import { AppConfigService } from '../../app-config.service'; import { AppConfigService } from '../../app-config.service';
@ -38,8 +38,8 @@ export class NavigatorComponent implements OnInit {
@Output() showAccountSettingsModal = new EventEmitter<ModalEvent>(); @Output() showAccountSettingsModal = new EventEmitter<ModalEvent>();
@Output() showPwdChangeModal = new EventEmitter<ModalEvent>(); @Output() showPwdChangeModal = new EventEmitter<ModalEvent>();
private selectedLang: string = enLang; selectedLang: string = enLang;
private appTitle: string = 'APP_TITLE.HARBOR'; appTitle: string = 'APP_TITLE.HARBOR';
constructor( constructor(
private session: SessionService, private session: SessionService,
@ -54,10 +54,10 @@ export class NavigatorComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.selectedLang = this.translate.currentLang; this.selectedLang = this.translate.currentLang;
this.translate.onLangChange.subscribe(langChange => { this.translate.onLangChange.subscribe((langChange: {lang: string}) => {
this.selectedLang = langChange.lang; this.selectedLang = langChange.lang;
//Keep in cookie for next use //Keep in cookie for next use
let opt = new CookieOptions({path: '/', expires: new Date(Date.now() + 3600*1000*24*31)}); let opt:CookieOptions = {path: '/', expires: new Date(Date.now() + 3600*1000*24*31)};
this.cookie.put("harbor-lang", langChange.lang, opt); this.cookie.put("harbor-lang", langChange.lang, opt);
}); });
if (this.appConfigService.isIntegrationMode()) { if (this.appConfigService.isIntegrationMode()) {

View File

@ -22,7 +22,7 @@ import { SessionUser } from '../../shared/session-user';
styleUrls: ['start.component.css'] styleUrls: ['start.component.css']
}) })
export class StartPageComponent implements OnInit{ export class StartPageComponent implements OnInit{
private isSessionValid: boolean = false; isSessionValid: boolean = false;
constructor( constructor(
private session: SessionService private session: SessionService

View File

@ -23,7 +23,7 @@ import { Configuration } from '../config';
styleUrls: ['../config.component.css'] styleUrls: ['../config.component.css']
}) })
export class ConfigurationAuthComponent { export class ConfigurationAuthComponent {
private changeSub: Subscription; changeSub: Subscription;
@Input("ldapConfig") currentConfig: Configuration = new Configuration(); @Input("ldapConfig") currentConfig: Configuration = new Configuration();
@ViewChild("authConfigFrom") authForm: NgForm; @ViewChild("authConfigFrom") authForm: NgForm;
@ -44,7 +44,7 @@ export class ConfigurationAuthComponent {
} }
} }
private disabled(prop: any): boolean { disabled(prop: any): boolean {
return !(prop && prop.editable); return !(prop && prop.editable);
} }
@ -52,7 +52,7 @@ export class ConfigurationAuthComponent {
return this.authForm && this.authForm.valid; return this.authForm && this.authForm.valid;
} }
private handleOnChange($event): void { handleOnChange($event: any): void {
if ($event && $event.target && $event.target["value"]) { if ($event && $event.target && $event.target["value"]) {
let authMode = $event.target["value"]; let authMode = $event.target["value"];
if (authMode === 'ldap_auth') { if (authMode === 'ldap_auth') {

View File

@ -44,13 +44,13 @@ const TabLinkContentMap = {
styleUrls: ['config.component.css'] styleUrls: ['config.component.css']
}) })
export class ConfigurationComponent implements OnInit, OnDestroy { export class ConfigurationComponent implements OnInit, OnDestroy {
private onGoing: boolean = false; onGoing: boolean = false;
allConfig: Configuration = new Configuration(); allConfig: Configuration = new Configuration();
private currentTabId: string = "config-auth";//default tab currentTabId: string = "config-auth";//default tab
private originalCopy: Configuration; originalCopy: Configuration;
private confirmSub: Subscription; confirmSub: Subscription;
private testingMailOnGoing: boolean = false; testingMailOnGoing: boolean = false;
private testingLDAPOnGoing: boolean = false; testingLDAPOnGoing: boolean = false;
@ViewChild("repoConfigFrom") repoConfigForm: NgForm; @ViewChild("repoConfigFrom") repoConfigForm: NgForm;
@ViewChild("systemConfigFrom") systemConfigForm: NgForm; @ViewChild("systemConfigFrom") systemConfigForm: NgForm;
@ -64,15 +64,15 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
private appConfigService: AppConfigService, private appConfigService: AppConfigService,
private session: SessionService) { } private session: SessionService) { }
private isCurrentTabLink(tabId: string): boolean { isCurrentTabLink(tabId: string): boolean {
return this.currentTabId === tabId; return this.currentTabId === tabId;
} }
private isCurrentTabContent(contentId: string): boolean { isCurrentTabContent(contentId: string): boolean {
return TabLinkContentMap[this.currentTabId] === contentId; return TabLinkContentMap[this.currentTabId] === contentId;
} }
private hasUnsavedChangesOfCurrentTab(): any { hasUnsavedChangesOfCurrentTab(): any {
let allChanges = this.getChanges(); let allChanges = this.getChanges();
if (this.isEmpty(allChanges)) { if (this.isEmpty(allChanges)) {
return null; return null;
@ -331,7 +331,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
}); });
} }
private confirmUnsavedChanges(changes: any) { confirmUnsavedChanges(changes: any) {
let msg = new ConfirmationMessage( let msg = new ConfirmationMessage(
"CONFIG.CONFIRM_TITLE", "CONFIG.CONFIRM_TITLE",
"CONFIG.CONFIRM_SUMMARY", "CONFIG.CONFIRM_SUMMARY",
@ -343,7 +343,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
this.confirmService.openComfirmDialog(msg); this.confirmService.openComfirmDialog(msg);
} }
private confirmUnsavedTabChanges(changes: any, tabId: string) { confirmUnsavedTabChanges(changes: any, tabId: string) {
let msg = new ConfirmationMessage( let msg = new ConfirmationMessage(
"CONFIG.CONFIRM_TITLE", "CONFIG.CONFIRM_TITLE",
"CONFIG.CONFIRM_SUMMARY", "CONFIG.CONFIRM_SUMMARY",
@ -358,7 +358,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
this.confirmService.openComfirmDialog(msg); this.confirmService.openComfirmDialog(msg);
} }
private retrieveConfig(): void { retrieveConfig(): void {
this.onGoing = true; this.onGoing = true;
this.configService.getConfiguration() this.configService.getConfiguration()
.then(configurations => { .then(configurations => {
@ -387,7 +387,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
* *
* @memberOf ConfigurationComponent * @memberOf ConfigurationComponent
*/ */
private getChanges(): any { getChanges(): any {
let changes = {}; let changes = {};
if (!this.allConfig || !this.originalCopy) { if (!this.allConfig || !this.originalCopy) {
return changes; return changes;
@ -419,7 +419,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
* *
* @memberOf ConfigurationComponent * @memberOf ConfigurationComponent
*/ */
private clone(src: Configuration): Configuration { clone(src: Configuration): Configuration {
let dest = new Configuration(); let dest = new Configuration();
if (!src) { if (!src) {
return dest;//Empty return dest;//Empty
@ -443,7 +443,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
* *
* @memberOf ConfigurationComponent * @memberOf ConfigurationComponent
*/ */
private reset(changes: any): void { reset(changes: any): void {
if (!this.isEmpty(changes)) { if (!this.isEmpty(changes)) {
for (let prop in changes) { for (let prop in changes) {
if (this.originalCopy[prop]) { if (this.originalCopy[prop]) {
@ -456,7 +456,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
} }
} }
private isEmpty(obj) { isEmpty(obj: any) {
for (let key in obj) { for (let key in obj) {
if (obj.hasOwnProperty(key)) if (obj.hasOwnProperty(key))
return false; return false;
@ -464,7 +464,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
return true; return true;
} }
private disabled(prop: any): boolean { disabled(prop: any): boolean {
return !(prop && prop.editable); return !(prop && prop.editable);
} }
} }

View File

@ -23,11 +23,11 @@ const ldapEndpoint = "/api/ldap/ping";
@Injectable() @Injectable()
export class ConfigurationService { export class ConfigurationService {
private headers: Headers = new Headers({ headers: Headers = new Headers({
"Accept": 'application/json', "Accept": 'application/json',
"Content-Type": 'application/json' "Content-Type": 'application/json'
}); });
private options: RequestOptions = new RequestOptions({ options: RequestOptions = new RequestOptions({
'headers': this.headers 'headers': this.headers
}); });

View File

@ -28,7 +28,7 @@ export class ConfigurationEmailComponent {
constructor() { } constructor() { }
private disabled(prop: any): boolean { disabled(prop: any): boolean {
return !(prop && prop.editable); return !(prop && prop.editable);
} }

View File

@ -15,20 +15,25 @@ import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http'; import { HttpModule } from '@angular/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ClarityModule } from 'clarity-angular'; import { ClarityModule } from 'clarity-angular';
import { CookieModule } from 'ngx-cookie';
@NgModule({ @NgModule({
imports: [ imports: [
BrowserModule, BrowserModule,
FormsModule, FormsModule,
HttpModule, HttpModule,
ClarityModule.forRoot() ClarityModule.forRoot(),
CookieModule.forRoot(),
BrowserAnimationsModule
], ],
exports: [ exports: [
BrowserModule, BrowserModule,
FormsModule, FormsModule,
HttpModule, HttpModule,
ClarityModule ClarityModule,
BrowserAnimationsModule
] ]
}) })
export class CoreModule { export class CoreModule {

View File

@ -31,11 +31,11 @@ export class MessageComponent implements OnInit, OnDestroy {
globalMessage: Message = new Message(); globalMessage: Message = new Message();
globalMessageOpened: boolean; globalMessageOpened: boolean;
messageText: string = ""; messageText: string = "";
private timer: any = null; timer: any = null;
private appLevelMsgSub: Subscription; appLevelMsgSub: Subscription;
private msgSub: Subscription; msgSub: Subscription;
private clearSub: Subscription; clearSub: Subscription;
constructor( constructor(
private messageService: MessageService, private messageService: MessageService,

View File

@ -19,9 +19,9 @@ import { AlertType } from '../shared/shared.const';
@Injectable() @Injectable()
export class MessageService { export class MessageService {
private messageAnnouncedSource = new Subject<Message>(); messageAnnouncedSource = new Subject<Message>();
private appLevelAnnouncedSource = new Subject<Message>(); appLevelAnnouncedSource = new Subject<Message>();
private clearSource = new Subject<boolean>(); clearSource = new Subject<boolean>();
messageAnnounced$ = this.messageAnnouncedSource.asObservable(); messageAnnounced$ = this.messageAnnouncedSource.asObservable();
appLevelAnnounced$ = this.appLevelAnnouncedSource.asObservable(); appLevelAnnounced$ = this.appLevelAnnouncedSource.asObservable();

View File

@ -77,7 +77,6 @@ export class AuditLogComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.projectId = +this.route.snapshot.parent.params['id']; this.projectId = +this.route.snapshot.parent.params['id'];
console.log('Get projectId from route params snapshot:' + this.projectId);
this.queryParam.project_id = this.projectId; this.queryParam.project_id = this.projectId;
this.queryParam.page_size = this.pageSize; this.queryParam.page_size = this.pageSize;
} }
@ -92,7 +91,6 @@ export class AuditLogComponent implements OnInit {
response=>{ response=>{
this.totalRecordCount = response.headers.get('x-total-count'); this.totalRecordCount = response.headers.get('x-total-count');
this.totalPage = Math.ceil(this.totalRecordCount / this.pageSize); this.totalPage = Math.ceil(this.totalRecordCount / this.pageSize);
console.log('TotalRecordCount:' + this.totalRecordCount + ', totalPage:' + this.totalPage);
this.auditLogs = response.json(); this.auditLogs = response.json();
}, },
error=>{ error=>{
@ -117,7 +115,6 @@ export class AuditLogComponent implements OnInit {
this.queryParam.end_timestamp = new Date(strDate).getTime() / 1000 + oneDayOffset; this.queryParam.end_timestamp = new Date(strDate).getTime() / 1000 + oneDayOffset;
break; break;
} }
console.log('Search audit log filtered by time range, begin: ' + this.queryParam.begin_timestamp + ', end:' + this.queryParam.end_timestamp);
this.retrieve(); this.retrieve();
} }
@ -136,8 +133,7 @@ export class AuditLogComponent implements OnInit {
operationFilter = []; operationFilter = [];
} }
this.queryParam.keywords = operationFilter.join('/'); this.queryParam.keywords = operationFilter.join('/');
this.retrieve(); this.retrieve();
console.log('Search option filter:' + operationFilter.join('/'));
} }
toggleOptionalName(option: number): void { toggleOptionalName(option: number): void {

View File

@ -25,7 +25,7 @@ export const logEndpoint = "/api/logs";
@Injectable() @Injectable()
export class AuditLogService { export class AuditLogService {
private httpOptions = new RequestOptions({ httpOptions = new RequestOptions({
headers: new Headers({ headers: new Headers({
"Content-Type": 'application/json', "Content-Type": 'application/json',
"Accept": 'application/json' "Accept": 'application/json'

View File

@ -25,7 +25,7 @@
<clr-dg-column>{{'AUDIT_LOG.TAGS' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.TAGS' | translate}}</clr-dg-column>
<clr-dg-column>{{'AUDIT_LOG.OPERATION' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.OPERATION' | translate}}</clr-dg-column>
<clr-dg-column>{{'AUDIT_LOG.TIMESTAMP' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.TIMESTAMP' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let l of recentLogs"> <clr-dg-row *clrDgItems="let l of recentLogs">
<clr-dg-cell>{{l.username}}</clr-dg-cell> <clr-dg-cell>{{l.username}}</clr-dg-cell>
<clr-dg-cell>{{l.repo_name}}</clr-dg-cell> <clr-dg-cell>{{l.repo_name}}</clr-dg-cell>
<clr-dg-cell>{{l.repo_tag}}</clr-dg-cell> <clr-dg-cell>{{l.repo_tag}}</clr-dg-cell>

View File

@ -30,11 +30,11 @@ import { errorHandler, accessErrorHandler } from '../shared/shared.utils';
}) })
export class RecentLogComponent implements OnInit { export class RecentLogComponent implements OnInit {
private sessionUser: SessionUser = null; sessionUser: SessionUser = null;
private recentLogs: AuditLog[]; recentLogs: AuditLog[];
private logsCache: AuditLog[]; logsCache: AuditLog[];
private onGoing: boolean = false; onGoing: boolean = false;
private lines: number = 10; //Support 10, 25 and 50 lines: number = 10; //Support 10, 25 and 50
currentTerm: string; currentTerm: string;
constructor( constructor(
@ -48,7 +48,7 @@ export class RecentLogComponent implements OnInit {
this.retrieveLogs(); this.retrieveLogs();
} }
private handleOnchange($event: any) { handleOnchange($event: any) {
this.currentTerm = ''; this.currentTerm = '';
if ($event && $event.target && $event.target["value"]) { if ($event && $event.target && $event.target["value"]) {
this.lines = $event.target["value"]; this.lines = $event.target["value"];
@ -80,7 +80,7 @@ export class RecentLogComponent implements OnInit {
this.retrieveLogs(); this.retrieveLogs();
} }
private retrieveLogs(): void { retrieveLogs(): void {
if (this.lines < 10) { if (this.lines < 10) {
this.lines = 10; this.lines = 10;
} }
@ -102,7 +102,7 @@ export class RecentLogComponent implements OnInit {
); );
} }
private isMatched(terms: string, log: AuditLog): boolean { isMatched(terms: string, log: AuditLog): boolean {
let reg = new RegExp('.*' + terms + '.*', 'i'); let reg = new RegExp('.*' + terms + '.*', 'i');
return reg.test(log.username) || return reg.test(log.username) ||
reg.test(log.repo_name) || reg.test(log.repo_name) ||

View File

@ -47,7 +47,7 @@ export class CreateProjectComponent implements AfterViewChecked {
@Output() create = new EventEmitter<boolean>(); @Output() create = new EventEmitter<boolean>();
@ViewChild(InlineAlertComponent) @ViewChild(InlineAlertComponent)
private inlineAlert: InlineAlertComponent; inlineAlert: InlineAlertComponent;
constructor(private projectService: ProjectService, constructor(private projectService: ProjectService,
private translateService: TranslateService, private translateService: TranslateService,

View File

@ -4,7 +4,7 @@
<clr-dg-column *ngIf="showRoleInfo">{{'PROJECT.ROLE' | translate}}</clr-dg-column> <clr-dg-column *ngIf="showRoleInfo">{{'PROJECT.ROLE' | translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.REPO_COUNT'| translate}}</clr-dg-column> <clr-dg-column>{{'PROJECT.REPO_COUNT'| translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.CREATION_TIME' | translate}}</clr-dg-column> <clr-dg-column>{{'PROJECT.CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let p of projects" [clrDgItem]="p"> <clr-dg-row *clrDgItems="let p of projects">
<clr-dg-action-overflow [hidden]="!(p.current_user_role_id === 1 || isSystemAdmin)"> <clr-dg-action-overflow [hidden]="!(p.current_user_role_id === 1 || isSystemAdmin)">
<button class="action-item" (click)="newReplicationRule(p)" [hidden]="!isSystemAdmin">{{'PROJECT.REPLICATION_RULE' | translate}}</button> <button class="action-item" (click)="newReplicationRule(p)" [hidden]="!isSystemAdmin">{{'PROJECT.REPLICATION_RULE' | translate}}</button>
<button class="action-item" (click)="toggleProject(p)">{{'PROJECT.MAKE' | translate}} {{(p.public === 0 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}} </button> <button class="action-item" (click)="toggleProject(p)">{{'PROJECT.MAKE' | translate}} {{(p.public === 0 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}} </button>
@ -17,7 +17,7 @@
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell> <clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
{{totalRecordCount || (projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}} {{(projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}}
<clr-dg-pagination [clrDgPageSize]="pageOffset" [clrDgTotalItems]="totalPage"></clr-dg-pagination> <clr-dg-pagination [clrDgPageSize]="15"></clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>

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 { Component, EventEmitter, Output, Input, OnInit } from '@angular/core'; import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { Router, NavigationExtras } from '@angular/router'; import { Router, NavigationExtras } from '@angular/router';
import { Project } from '../project'; import { Project } from '../project';
import { ProjectService } from '../project.service'; import { ProjectService } from '../project.service';
@ -24,17 +24,12 @@ import { State } from 'clarity-angular';
@Component({ @Component({
selector: 'list-project', selector: 'list-project',
templateUrl: 'list-project.component.html' templateUrl: 'list-project.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListProjectComponent implements OnInit { export class ListProjectComponent {
@Input() projects: Project[]; @Input() projects: Project[];
@Input() totalPage: number;
@Input() totalRecordCount: number;
pageOffset: number = 1;
@Input() filteredType: string; @Input() filteredType: string;
@Output() paginate = new EventEmitter<State>(); @Output() paginate = new EventEmitter<State>();
@ -47,10 +42,11 @@ export class ListProjectComponent implements OnInit {
constructor( constructor(
private session: SessionService, private session: SessionService,
private router: Router, private router: Router,
private searchTrigger: SearchTriggerService) { } private searchTrigger: SearchTriggerService,
private ref: ChangeDetectorRef) {
ngOnInit(): void { let hnd = setInterval(()=>ref.markForCheck(), 100);
} setTimeout(()=>clearInterval(hnd), 1000);
}
get showRoleInfo(): boolean { get showRoleInfo(): boolean {
return this.filteredType === ProjectTypes[0]; return this.filteredType === ProjectTypes[0];

View File

@ -63,7 +63,6 @@ export class AddMemberComponent implements AfterViewChecked {
.subscribe( .subscribe(
response=>{ response=>{
this.messageHandlerService.showSuccess('MEMBER.ADDED_SUCCESS'); this.messageHandlerService.showSuccess('MEMBER.ADDED_SUCCESS');
console.log('Added member successfully.');
this.added.emit(true); this.added.emit(true);
this.addMemberOpened = false; this.addMemberOpened = false;
}, },
@ -89,7 +88,6 @@ export class AddMemberComponent implements AfterViewChecked {
.subscribe(errorMessage=>this.inlineAlert.showInlineError(errorMessage)); .subscribe(errorMessage=>this.inlineAlert.showInlineError(errorMessage));
} }
} }
console.log('Failed to add member of project:' + this.projectId, ' with error:' + error);
} }
); );
} }

View File

@ -17,7 +17,7 @@
<clr-datagrid> <clr-datagrid>
<clr-dg-column>{{'MEMBER.NAME' | translate}}</clr-dg-column> <clr-dg-column>{{'MEMBER.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'MEMBER.ROLE' | translate}}</clr-dg-column> <clr-dg-column>{{'MEMBER.ROLE' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let m of members"> <clr-dg-row *clrDgItems="let m of members">
<clr-dg-action-overflow [hidden]="m.user_id === currentUser.user_id || !hasProjectAdminRole"> <clr-dg-action-overflow [hidden]="m.user_id === currentUser.user_id || !hasProjectAdminRole">
<button class="action-item" (click)="changeRole(m, 1)">{{'MEMBER.PROJECT_ADMIN' | translate}}</button> <button class="action-item" (click)="changeRole(m, 1)">{{'MEMBER.PROJECT_ADMIN' | translate}}</button>
<button class="action-item" (click)="changeRole(m, 2)">{{'MEMBER.DEVELOPER' | translate}}</button> <button class="action-item" (click)="changeRole(m, 2)">{{'MEMBER.DEVELOPER' | translate}}</button>

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 { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { Component, OnInit, ViewChild, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { Response } from '@angular/http'; import { Response } from '@angular/http';
@ -41,14 +41,15 @@ import { Project } from '../../project/project';
@Component({ @Component({
templateUrl: 'member.component.html', templateUrl: 'member.component.html',
styleUrls: ['./member.component.css'] styleUrls: ['./member.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class MemberComponent implements OnInit, OnDestroy { export class MemberComponent implements OnInit, OnDestroy {
members: Member[]; members: Member[];
projectId: number; projectId: number;
roleInfo = RoleInfo; roleInfo = RoleInfo;
private delSub: Subscription; delSub: Subscription;
@ViewChild(AddMemberComponent) @ViewChild(AddMemberComponent)
addMemberComponent: AddMemberComponent; addMemberComponent: AddMemberComponent;
@ -64,7 +65,8 @@ export class MemberComponent implements OnInit, OnDestroy {
private memberService: MemberService, private memberService: MemberService,
private messageHandlerService: MessageHandlerService, private messageHandlerService: MessageHandlerService,
private deletionDialogService: ConfirmationDialogService, private deletionDialogService: ConfirmationDialogService,
private session: SessionService) { private session: SessionService,
private ref: ChangeDetectorRef) {
this.delSub = deletionDialogService.confirmationConfirm$.subscribe(message => { this.delSub = deletionDialogService.confirmationConfirm$.subscribe(message => {
if (message && if (message &&
@ -75,20 +77,25 @@ export class MemberComponent implements OnInit, OnDestroy {
.subscribe( .subscribe(
response => { response => {
this.messageHandlerService.showSuccess('MEMBER.DELETED_SUCCESS'); this.messageHandlerService.showSuccess('MEMBER.DELETED_SUCCESS');
console.log('Successful delete member: ' + message.data);
this.retrieve(this.projectId, ''); this.retrieve(this.projectId, '');
}, },
error => this.messageHandlerService.handleError(error) error => this.messageHandlerService.handleError(error)
); );
} }
}); });
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
} }
retrieve(projectId: number, username: string) { retrieve(projectId: number, username: string) {
this.memberService this.memberService
.listMembers(projectId, username) .listMembers(projectId, username)
.subscribe( .subscribe(
response => this.members = response, response => {
this.members = response;
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
},
error => { error => {
this.router.navigate(['/harbor', 'projects']); this.router.navigate(['/harbor', 'projects']);
this.messageHandlerService.handleError(error); this.messageHandlerService.handleError(error);
@ -103,18 +110,13 @@ export class MemberComponent implements OnInit, OnDestroy {
ngOnInit() { ngOnInit() {
//Get projectId from route params snapshot. //Get projectId from route params snapshot.
this.projectId = +this.route.snapshot.parent.params['id']; this.projectId = +this.route.snapshot.parent.params['id'];
console.log('Get projectId from route params snapshot:' + this.projectId);
this.currentUser = this.session.getCurrentUser(); this.currentUser = this.session.getCurrentUser();
//Get current user from registered resolver. //Get current user from registered resolver.
let resolverData = this.route.snapshot.parent.data; let resolverData = this.route.snapshot.parent.data;
if(resolverData) { if(resolverData) {
this.hasProjectAdminRole = (<Project>resolverData['projectResolver']).has_project_admin_role; this.hasProjectAdminRole = (<Project>resolverData['projectResolver']).has_project_admin_role;
} }
this.retrieve(this.projectId, ''); this.retrieve(this.projectId, '');
} }
@ -122,7 +124,7 @@ export class MemberComponent implements OnInit, OnDestroy {
this.addMemberComponent.openAddMemberModal(); this.addMemberComponent.openAddMemberModal();
} }
addedMember() { addedMember($event: any) {
this.searchMember = ''; this.searchMember = '';
this.retrieve(this.projectId, ''); this.retrieve(this.projectId, '');
} }
@ -134,7 +136,6 @@ export class MemberComponent implements OnInit, OnDestroy {
.subscribe( .subscribe(
response => { response => {
this.messageHandlerService.showSuccess('MEMBER.SWITCHED_SUCCESS'); this.messageHandlerService.showSuccess('MEMBER.SWITCHED_SUCCESS');
console.log('Successful change role with user ' + m.user_id + ' to roleId ' + roleId);
this.retrieve(this.projectId, ''); this.retrieve(this.projectId, '');
}, },
error => this.messageHandlerService.handleError(error) error => this.messageHandlerService.handleError(error)
@ -153,7 +154,7 @@ export class MemberComponent implements OnInit, OnDestroy {
this.deletionDialogService.openComfirmDialog(deletionMessage); this.deletionDialogService.openComfirmDialog(deletionMessage);
} }
doSearch(searchMember) { doSearch(searchMember: string) {
this.searchMember = searchMember; this.searchMember = searchMember;
this.retrieve(this.projectId, this.searchMember); this.retrieve(this.projectId, this.searchMember);
} }

View File

@ -27,7 +27,6 @@ export class MemberService {
constructor(private http: Http) {} constructor(private http: Http) {}
listMembers(projectId: number, username: string): Observable<Member[]> { listMembers(projectId: number, username: string): Observable<Member[]> {
console.log('Get member from project_id:' + projectId + ', username:' + username);
return this.http return this.http
.get(`/api/projects/${projectId}/members?username=${username}`) .get(`/api/projects/${projectId}/members?username=${username}`)
.map(response=>response.json() as Member[]) .map(response=>response.json() as Member[])
@ -35,7 +34,6 @@ export class MemberService {
} }
addMember(projectId: number, username: string, roleId: number): Observable<any> { addMember(projectId: number, username: string, roleId: number): Observable<any> {
console.log('Adding member with username:' + username + ', roleId:' + roleId + ' under projectId:' + projectId);
return this.http return this.http
.post(`/api/projects/${projectId}/members`, { username: username, roles: [ roleId ] }) .post(`/api/projects/${projectId}/members`, { username: username, roles: [ roleId ] })
.map(response=>response.status) .map(response=>response.status)
@ -43,7 +41,6 @@ export class MemberService {
} }
changeMemberRole(projectId: number, userId: number, roleId: number): Observable<any> { changeMemberRole(projectId: number, userId: number, roleId: number): Observable<any> {
console.log('Changing member role with userId:' + ' to roleId:' + roleId + ' under projectId:' + projectId);
return this.http return this.http
.put(`/api/projects/${projectId}/members/${userId}`, { roles: [ roleId ]}) .put(`/api/projects/${projectId}/members/${userId}`, { roles: [ roleId ]})
.map(response=>response.status) .map(response=>response.status)
@ -51,7 +48,6 @@ export class MemberService {
} }
deleteMember(projectId: number, userId: number): Observable<any> { deleteMember(projectId: number, userId: number): Observable<any> {
console.log('Deleting member role with userId:' + userId + ' under projectId:' + projectId);
return this.http return this.http
.delete(`/api/projects/${projectId}/members/${userId}`) .delete(`/api/projects/${projectId}/members/${userId}`)
.map(response=>response.status) .map(response=>response.status)

View File

@ -29,7 +29,6 @@ export class ProjectRoutingResolver implements Resolve<Project>{
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<Project> { resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<Project> {
let projectId = route.params['id']; let projectId = route.params['id'];
console.log('Project resolver, projectID:' + projectId);
return this.projectService return this.projectService
.getProject(projectId) .getProject(projectId)
.toPromise() .toPromise()

View File

@ -24,6 +24,6 @@
</a> </a>
</div> </div>
</div> </div>
<list-project [projects]="changedProjects" [filteredType]="projectTypes[currentFilteredType]" (toggle)="toggleProject($event)" (delete)="deleteProject($event)" (paginate)="retrieve($event)" [totalPage]="totalPage" [totalRecordCount]="totalRecordCount"></list-project> <list-project [projects]="changedProjects" [filteredType]="projectTypes[currentFilteredType]" (toggle)="toggleProject($event)" (delete)="deleteProject($event)" (paginate)="retrieve($event)"></list-project>
</div> </div>
</div> </div>

View File

@ -47,7 +47,6 @@ import { StatisticHandler } from '../shared/statictics/statistic-handler.service
}) })
export class ProjectComponent implements OnInit, OnDestroy { export class ProjectComponent implements OnInit, OnDestroy {
selected = [];
changedProjects: Project[]; changedProjects: Project[];
projectTypes = ProjectTypes; projectTypes = ProjectTypes;
@ -64,12 +63,6 @@ export class ProjectComponent implements OnInit, OnDestroy {
projectName: string; projectName: string;
isPublic: number; isPublic: number;
page: number = 1;
pageSize: number = 15;
totalPage: number;
totalRecordCount: number;
constructor( constructor(
private projectService: ProjectService, private projectService: ProjectService,
private messageHandlerService: MessageHandlerService, private messageHandlerService: MessageHandlerService,
@ -129,15 +122,10 @@ export class ProjectComponent implements OnInit, OnDestroy {
} }
retrieve(state?: State): void { retrieve(state?: State): void {
if (state) {
this.page = state.page.to + 1;
}
this.projectService this.projectService
.listProjects(this.projectName, this.isPublic, this.page, this.pageSize) .listProjects(this.projectName, this.isPublic)
.subscribe( .subscribe(
response => { response => {
this.totalRecordCount = response.headers.get('x-total-count');
this.totalPage = Math.ceil(this.totalRecordCount / this.pageSize);
this.changedProjects = response.json(); this.changedProjects = response.json();
}, },
error => this.messageHandlerService.handleError(error) error => this.messageHandlerService.handleError(error)

View File

@ -42,8 +42,10 @@ export class ProjectService {
listProjects(name: string, isPublic: number, page?: number, pageSize?: number): Observable<any>{ listProjects(name: string, isPublic: number, page?: number, pageSize?: number): Observable<any>{
let params = new URLSearchParams(); let params = new URLSearchParams();
params.set('page', page + ''); if(page && pageSize) {
params.set('page_size', pageSize + ''); params.set('page', page + '');
params.set('page_size', pageSize + '');
}
return this.http return this.http
.get(`/api/projects?project_name=${name}&is_public=${isPublic}`, {search: params}) .get(`/api/projects?project_name=${name}&is_public=${isPublic}`, {search: params})
.map(response=>response) .map(response=>response)

View File

@ -157,7 +157,6 @@ export class CreateEditDestinationComponent implements AfterViewChecked {
.subscribe( .subscribe(
response=>{ response=>{
this.messageHandlerService.showSuccess('DESTINATION.CREATED_SUCCESS'); this.messageHandlerService.showSuccess('DESTINATION.CREATED_SUCCESS');
console.log('Successful added target.');
this.createEditDestinationOpened = false; this.createEditDestinationOpened = false;
this.reload.emit(true); this.reload.emit(true);
}, },
@ -206,7 +205,6 @@ export class CreateEditDestinationComponent implements AfterViewChecked {
.subscribe( .subscribe(
response=>{ response=>{
this.messageHandlerService.showSuccess('DESTINATION.UPDATED_SUCCESS'); this.messageHandlerService.showSuccess('DESTINATION.UPDATED_SUCCESS');
console.log('Successful updated target.');
this.createEditDestinationOpened = false; this.createEditDestinationOpened = false;
this.reload.emit(true); this.reload.emit(true);
}, },

View File

@ -18,7 +18,7 @@
<clr-dg-column>{{'DESTINATION.NAME' | translate}}</clr-dg-column> <clr-dg-column>{{'DESTINATION.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'DESTINATION.URL' | translate}}</clr-dg-column> <clr-dg-column>{{'DESTINATION.URL' | translate}}</clr-dg-column>
<clr-dg-column>{{'DESTINATION.CREATION_TIME' | translate}}</clr-dg-column> <clr-dg-column>{{'DESTINATION.CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let t of targets" [clrDgItem]='t'> <clr-dg-row *clrDgItems="let t of targets" [clrDgItem]='t'>
<clr-dg-action-overflow> <clr-dg-action-overflow>
<button class="action-item" (click)="editTarget(t)">{{'DESTINATION.TITLE_EDIT' | translate}}</button> <button class="action-item" (click)="editTarget(t)">{{'DESTINATION.TITLE_EDIT' | translate}}</button>
<button class="action-item" (click)="deleteTarget(t)">{{'DESTINATION.DELETE' | translate}}</button> <button class="action-item" (click)="deleteTarget(t)">{{'DESTINATION.DELETE' | translate}}</button>

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 { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { Component, OnInit, ViewChild, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { Target } from '../target'; import { Target } from '../target';
import { ReplicationService } from '../replication.service'; import { ReplicationService } from '../replication.service';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
@ -28,7 +28,8 @@ import { CreateEditDestinationComponent } from '../create-edit-destination/creat
@Component({ @Component({
selector: 'destination', selector: 'destination',
templateUrl: 'destination.component.html', templateUrl: 'destination.component.html',
styleUrls: ['./destination.component.css'] styleUrls: ['./destination.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class DestinationComponent implements OnInit { export class DestinationComponent implements OnInit {
@ -44,7 +45,8 @@ export class DestinationComponent implements OnInit {
constructor( constructor(
private replicationService: ReplicationService, private replicationService: ReplicationService,
private messageHandlerService: MessageHandlerService, private messageHandlerService: MessageHandlerService,
private deletionDialogService: ConfirmationDialogService) { private deletionDialogService: ConfirmationDialogService,
private ref: ChangeDetectorRef) {
this.subscription = this.deletionDialogService.confirmationConfirm$.subscribe(message => { this.subscription = this.deletionDialogService.confirmationConfirm$.subscribe(message => {
if (message && if (message &&
message.source === ConfirmationTargets.TARGET && message.source === ConfirmationTargets.TARGET &&
@ -55,7 +57,7 @@ export class DestinationComponent implements OnInit {
.subscribe( .subscribe(
response => { response => {
this.messageHandlerService.showSuccess('DESTINATION.DELETED_SUCCESS'); this.messageHandlerService.showSuccess('DESTINATION.DELETED_SUCCESS');
this.reload(); this.reload(true);
}, },
error => { error => {
if(error && error.status === 412) { if(error && error.status === 412) {
@ -66,6 +68,8 @@ export class DestinationComponent implements OnInit {
}); });
} }
}); });
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
} }
ngOnInit(): void { ngOnInit(): void {
@ -83,7 +87,11 @@ export class DestinationComponent implements OnInit {
this.replicationService this.replicationService
.listTargets(targetName) .listTargets(targetName)
.subscribe( .subscribe(
targets => this.targets = targets, targets => {
this.targets = targets || [];
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
},
error => this.messageHandlerService.handleError(error) error => this.messageHandlerService.handleError(error)
); );
} }
@ -97,7 +105,7 @@ export class DestinationComponent implements OnInit {
this.retrieve(''); this.retrieve('');
} }
reload() { reload($event: any) {
this.targetName = ''; this.targetName = '';
this.retrieve(''); this.retrieve('');
} }
@ -124,6 +132,8 @@ export class DestinationComponent implements OnInit {
} }
} }
this.createEditDestinationComponent.openCreateEditTarget(editable, target.id); this.createEditDestinationComponent.openCreateEditTarget(editable, target.id);
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}, },
error=>this.messageHandlerService.handleError(error) error=>this.messageHandlerService.handleError(error)
); );

View File

@ -11,14 +11,15 @@
// 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 { Component, Input, Output, EventEmitter } from '@angular/core'; import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { Job } from '../job'; import { Job } from '../job';
import { State } from 'clarity-angular'; import { State } from 'clarity-angular';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
@Component({ @Component({
selector: 'list-job', selector: 'list-job',
templateUrl: 'list-job.component.html' templateUrl: 'list-job.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListJobComponent { export class ListJobComponent {
@Input() jobs: Job[]; @Input() jobs: Job[];
@ -26,7 +27,12 @@ export class ListJobComponent {
@Input() totalPage: number; @Input() totalPage: number;
@Output() paginate = new EventEmitter<State>(); @Output() paginate = new EventEmitter<State>();
constructor(private messageHandlerService: MessageHandlerService) {} constructor(
private messageHandlerService: MessageHandlerService,
private ref: ChangeDetectorRef) {
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}
pageOffset: number = 1; pageOffset: number = 1;

View File

@ -18,11 +18,8 @@ import { CreateEditPolicyComponent } from '../shared/create-edit-policy/create-e
import { MessageHandlerService } from '../shared/message-handler/message-handler.service'; import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
import { SessionService } from '../shared/session.service';
import { ReplicationService } from './replication.service'; import { ReplicationService } from './replication.service';
import { SessionUser } from '../shared/session-user';
import { Policy } from './policy'; import { Policy } from './policy';
import { Job } from './job'; import { Job } from './job';
import { Target } from './target'; import { Target } from './target';
@ -65,8 +62,7 @@ class SearchOption {
styleUrls: ['./replication.component.css'] styleUrls: ['./replication.component.css']
}) })
export class ReplicationComponent implements OnInit { export class ReplicationComponent implements OnInit {
currentUser: SessionUser;
projectId: number; projectId: number;
search: SearchOption; search: SearchOption;
@ -94,11 +90,9 @@ export class ReplicationComponent implements OnInit {
createEditPolicyComponent: CreateEditPolicyComponent; createEditPolicyComponent: CreateEditPolicyComponent;
constructor( constructor(
private sessionService: SessionService,
private messageHandlerService: MessageHandlerService, private messageHandlerService: MessageHandlerService,
private replicationService: ReplicationService, private replicationService: ReplicationService,
private route: ActivatedRoute) { private route: ActivatedRoute) {
this.currentUser = this.sessionService.getCurrentUser();
} }
ngOnInit(): void { ngOnInit(): void {
@ -120,7 +114,7 @@ export class ReplicationComponent implements OnInit {
.listPolicies(this.search.policyName, this.projectId) .listPolicies(this.search.policyName, this.projectId)
.subscribe( .subscribe(
response=>{ response=>{
this.changedPolicies = response; this.changedPolicies = response || [];
if(this.changedPolicies && this.changedPolicies.length > 0) { if(this.changedPolicies && this.changedPolicies.length > 0) {
this.initSelectedId = this.changedPolicies[0].id; this.initSelectedId = this.changedPolicies[0].id;
} }
@ -128,8 +122,6 @@ export class ReplicationComponent implements OnInit {
if(this.changedPolicies && this.changedPolicies.length > 0) { if(this.changedPolicies && this.changedPolicies.length > 0) {
this.search.policyId = this.changedPolicies[0].id; this.search.policyId = this.changedPolicies[0].id;
this.fetchPolicyJobs(); this.fetchPolicyJobs();
} else {
this.changedJobs = [];
} }
}, },
error=>this.messageHandlerService.handleError(error) error=>this.messageHandlerService.handleError(error)
@ -169,7 +161,7 @@ export class ReplicationComponent implements OnInit {
this.messageHandlerService.showError('REPLICATION.FOUND_ERROR_IN_JOBS', ''); this.messageHandlerService.showError('REPLICATION.FOUND_ERROR_IN_JOBS', '');
break; break;
} }
} }
}, },
error=>this.messageHandlerService.handleError(error) error=>this.messageHandlerService.handleError(error)
); );

View File

@ -100,7 +100,6 @@ export class ReplicationService {
} }
enablePolicy(policyId: number, enabled: number): Observable<any> { enablePolicy(policyId: number, enabled: number): Observable<any> {
console.log('Enable or disable policy ID:' + policyId + ' with activation status:' + enabled);
return this.http return this.http
.put(`/api/policies/replication/${policyId}/enablement`, {enabled: enabled}) .put(`/api/policies/replication/${policyId}/enablement`, {enabled: enabled})
.map(response=>response.status) .map(response=>response.status)
@ -108,7 +107,6 @@ export class ReplicationService {
} }
deletePolicy(policyId: number): Observable<any> { deletePolicy(policyId: number): Observable<any> {
console.log('Delete policy ID:' + policyId);
return this.http return this.http
.delete(`/api/policies/replication/${policyId}`) .delete(`/api/policies/replication/${policyId}`)
.map(response=>response.status) .map(response=>response.status)

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 { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ReplicationService } from '../../replication/replication.service'; import { ReplicationService } from '../../replication/replication.service';
import { CreateEditPolicyComponent } from '../../shared/create-edit-policy/create-edit-policy.component'; import { CreateEditPolicyComponent } from '../../shared/create-edit-policy/create-edit-policy.component';
@ -24,7 +24,8 @@ import { Policy } from '../../replication/policy';
selector: 'total-replication', selector: 'total-replication',
templateUrl: 'total-replication.component.html', templateUrl: 'total-replication.component.html',
providers: [ ReplicationService ], providers: [ ReplicationService ],
styleUrls: ['./total-replication.component.css'] styleUrls: ['./total-replication.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class TotalReplicationComponent implements OnInit { export class TotalReplicationComponent implements OnInit {
@ -38,7 +39,11 @@ export class TotalReplicationComponent implements OnInit {
constructor( constructor(
private replicationService: ReplicationService, private replicationService: ReplicationService,
private messageHandlerService: MessageHandlerService) {} private messageHandlerService: MessageHandlerService,
private ref: ChangeDetectorRef) {
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}
ngOnInit() { ngOnInit() {
this.retrievePolicies(); this.retrievePolicies();

View File

@ -2,7 +2,7 @@
<clr-dg-column>{{'REPOSITORY.NAME' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPOSITORY.TAGS_COUNT' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.TAGS_COUNT' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPOSITORY.PULL_COUNT' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.PULL_COUNT' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let r of repositories" [clrDgItem]='r'> <clr-dg-row *clrDgItems="let r of repositories" [clrDgItem]='r'>
<clr-dg-action-overflow [hidden]="!hasProjectAdminRole"> <clr-dg-action-overflow [hidden]="!hasProjectAdminRole">
<button class="action-item" (click)="deleteRepo(r.name)">{{'REPOSITORY.DELETE' | translate}}</button> <button class="action-item" (click)="deleteRepo(r.name)">{{'REPOSITORY.DELETE' | translate}}</button>
</clr-dg-action-overflow> </clr-dg-action-overflow>
@ -11,7 +11,7 @@
<clr-dg-cell>{{r.pull_count}}</clr-dg-cell> <clr-dg-cell>{{r.pull_count}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
{{totalRecordCount || (repositories ? repositories.length : 0)}} {{'REPOSITORY.ITEMS' | translate}} {{(repositories ? repositories.length : 0)}} {{'REPOSITORY.ITEMS' | translate}}
<clr-dg-pagination [clrDgPageSize]="pageOffset" [clrDgTotalItems]="totalPage"></clr-dg-pagination> <clr-dg-pagination [clrDgPageSize]="15"></clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>

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 { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; import { Component, Input, Output, EventEmitter, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { Repository } from '../repository'; import { Repository } from '../repository';
import { State } from 'clarity-angular'; import { State } from 'clarity-angular';
@ -20,18 +20,15 @@ import { SearchTriggerService } from '../../base/global-search/search-trigger.se
@Component({ @Component({
selector: 'list-repository', selector: 'list-repository',
templateUrl: 'list-repository.component.html' templateUrl: 'list-repository.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListRepositoryComponent implements OnInit { export class ListRepositoryComponent implements OnInit {
@Input() projectId: number; @Input() projectId: number;
@Input() repositories: Repository[]; @Input() repositories: Repository[];
@Output() delete = new EventEmitter<string>(); @Output() delete = new EventEmitter<string>();
@Input() totalPage: number;
@Input() totalRecordCount: number;
@Output() paginate = new EventEmitter<State>(); @Output() paginate = new EventEmitter<State>();
@Input() hasProjectAdminRole: boolean; @Input() hasProjectAdminRole: boolean;
@ -40,7 +37,11 @@ export class ListRepositoryComponent implements OnInit {
constructor( constructor(
private router: Router, private router: Router,
private searchTrigger: SearchTriggerService) { } private searchTrigger: SearchTriggerService,
private ref: ChangeDetectorRef) {
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}
ngOnInit() { } ngOnInit() { }

View File

@ -8,6 +8,6 @@
</div> </div>
</div> </div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<list-repository [projectId]="projectId" [repositories]="changedRepositories" (delete)="deleteRepo($event)" [totalPage]="totalPage" [totalRecordCount]="totalRecordCount" [hasProjectAdminRole]="hasProjectAdminRole" (paginate)="retrieve($event)"></list-repository> <list-repository [projectId]="projectId" [repositories]="changedRepositories" (delete)="deleteRepo($event)" [hasProjectAdminRole]="hasProjectAdminRole" (paginate)="retrieve($event)"></list-repository>
</div> </div>
</div> </div>

View File

@ -41,9 +41,6 @@ export class RepositoryComponent implements OnInit {
lastFilteredRepoName: string; lastFilteredRepoName: string;
page: number = 1;
pageSize: number = 15;
totalPage: number; totalPage: number;
totalRecordCount: number; totalRecordCount: number;
@ -71,7 +68,6 @@ export class RepositoryComponent implements OnInit {
response => { response => {
this.refresh(); this.refresh();
this.messageHandlerService.showSuccess('REPOSITORY.DELETED_REPO_SUCCESS'); this.messageHandlerService.showSuccess('REPOSITORY.DELETED_REPO_SUCCESS');
console.log('Successful deleted repo:' + repoName);
}, },
error => this.messageHandlerService.handleError(error) error => this.messageHandlerService.handleError(error)
); );
@ -97,16 +93,10 @@ export class RepositoryComponent implements OnInit {
} }
retrieve(state?: State) { retrieve(state?: State) {
if (state) {
this.page = state.page.to + 1;
}
this.repositoryService this.repositoryService
.listRepositories(this.projectId, this.lastFilteredRepoName, this.page, this.pageSize) .listRepositories(this.projectId, this.lastFilteredRepoName)
.subscribe( .subscribe(
response => { response => {
this.totalRecordCount = response.headers.get('x-total-count');
this.totalPage = Math.ceil(this.totalRecordCount / this.pageSize);
console.log('TotalRecordCount:' + this.totalRecordCount + ', totalPage:' + this.totalPage);
this.changedRepositories = response.json(); this.changedRepositories = response.json();
}, },
error => this.messageHandlerService.handleError(error) error => this.messageHandlerService.handleError(error)

View File

@ -28,10 +28,11 @@ export class RepositoryService {
constructor(private http: Http){} constructor(private http: Http){}
listRepositories(projectId: number, repoName: string, page?: number, pageSize?: number): Observable<any> { listRepositories(projectId: number, repoName: string, page?: number, pageSize?: number): Observable<any> {
console.log('List repositories with project ID:' + projectId);
let params = new URLSearchParams(); let params = new URLSearchParams();
params.set('page', page + ''); if(page && pageSize) {
params.set('page_size', pageSize + ''); params.set('page', page + '');
params.set('page_size', pageSize + '');
}
return this.http return this.http
.get(`/api/repositories?project_id=${projectId}&q=${repoName}&detail=1`, {search: params}) .get(`/api/repositories?project_id=${projectId}&q=${repoName}&detail=1`, {search: params})
.map(response=>response) .map(response=>response)
@ -75,7 +76,6 @@ export class RepositoryService {
} }
deleteRepository(repoName: string): Observable<any> { deleteRepository(repoName: string): Observable<any> {
console.log('Delete repository with repo name:' + repoName);
return this.http return this.http
.delete(`/api/repositories/${repoName}/tags`) .delete(`/api/repositories/${repoName}/tags`)
.map(response=>response.status) .map(response=>response.status)
@ -83,7 +83,6 @@ export class RepositoryService {
} }
deleteRepoByTag(repoName: string, tag: string): Observable<any> { deleteRepoByTag(repoName: string, tag: string): Observable<any> {
console.log('Delete repository with repo name:' + repoName + ', tag:' + tag);
return this.http return this.http
.delete(`/api/repositories/${repoName}/tags/${tag}`) .delete(`/api/repositories/${repoName}/tags/${tag}`)
.map(response=>response.status) .map(response=>response.status)

View File

@ -24,7 +24,7 @@
<clr-dg-column>{{'REPOSITORY.DOCKER_VERSION' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.DOCKER_VERSION' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPOSITORY.ARCHITECTURE' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.ARCHITECTURE' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPOSITORY.OS' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.OS' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let t of tags" [clrDgItem]='t'> <clr-dg-row *clrDgItems="let t of tags" [clrDgItem]='t'>
<clr-dg-action-overflow> <clr-dg-action-overflow>
<button class="action-item" (click)="showTagID('tag', t)">{{'REPOSITORY.COPY_ID' | translate}}</button> <button class="action-item" (click)="showTagID('tag', t)">{{'REPOSITORY.COPY_ID' | translate}}</button>
<button class="action-item" (click)="showTagID('parent', t)">{{'REPOSITORY.COPY_PARENT_ID' | translate}}</button> <button class="action-item" (click)="showTagID('parent', t)">{{'REPOSITORY.COPY_PARENT_ID' | translate}}</button>

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 { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { RepositoryService } from '../repository.service'; import { RepositoryService } from '../repository.service';
@ -35,7 +35,8 @@ import { Project } from '../../project/project';
@Component({ @Component({
selector: 'tag-repository', selector: 'tag-repository',
templateUrl: 'tag-repository.component.html', templateUrl: 'tag-repository.component.html',
styleUrls: ['./tag-repository.component.css'] styleUrls: ['./tag-repository.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class TagRepositoryComponent implements OnInit, OnDestroy { export class TagRepositoryComponent implements OnInit, OnDestroy {
@ -58,7 +59,7 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
selectAll: boolean = false; selectAll: boolean = false;
private subscription: Subscription; subscription: Subscription;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@ -66,8 +67,9 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
private deletionDialogService: ConfirmationDialogService, private deletionDialogService: ConfirmationDialogService,
private repositoryService: RepositoryService, private repositoryService: RepositoryService,
private appConfigService: AppConfigService, private appConfigService: AppConfigService,
private session: SessionService){ private session: SessionService,
private ref: ChangeDetectorRef){
this.subscription = this.deletionDialogService.confirmationConfirm$.subscribe( this.subscription = this.deletionDialogService.confirmationConfirm$.subscribe(
message => { message => {
if (message && if (message &&
@ -85,7 +87,6 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
response => { response => {
this.retrieve(); this.retrieve();
this.messageHandlerService.showSuccess('REPOSITORY.DELETED_TAG_SUCCESS'); this.messageHandlerService.showSuccess('REPOSITORY.DELETED_TAG_SUCCESS');
console.log('Deleted repo:' + this.repoName + ' with tag:' + tagName);
}, },
error => this.messageHandlerService.handleError(error) error => this.messageHandlerService.handleError(error)
); );
@ -132,7 +133,7 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
} }
} }
private listTags(tags: Tag[]): void { listTags(tags: Tag[]): void {
tags.forEach(t => { tags.forEach(t => {
let tag = new TagView(); let tag = new TagView();
tag.tag = t.tag; tag.tag = t.tag;
@ -148,6 +149,8 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
tag.parent = data['parent']; tag.parent = data['parent'];
this.tags.push(tag); this.tags.push(tag);
}); });
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
} }
deleteTag(tag: TagView) { deleteTag(tag: TagView) {
@ -187,7 +190,7 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
this.showTagManifestOpened = true; this.showTagManifestOpened = true;
} }
} }
selectAndCopy($event) { selectAndCopy($event: any) {
$event.target.select(); $event.target.select();
} }
} }

View File

@ -27,7 +27,7 @@ import { Repository } from '../repository';
providers: [TopRepoService] providers: [TopRepoService]
}) })
export class TopRepoComponent implements OnInit{ export class TopRepoComponent implements OnInit{
private topRepos: Repository[] = []; topRepos: Repository[] = [];
constructor( constructor(
private topRepoService: TopRepoService, private topRepoService: TopRepoService,

View File

@ -27,10 +27,10 @@ export const topRepoEndpoint = "/api/repositories/top?detail=1";
*/ */
@Injectable() @Injectable()
export class TopRepoService { export class TopRepoService {
private headers = new Headers({ headers = new Headers({
"Content-Type": 'application/json' "Content-Type": 'application/json'
}); });
private options = new RequestOptions({ options = new RequestOptions({
headers: this.headers headers: this.headers
}); });

View File

@ -21,8 +21,8 @@ import { AppConfigService } from '../../app-config.service';
styleUrls: ["about-dialog.component.css"] styleUrls: ["about-dialog.component.css"]
}) })
export class AboutDialogComponent { export class AboutDialogComponent {
private opened: boolean = false; opened: boolean = false;
private build: string = "4276418"; build: string = "4276418";
constructor(private appConfigService: AppConfigService) { } constructor(private appConfigService: AppConfigService) { }

View File

@ -33,7 +33,7 @@ export class ConfirmationDialogComponent implements OnDestroy {
buttonKey: string = 'BUTTON.OK'; buttonKey: string = 'BUTTON.OK';
confirmOnly: boolean = false; confirmOnly: boolean = false;
message: ConfirmationMessage; message: ConfirmationMessage;
private annouceSubscription: Subscription; annouceSubscription: Subscription;
constructor( constructor(
private confirmationService: ConfirmationDialogService, private confirmationService: ConfirmationDialogService,

View File

@ -20,8 +20,8 @@ import { ConfirmationAcknowledgement } from './confirmation-state-message';
@Injectable() @Injectable()
export class ConfirmationDialogService { export class ConfirmationDialogService {
private confirmationAnnoucedSource = new Subject<ConfirmationMessage>(); confirmationAnnoucedSource = new Subject<ConfirmationMessage>();
private confirmationConfirmSource = new Subject<ConfirmationAcknowledgement>(); confirmationConfirmSource = new Subject<ConfirmationAcknowledgement>();
confirmationAnnouced$ = this.confirmationAnnoucedSource.asObservable(); confirmationAnnouced$ = this.confirmationAnnoucedSource.asObservable();
confirmationConfirm$ = this.confirmationConfirmSource.asObservable(); confirmationConfirm$ = this.confirmationConfirmSource.asObservable();

View File

@ -157,7 +157,6 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
} }
newDestination(checkedAddNew: boolean): void { newDestination(checkedAddNew: boolean): void {
console.log('CheckedAddNew:' + checkedAddNew);
this.isCreateDestination = checkedAddNew; this.isCreateDestination = checkedAddNew;
if(this.isCreateDestination) { if(this.isCreateDestination) {
this.createEditPolicy.targetName = ''; this.createEditPolicy.targetName = '';
@ -201,13 +200,11 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
} }
createPolicy(): void { createPolicy(): void {
console.log('Create policy with existing target in component.');
this.replicationService this.replicationService
.createPolicy(this.getPolicyByForm()) .createPolicy(this.getPolicyByForm())
.subscribe( .subscribe(
response=>{ response=>{
this.messageHandlerService.showSuccess('REPLICATION.CREATED_SUCCESS'); this.messageHandlerService.showSuccess('REPLICATION.CREATED_SUCCESS');
console.log('Successful created policy: ' + response);
this.createEditPolicyOpened = false; this.createEditPolicyOpened = false;
this.reload.emit(true); this.reload.emit(true);
}, },
@ -220,18 +217,16 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
} else { } else {
this.inlineAlert.showInlineError(error); this.inlineAlert.showInlineError(error);
} }
console.log('Failed to create policy:' + error.status + ', error message:' + JSON.stringify(error['_body'])); console.error('Failed to create policy:' + error.status + ', error message:' + JSON.stringify(error['_body']));
}); });
} }
createOrUpdatePolicyAndCreateTarget(): void { createOrUpdatePolicyAndCreateTarget(): void {
console.log('Creating policy with new created target.');
this.replicationService this.replicationService
.createOrUpdatePolicyWithNewTarget(this.getPolicyByForm(), this.getTargetByForm()) .createOrUpdatePolicyWithNewTarget(this.getPolicyByForm(), this.getTargetByForm())
.subscribe( .subscribe(
response=>{ response=>{
this.messageHandlerService.showSuccess('REPLICATION.CREATED_SUCCESS'); this.messageHandlerService.showSuccess('REPLICATION.CREATED_SUCCESS');
console.log('Successful created policy and target:' + response);
this.createEditPolicyOpened = false; this.createEditPolicyOpened = false;
this.reload.emit(true); this.reload.emit(true);
}, },
@ -244,18 +239,16 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
} else { } else {
this.inlineAlert.showInlineError(error); this.inlineAlert.showInlineError(error);
} }
console.log('Failed to create policy and target:' + error.status + ', error message:' + JSON.stringify(error['_body'])); console.error('Failed to create policy and target:' + error.status + ', error message:' + JSON.stringify(error['_body']));
} }
); );
} }
updatePolicy(): void { updatePolicy(): void {
console.log('Creating policy with existing target.');
this.replicationService this.replicationService
.updatePolicy(this.getPolicyByForm()) .updatePolicy(this.getPolicyByForm())
.subscribe( .subscribe(
response=>{ response=>{
console.log('Successful created policy and target:' + response);
this.messageHandlerService.showSuccess('REPLICATION.UPDATED_SUCCESS') this.messageHandlerService.showSuccess('REPLICATION.UPDATED_SUCCESS')
this.createEditPolicyOpened = false; this.createEditPolicyOpened = false;
this.reload.emit(true); this.reload.emit(true);
@ -269,7 +262,7 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
} else { } else {
this.inlineAlert.showInlineError(error); this.inlineAlert.showInlineError(error);
} }
console.log('Failed to create policy and target:' + error.status + ', error message:' + JSON.stringify(error['_body'])); console.error('Failed to create policy and target:' + error.status + ', error message:' + JSON.stringify(error['_body']));
} }
); );
} }

View File

@ -27,12 +27,12 @@ import 'rxjs/add/operator/distinctUntilChanged';
export class FilterComponent implements OnInit { export class FilterComponent implements OnInit {
private placeHolder: string = ""; placeHolder: string = "";
private filterTerms = new Subject<string>(); filterTerms = new Subject<string>();
@Output("filter") private filterEvt = new EventEmitter<string>(); @Output("filter") private filterEvt = new EventEmitter<string>();
@Input() currentValue; @Input() currentValue: string;
@Input("filterPlaceholder") @Input("filterPlaceholder")
public set flPlaceholder(placeHolder: string) { public set flPlaceholder(placeHolder: string) {
this.placeHolder = placeHolder; this.placeHolder = placeHolder;

View File

@ -37,13 +37,13 @@ const RESOURCE_COLOR_GREY600: string = '#C7D1D6';
}) })
export class GaugeComponent implements AfterViewInit { export class GaugeComponent implements AfterViewInit {
private _backgroundColor: string; _backgroundColor: string;
private _colorOne: string; _colorOne: string;
private _colorTwo: string; _colorTwo: string;
private _size: string = "small"; //Support small, medium, large _size: string = "small"; //Support small, medium, large
private _title: string = "UNKNOWN"; //Lang key _title: string = "UNKNOWN"; //Lang key
private _free: number = 0; _free: number = 0;
private _threasHold: number = 0; _threasHold: number = 0;
/** /**
* Background color of the component. Default is white. * Background color of the component. Default is white.
@ -60,7 +60,7 @@ export class GaugeComponent implements AfterViewInit {
this._backgroundColor = value; this._backgroundColor = value;
} }
private _positionOne: number; _positionOne: number;
/** /**
* Keep these two properties * Keep these two properties
* Percentage of the total width for the first portion of the bar. * Percentage of the total width for the first portion of the bar.
@ -77,7 +77,7 @@ export class GaugeComponent implements AfterViewInit {
this.setBars(); this.setBars();
} }
private _positionTwo: number; _positionTwo: number;
/** /**
* Percentage of the total width for the second portion of the bar * Percentage of the total width for the second portion of the bar
*/ */
@ -91,7 +91,7 @@ export class GaugeComponent implements AfterViewInit {
this.setBars(); this.setBars();
} }
private _animate: boolean; _animate: boolean;
/** /**
* Whether to animate transitions in the bars * Whether to animate transitions in the bars
*/ */
@ -170,7 +170,7 @@ export class GaugeComponent implements AfterViewInit {
@ViewChild('barOne') private barOne: ElementRef; @ViewChild('barOne') private barOne: ElementRef;
@ViewChild('barTwo') private barTwo: ElementRef; @ViewChild('barTwo') private barTwo: ElementRef;
private determineColors() { determineColors() {
let percent: number = 0; let percent: number = 0;
if (this._threasHold !== 0) { if (this._threasHold !== 0) {
let used: number = this._threasHold - this._free; let used: number = this._threasHold - this._free;
@ -200,7 +200,7 @@ export class GaugeComponent implements AfterViewInit {
this.setAnimate(); this.setAnimate();
} }
private setBars() { setBars() {
if (!this.barOne || !this.barTwo) { if (!this.barOne || !this.barTwo) {
return; return;
} }
@ -238,7 +238,7 @@ export class GaugeComponent implements AfterViewInit {
}); });
} }
private setColors() { setColors() {
if (!this.barOne || !this.barTwo) { if (!this.barOne || !this.barTwo) {
return; return;
} }
@ -259,7 +259,7 @@ export class GaugeComponent implements AfterViewInit {
}); });
} }
private setAnimate() { setAnimate() {
if (!this.barOne || !this.barTwo) { if (!this.barOne || !this.barTwo) {
return; return;
} }

View File

@ -24,15 +24,15 @@ import { Subscription } from "rxjs";
styleUrls: ['inline-alert.component.css'] styleUrls: ['inline-alert.component.css']
}) })
export class InlineAlertComponent { export class InlineAlertComponent {
private inlineAlertType: string = 'alert-danger'; inlineAlertType: string = 'alert-danger';
private inlineAlertClosable: boolean = false; inlineAlertClosable: boolean = false;
private alertClose: boolean = true; alertClose: boolean = true;
private displayedText: string = ""; displayedText: string = "";
private showCancelAction: boolean = false; showCancelAction: boolean = false;
private useAppLevelStyle: boolean = false; useAppLevelStyle: boolean = false;
private timer: Subscription = null; timer: Subscription = null;
private count: number = 0; count: number = 0;
private blinking: boolean = false; blinking: boolean = false;
@Output() confirmEvt = new EventEmitter<boolean>(); @Output() confirmEvt = new EventEmitter<boolean>();
@ -90,7 +90,7 @@ export class InlineAlertComponent {
public blink() { public blink() {
} }
private confirmCancel(): void { confirmCancel(): void {
this.confirmEvt.emit(true); this.confirmEvt.emit(true);
} }
} }

View File

@ -5,26 +5,26 @@
<clr-dg-column>{{'REPLICATION.DESTINATION_NAME' | translate}}</clr-dg-column> <clr-dg-column>{{'REPLICATION.DESTINATION_NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.LAST_START_TIME' | translate}}</clr-dg-column> <clr-dg-column>{{'REPLICATION.LAST_START_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPLICATION.ACTIVATION' | translate}}</clr-dg-column> <clr-dg-column>{{'REPLICATION.ACTIVATION' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let p of policies;let i = index;" [clrDgItem]="p" (click)="selectPolicy(p)" [style.backgroundColor]="(!projectless && selectedId === p.id) ? '#eee' : ''"> <clr-dg-row *clrDgItems="let p of policies" [clrDgItem]="p" (click)="selectPolicy(p)" [style.backgroundColor]="(!projectless && selectedId === p.id) ? '#eee' : ''">
<clr-dg-action-overflow> <clr-dg-action-overflow>
<button class="action-item" (click)="editPolicy(p)">{{'REPLICATION.EDIT_POLICY' | translate}}</button> <button class="action-item" (click)="editPolicy(p)">{{'REPLICATION.EDIT_POLICY' | translate}}</button>
<button class="action-item" (click)="togglePolicy(p)">{{ (p.enabled === 0 ? 'REPLICATION.ENABLE' : 'REPLICATION.DISABLE') | translate}}</button> <button class="action-item" (click)="togglePolicy(p)">{{ (p.enabled === 0 ? 'REPLICATION.ENABLE' : 'REPLICATION.DISABLE') | translate}}</button>
<button class="action-item" (click)="deletePolicy(p)">{{'REPLICATION.DELETE_POLICY' | translate}}</button> <button class="action-item" (click)="deletePolicy(p)">{{'REPLICATION.DELETE_POLICY' | translate}}</button>
</clr-dg-action-overflow> </clr-dg-action-overflow>
<clr-dg-cell> <clr-dg-cell>
<template [ngIf]="projectless"> <ng-template [ngIf]="projectless">
<a href="javascript:void(0)" [routerLink]="['/harbor', 'projects', p.project_id, 'replication']">{{p.name}}</a> <a href="javascript:void(0)" [routerLink]="['/harbor', 'projects', p.project_id, 'replication']">{{p.name}}</a>
</template> </ng-template>
<template [ngIf]="!projectless"> <ng-template [ngIf]="!projectless">
{{p.name}} {{p.name}}
</template> </ng-template>
</clr-dg-cell> </clr-dg-cell>
<clr-dg-cell *ngIf="projectless">{{p.project_name}}</clr-dg-cell> <clr-dg-cell *ngIf="projectless">{{p.project_name}}</clr-dg-cell>
<clr-dg-cell>{{p.description ? p.description : '-'}}</clr-dg-cell> <clr-dg-cell>{{p.description ? p.description : '-'}}</clr-dg-cell>
<clr-dg-cell>{{p.target_name}}</clr-dg-cell> <clr-dg-cell>{{p.target_name}}</clr-dg-cell>
<clr-dg-cell> <clr-dg-cell>
<template [ngIf]="p.start_time === nullTime">-</template> <ng-template [ngIf]="p.start_time === nullTime">-</ng-template>
<template [ngIf]="p.start_time !== nullTime">{{p.start_time | date: 'short'}}</template> <ng-template [ngIf]="p.start_time !== nullTime">{{p.start_time | date: 'short'}}</ng-template>
</clr-dg-cell> </clr-dg-cell>
<clr-dg-cell> <clr-dg-cell>
{{ (p.enabled === 1 ? 'REPLICATION.ENABLED' : 'REPLICATION.DISABLED') | translate}} {{ (p.enabled === 1 ? 'REPLICATION.ENABLED' : 'REPLICATION.DISABLED') | translate}}

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 { Component, Input, Output, EventEmitter, ViewChild, OnDestroy } from '@angular/core'; import { Component, Input, Output, EventEmitter, ViewChild, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ReplicationService } from '../../replication/replication.service'; import { ReplicationService } from '../../replication/replication.service';
import { Policy } from '../../replication/policy'; import { Policy } from '../../replication/policy';
@ -28,6 +28,7 @@ import { Subscription } from 'rxjs/Subscription';
@Component({ @Component({
selector: 'list-policy', selector: 'list-policy',
templateUrl: 'list-policy.component.html', templateUrl: 'list-policy.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListPolicyComponent implements OnDestroy { export class ListPolicyComponent implements OnDestroy {
@ -49,8 +50,9 @@ export class ListPolicyComponent implements OnDestroy {
private replicationService: ReplicationService, private replicationService: ReplicationService,
private toggleConfirmDialogService: ConfirmationDialogService, private toggleConfirmDialogService: ConfirmationDialogService,
private deletionDialogService: ConfirmationDialogService, private deletionDialogService: ConfirmationDialogService,
private messageHandlerService: MessageHandlerService) { private messageHandlerService: MessageHandlerService,
private ref: ChangeDetectorRef) {
setInterval(()=>ref.markForCheck(), 500);
this.toggleSubscription = this.toggleConfirmDialogService this.toggleSubscription = this.toggleConfirmDialogService
.confirmationConfirm$ .confirmationConfirm$
.subscribe( .subscribe(
@ -60,13 +62,11 @@ export class ListPolicyComponent implements OnDestroy {
message.state === ConfirmationState.CONFIRMED) { message.state === ConfirmationState.CONFIRMED) {
let policy: Policy = message.data; let policy: Policy = message.data;
policy.enabled = policy.enabled === 0 ? 1 : 0; policy.enabled = policy.enabled === 0 ? 1 : 0;
console.log('Enable policy ID:' + policy.id + ' with activation status ' + policy.enabled);
this.replicationService this.replicationService
.enablePolicy(policy.id, policy.enabled) .enablePolicy(policy.id, policy.enabled)
.subscribe( .subscribe(
response => { response => {
this.messageHandlerService.showSuccess('REPLICATION.TOGGLED_SUCCESS'); this.messageHandlerService.showSuccess('REPLICATION.TOGGLED_SUCCESS');
console.log('Successful toggled policy status')
}, },
error => this.messageHandlerService.handleError(error) error => this.messageHandlerService.handleError(error)
); );
@ -85,7 +85,6 @@ export class ListPolicyComponent implements OnDestroy {
.subscribe( .subscribe(
response => { response => {
this.messageHandlerService.showSuccess('REPLICATION.DELETED_SUCCESS'); this.messageHandlerService.showSuccess('REPLICATION.DELETED_SUCCESS');
console.log('Successful delete policy with ID:' + message.data);
this.reload.emit(true); this.reload.emit(true);
}, },
error => { error => {
@ -98,8 +97,7 @@ export class ListPolicyComponent implements OnDestroy {
); );
} }
} }
); );
} }
ngOnDestroy() { ngOnDestroy() {
@ -113,12 +111,10 @@ export class ListPolicyComponent implements OnDestroy {
selectPolicy(policy: Policy): void { selectPolicy(policy: Policy): void {
this.selectedId = policy.id; this.selectedId = policy.id;
console.log('Select policy ID:' + policy.id);
this.selectOne.emit(policy); this.selectOne.emit(policy);
} }
editPolicy(policy: Policy) { editPolicy(policy: Policy) {
console.log('Open modal to edit policy.');
this.editOne.emit(policy); this.editOne.emit(policy);
} }

View File

@ -3,14 +3,14 @@
<clr-dg-column>{{'PROJECT.PUBLIC_OR_PRIVATE' | translate}}</clr-dg-column> <clr-dg-column>{{'PROJECT.PUBLIC_OR_PRIVATE' | translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.REPO_COUNT'| translate}}</clr-dg-column> <clr-dg-column>{{'PROJECT.REPO_COUNT'| translate}}</clr-dg-column>
<clr-dg-column>{{'PROJECT.CREATION_TIME' | translate}}</clr-dg-column> <clr-dg-column>{{'PROJECT.CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let p of projects" [clrDgItem]="p"> <clr-dg-row *clrDgItems="let p of projects" [clrDgItem]="p">
<clr-dg-cell><a href="javascript:void(0)" (click)="goToLink(p.project_id)">{{p.name}}</a></clr-dg-cell> <clr-dg-cell><a href="javascript:void(0)" (click)="goToLink(p.project_id)">{{p.name}}</a></clr-dg-cell>
<clr-dg-cell>{{ (p.public === 1 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}}</clr-dg-cell> <clr-dg-cell>{{ (p.public === 1 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}}</clr-dg-cell>
<clr-dg-cell>{{p.repo_count}}</clr-dg-cell> <clr-dg-cell>{{p.repo_count}}</clr-dg-cell>
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell> <clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
{{totalRecordCount || (projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}} {{(projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}}
<clr-dg-pagination [clrDgPageSize]="pageOffset" [clrDgTotalItems]="totalPage"></clr-dg-pagination> <clr-dg-pagination [clrDgPageSize]="5"></clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>

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 { Component, EventEmitter, Output, Input } from '@angular/core'; import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { SearchTriggerService } from '../../base/global-search/search-trigger.service'; import { SearchTriggerService } from '../../base/global-search/search-trigger.service';
@ -21,20 +21,21 @@ import { State } from 'clarity-angular';
@Component({ @Component({
selector: 'list-project-ro', selector: 'list-project-ro',
templateUrl: 'list-project-ro.component.html' templateUrl: 'list-project-ro.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListProjectROComponent { export class ListProjectROComponent {
@Input() projects: Project[]; @Input() projects: Project[];
@Input() totalPage: number;
@Input() totalRecordCount: number;
pageOffset: number = 1;
@Output() paginate = new EventEmitter<State>(); @Output() paginate = new EventEmitter<State>();
constructor( constructor(
private searchTrigger: SearchTriggerService, private searchTrigger: SearchTriggerService,
private router: Router) { } private router: Router,
private ref: ChangeDetectorRef) {
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}
goToLink(proId: number): void { goToLink(proId: number): void {
this.searchTrigger.closeSearch(true); this.searchTrigger.closeSearch(true);

View File

@ -2,13 +2,13 @@
<clr-dg-column>{{'REPOSITORY.NAME' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.NAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPOSITORY.TAGS_COUNT' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.TAGS_COUNT' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPOSITORY.PULL_COUNT' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.PULL_COUNT' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let r of repositories" [clrDgItem]='r'> <clr-dg-row *clrDgItems="let r of repositories" [clrDgItem]='r'>
<clr-dg-cell><a href="javascript:void(0)" (click)="gotoLink(projectId || r.project_id, r.name || r.repository_name)">{{r.name || r.repository_name}}</a></clr-dg-cell> <clr-dg-cell><a href="javascript:void(0)" (click)="gotoLink(projectId || r.project_id, r.name || r.repository_name)">{{r.name || r.repository_name}}</a></clr-dg-cell>
<clr-dg-cell>{{r.tags_count}}</clr-dg-cell> <clr-dg-cell>{{r.tags_count}}</clr-dg-cell>
<clr-dg-cell>{{r.pull_count}}</clr-dg-cell> <clr-dg-cell>{{r.pull_count}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
{{totalRecordCount || (repositories ? repositories.length : 0)}} {{'REPOSITORY.ITEMS' | translate}} {{(repositories ? repositories.length : 0)}} {{'REPOSITORY.ITEMS' | translate}}
<clr-dg-pagination [clrDgPageSize]="pageOffset" [clrDgTotalItems]="totalPage"></clr-dg-pagination> <clr-dg-pagination [clrDgPageSize]="3"></clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>

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 { Component, Input, Output, EventEmitter } from '@angular/core'; import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { Router, NavigationExtras } from '@angular/router'; import { Router, NavigationExtras } from '@angular/router';
import { Repository } from '../../repository/repository'; import { Repository } from '../../repository/repository';
import { State } from 'clarity-angular'; import { State } from 'clarity-angular';
@ -20,22 +20,23 @@ import { SearchTriggerService } from '../../base/global-search/search-trigger.se
@Component({ @Component({
selector: 'list-repository-ro', selector: 'list-repository-ro',
templateUrl: 'list-repository-ro.component.html' templateUrl: 'list-repository-ro.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListRepositoryROComponent { export class ListRepositoryROComponent {
@Input() projectId: number; @Input() projectId: number;
@Input() repositories: Repository[]; @Input() repositories: Repository[];
@Input() totalPage: number;
@Input() totalRecordCount: number;
@Output() paginate = new EventEmitter<State>(); @Output() paginate = new EventEmitter<State>();
pageOffset: number = 1;
constructor( constructor(
private router: Router, private router: Router,
private searchTrigger: SearchTriggerService private searchTrigger: SearchTriggerService,
) { } private ref: ChangeDetectorRef) {
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}
refresh(state: State) { refresh(state: State) {
if (this.repositories) { if (this.repositories) {

View File

@ -45,7 +45,7 @@ export function maxLengthExtValidator(length: number): ValidatorFn {
export class MaxLengthExtValidatorDirective implements Validator, OnChanges { export class MaxLengthExtValidatorDirective implements Validator, OnChanges {
@Input() maxLengthExt: number; @Input() maxLengthExt: number;
private valFn = Validators.nullValidator; valFn = Validators.nullValidator;
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
const change = changes['maxLengthExt']; const change = changes['maxLengthExt'];

View File

@ -82,7 +82,7 @@ export class MessageHandlerService {
this.msgService.clear(); this.msgService.clear();
} }
public isAppLevel(error): boolean { public isAppLevel(error: any): boolean {
return error && error.statusCode === httpStatusCode.Unauthorized; return error && error.statusCode === httpStatusCode.Unauthorized;
} }
} }

View File

@ -42,23 +42,25 @@ export class NewUserFormComponent implements AfterViewChecked, OnInit {
//Notify the form value changes //Notify the form value changes
@Output() valueChange = new EventEmitter<boolean>(); @Output() valueChange = new EventEmitter<boolean>();
confirmedPwd: string;
constructor(private session: SessionService) { } constructor(private session: SessionService) { }
ngOnInit() { ngOnInit() {
this.resetState(); this.resetState();
} }
private validationStateMap: any = {}; validationStateMap: any = {};
private mailAlreadyChecked: any = {}; mailAlreadyChecked: any = {};
private userNameAlreadyChecked: any = {}; userNameAlreadyChecked: any = {};
private emailTooltip: string = 'TOOLTIP.EMAIL'; emailTooltip: string = 'TOOLTIP.EMAIL';
private usernameTooltip: string = 'TOOLTIP.USER_NAME'; usernameTooltip: string = 'TOOLTIP.USER_NAME';
private formValueChanged: boolean = false; formValueChanged: boolean = false;
private checkOnGoing: any = {}; checkOnGoing: any = {};
private resetState(): void { resetState(): void {
this.mailAlreadyChecked = {}; this.mailAlreadyChecked = {};
this.userNameAlreadyChecked = {}; this.userNameAlreadyChecked = {};
this.emailTooltip = 'TOOLTIP.EMAIL'; this.emailTooltip = 'TOOLTIP.EMAIL';
@ -82,11 +84,11 @@ export class NewUserFormComponent implements AfterViewChecked, OnInit {
return !this.checkOnGoing[key]; return !this.checkOnGoing[key];
} }
private getValidationState(key: string): boolean { getValidationState(key: string): boolean {
return !this.validationStateMap[key]; return !this.validationStateMap[key];
} }
private handleValidation(key: string, flag: boolean): void { handleValidation(key: string, flag: boolean): void {
if (flag) { if (flag) {
//Checking //Checking
let cont = this.newUserForm.controls[key]; let cont = this.newUserForm.controls[key];

View File

@ -23,8 +23,8 @@ const defaultLeftTime = 5;
styleUrls: ['not-found.component.css'] styleUrls: ['not-found.component.css']
}) })
export class PageNotFoundComponent implements OnInit, OnDestroy{ export class PageNotFoundComponent implements OnInit, OnDestroy{
private leftSeconds: number = defaultLeftTime; leftSeconds: number = defaultLeftTime;
private timeInterval: any = null; timeInterval: any = null;
constructor(private router: Router){} constructor(private router: Router){}

View File

@ -42,7 +42,7 @@ export function portValidator(): ValidatorFn {
}) })
export class PortValidatorDirective implements Validator { export class PortValidatorDirective implements Validator {
private valFn = portValidator(); valFn = portValidator();
validate(control: AbstractControl): { [key: string]: any } { validate(control: AbstractControl): { [key: string]: any } {
return this.valFn(control); return this.valFn(control);

View File

@ -35,7 +35,7 @@ export class AuthCheckGuard implements CanActivate, CanActivateChild {
private msgHandler: MessageHandlerService, private msgHandler: MessageHandlerService,
private searchTrigger: SearchTriggerService) { } private searchTrigger: SearchTriggerService) { }
private isGuest(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { isGuest(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
const proRegExp = /\/harbor\/projects\/[\d]+\/.+/i; const proRegExp = /\/harbor\/projects\/[\d]+\/.+/i;
const libRegExp = /\/harbor\/tags\/[\d]+\/.+/i; const libRegExp = /\/harbor\/tags\/[\d]+\/.+/i;
if (proRegExp.test(state.url) || libRegExp.test(state.url)) { if (proRegExp.test(state.url) || libRegExp.test(state.url)) {

View File

@ -44,18 +44,18 @@ export class SessionService {
projectMembers: Member[]; projectMembers: Member[];
private headers = new Headers({ headers = new Headers({
"Content-Type": 'application/json' "Content-Type": 'application/json'
}); });
private formHeaders = new Headers({ formHeaders = new Headers({
"Content-Type": 'application/x-www-form-urlencoded' "Content-Type": 'application/x-www-form-urlencoded'
}); });
constructor(private http: Http) { } constructor(private http: Http) { }
//Handle the related exceptions //Handle the related exceptions
private handleError(error: any): Promise<any> { handleError(error: any): Promise<any> {
return Promise.reject(error.message || error); return Promise.reject(error.message || error);
} }

View File

@ -13,7 +13,7 @@
// 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 { CoreModule } from '../core/core.module';
import { CookieService } from 'angular2-cookie/core'; import { CookieService } from 'ngx-cookie';
import { SessionService } from '../shared/session.service'; import { SessionService } from '../shared/session.service';
import { MessageComponent } from '../global-message/message.component'; import { MessageComponent } from '../global-message/message.component';

View File

@ -24,7 +24,6 @@ export const errorHandler = function (error: any): string {
if (!error) { if (!error) {
return "UNKNOWN_ERROR"; return "UNKNOWN_ERROR";
} }
console.log(error);
if (!(error.statusCode || error.status)) { if (!(error.statusCode || error.status)) {
//treat as string message //treat as string message
return '' + error; return '' + error;

View File

@ -17,7 +17,7 @@ import { Subject } from 'rxjs/Subject';
@Injectable() @Injectable()
export class StatisticHandler { export class StatisticHandler {
private refreshSource = new Subject<boolean>(); refreshSource = new Subject<boolean>();
refreshChan$ = this.refreshSource.asObservable(); refreshChan$ = this.refreshSource.asObservable();

View File

@ -32,10 +32,11 @@ import { StatisticHandler } from './statistic-handler.service';
export class StatisticsPanelComponent implements OnInit, OnDestroy { export class StatisticsPanelComponent implements OnInit, OnDestroy {
private originalCopy: Statistics = new Statistics(); originalCopy: Statistics = new Statistics();
private volumesInfo: Volumes = new Volumes(); volumesInfo: Volumes = new Volumes();
refreshSub: Subscription; refreshSub: Subscription;
small: number;
constructor( constructor(
private statistics: StatisticsService, private statistics: StatisticsService,
private msgHandler: MessageHandlerService, private msgHandler: MessageHandlerService,
@ -97,7 +98,7 @@ export class StatisticsPanelComponent implements OnInit, OnDestroy {
return this.volumesInfo.storage.total != 0; return this.volumesInfo.storage.total != 0;
} }
private getGBFromBytes(bytes: number): number { getGBFromBytes(bytes: number): number {
return Math.round((bytes / (1024 * 1024 * 1024))); return Math.round((bytes / (1024 * 1024 * 1024)));
} }
} }

View File

@ -29,10 +29,10 @@ const volumesEndpoint = "/api/systeminfo/volumes";
*/ */
@Injectable() @Injectable()
export class StatisticsService { export class StatisticsService {
private headers = new Headers({ headers = new Headers({
"Content-Type": 'application/json' "Content-Type": 'application/json'
}); });
private options = new RequestOptions({ options = new RequestOptions({
headers: this.headers headers: this.headers
}); });

View File

@ -30,7 +30,7 @@ export class TargetExistsValidatorDirective implements Validator, OnChanges {
@Input() targetExists: string; @Input() targetExists: string;
@Input() projectId: number; @Input() projectId: number;
private valFn = Validators.nullValidator; valFn = Validators.nullValidator;
constructor( constructor(
private projectService: ProjectService, private projectService: ProjectService,
@ -51,7 +51,6 @@ export class TargetExistsValidatorDirective implements Validator, OnChanges {
targetExistsValidator(target: string): ValidatorFn { targetExistsValidator(target: string): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => { return (control: AbstractControl): {[key: string]: any} => {
console.log('Target:' + target + ', validate value:' + control.value);
switch(target) { switch(target) {
case 'PROJECT_NAME': case 'PROJECT_NAME':
return new Promise(resolve=>{ return new Promise(resolve=>{

View File

@ -29,9 +29,9 @@ import { MessageHandlerService } from '../shared/message-handler/message-handler
export class NewUserModalComponent { export class NewUserModalComponent {
opened: boolean = false; opened: boolean = false;
private error: any; error: any;
private onGoing: boolean = false; onGoing: boolean = false;
private formValueChanged: boolean = false; formValueChanged: boolean = false;
@Output() addNew = new EventEmitter<User>(); @Output() addNew = new EventEmitter<User>();
@ -40,11 +40,11 @@ export class NewUserModalComponent {
private msgHandler: MessageHandlerService) { } private msgHandler: MessageHandlerService) { }
@ViewChild(NewUserFormComponent) @ViewChild(NewUserFormComponent)
private newUserForm: NewUserFormComponent; newUserForm: NewUserFormComponent;
@ViewChild(InlineAlertComponent) @ViewChild(InlineAlertComponent)
private inlineAlert: InlineAlertComponent; inlineAlert: InlineAlertComponent;
private getNewUser(): User { getNewUser(): User {
return this.newUserForm.getData(); return this.newUserForm.getData();
} }

View File

@ -17,7 +17,7 @@
<clr-dg-column>{{'USER.COLUMN_ADMIN' | translate}}</clr-dg-column> <clr-dg-column>{{'USER.COLUMN_ADMIN' | translate}}</clr-dg-column>
<clr-dg-column>{{'USER.COLUMN_EMAIL' | translate}}</clr-dg-column> <clr-dg-column>{{'USER.COLUMN_EMAIL' | translate}}</clr-dg-column>
<clr-dg-column>{{'USER.COLUMN_REG_NAME' | translate}}</clr-dg-column> <clr-dg-column>{{'USER.COLUMN_REG_NAME' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let user of users" [clrDgItem]="user"> <clr-dg-row *clrDgItems="let user of users" [clrDgItem]="user">
<clr-dg-action-overflow [hidden]="isMySelf(user.user_id)"> <clr-dg-action-overflow [hidden]="isMySelf(user.user_id)">
<button class="action-item" (click)="changeAdminRole(user)">{{adminActions(user)}}</button> <button class="action-item" (click)="changeAdminRole(user)">{{adminActions(user)}}</button>
<button class="action-item" (click)="deleteUser(user)">{{'USER.DEL_ACTION' | translate}}</button> <button class="action-item" (click)="deleteUser(user)">{{'USER.DEL_ACTION' | translate}}</button>

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 { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { Component, OnInit, ViewChild, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import 'rxjs/add/operator/toPromise'; import 'rxjs/add/operator/toPromise';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
@ -31,22 +31,22 @@ import { AppConfigService } from '../app-config.service';
selector: 'harbor-user', selector: 'harbor-user',
templateUrl: 'user.component.html', templateUrl: 'user.component.html',
styleUrls: ['user.component.css'], styleUrls: ['user.component.css'],
providers: [UserService],
providers: [UserService] changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class UserComponent implements OnInit, OnDestroy { export class UserComponent implements OnInit, OnDestroy {
users: User[] = []; users: User[] = [];
originalUsers: Promise<User[]>; originalUsers: Promise<User[]>;
private onGoing: boolean = false; onGoing: boolean = false;
private adminMenuText: string = ""; adminMenuText: string = "";
private adminColumn: string = ""; adminColumn: string = "";
private deletionSubscription: Subscription; deletionSubscription: Subscription;
currentTerm: string; currentTerm: string;
@ViewChild(NewUserModalComponent) @ViewChild(NewUserModalComponent)
private newUserDialog: NewUserModalComponent; newUserDialog: NewUserModalComponent;
constructor( constructor(
private userService: UserService, private userService: UserService,
@ -54,7 +54,8 @@ export class UserComponent implements OnInit, OnDestroy {
private deletionDialogService: ConfirmationDialogService, private deletionDialogService: ConfirmationDialogService,
private msgHandler: MessageHandlerService, private msgHandler: MessageHandlerService,
private session: SessionService, private session: SessionService,
private appConfigService: AppConfigService) { private appConfigService: AppConfigService,
private ref: ChangeDetectorRef) {
this.deletionSubscription = deletionDialogService.confirmationConfirm$.subscribe(confirmed => { this.deletionSubscription = deletionDialogService.confirmationConfirm$.subscribe(confirmed => {
if (confirmed && if (confirmed &&
confirmed.source === ConfirmationTargets.USER && confirmed.source === ConfirmationTargets.USER &&
@ -62,9 +63,11 @@ export class UserComponent implements OnInit, OnDestroy {
this.delUser(confirmed.data); this.delUser(confirmed.data);
} }
}); });
let hnd = setInterval(()=>ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
} }
private isMySelf(uid: number): boolean { isMySelf(uid: number): boolean {
let currentUser = this.session.getCurrentUser(); let currentUser = this.session.getCurrentUser();
if (currentUser) { if (currentUser) {
if (currentUser.user_id === uid) { if (currentUser.user_id === uid) {
@ -75,7 +78,7 @@ export class UserComponent implements OnInit, OnDestroy {
return false; return false;
} }
private isMatchFilterTerm(terms: string, testedItem: string): boolean { isMatchFilterTerm(terms: string, testedItem: string): boolean {
return testedItem.indexOf(terms) != -1; return testedItem.indexOf(terms) != -1;
} }
@ -132,6 +135,8 @@ export class UserComponent implements OnInit, OnDestroy {
}) })
} }
}); });
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
} }
//Disable the admin role for the specified user //Disable the admin role for the specified user
@ -159,6 +164,8 @@ export class UserComponent implements OnInit, OnDestroy {
.then(() => { .then(() => {
//Change view now //Change view now
user.has_admin_role = updatedUser.has_admin_role; user.has_admin_role = updatedUser.has_admin_role;
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}) })
.catch(error => { .catch(error => {
this.msgHandler.handleError(error); this.msgHandler.handleError(error);
@ -186,7 +193,7 @@ export class UserComponent implements OnInit, OnDestroy {
this.deletionDialogService.openComfirmDialog(msg); this.deletionDialogService.openComfirmDialog(msg);
} }
private delUser(user: User): void { delUser(user: User): void {
this.userService.deleteUser(user.user_id) this.userService.deleteUser(user.user_id)
.then(() => { .then(() => {
//Remove it from current user list //Remove it from current user list
@ -195,6 +202,8 @@ export class UserComponent implements OnInit, OnDestroy {
this.originalUsers.then(users => { this.originalUsers.then(users => {
this.users = users.filter(u => u.user_id != user.user_id); this.users = users.filter(u => u.user_id != user.user_id);
this.msgHandler.showSuccess("USER.DELETE_SUCCESS"); this.msgHandler.showSuccess("USER.DELETE_SUCCESS");
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
}); });
}) })
.catch(error => { .catch(error => {
@ -211,7 +220,6 @@ export class UserComponent implements OnInit, OnDestroy {
this.originalUsers = this.userService.getUsers() this.originalUsers = this.userService.getUsers()
.then(users => { .then(users => {
this.onGoing = false; this.onGoing = false;
this.users = users; this.users = users;
return users; return users;
}) })
@ -219,6 +227,8 @@ export class UserComponent implements OnInit, OnDestroy {
this.onGoing = false; this.onGoing = false;
this.msgHandler.handleError(error); this.msgHandler.handleError(error);
}); });
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
setTimeout(()=>clearInterval(hnd), 1000);
} }
//Add new user //Add new user

View File

@ -27,7 +27,7 @@ const userMgmtEndpoint = '/api/users';
*/ */
@Injectable() @Injectable()
export class UserService { export class UserService {
private httpOptions = new RequestOptions({ httpOptions = new RequestOptions({
headers: new Headers({ headers: new Headers({
"Content-Type": 'application/json' "Content-Type": 'application/json'
}) })
@ -36,7 +36,7 @@ export class UserService {
constructor(private http: Http) { } constructor(private http: Http) { }
//Handle the related exceptions //Handle the related exceptions
private handleError(error: any): Promise<any> { handleError(error: any): Promise<any> {
return Promise.reject(error.message || error); return Promise.reject(error.message || error);
} }

11
src/ui_ng/src/main-aot.ts Normal file
View File

@ -0,0 +1,11 @@
import './polyfills.ts';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory';
enableProdMode();
platformBrowserDynamic().bootstrapModuleFactory(AppModuleNgFactory);

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true,
"typeRoots": [
"./node_modules/@types/"
]
},
"files": [
"src/app/app.module.ts",
"src/main-aot.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
}
}