Commit 4d5b6d81 authored by Steven Zou's avatar Steven Zou Committed by GitHub
Browse files

Merge pull request #1578 from wknet123/dev-revised

Merge latest UI codes to dev.
parents f9e8394b e80840c2
version: '2'
services:
log:
build:
context: ../../
dockerfile: make/photon/log/Dockerfile
restart: always
volumes:
- /var/log/harbor/:/var/log/docker/
ports:
- 1514:514
registry:
image: library/registry:2.5.1
restart: always
volumes:
- /data/registry:/storage
- ../common/config/registry/:/etc/registry/
environment:
- GODEBUG=netdns=cgo
command:
["serve", "/etc/registry/config.yml"]
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "registry"
mysql:
build: ../common/db/
restart: always
volumes:
- /data/database:/var/lib/mysql
env_file:
- ../common/config/db/env
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "mysql"
adminserver:
build:
context: ../../
dockerfile: make/dev/adminserver/Dockerfile
env_file:
- ../common/config/adminserver/env
restart: always
volumes:
- /data/config/:/etc/harbor/
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "adminserver"
ui:
build:
context: ../../
dockerfile: make/dev/ui/Dockerfile
env_file:
- ../common/config/ui/env
restart: always
volumes:
- ../common/config/ui/app.conf:/etc/ui/app.conf
- ../common/config/ui/private_key.pem:/etc/ui/private_key.pem
depends_on:
- log
- adminserver
- registry
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "ui"
jobservice:
build:
context: ../../
dockerfile: make/dev/jobservice/Dockerfile
env_file:
- ../common/config/jobservice/env
restart: always
volumes:
- /data/job_logs:/var/log/jobs
- ../common/config/jobservice/app.conf:/etc/jobservice/app.conf
depends_on:
- ui
- adminserver
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "jobservice"
proxy:
image: library/nginx:1.11.5
restart: always
volumes:
- ../common/config/nginx:/etc/nginx
ports:
- 80:80
- 443:443
depends_on:
- mysql
- registry
- ui
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy"
nodeclarity:
image : danieljt/harbor-clarity-base:0.8.0
image : danieljt/harbor-clarity-base:0.8.1
volumes:
- ../../src/ui/static/new-ui:/clarity-seed/dist
- ../../src/ui_ng/src/app:/clarity-seed/src/app
depends_on:
- ui
- ../../src/ui_ng:/clarity-seed
FROM node:7.5.0
RUN git clone https://github.com/vmware/clarity-seed.git /clarity-seed
COPY index.html /clarity-seed
COPY entrypoint.sh /clarity-seed
WORKDIR /clarity-seed
COPY angular-cli.json /
COPY index.html /
COPY entrypoint.sh /
RUN npm install -g @angular/cli && \
npm install && \
chmod u+x entrypoint.sh
VOLUME ["/clarity-seed/src/app", "/clarity-seed/dist"]
VOLUME ["/clarity-seed", "/clarity-seed/dist"]
ENTRYPOINT ["/clarity-seed/entrypoint.sh"]
ENTRYPOINT ["/entrypoint.sh"]
#!/bin/bash
cd /clarity-seed
rm -rf dist/*
cp /angular-cli.json /clarity-seed
npm install
ng build
cp index.html dist/index.html
cp /index.html dist/index.html
version: '2'
services:
nodeclarity:
image : danieljt/harbor-clarity-base:0.8.0
volumes:
- ../src/ui/static/new-ui:/clarity-seed/dist
- ../src/ui_ng/src/app:/clarity-seed/src/app
depends_on:
- ui
......@@ -25,7 +25,7 @@
<div class="checkbox">
<input type="checkbox" id="rememberme">
<label for="rememberme">{{ 'SIGN_IN.REMEMBER' | translate }}</label>
<a href="javascript:void(0)" class="forgot-password-link" (click)="forgotPassword()">Forgot password</a>
<a href="javascript:void(0)" class="forgot-password-link" (click)="forgotPassword()">{{'SIGN_IN.FORGOT_PWD' | translate}}</a>
</div>
<div [class.visibility-hidden]="!isError" class="error active">
{{ 'SIGN_IN.INVALID_MSG' | translate }}
......
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { ClarityModule } from 'clarity-angular';
......@@ -16,10 +16,19 @@ import { MyMissingTranslationHandler } from './i18n/missing-trans.handler';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { Http } from '@angular/http';
import { SessionService } from './shared/session.service';
export function HttpLoaderFactory(http: Http) {
return new TranslateHttpLoader(http, 'ng/i18n/lang/', '-lang.json');
}
export function initConfig(session: SessionService) {
return () => {
console.info("app init here");
return Promise.resolve(true);
};
}
@NgModule({
declarations: [
AppComponent,
......@@ -42,7 +51,12 @@ export function HttpLoaderFactory(http: Http) {
}
})
],
providers: [],
providers: [{
provide: APP_INITIALIZER,
useFactory: initConfig,
deps: [SessionService],
multi: true
}],
bootstrap: [AppComponent]
})
export class AppModule {
......
......@@ -5,13 +5,14 @@ import { RouterModule } from '@angular/router';
import { ProjectModule } from '../project/project.module';
import { UserModule } from '../user/user.module';
import { AccountModule } from '../account/account.module';
import { RepositoryModule } from '../repository/repository.module';
import { NavigatorComponent } from './navigator/navigator.component';
import { GlobalSearchComponent } from './global-search/global-search.component';
import { FooterComponent } from './footer/footer.component';
import { HarborShellComponent } from './harbor-shell/harbor-shell.component';
import { SearchResultComponent } from './global-search/search-result.component';
import { SearchStartComponent } from './global-search/search-start.component';
import { StartPageComponent } from './start-page/start.component';
import { SearchTriggerService } from './global-search/search-trigger.service';
......@@ -21,7 +22,8 @@ import { SearchTriggerService } from './global-search/search-trigger.service';
ProjectModule,
UserModule,
AccountModule,
RouterModule
RouterModule,
RepositoryModule
],
declarations: [
NavigatorComponent,
......@@ -29,7 +31,7 @@ import { SearchTriggerService } from './global-search/search-trigger.service';
FooterComponent,
HarborShellComponent,
SearchResultComponent,
SearchStartComponent
StartPageComponent
],
exports: [ HarborShellComponent ],
providers: [SearchTriggerService]
......
<form class="search" *ngIf="!shouldHide">
<form class="search">
<label for="search_input">
<input #globalSearchBox id="search_input" type="text" (keyup)="search(globalSearchBox.value)" placeholder='{{"GLOBAL_SEARCH.PLACEHOLDER" | translate}}'>
</label>
......
......@@ -31,10 +31,6 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
private searchTrigger: SearchTriggerService,
private router: Router) { }
public get shouldHide(): boolean {
return this.router.routerState.snapshot.url === harborRootRoute && !this.isResPanelOpened;
}
//Implement ngOnIni
ngOnInit(): void {
this.searchSub = this.searchTerms
......@@ -43,19 +39,12 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
.subscribe(term => {
this.searchTrigger.triggerSearch(term);
});
this.stateSub = this.searchTrigger.searchInputChan$.subscribe(state => {
this.isResPanelOpened = state;
});
}
ngOnDestroy(): void {
if (this.searchSub) {
this.searchSub.unsubscribe();
}
if (this.stateSub) {
this.stateSub.unsubscribe();
}
}
//Handle the term inputting event
......
......@@ -36,6 +36,6 @@ export class GlobalSearchService {
return this.http.get(searchUrl, this.options).toPromise()
.then(response => response.json() as SearchResults)
.catch(error => error);
.catch(error => Promise.reject(error));
}
}
\ No newline at end of file
......@@ -13,6 +13,8 @@
<div class="grid-header-wrapper">
<grid-filter class="grid-filter" filterPlaceholder='{{"PROJECT.FILTER_PLACEHOLDER" | translate}}' (filter)="doFilterProjects($event)"></grid-filter>
</div>
<list-project [projects]="searchResults.project"></list-project>
<list-project [projects]="searchResults.project" [mode]="listMode"></list-project>
<h2>Repositories</h2>
<list-repository [repositories]="searchResults.repository" [mode]="listMode"></list-repository>
</div>
</div>
\ No newline at end of file
......@@ -3,7 +3,7 @@ import { Component, Output, EventEmitter } from '@angular/core';
import { GlobalSearchService } from './global-search.service';
import { SearchResults } from './search-results';
import { errorHandler, accessErrorHandler } from '../../shared/shared.utils';
import { AlertType } from '../../shared/shared.const';
import { AlertType, ListMode } from '../../shared/shared.const';
import { MessageService } from '../../global-message/message.service';
import { SearchTriggerService } from './search-trigger.service';
......@@ -52,6 +52,10 @@ export class SearchResultComponent {
return res//Empty object
}
public get listMode(): string {
return ListMode.READONLY;
}
public get state(): boolean {
return this.stateIndicator;
}
......
.search-start-wrapper {
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -230px;
}
.search-icon {
position: relative;
right: -6px;
}
.search-font {
font-weight: 600;
font-size: 18px;
}
\ No newline at end of file
<h2>Hello {{currentUsername}}, start to use harbor from search</h2>
<div class="search-start-wrapper">
<form class="search">
<label for="search_start_input">
<clr-icon shape="search" size="24" class="search-icon is-highlight"></clr-icon>
<input #startSearchBox id="search_start_input" type="text" class="search-font" (keyup)="search(startSearchBox.value)" placeholder='{{"GLOBAL_SEARCH.PLACEHOLDER" | translate}}' size="60">
</label>
</form>
</div>
\ No newline at end of file
import { Component, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';;
import { Subscription } from 'rxjs/Subscription';
import { SessionService } from '../../shared/session.service';
import { SessionUser } from '../../shared/session-user';
import { SearchTriggerService } from './search-trigger.service';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
const deBounceTime = 500; //ms
@Component({
selector: 'search-start',
templateUrl: "search-start.component.html",
styleUrls: ['search-start.component.css']
})
export class SearchStartComponent implements OnInit, OnDestroy {
//Keep search term as Subject
private searchTerms = new Subject<string>();
private searchSub: Subscription;
private currentUser: SessionUser = null;
constructor(
private session: SessionService,
private searchTrigger: SearchTriggerService){}
public get currentUsername(): string {
return this.currentUser?this.currentUser.username: "";
}
//Implement ngOnIni
ngOnInit(): void {
this.currentUser = this.session.getCurrentUser();
this.searchSub = this.searchTerms
.debounceTime(deBounceTime)
.distinctUntilChanged()
.subscribe(term => {
this.searchTrigger.triggerSearch(term);
});
}
ngOnDestroy(): void {
if(this.searchSub){
this.searchSub.unsubscribe();
}
}
//Handle the term inputting event
search(term: string): void {
//Send event only when term is not empty
this.searchTerms.next(term);
}
}
\ No newline at end of file
......@@ -4,4 +4,10 @@
.container-override {
position: relative !important;
}
.start-content-padding {
padding-top: 0px !important;
padding-bottom: 0px !important;
padding-left: 0px !important;
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
<global-message [isAppLevel]="true"></global-message>
<navigator (showAccountSettingsModal)="openModal($event)" (showPwdChangeModal)="openModal($event)"></navigator>
<div class="content-container">
<div class="content-area" [class.container-override]="showSearch">
<div class="content-area" [class.container-override]="showSearch" [class.start-content-padding]="isStartPage">
<global-message [isAppLevel]="false"></global-message>
<!-- Only appear when searching -->
<search-result></search-result>
......@@ -10,15 +10,16 @@
</div>
<nav class="sidenav" *ngIf="isUserExisting" [class.side-nav-override]="showSearch" (click)='watchClickEvt()'>
<section class="sidenav-content">
<a routerLink="/harbor/dashboard" routerLinkActive="active" class="nav-link">{{'SIDE_NAV.DASHBOARD' | translate}}</a>
<a routerLink="/harbor/projects" routerLinkActive="active" class="nav-link">{{'SIDE_NAV.PROJECTS' | translate}}</a>
<a routerLink="/harbor/logs" routerLinkActive="active" class="nav-link">{{'SIDE_NAV.LOGS' | translate}}</a>
<section class="nav-group collapsible" *ngIf="isSystemAdmin">
<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.USERS' | translate}}</a></li>
<li><a class="nav-link" routerLink="/harbor/replications/endpoints" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.REPLICATIONS' | translate}}</a></li>
<li><a class="nav-link" routerLink="/harbor/configs" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.CONFIGS' | translate}}</a></li>
<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>
</ul>
</section>
</section>
......
......@@ -11,12 +11,14 @@ import { NavigatorComponent } from '../navigator/navigator.component';
import { SessionService } from '../../shared/session.service';
import { AboutDialogComponent } from '../../shared/about-dialog/about-dialog.component';
import { SearchStartComponent } from '../global-search/search-start.component';
import { StartPageComponent } from '../start-page/start.component';
import { SearchTriggerService } from '../global-search/search-trigger.service';
import { Subscription } from 'rxjs/Subscription';
import { harborRootRoute } from '../../shared/shared.const';
@Component({
selector: 'harbor-shell',
templateUrl: 'harbor-shell.component.html',
......@@ -40,8 +42,8 @@ export class HarborShellComponent implements OnInit, OnDestroy {
@ViewChild(AboutDialogComponent)
private aboutDialog: AboutDialogComponent;
@ViewChild(SearchStartComponent)
private searchSatrt: SearchStartComponent;
@ViewChild(StartPageComponent)
private searchSatrt: StartPageComponent;
//To indicator whwther or not the search results page is displayed
//We need to use this property to do some overriding work
......@@ -52,6 +54,7 @@ export class HarborShellComponent implements OnInit, OnDestroy {
constructor(
private route: ActivatedRoute,
private router: Router,
private session: SessionService,
private searchTrigger: SearchTriggerService) { }
......@@ -79,6 +82,10 @@ export class HarborShellComponent implements OnInit, OnDestroy {
}
}
public get isStartPage(): boolean {
return this.router.routerState.snapshot.url.toString() === harborRootRoute;
}
public get showSearch(): boolean {
return this.isSearchResultsOpened;
}
......
.start-card {
border-right: 1px solid #cccccc;
padding: 24px;
background-color: white;
height: 100%;
}
.row-fill-height {
height: 100%;
}
.row-margin {
margin-left: 24px;
}
.column-fill-height {
height: 100%;
}
.my-card-img {
background-image: url('../../../images/harbor-logo.png');
background-repeat: no-repeat;
background-size: contain;
height: 160px;
}
.my-card-footer {
float: right;
margin-top: 100px;
}
\ No newline at end of file
<!-- Authenticated-->
<div class="row row-fill-height row-margin" *ngIf="isSessionValid">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<statistics-panel></statistics-panel>
<top-repo></top-repo>
</div>
</div>
<!-- Guest -->
<div class="row row-fill-height" *ngIf="!isSessionValid">
<div class="col-xs-12 col-sm-12 col-md-5 col-lg-5 col-xl-5 column-fill-height">
<div class="start-card">
<div class="card-img my-card-img">
</div>
<div class="card-block">
<h3 class="card-title">Getting Start</h3>
<p class="card-text">
{{'START_PAGE.GETTING_START' | translate}}
</p>
</div>
<div class="card-footer my-card-footer">
<a href="http://vmware.github.io/harbor/" target="_blank" class="btn btn-sm btn-link">Learn More</a>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-7 col-lg-7 col-xl-7">
<top-repo></top-repo>
</div>
</div>
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment