Skip to content

Commit

Permalink
#249 added console pop-out functionality (#251)
Browse files Browse the repository at this point in the history
* #249 added console pop-out functionality

* #249
  • Loading branch information
arawinters authored Jan 31, 2022
1 parent 666c96e commit 99b3097
Show file tree
Hide file tree
Showing 16 changed files with 218 additions and 31 deletions.
7 changes: 6 additions & 1 deletion src/app/admin/admin-console/admin-console.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ <h2 class="section-title">
These were formerly known as the POC (Proof of Concept) utilities in prior Senzing versions. We renamed them to EDA (Exploratory Data Analysis) tools because while they certainly help POCs they can be used long after to help ensure your system is performing as expected.
<a href="https://senzing.zendesk.com/hc/en-us/articles/360052040553-Exploratory-Data-Analysis-Overview-EDA-Tools-" target="_new">Click here</a> for more information on what each tool does and a brief walkthrough of functionality.
</p>
<sz-xterm #xtermConsole [class.taller]="!this.uiService.searchExpanded"></sz-xterm>
<div *ngIf="!isConsolePoppedOut" class="xterm-rel-wrapper">
<mat-icon class="pop-out-icon" (click)="detachCmdFromPage()">open_in_new</mat-icon>
<button mat-button class="button-connect" *ngIf="!isConnected && !isConsolePoppedOut" (click)="toggleConnection()"><mat-icon>link</mat-icon>Connect</button>
<!--<button mat-button class="button-disconnect" *ngIf="isConnected && !isConsolePoppedOut" (click)="toggleConnection()"><mat-icon>link_off</mat-icon>Disconnect</button>-->
<sz-xterm #xtermConsole [class.taller]="!this.uiService.searchExpanded"></sz-xterm>
</div>
23 changes: 23 additions & 0 deletions src/app/admin/admin-console/admin-console.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,27 @@
height: calc(100vh - 240px);
}
}
.xterm-rel-wrapper {
position: relative;
.pop-out-icon {
position: absolute;
bottom: 25px;
right: 30px;
color: #fff;
z-index: 20;
cursor: pointer;
}
.button-connect,
.button-disconnect {
position: absolute;
bottom: 20px;
right: 60px;
z-index: 22;
cursor: pointer;
color: #fff;
.mat-icon {
margin-right: 8px;
}
}
}
}
47 changes: 44 additions & 3 deletions src/app/admin/admin-console/admin-console.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,30 @@ export class AdminConsoleComponent implements AfterViewInit, OnDestroy {
@ViewChild('xtermConsole')
xtermConsole: XtermComponent;

private externalWindow = null;
private _extConsoleClosedCheckTimer;
private _externalWindowDefaultWidth = 1280;
private _externalWindowDefaultHeight = 768;

public get isConnected(): boolean {
return this.xtermService.connected;
}
public get isConsolePoppedOut(): boolean {
return this.uiService.consolePopOutOpen;
}

constructor( public uiService: UiService, private xtermService: SzXtermSocket) {}
constructor( private xtermService: SzXtermSocket, public uiService: UiService) {}

ngAfterViewInit(): void {
this.uiService.onSearchExpanded.pipe(
takeUntil(this.unsubscribe$)
).subscribe((isExpanded: boolean) => {
// call "fit()" in the xterm component when expansion state changes
console.log('search expansion state changed. calling "xtermConsole.fit()"..');
this.xtermConsole.fit();
if(this.xtermConsole && this.xtermConsole.fit) {
try {
this.xtermConsole.fit();
} catch(err){}
}
});
}

Expand All @@ -39,4 +50,34 @@ export class AdminConsoleComponent implements AfterViewInit, OnDestroy {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
public toggleConnection() {
if(this.xtermConsole && this.xtermConsole.refresh) {
console.log('toggleConnection: ', this.xtermConsole);
this.xtermConsole.refresh();
}
}
/** pop command window out of page */
public detachCmdFromPage() {
if(this.xtermConsole && this.xtermConsole.disconnect) {
console.log('disconnect socket from console');
this.xtermConsole.disconnect();
}

let _windowOpts = 'width='+ this._externalWindowDefaultWidth +',height='+this._externalWindowDefaultHeight+',left=200,top=200'
this.externalWindow = window.open('/no-decorator(popup:console)', '_szconsole', _windowOpts);
this.uiService.consolePopOutOpen = true;
this._extConsoleClosedCheckTimer = setInterval(() => {
if(this.externalWindow && this.externalWindow.closed){
clearInterval(this._extConsoleClosedCheckTimer);
this.uiService.consolePopOutOpen = false;
setTimeout(() => {
if(this.xtermConsole && this.xtermConsole.refresh) {
try {
this.xtermConsole.refresh()
} catch(err){}
}
}, 1000);
}
})
}
}
2 changes: 2 additions & 0 deletions src/app/admin/admin-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { AdminServerInfoComponent } from './server-info/server-info.component';
import { AdminLicenseInfoComponent } from './license-info/license-info.component';
import { AdminLoginComponent } from './login/login.component';
import { AdminConsoleComponent } from './admin-console/admin-console.component';
import { XtermComponent } from './xterm/xterm.component';

/** injection token for external redirects */
const externalUrlProvider = new InjectionToken('externalUrlRedirectResolver');
Expand Down Expand Up @@ -74,6 +75,7 @@ const routes: Routes = [
},
{
path: 'console',
pathMatch: 'full',
component: AdminConsoleComponent
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/app/admin/xterm/xterm.component.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="xterm-wrapper">
<div class="xterm-wrapper" [class.fullscreen]="_isFullScreen">
<div *ngIf="!isConnected" class="xterm-console-shade" [class.xtermConsoleDisconnected]="!isConnected">
<span class="xterm-console-shade-center">Disconnected</span>
</div>
Expand Down
31 changes: 31 additions & 0 deletions src/app/admin/xterm/xterm.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@
position: relative;
width: calc(100vw - 220px - 80px);
height: calc(100vh - 470px);
&.fullscreen {
width: calc(100vw - 0px) !important;
height: calc(100vh - 0px) !important;
.xterm-viewport,
.xterm-screen,
.xterm-console-shade {
width: calc(100vw - 0px) !important;
height: calc(100vh - 0px) !important;
}
.xterm-console-shade {
width: calc(100vw - 0px) !important;
}
.xterm-screen {
margin: 0;
}
}
}
.xterm-console-shade {
position: absolute;
Expand All @@ -49,4 +65,19 @@
width: 100%;
height: 100%;
}

/* I have no idea why but this doesnt work
maybe something to do with ShadowDom
*/
/*
&.fullscreen {
border: 2px dashed darkblue;
.xterm-viewport,
.xterm-screen,
.xterm-wrapper,
.xterm-console-shade {
width: 100vw !important;
height: 100vh !important;
}
}*/
}
51 changes: 40 additions & 11 deletions src/app/admin/xterm/xterm.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild, ViewEncapsulation } from '@angular/core';
import { AfterViewInit, Component, ElementRef, HostBinding, OnDestroy, ViewChild, ViewEncapsulation } from '@angular/core';
import { Terminal } from 'xterm';
import { WebLinksAddon } from 'xterm-addon-web-links';
import { FitAddon } from 'xterm-addon-fit';
import { debounce, interval, fromEvent, Observable, Subject, Subscription, takeUntil, take, filter } from 'rxjs';
import { fromEvent, Observable, Subject, Subscription, takeUntil, take, filter } from 'rxjs';
import { SzXtermSocket } from '../../services/xterm.socket.service';
import { UiService } from '../../services/ui.service';
import { Title } from '@angular/platform-browser';

@Component({
encapsulation: ViewEncapsulation.ShadowDom,
Expand All @@ -17,11 +19,13 @@ export class XtermComponent implements AfterViewInit, OnDestroy {
/** observable to watch for window resize events (allows us to debounce)*/
resizeObservable$: Observable<Event>
resizeSubscription$: Subscription

/** if fullscreen max width/height */
@HostBinding('class.fullscreen') get _isFullScreen() {
return this.uiService.noDecoration;
}
/** native html element for xterm to bind to */
@ViewChild('myTerminal')
terminalDiv: ElementRef;

/** terminal instance */
public term: Terminal;
/** is the console component connected to the socket-io server */
Expand All @@ -34,12 +38,20 @@ export class XtermComponent implements AfterViewInit, OnDestroy {
public get reconnecting(): boolean {
return this._reconnecting
}
/** console can be popped out of page
* when it is this flag is "true"
*/
public get isFullScreen(): boolean {
return this.uiService.noDecoration;
}

/** fit addon responsible for resizing xterm to container size */
private fitAddon: FitAddon;

constructor(private socket: SzXtermSocket) {}

constructor(private socket: SzXtermSocket,
private titleService: Title,
private uiService: UiService) {}

ngAfterViewInit(): void {
console.log('XtermComponent.ngAfterViewInit');
// initialize terminal
Expand All @@ -54,6 +66,10 @@ export class XtermComponent implements AfterViewInit, OnDestroy {
console.log('terminal resized: ', evt);
this.fitAddon.fit();
});

if(this.isFullScreen) {
this.titleService.setTitle('Senzing EDA Tools Web Console');
}
}
private initializeTerminal() {
if(this.term) {
Expand Down Expand Up @@ -81,10 +97,11 @@ export class XtermComponent implements AfterViewInit, OnDestroy {
this._reconnectionAttempt = 0;

this.term.clear();
this.term.writeln('Welcome to senzing eda-tools console');
//this.term.writeln('Welcome to senzing eda-tools console');
this.term.writeln('');
this.socket.emit("input", String.fromCharCode(13));
} else {
this.term.writeln('Connecting to console..');
//this.term.writeln('Connecting to console..');
}
this.term.focus();

Expand Down Expand Up @@ -127,7 +144,8 @@ export class XtermComponent implements AfterViewInit, OnDestroy {
this._reconnecting = false;
this._reconnectionAttempt = 0;
this.term.clear();
this.term.writeln('Welcome to senzing eda-tools console');
this.term.writeln('');
//this.term.writeln('Welcome to senzing eda-tools console');
});

this.socket.onConnected.pipe(
Expand All @@ -136,7 +154,7 @@ export class XtermComponent implements AfterViewInit, OnDestroy {
this._hasEverConnected = true;
this._reconnecting = false;
this._reconnectionAttempt = 0;
console.warn('socket connected..', data);
//console.warn('socket connected..', data);
});

if(this.socket.disconnected){
Expand All @@ -153,6 +171,17 @@ export class XtermComponent implements AfterViewInit, OnDestroy {
}
/** resize the console interface */
fit() {
this.fitAddon.fit();
if(this.fitAddon && this.fitAddon.fit) {
this.fitAddon.fit();
}
}
/** do a quick disconnect and reconnect */
refresh() {
this.socket.disconnect();
this.socket.reconnect();
}
/** pass disconnect through to socket-io */
disconnect() {
this.socket.disconnect();
}
}
9 changes: 9 additions & 0 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ import { GatewayTimeoutErrorComponent } from './errors/timeout/timeout.component
import { UnknownErrorComponent } from './errors/uknown/uknown.component';
import { AboutComponent } from './about/about.component';
import { BlankComponent } from './common/blank/blank.component';
import { XtermComponent } from './admin/xterm/xterm.component';
import { NoDecorationComponent } from './common/no-decoration/no-decoration.component';

export const routes: Routes = [
{ path: 'no-decorator', component: NoDecorationComponent},
{ path: 'debug', component: BlankComponent},
{ path: 'search', component: TipsComponent, resolve: {entityId: CurrentEntityUnResolverService}, data: { animation: 'search-results' }},
{ path: 'search/results', component: SearchResultsComponent, resolve: { params: SearchParamsResolverService, results: SearchResultsResolverService }, data: { animation: 'search-results' } },
Expand All @@ -35,6 +38,12 @@ export const routes: Routes = [
{ path: 'errors/504', component: GatewayTimeoutErrorComponent, data: { animation: 'search-detail' } },
{ path: 'errors/unknown', component: UnknownErrorComponent, data: { animation: 'search-detail' } },
{ path: 'about', component: AboutComponent, data: { animation: 'search-detail'} },
{
path: 'console',
outlet: 'popup',
component: XtermComponent,
data: { fullscreen: true }
},
{ path: '', redirectTo: 'search', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
];
Expand Down
13 changes: 9 additions & 4 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<app-toolbar
<app-toolbar *ngIf="!noDecoration"
(showSection)="onToolBarSectionChange($event)"
[prefsIsShowing]="showPrefs"></app-toolbar>
<div class="tool-tray" [class.expanded]="searchExpanded" [class.graph-open]="isGraphOpen" [class.prefs-showing]="showPrefs">
<div *ngIf="!noDecoration" class="tool-tray"
[class.expanded]="searchExpanded"
[class.graph-open]="isGraphOpen"
[class.prefs-showing]="showPrefs">
<div id="toolbar-col1" class="column">
<sz-preferences *ngIf="showPrefs"
showControls="true"></sz-preferences>
Expand Down Expand Up @@ -55,7 +58,9 @@ <h2 class="title">Storage Mode</h2>
<mat-icon (click)="toggleRibbonState($event)"*ngIf="searchExpanded && !showPrefs" class="toggle-icon">expand_less</mat-icon>
</div>
<app-spinner></app-spinner>
<div class="view-primary" [class.expanded]="!this.uiService.searchExpanded" [@routeAnimation]="getAnimationData(routerOutlet)">
<div *ngIf="!noDecoration" class="view-primary" [class.expanded]="!this.uiService.searchExpanded" [@routeAnimation]="getAnimationData(routerOutlet)">
<router-outlet #routerOutlet="outlet"></router-outlet>
</div>
<router-outlet name="popup"></router-outlet>
<div *ngIf="noDecoration" class="popup-wrapper">
<router-outlet name="popup"></router-outlet>
</div>
13 changes: 10 additions & 3 deletions src/app/app.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,15 @@ sz-powered-by {
height: unset;
}
}
:host.layout-super-narrow, {
:host.layout-super-narrow {
.tool-tray.expanded {
height: 520px;
}
.tool-tray.expanded.prefs-showing {
height: unset;
}
}
:host.layout-medium, {

:host.layout-medium {
.tool-tray.expanded.prefs-showing {
height: unset;
}
Expand All @@ -174,6 +173,14 @@ app-spinner {
}
}

/* pop-ups use a different router-outlet
* inside the top-level AppComponent.
* Other elements are hidden.
*/
.popup-wrapper {
display: block;
}

// spinner animations
@-webkit-keyframes sk-stretchdelay {
0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
Expand Down
3 changes: 3 additions & 0 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export class AppComponent implements OnInit, OnDestroy {
return 'memory';
}
}
public get noDecoration(): boolean {
return this.uiService.noDecoration;
}

/** subscription to notify subscribers to unbind */
public unsubscribe$ = new Subject<void>();
Expand Down
Loading

0 comments on commit 99b3097

Please sign in to comment.