You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by zj...@apache.org on 2020/01/12 06:38:20 UTC
[zeppelin] 03/16: [ZEPPELIN-4450] Provide Angular.js Template
Migration Tool
This is an automated email from the ASF dual-hosted git repository.
zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git
commit 1e0177d132f8458aa6beff570c380b7b4740399f
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Tue Nov 26 11:28:28 2019 +0800
[ZEPPELIN-4450] Provide Angular.js Template Migration Tool
### What is this PR for?
We have implemented the frontend API of Angular.js using the latest Angular. But the templates some [differences](https://angular.io/guide/ajs-quick-reference) between Angular.js and Angular.
So to help users migrate templates, we provide a migration tool that will be integrated into the Zeppelin web. This is its [DEMO](https://ng1-updater.hsuan.xyz/) it can quickly fix these differences.
We plan to do the following work:
1. Add a new type `%ng` (official abbreviation) to distinguish between Angular.js and Angular templates.
2. When the user runs a paragraph with the `%angular` type, the upgrade dialog will be open.
3. Upgrade the template in the dialog and click the `Update and Copy` button.
4. Automatically create a paragraph of type `%ng` template in below
### What type of PR is it?
[Feature]
### What is the Jira issue?
https://issues.apache.org/jira/browse/ZEPPELIN-4321
https://issues.apache.org/jira/browse/ZEPPELIN-4450
### How should this be tested?
* First time? Setup Travis CI as described on https://zeppelin.apache.org/contribution/contributions.html#continuous-integration
* Strongly recommended: add automated unit tests for any new or changed behavior
* Outline any manual steps to test the PR here.
### Screenshots (if appropriate)
![ng1-template](https://user-images.githubusercontent.com/22736418/69597301-78de3000-1040-11ea-85a6-830d573f1305.gif)
### Questions:
* Does the licenses files need update? NO
* Is there breaking changes for older versions? NO
* Does this needs documentation? NO
Author: Hsuan Lee <hs...@gmail.com>
Closes #3528 from hsuanxyz/angularjs-template-compatible and squashes the following commits:
3474f81c5 [Hsuan Lee] fix: fix editor focus
d639a2b13 [Hsuan Lee] fix: fix focus bar
38d0c4659 [Hsuan Lee] chore: update code editor actions
1a28a7a9f [Hsuan Lee] feat: provide Angular.js template migration tool
---
.../src/main/resources/interpreter-setting.json | 11 +
zeppelin-web-angular/package-lock.json | 18 +-
zeppelin-web-angular/package.json | 3 +
.../code-editor/code-editor.component.html | 5 +-
.../code-editor/code-editor.component.less | 6 +-
.../paragraph/code-editor/code-editor.component.ts | 10 +-
.../paragraph/control/control.component.ts | 117 ++++----
.../notebook/paragraph/paragraph.component.ts | 297 ++++++++++++---------
.../paragraph/result/result.component.html | 2 +-
.../notebook/paragraph/result/result.component.ts | 17 +-
.../app/services/ng-template-adapter.service.ts | 65 +++++
.../ng1-migration/ng1-migration.component.html | 54 ++++
.../ng1-migration/ng1-migration.component.less | 77 ++++++
.../share/ng1-migration/ng1-migration.component.ts | 174 ++++++++++++
zeppelin-web-angular/src/app/share/share.module.ts | 4 +-
15 files changed, 646 insertions(+), 214 deletions(-)
diff --git a/angular/src/main/resources/interpreter-setting.json b/angular/src/main/resources/interpreter-setting.json
index 723348d..957295f 100644
--- a/angular/src/main/resources/interpreter-setting.json
+++ b/angular/src/main/resources/interpreter-setting.json
@@ -9,5 +9,16 @@
"editOnDblClick": true,
"completionSupport": false
}
+ },
+ {
+ "group": "angular",
+ "name": "ng",
+ "className": "org.apache.zeppelin.angular.AngularInterpreter",
+ "properties": {
+ },
+ "editor": {
+ "editOnDblClick": true,
+ "completionSupport": false
+ }
}
]
diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json
index 85ad2a6..cd5fb2f 100644
--- a/zeppelin-web-angular/package-lock.json
+++ b/zeppelin-web-angular/package-lock.json
@@ -2370,6 +2370,12 @@
"integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
"dev": true
},
+ "@types/parse5": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.2.tgz",
+ "integrity": "sha512-BOl+6KDs4ItndUWUFchy3aEqGdHhw0BC4Uu+qoDonN/f0rbUnJbm71Ulj8Tt9jLFRaAxPLKvdS1bBLfx1qXR9g==",
+ "dev": true
+ },
"@types/q": {
"version": "0.0.32",
"resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz",
@@ -9967,6 +9973,11 @@
"tslib": "^1.9.0"
}
},
+ "ng1-template-updater": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/ng1-template-updater/-/ng1-template-updater-0.0.4.tgz",
+ "integrity": "sha512-GgmAV7Zbj8ZLQ/IJGjjSi40bXTHFP/k5fhlxcH0V2fWaya5lu6y07Vh4LKvuUqNbkbKl28XW8Z1fhL5pwHxgsA=="
+ },
"ngx-build-plus": {
"version": "8.1.5",
"resolved": "https://registry.npmjs.org/ngx-build-plus/-/ngx-build-plus-8.1.5.tgz",
@@ -10695,10 +10706,9 @@
"integrity": "sha1-en7A0esG+lMlx9PgCbhZoJtdSes="
},
"parse5": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
- "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
- "optional": true
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="
},
"parseqs": {
"version": "0.0.5",
diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json
index 63b6be1..9d9aa93 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -37,6 +37,8 @@
"mathjax": "2.7.5",
"monaco-editor": "^0.18.1",
"ng-zorro-antd": "^8.4.0",
+ "ng1-template-updater": "0.0.4",
+ "parse5": "^5.1.1",
"rxjs": "~6.5.3",
"systemjs": "^5.0.0",
"tslib": "^1.9.0",
@@ -56,6 +58,7 @@
"@types/lodash": "^4.14.124",
"@types/mathjax": "^0.0.35",
"@types/node": "~8.9.4",
+ "@types/parse5": "^5.0.2",
"codelyzer": "^5.0.0",
"dotenv": "^8.0.0",
"https-proxy-agent": "^2.2.1",
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html
index 4d382f2..d543e67 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html
@@ -11,6 +11,7 @@
-->
<zeppelin-code-editor [style.height.px]="height"
- [class.dirty]="dirty"
- (nzEditorInitialized)="initializedEditor($event)">
+ [class.focused]="focus"
+ [class.dirty]="dirty"
+ (nzEditorInitialized)="initializedEditor($event)">
</zeppelin-code-editor>
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less
index 72a1f68..8f61bd5 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less
@@ -18,7 +18,7 @@
.themeMixin({
- zeppelin-monaco-editor {
+ zeppelin-code-editor {
display: block;
border-left: 4px solid @border-color-split;
overflow: hidden;
@@ -26,6 +26,10 @@
&.dirty {
border-left-color: @warning-color;
}
+
+ &.focused:not(.dirty) {
+ border-left-color: @primary-color;
+ }
}
});
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
index 0711e81..916afef 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
@@ -76,16 +76,10 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
const editor = this.editor;
this.monacoDisposables.push(
editor.onDidFocusEditorText(() => {
- this.ngZone.runOutsideAngular(() => {
- this.editorFocus.emit();
- editor.updateOptions({ renderLineHighlight: 'all' });
- });
+ this.editorFocus.emit();
}),
editor.onDidBlurEditorText(() => {
this.editorBlur.emit();
- this.ngZone.runOutsideAngular(() => {
- editor.updateOptions({ renderLineHighlight: 'none' });
- });
}),
editor.onDidChangeModelContent(() => {
@@ -110,13 +104,11 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
initializedEditor(editor: IEditor) {
this.editor = editor as IStandaloneCodeEditor;
- this.paragraphControl.updateListOfMenu(monaco);
if (this.paragraphControl) {
this.paragraphControl.listOfMenu.forEach((item, index) => {
this.editor.addAction({
id: item.icon,
label: item.label,
- keybindings: item.keyBindings,
precondition: null,
keybindingContext: null,
contextMenuGroupId: 'navigation',
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts
index 5b95953..bda003d 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts
@@ -81,20 +81,66 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
disabled: boolean;
icon: string;
shortCut: string;
- keyBindings: number[];
trigger(): void;
}> = [];
- updateListOfMenu(monaco?) {
+ updateListOfMenu() {
this.listOfMenu = [
{
+ label: 'Run',
+ show: !this.first,
+ disabled: this.isEntireNoteRunning,
+ icon: 'play-circle',
+ trigger: () => this.trigger(this.runParagraph),
+ shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter'
+ },
+ {
+ label: 'Run all above',
+ show: !this.first,
+ disabled: this.isEntireNoteRunning,
+ icon: 'up-square',
+ trigger: () => this.trigger(this.runAllAbove),
+ shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter'
+ },
+ {
+ label: 'Run all below',
+ show: !this.last,
+ disabled: this.isEntireNoteRunning,
+ icon: 'down-square',
+ trigger: () => this.trigger(this.runAllBelowAndCurrent),
+ shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter'
+ },
+ {
+ label: 'Link this paragraph',
+ show: true,
+ disabled: false,
+ icon: 'export',
+ trigger: () => this.goToSingleParagraph(),
+ shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W`
+ },
+ {
+ label: 'Clear output',
+ show: true,
+ disabled: this.isEntireNoteRunning,
+ icon: 'fire',
+ trigger: () => this.clearParagraphOutput(),
+ shortCut: this.isMac ? '⌥+⌘+L' : 'Alt+Ctrl+L'
+ },
+ {
+ label: 'Remove',
+ show: this.paragraphLength > 1,
+ disabled: this.isEntireNoteRunning,
+ icon: 'delete',
+ trigger: () => this.onRemoveParagraph(),
+ shortCut: this.isMac ? '⇧+Del (Command)' : 'Shift+Del (Command)'
+ },
+ {
label: 'Move up',
show: !this.first,
disabled: this.isEntireNoteRunning,
icon: 'up',
trigger: () => this.trigger(this.moveUp),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+K`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_K] : []
+ shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+K (Command)`
},
{
label: 'Move down',
@@ -102,8 +148,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
disabled: this.isEntireNoteRunning,
icon: 'down',
trigger: () => this.trigger(this.moveDown),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+J`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_J] : []
+ shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+J (Command)`
},
{
label: 'Insert new',
@@ -111,26 +156,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
disabled: this.isEntireNoteRunning,
icon: 'plus',
trigger: () => this.trigger(this.insertNew),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+B`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_B] : []
- },
- {
- label: 'Run all above',
- show: !this.first,
- disabled: this.isEntireNoteRunning,
- icon: 'up-square',
- trigger: () => this.trigger(this.runAllAbove),
- shortCut: `Ctrl+Shift+Enter`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.Enter] : []
- },
- {
- label: 'Run all below',
- show: !this.last,
- disabled: this.isEntireNoteRunning,
- icon: 'down-square',
- trigger: () => this.trigger(this.runAllBelowAndCurrent),
- shortCut: `Ctrl+Shift+Enter`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.Enter] : []
+ shortCut: `B (Command)`
},
{
label: 'Clone paragraph',
@@ -138,8 +164,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
disabled: this.isEntireNoteRunning,
icon: 'copy',
trigger: () => this.trigger(this.cloneParagraph),
- shortCut: `Ctrl+Shift+C`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.KEY_C] : []
+ shortCut: `C (Command)`
},
{
label: this.title ? 'Hide Title' : 'Show Title',
@@ -147,8 +172,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
disabled: false,
icon: 'font-colors',
trigger: () => this.toggleTitle(),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+T`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_T] : []
+ shortCut: `T (Command)`
},
{
label: this.lineNumbers ? 'Hide line numbers' : 'Show line numbers',
@@ -156,8 +180,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
disabled: false,
icon: 'ordered-list',
trigger: () => this.toggleLineNumbers(),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+M`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_M] : []
+ shortCut: `L (Command)`
},
{
label: this.enabled ? 'Disable run' : 'Enable run',
@@ -165,35 +188,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
disabled: this.isEntireNoteRunning,
icon: 'api',
trigger: () => this.toggleEnabled(),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+R`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_R] : []
- },
- {
- label: 'Link this paragraph',
- show: true,
- disabled: false,
- icon: 'export',
- trigger: () => this.goToSingleParagraph(),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_W] : []
- },
- {
- label: 'Clear output',
- show: true,
- disabled: this.isEntireNoteRunning,
- icon: 'fire',
- trigger: () => this.clearParagraphOutput(),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+L`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_L] : []
- },
- {
- label: 'Remove',
- show: this.paragraphLength > 1,
- disabled: this.isEntireNoteRunning,
- icon: 'delete',
- trigger: () => this.onRemoveParagraph(),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+D`,
- keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_D] : []
+ shortCut: `R (Command)`
}
];
}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts
index 1dde62d..f5b61e8 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts
@@ -13,7 +13,8 @@
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
- Component, ElementRef,
+ Component,
+ ElementRef,
EventEmitter,
Input,
OnChanges,
@@ -25,8 +26,8 @@ import {
ViewChild,
ViewChildren
} from '@angular/core';
-import {merge, Observable, Subject} from 'rxjs';
-import {map, takeUntil} from 'rxjs/operators';
+import { merge, Observable, Subject } from 'rxjs';
+import { map, takeUntil } from 'rxjs/operators';
import DiffMatchPatch from 'diff-match-patch';
import { isEmpty, isEqual } from 'lodash';
@@ -60,6 +61,7 @@ import {
} from '@zeppelin/services';
import { SpellResult } from '@zeppelin/spell/spell-result';
+import { NgTemplateAdapterService } from '@zeppelin/services/ng-template-adapter.service';
import { NzResizeEvent } from 'ng-zorro-antd/resizable';
import { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component';
import { NotebookParagraphResultComponent } from './result/result.component';
@@ -71,7 +73,7 @@ type Mode = 'edit' | 'command';
templateUrl: './paragraph.component.html',
styleUrls: ['./paragraph.component.less'],
host: {
- 'tabindex': '-1',
+ tabindex: '-1',
'(focusin)': 'onFocus()'
},
changeDetection: ChangeDetectionStrategy.OnPush
@@ -210,7 +212,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
this.focusEditor();
} else {
this.blurEditor();
- (this.host.nativeElement as HTMLElement).focus();
}
}
@@ -370,21 +371,22 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
params: p.settings.params
};
});
- this.nzModalService.confirm({
- nzTitle: 'Run current and all below?',
- nzContent: 'Are you sure to run current and all below?',
- nzOnOk: () => {
- this.messageService.runAllParagraphs(this.note.id, paragraphs);
- }
- }).afterClose
- .pipe(takeUntil(this.destroy$))
+ this.nzModalService
+ .confirm({
+ nzTitle: 'Run current and all below?',
+ nzContent: 'Are you sure to run current and all below?',
+ nzOnOk: () => {
+ this.messageService.runAllParagraphs(this.note.id, paragraphs);
+ }
+ })
+ .afterClose.pipe(takeUntil(this.destroy$))
.subscribe(() => {
this.waitConfirmFromEdit = false;
});
// TODO(hsuanxyz): save cursor
}
- cloneParagraph(position: string = 'below') {
+ cloneParagraph(position: string = 'below', newText?: string) {
let newIndex = -1;
for (let i = 0; i < this.note.paragraphs.length; i++) {
if (this.note.paragraphs[i].id === this.paragraph.id) {
@@ -408,12 +410,30 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
this.messageService.copyParagraph(
newIndex,
this.paragraph.title,
- this.paragraph.text,
+ newText || this.paragraph.text,
config,
this.paragraph.settings.params
);
}
+ runParagraphAfter(text: string) {
+ this.originalText = text;
+ this.dirtyText = undefined;
+
+ if (this.paragraph.config.editorSetting.editOnDblClick) {
+ this.paragraph.config.editorHide = true;
+ this.paragraph.config.tableHide = false;
+ this.commitParagraph();
+ } else if (this.editorSetting.isOutputHidden && !this.paragraph.config.editorSetting.editOnDblClick) {
+ // %md/%angular repl make output to be hidden by default after running
+ // so should open output if repl changed from %md/%angular to another
+ this.paragraph.config.editorHide = false;
+ this.paragraph.config.tableHide = false;
+ this.commitParagraph();
+ }
+ this.editorSetting.isOutputHidden = this.paragraph.config.editorSetting.editOnDblClick;
+ }
+
runParagraph(paragraphText?: string, propagated: boolean = false) {
const text = paragraphText || this.paragraph.text;
if (text && !this.isParagraphRunning) {
@@ -421,25 +441,34 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
if (this.heliumService.getSpellByMagic(magic)) {
this.runParagraphUsingSpell(text, magic, propagated);
+ this.runParagraphAfter(text);
} else {
- this.runParagraphUsingBackendInterpreter(text);
- }
-
- this.originalText = text;
- this.dirtyText = undefined;
-
- if (this.paragraph.config.editorSetting.editOnDblClick) {
- this.paragraph.config.editorHide = true;
- this.paragraph.config.tableHide = false;
- this.commitParagraph();
- } else if (this.editorSetting.isOutputHidden && !this.paragraph.config.editorSetting.editOnDblClick) {
- // %md/%angular repl make output to be hidden by default after running
- // so should open output if repl changed from %md/%angular to another
- this.paragraph.config.editorHide = false;
- this.paragraph.config.tableHide = false;
- this.commitParagraph();
+ const check = this.ngTemplateAdapterService.preCheck(text);
+ if (!check) {
+ this.runParagraphUsingBackendInterpreter(text);
+ this.runParagraphAfter(text);
+ } else {
+ this.waitConfirmFromEdit = true;
+ this.nzModalService
+ .confirm({
+ nzTitle: 'Do you want to migrate the Angular.js template?',
+ nzContent:
+ 'The Angular.js template has been deprecated, please upgrade to Angular template.' +
+ ' (<a href="https://angular.io/guide/ajs-quick-reference" target="_blank">more info</a>)',
+ nzOnOk: () => {
+ this.switchMode('command');
+ this.ngTemplateAdapterService
+ .openMigrationDialog(check)
+ .pipe(takeUntil(this.destroy$))
+ .subscribe(newText => {
+ this.cloneParagraph('below', newText);
+ });
+ }
+ })
+ .afterClose.pipe(takeUntil(this.destroy$))
+ .subscribe(() => (this.waitConfirmFromEdit = false));
+ }
}
- this.editorSetting.isOutputHidden = this.paragraph.config.editorSetting.editOnDblClick;
}
}
@@ -693,125 +722,131 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
private cdr: ChangeDetectorRef,
private ngZService: NgZService,
private shortcutService: ShortcutService,
- private host: ElementRef
+ private host: ElementRef,
+ private ngTemplateAdapterService: NgTemplateAdapterService
) {
super(messageService);
}
ngOnInit() {
const shortcutService = this.shortcutService.forkByElement(this.host.nativeElement);
- const observables: Array<Observable<{
- action: ParagraphActions,
- event: KeyboardEvent
- }>> = [];
+ const observables: Array<
+ Observable<{
+ action: ParagraphActions;
+ event: KeyboardEvent;
+ }>
+ > = [];
Object.entries(ShortcutsMap).forEach(([action, keys]) => {
const keysArr: string[] = Array.isArray(keys) ? keys : [keys];
keysArr.forEach(key => {
observables.push(
- shortcutService.bindShortcut({
- keybindings: key
- }).pipe(
- takeUntil(this.destroy$),
- map(({event}) => {
- return {
- event,
- action: action as ParagraphActions
- }
- }))
+ shortcutService
+ .bindShortcut({
+ keybindings: key
+ })
+ .pipe(
+ takeUntil(this.destroy$),
+ map(({ event }) => {
+ return {
+ event,
+ action: action as ParagraphActions
+ };
+ })
+ )
);
});
});
merge<{
- action: ParagraphActions,
- event: KeyboardEvent
+ action: ParagraphActions;
+ event: KeyboardEvent;
}>(...observables)
.pipe(takeUntil(this.destroy$))
- .subscribe(({action, event}) => {
- if (this.mode === 'command') {
+ .subscribe(({ action, event }) => {
+ if (this.mode === 'command') {
+ switch (action) {
+ case ParagraphActions.InsertAbove:
+ this.insertParagraph('above');
+ break;
+ case ParagraphActions.InsertBelow:
+ this.insertParagraph('below');
+ break;
+ case ParagraphActions.SwitchEditorShow:
+ this.setEditorHide(!this.paragraph.config.editorHide);
+ this.commitParagraph();
+ break;
+ case ParagraphActions.SwitchOutputShow:
+ this.setTableHide(!this.paragraph.config.tableHide);
+ this.commitParagraph();
+ break;
+ case ParagraphActions.SwitchTitleShow:
+ this.paragraph.config.title = !this.paragraph.config.title;
+ this.commitParagraph();
+ break;
+ case ParagraphActions.SwitchLineNumber:
+ this.paragraph.config.lineNumbers = !this.paragraph.config.lineNumbers;
+ this.commitParagraph();
+ break;
+ case ParagraphActions.MoveToUp:
+ this.moveUpParagraph();
+ break;
+ case ParagraphActions.MoveToDown:
+ this.moveDownParagraph();
+ break;
+ case ParagraphActions.SwitchEnable:
+ this.paragraph.config.enabled = !this.paragraph.config.enabled;
+ this.commitParagraph();
+ break;
+ case ParagraphActions.ReduceWidth:
+ this.paragraph.config.colWidth = Math.max(1, this.paragraph.config.colWidth - 1);
+ this.cdr.markForCheck();
+ this.changeColWidth(true);
+ break;
+ case ParagraphActions.IncreaseWidth:
+ this.paragraph.config.colWidth = Math.min(12, this.paragraph.config.colWidth + 1);
+ this.cdr.markForCheck();
+ this.changeColWidth(true);
+ break;
+ case ParagraphActions.Delete:
+ this.removeParagraph();
+ break;
+ case ParagraphActions.SelectAbove:
+ event.preventDefault();
+ this.selectAtIndex.emit(this.index - 1);
+ break;
+ case ParagraphActions.SelectBelow:
+ event.preventDefault();
+ this.selectAtIndex.emit(this.index + 1);
+ break;
+ default:
+ break;
+ }
+ }
switch (action) {
- case ParagraphActions.InsertAbove:
- this.insertParagraph('above');
- break;
- case ParagraphActions.InsertBelow:
- this.insertParagraph('below');
- break;
- case ParagraphActions.SwitchEditorShow:
- this.setEditorHide(!this.paragraph.config.editorHide);
- this.commitParagraph();
- break;
- case ParagraphActions.SwitchOutputShow:
- this.setTableHide(!this.paragraph.config.tableHide);
- this.commitParagraph();
- break;
- case ParagraphActions.SwitchTitleShow:
- this.paragraph.config.title = !this.paragraph.config.title;
- this.commitParagraph();
- break;
- case ParagraphActions.SwitchLineNumber:
- this.paragraph.config.lineNumbers = !this.paragraph.config.lineNumbers;
- this.commitParagraph();
- break;
- case ParagraphActions.MoveToUp:
- this.moveUpParagraph();
- break;
- case ParagraphActions.MoveToDown:
- this.moveDownParagraph();
- break;
- case ParagraphActions.SwitchEnable:
- this.paragraph.config.enabled = !this.paragraph.config.enabled;
- this.commitParagraph();
- break;
- case ParagraphActions.ReduceWidth:
- this.paragraph.config.colWidth = Math.max(1, this.paragraph.config.colWidth - 1);
- this.cdr.markForCheck();
- this.changeColWidth(true);
- break;
- case ParagraphActions.IncreaseWidth:
- this.paragraph.config.colWidth = Math.min(12, this.paragraph.config.colWidth + 1);
- this.cdr.markForCheck();
- this.changeColWidth(true);
- break;
- case ParagraphActions.Delete:
- this.removeParagraph();
+ case ParagraphActions.EditMode:
+ if (this.mode === 'command') {
+ event.preventDefault();
+ }
+ if (!this.paragraph.config.editorHide) {
+ this.switchMode('edit');
+ }
break;
- case ParagraphActions.SelectAbove:
+ case ParagraphActions.Run:
event.preventDefault();
- this.selectAtIndex.emit(this.index - 1);
+ this.runParagraph();
+ break;
+ case ParagraphActions.RunBelow:
+ this.waitConfirmFromEdit = true;
+ this.runAllBelowAndCurrent();
break;
- case ParagraphActions.SelectBelow:
+ case ParagraphActions.Cancel:
event.preventDefault();
- this.selectAtIndex.emit(this.index + 1);
+ this.cancelParagraph();
break;
default:
break;
}
- }
- switch (action) {
- case ParagraphActions.EditMode:
- if (this.mode === 'command') {
- event.preventDefault();
- }
- if (!this.paragraph.config.editorHide) {
- this.switchMode('edit');
- }
- break;
- case ParagraphActions.Run:
- event.preventDefault();
- this.runParagraph();
- break;
- case ParagraphActions.RunBelow:
- this.waitConfirmFromEdit = true;
- this.runAllBelowAndCurrent();
- break;
- case ParagraphActions.Cancel:
- event.preventDefault();
- this.cancelParagraph();
- break;
- default:
- break;
- }
- });
+ });
this.setResults();
this.originalText = this.paragraph.text;
@@ -843,12 +878,16 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
ngOnChanges(changes: SimpleChanges): void {
const { index, select } = changes;
- if (index && index.currentValue !== index.previousValue && this.select
- || select && select.currentValue === true && select.previousValue !== true) {
+ if (
+ (index && index.currentValue !== index.previousValue && this.select) ||
+ (select && select.currentValue === true && select.previousValue !== true)
+ ) {
if (this.host.nativeElement) {
setTimeout(() => {
- (this.host.nativeElement as HTMLElement).focus();
- })
+ if (this.mode === 'command') {
+ (this.host.nativeElement as HTMLElement).focus();
+ }
+ });
}
}
}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
index 028c3e5..fe34a37 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
@@ -65,7 +65,7 @@
zeppelinRunScripts
[scriptsContent]="innerHTML"
[innerHTML]="innerHTML"></div>
- <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre [innerHTML]="plainText"></pre></div>
+ <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre>{{plainText}}</pre></div>
<div *ngSwitchCase="datasetType.IMG" class="img"><img [src]="imgData" alt="img"></div>
</ng-container>
<div *ngIf="angularComponent">
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
index 903f72b..742a9fb 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
@@ -16,7 +16,6 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
- ElementRef,
EventEmitter,
Injector,
Input,
@@ -81,6 +80,7 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
plainText: string | SafeHtml = '';
imgData: string | SafeUrl = '';
tableData = new TableData();
+ frontEndError: string;
// tslint:disable-next-line:no-any
visualizations: any[] = [
{
@@ -236,11 +236,16 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
}
renderAngular(): void {
- this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => {
- this.angularComponent = data;
- // this.angularComponent.moduleFactory
- this.cdr.markForCheck();
- });
+ try {
+ this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => {
+ this.angularComponent = data;
+ // this.angularComponent.moduleFactory
+ this.cdr.markForCheck();
+ });
+ } catch (e) {
+ this.frontEndError = e.message;
+ console.log(e);
+ }
}
renderText(): void {
diff --git a/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts
new file mode 100644
index 0000000..651b709
--- /dev/null
+++ b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts
@@ -0,0 +1,65 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { Ng1MigrationComponent } from '@zeppelin/share/ng1-migration/ng1-migration.component';
+import { NzModalService } from 'ng-zorro-antd';
+import { Observable } from 'rxjs';
+
+export interface NgTemplateCheckResult {
+ index: number;
+ match: string;
+ magic: string;
+ template: string;
+ origin: string;
+}
+
+@Injectable({
+ providedIn: 'root'
+})
+export class NgTemplateAdapterService {
+ constructor(private nzModalService: NzModalService) {}
+ preCheck(origin: string): NgTemplateCheckResult | null {
+ const regexp = /(%angular)([\s\S]*<[\s\S]*>)/im;
+ const math = regexp.exec(origin);
+ if (math) {
+ const index = math.index;
+ const [output, magic, template] = math;
+ return {
+ index,
+ magic,
+ template,
+ origin,
+ match: output
+ };
+ }
+ return null;
+ }
+
+ openMigrationDialog(check: NgTemplateCheckResult): Observable<string> {
+ const modalRef = this.nzModalService.create({
+ nzTitle: 'Angular.js Templates Migration Tool',
+ nzContent: Ng1MigrationComponent,
+ nzComponentParams: check,
+ nzFooter: null,
+ nzWidth: '980px',
+ nzStyle: {
+ top: '45px'
+ },
+ nzBodyStyle: {
+ padding: '0'
+ }
+ });
+
+ return modalRef.afterClose;
+ }
+}
diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html
new file mode 100644
index 0000000..34d948a
--- /dev/null
+++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html
@@ -0,0 +1,54 @@
+<div class="code-editor">
+ <zeppelin-code-editor
+ (nzEditorInitialized)="onEditorInit($event)"
+ [nzEditorOption]="{
+ language: 'html' ,
+ minimap: {
+ enabled: false
+ }
+ }">
+ </zeppelin-code-editor>
+</div>
+<div class="messages">
+
+ <div class="fix-bar">
+ <button nz-button
+ [disabled]="(messageDetails.length - errorCount) === 0"
+ class="fix-btn"
+ nzSize="small"
+ nzType="link"
+ (click)="fix()">
+ Quick Fix
+ </button>
+ <span class="log-counts">
+ <span>
+ <i nz-icon class="error" nzType="stop" nzTheme="outline"></i>
+ {{errorCount}}
+ </span>
+ <span>
+ <i nz-icon class="close" nzType="issues-close" nzTheme="outline"></i>
+ {{messageDetails.length - errorCount}}
+ </span>
+ </span>
+ </div>
+
+ <div class="message"
+ (click)="scrollToLine(item)"
+ *ngFor="let item of messageDetails">
+ <i *ngIf="item.level === 0" nz-icon class="error" nzType="stop" nzTheme="outline"></i>
+ <i *ngIf="item.level === 2" nz-icon class="close" nzType="issues-close" nzTheme="outline"></i>
+ <span class="position"> ({{(item.pos.line + 1) + ',' + (item.pos.character + 1)}})</span>
+ {{item.message}}
+ <a *ngIf="item.url" [href]="item.url" target="_blank">more</a>
+ </div>
+</div>
+
+<div *nzModalFooter>
+ <button nz-button (click)="cancel()">Cancel</button>
+ <button nz-button
+ nzType="primary"
+ [disabled]="this.messageDetails.length"
+ (click)="updateAndCopy()">
+ Update and Copy
+ </button>
+</div>
diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less
new file mode 100644
index 0000000..cb1fdc2
--- /dev/null
+++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less
@@ -0,0 +1,77 @@
+:host {
+ height: 70vh;
+ display: flex;
+
+ .code-editor {
+ flex: auto;
+ }
+
+ .messages {
+ overflow: auto;
+ position: relative;
+ width: 240px;
+ border-left: 1px solid #e8e8e8;
+
+ i {
+ &.error {
+ color: red;
+ }
+ &.close {
+ color: #1f8ffb;
+ }
+ }
+
+ .fix-bar {
+ padding-right: 16px;
+ display: flex;
+ font-size: 12px;
+ border-bottom: 1px solid #e8e8e8;
+ height: 25px;
+ line-height: 25px;
+ .fix-btn {
+ flex: 0;
+ font-size: 12px;
+ }
+ .log-counts {
+ text-align: right;
+ flex: 1 auto;
+ }
+ }
+
+
+ .message {
+ font-family: Consolas, Verdana;
+ color: #1e1e1e;
+ padding: 8px 16px 8px 5px;
+ transition: background-color 0.3s;
+ word-break: break-all;
+ line-height: 17px;
+ cursor: pointer;
+ font-size: 12px;
+ .position {
+ color: #5d5d5d;
+ }
+ &:hover {
+ background-color: #ffb86c;
+ }
+ }
+ }
+}
+
+
+::ng-deep {
+ .monaco-editor {
+ .scroll-decoration {
+ box-shadow: none;
+ }
+ .decoration-link {
+ text-decoration-color: red;
+ text-decoration-line: underline;
+ text-decoration-style: wavy;
+ text-decoration-skip-ink: none;
+ }
+ .warn-content {
+ background: rgba(182, 182, 182, .3);
+ }
+ }
+}
diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts
new file mode 100644
index 0000000..340330e
--- /dev/null
+++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts
@@ -0,0 +1,174 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core';
+import { editor, IDisposable, Range } from 'monaco-editor';
+import { NzModalRef } from 'ng-zorro-antd';
+import {
+ defaultTemplateUpdaterRules,
+ LogLevel,
+ Message,
+ MessageDetail,
+ TemplateUpdater,
+ ValueChangeRule
+} from 'ng1-template-updater';
+import { combineLatest, Subject } from 'rxjs';
+import IEditor = editor.IEditor;
+import ITextModel = editor.ITextModel;
+import IStandaloneCodeEditor = editor.IStandaloneCodeEditor;
+
+const zeppelinFunctionChangeRule: ValueChangeRule = (expression: string, start?: number) => {
+ let value = expression;
+ const messages: Message[] = [];
+ const funChanges = [
+ {
+ regexp: /z\.angularBind/gm,
+ replace: 'z.set'
+ },
+ {
+ regexp: /z\.angularUnbind/gm,
+ replace: 'z.unset'
+ },
+ {
+ regexp: /z\.runParagraph/gm,
+ replace: 'z.run'
+ }
+ ];
+
+ funChanges.forEach(change => {
+ let match = change.regexp.exec(value);
+ while (match !== null) {
+ messages.push({
+ position: start + match.index,
+ message: `${match[0]} has been deprecated, using ${change.replace} instead`,
+ length: match[0].length,
+ // url: 'https://angular.io/guide/ajs-quick-reference',
+ level: LogLevel.Info
+ });
+ match = change.regexp.exec(value);
+ }
+ value = value.replace(change.regexp, change.replace);
+ });
+
+ return {
+ messages,
+ value
+ };
+};
+
+@Component({
+ selector: 'zeppelin-ng1-migration',
+ templateUrl: './ng1-migration.component.html',
+ styleUrls: ['./ng1-migration.component.less'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Ng1MigrationComponent implements OnDestroy {
+ @Input() origin: string;
+ @Input() index: number;
+ @Input() match: string;
+ @Input() template: string;
+
+ messageDetails: MessageDetail[] = [];
+ templateUpdater: TemplateUpdater;
+ errorCount = 0;
+ decorations: string[] = [];
+ timeoutId = -1;
+ editor: IStandaloneCodeEditor;
+ editorModel: ITextModel;
+ editorInit$ = new Subject();
+ editorChangeDisposable: IDisposable;
+
+ constructor(private nzModalRef: NzModalRef, private cdr: ChangeDetectorRef) {
+ const updateRules = {
+ ...defaultTemplateUpdaterRules,
+ valueChangeRules: [...defaultTemplateUpdaterRules.valueChangeRules, zeppelinFunctionChangeRule]
+ };
+ this.templateUpdater = new TemplateUpdater(updateRules);
+ combineLatest([this.nzModalRef.afterOpen, this.editorInit$]).subscribe(() => {
+ if (this.editor) {
+ this.editorModel = this.editor.getModel() as ITextModel;
+ this.editor.setValue(this.template);
+ this.editor.layout();
+ this.bindEditorEvents();
+ this.check();
+ setTimeout(() => {
+ this.editor.focus();
+ }, 150);
+ }
+ });
+ }
+
+ onEditorInit(_editor: IEditor) {
+ this.editorInit$.next();
+ this.editorInit$.complete();
+ this.editor = _editor as IStandaloneCodeEditor;
+ }
+
+ bindEditorEvents() {
+ if (this.editorModel) {
+ this.editorChangeDisposable = this.editorModel.onDidChangeContent(() => {
+ clearTimeout(this.timeoutId);
+ this.timeoutId = setTimeout(() => {
+ this.check();
+ }, 300);
+ });
+ }
+ }
+
+ scrollToLine(failure: MessageDetail) {
+ const line = failure.pos.line + 1;
+ const character = failure.pos.character + 1;
+ const range = new Range(line, character, line, character + failure.length);
+ this.editor.revealRangeAtTop(range);
+ this.editor.setSelection(range);
+ this.editor.focus();
+ }
+
+ check() {
+ const code = this.editor.getValue();
+ const { messages } = this.templateUpdater.parse(code);
+ this.messageDetails = [...messages];
+ this.errorCount = messages.filter(f => f.level === LogLevel.Error).length;
+ this.decorations = this.editor.deltaDecorations(
+ this.decorations,
+ messages.map(failure => {
+ const line = failure.pos.line + 1;
+ const character = failure.pos.character + 1;
+ return {
+ range: new Range(line, character, line, character + failure.length),
+ options: {
+ className: failure.level === LogLevel.Error ? '' : 'warn-content',
+ inlineClassName: failure.level === LogLevel.Error ? 'decoration-link' : '',
+ stickiness: 1,
+ hoverMessage: {
+ value: failure.message + (failure.url ? ` [more](${failure.url})` : '')
+ }
+ }
+ };
+ })
+ );
+ this.cdr.markForCheck();
+ }
+
+ fix() {
+ const code = this.editor.getValue();
+ const { template } = this.templateUpdater.parse(code);
+ this.editor.setValue(template);
+ }
+
+ updateAndCopy() {
+ const code = this.editor.getValue();
+ const newTemplate = this.origin.replace(this.match, `%ng\n${code}`);
+ this.nzModalRef.close(newTemplate);
+ }
+
+ cancel() {
+ this.nzModalRef.destroy();
+ }
+
+ ngOnDestroy(): void {
+ if (this.editorChangeDisposable) {
+ this.editorChangeDisposable.dispose();
+ }
+ if (this.editorModel) {
+ this.editorModel.dispose();
+ }
+ }
+}
diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts
index ed5d191..fcb0375 100644
--- a/zeppelin-web-angular/src/app/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/share/share.module.ts
@@ -52,6 +52,7 @@ import { PageHeaderComponent } from '@zeppelin/share/page-header/page-header.com
import { HumanizeBytesPipe } from '@zeppelin/share/pipes';
import { RunScriptsDirective } from '@zeppelin/share/run-scripts/run-scripts.directive';
import { SpinComponent } from '@zeppelin/share/spin/spin.component';
+import { Ng1MigrationComponent } from './ng1-migration/ng1-migration.component';
import { ResizeHandleComponent } from './resize-handle';
const MODAL_LIST = [
@@ -59,7 +60,8 @@ const MODAL_LIST = [
NoteImportComponent,
NoteCreateComponent,
NoteRenameComponent,
- FolderRenameComponent
+ FolderRenameComponent,
+ Ng1MigrationComponent
];
const EXPORT_LIST = [HeaderComponent, NodeListComponent, PageHeaderComponent, SpinComponent, ResizeHandleComponent];
const PIPES = [HumanizeBytesPipe];