mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-06 23:11:31 +01:00
Merge remote-tracking branch 'upstream/master' into master-ui-aot
This commit is contained in:
commit
e8113fa3fa
1
.gitignore
vendored
1
.gitignore
vendored
@ -42,3 +42,4 @@ src/ui_ng/aot/**/*.json
|
||||
|
||||
**/*ngsummary.json
|
||||
**/*ngfactory.ts
|
||||
**/aot
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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": {
|
||||
|
44
src/ui_ng/lib/karma.conf.js
Normal file
44
src/ui_ng/lib/karma.conf.js
Normal 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
|
||||
});
|
||||
};
|
@ -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",
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
24
src/ui_ng/lib/src/app.module.ts
Normal file
24
src/ui_ng/lib/src/app.module.ts
Normal 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 {
|
||||
}
|
3
src/ui_ng/lib/src/environments/environment.prod.ts
Normal file
3
src/ui_ng/lib/src/environments/environment.prod.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const environment = {
|
||||
production: true
|
||||
};
|
8
src/ui_ng/lib/src/environments/environment.ts
Normal file
8
src/ui_ng/lib/src/environments/environment.ts
Normal 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
12
src/ui_ng/lib/src/main.ts
Normal 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);
|
22
src/ui_ng/lib/src/polyfills.ts
Normal file
22
src/ui_ng/lib/src/polyfills.ts
Normal 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';
|
||||
|
@ -5,14 +5,16 @@ import { AccessLogService, AccessLogDefaultService } from './access-log.service'
|
||||
describe('AccessLogService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{
|
||||
provide: AccessLogService,
|
||||
useClass: AccessLogDefaultService
|
||||
}]
|
||||
providers: [
|
||||
AccessLogDefaultService,
|
||||
{
|
||||
provide: AccessLogService,
|
||||
useClass: AccessLogDefaultService
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should ...', inject([AccessLogDefaultService], (service: AccessLogService) => {
|
||||
it('should be initialized', inject([AccessLogDefaultService], (service: AccessLogService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
@ -5,14 +5,16 @@ import { EndpointService, EndpointDefaultService } from './endpoint.service';
|
||||
describe('EndpointService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{
|
||||
provide: EndpointService,
|
||||
useClass: EndpointDefaultService
|
||||
}]
|
||||
providers: [
|
||||
EndpointDefaultService,
|
||||
{
|
||||
provide: EndpointService,
|
||||
useClass: EndpointDefaultService
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should ...', inject([EndpointDefaultService], (service: EndpointService) => {
|
||||
it('should be initialized', inject([EndpointDefaultService], (service: EndpointService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
@ -5,14 +5,16 @@ import { ReplicationService, ReplicationDefaultService } from './replication.ser
|
||||
describe('ReplicationService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{
|
||||
provide: ReplicationService,
|
||||
useClass: ReplicationDefaultService
|
||||
}]
|
||||
providers: [
|
||||
ReplicationDefaultService,
|
||||
{
|
||||
provide: ReplicationService,
|
||||
useClass: ReplicationDefaultService
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should ...', inject([ReplicationDefaultService], (service: ReplicationService) => {
|
||||
it('should be initialized', inject([ReplicationDefaultService], (service: ReplicationService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
@ -5,14 +5,16 @@ import { ReplicationService, ReplicationDefaultService } from './replication.ser
|
||||
describe('ReplicationService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{
|
||||
provide: ReplicationService,
|
||||
useClass: ReplicationDefaultService
|
||||
}]
|
||||
providers: [
|
||||
ReplicationDefaultService,
|
||||
{
|
||||
provide: ReplicationService,
|
||||
useClass: ReplicationDefaultService
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should ...', inject([ReplicationDefaultService], (service: ReplicationService) => {
|
||||
it('should be initialized', inject([ReplicationDefaultService], (service: ReplicationService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
@ -5,14 +5,16 @@ import { TagService, TagDefaultService } from './tag.service';
|
||||
describe('TagService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{
|
||||
provide: TagService,
|
||||
useClass: TagDefaultService
|
||||
}]
|
||||
providers: [
|
||||
TagDefaultService,
|
||||
{
|
||||
provide: TagService,
|
||||
useClass: TagDefaultService
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should ...', inject([TagDefaultService], (service: TagService) => {
|
||||
it('should be initialized', inject([TagDefaultService], (service: TagService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
@ -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();
|
||||
}));
|
||||
});
|
||||
|
@ -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
32
src/ui_ng/lib/src/test.ts
Normal 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();
|
33
src/ui_ng/lib/src/tsconfig.json
Normal file
33
src/ui_ng/lib/src/tsconfig.json
Normal 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"
|
||||
]
|
||||
}
|
@ -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"
|
||||
],
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
.repo-container {
|
||||
width: 100%;
|
||||
margin-top: -250px;
|
||||
margin-top: -210px;
|
||||
}
|
||||
|
||||
.more-info-link {
|
||||
@ -41,4 +41,10 @@
|
||||
top: 80px;
|
||||
left: 294px;
|
||||
padding-right: 36px;
|
||||
}
|
||||
|
||||
.tm-font {
|
||||
font-size: 14px !important;
|
||||
position: relative;
|
||||
top: -9px;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<div class="login-wrapper login-wrapper-override">
|
||||
<form #signInForm="ngForm" class="login">
|
||||
<label class="title">{{appTitle | translate}}<span class="trademark">™</span>
|
||||
<label class="title">{{appTitle | translate}}<span class="trademark tm-font">™</span>
|
||||
</label>
|
||||
<div class="login-group">
|
||||
<label for="username" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left">
|
||||
|
@ -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
|
||||
@ -62,7 +63,7 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
|
||||
this.searchTerm = "";
|
||||
});
|
||||
|
||||
if(this.appConfigService.isIntegrationMode()){
|
||||
if (this.appConfigService.isIntegrationMode()) {
|
||||
this.placeholderText = "GLOBAL_SEARCH.PLACEHOLDER_VIC";
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
})
|
||||
|
@ -53,4 +53,15 @@
|
||||
|
||||
.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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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>
|
||||
<global-message [isAppLevel]="false"></global-message>
|
||||
<!-- 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>
|
||||
|
@ -28,4 +28,9 @@
|
||||
top: 10px;
|
||||
opacity: 0.15;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.nav-about-link {
|
||||
padding-left: 12px !important;
|
||||
padding-right: 12px !important;
|
||||
}
|
@ -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>
|
7
src/ui_ng/src/app/global-message/message.component.css
Normal file
7
src/ui_ng/src/app/global-message/message.component.css
Normal file
@ -0,0 +1,7 @@
|
||||
.global-message-alert {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
z-index: 9999;
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
<clr-alert [clrAlertType]="globalMessage.type" [clrAlertAppLevel]="isAppLevel" [(clrAlertClosed)]="!globalMessageOpened" (clrAlertClosedChange)="onClose()">
|
||||
<div class="alert-item">
|
||||
<span class="alert-text">
|
||||
<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">
|
||||
{{message}}
|
||||
</span>
|
||||
<div class="alert-actions" *ngIf="needAuth">
|
||||
<button class="btn alert-action" (click)="signIn()">{{ 'BUTTON.LOG_IN' | translate }}</button>
|
||||
<div class="alert-actions" *ngIf="needAuth">
|
||||
<button class="btn alert-action" (click)="signIn()">{{ 'BUTTON.LOG_IN' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</clr-alert>
|
||||
</clr-alert>
|
||||
</div>
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -6,4 +6,26 @@
|
||||
margin-left: -54px;
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user