Skip to content

Commit

Permalink
feat(ui-devkit): Allow ui extensions to be launched in a new window
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Dec 17, 2019
1 parent 895ebdf commit 71eb6a5
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
export interface ExtensionHostOptions {
extensionUrl: string;
openInNewTab?: boolean;
}

export class ExtensionHostConfig {
public extensionUrl: string;
public openInNewTab: boolean;
constructor(options: ExtensionHostOptions) {
this.extensionUrl = options.extensionUrl;
this.openInNewTab = options.openInNewTab != null ? options.openInNewTab : false;
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
<iframe [src]="extensionUrl" #extensionFrame></iframe>
<ng-template [ngIf]="openInIframe" [ngIfElse]="launchExtension">
<iframe [src]="extensionUrl" #extensionFrame></iframe>
</ng-template>
<ng-template #launchExtension>
<div class="launch-button" [class.launched]="extensionWindowIsOpen">
<div>
<button
class="btn btn-lg btn-primary"
[disabled]="extensionWindowIsOpen"
(click)="launchExtensionWindow()"
>
<clr-icon shape="pop-out"></clr-icon>
{{ 'common.launch-extension' | translate }}
</button>
<h3 class="window-hint" [class.visible]="extensionWindowIsOpen">
{{ 'common.extension-running-in-separate-window' | translate }}
</h3>
</div>
</div>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,34 @@ iframe {
height: 100%;
border: none;
}

.launch-button {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
border: none;
padding: 24px;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.3s;
text-align: center;
&.launched {
background-color: $color-grey-300;
}
}

.window-hint {
visibility: hidden;
opacity: 0;
transition: visibility 0.3s 0, opacity 0.3s;
&.visible {
visibility: visible;
opacity: 1;
transition: visibility 0, opacity 0.3s;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
ElementRef,
OnDestroy,
OnInit,
ViewChild,
} from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';

Expand All @@ -12,9 +20,13 @@ import { ExtensionHostService } from './extension-host.service';
changeDetection: ChangeDetectionStrategy.Default,
providers: [ExtensionHostService],
})
export class ExtensionHostComponent implements OnInit {
export class ExtensionHostComponent implements OnInit, AfterViewInit, OnDestroy {
extensionUrl: SafeResourceUrl;
@ViewChild('extensionFrame', { static: true }) private extensionFrame: ElementRef<HTMLIFrameElement>;
openInIframe = true;
extensionWindowIsOpen = false;
private config: ExtensionHostConfig;
private extensionWindow?: Window;
@ViewChild('extensionFrame', { static: false }) private extensionFrame: ElementRef<HTMLIFrameElement>;

constructor(
private route: ActivatedRoute,
Expand All @@ -29,15 +41,53 @@ export class ExtensionHostComponent implements OnInit {
`Expected an ExtensionHostConfig object, got ${JSON.stringify(data.extensionHostConfig)}`,
);
}
this.config = data.extensionHostConfig;
this.openInIframe = !this.config.openInNewTab;
this.extensionUrl = this.sanitizer.bypassSecurityTrustResourceUrl(
data.extensionHostConfig.extensionUrl || 'about:blank',
this.config.extensionUrl || 'about:blank',
);
const { contentWindow } = this.extensionFrame.nativeElement;
if (contentWindow) {
this.extensionHostService.init(contentWindow);
}

ngAfterViewInit() {
if (this.openInIframe) {
const extensionWindow = this.extensionFrame.nativeElement.contentWindow;
if (extensionWindow) {
this.extensionHostService.init(extensionWindow);
}
}
}

ngOnDestroy(): void {
if (this.extensionWindow) {
this.extensionWindow.close();
}
}

launchExtensionWindow() {
const extensionWindow = window.open(this.config.extensionUrl);
if (!extensionWindow) {
return;
}
this.extensionHostService.init(extensionWindow);
this.extensionWindowIsOpen = true;
this.extensionWindow = extensionWindow;

let timer: number;
function pollWindowState(extwindow: Window, onClosed: () => void) {
if (extwindow.closed) {
window.clearTimeout(timer);
onClosed();
} else {
timer = window.setTimeout(() => pollWindowState(extwindow, onClosed), 250);
}
}

pollWindowState(extensionWindow, () => {
this.extensionWindowIsOpen = false;
this.extensionHostService.destroy();
});
}

private isExtensionHostConfig(input: any): input is ExtensionHostConfig {
return input.hasOwnProperty('extensionUrl');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ export class ExtensionHostService implements OnDestroy {
window.addEventListener('message', this.handleMessage);
}

ngOnDestroy(): void {
destroy() {
window.removeEventListener('message', this.handleMessage);
this.destroyMessage$.next();
}

ngOnDestroy(): void {
this.destroy();
}

private handleMessage = (message: MessageEvent) => {
const { data, origin } = message;
if (this.isExtensionMessage(data)) {
Expand Down
5 changes: 4 additions & 1 deletion packages/admin-ui/src/i18n-messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,12 @@
"edit": "Edit",
"edit-field": "Edit field",
"enabled": "Enabled",
"extension-running-in-separate-window": "Extension is running in a separate window",
"guest": "Guest",
"items-per-page-option": "{ count } per page",
"jobs-in-progress": "{ count } {count, plural, one {job} other {jobs}} in progress",
"language": "Language",
"launch-extension": "Launch extension",
"log-out": "Log out",
"login": "Log in",
"more": "More...",
Expand Down Expand Up @@ -555,6 +557,7 @@
"catalog": "Catalog",
"channel": "Channel",
"channel-token": "Channel token",
"confirm-delete-role": "Delete role?",
"create": "Create",
"create-new-channel": "Create new channel",
"create-new-country": "Create new country",
Expand Down Expand Up @@ -604,4 +607,4 @@
"update": "Update",
"zone": "Zone"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export class TestComponent {
],
extensionHostConfig: new ExtensionHostConfig({
extensionUrl: './assets/vue-app/index.html',
openInNewTab: true,
}),
},
},
Expand Down
5 changes: 3 additions & 2 deletions packages/ui-devkit/src/devkit-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ function sendMessage<T extends ExtensionMesssage>(type: T['type'], data: T['data
};

return new Observable<any>(subscriber => {
const hostWindow = window.opener || window.parent;
const handleReply = (event: MessageEvent) => {
const response: MessageResponse = event.data;
if (response && response.requestId === requestId) {
Expand All @@ -113,10 +114,10 @@ function sendMessage<T extends ExtensionMesssage>(type: T['type'], data: T['data
}
};
const tearDown = () => {
window.parent.postMessage({ requestId, type: 'cancellation', data: null }, targetOrigin);
hostWindow.postMessage({ requestId, type: 'cancellation', data: null }, targetOrigin);
};
window.addEventListener('message', handleReply);
window.parent.postMessage(message, targetOrigin);
hostWindow.postMessage(message, targetOrigin);

return tearDown;
});
Expand Down

0 comments on commit 71eb6a5

Please sign in to comment.