diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java index 20a90b3cc06..4d94ce69c71 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java @@ -334,6 +334,7 @@ void testAngularRunParagraph() throws Exception { // Click on 1 paragraph to trigger z.runParagraph() function + ZeppelinITUtils.sleep(1000, false); clickAndWait(By.xpath(getParagraphXPath(1) + "//div[@id=\"angularRunParagraph\"]")); waitForParagraph(2, "FINISHED"); diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/ConfigurationsRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/ConfigurationsRestApi.java index 78b8f8ef045..d907fa56110 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/ConfigurationsRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/ConfigurationsRestApi.java @@ -32,7 +32,7 @@ import org.apache.zeppelin.service.AuthenticationService; /** Configurations Rest API Endpoint. */ -@Path("/configurations") +@Path("/") @Produces("application/json") @Singleton public class ConfigurationsRestApi extends AbstractRestApi { @@ -47,7 +47,19 @@ public ConfigurationsRestApi( } @GET - @Path("all") + @Path("wsMaxMessageSize") + @ZeppelinApi + public Response getWsMaxMessageSize() { + try { + int maxMessageSize = configurationService.getWsMaxMessageSize(); + return new JsonResponse<>(Status.OK, "", maxMessageSize).build(); + } catch (Exception e) { + return new JsonResponse<>(Status.INTERNAL_SERVER_ERROR, "Fail to get max message size", e).build(); + } + } + + @GET + @Path("configurations/all") @ZeppelinApi public Response getAll() { try { @@ -60,7 +72,7 @@ public Response getAll() { } @GET - @Path("prefix/{prefix}") + @Path("configurations/prefix/{prefix}") @ZeppelinApi public Response getByPrefix(@PathParam("prefix") final String prefix) { try { diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/service/ConfigurationService.java b/zeppelin-server/src/main/java/org/apache/zeppelin/service/ConfigurationService.java index a73c0a9bb61..a3b226770d6 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/service/ConfigurationService.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/service/ConfigurationService.java @@ -43,6 +43,10 @@ public Map getAllProperties(ServiceContext context, return properties; } + public int getWsMaxMessageSize() { + return Integer.parseInt(zConf.getWebsocketMaxTextMessageSize()); + } + public Map getPropertiesWithPrefix(String prefix, ServiceContext context, ServiceCallback> callback) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts index 3322fe0a5ac..ee0b581a3e5 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts @@ -29,7 +29,14 @@ import { NzModalService } from 'ng-zorro-antd/modal'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; import { MessageReceiveDataTypeMap, Note, OP, RevisionListItem } from '@zeppelin/sdk'; -import { MessageService, NotebookService, NoteStatusService, SaveAsService, TicketService } from '@zeppelin/services'; +import { + ConfigurationService, + MessageService, + NotebookService, + NoteStatusService, + SaveAsService, + TicketService +} from '@zeppelin/services'; import { NoteCreateComponent, ShortcutComponent } from '@zeppelin/share'; @Component({ @@ -191,11 +198,12 @@ export class NotebookActionBarComponent extends MessageListenersManager implemen }); } - exportNote() { + async exportNote() { if (!this.ticketService.configuration) { throw new Error('Configuration is not loaded'); } - const sizeLimit = +this.ticketService.configuration['zeppelin.websocket.max.text.message.size']; + + const sizeLimit = await this.configurationService.fetchWsMaxMessageSize(); const jsonContent = JSON.stringify(this.note); if (jsonContent.length > sizeLimit) { this.nzModalService.confirm({ @@ -326,6 +334,7 @@ export class NotebookActionBarComponent extends MessageListenersManager implemen @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string, private nzModalService: NzModalService, private ticketService: TicketService, + private configurationService: ConfigurationService, private nzMessageService: NzMessageService, private router: Router, private cdr: ChangeDetectorRef, diff --git a/zeppelin-web-angular/src/app/services/configuration.service.ts b/zeppelin-web-angular/src/app/services/configuration.service.ts index d409083c068..b72ec50129f 100644 --- a/zeppelin-web-angular/src/app/services/configuration.service.ts +++ b/zeppelin-web-angular/src/app/services/configuration.service.ts @@ -13,6 +13,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; import { BaseRest } from './base-rest'; import { BaseUrlService } from './base-url.service'; @@ -24,7 +25,11 @@ export class ConfigurationService extends BaseRest { super(baseUrlService); } - getAll() { + fetchWsMaxMessageSize(): Promise { + return this.http.get(this.restUrl`/wsMaxMessageSize`).toPromise(); + } + + getAll(): Observable<{ [p: string]: string }> { return this.http.get<{ [key: string]: string }>(this.restUrl`/configurations/all`); } } diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.html b/zeppelin-web-angular/src/app/share/note-import/note-import.component.html index ae099ca1c9a..b7899e4b918 100644 --- a/zeppelin-web-angular/src/app/share/note-import/note-import.component.html +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.html @@ -28,7 +28,7 @@

Click or drag JSON file to this area to upload

JSON file size cannot exceed - {{ maxLimit | humanizeBytes }} + {{ wsMaxLimit | humanizeBytes }}

diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts index 05dc9e38d3e..8074ae32eec 100644 --- a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts @@ -12,9 +12,8 @@ import { HttpClient } from '@angular/common/http'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; -import { MessageService, TicketService } from '@zeppelin/services'; +import { ConfigurationService, MessageService, TicketService } from '@zeppelin/services'; -import { get } from 'lodash'; import { NzModalRef } from 'ng-zorro-antd/modal'; import { NzUploadFile } from 'ng-zorro-antd/upload'; @@ -32,7 +31,7 @@ export class NoteImportComponent extends MessageListenersManager implements OnIn importUrl?: string; errorText?: string; importLoading = false; - maxLimit = get(this.ticketService.configuration, ['zeppelin.websocket.max.text.message.size'], null); + wsMaxLimit?: number; @MessageListener(OP.IMPORT_NOTE) noteImported(_: MessageReceiveDataTypeMap[OP.IMPORT_NOTE]) { @@ -59,7 +58,7 @@ export class NoteImportComponent extends MessageListenersManager implements OnIn beforeUpload = (file: NzUploadFile): boolean => { this.errorText = ''; - if (file.size !== undefined && this.maxLimit && file.size > Number.parseInt(this.maxLimit, 10)) { + if (file.size !== undefined && this.wsMaxLimit && file.size > this.wsMaxLimit) { this.errorText = 'File size limit Exceeded!'; } else { const reader = new FileReader(); @@ -102,6 +101,7 @@ export class NoteImportComponent extends MessageListenersManager implements OnIn constructor( public messageService: MessageService, private ticketService: TicketService, + private configurationService: ConfigurationService, private cdr: ChangeDetectorRef, private nzModalRef: NzModalRef, private httpClient: HttpClient @@ -109,5 +109,7 @@ export class NoteImportComponent extends MessageListenersManager implements OnIn super(messageService); } - ngOnInit() {} + async ngOnInit() { + this.wsMaxLimit = await this.configurationService.fetchWsMaxMessageSize(); + } } diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js index 67a088cd9f1..b8e79e391d1 100644 --- a/zeppelin-web/src/app/notebook/notebook.controller.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -267,30 +267,29 @@ function NotebookCtrl($scope, $route, $routeParams, $location, $rootScope, return note && note.path ? note.path.split('/')[1] === TRASH_FOLDER_ID : false; }; - // Export notebook - let limit = 0; + $scope.exportNote = function() { + $http.get(baseUrlSrv.getRestApiBase() + '/wsMaxMessageSize').then(function(response) { + const limit = response.data.body; - websocketMsgSrv.listConfigurations(); - $scope.$on('configurationsInfo', function(scope, event) { - limit = event.configurations['zeppelin.websocket.max.text.message.size']; - }); + let jsonContent = JSON.stringify($scope.note, null, 2); - $scope.exportNote = function() { - let jsonContent = JSON.stringify($scope.note, null, 2); - if (jsonContent.length > limit) { - BootstrapDialog.confirm({ - closable: true, - title: 'Note size exceeds importable limit (' + limit + ')', - message: 'Do you still want to export this note?', - callback: function(result) { - if (result) { - saveAsService.saveAs(jsonContent, $scope.note.name + '_' + $scope.note.id, 'zpln'); - } - }, - }); - } else { - saveAsService.saveAs(jsonContent, $scope.note.name + '_' + $scope.note.id, 'zpln'); - } + if (jsonContent.length > limit) { + BootstrapDialog.confirm({ + closable: true, + title: 'Note size exceeds importable limit (' + limit + ')', + message: 'Do you still want to export this note?', + callback: function(result) { + if (result) { + saveAsService.saveAs(jsonContent, $scope.note.name + '_' + $scope.note.id, 'zpln'); + } + }, + }); + } else { + saveAsService.saveAs(jsonContent, $scope.note.name + '_' + $scope.note.id, 'zpln'); + } + }).catch(function(err) { + console.error('Error while fetching max message size', err); + }); }; // Export nbformat diff --git a/zeppelin-web/src/components/note-import/note-import.controller.js b/zeppelin-web/src/components/note-import/note-import.controller.js index fb14ac2eddf..c53efc12d45 100644 --- a/zeppelin-web/src/components/note-import/note-import.controller.js +++ b/zeppelin-web/src/components/note-import/note-import.controller.js @@ -16,7 +16,7 @@ import './note-import.css'; angular.module('zeppelinWebApp').controller('NoteImportCtrl', NoteImportCtrl); -function NoteImportCtrl($scope, $timeout, websocketMsgSrv) { +function NoteImportCtrl($scope, $timeout, websocketMsgSrv, $http, baseUrlSrv) { 'ngInject'; let vm = this; @@ -24,13 +24,6 @@ function NoteImportCtrl($scope, $timeout, websocketMsgSrv) { $scope.note.step1 = true; $scope.note.step2 = false; $scope.maxLimit = ''; - let limit = 0; - - websocketMsgSrv.listConfigurations(); - $scope.$on('configurationsInfo', function(scope, event) { - limit = event.configurations['zeppelin.websocket.max.text.message.size']; - $scope.maxLimit = Math.round(limit / 1048576); - }); vm.resetFlags = function() { $scope.note = {}; @@ -53,19 +46,29 @@ function NoteImportCtrl($scope, $timeout, websocketMsgSrv) { let file = $scope.note.importFile; let reader = new FileReader(); - if (file.size > limit) { - $scope.note.errorText = 'File size limit Exceeded!'; - $scope.$apply(); - return; - } - - reader.onloadend = function() { - vm.processImportJson(reader.result); - }; + $http.get(baseUrlSrv.getRestApiBase() + '/wsMaxMessageSize') + .then(function(response) { + const limit = response.data.body; - if (file) { - reader.readAsText(file); - } + if (file.size > limit) { + $scope.note.errorText = 'File size limit Exceeded!'; + $scope.$apply(); + return; + } + + reader.onloadend = function() { + vm.processImportJson(reader.result); + }; + + if (file) { + reader.readAsText(file); + } + }) + .catch(function(err) { + console.error('Error while fetching max message size', err); + $scope.note.errorText = 'Unable to get upload limit.'; + $scope.$apply(); + }); }; $scope.uploadURL = function() {