Unverified Commit 76928733 authored by BaiJiangJie's avatar BaiJiangJie Committed by GitHub

Merge pull request #121 from jumpserver/dev

Dev
parents 100a1ac4 c9090d26
...@@ -9,7 +9,7 @@ import {MAT_LABEL_GLOBAL_OPTIONS} from '@angular/material'; ...@@ -9,7 +9,7 @@ import {MAT_LABEL_GLOBAL_OPTIONS} from '@angular/material';
// service // service
import {AllServices} from '@app/services'; import {AllServices} from '@app/services';
import {AppRouterModule} from './router/router.module'; import {AppRouterModule} from './router.module';
import {Pipes} from './pipes/pipes'; import {Pipes} from './pipes/pipes';
import {AppComponent} from './pages/app.component'; import {AppComponent} from './pages/app.component';
import {PagesComponents} from './pages/pages.component'; import {PagesComponents} from './pages/pages.component';
......
<div> <div>
<p *ngIf="loading" style="padding: 3px">{{ "Loading"|trans }} ...</p>
<ul id="assetsTree" class="ztree"> <ul id="assetsTree" class="ztree">
{{ "Loading"|trans }} ...
</ul> </ul>
<ul id="remoteAppsTree" class="ztree"> <ul id="remoteAppsTree" class="ztree">
{{ "Loading"|trans }} ...
</ul> </ul>
</div> </div>
......
...@@ -46,6 +46,7 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -46,6 +46,7 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
treeFilterSubscription: any; treeFilterSubscription: any;
isLoadTreeAsync: boolean; isLoadTreeAsync: boolean;
filterAssetCancel$: Subject<boolean> = new Subject(); filterAssetCancel$: Subject<boolean> = new Subject();
loading = true;
constructor(private _appSvc: AppService, constructor(private _appSvc: AppService,
private _treeFilterSvc: TreeFilterService, private _treeFilterSvc: TreeFilterService,
...@@ -103,7 +104,9 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -103,7 +104,9 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
}; };
} }
this.loading = true;
this._http.getMyGrantedNodes(this.isLoadTreeAsync, refresh).subscribe(resp => { this._http.getMyGrantedNodes(this.isLoadTreeAsync, refresh).subscribe(resp => {
this.loading = false;
const assetsTree = $.fn.zTree.init($('#assetsTree'), setting, resp); const assetsTree = $.fn.zTree.init($('#assetsTree'), setting, resp);
this.assetsTree = assetsTree; this.assetsTree = assetsTree;
this.rootNodeAddDom(assetsTree, () => { this.rootNodeAddDom(assetsTree, () => {
...@@ -134,7 +137,7 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -134,7 +137,7 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
}; };
this._http.getMyGrantedRemoteApps().subscribe( this._http.getMyGrantedRemoteApps().subscribe(
resp => { resp => {
if (!resp) { if (resp.length === 1) {
return; return;
} }
const tree = $.fn.zTree.init($('#remoteAppsTree'), setting, resp); const tree = $.fn.zTree.init($('#remoteAppsTree'), setting, resp);
...@@ -325,21 +328,22 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -325,21 +328,22 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
this.assetsTree.removeChildNodes(searchNode[0]); this.assetsTree.removeChildNodes(searchNode[0]);
this.assetsTree.removeNode(searchNode[0]); this.assetsTree.removeNode(searchNode[0]);
} }
const treeNodes = this.assetsTree.getNodes();
if (!keyword) { if (!keyword) {
const treeNodes = this.assetsTree.getNodes();
if (treeNodes.length !== 0) { if (treeNodes.length !== 0) {
this.assetsTree.showNode(treeNodes[0]); this.assetsTree.showNode(treeNodes[0]);
} }
return; return;
} }
this.filterAssetCancel$.next(true); this.filterAssetCancel$.next(true);
if (treeNodes.length !== 0) {
this.assetsTree.hideNode(treeNodes[0]);
}
this.loading = true;
this._http.getMyGrantedAssets(keyword) this._http.getMyGrantedAssets(keyword)
.pipe(takeUntil(this.filterAssetCancel$)) .pipe(takeUntil(this.filterAssetCancel$))
.subscribe(nodes => { .subscribe(nodes => {
const treeNodes = this.assetsTree.getNodes(); this.loading = false;
if (treeNodes.length !== 0) {
this.assetsTree.hideNode(treeNodes[0]);
}
let name = translate('Search'); let name = translate('Search');
const assetsAmount = nodes.length; const assetsAmount = nodes.length;
name = `${name} (${assetsAmount})`; name = `${name} (${assetsAmount})`;
......
...@@ -13,8 +13,10 @@ import {ElementDialogAlertComponent} from './dialog/dialog.service'; ...@@ -13,8 +13,10 @@ import {ElementDialogAlertComponent} from './dialog/dialog.service';
import {ElementGuacamoleComponent} from './guacamole/guacamole.component'; import {ElementGuacamoleComponent} from './guacamole/guacamole.component';
import {ElementSshTermComponent} from './ssh-term/ssh-term.component'; import {ElementSshTermComponent} from './ssh-term/ssh-term.component';
import {ElementConnectComponent, AssetTreeDialogComponent, ManualPasswordDialogComponent} from './connect/connect.component'; import {ElementConnectComponent, AssetTreeDialogComponent, ManualPasswordDialogComponent} from './connect/connect.component';
import {ElementSftpComponent} from '@app/elements/sftp/sftp.component'; import {ElementSftpComponent} from './sftp/sftp.component';
import {ElementSettingComponent} from '@app/elements/setting/setting.component'; import {ElementSettingComponent} from './setting/setting.component';
import {ElementReplayGuacamoleComponent} from './replay/guacamole/guacamole.component';
import {ElementReplayJsonComponent} from './replay/json/json.component';
export const ElementComponents = [ export const ElementComponents = [
ElementLeftBarComponent, ElementLeftBarComponent,
...@@ -33,6 +35,8 @@ export const ElementComponents = [ ...@@ -33,6 +35,8 @@ export const ElementComponents = [
ElementSshTermComponent, ElementSshTermComponent,
ElementConnectComponent, ElementConnectComponent,
ElementSftpComponent, ElementSftpComponent,
ElementReplayGuacamoleComponent,
ElementReplayJsonComponent,
AssetTreeDialogComponent, AssetTreeDialogComponent,
ChangLanWarningDialogComponent, ChangLanWarningDialogComponent,
ManualPasswordDialogComponent, ManualPasswordDialogComponent,
......
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReplayGuacamoleComponent } from './guacamole.component'; import { ElementReplayGuacamoleComponent } from './guacamole.component';
describe('ReplayGuacamoleComponent', () => { describe('ReplayGuacamoleComponent', () => {
let component: ReplayGuacamoleComponent; let component: ElementReplayGuacamoleComponent;
let fixture: ComponentFixture<ReplayGuacamoleComponent>; let fixture: ComponentFixture<ElementReplayGuacamoleComponent>;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ReplayGuacamoleComponent ] declarations: [ ElementReplayGuacamoleComponent ]
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ReplayGuacamoleComponent); fixture = TestBed.createComponent(ElementReplayGuacamoleComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
......
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import * as Guacamole from 'guacamole-common-js/dist/guacamole-common'; import * as Guacamole from 'guacamole-common-js/dist/guacamole-common';
import { Replay } from '../replay.model'; import { Replay } from '@app/model';
function zeroPad(num, minLength) { function zeroPad(num, minLength) {
let str = num.toString(); let str = num.toString();
...@@ -46,11 +46,11 @@ function formatTime(millis: number) { ...@@ -46,11 +46,11 @@ function formatTime(millis: number) {
@Component({ @Component({
selector: 'app-replay-guacamole', selector: 'elements-replay-guacamole',
templateUrl: './guacamole.component.html', templateUrl: './guacamole.component.html',
styleUrls: ['./guacamole.component.scss'] styleUrls: ['./guacamole.component.scss']
}) })
export class ReplayGuacamoleComponent implements OnInit { export class ElementReplayGuacamoleComponent implements OnInit {
isPlaying = false; isPlaying = false;
recording: any; recording: any;
playerRef: any; playerRef: any;
...@@ -80,9 +80,6 @@ export class ReplayGuacamoleComponent implements OnInit { ...@@ -80,9 +80,6 @@ export class ReplayGuacamoleComponent implements OnInit {
recordingElement.style.margin = '0 auto'; recordingElement.style.margin = '0 auto';
this.screenRef.appendChild(recordingElement); this.screenRef.appendChild(recordingElement);
this.initRecording(); this.initRecording();
// this.toggle();
} }
initRecording() { initRecording() {
...@@ -99,7 +96,7 @@ export class ReplayGuacamoleComponent implements OnInit { ...@@ -99,7 +96,7 @@ export class ReplayGuacamoleComponent implements OnInit {
this.recording.onprogress = (millis) => { this.recording.onprogress = (millis) => {
this.duration = formatTime(millis); this.duration = formatTime(millis);
this.max = millis; this.max = millis;
this.toggle(); this.play();
}; };
// If paused, the play/pause button should read "Play" // If paused, the play/pause button should read "Play"
...@@ -140,13 +137,25 @@ export class ReplayGuacamoleComponent implements OnInit { ...@@ -140,13 +137,25 @@ export class ReplayGuacamoleComponent implements OnInit {
e.stopPropagation(); e.stopPropagation();
} }
toggle() { play() {
if (!this.recording.isPlaying()) { if (!this.recording.isPlaying()) {
this.recording.play(); this.recording.play();
this.isPlaying = true; this.isPlaying = true;
} else { }
}
pause() {
if (this.recording.isPlaying()) {
this.recording.pause(); this.recording.pause();
this.isPlaying = false; this.isPlaying = false;
} }
} }
toggle() {
if (!this.recording.isPlaying()) {
this.play();
} else {
this.pause();
}
}
} }
...@@ -14,13 +14,19 @@ ...@@ -14,13 +14,19 @@
<input id="scrubber" type="range" [(ngModel)]="time" min=0 [attr.max]="max" (mouseup)="runFrom()"/> <input id="scrubber" type="range" [(ngModel)]="time" min=0 [attr.max]="max" (mouseup)="runFrom()"/>
<span id="position">{{ position }}</span> <span id="position" style="padding-left: 10px">{{ position }}</span>
<span>/</span> <span>/</span>
<span id="duration">{{ duration }}</span> <span id="duration">{{ duration }}</span>
{{"Speed"|trans}}: {{speed}} {{"Speed"|trans}}: {{speed}}
<span style="float: right;padding-top: 5px;padding-right: 20px">
<span style="padding-left: 10px">{{"cols"|trans}}: <input type="number" style="width: 60px" [(ngModel)]="termCols"></span>
<span style="padding-left: 10px">{{"rows"|trans}}: <input type="number" style="width: 60px" [(ngModel)]="termRows"></span>
<span style="padding-left: 10px"><input type="button" value="{{'confirm'|trans}}" (click)="resizeTerm()"></span>
</span>
</div> </div>
<div id="winContainer" style="height: 90%;width: 100%"> <div id="winContainer" style="height: 90%;width: 100%">
<elements-term [term]="term"></elements-term> <elements-term #termRef [term]="term" [stopWatchWinChange]="true" (winSizeChangeTrigger)="onTermSizeChange($event)"></elements-term>
</div> </div>
<!--<asciinema-player></asciinema-player>--> <!--<asciinema-player></asciinema-player>-->
import {Component, Input, OnInit} from '@angular/core'; import {Component, Input, OnInit, OnChanges} from '@angular/core';
import {Terminal} from 'xterm'; import {Terminal} from 'xterm';
import {HttpService, LogService} from '@app/services'; import {HttpService, LogService} from '@app/services';
import {Replay} from '../replay.model'; import {Replay} from '@app/model';
function zeroPad(num, minLength) { function zeroPad(num, minLength) {
let str = num.toString(); let str = num.toString();
...@@ -47,11 +47,11 @@ function formatTime(millis: number) { ...@@ -47,11 +47,11 @@ function formatTime(millis: number) {
@Component({ @Component({
selector: 'app-replay-json', selector: 'elements-replay-json',
templateUrl: './json.component.html', templateUrl: './json.component.html',
styleUrls: ['./json.component.css'] styleUrls: ['./json.component.css']
}) })
export class JsonComponent implements OnInit { export class ElementReplayJsonComponent implements OnInit {
isPlaying = false; isPlaying = false;
recording: any; recording: any;
playerRef: any; playerRef: any;
...@@ -67,6 +67,9 @@ export class JsonComponent implements OnInit { ...@@ -67,6 +67,9 @@ export class JsonComponent implements OnInit {
timer: any; // 多长时间播放下一个 timer: any; // 多长时间播放下一个
pos = 0; // 播放点 pos = 0; // 播放点
term: Terminal; term: Terminal;
termCols = 80;
termRows = 24;
get position() { get position() {
return formatTime(this.time); return formatTime(this.time);
} }
...@@ -110,6 +113,7 @@ export class JsonComponent implements OnInit { ...@@ -110,6 +113,7 @@ export class JsonComponent implements OnInit {
clearInterval(this.timer); clearInterval(this.timer);
this.term.reset(); this.term.reset();
this.pos = 0; this.pos = 0;
this.time = 0;
this.isPlaying = true; this.isPlaying = true;
this.timer = setInterval(() => { this.timer = setInterval(() => {
this.advance(); this.advance();
...@@ -173,4 +177,16 @@ export class JsonComponent implements OnInit { ...@@ -173,4 +177,16 @@ export class JsonComponent implements OnInit {
} }
this.advance(); this.advance();
} }
resizeTerm() {
this.term.resize(this.termCols, this.termRows);
this.restart();
}
onTermSizeChange(evt) {
setTimeout(() => {
this.termCols = evt[0];
this.termRows = evt[1];
}, 500);
}
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<input [(value)]="setting.fontSize" matInput placeholder='{{"Font size"|trans}}' name="fontSize" type="number" min="5" max="60" > <input [(ngModel)]="setting.fontSize" matInput placeholder='{{"Font size"|trans}}' name="fontSize" type="number" min="5" max="60" >
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
......
...@@ -3,7 +3,7 @@ import {ElementRef} from '@angular/core'; ...@@ -3,7 +3,7 @@ import {ElementRef} from '@angular/core';
import {Terminal} from 'xterm'; import {Terminal} from 'xterm';
import {fit} from 'xterm/lib/addons/fit/fit'; import {fit} from 'xterm/lib/addons/fit/fit';
import {LogService} from '@app/services'; import {LogService} from '@app/services';
import {Observable, fromEvent} from 'rxjs'; import {Observable, fromEvent, Subscription} from 'rxjs';
import {debounceTime, distinctUntilChanged } from 'rxjs/operators'; import {debounceTime, distinctUntilChanged } from 'rxjs/operators';
import * as $ from 'jquery/dist/jquery.min.js'; import * as $ from 'jquery/dist/jquery.min.js';
import 'rxjs/Observable'; import 'rxjs/Observable';
...@@ -18,12 +18,12 @@ export class ElementTermComponent implements OnInit, AfterViewInit { ...@@ -18,12 +18,12 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
@ViewChild('term') el: ElementRef; @ViewChild('term') el: ElementRef;
@Input() term: Terminal; @Input() term: Terminal;
@Input() offset: Array<number>; @Input() offset: Array<number>;
@Input() stopWatchWinChange = false;
@Output() winSizeChangeTrigger = new EventEmitter<Array<number>>(); @Output() winSizeChangeTrigger = new EventEmitter<Array<number>>();
winSizeChange$: Observable<any>; winSizeChange$: Observable<any>;
winSizeSub: Subscription;
constructor(private _logger: LogService) { constructor(private _logger: LogService) {}
}
ngOnInit() { ngOnInit() {
this.winSizeChange$ = fromEvent(window, 'resize').pipe( this.winSizeChange$ = fromEvent(window, 'resize').pipe(
...@@ -31,7 +31,7 @@ export class ElementTermComponent implements OnInit, AfterViewInit { ...@@ -31,7 +31,7 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
distinctUntilChanged(), distinctUntilChanged(),
); );
this.winSizeChange$ this.winSizeSub = this.winSizeChange$
.subscribe(() => { .subscribe(() => {
this._logger.debug('Get win size change event'); this._logger.debug('Get win size change event');
this.resizeTerm(); this.resizeTerm();
...@@ -41,6 +41,9 @@ export class ElementTermComponent implements OnInit, AfterViewInit { ...@@ -41,6 +41,9 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
ngAfterViewInit() { ngAfterViewInit() {
this.term.open(this.el.nativeElement); this.term.open(this.el.nativeElement);
this.resizeTerm(); this.resizeTerm();
if (this.stopWatchWinChange) {
this.winSizeSub.unsubscribe();
}
} }
getWinSize() { getWinSize() {
......
...@@ -193,3 +193,16 @@ export class Setting { ...@@ -193,3 +193,16 @@ export class Setting {
isLoadTreeAsync: string = '1'; isLoadTreeAsync: string = '1';
isSkipAllManualPassword: string = '0'; isSkipAllManualPassword: string = '0';
} }
export class Replay {
id: string;
src: string;
type: string;
status: string;
timelist: Array<number>;
totalTime: number;
json: any;
height: number;
width: number;
}
...@@ -5,20 +5,17 @@ import {PagesMonitorComponent} from './monitor/monitor.component'; ...@@ -5,20 +5,17 @@ import {PagesMonitorComponent} from './monitor/monitor.component';
import {PagesReplayComponent} from './replay/replay.component'; import {PagesReplayComponent} from './replay/replay.component';
import {PagesNotFoundComponent} from './not-found/not-found.component'; import {PagesNotFoundComponent} from './not-found/not-found.component';
import {PagesLoginComponent} from './login/login.component'; import {PagesLoginComponent} from './login/login.component';
import {JsonComponent} from './replay/json/json.component';
import {PagesMonitorLinuxComponent} from './monitor/linux/linux.component'; import {PagesMonitorLinuxComponent} from './monitor/linux/linux.component';
import {PagesMonitorWindowsComponent} from './monitor/windows/windows.component'; import {PagesMonitorWindowsComponent} from './monitor/windows/windows.component';
import {ReplayGuacamoleComponent} from './replay/guacamole/guacamole.component';
export const PagesComponents = [ export const PagesComponents = [
PageMainComponent, PageMainComponent,
PagesBlankComponent, PagesBlankComponent,
PagesConnectComponent, PagesConnectComponent,
PagesMonitorComponent, PagesMonitorComponent,
PagesReplayComponent, JsonComponent, PagesReplayComponent,
PagesNotFoundComponent, PagesNotFoundComponent,
PagesLoginComponent, PagesLoginComponent,
PagesMonitorLinuxComponent, PagesMonitorLinuxComponent,
PagesMonitorWindowsComponent, PagesMonitorWindowsComponent,
ReplayGuacamoleComponent
]; ];
<app-replay-json [replay]="replay" *ngIf="replay.type=='json'"></app-replay-json> <elements-replay-json [replay]="replay" *ngIf="replay.type=='json'"></elements-replay-json>
<app-replay-guacamole [replay]="replay" *ngIf="replay.type=='guacamole'"></app-replay-guacamole> <elements-replay-guacamole [replay]="replay" *ngIf="replay.type=='guacamole'"></elements-replay-guacamole>
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute} from '@angular/router';
import {HttpService, LogService} from '@app/services'; import {HttpService, LogService} from '@app/services';
import {Replay} from './replay.model'; import {Replay} from '@app/model';
@Component({ @Component({
selector: 'pages-replay', selector: 'pages-replay',
......
export class Replay {
id: string;
src: string;
type: string;
status: string;
timelist: Array<number>;
totalTime: number;
json: any;
height: number;
width: number;
}
import {NgModule} from '@angular/core'; import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router'; import {RouterModule, Routes} from '@angular/router';
import {PagesBlankComponent} from '../pages/blank/blank.component'; import {PagesBlankComponent} from './pages/blank/blank.component';
import {PagesConnectComponent} from '../pages/connect/connect.component'; import {PagesConnectComponent} from './pages/connect/connect.component';
import {PagesReplayComponent} from '../pages/replay/replay.component'; import {PagesReplayComponent} from './pages/replay/replay.component';
import {PageMainComponent} from '../pages/main/main.component'; import {PageMainComponent} from './pages/main/main.component';
import {PagesMonitorComponent} from '../pages/monitor/monitor.component'; import {PagesMonitorComponent} from './pages/monitor/monitor.component';
import {ElementSftpComponent} from '../elements/sftp/sftp.component'; import {ElementSftpComponent} from './elements/sftp/sftp.component';
const appRoutes: Routes = [ const appRoutes: Routes = [
......
...@@ -74,5 +74,7 @@ ...@@ -74,5 +74,7 @@
"open in new window": "新窗口打开", "open in new window": "新窗口打开",
"setting": "设置", "setting": "设置",
"yes": "是", "yes": "是",
"no": "否" "no": "否",
"cols": "列数",
"rows": "行数"
} }
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