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:21 UTC
[zeppelin] 04/16: [ZEPPELIN-4403] Support publishable for paragraph
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 66f4dd1489ca738bdee7757ff64a6e63b348589d
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Fri Nov 29 17:16:34 2019 +0800
[ZEPPELIN-4403] Support publishable for paragraph
### What is this PR for?
A few sentences describing the overall goals of the pull request's commits.
First time? Check out the contributing guide - https://zeppelin.apache.org/contribution/contributions.html
### What type of PR is it?
[Feature]
### Todos
*
### What is the Jira issue?
https://issues.apache.org/jira/browse/ZEPPELIN-4403
### 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)
![publish](https://user-images.githubusercontent.com/22736418/69940879-4770d300-151e-11ea-9ed1-2925ce825e58.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 #3530 from hsuanxyz/paragraph-publishable and squashes the following commits:
a9b974c1d [Hsuan Lee] feat: support paragraph publishable
---
.../{public-api.ts => paragraph-base/index.ts} | 4 +-
.../src/app/core/paragraph-base/paragraph-base.ts | 315 +++++++++++++++++++++
.../app/core/{ => paragraph-base}/public-api.ts | 5 +-
.../{public-api.ts => paragraph-base/published.ts} | 8 +-
zeppelin-web-angular/src/app/core/public-api.ts | 1 +
.../workspace/notebook/notebook-routing.module.ts | 4 -
.../pages/workspace/notebook/notebook.component.ts | 13 +-
.../pages/workspace/notebook/notebook.module.ts | 14 +-
.../paragraph/code-editor/code-editor.component.ts | 14 -
.../paragraph/control/control.component.ts | 17 +-
.../notebook/paragraph/paragraph.component.html | 1 +
.../notebook/paragraph/paragraph.component.ts | 305 ++------------------
.../published/paragraph/paragraph.component.html | 15 +
.../published/paragraph/paragraph.component.less | 0
.../published/paragraph/paragraph.component.ts | 88 ++++++
.../published-ruoting.module.ts} | 17 +-
.../pages/workspace/published/published.module.ts | 11 +
.../dynamic-forms/dynamic-forms.component.html | 0
.../dynamic-forms/dynamic-forms.component.less | 0
.../dynamic-forms/dynamic-forms.component.ts | 0
.../workspace/share/index.ts} | 4 +-
.../{core => pages/workspace/share}/public-api.ts | 4 +-
.../result/result.component.html | 6 +-
.../result/result.component.less | 0
.../paragraph => share}/result/result.component.ts | 4 +
.../src/app/pages/workspace/share/share.module.ts | 56 ++++
.../pages/workspace/workspace-routing.module.ts | 4 +
.../app/pages/workspace/workspace.component.html | 4 +-
.../src/app/pages/workspace/workspace.component.ts | 11 +-
.../src/app/services/shortcut.service.ts | 37 +--
30 files changed, 581 insertions(+), 381 deletions(-)
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/paragraph-base/index.ts
similarity index 85%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/core/paragraph-base/index.ts
index c514103..49e4740 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/index.ts
@@ -10,6 +10,4 @@
* limitations under the License.
*/
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+export * from './public-api';
diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts
new file mode 100644
index 0000000..f8f9a1b
--- /dev/null
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts
@@ -0,0 +1,315 @@
+/*
+ * 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 { ChangeDetectorRef, QueryList } from '@angular/core';
+
+import {
+ AngularObjectRemove,
+ AngularObjectUpdate,
+ GraphConfig,
+ MessageReceiveDataTypeMap,
+ OP,
+ ParagraphConfig,
+ ParagraphEditorSetting,
+ ParagraphItem,
+ ParagraphIResultsMsgItem
+} from '@zeppelin/sdk';
+
+import { MessageService } from '@zeppelin/services/message.service';
+import { NgZService } from '@zeppelin/services/ng-z.service';
+import { NoteStatusService, ParagraphStatus } from '@zeppelin/services/note-status.service';
+
+import DiffMatchPatch from 'diff-match-patch';
+import { isEmpty, isEqual } from 'lodash';
+
+import { NotebookParagraphResultComponent } from '@zeppelin/pages/workspace/share/result/result.component';
+import { MessageListener, MessageListenersManager } from '../message-listener/message-listener';
+
+export abstract class ParagraphBase extends MessageListenersManager {
+ paragraph: ParagraphItem;
+ dirtyText: string;
+ originalText: string;
+ isEntireNoteRunning = false;
+ revisionView = false;
+ diffMatchPatch = new DiffMatchPatch();
+ isParagraphRunning = false;
+ results = [];
+ configs = {};
+ progress = 0;
+ colWidthOption = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ editorSetting: ParagraphEditorSetting = {};
+
+ notebookParagraphResultComponents: QueryList<NotebookParagraphResultComponent>;
+
+ constructor(
+ public messageService: MessageService,
+ protected noteStatusService: NoteStatusService,
+ protected ngZService: NgZService,
+ protected cdr: ChangeDetectorRef
+ ) {
+ super(messageService);
+ }
+
+ abstract changeColWidth(needCommit: boolean, updateResult?: boolean): void;
+
+ @MessageListener(OP.PROGRESS)
+ onProgress(data: MessageReceiveDataTypeMap[OP.PROGRESS]) {
+ if (data.id === this.paragraph.id) {
+ this.progress = data.progress;
+ this.cdr.markForCheck();
+ }
+ }
+
+ @MessageListener(OP.NOTE_RUNNING_STATUS)
+ noteRunningStatusChange(data: MessageReceiveDataTypeMap[OP.NOTE_RUNNING_STATUS]) {
+ this.isEntireNoteRunning = data.status;
+ this.cdr.markForCheck();
+ }
+
+ @MessageListener(OP.PARAS_INFO)
+ updateParaInfos(data: MessageReceiveDataTypeMap[OP.PARAS_INFO]) {
+ if (this.paragraph.id === data.id) {
+ this.paragraph.runtimeInfos = data.infos;
+ this.cdr.markForCheck();
+ }
+ }
+
+ @MessageListener(OP.EDITOR_SETTING)
+ getEditorSetting(data: MessageReceiveDataTypeMap[OP.EDITOR_SETTING]) {
+ if (this.paragraph.id === data.paragraphId) {
+ this.paragraph.config.editorSetting = { ...this.paragraph.config.editorSetting, ...data.editor };
+ this.cdr.markForCheck();
+ }
+ }
+
+ @MessageListener(OP.PARAGRAPH)
+ paragraphData(data: MessageReceiveDataTypeMap[OP.PARAGRAPH]) {
+ const oldPara = this.paragraph;
+ const newPara = data.paragraph;
+ if (this.isUpdateRequired(oldPara, newPara)) {
+ this.updateParagraph(oldPara, newPara, () => {
+ if (newPara.results && newPara.results.msg) {
+ // tslint:disable-next-line:no-for-in-array
+ for (const i in newPara.results.msg) {
+ if (newPara.results.msg[i]) {
+ const newResult = newPara.results.msg ? newPara.results.msg[i] : new ParagraphIResultsMsgItem();
+ const oldResult =
+ oldPara.results && oldPara.results.msg ? oldPara.results.msg[i] : new ParagraphIResultsMsgItem();
+ const newConfig = newPara.config.results ? newPara.config.results[i] : { graph: new GraphConfig() };
+ const oldConfig = oldPara.config.results ? oldPara.config.results[i] : { graph: new GraphConfig() };
+ if (!isEqual(newResult, oldResult) || !isEqual(newConfig, oldConfig)) {
+ const resultComponent = this.notebookParagraphResultComponents.toArray()[i];
+ if (resultComponent) {
+ resultComponent.updateResult(newConfig, newResult);
+ }
+ }
+ }
+ }
+ }
+ this.cdr.markForCheck();
+ });
+ this.cdr.markForCheck();
+ }
+ }
+
+ @MessageListener(OP.PATCH_PARAGRAPH)
+ patchParagraph(data: MessageReceiveDataTypeMap[OP.PATCH_PARAGRAPH]) {
+ if (data.paragraphId === this.paragraph.id) {
+ let patch = data.patch;
+ patch = this.diffMatchPatch.patch_fromText(patch);
+ if (!this.paragraph.text) {
+ this.paragraph.text = '';
+ }
+ this.paragraph.text = this.diffMatchPatch.patch_apply(patch, this.paragraph.text)[0];
+ this.originalText = this.paragraph.text;
+ this.cdr.markForCheck();
+ }
+ }
+
+ @MessageListener(OP.ANGULAR_OBJECT_UPDATE)
+ angularObjectUpdate(data: AngularObjectUpdate) {
+ if (data.paragraphId === this.paragraph.id) {
+ const { name, object } = data.angularObject;
+ this.ngZService.setContextValue(name, object, data.paragraphId, false);
+ }
+ }
+
+ @MessageListener(OP.ANGULAR_OBJECT_REMOVE)
+ angularObjectRemove(data: AngularObjectRemove) {
+ if (data.paragraphId === this.paragraph.id) {
+ this.ngZService.unsetContextValue(data.name, data.paragraphId, false);
+ }
+ }
+
+ updateParagraph(oldPara: ParagraphItem, newPara: ParagraphItem, updateCallback: () => void) {
+ // 1. can't update on revision view
+ if (!this.revisionView) {
+ // 2. get status, refreshed
+ const statusChanged = newPara.status !== oldPara.status;
+ const resultRefreshed =
+ newPara.dateFinished !== oldPara.dateFinished ||
+ isEmpty(newPara.results) !== isEmpty(oldPara.results) ||
+ newPara.status === ParagraphStatus.ERROR ||
+ (newPara.status === ParagraphStatus.FINISHED && statusChanged);
+
+ // 3. update texts managed by paragraph
+ this.updateAllScopeTexts(oldPara, newPara);
+ // 4. execute callback to update result
+ updateCallback();
+
+ // 5. update remaining paragraph objects
+ this.updateParagraphObjectWhenUpdated(newPara);
+
+ // 6. handle scroll down by key properly if new paragraph is added
+ if (statusChanged || resultRefreshed) {
+ // when last paragraph runs, zeppelin automatically appends new paragraph.
+ // this broadcast will focus to the newly inserted paragraph
+ // TODO(hsuanxyz)
+ }
+ this.cdr.markForCheck();
+ }
+ }
+
+ isUpdateRequired(oldPara: ParagraphItem, newPara: ParagraphItem): boolean {
+ return (
+ newPara.id === oldPara.id &&
+ (newPara.dateCreated !== oldPara.dateCreated ||
+ newPara.text !== oldPara.text ||
+ newPara.dateFinished !== oldPara.dateFinished ||
+ newPara.dateStarted !== oldPara.dateStarted ||
+ newPara.dateUpdated !== oldPara.dateUpdated ||
+ newPara.status !== oldPara.status ||
+ newPara.jobName !== oldPara.jobName ||
+ newPara.title !== oldPara.title ||
+ isEmpty(newPara.results) !== isEmpty(oldPara.results) ||
+ newPara.errorMessage !== oldPara.errorMessage ||
+ !isEqual(newPara.settings, oldPara.settings) ||
+ !isEqual(newPara.config, oldPara.config) ||
+ !isEqual(newPara.runtimeInfos, oldPara.runtimeInfos))
+ );
+ }
+
+ updateAllScopeTexts(oldPara: ParagraphItem, newPara: ParagraphItem) {
+ if (oldPara.text !== newPara.text) {
+ if (this.dirtyText) {
+ // check if editor has local update
+ if (this.dirtyText === newPara.text) {
+ // when local update is the same from remote, clear local update
+ this.paragraph.text = newPara.text;
+ this.dirtyText = undefined;
+ this.originalText = newPara.text;
+ } else {
+ // if there're local update, keep it.
+ this.paragraph.text = newPara.text;
+ }
+ } else {
+ this.paragraph.text = newPara.text;
+ this.originalText = newPara.text;
+ }
+ }
+ this.cdr.markForCheck();
+ }
+
+ updateParagraphObjectWhenUpdated(newPara: ParagraphItem) {
+ if (this.paragraph.config.colWidth !== newPara.config.colWidth) {
+ this.changeColWidth(false);
+ }
+ this.paragraph.aborted = newPara.aborted;
+ this.paragraph.user = newPara.user;
+ this.paragraph.dateUpdated = newPara.dateUpdated;
+ this.paragraph.dateCreated = newPara.dateCreated;
+ this.paragraph.dateFinished = newPara.dateFinished;
+ this.paragraph.dateStarted = newPara.dateStarted;
+ this.paragraph.errorMessage = newPara.errorMessage;
+ this.paragraph.jobName = newPara.jobName;
+ this.paragraph.title = newPara.title;
+ this.paragraph.lineNumbers = newPara.lineNumbers;
+ this.paragraph.status = newPara.status;
+ this.paragraph.fontSize = newPara.fontSize;
+ if (newPara.status !== ParagraphStatus.RUNNING) {
+ this.paragraph.results = newPara.results;
+ }
+ this.paragraph.settings = newPara.settings;
+ this.paragraph.runtimeInfos = newPara.runtimeInfos;
+ this.isParagraphRunning = this.noteStatusService.isParagraphRunning(newPara);
+ this.paragraph.config = newPara.config;
+ this.initializeDefault(this.paragraph.config);
+ this.setResults();
+ this.cdr.markForCheck();
+ }
+
+ setResults() {
+ if (this.paragraph.results) {
+ this.results = this.paragraph.results.msg;
+ this.configs = this.paragraph.config.results;
+ }
+ if (!this.paragraph.config) {
+ this.paragraph.config = {};
+ }
+ }
+
+ initializeDefault(config: ParagraphConfig) {
+ const forms = this.paragraph.settings.forms;
+
+ if (!config.colWidth) {
+ config.colWidth = 12;
+ }
+
+ if (!config.fontSize) {
+ config.fontSize = 9;
+ }
+
+ if (config.enabled === undefined) {
+ config.enabled = true;
+ }
+
+ for (const idx in forms) {
+ if (forms[idx]) {
+ if (forms[idx].options) {
+ if (config.runOnSelectionChange === undefined) {
+ config.runOnSelectionChange = true;
+ }
+ }
+ }
+ }
+
+ if (!config.results) {
+ config.results = {};
+ }
+
+ if (!config.editorSetting) {
+ config.editorSetting = {};
+ } else if (config.editorSetting.editOnDblClick) {
+ this.editorSetting.isOutputHidden = config.editorSetting.editOnDblClick;
+ }
+ }
+
+ runParagraphUsingSpell(paragraphText: string, magic: string, propagated: boolean) {
+ // TODO(hsuanxyz)
+ }
+
+ runParagraphUsingBackendInterpreter(paragraphText: string) {
+ this.messageService.runParagraph(
+ this.paragraph.id,
+ this.paragraph.title,
+ paragraphText,
+ this.paragraph.config,
+ this.paragraph.settings.params
+ );
+ }
+
+ cancelParagraph() {
+ if (!this.isEntireNoteRunning) {
+ this.messageService.cancelParagraph(this.paragraph.id);
+ }
+ }
+}
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
similarity index 85%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
index c514103..a6ba532 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
@@ -10,6 +10,5 @@
* limitations under the License.
*/
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+export * from './paragraph-base';
+export * from './published';
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/paragraph-base/published.ts
similarity index 82%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/core/paragraph-base/published.ts
index c514103..0f41577 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/published.ts
@@ -10,6 +10,8 @@
* limitations under the License.
*/
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+export const publishedSymbol = Symbol('published');
+
+export interface Published {
+ readonly [publishedSymbol]: true;
+}
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/public-api.ts
index c514103..3bcd355 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/public-api.ts
@@ -13,3 +13,4 @@
export * from './message-listener';
export * from './destroy-hook';
export * from './copy-text';
+export * from './paragraph-base';
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts
index 6c177b6..321b788 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts
@@ -21,10 +21,6 @@ const routes: Routes = [
component: NotebookComponent
},
{
- path: ':noteId/paragraph/:paragraphId',
- component: NotebookComponent
- },
- {
path: ':noteId/revision/:revisionId',
component: NotebookComponent
}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
index 97479a7..e0c17a1 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
@@ -21,7 +21,7 @@ import {
} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { isNil } from 'lodash';
-import { Subject} from 'rxjs';
+import { Subject } from 'rxjs';
import { distinctUntilKeyChanged, takeUntil } from 'rxjs/operators';
import { MessageListener, MessageListenersManager } from '@zeppelin/core';
@@ -29,6 +29,7 @@ import { Permissions } from '@zeppelin/interfaces';
import { InterpreterBindingItem, MessageReceiveDataTypeMap, Note, OP, RevisionListItem } from '@zeppelin/sdk';
import {
MessageService,
+ NgZService,
NoteStatusService,
NoteVarShareService,
SecurityService,
@@ -66,6 +67,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
if (isNil(note)) {
this.router.navigate(['/']).then();
} else {
+ this.removeParagraphFromNgZ();
this.note = note;
const { paragraphId } = this.activatedRoute.snapshot.params;
if (paragraphId) {
@@ -289,6 +291,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
private ticketService: TicketService,
private securityService: SecurityService,
private router: Router,
+ protected ngZService: NgZService
) {
super(messageService);
}
@@ -317,6 +320,14 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
this.revisionView = !!this.activatedRoute.snapshot.params.revisionId;
}
+ removeParagraphFromNgZ(): void {
+ if (this.note && Array.isArray(this.note.paragraphs)) {
+ this.note.paragraphs.forEach(p => {
+ this.ngZService.removeParagraph(p.id);
+ });
+ }
+ }
+
ngOnDestroy(): void {
super.ngOnDestroy();
this.killSaveTimer();
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
index ccdd4de..0258bbe 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
@@ -18,7 +18,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import {
NzButtonModule,
- NzCheckboxModule,
NzDividerModule,
NzDropDownModule,
NzFormModule,
@@ -35,23 +34,20 @@ import {
NzToolTipModule
} from 'ng-zorro-antd';
import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';
-import { NzResizableModule } from 'ng-zorro-antd/resizable';
import { ShareModule } from '@zeppelin/share';
-import { VisualizationModule } from 'src/app/visualizations/visualization.module';
import { NotebookAddParagraphComponent } from './add-paragraph/add-paragraph.component';
import { NotebookInterpreterBindingComponent } from './interpreter-binding/interpreter-binding.component';
import { NotebookParagraphCodeEditorComponent } from './paragraph/code-editor/code-editor.component';
import { NotebookParagraphControlComponent } from './paragraph/control/control.component';
-import { NotebookParagraphDynamicFormsComponent } from './paragraph/dynamic-forms/dynamic-forms.component';
import { NotebookParagraphFooterComponent } from './paragraph/footer/footer.component';
import { NotebookParagraphComponent } from './paragraph/paragraph.component';
import { NotebookParagraphProgressComponent } from './paragraph/progress/progress.component';
-import { NotebookParagraphResultComponent } from './paragraph/result/result.component';
import { NotebookPermissionsComponent } from './permissions/permissions.component';
import { NotebookRevisionsComparatorComponent } from './revisions-comparator/revisions-comparator.component';
+import { WorkspaceShareModule } from '../../workspace/share/share.module';
import { NotebookActionBarComponent } from './action-bar/action-bar.component';
import { NotebookRoutingModule } from './notebook-routing.module';
import { NotebookComponent } from './notebook.component';
@@ -67,18 +63,16 @@ import { NotebookShareModule } from './share/share.module';
NotebookParagraphComponent,
NotebookAddParagraphComponent,
NotebookParagraphCodeEditorComponent,
- NotebookParagraphResultComponent,
NotebookParagraphProgressComponent,
NotebookParagraphFooterComponent,
- NotebookParagraphControlComponent,
- NotebookParagraphDynamicFormsComponent
+ NotebookParagraphControlComponent
],
imports: [
CommonModule,
PortalModule,
+ WorkspaceShareModule,
NotebookRoutingModule,
ShareModule,
- VisualizationModule,
NotebookShareModule,
NzButtonModule,
NzIconModule,
@@ -92,14 +86,12 @@ import { NotebookShareModule } from './share/share.module';
FormsModule,
ReactiveFormsModule,
NzDividerModule,
- NzCheckboxModule,
NzProgressModule,
NzSwitchModule,
NzSelectModule,
NzGridModule,
NzRadioModule,
DragDropModule,
- NzResizableModule,
NzCodeEditorModule
]
})
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 916afef..8cf4bd7 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
@@ -104,20 +104,6 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
initializedEditor(editor: IEditor) {
this.editor = editor as IStandaloneCodeEditor;
- if (this.paragraphControl) {
- this.paragraphControl.listOfMenu.forEach((item, index) => {
- this.editor.addAction({
- id: item.icon,
- label: item.label,
- precondition: null,
- keybindingContext: null,
- contextMenuGroupId: 'navigation',
- contextMenuOrder: index,
- run: () => item.trigger()
- });
- });
- }
-
this.editor.addCommand(
monaco.KeyCode.Escape,
() => {
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 bda003d..eacf2da 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
@@ -72,6 +72,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
@Output() readonly runAllBelowAndCurrent = new EventEmitter<void>();
@Output() readonly cloneParagraph = new EventEmitter<void>();
@Output() readonly removeParagraph = new EventEmitter<void>();
+ @Output() readonly openSingleParagraph = new EventEmitter<string>();
fontSizeOption = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
dropdownVisible = false;
isMac = navigator.appVersion.indexOf('Mac') !== -1;
@@ -115,8 +116,10 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
show: true,
disabled: false,
icon: 'export',
- trigger: () => this.goToSingleParagraph(),
- shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W`
+ trigger: () => {
+ this.openSingleParagraph.emit(this.pid);
+ },
+ shortCut: this.isMac ? '⌥+⌘+T' : 'Alt+Ctrl+T'
},
{
label: 'Clear output',
@@ -225,13 +228,6 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
}
}
- goToSingleParagraph() {
- // TODO(hsuanxyz) asIframe
- const { noteId } = this.activatedRoute.snapshot.params;
- const redirectToUrl = `${location.protocol}//${location.host}${location.pathname}#/notebook/${noteId}/paragraph/${this.pid}`;
- window.open(redirectToUrl);
- }
-
changeColWidth(colWidth: number) {
this.colWidth = +colWidth;
this.colWidthChange.emit(this.colWidth);
@@ -269,8 +265,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
private cdr: ChangeDetectorRef,
private nzMessageService: NzMessageService,
private activatedRoute: ActivatedRoute,
- private messageService: MessageService,
- private nzModalService: NzModalService
+ private messageService: MessageService
) {}
ngOnInit() {
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html
index 1c42f87..e286627 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html
@@ -48,6 +48,7 @@
(editorHideChange)="commitParagraph()"
(enabledChange)="commitParagraph()"
(titleChange)="commitParagraph()"
+ (openSingleParagraph)="openSingleParagraph($event)"
(runOnSelectionChangeChange)="commitParagraph()"
(runParagraph)="runParagraph()"
(moveUp)="moveUpParagraph()"
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 f5b61e8..246d09e 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
@@ -29,25 +29,10 @@ import {
import { merge, Observable, Subject } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
-import DiffMatchPatch from 'diff-match-patch';
-import { isEmpty, isEqual } from 'lodash';
import { NzModalService } from 'ng-zorro-antd/modal';
-import { MessageListener, MessageListenersManager } from '@zeppelin/core';
-import {
- AngularObjectRemove,
- AngularObjectUpdate,
- GraphConfig,
- InterpreterBindingItem,
- MessageReceiveDataTypeMap,
- Note,
- OP,
- ParagraphConfig,
- ParagraphConfigResult,
- ParagraphEditorSetting,
- ParagraphItem,
- ParagraphIResultsMsgItem
-} from '@zeppelin/sdk';
+import { ParagraphBase } from '@zeppelin/core';
+import { InterpreterBindingItem, Note, ParagraphConfigResult, ParagraphItem } from '@zeppelin/sdk';
import {
HeliumService,
MessageService,
@@ -55,7 +40,6 @@ import {
NoteStatusService,
NoteVarShareService,
ParagraphActions,
- ParagraphStatus,
ShortcutsMap,
ShortcutService
} from '@zeppelin/services';
@@ -63,8 +47,8 @@ import { SpellResult } from '@zeppelin/spell/spell-result';
import { NgTemplateAdapterService } from '@zeppelin/services/ng-template-adapter.service';
import { NzResizeEvent } from 'ng-zorro-antd/resizable';
+import { NotebookParagraphResultComponent } from '../../share/result/result.component';
import { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component';
-import { NotebookParagraphResultComponent } from './result/result.component';
type Mode = 'edit' | 'command';
@@ -78,7 +62,7 @@ type Mode = 'edit' | 'command';
},
changeDetection: ChangeDetectionStrategy.OnPush
})
-export class NotebookParagraphComponent extends MessageListenersManager implements OnInit, OnChanges, OnDestroy {
+export class NotebookParagraphComponent extends ParagraphBase implements OnInit, OnChanges, OnDestroy {
@ViewChild(NotebookParagraphCodeEditorComponent, { static: false })
notebookParagraphCodeEditorComponent: NotebookParagraphCodeEditorComponent;
@ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList<
@@ -103,105 +87,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
private destroy$ = new Subject();
private mode: Mode = 'command';
waitConfirmFromEdit = false;
- dirtyText: string;
- originalText: string;
- isEntireNoteRunning = false;
- diffMatchPatch = new DiffMatchPatch();
- isParagraphRunning = false;
- results = [];
- configs = {};
- progress = 0;
- colWidthOption = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
- editorSetting: ParagraphEditorSetting = {};
-
- @MessageListener(OP.PROGRESS)
- onProgress(data: MessageReceiveDataTypeMap[OP.PROGRESS]) {
- if (data.id === this.paragraph.id) {
- this.progress = data.progress;
- this.cdr.markForCheck();
- }
- }
-
- @MessageListener(OP.NOTE_RUNNING_STATUS)
- noteRunningStatusChange(data: MessageReceiveDataTypeMap[OP.NOTE_RUNNING_STATUS]) {
- this.isEntireNoteRunning = data.status;
- this.cdr.markForCheck();
- }
-
- @MessageListener(OP.PARAS_INFO)
- updateParaInfos(data: MessageReceiveDataTypeMap[OP.PARAS_INFO]) {
- if (this.paragraph.id === data.id) {
- this.paragraph.runtimeInfos = data.infos;
- this.cdr.markForCheck();
- }
- }
-
- @MessageListener(OP.EDITOR_SETTING)
- getEditorSetting(data: MessageReceiveDataTypeMap[OP.EDITOR_SETTING]) {
- if (this.paragraph.id === data.paragraphId) {
- this.paragraph.config.editorSetting = { ...this.paragraph.config.editorSetting, ...data.editor };
- this.cdr.markForCheck();
- }
- }
-
- @MessageListener(OP.PARAGRAPH)
- paragraphData(data: MessageReceiveDataTypeMap[OP.PARAGRAPH]) {
- const oldPara = this.paragraph;
- const newPara = data.paragraph;
- if (this.isUpdateRequired(oldPara, newPara)) {
- this.updateParagraph(oldPara, newPara, () => {
- if (newPara.results && newPara.results.msg) {
- // tslint:disable-next-line:no-for-in-array
- for (const i in newPara.results.msg) {
- if (newPara.results.msg[i]) {
- const newResult = newPara.results.msg ? newPara.results.msg[i] : new ParagraphIResultsMsgItem();
- const oldResult =
- oldPara.results && oldPara.results.msg ? oldPara.results.msg[i] : new ParagraphIResultsMsgItem();
- const newConfig = newPara.config.results ? newPara.config.results[i] : { graph: new GraphConfig() };
- const oldConfig = oldPara.config.results ? oldPara.config.results[i] : { graph: new GraphConfig() };
- if (!isEqual(newResult, oldResult) || !isEqual(newConfig, oldConfig)) {
- const resultComponent = this.notebookParagraphResultComponents.toArray()[i];
- if (resultComponent) {
- resultComponent.updateResult(newConfig, newResult);
- }
- }
- }
- }
- }
- this.cdr.markForCheck();
- });
- this.cdr.markForCheck();
- }
- }
-
- @MessageListener(OP.PATCH_PARAGRAPH)
- patchParagraph(data: MessageReceiveDataTypeMap[OP.PATCH_PARAGRAPH]) {
- if (data.paragraphId === this.paragraph.id) {
- let patch = data.patch;
- patch = this.diffMatchPatch.patch_fromText(patch);
- if (!this.paragraph.text) {
- this.paragraph.text = '';
- }
- this.paragraph.text = this.diffMatchPatch.patch_apply(patch, this.paragraph.text)[0];
- this.originalText = this.paragraph.text;
- this.cdr.markForCheck();
- }
- }
-
- @MessageListener(OP.ANGULAR_OBJECT_UPDATE)
- angularObjectUpdate(data: AngularObjectUpdate) {
- if (data.paragraphId === this.paragraph.id) {
- const { name, object } = data.angularObject;
- this.ngZService.setContextValue(name, object, data.paragraphId, false);
- }
- }
-
- @MessageListener(OP.ANGULAR_OBJECT_REMOVE)
- angularObjectRemove(data: AngularObjectRemove) {
- if (data.paragraphId === this.paragraph.id) {
- this.ngZService.unsetContextValue(data.name, data.paragraphId, false);
- }
- }
switchMode(mode: Mode): void {
if (mode === this.mode) {
@@ -215,35 +100,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
}
}
- updateParagraph(oldPara: ParagraphItem, newPara: ParagraphItem, updateCallback: () => void) {
- // 1. can't update on revision view
- if (!this.revisionView) {
- // 2. get status, refreshed
- const statusChanged = newPara.status !== oldPara.status;
- const resultRefreshed =
- newPara.dateFinished !== oldPara.dateFinished ||
- isEmpty(newPara.results) !== isEmpty(oldPara.results) ||
- newPara.status === ParagraphStatus.ERROR ||
- (newPara.status === ParagraphStatus.FINISHED && statusChanged);
-
- // 3. update texts managed by paragraph
- this.updateAllScopeTexts(oldPara, newPara);
- // 4. execute callback to update result
- updateCallback();
-
- // 5. update remaining paragraph objects
- this.updateParagraphObjectWhenUpdated(newPara);
-
- // 6. handle scroll down by key properly if new paragraph is added
- if (statusChanged || resultRefreshed) {
- // when last paragraph runs, zeppelin automatically appends new paragraph.
- // this broadcast will focus to the newly inserted paragraph
- // TODO(hsuanxyz)
- }
- this.cdr.markForCheck();
- }
- }
-
textChanged(text: string) {
this.dirtyText = text;
this.paragraph.text = text;
@@ -472,94 +328,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
}
}
- runParagraphUsingSpell(paragraphText: string, magic: string, propagated: boolean) {
- // TODO(hsuanxyz)
- }
-
- runParagraphUsingBackendInterpreter(paragraphText: string) {
- this.messageService.runParagraph(
- this.paragraph.id,
- this.paragraph.title,
- paragraphText,
- this.paragraph.config,
- this.paragraph.settings.params
- );
- }
-
- cancelParagraph() {
- if (!this.isEntireNoteRunning) {
- this.messageService.cancelParagraph(this.paragraph.id);
- }
- }
-
- updateAllScopeTexts(oldPara: ParagraphItem, newPara: ParagraphItem) {
- if (oldPara.text !== newPara.text) {
- if (this.dirtyText) {
- // check if editor has local update
- if (this.dirtyText === newPara.text) {
- // when local update is the same from remote, clear local update
- this.paragraph.text = newPara.text;
- this.dirtyText = undefined;
- this.originalText = newPara.text;
- } else {
- // if there're local update, keep it.
- this.paragraph.text = newPara.text;
- }
- } else {
- this.paragraph.text = newPara.text;
- this.originalText = newPara.text;
- }
- }
- this.cdr.markForCheck();
- }
-
- updateParagraphObjectWhenUpdated(newPara: ParagraphItem) {
- if (this.paragraph.config.colWidth !== newPara.config.colWidth) {
- this.changeColWidth(false);
- }
- this.paragraph.aborted = newPara.aborted;
- this.paragraph.user = newPara.user;
- this.paragraph.dateUpdated = newPara.dateUpdated;
- this.paragraph.dateCreated = newPara.dateCreated;
- this.paragraph.dateFinished = newPara.dateFinished;
- this.paragraph.dateStarted = newPara.dateStarted;
- this.paragraph.errorMessage = newPara.errorMessage;
- this.paragraph.jobName = newPara.jobName;
- this.paragraph.title = newPara.title;
- this.paragraph.lineNumbers = newPara.lineNumbers;
- this.paragraph.status = newPara.status;
- this.paragraph.fontSize = newPara.fontSize;
- if (newPara.status !== ParagraphStatus.RUNNING) {
- this.paragraph.results = newPara.results;
- }
- this.paragraph.settings = newPara.settings;
- this.paragraph.runtimeInfos = newPara.runtimeInfos;
- this.isParagraphRunning = this.noteStatusService.isParagraphRunning(newPara);
- this.paragraph.config = newPara.config;
- this.initializeDefault(this.paragraph.config);
- this.setResults();
- this.cdr.markForCheck();
- }
-
- isUpdateRequired(oldPara: ParagraphItem, newPara: ParagraphItem): boolean {
- return (
- newPara.id === oldPara.id &&
- (newPara.dateCreated !== oldPara.dateCreated ||
- newPara.text !== oldPara.text ||
- newPara.dateFinished !== oldPara.dateFinished ||
- newPara.dateStarted !== oldPara.dateStarted ||
- newPara.dateUpdated !== oldPara.dateUpdated ||
- newPara.status !== oldPara.status ||
- newPara.jobName !== oldPara.jobName ||
- newPara.title !== oldPara.title ||
- isEmpty(newPara.results) !== isEmpty(oldPara.results) ||
- newPara.errorMessage !== oldPara.errorMessage ||
- !isEqual(newPara.settings, oldPara.settings) ||
- !isEqual(newPara.config, oldPara.config) ||
- !isEqual(newPara.runtimeInfos, oldPara.runtimeInfos))
- );
- }
-
insertParagraph(position: string) {
if (this.revisionView === true) {
return;
@@ -584,16 +352,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
this.cdr.markForCheck();
}
- setResults() {
- if (this.paragraph.results) {
- this.results = this.paragraph.results.msg;
- this.configs = this.paragraph.config.results;
- }
- if (!this.paragraph.config) {
- this.paragraph.config = {};
- }
- }
-
setTitle(title: string) {
this.paragraph.title = title;
this.commitParagraph();
@@ -611,42 +369,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
this.cdr.markForCheck();
}
- initializeDefault(config: ParagraphConfig) {
- const forms = this.paragraph.settings.forms;
-
- if (!config.colWidth) {
- config.colWidth = 12;
- }
-
- if (!config.fontSize) {
- config.fontSize = 9;
- }
-
- if (config.enabled === undefined) {
- config.enabled = true;
- }
-
- for (const idx in forms) {
- if (forms[idx]) {
- if (forms[idx].options) {
- if (config.runOnSelectionChange === undefined) {
- config.runOnSelectionChange = true;
- }
- }
- }
- }
-
- if (!config.results) {
- config.results = {};
- }
-
- if (!config.editorSetting) {
- config.editorSetting = {};
- } else if (config.editorSetting.editOnDblClick) {
- this.editorSetting.isOutputHidden = config.editorSetting.editOnDblClick;
- }
- }
-
moveUpParagraph() {
const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) - 1;
if (newIndex < 0 || newIndex >= this.note.paragraphs.length) {
@@ -709,23 +431,29 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
this.cdr.markForCheck();
}
+ openSingleParagraph(paragraphId: string): void {
+ const noteId = this.note.id;
+ const redirectToUrl = `${location.protocol}//${location.host}${location.pathname}#/notebook/${noteId}/paragraph/${paragraphId}`;
+ window.open(redirectToUrl);
+ }
+
trackByIndexFn(index: number) {
return index;
}
constructor(
+ noteStatusService: NoteStatusService,
+ cdr: ChangeDetectorRef,
+ ngZService: NgZService,
private heliumService: HeliumService,
- private noteStatusService: NoteStatusService,
public messageService: MessageService,
private nzModalService: NzModalService,
private noteVarShareService: NoteVarShareService,
- private cdr: ChangeDetectorRef,
- private ngZService: NgZService,
private shortcutService: ShortcutService,
private host: ElementRef,
private ngTemplateAdapterService: NgTemplateAdapterService
) {
- super(messageService);
+ super(messageService, noteStatusService, ngZService, cdr);
}
ngOnInit() {
@@ -823,6 +551,9 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
}
}
switch (action) {
+ case ParagraphActions.Link:
+ this.openSingleParagraph(this.paragraph.id);
+ break;
case ParagraphActions.EditMode:
if (this.mode === 'command') {
event.preventDefault();
@@ -847,7 +578,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
break;
}
});
-
this.setResults();
this.originalText = this.paragraph.text;
this.isEntireNoteRunning = this.noteStatusService.isEntireNoteRunning(this.note);
@@ -894,6 +624,5 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
ngOnDestroy(): void {
super.ngOnDestroy();
- this.ngZService.removeParagraph(this.paragraph.id);
}
}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html
new file mode 100644
index 0000000..d69a0f4
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html
@@ -0,0 +1,15 @@
+<zeppelin-notebook-paragraph-dynamic-forms
+ *ngIf="paragraph"
+ [disable]="paragraph.status == 'RUNNING' || paragraph.status == 'PENDING'"
+ [paramDefs]="paragraph.settings.params"
+ [formDefs]="paragraph.settings.forms"
+ [runOnChange]="paragraph.config.runOnSelectionChange"
+ (formChange)="runParagraph()">
+</zeppelin-notebook-paragraph-dynamic-forms>
+<zeppelin-notebook-paragraph-result *ngFor="let result of results; index as i; trackBy: trackByIndexFn"
+ [id]="paragraph.id"
+ [published]="true"
+ [currentCol]="paragraph.config.colWidth"
+ [config]="configs[i]"
+ [result]="result">
+</zeppelin-notebook-paragraph-result>
diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less
new file mode 100644
index 0000000..e69de29
diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts
new file mode 100644
index 0000000..12e10de
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts
@@ -0,0 +1,88 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, QueryList, ViewChildren } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { MessageListener, ParagraphBase } from '@zeppelin/core';
+import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published';
+import { NotebookParagraphResultComponent } from '@zeppelin/pages/workspace/share/result/result.component';
+import { MessageReceiveDataTypeMap, Note, OP } from '@zeppelin/sdk';
+import { HeliumService, MessageService, NgZService, NoteStatusService } from '@zeppelin/services';
+import { SpellResult } from '@zeppelin/spell/spell-result';
+import { isNil } from 'lodash';
+
+@Component({
+ selector: 'zeppelin-publish-paragraph',
+ templateUrl: './paragraph.component.html',
+ styleUrls: ['./paragraph.component.less'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class PublishedParagraphComponent extends ParagraphBase implements Published, OnInit {
+ readonly [publishedSymbol] = true;
+
+ noteId: string;
+ paragraphId: string;
+
+ @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList<
+ NotebookParagraphResultComponent
+ >;
+
+ constructor(
+ public messageService: MessageService,
+ noteStatusService: NoteStatusService,
+ ngZService: NgZService,
+ cdr: ChangeDetectorRef,
+ private activatedRoute: ActivatedRoute,
+ private heliumService: HeliumService
+ ) {
+ super(messageService, noteStatusService, ngZService, cdr);
+ this.activatedRoute.params.subscribe(params => {
+ this.noteId = params.noteId;
+ this.paragraphId = params.paragraphId;
+ this.messageService.getNote(this.noteId);
+ });
+ }
+
+ ngOnInit() {}
+
+ @MessageListener(OP.NOTE)
+ getNote(data: MessageReceiveDataTypeMap[OP.NOTE]) {
+ const note = data.note;
+ if (!isNil(note)) {
+ this.paragraph = (note as Note['note']).paragraphs.find(p => p.id === this.paragraphId);
+ if (this.paragraph) {
+ this.setResults();
+ this.originalText = this.paragraph.text;
+ this.initializeDefault(this.paragraph.config);
+ }
+ }
+ this.cdr.markForCheck();
+ }
+
+ trackByIndexFn(index: number) {
+ return index;
+ }
+
+ setResults() {
+ if (this.paragraph.results) {
+ this.results = this.paragraph.results.msg;
+ this.configs = this.paragraph.config.results;
+ }
+ if (!this.paragraph.config) {
+ this.paragraph.config = {};
+ }
+ }
+
+ changeColWidth(needCommit: boolean, updateResult?: boolean): void {
+ // noop
+ }
+
+ runParagraph(): void {
+ const text = this.paragraph.text;
+ if (text && !this.isParagraphRunning) {
+ const magic = SpellResult.extractMagic(this.paragraph.text);
+ if (this.heliumService.getSpellByMagic(magic)) {
+ this.runParagraphUsingSpell(text, magic, false);
+ } else {
+ this.runParagraphUsingBackendInterpreter(text);
+ }
+ }
+ }
+}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts
similarity index 70%
copy from zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts
copy to zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts
index 6c177b6..eaf001f 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts
@@ -12,21 +12,12 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
-
-import { NotebookComponent } from './notebook.component';
+import { PublishedParagraphComponent } from './paragraph/paragraph.component';
const routes: Routes = [
{
- path: ':noteId',
- component: NotebookComponent
- },
- {
- path: ':noteId/paragraph/:paragraphId',
- component: NotebookComponent
- },
- {
- path: ':noteId/revision/:revisionId',
- component: NotebookComponent
+ path: ':paragraphId',
+ component: PublishedParagraphComponent
}
];
@@ -34,4 +25,4 @@ const routes: Routes = [
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
-export class NotebookRoutingModule {}
+export class PublishedRoutingModule {}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts b/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts
new file mode 100644
index 0000000..f6474d9
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts
@@ -0,0 +1,11 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { WorkspaceShareModule } from '../../workspace/share/share.module';
+import { PublishedParagraphComponent } from './paragraph/paragraph.component';
+import { PublishedRoutingModule } from './published-ruoting.module';
+
+@NgModule({
+ declarations: [PublishedParagraphComponent],
+ imports: [CommonModule, WorkspaceShareModule, PublishedRoutingModule]
+})
+export class PublishedModule {}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html
similarity index 100%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html
rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less
similarity index 100%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less
rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts
similarity index 100%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts
rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/share/index.ts
similarity index 85%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/share/index.ts
index c514103..49e4740 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/index.ts
@@ -10,6 +10,4 @@
* limitations under the License.
*/
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+export * from './public-api';
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts
similarity index 85%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts
index c514103..e865360 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts
@@ -10,6 +10,4 @@
* limitations under the License.
*/
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+export * from './share.module';
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html
similarity index 95%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html
index fe34a37..0b246b0 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html
@@ -10,7 +10,7 @@
~ limitations under the License.
-->
-<div class="setting-bar" *ngIf="result.type === datasetType.TABLE">
+<div class="setting-bar" *ngIf="result.type === datasetType.TABLE && !published">
<div class="visualization-selector">
<nz-radio-group [(ngModel)]="config?.graph.mode" (ngModelChange)="switchMode($event)" nzButtonStyle="solid">
<label *ngFor="let item of visualizations"
@@ -54,7 +54,7 @@
[nzGridColumnCount]="12"
[nzMinColumn]="1"
nzBounds="window">
- <nz-resize-handle nzDirection="bottomRight">
+ <nz-resize-handle nzDirection="bottomRight" *ngIf="!published">
<zeppelin-resize-handle></zeppelin-resize-handle>
</nz-resize-handle>
<ng-template cdkPortalOutlet></ng-template>
@@ -65,7 +65,7 @@
zeppelinRunScripts
[scriptsContent]="innerHTML"
[innerHTML]="innerHTML"></div>
- <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre>{{plainText}}</pre></div>
+ <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre [innerHTML]="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.less b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less
similarity index 100%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less
rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
similarity index 99%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
index 742a9fb..86d94cc 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
@@ -68,6 +68,7 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
@Input() result: ParagraphIResultsMsgItem;
@Input() config: ParagraphConfigResult;
@Input() id: string;
+ @Input() published = false;
@Input() currentCol = 12;
@Output() readonly configChange = new EventEmitter<ParagraphConfigResult>();
@Output() readonly sizeChange = new EventEmitter<NzResizeEvent>();
@@ -223,6 +224,9 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
break;
}
this.cdr.markForCheck();
+ if (this.published) {
+ this.cdr.detectChanges();
+ }
}
renderHTML(): void {
diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
new file mode 100644
index 0000000..4c7ef1d
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
@@ -0,0 +1,56 @@
+/*
+ * 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 { PortalModule } from '@angular/cdk/portal';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+
+import {
+ NzButtonModule,
+ NzCheckboxModule,
+ NzDropDownModule,
+ NzIconModule,
+ NzRadioModule,
+ NzSelectModule,
+ NzSwitchModule,
+ NzToolTipModule
+} from 'ng-zorro-antd';
+import { NzResizableModule } from 'ng-zorro-antd/resizable';
+
+import { ShareModule } from '@zeppelin/share';
+import { VisualizationModule } from '@zeppelin/visualizations/visualization.module';
+
+import { NotebookParagraphDynamicFormsComponent } from './dynamic-forms/dynamic-forms.component';
+import { NotebookParagraphResultComponent } from './result/result.component';
+
+@NgModule({
+ exports: [NotebookParagraphResultComponent, NotebookParagraphDynamicFormsComponent],
+ declarations: [NotebookParagraphResultComponent, NotebookParagraphDynamicFormsComponent],
+ imports: [
+ CommonModule,
+ ShareModule,
+ PortalModule,
+ VisualizationModule,
+ FormsModule,
+ NzButtonModule,
+ NzDropDownModule,
+ NzRadioModule,
+ NzResizableModule,
+ NzToolTipModule,
+ NzIconModule,
+ NzCheckboxModule,
+ NzSelectModule,
+ NzSwitchModule
+ ]
+})
+export class WorkspaceShareModule {}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
index 0340a8d..9315443 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
@@ -31,6 +31,10 @@ const routes: Routes = [
loadChildren: () => import('@zeppelin/pages/workspace/notebook/notebook.module').then(m => m.NotebookModule)
},
{
+ path: 'notebook/:noteId/paragraph',
+ loadChildren: () => import('@zeppelin/pages/workspace/published/published.module').then(m => m.PublishedModule)
+ },
+ {
path: 'jobmanager',
loadChildren: () =>
import('@zeppelin/pages/workspace/job-manager/job-manager.module').then(m => m.JobManagerModule)
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
index 6bcae47..c41cf78 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
@@ -11,7 +11,7 @@
-->
<div class="content" [class.blur]="!websocketConnected">
- <zeppelin-header></zeppelin-header>
- <router-outlet></router-outlet>
+ <zeppelin-header *ngIf="!publishMode"></zeppelin-header>
+ <router-outlet (activate)="onActivate($event)"></router-outlet>
</div>
<zeppelin-spin *ngIf="!websocketConnected" [transparent]="true">Connecting WebSocket ...</zeppelin-spin>
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
index 03c5b9b..c89d287e 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
@@ -12,10 +12,13 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
-import { takeUntil } from 'rxjs/operators';
+import { filter, map, startWith, takeUntil, tap } from 'rxjs/operators';
+import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router';
+import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published';
import { HeliumManagerService } from '@zeppelin/helium-manager';
import { MessageService } from '@zeppelin/services';
+import { log } from 'ng-zorro-antd';
@Component({
selector: 'zeppelin-workspace',
@@ -26,6 +29,7 @@ import { MessageService } from '@zeppelin/services';
export class WorkspaceComponent implements OnInit, OnDestroy {
private destroy$ = new Subject();
websocketConnected = false;
+ publishMode = false;
constructor(
public messageService: MessageService,
@@ -33,6 +37,11 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
private heliumManagerService: HeliumManagerService
) {}
+ onActivate(e) {
+ this.publishMode = e && e[publishedSymbol];
+ this.cdr.markForCheck();
+ }
+
ngOnInit() {
this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(data => {
this.websocketConnected = data;
diff --git a/zeppelin-web-angular/src/app/services/shortcut.service.ts b/zeppelin-web-angular/src/app/services/shortcut.service.ts
index b6d6a3a..4b2a626 100644
--- a/zeppelin-web-angular/src/app/services/shortcut.service.ts
+++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts
@@ -1,7 +1,7 @@
-import {DOCUMENT} from "@angular/common";
-import {Inject, Injectable} from '@angular/core';
-import {EventManager} from "@angular/platform-browser";
-import {Observable} from "rxjs";
+import { DOCUMENT } from '@angular/common';
+import { Inject, Injectable } from '@angular/core';
+import { EventManager } from '@angular/platform-browser';
+import { Observable } from 'rxjs';
export enum ParagraphActions {
EditMode = 'Paragraph:EditMode',
@@ -23,7 +23,8 @@ export enum ParagraphActions {
SwitchTitleShow = 'Paragraph:SwitchTitleShow',
SwitchOutputShow = 'Paragraph:SwitchOutputShow',
SwitchEditorShow = 'Paragraph:SwitchEditorShow',
- SwitchEnable = 'Paragraph:SwitchEnable'
+ SwitchEnable = 'Paragraph:SwitchEnable',
+ Link = 'Paragraph:Link'
}
export const ShortcutsMap = {
@@ -34,6 +35,8 @@ export const ShortcutsMap = {
[ParagraphActions.Cancel]: 'shift.ctrlCmd.c',
// Need register special character `¬` in MacOS
[ParagraphActions.Clear]: ['alt.ctrlCmd.l', 'alt.ctrlCmd.¬'],
+ // Need register special character `†` in MacOS
+ [ParagraphActions.Link]: ['alt.ctrlCmd.t', 'alt.ctrlCmd.†'],
// Need register special character `®` in MacOS
[ParagraphActions.SwitchEnable]: ['alt.ctrlCmd.r', 'alt.ctrlCmd.®'],
// Need register special character `–` in MacOS
@@ -54,28 +57,27 @@ export const ShortcutsMap = {
};
export interface ShortcutEvent {
- event: KeyboardEvent
+ event: KeyboardEvent;
keybindings: string;
}
export interface ShortcutOption {
- scope?: HTMLElement,
- keybindings: string
+ scope?: HTMLElement;
+ keybindings: string;
}
function isMacOS() {
- return navigator.platform.indexOf('Mac') > -1
+ return navigator.platform.indexOf('Mac') > -1;
}
@Injectable({
providedIn: 'root'
})
export class ShortcutService {
-
private element: HTMLElement;
- constructor(private eventManager: EventManager,
- @Inject(DOCUMENT) _document: any) {
+ // tslint:disable-next-line:no-any
+ constructor(private eventManager: EventManager, @Inject(DOCUMENT) _document: any) {
this.element = _document;
}
@@ -86,9 +88,9 @@ export class ShortcutService {
bindShortcut(option: ShortcutOption): Observable<ShortcutEvent> {
const host = option.scope || this.element;
// `ctrlCmd` is special symbol, will be replaced `meta` in MacOS, 'control' in Windows/Linux
- const keybindings = option.keybindings
- .replace(/ctrlCmd/g, isMacOS() ? 'meta' : 'control');
- const event = `keydown.${keybindings}`;
+ const keybindings = option.keybindings.replace(/ctrlCmd/g, isMacOS() ? 'meta' : 'control');
+ const eventName = `keydown.${keybindings}`;
+ // tslint:disable-next-line:ban-types
let dispose: Function;
return new Observable<ShortcutEvent>(observer => {
const handler = event => {
@@ -98,12 +100,11 @@ export class ShortcutService {
});
};
- dispose = this.eventManager.addEventListener(host, event, handler);
+ dispose = this.eventManager.addEventListener(host, eventName, handler);
return () => {
dispose();
};
- })
+ });
}
-
}