Unverified Commit ee0f3c22 authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #104 from jumpserver/dev_beta

Dev beta
parents 77910c92 6bb66d4f
...@@ -8,6 +8,6 @@ RUN npm run-script build ...@@ -8,6 +8,6 @@ RUN npm run-script build
FROM nginx:alpine FROM nginx:alpine
COPY --from=stage-build /data/dist /opt/luna/ COPY --from=stage-build /data/luan /opt/luna/
COPY ./src/assets/i18n /opt/luna/i18n COPY ./src/assets/i18n /opt/luna/i18n
COPY nginx.conf /etc/nginx/conf.d/default.conf COPY nginx.conf /etc/nginx/conf.d/default.conf
...@@ -7,7 +7,9 @@ import {CookieService} from 'ngx-cookie-service'; ...@@ -7,7 +7,9 @@ import {CookieService} from 'ngx-cookie-service';
import {MAT_LABEL_GLOBAL_OPTIONS} from '@angular/material'; import {MAT_LABEL_GLOBAL_OPTIONS} from '@angular/material';
// service // service
import {AppService, HttpService, LocalStorageService, NavService, LogService, UUIDService, TreeFilterService} from './app.service'; import {AppService, HttpService, LocalStorageService, NavService, LogService,
UUIDService, TreeFilterService, ViewService,
} from './app.service';
import {AppRouterModule} from './router/router.module'; import {AppRouterModule} from './router/router.module';
import {Pipes} from './pipes/pipes'; import {Pipes} from './pipes/pipes';
...@@ -55,6 +57,7 @@ import {AssetTreeDialogComponent, ManualPasswordDialogComponent} from './element ...@@ -55,6 +57,7 @@ import {AssetTreeDialogComponent, ManualPasswordDialogComponent} from './element
LocalStorageService, LocalStorageService,
CookieService, CookieService,
TreeFilterService, TreeFilterService,
ViewService,
NGXLogger, NGXLogger,
{provide: MAT_LABEL_GLOBAL_OPTIONS, useValue: {float: 'always'}} {provide: MAT_LABEL_GLOBAL_OPTIONS, useValue: {float: 'always'}}
] ]
......
...@@ -2,11 +2,10 @@ import {EventEmitter, Injectable, OnInit} from '@angular/core'; ...@@ -2,11 +2,10 @@ import {EventEmitter, Injectable, OnInit} from '@angular/core';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {CookieService} from 'ngx-cookie-service'; import {CookieService} from 'ngx-cookie-service';
import {DataStore, User, Browser, i18n} from './globals'; import {DataStore, User, Browser, i18n} from './globals';
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
import {NGXLogger} from 'ngx-logger'; import {NGXLogger} from 'ngx-logger';
import {SystemUser, GuacObjAddResp, TreeNode, User as _User, NavEvt} from './model'; import {SystemUser, GuacObjAddResp, TreeNode, User as _User, NavEvt, View} from './model';
import {environment} from '../environments/environment'; import {environment} from '../environments/environment';
import * as UUID from 'uuid-js/lib/uuid.js'; import * as UUID from 'uuid-js/lib/uuid.js';
...@@ -66,6 +65,11 @@ export class HttpService { ...@@ -66,6 +65,11 @@ export class HttpService {
return this.http.get<Array<TreeNode>>(url); return this.http.get<Array<TreeNode>>(url);
} }
filterMyGrantedAssetsById(id: string) {
const url = `/api/perms/v1/users/assets/tree/?id=${id}`;
return this.http.get<Array<TreeNode>>(url);
}
getMyGrantedNodes(async: boolean, refresh?: boolean) { getMyGrantedNodes(async: boolean, refresh?: boolean) {
const cachePolicy = refresh ? '2' : '1'; const cachePolicy = refresh ? '2' : '1';
const syncUrl = `/api/perms/v1/users/nodes-with-assets/tree/?cache_policy=${cachePolicy}`; const syncUrl = `/api/perms/v1/users/nodes-with-assets/tree/?cache_policy=${cachePolicy}`;
...@@ -442,3 +446,34 @@ export class TreeFilterService { ...@@ -442,3 +446,34 @@ export class TreeFilterService {
this.onFilter.emit(q); this.onFilter.emit(q);
} }
} }
@Injectable()
export class ViewService {
viewList: Array<View> = [];
currentView: View;
num = 0;
addView(view: View) {
this.num += 1;
view.id = 'View_' + this.num;
this.viewList.push(view);
}
activeView(view: View) {
this.viewList.forEach((v, k) => {
v.active = v === view;
});
setTimeout(() => {
const viewEl = document.getElementById(view.id);
if (viewEl) {
viewEl.scrollIntoView();
}
}, 100);
this.currentView = view;
}
removeView(view: View) {
const index = this.viewList.indexOf(view);
this.viewList.splice(index, 1);
}
}
...@@ -141,20 +141,6 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -141,20 +141,6 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
initTree() { initTree() {
this.initAssetsTree(); this.initAssetsTree();
this.initRemoteAppsTree(); this.initRemoteAppsTree();
// Todo: connect to some asset, direct
this.activatedRoute.queryParams.subscribe(params => {
const login_to = params['login_to'];
if (login_to && !this.hasLoginTo) {
this.Data.forEach(t => {
if (login_to === t.id && t.isParent === false) {
this.hasLoginTo = true;
this.connectAsset(t);
return;
}
});
}
});
} }
connectAsset(node: TreeNode) { connectAsset(node: TreeNode) {
...@@ -289,12 +275,12 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -289,12 +275,12 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
if (!this.assetsTree) { if (!this.assetsTree) {
return; return;
} }
const searchNode = this.assetsTree.getNodesByFilter((node) => node.id === 'search');
if (searchNode) {
this.assetsTree.removeChildNodes(searchNode[0]);
this.assetsTree.removeNode(searchNode[0]);
}
if (!keyword) { if (!keyword) {
const searchNode = this.assetsTree.getNodesByFilter((node) => node.id === 'search');
if (searchNode) {
this.assetsTree.removeChildNodes(searchNode[0]);
this.assetsTree.removeNode(searchNode[0]);
}
const treeNodes = this.assetsTree.getNodes(); const treeNodes = this.assetsTree.getNodes();
if (treeNodes.length !== 0) { if (treeNodes.length !== 0) {
this.assetsTree.showNode(treeNodes[0]); this.assetsTree.showNode(treeNodes[0]);
......
import {Component, Input, OnInit, Output, Inject, OnDestroy, EventEmitter} from '@angular/core'; import {Component, OnInit, Output, Inject, OnDestroy, EventEmitter} from '@angular/core';
import {connectEvt} from '@app/globals'; import {connectEvt} from '@app/globals';
import {AppService, HttpService, LogService, NavService} from '@app/app.service'; import {AppService, HttpService, LogService} from '@app/app.service';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
import {FormControl, Validators} from '@angular/forms'; import {FormControl, Validators} from '@angular/forms';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute} from '@angular/router';
import {SystemUser, TreeNode, Asset} from '@app/model'; import {SystemUser, TreeNode, Asset} from '@app/model';
import {View} from '@app/model'; import {View} from '@app/model';
import * as jQuery from 'jquery/dist/jquery.min';
declare var $: any;
@Component({ @Component({
selector: 'elements-connect', selector: 'elements-connect',
...@@ -41,6 +38,20 @@ export class ElementConnectComponent implements OnInit, OnDestroy { ...@@ -41,6 +38,20 @@ export class ElementConnectComponent implements OnInit, OnDestroy {
} }
} }
}); });
this.activatedRoute.queryParams.subscribe(params => {
const login_to = params['login_to'];
if (login_to && !this.hasLoginTo) {
this._http.filterMyGrantedAssetsById(login_to).subscribe(
nodes => {
if (nodes.length === 1) {
this.hasLoginTo = true;
const node = nodes[0];
this.Connect(node);
}
}
);
}
});
} }
ngOnDestroy(): void { ngOnDestroy(): void {
connectEvt.unsubscribe(); connectEvt.unsubscribe();
......
...@@ -29,10 +29,6 @@ export class ElementContentViewComponent implements OnInit { ...@@ -29,10 +29,6 @@ export class ElementContentViewComponent implements OnInit {
} }
static DisconnectAll() { static DisconnectAll() {
// for (let i = 0; i < viewList.List.length; i++) {
// Todo:
// ContentComponent.TerminalDisconnect(i);
// }
} }
constructor() { constructor() {
......
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {View, ViewAction} from '@app/model'; import {View, ViewAction} from '@app/model';
import {ViewService} from '@app/app.service';
@Component({ @Component({
selector: 'elements-content', selector: 'elements-content',
...@@ -8,7 +9,8 @@ import {View, ViewAction} from '@app/model'; ...@@ -8,7 +9,8 @@ import {View, ViewAction} from '@app/model';
}) })
export class ElementContentComponent implements OnInit { export class ElementContentComponent implements OnInit {
@ViewChild('tabs') tabsRef: ElementRef; @ViewChild('tabs') tabsRef: ElementRef;
viewList: Array<View> = []; viewList: Array<View>;
hasLoginTo = false;
static DisconnectAll() { static DisconnectAll() {
} }
...@@ -17,16 +19,17 @@ export class ElementContentComponent implements OnInit { ...@@ -17,16 +19,17 @@ export class ElementContentComponent implements OnInit {
return (this.viewList.length + 1) * 151 + 10; return (this.viewList.length + 1) * 151 + 10;
} }
constructor() { constructor(private viewSrv: ViewService) {
} }
ngOnInit() { ngOnInit() {
this.viewList = this.viewSrv.viewList;
} }
onNewView(view) { onNewView(view) {
this.scrollToEnd(); this.scrollToEnd();
setTimeout(() => { setTimeout(() => {
this.viewList.push(view); this.viewSrv.addView(view);
this.setViewActive(view); this.setViewActive(view);
}, 100); }, 100);
} }
...@@ -45,9 +48,7 @@ export class ElementContentComponent implements OnInit { ...@@ -45,9 +48,7 @@ export class ElementContentComponent implements OnInit {
} }
setViewActive(view) { setViewActive(view) {
this.viewList.forEach((v, k) => { this.viewSrv.activeView(view);
v.active = v === view;
});
} }
closeView(view) { closeView(view) {
...@@ -61,7 +62,7 @@ export class ElementContentComponent implements OnInit { ...@@ -61,7 +62,7 @@ export class ElementContentComponent implements OnInit {
nextActiveView = this.viewList[index + 1]; nextActiveView = this.viewList[index + 1];
} }
} }
this.viewList.splice(index, 1); this.viewSrv.removeView(view);
if (nextActiveView) { if (nextActiveView) {
this.setViewActive(nextActiveView); this.setViewActive(nextActiveView);
} }
......
...@@ -84,11 +84,6 @@ export class ElementGuacamoleComponent implements OnInit { ...@@ -84,11 +84,6 @@ export class ElementGuacamoleComponent implements OnInit {
return this.sanitizer.bypassSecurityTrustResourceUrl(url); return this.sanitizer.bypassSecurityTrustResourceUrl(url);
} }
Disconnect() {
// TOdo:
return;
}
active() { active() {
this.el.nativeElement.focus(); this.el.nativeElement.focus();
} }
......
import {Component, Inject, OnInit, ViewChild, ElementRef} from '@angular/core'; import {Component} from '@angular/core';
import {AppService, HttpService, LogService} from '@app/app.service';
// import {ElementTreeFilterComponent} from '../tree-filter/tree-filter.component';
import {DataStore} from '@app/globals'; import {DataStore} from '@app/globals';
import {version} from '@src/environments/environment'; import {version} from '@src/environments/environment';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
export interface Node {
id: string;
name: string;
comment: string;
title: string;
isParent: boolean;
pId: string;
open: boolean;
iconSkin: string;
meta: object;
}
export class Host {
name: string;
id: string;
type: string;
}
@Component({ @Component({
selector: 'elements-left-bar', selector: 'elements-left-bar',
templateUrl: './left-bar.component.html', templateUrl: './left-bar.component.html',
styleUrls: ['./left-bar.component.scss'], styleUrls: ['./left-bar.component.scss'],
// providers: [ElementTreeFilterComponent]
}) })
export class ElementLeftBarComponent { export class ElementLeftBarComponent {
DataStore = DataStore; DataStore = DataStore;
version = version; version = version;
q: string;
event: MouseEvent;
clientX = 0;
clientY = 0;
TooltipPosition = 'above';
static Reload() {
}
static Hide() { static Hide() {
DataStore.showLeftBar = false; DataStore.showLeftBar = false;
DataStore.Nav.map(function (value, i) {
value['children'].forEach((v, key) => {
if (DataStore.Nav[i]['children'][key]['id'] === 'HideLeftManager') {
DataStore.Nav[i]['children'][key] = {
'id': 'ShowLeftManager',
'click': 'ShowLeft',
'name': 'Show left manager'
};
}
});
});
window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('resize'));
} }
static Show() { static Show() {
DataStore.showLeftBar = true; DataStore.showLeftBar = true;
DataStore.Nav.map(function (value, i) {
value['children'].forEach((v, key) => {
if (DataStore.Nav[i]['children'][key]['id'] === 'ShowLeftManager') {
DataStore.Nav[i]['children'][key] = {
'id': 'HideLeftManager',
'click': 'HideLeft',
'name': 'Hide left manager'
};
}
});
});
window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('resize'));
} }
constructor(private _appService: AppService,
private _http: HttpService,
private _logger: LogService,
public _dialog: MatDialog,
) {
this._logger.log('nav.ts:NavComponent');
}
Search(q) {
// Todo:
// this._search.Search(q);
}
onRightClick(event: MouseEvent): void {
this.clientX = event.clientX;
this.clientY = event.clientY;
}
} }
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
display: flex; display: flex;
} }
.nav .dropdown-content li a { .nav .dropdown-content a {
padding: 6px 14px 6px 25px; padding: 6px 14px 6px 25px;
white-space: nowrap; white-space: nowrap;
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
...@@ -110,7 +110,14 @@ ...@@ -110,7 +110,14 @@
background-color: darkgray; background-color: darkgray;
} }
.nav ul li.active {
box-sizing: border-box; .flag {
border-bottom: 3px solid #19aa8d !important; display: none;
color: #19aa8d;
padding-right: 10px;
}
.active .flag {
display: inline;
} }
...@@ -12,5 +12,17 @@ ...@@ -12,5 +12,17 @@
</li> </li>
</ul> </ul>
</li> </li>
<li [ngClass]="{'dropdown': true}">
<a>{{"Tab List"|trans}}</a>
<ul *ngIf="viewList.length > 0" [ngClass]="{'dropdown-content': true}">
<ng-container *ngFor="let v of viewList, let idx = index" >
<li *ngIf="v.nick!=null" [ngClass]="{'disconnected':!v.connected, 'hidden': v.closed != false}">
<span [class.active]="v.active">
<a id="{{ 'tab' + idx }}" (click)="_viewSrv.activeView(v)"><i class="fa fa-circle flag"></i> {{v.nick}} </a>
</span>
</li>
</ng-container>
</ul>
</li>
</ul> </ul>
</div> </div>
...@@ -6,11 +6,12 @@ ...@@ -6,11 +6,12 @@
* @author liuzheng <liuzheng712@gmail.com> * @author liuzheng <liuzheng712@gmail.com>
*/ */
import {Component, Inject, OnInit} from '@angular/core'; import {Component, Inject, OnInit} from '@angular/core';
import {HttpService, LocalStorageService, NavService, LogService} from '@app/app.service'; import {HttpService, LocalStorageService, NavService, LogService, ViewService} from '@app/app.service';
import {DataStore, i18n} from '@app/globals'; import {DataStore, i18n} from '@app/globals';
import * as jQuery from 'jquery/dist/jquery.min.js'; import * as jQuery from 'jquery/dist/jquery.min.js';
import {ElementLeftBarComponent} from '@app/elements/left-bar/left-bar.component';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
declare let layer: any; import {View} from '@app/model';
@Component({ @Component({
selector: 'elements-nav', selector: 'elements-nav',
...@@ -21,6 +22,7 @@ export class ElementNavComponent implements OnInit { ...@@ -21,6 +22,7 @@ export class ElementNavComponent implements OnInit {
DataStore = DataStore; DataStore = DataStore;
navs: Array<any>; navs: Array<any>;
_asyncTree = false; _asyncTree = false;
viewList: Array<View>;
static Hide() { static Hide() {
jQuery('elements-nav').hide(); jQuery('elements-nav').hide();
...@@ -30,13 +32,13 @@ export class ElementNavComponent implements OnInit { ...@@ -30,13 +32,13 @@ export class ElementNavComponent implements OnInit {
private _logger: LogService, private _logger: LogService,
public _dialog: MatDialog, public _dialog: MatDialog,
public _navSvc: NavService, public _navSvc: NavService,
public _viewSrv: ViewService,
private _localStorage: LocalStorageService) { private _localStorage: LocalStorageService) {
this._logger.log('nav.ts:NavComponent');
this.getNav();
} }
ngOnInit() { ngOnInit() {
this.navs = this.getNav(); this.navs = this.getNav();
this.viewList = this._viewSrv.viewList;
} }
get treeLoadAsync() { get treeLoadAsync() {
...@@ -54,12 +56,12 @@ export class ElementNavComponent implements OnInit { ...@@ -54,12 +56,12 @@ export class ElementNavComponent implements OnInit {
break; break;
} }
case 'HideLeft': { case 'HideLeft': {
DataStore.showLeftBar = false; ElementLeftBarComponent.Hide();
this.refreshNav(); this.refreshNav();
break; break;
} }
case 'ShowLeft': { case 'ShowLeft': {
DataStore.showLeftBar = true; ElementLeftBarComponent.Show();
this.refreshNav(); this.refreshNav();
break; break;
} }
...@@ -90,11 +92,6 @@ export class ElementNavComponent implements OnInit { ...@@ -90,11 +92,6 @@ export class ElementNavComponent implements OnInit {
window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('resize'));
break; break;
} }
case'Disconnect': {
if (!confirm('断开当前连接?')) {
return
}
}
case 'Reconnect': { case 'Reconnect': {
break; break;
} }
......
...@@ -21,7 +21,7 @@ export class ElementTermComponent implements OnInit, AfterViewInit { ...@@ -21,7 +21,7 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
@Output() winSizeChangeTrigger = new EventEmitter<Array<number>>(); @Output() winSizeChangeTrigger = new EventEmitter<Array<number>>();
winSizeChange$: Observable<any>; winSizeChange$: Observable<any>;
constructor(private _logger: LogService){ constructor(private _logger: LogService) {
} }
...@@ -33,7 +33,8 @@ export class ElementTermComponent implements OnInit, AfterViewInit { ...@@ -33,7 +33,8 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
this.winSizeChange$ this.winSizeChange$
.subscribe(() => { .subscribe(() => {
this.resizeTerm(); this._logger.debug('Get win size change event');
this.resizeTerm();
}); });
} }
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
/*}*/ /*}*/
.left-side { .left-side {
min-width: 100px;
} }
.handle { .handle {
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
user-select: none; user-select: none;
z-index: 9999; z-index: 9999;
height: 5px; height: 5px;
width: 1px; width: 0;
display: block; display: block;
padding: 0; padding: 0;
margin: 0; margin: 0;
......
<elements-nav></elements-nav> <elements-nav></elements-nav>
<div fxLayout="row" id="container" ngxSplit="row"> <div fxLayout="row" id="container" ngxSplit="row">
<div fxFlex="20%" fxFlexFill maxBasis="400px" minBasis="100px" ngxSplitArea *ngIf="DataStore.showLeftBar" class="left-side"> <div fxFlex="20%" fxFlexFill ngxSplitArea
[ngStyle]="{'display': store.showLeftBar ? '' : 'none', 'min-width': store.showLeftBar ? '100px': ''}"
class="left-side"
>
<elements-left-bar></elements-left-bar> <elements-left-bar></elements-left-bar>
</div> </div>
<div ngxSplitHandle (mouseup)="dragSplitBtn($event)" class="handle handle-row" *ngIf="DataStore.showLeftBar" > <div ngxSplitHandle (mouseup)="dragSplitBtn($event)" class="handle handle-row" [ngStyle]="{'display': store.showLeftBar ? '' : 'none'}" >
<i class="fa fa-window-minimize" style="color: white"></i> <i class="fa fa-window-minimize" style="color: white"></i>
</div> </div>
<div [fxFlex]="DataStore.showLeftBar ? '80%' : '100%'" fxFlexFill ngxSplitArea class="content"> <div [fxFlex]="store.showLeftBar ? '80%' : '100%'" fxFlexFill ngxSplitArea class="content">
<elements-content></elements-content> <elements-content></elements-content>
</div> </div>
</div> </div>
...@@ -9,7 +9,7 @@ import {environment} from '@src/environments/environment'; ...@@ -9,7 +9,7 @@ import {environment} from '@src/environments/environment';
}) })
export class PageMainComponent implements OnInit { export class PageMainComponent implements OnInit {
User = User; User = User;
DataStore = DataStore; store = DataStore;
ngOnInit(): void { ngOnInit(): void {
} }
......
...@@ -69,5 +69,6 @@ ...@@ -69,5 +69,6 @@
"load tree async": "异步加载树", "load tree async": "异步加载树",
"load tree sync": "同步加载树", "load tree sync": "同步加载树",
"show manual password": "显示手动密码窗", "show manual password": "显示手动密码窗",
"skip manual password": "跳过手动密码窗" "skip manual password": "跳过手动密码窗",
"tab list": "窗口列表"
} }
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