Commit bc92f254 authored by ibuler's avatar ibuler

[Update] 支持新窗口打开

parent 989b0fd8
......@@ -78,8 +78,12 @@ export class HttpService {
return this.http.get<Array<TreeNode>>(url);
}
getMyGrantedRemoteApps() {
return this.http.get<Array<TreeNode>>('/api/perms/v1/user/remote-apps/tree/');
getMyGrantedRemoteApps(id?: string) {
let url = '/api/perms/v1/user/remote-apps/tree/';
if (id) {
url += `?id=${id}&only=1`;
}
return this.http.get<Array<TreeNode>>(url);
}
getMyAssetSystemUsers(assetId: string) {
......@@ -339,13 +343,11 @@ export class AppService implements OnInit {
}
checklogin() {
this._logger.log('service.ts:AppService,checklogin');
this._logger.debug('Check user auth');
if (!DataStore.Path) {
this._router.navigate(['FOF']);
}
if (document.location.pathname === '/luna/connect') {
return;
}
if (User.logined) {
if (document.location.pathname === '/login') {
this._router.navigate(['']);
......@@ -363,8 +365,10 @@ export class AppService implements OnInit {
err => {
// this._logger.error(err);
User.logined = false;
window.location.href = document.location.origin + '/users/login?next=' +
document.location.pathname + document.location.search;
if (document.location.pathname !== '/luna/connect') {
window.location.href = document.location.origin + '/users/login?next=' +
document.location.pathname + document.location.search;
}
// this._router.navigate(['login']);
},
);
......
......@@ -12,12 +12,10 @@
<div #rMenu *ngIf="isShowRMenu" class="basicContext" [style.top]="pos.top" [style.left]="pos.left">
<table>
<tbody>
<tr class="basicContext__item ">
<td class="basicContext__data" data-num="0" (click)="connectTerminal()"> <span class="basicContext__icon fa fa-terminal new-connection"></span> {{ "New Connection"|trans }} </td>
</tr>
<tr class="basicContext__item basicContext__item--separator"></tr>
<tr class="basicContext__item ">
<td class="basicContext__data" data-num="2" (click)="connectFileManager()"><span class="basicContext__icon fa fa-file refresh"></span> {{ "File Manager"|trans }} </td>
<tr *ngFor="let menu of RMenuList; let i = index" class="basicContext__item ">
<td class="basicContext__data" [attr.data-num]="i" (click)="menu.click()" [ngStyle]="{'display': menu.hide ? 'none': ''}">
<span class="basicContext__icon fa" [ngClass]="menu.fa"></span> {{ menu.name|trans }}
</td>
</tr>
</tbody>
</table>
......
......@@ -57,8 +57,9 @@
.basicContext td {
display: block;
padding: 0 35px;
padding: 0 15px;
text-decoration: none;
min-width: 150px;
width: auto;
opacity: 1;
white-space: nowrap;
......@@ -69,6 +70,11 @@
border-radius: 0;
cursor: pointer;
}
.basicContext__icon {
padding-right: 5px;
}
.basicContext__item.basicContext__item--separator {
background: #181414;
border: 0;
......
......@@ -126,9 +126,13 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
const setting = Object.assign({}, this.setting);
setting['callback'] = {
onClick: this.onRemoteAppsNodeClick.bind(this),
onRightClick: this.onRightClick.bind(this)
};
this._http.getMyGrantedRemoteApps().subscribe(
resp => {
if (!resp) {
return;
}
const tree = $.fn.zTree.init($('#remoteAppsTree'), setting, resp);
this.remoteAppsTree = tree;
this.rootNodeAddDom(tree, () => {
......@@ -175,11 +179,11 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
this.isShowRMenu = false;
}
onRightClick(event, treeId, treeNode) {
if (!treeNode || treeNode.isParent) {
return null;
nodeSupportSSH() {
const host = this.rightClickSelectNode.meta.asset;
if (!host) {
return false;
}
const host = treeNode.meta.asset;
let findSSHProtocol = false;
const protocols = host.protocols || [];
if (host.protocol) {
......@@ -191,9 +195,34 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
findSSHProtocol = true;
}
}
if (!findSSHProtocol) {
alert('Windows 请使用Ctrl+Shift+Alt呼出侧边栏上传下载');
return findSSHProtocol;
}
get RMenuList() {
const menuList = [{
'id': 'new-connection',
'name': 'Open in new window',
'fa': 'fa-terminal',
'hide': false,
'click': this.connectInNewWindow.bind(this)
}, {
'id': 'file-manager',
'name': 'File Manager',
'fa': 'fa-file',
'hide': !this.nodeSupportSSH(),
'click': this.connectFileManager.bind(this)
}];
if (!this.rightClickSelectNode) {
return [];
}
return menuList;
}
onRightClick(event, treeId, treeNode) {
if (!treeNode || treeNode.isParent) {
return null;
}
this.rightClickSelectNode = treeNode;
if (!treeNode && event.target.tagName.toLowerCase() !== 'button' && $(event.target).parents('a').length === 0) {
this.assetsTree.cancelSelectedNode();
......@@ -211,9 +240,21 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
connectEvt.next(evt);
}
connectTerminal() {
const host = this.rightClickSelectNode;
this.connectAsset(host);
connectInNewWindow() {
const node = this.rightClickSelectNode;
let url = '/luna/connect?';
switch (node.meta.type) {
case 'asset':
url += 'asset=' + node.meta.asset.id;
break;
case 'remote_app':
url += 'remote_app=' + node.id;
break;
default:
alert('Unknown type: ' + node.meta.type);
return;
}
window.open(url, '_blank');
}
filterAssets(keyword) {
......
......@@ -14,7 +14,6 @@ import {View} from '@app/model';
export class ElementConnectComponent implements OnInit, OnDestroy {
@Output() onNewView: EventEmitter<View> = new EventEmitter<View>();
pos = {left: '100px', top: '200px'};
hasLoginTo = false;
constructor(private _appSvc: AppService,
......
<div class="window" [ngClass]="{'active':view.active}" style="height: 100%">
<elements-ssh-term
[view]="view"
[host]="view.host"
[sysUser]="view.user"
*ngIf="view.type=='ssh'"
>
</elements-ssh-term>
<elements-guacamole
[view]="view"
[host]="view.host"
[sysUser]="view.user"
[remoteAppId]="view.remoteApp"
*ngIf="view.type=='rdp'"
>
</elements-guacamole>
<app-sftp *ngIf="view.type=='sftp'" [host]="view.host"></app-sftp>
</div>
<div class="window" [ngClass]="{'active':view.active}" style="height: 100%">
<elements-ssh-term
[view]="view"
[host]="view.host"
[sysUser]="view.user"
*ngIf="view.type=='ssh'"
>
</elements-ssh-term>
<elements-guacamole
[view]="view"
[host]="view.host"
[sysUser]="view.user"
[remoteAppId]="view.remoteApp"
*ngIf="view.type=='rdp'"
>
</elements-guacamole>
<app-sftp *ngIf="view.type=='sftp'" [host]="view.host"></app-sftp>
</div>
......@@ -10,7 +10,6 @@ import {ViewService} from '@app/app.service';
export class ElementContentComponent implements OnInit {
@ViewChild('tabs') tabsRef: ElementRef;
viewList: Array<View>;
hasLoginTo = false;
static DisconnectAll() {
}
......
......@@ -40,7 +40,7 @@ export class ElementGuacamoleComponent implements OnInit {
},
error => {
if (!this.registered) {
console.log('Register host error, register token then connect');
this._logger.debug('Register host error, register token then connect');
this.registerToken();
}
}
......@@ -51,6 +51,7 @@ export class ElementGuacamoleComponent implements OnInit {
const now = new Date();
const nowTime = now.getTime() / 1000;
this.registered = true;
this._logger.debug('Userid is', User.id);
this._http.getGuacamoleToken(User.id, '').subscribe(
data => {
// /guacamole/client will redirect to http://guacamole/#/client
......
<div class="nav">
<ul class="nav-main">
<li>
<li style="padding-right: 10px">
<a href="/"><img src="static/imgs/logo.png" height="26px"/></a>
</li>
<li *ngFor="let v of navs" [ngClass]="{'dropdown': v.children}" >
......
......@@ -56,7 +56,7 @@ export class ElementSshTermComponent implements OnInit, OnDestroy {
}
reconnect() {
if (this.view.connected === true) {
if (this.view.connected !== true) {
if (!confirm(translate('Are you sure to reconnect it?(RDP not support)'))) {
return;
}
......
......@@ -46,11 +46,11 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
getWinSize() {
let availableHeight = 0;
let availableWidth = 0;
const activeEle = $('#winContainer');
if (document['fullscreenElement']) {
availableWidth = document.body.clientWidth - 10;
availableHeight = document.body.clientHeight;
} else {
const activeEle = $('#winContainer');
} else if (activeEle) {
const elementStyle = window.getComputedStyle(this.term.element);
const elementPadding = {
top: parseInt(elementStyle.getPropertyValue('padding-top'), 10),
......@@ -63,6 +63,7 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
availableHeight = activeEle.height() - elementPaddingVer;
availableWidth = activeEle.width() - elementPaddingHor - (<any>this.term).viewport.scrollBarWidth;
}
this._logger.debug('Winsize: ', availableWidth, availableHeight);
const dimensions = (<any>this.term).renderer.dimensions;
const geometry = [
......@@ -76,6 +77,7 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
if (!isFinite(geometry[1])) {
geometry[1] = 24;
}
this._logger.debug('size: ', geometry);
return geometry;
}
......
<elements-ssh-term
[token]="token"
[index]="0"
*ngIf="system =='linux'">
</elements-ssh-term>
<elements-guacamole
[target]="target"
[index]="0"
*ngIf="system=='windows' && target">
</elements-guacamole>
<div class="windows" id="winContainer">
<elements-content-window [view]="view" *ngIf="view"></elements-content-window>
<elements-connect [ngStyle]="{'display': 'none'}" (onNewView)="onNewView($event)"></elements-connect>
</div>
.windows {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
background-color: #1f1b1b;
}
import {Component, OnInit} from '@angular/core';
import {AppService, HttpService, LocalStorageService} from '@app/app.service';
import {DataStore} from '@app/globals';
import * as jQuery from 'jquery/dist/jquery.min.js';
import {connectEvt} from '@app/globals';
import {ConnectEvt} from '@app/model';
// import {DataStore} from '@app/globals';
// import * as jQuery from 'jquery/dist/jquery.min.js';
import {View, ViewAction} from '@app/model';
@Component({
selector: 'pages-connect',
......@@ -11,80 +14,44 @@ import * as jQuery from 'jquery/dist/jquery.min.js';
export class PagesConnectComponent implements OnInit {
token: string;
system: string;
authToken: string;
userid: string;
target: string;
base: string;
view: View;
constructor(private _appService: AppService,
private _http: HttpService,
private _localStorage: LocalStorageService) {
DataStore.NavShow = false;
}
onNewView(view) {
view.active = true;
this.view = view;
}
ngOnInit() {
this.system = this._appService.getQueryString('system');
this.token = this._appService.getQueryString('token');
this.userid = this._localStorage.get('user-' + this.token);
this.authToken = this._localStorage.get('authToken-' + this.token);
this.base = this._localStorage.get('base-' + this.token);
jQuery('body').css('background-color', '#1f1b1b');
if (this.system === 'windows') {
if (!this.userid) {
this._http.getUserIdFromToken(this.token)
.subscribe(
data => {
this._localStorage.set('user-' + this.token, data['user']);
this.userid = data['user'];
this.getAuthToken();
}
);
} else {
this.getAuthToken();
}
}
}
getAuthToken() {
if (!this.authToken) {
this._http.getGuacamoleToken(this.userid, this.token).subscribe(
data => {
if (data['authToken']) {
this._localStorage.set('authToken-' + this.token, data['authToken']);
this.authToken = data['authToken'];
this.getBase();
const assetId = this._appService.getQueryString('asset');
const remoteAppId = this._appService.getQueryString('remote_app');
if (assetId) {
this._http.filterMyGrantedAssetsById(assetId).subscribe(
nodes => {
if (!nodes) {
return;
}
const evt = new ConnectEvt(nodes[0], 'asset');
connectEvt.next(evt);
}
);
} else {
this.getBase();
}
}
getBase() {
if (!this.base) {
this._http.guacamoleTokenAddAsset(this.token, this.authToken).subscribe(
data => {
if (data['result']) {
this._localStorage.set('base-' + this.token, data['result']);
this.base = data['result'];
this.setWinTarget();
if (remoteAppId) {
this._http.getMyGrantedRemoteApps(remoteAppId).subscribe(
nodes => {
if (!nodes) {
return;
}
});
} else {
this.setWinTarget();
}
}
setWinTarget() {
if (this.base && this.authToken) {
this.target = document.location.origin + '/guacamole/#/client/' + this.base +
'?asset_token=jumpserver&token=' + this.authToken;
} else {
window.location.reload();
const evt = new ConnectEvt(nodes[0], 'asset');
connectEvt.next(evt);
}
);
}
}
}
......@@ -6,7 +6,8 @@
>
<elements-left-bar></elements-left-bar>
</div>
<div ngxSplitHandle (mouseup)="dragSplitBtn($event)" class="handle handle-row" [ngStyle]="{'display': store.showLeftBar ? '' : 'none'}" >
<div ngxSplitHandle (mouseup)="dragSplitBtn($event)" class="handle handle-row"
[ngStyle]="{'display': showSplitter ? '' : 'none'}" >
<i class="fa fa-window-minimize" style="color: white"></i>
</div>
<div [fxFlex]="store.showLeftBar ? '80%' : '100%'" fxFlexFill ngxSplitArea class="content">
......
import {Component, HostListener, OnInit} from '@angular/core';
import {DataStore, User} from '@app/globals';
import {environment} from '@src/environments/environment';
import {ViewService} from '@app/app.service';
@Component({
selector: 'pages-main',
......@@ -11,6 +12,19 @@ export class PageMainComponent implements OnInit {
User = User;
store = DataStore;
constructor(public viewSrv: ViewService) {}
get currentView() {
return this.viewSrv.currentView;
}
get showSplitter() {
if (this.currentView && this.currentView.type !== 'ssh') {
return false;
}
return this.store.showLeftBar;
}
ngOnInit(): void {
}
......
......@@ -70,5 +70,6 @@
"load tree sync": "同步加载树",
"show manual password": "显示手动密码窗",
"skip manual password": "跳过手动密码窗",
"tab list": "窗口列表"
"tab list": "窗口列表",
"open in new window": "新窗口打开"
}
......@@ -2,10 +2,9 @@
set -ex
rm -fr luna
npm run-script build
rm -fr luna*
mv dist luna
cp -R src/assets/i18n luna/
tar czf luna.tar.gz luna
md5 luna.tar.gz
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