Merge remote-tracking branch 'upstream/master' into master-ui-aot

This commit is contained in:
kunw 2017-04-25 20:34:44 +08:00
commit e8113fa3fa
36 changed files with 418 additions and 101 deletions

1
.gitignore vendored
View File

@ -42,3 +42,4 @@ src/ui_ng/aot/**/*.json
**/*ngsummary.json
**/*ngfactory.ts
**/aot

View File

@ -15,8 +15,8 @@
package utils
import (
"crypto/rand"
"fmt"
"math/rand"
"net"
"net/url"
"strings"
@ -65,11 +65,15 @@ func ParseRepository(repository string) (project, rest string) {
// GenerateRandomString generates a random string
func GenerateRandomString() string {
length := 32
rand.Seed(time.Now().UTC().UnixNano())
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
l := len(chars)
result := make([]byte, length)
_, err := rand.Read(result)
if err != nil {
log.Warningf("Error reading random bytes: %v", err)
}
for i := 0; i < length; i++ {
result[i] = chars[rand.Intn(len(chars))]
result[i] = chars[int(result[i])%l]
}
return string(result)
}

View File

@ -140,6 +140,10 @@ func TestGenerateRandomString(t *testing.T) {
if len(str) != 32 {
t.Errorf("unexpected length: %d != %d", len(str), 32)
}
str2 := GenerateRandomString()
if str2 == str {
t.Errorf("Two identical random strings in a row: %s", str)
}
}
func TestParseLink(t *testing.T) {

View File

@ -4,28 +4,24 @@
"name": "harbor-ui"
},
"apps": [{
"root": ".",
"outDir": "../dist",
"assets": [
"images",
"favicon.ico"
],
"index": "index.html",
"main": "index.ts",
"root": "src",
"outDir": "dist",
"index": "index.ts",
"main": "main.ts",
"test": "test.ts",
"tsconfig": "tsconfig.json",
"prefix": "",
"mobile": false,
"styles": [
"node_modules/clarity-icons/clarity-icons.min.css",
"node_modules/clarity-ui/clarity-ui.min.css"
"../node_modules/clarity-icons/clarity-icons.min.css",
"../node_modules/clarity-ui/clarity-ui.min.css"
],
"scripts": [
"node_modules/core-js/client/shim.min.js",
"node_modules/mutationobserver-shim/dist/mutationobserver.min.js",
"node_modules/@webcomponents/custom-elements/custom-elements.min.js",
"node_modules/clarity-icons/clarity-icons.min.js",
"node_modules/web-animations-js/web-animations.min.js"
"../node_modules/core-js/client/shim.min.js",
"../node_modules/mutationobserver-shim/dist/mutationobserver.min.js",
"../node_modules/@webcomponents/custom-elements/custom-elements.min.js",
"../node_modules/clarity-icons/clarity-icons.min.js",
"../node_modules/web-animations-js/web-animations.min.js"
],
"environmentSource": "environments/environment.ts",
"environments": {

View File

@ -0,0 +1,44 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-phantomjs-launcher'),
require('karma-mocha-reporter'),
require('karma-remap-istanbul'),
require('@angular/cli/plugins/karma')
],
files: [
{pattern: './src/test.ts', watched: false}
],
preprocessors: {
'./src/test.ts': ['@angular/cli']
},
mime: {
'text/x-typescript': ['ts', 'tsx']
},
remapIstanbulReporter: {
reports: {
html: 'coverage',
lcovonly: './coverage/coverage.lcov'
}
},
angularCli: {
config: './angular-cli.json',
environment: 'dev'
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['mocha', 'karma-remap-istanbul']
: ['mocha'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['PhantomJS'],
singleRun: true
});
};

View File

@ -6,6 +6,7 @@
"start": "ng serve --host 0.0.0.0 --port 4500 --proxy-config proxy.config.json",
"lint": "tslint \"src/**/*.ts\"",
"test": "ng test --single-run",
"test:once": "karma start karma.conf.js --single-run",
"pree2e": "webdriver-manager update",
"e2e": "protractor",
"cleanup": "rimraf dist/bundles dist/src dist/index.d.ts dist/index.metadata.json dist/index.js dist/index.js.map dist/LICENSE dist/AUTHORS",
@ -17,21 +18,28 @@
},
"private": true,
"dependencies": {
"@angular/common": "^4.0.0",
"@angular/compiler": "^4.0.0",
"@angular/core": "^4.0.0",
"@angular/http": "^4.0.0",
"clarity-angular": "^0.8.14",
"clarity-icons": "^0.8.14",
"clarity-ui": "^0.8.14",
"@angular/animations": "^4.0.1",
"@angular/common": "^4.0.1",
"@angular/compiler": "^4.0.1",
"@angular/core": "^4.0.1",
"@angular/forms": "^4.0.1",
"@angular/http": "^4.0.1",
"@angular/platform-browser": "^4.0.1",
"@angular/platform-browser-dynamic": "^4.0.1",
"@angular/router": "^4.0.1",
"@webcomponents/custom-elements": "1.0.0-alpha.3",
"web-animations-js": "^2.2.1",
"clarity-angular": "^0.9.0",
"clarity-icons": "^0.9.0",
"clarity-ui": "^0.9.0",
"core-js": "^2.4.1",
"rxjs": "^5.0.1",
"ts-helpers": "^1.1.1",
"zone.js": "^0.7.2"
"zone.js": "^0.8.4"
},
"devDependencies": {
"@angular/cli": "^1.0.0",
"@angular/compiler-cli": "^2.4.1",
"@angular/compiler-cli": "^4.0.1",
"@types/core-js": "^0.9.41",
"@types/jasmine": "~2.2.30",
"@types/node": "^6.0.42",
@ -50,7 +58,7 @@
"rollup": "^0.41.6",
"ts-node": "1.2.1",
"tslint": "^4.1.1",
"typescript": "~2.0.3",
"typescript": "~2.2.0",
"typings": "^1.4.0",
"uglify-js": "^2.8.22",
"webdriver-manager": "10.2.5",

View File

@ -19,16 +19,23 @@
},
"homepage": "https://github.com/vmware/harbor#readme",
"peerDependencies": {
"@angular/common": "^4.0.0",
"@angular/compiler": "^4.0.0",
"@angular/core": "^4.0.0",
"@angular/http": "^4.0.0",
"clarity-angular": "^0.8.14",
"clarity-icons": "^0.8.14",
"clarity-ui": "^0.8.14",
"@angular/animations": "^4.0.1",
"@angular/common": "^4.0.1",
"@angular/compiler": "^4.0.1",
"@angular/core": "^4.0.1",
"@angular/forms": "^4.0.1",
"@angular/http": "^4.0.1",
"@angular/platform-browser": "^4.0.1",
"@angular/platform-browser-dynamic": "^4.0.1",
"@angular/router": "^4.0.1",
"@webcomponents/custom-elements": "1.0.0-alpha.3",
"web-animations-js": "^2.2.1",
"clarity-angular": "^0.9.0",
"clarity-icons": "^0.9.0",
"clarity-ui": "^0.9.0",
"core-js": "^2.4.1",
"rxjs": "^5.0.1",
"ts-helpers": "^1.1.1",
"zone.js": "^0.7.2"
"zone.js": "^0.8.4"
}
}

View File

@ -0,0 +1,24 @@
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { ClarityModule } from 'clarity-angular';
import { HarborLibraryModule } from './harbor-library.module';
@NgModule({
declarations: [],
imports: [
BrowserAnimationsModule,
BrowserModule,
FormsModule,
HttpModule,
ClarityModule.forRoot(),
HarborLibraryModule.forRoot()
],
providers: [],
bootstrap: []
})
export class AppModule {
}

View File

@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@ -0,0 +1,8 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `angular-cli.json`.
export const environment = {
production: false
};

12
src/ui_ng/lib/src/main.ts Normal file
View File

@ -0,0 +1,12 @@
import './polyfills.ts';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { AppModule } from './app.module';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,22 @@
// This file includes polyfills needed by Angular 2 and is loaded before
// the app. You can add your own extra polyfills to this file.
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/set';
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';

View File

@ -5,14 +5,16 @@ import { AccessLogService, AccessLogDefaultService } from './access-log.service'
describe('AccessLogService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{
providers: [
AccessLogDefaultService,
{
provide: AccessLogService,
useClass: AccessLogDefaultService
}]
});
});
it('should ...', inject([AccessLogDefaultService], (service: AccessLogService) => {
it('should be initialized', inject([AccessLogDefaultService], (service: AccessLogService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -5,14 +5,16 @@ import { EndpointService, EndpointDefaultService } from './endpoint.service';
describe('EndpointService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{
providers: [
EndpointDefaultService,
{
provide: EndpointService,
useClass: EndpointDefaultService
}]
});
});
it('should ...', inject([EndpointDefaultService], (service: EndpointService) => {
it('should be initialized', inject([EndpointDefaultService], (service: EndpointService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -5,14 +5,16 @@ import { ReplicationService, ReplicationDefaultService } from './replication.ser
describe('ReplicationService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{
providers: [
ReplicationDefaultService,
{
provide: ReplicationService,
useClass: ReplicationDefaultService
}]
});
});
it('should ...', inject([ReplicationDefaultService], (service: ReplicationService) => {
it('should be initialized', inject([ReplicationDefaultService], (service: ReplicationService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -5,14 +5,16 @@ import { ReplicationService, ReplicationDefaultService } from './replication.ser
describe('ReplicationService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{
providers: [
ReplicationDefaultService,
{
provide: ReplicationService,
useClass: ReplicationDefaultService
}]
});
});
it('should ...', inject([ReplicationDefaultService], (service: ReplicationService) => {
it('should be initialized', inject([ReplicationDefaultService], (service: ReplicationService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -5,14 +5,16 @@ import { TagService, TagDefaultService } from './tag.service';
describe('TagService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{
providers: [
TagDefaultService,
{
provide: TagService,
useClass: TagDefaultService
}]
});
});
it('should ...', inject([TagDefaultService], (service: TagService) => {
it('should be initialized', inject([TagDefaultService], (service: TagService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -1,15 +1,29 @@
import { TestBed, inject } from '@angular/core/testing';
import { SystemInfoService } from './system-info.service';
import { HttpModule } from '@angular/http';
import { SERVICE_CONFIG, IServiceConfig } from '../../service.config';
export const testConfig: IServiceConfig = {
systemInfoEndpoint: "/api/systeminfo",
repositoryBaseEndpoint: "",
logBaseEndpoint: "",
targetBaseEndpoint: "",
replicationRuleEndpoint: "",
replicationJobEndpoint: ""
};
describe('SysteninfoService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [SystemInfoService]
imports: [HttpModule],
providers: [
{ provide: SERVICE_CONFIG, useValue: testConfig },
SystemInfoService]
});
});
it('should ...', inject([SystemInfoService], (service: SystemInfoService) => {
it('should be initialized', inject([SystemInfoService], (service: SystemInfoService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -1,6 +1,18 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpModule } from '@angular/http';
import { SystemComponent } from './system.component';
import { SystemInfoService } from './providers/system-info.service';
import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
export const testConfig: IServiceConfig = {
systemInfoEndpoint: "/api/systeminfo",
repositoryBaseEndpoint: "",
logBaseEndpoint: "",
targetBaseEndpoint: "",
replicationRuleEndpoint: "",
replicationJobEndpoint: ""
};
describe('SystemComponent', () => {
let component: SystemComponent;
@ -8,7 +20,12 @@ describe('SystemComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SystemComponent]
imports: [HttpModule],
declarations: [SystemComponent],
providers: [
{ provide: SERVICE_CONFIG, useValue: testConfig },
SystemInfoService
]
})
.compileComponents();
}));
@ -19,7 +36,7 @@ describe('SystemComponent', () => {
fixture.detectChanges();
});
it('should create', () => {
it('should be created', () => {
expect(component).toBeTruthy();
});
});

32
src/ui_ng/lib/src/test.ts Normal file
View File

@ -0,0 +1,32 @@
import './polyfills.ts';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare var __karma__: any;
declare var require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
let context = require.context('./', true, /\.spec\.ts/);
// And load the modules.
context.keys().map(context);
// Finally, start Karma to run the tests.
__karma__.start();

View File

@ -0,0 +1,33 @@
{
"compileOnSave": false,
"compilerOptions": {
"rootDir": "../",
"baseUrl": "",
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [
"es6",
"dom"
],
"mapRoot": "src",
"module": "commonjs",
"moduleResolution": "node",
"outDir": "dist",
"sourceMap": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"types": [
"jasmine",
"core-js",
"node"
]
},
"exclude": [
"node_modules",
"dist",
"test.ts"
]
}

View File

@ -1,6 +1,7 @@
{
"compilerOptions": {
"baseUrl": ".",
"baseUrl": "",
"rootDir": ".",
"declaration": true,
"stripInternal": true,
"experimentalDecorators": true,
@ -12,7 +13,6 @@
"@angular/core": ["node_modules/@angular/core"],
"rxjs/*": ["node_modules/rxjs/*"]
},
"rootDir": ".",
"outDir": "dist",
"sourceMap": true,
"inlineSources": true,
@ -20,9 +20,23 @@
"skipLibCheck": true,
"lib": [
"es2015",
"es6",
"dom"
],
"typeRoots": [
"node_modules/@types"
],
"types": [
"jasmine",
"core-js",
"node"
]
},
"exclude": [
"node_modules",
"dist",
"test.ts"
],
"files": [
"index.ts"
],

View File

@ -33,7 +33,7 @@
.repo-container {
width: 100%;
margin-top: -250px;
margin-top: -210px;
}
.more-info-link {
@ -42,3 +42,9 @@
left: 294px;
padding-right: 36px;
}
.tm-font {
font-size: 14px !important;
position: relative;
top: -9px;
}

View File

@ -1,6 +1,6 @@
<div class="login-wrapper login-wrapper-override">
<form #signInForm="ngForm" class="login">
<label class="title">{{appTitle | translate}}<span class="trademark">&#8482;</span>
<label class="title">{{appTitle | translate}}<span class="trademark tm-font">&#8482;</span>
</label>
<div class="login-group">
<label for="username" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left">

View File

@ -28,7 +28,8 @@ const deBounceTime = 500; //ms
@Component({
selector: 'global-search',
templateUrl: "global-search.component.html"
templateUrl: "global-search.component.html",
styleUrls: ["search.component.css"]
})
export class GlobalSearchComponent implements OnInit, OnDestroy {
//Keep search term as Subject

View File

@ -24,7 +24,7 @@ import { MessageHandlerService } from '../../shared/message-handler/message-hand
@Component({
selector: "search-result",
templateUrl: "search-result.component.html",
styleUrls: ["search-result.component.css"],
styleUrls: ["search.component.css"],
providers: [GlobalSearchService]
})

View File

@ -54,3 +54,14 @@
.search-header a:hover {
text-decoration: none;
}
.search::after {
position: absolute;
content: '';
display: inline-block;
background: #fafafa;
opacity: .15;
height: 40px;
width: 1px;
top: 10px;
}

View File

@ -17,12 +17,6 @@
padding-right: 21px !important;
}
/*.global-message-alert {
position: fixed;
top: 55px;
left: 260px;
width: 100%;
z-index: 999;
padding-right: 276px;
}*/
.nav-link-override {
width: 126px !important;
}

View File

@ -3,24 +3,22 @@
<navigator (showAccountSettingsModal)="openModal($event)" (showPwdChangeModal)="openModal($event)"></navigator>
<div class="content-container">
<div class="content-area" [class.container-override]="showSearch" [class.content-area-override]="!shouldOverrideContent" [class.start-content-padding]="shouldOverrideContent">
<div class="global-message-alert">
<global-message [isAppLevel]="false"></global-message>
</div>
<!-- Only appear when searching -->
<search-result></search-result>
<router-outlet></router-outlet>
</div>
<nav class="sidenav" style="padding: 12px 36px;" *ngIf="isUserExisting">
<section class="sidenav-content">
<a routerLink="/harbor/projects" routerLinkActive="active" class="nav-link">{{'SIDE_NAV.PROJECTS' | translate}}</a>
<a routerLink="/harbor/logs" routerLinkActive="active" class="nav-link" style="margin-top: 4px;">{{'SIDE_NAV.LOGS' | translate}}</a>
<section class="sidenav-content" style="padding-top: 20px;">
<a routerLink="/harbor/projects" routerLinkActive="active" class="nav-link nav-link-override">{{'SIDE_NAV.PROJECTS' | translate}}</a>
<a routerLink="/harbor/logs" routerLinkActive="active" class="nav-link nav-link-override" style="margin-top: 4px;">{{'SIDE_NAV.LOGS' | translate}}</a>
<section class="nav-group collapsible" *ngIf="isSystemAdmin" style="margin-top: 4px;">
<input id="tabsystem" type="checkbox">
<label for="tabsystem">{{'SIDE_NAV.SYSTEM_MGMT.NAME' | translate}}</label>
<ul class="nav-list">
<li><a class="nav-link" routerLink="/harbor/users" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}</a></li>
<li><a class="nav-link" routerLink="/harbor/replications/endpoints" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.REPLICATION' | translate}}</a></li>
<li><a class="nav-link" routerLink="/harbor/configs" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.CONFIG' | translate}}</a></li>
<li><a class="nav-link nav-link-override" routerLink="/harbor/users" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}</a></li>
<li><a class="nav-link nav-link-override" routerLink="/harbor/replications/endpoints" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.REPLICATION' | translate}}</a></li>
<li><a class="nav-link nav-link-override" routerLink="/harbor/configs" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.CONFIG' | translate}}</a></li>
</ul>
</section>
</section>

View File

@ -29,3 +29,8 @@
opacity: 0.15;
content: '';
}
.nav-about-link {
padding-left: 12px !important;
padding-right: 12px !important;
}

View File

@ -38,6 +38,7 @@
<a href="javascript:void(0)" clrDropdownItem (click)="logOut()">{{'ACCOUNT_SETTINGS.LOGOUT' | translate}}</a>
</div>
</clr-dropdown>
<a href="javascript:void(0)" class="nav-link nav-text" (click)="openAboutDialog()" *ngIf="isSessionValid === false">{{'ACCOUNT_SETTINGS.ABOUT' | translate}}</a>
<div class="nav-divider" *ngIf="!isSessionValid"></div>
<a href="javascript:void(0)" id="aboutMenu" class="nav-link nav-text nav-about-link" (click)="openAboutDialog()" *ngIf="!isSessionValid">{{'ACCOUNT_SETTINGS.ABOUT' | translate}}</a>
</div>
</clr-header>

View File

@ -0,0 +1,7 @@
.global-message-alert {
position: fixed;
top: 60px;
left: 0px;
width: 100%;
z-index: 9999;
}

View File

@ -1,3 +1,4 @@
<div class="global-message-alert" [hidden]="hideOuter">
<clr-alert [clrAlertType]="globalMessage.type" [clrAlertAppLevel]="isAppLevel" [(clrAlertClosed)]="!globalMessageOpened" (clrAlertClosedChange)="onClose()">
<div class="alert-item">
<span class="alert-text">
@ -8,3 +9,4 @@
</div>
</div>
</clr-alert>
</div>

View File

@ -11,7 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { Component, Input, OnInit, OnDestroy, ElementRef } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
import { TranslateService } from '@ngx-translate/core';
@ -23,7 +23,8 @@ import { AlertType, dismissInterval, httpStatusCode, CommonRoutes } from '../sha
@Component({
selector: 'global-message',
templateUrl: 'message.component.html'
templateUrl: 'message.component.html',
styleUrls: ['message.component.css']
})
export class MessageComponent implements OnInit, OnDestroy {
@ -32,12 +33,14 @@ export class MessageComponent implements OnInit, OnDestroy {
globalMessageOpened: boolean;
messageText: string = "";
timer: any = null;
hideOuter: boolean = true;
appLevelMsgSub: Subscription;
msgSub: Subscription;
clearSub: Subscription;
constructor(
private elementRef: ElementRef,
private messageService: MessageService,
private router: Router,
private translate: TranslateService) { }
@ -67,6 +70,19 @@ export class MessageComponent implements OnInit, OnDestroy {
// Make the message alert bar dismiss after several intervals.
//Only for this case
this.timer = setTimeout(() => this.onClose(), dismissInterval);
//Hack the Clarity Alert style with native dom
setTimeout(() => {
let nativeDom: any = this.elementRef.nativeElement;
let queryDoms: any[] = nativeDom.getElementsByClassName("alert");
if (queryDoms && queryDoms.length > 0) {
let hackDom: any = queryDoms[0];
hackDom.className += ' alert-global alert-global-align';
}
this.hideOuter = false;
}, 0);
}
);
}
@ -122,5 +138,6 @@ export class MessageComponent implements OnInit, OnDestroy {
clearTimeout(this.timer);
}
this.globalMessageOpened = false;
this.hideOuter = true;
}
}

View File

@ -22,7 +22,7 @@ export const enum AlertType {
DANGER, WARNING, INFO, SUCCESS
};
export const dismissInterval = 15 * 1000;
export const dismissInterval = 10 * 1000;
export const httpStatusCode = {
"Unauthorized": 401,
"Forbidden": 403

View File

@ -7,3 +7,25 @@
width: 108px !important;
height: 108px !important;
}
/*Hack Clarity alert*/
.alert-global {
font-size: 16px;
font-weight: 400;
font-family: Metropolis, "Avenir Next", "Helvetica Neue", Arial, sans-serif;
padding: 12px !important;
border: none !important;
margin-top: 0px !important;
max-height: 96px;
}
.alert-global-align {
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
overflow-y: auto;
overflow-x: hidden;
}