This is an automated email from the ASF dual-hosted git repository. pdallig pushed a commit to branch branch-0.12 in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/branch-0.12 by this push: new aed246d630 [ZEPPELIN-6283] Decouple 'isRevisionSupported' state from configuration API response aed246d630 is described below commit aed246d630c3eeec149e598d379dc40041de6a99 Author: SeungYoung Oh <seung...@naver.com> AuthorDate: Wed Aug 20 15:38:48 2025 +0900 [ZEPPELIN-6283] Decouple 'isRevisionSupported' state from configuration API response ### What is this PR for? This PR separates the `isRevisionSupported` field from the configuration API into a dedicated endpoint. No internal logic is changed. * `isRevisionSupported` seems to be more related to Notebook logic rather than configuration. It is included in the WebSocket configuration response, making the code more complex and less extensible. * For example, the REST configuration response doesn’t have `isRevisionSupported`. Adding it would require injecting a Notebook instance into ConfigurationsRestApi, which doesn’t seem related to configurations. It feels like a code smell. * On the client, it was previously fetched globally. Now it is fetched in the Notebook page. There seems to be no need to use it as a global state. ### What type of PR is it? Refactoring ### Todos ### What is the Jira issue? - [ZEPPELIN-6283](https://issues.apache.org/jira/browse/ZEPPELIN-6283) ### How should this be tested? * Run `NotebookTest.testRevisionSupported()` * Verify on both New UI and Old UI ### Questions: * Does the license files need to update? N * Is there breaking changes for older versions? N * Does this needs documentation? N Closes #5030 from seung-00/feature/ZEPPELIN-6283. Signed-off-by: Philipp Dallig <philipp.dal...@gmail.com> (cherry picked from commit 6dd03ab5bd07f192f7ec6381c651add65eb17a1f) Signed-off-by: Philipp Dallig <philipp.dal...@gmail.com> --- .../org/apache/zeppelin/rest/NotebookRestApi.java | 12 ++++++++++++ .../org/apache/zeppelin/socket/NotebookServer.java | 1 - .../src/interfaces/message-common.interface.ts | 1 - .../interfaces/{notebook-search.ts => notebook.ts} | 4 ++++ zeppelin-web-angular/src/app/interfaces/public-api.ts | 2 +- .../notebook-search/notebook-search.component.ts | 8 ++++---- .../notebook/action-bar/action-bar.component.ts | 19 ++++++++++++++----- ...notebook-search.service.ts => notebook.service.ts} | 10 +++++++--- .../src/app/share/header/header.component.ts | 6 +++--- .../notebook-repository.controller.js | 1 - zeppelin-web/src/app/notebook/notebook-actionBar.html | 2 +- zeppelin-web/src/app/notebook/notebook.controller.js | 17 +++++++++++++++++ .../src/components/navbar/navbar.controller.js | 12 ------------ .../java/org/apache/zeppelin/notebook/Notebook.java | 2 +- 14 files changed, 64 insertions(+), 33 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java index 5d997268f4..db5275f76f 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java @@ -221,6 +221,18 @@ public class NotebookRestApi extends AbstractRestApi { } } + /** + * Get notebook capabilities. + */ + @GET + @Path("capabilities") + @ZeppelinApi + public Response getNotebookCapabilities() { + Map<String, Object> capabilities = Map.of("isRevisionSupported", notebook.isRevisionSupported()); + + return new JsonResponse<>(Status.OK, "", capabilities).build(); + } + /** * Set note authorization information. */ diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 03637fbd2c..fabdd8eea6 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -1561,7 +1561,6 @@ public class NotebookServer implements AngularObjectRegistryListener, @Override public void onSuccess(Map<String, String> properties, ServiceContext context) throws IOException { super.onSuccess(properties, context); - properties.put("isRevisionSupported", String.valueOf(getNotebook().isRevisionSupported())); conn.send(serializeMessage(new Message(OP.CONFIGURATIONS_INFO).put("configurations", properties))); } }); diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts index 82cb8e9d3c..b8011826f3 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts @@ -57,7 +57,6 @@ export interface ConfigurationsInfo { 'zeppelin.websocket.max.text.message.size': string; 'zeppelin.notebook.git.remote.origin': string; 'zeppelin.server.authorization.header.clear': string; - isRevisionSupported: string; 'zeppelin.interpreter.dep.mvnRepo': string; 'zeppelin.ssl': string; 'zeppelin.notebook.autoInterpreterBinding': string; diff --git a/zeppelin-web-angular/src/app/interfaces/notebook-search.ts b/zeppelin-web-angular/src/app/interfaces/notebook.ts similarity index 90% rename from zeppelin-web-angular/src/app/interfaces/notebook-search.ts rename to zeppelin-web-angular/src/app/interfaces/notebook.ts index 267ee943a5..c6c591524b 100644 --- a/zeppelin-web-angular/src/app/interfaces/notebook-search.ts +++ b/zeppelin-web-angular/src/app/interfaces/notebook.ts @@ -17,3 +17,7 @@ export interface NotebookSearchResultItem { text: string; header: string; } + +export interface NotebookCapabilities { + isRevisionSupported: boolean; +} diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/interfaces/public-api.ts index e762a5c366..7e15c29918 100644 --- a/zeppelin-web-angular/src/app/interfaces/public-api.ts +++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts @@ -17,4 +17,4 @@ export * from './message-interceptor'; export * from './security'; export * from './credential'; export * from './notebook-repo'; -export * from './notebook-search'; +export * from './notebook'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts index de02a290bf..1269a5bcd4 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts @@ -13,7 +13,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { NotebookSearchResultItem } from '@zeppelin/interfaces'; -import { NotebookSearchService } from '@zeppelin/services/notebook-search.service'; +import { NotebookService } from '@zeppelin/services/notebook.service'; import { Subject } from 'rxjs'; import { filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; @@ -33,7 +33,7 @@ export class NotebookSearchComponent implements OnInit, OnDestroy { this.searching = true; this.searchTerm = queryStr; }), - switchMap(queryStr => this.notebookSearchService.search(queryStr)) + switchMap(queryStr => this.notebookService.search(queryStr)) ); results: NotebookSearchResultItem[] = []; @@ -47,7 +47,7 @@ export class NotebookSearchComponent implements OnInit, OnDestroy { constructor( private cdr: ChangeDetectorRef, private router: ActivatedRoute, - private notebookSearchService: NotebookSearchService + private notebookService: NotebookService ) {} ngOnInit() { @@ -59,7 +59,7 @@ export class NotebookSearchComponent implements OnInit, OnDestroy { } ngOnDestroy(): void { - this.notebookSearchService.clear(); + this.notebookService.clearQuery(); this.destroy$.next(); this.destroy$.complete(); } 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 1c73730cc7..a4da1c22e2 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 @@ -17,6 +17,7 @@ import { EventEmitter, Inject, Input, + OnInit, Output } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; @@ -26,8 +27,9 @@ 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, NoteActionService, NoteStatusService, SaveAsService, TicketService } from '@zeppelin/services'; +import { MessageService, NoteStatusService, SaveAsService, TicketService } from '@zeppelin/services'; +import { NotebookService } from '@zeppelin/services/notebook.service'; import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.component'; @Component({ @@ -36,7 +38,7 @@ import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.com styleUrls: ['./action-bar.component.less'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class NotebookActionBarComponent extends MessageListenersManager { +export class NotebookActionBarComponent extends MessageListenersManager implements OnInit { @Input() note!: Exclude<Note['note'], undefined>; @Input() isOwner = true; @Input() looknfeel: 'report' | 'default' | 'simple' = 'default'; @@ -52,12 +54,12 @@ export class NotebookActionBarComponent extends MessageListenersManager { @Output() readonly editorHideChange = new EventEmitter<boolean>(); @Output() readonly tableHideChange = new EventEmitter<boolean>(); lfOption: Array<'report' | 'default' | 'simple'> = ['default', 'simple', 'report']; + isRevisionSupported: boolean = false; isNoteParagraphRunning = false; principal = this.ticketService.ticket.principal; editorHide = false; commitVisible = false; tableHide = false; - isRevisionSupported: boolean; cronOption = [ { name: 'None', value: undefined }, { name: '1m', value: '0 0/1 * * * ?' }, @@ -68,6 +70,7 @@ export class NotebookActionBarComponent extends MessageListenersManager { { name: '12h', value: '0 0 0/12 * * ?' }, { name: '1d', value: '0 0 0 * * ?' } ]; + updateNoteName(name: string) { const trimmedNewName = name.trim(); if (trimmedNewName.length > 0 && this.note.name !== trimmedNewName) { @@ -288,8 +291,8 @@ export class NotebookActionBarComponent extends MessageListenersManager { private nzMessageService: NzMessageService, private router: Router, private cdr: ChangeDetectorRef, - private noteActionService: NoteActionService, private noteStatusService: NoteStatusService, + private notebookService: NotebookService, @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string, private activatedRoute: ActivatedRoute, private saveAsService: SaveAsService @@ -299,6 +302,12 @@ export class NotebookActionBarComponent extends MessageListenersManager { if (!this.ticketService.configuration) { throw new Error('Configuration is not loaded'); } - this.isRevisionSupported = JSON.parse(this.ticketService.configuration.isRevisionSupported); + } + + ngOnInit(): void { + this.notebookService.capabilities().subscribe(c => { + this.isRevisionSupported = c.isRevisionSupported; + this.cdr.markForCheck(); + }); } } diff --git a/zeppelin-web-angular/src/app/services/notebook-search.service.ts b/zeppelin-web-angular/src/app/services/notebook.service.ts similarity index 83% rename from zeppelin-web-angular/src/app/services/notebook-search.service.ts rename to zeppelin-web-angular/src/app/services/notebook.service.ts index 7371eec736..93d5a7a933 100644 --- a/zeppelin-web-angular/src/app/services/notebook-search.service.ts +++ b/zeppelin-web-angular/src/app/services/notebook.service.ts @@ -13,7 +13,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { NotebookSearchResultItem } from '@zeppelin/interfaces'; +import { NotebookCapabilities, NotebookSearchResultItem } from '@zeppelin/interfaces'; import { BaseRest } from '@zeppelin/services/base-rest'; import { BaseUrlService } from '@zeppelin/services/base-url.service'; import { BehaviorSubject } from 'rxjs'; @@ -21,7 +21,7 @@ import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) -export class NotebookSearchService extends BaseRest { +export class NotebookService extends BaseRest { private queryStr$ = new BehaviorSubject<string | null>(null); constructor(baseUrlService: BaseUrlService, private http: HttpClient) { @@ -32,7 +32,7 @@ export class NotebookSearchService extends BaseRest { return this.queryStr$.asObservable(); } - clear() { + clearQuery() { this.queryStr$.next(null); } @@ -44,4 +44,8 @@ export class NotebookSearchService extends BaseRest { } }); } + + capabilities() { + return this.http.get<NotebookCapabilities>(this.restUrl`/notebook/capabilities`); + } } diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts b/zeppelin-web-angular/src/app/share/header/header.component.ts index 7d044f9e99..f1a1982db2 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.ts +++ b/zeppelin-web-angular/src/app/share/header/header.component.ts @@ -20,7 +20,7 @@ import { filter, takeUntil } from 'rxjs/operators'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk'; import { MessageService, TicketService } from '@zeppelin/services'; -import { NotebookSearchService } from '@zeppelin/services/notebook-search.service'; +import { NotebookService } from '@zeppelin/services/notebook.service'; import { AboutZeppelinComponent } from '@zeppelin/share/about-zeppelin/about-zeppelin.component'; @Component({ @@ -69,7 +69,7 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, private nzModalService: NzModalService, public messageService: MessageService, private router: Router, - private notebookSearchService: NotebookSearchService, + private notebookService: NotebookService, private cdr: ChangeDetectorRef ) { super(messageService); @@ -92,7 +92,7 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, this.cdr.markForCheck(); }); - this.notebookSearchService + this.notebookService .queried() .pipe(takeUntil(this.destroy$)) .subscribe(queryStr => (this.queryStr = queryStr)); diff --git a/zeppelin-web/src/app/notebook-repository/notebook-repository.controller.js b/zeppelin-web/src/app/notebook-repository/notebook-repository.controller.js index d6d13b32c7..ed4d48c9c8 100644 --- a/zeppelin-web/src/app/notebook-repository/notebook-repository.controller.js +++ b/zeppelin-web/src/app/notebook-repository/notebook-repository.controller.js @@ -65,7 +65,6 @@ function NotebookRepositoryCtrl($http, baseUrlSrv, ngToast) { $http.get(baseUrlSrv.getRestApiBase() + '/notebook-repositories') .success(function(data, status, headers, config) { vm.notebookRepos = data.body; - console.log('ya notebookRepos %o', vm.notebookRepos); }).error(function(data, status, headers, config) { if (status === 401) { ngToast.danger({ diff --git a/zeppelin-web/src/app/notebook/notebook-actionBar.html b/zeppelin-web/src/app/notebook/notebook-actionBar.html index e3d4fff507..34605abd44 100644 --- a/zeppelin-web/src/app/notebook/notebook-actionBar.html +++ b/zeppelin-web/src/app/notebook/notebook-actionBar.html @@ -125,7 +125,7 @@ limitations under the License. </button> </span> - <span class="labelBtn btn-group" role="group" ng-if="isRevisionSupported()" > + <span class="labelBtn btn-group" role="group" ng-if="isRevisionSupported" > <div class="btn-group" role="group"> <button type="button" class="btn btn-default btn-xs dropdown-toggle" diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js index 3b1a13f299..67a088cd9f 100644 --- a/zeppelin-web/src/app/notebook/notebook.controller.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -39,6 +39,7 @@ function NotebookCtrl($scope, $route, $routeParams, $location, $rootScope, $scope.collaborativeModeUsers = []; $scope.looknfeelOption = ['default', 'simple', 'report']; $scope.noteFormTitle = null; + $scope.isRevisionSupported = false; $scope.cronOption = [ {name: 'None', value: undefined}, {name: '1m', value: '0 0/1 * * * ?'}, @@ -169,9 +170,25 @@ function NotebookCtrl($scope, $route, $routeParams, $location, $rootScope, }); }; + const initializeRevisionSupported = function() { + $http.get(baseUrlSrv.getRestApiBase() + '/notebook/capabilities') + .then(function(response) { + $scope.isRevisionSupported = response.data.body.isRevisionSupported; + }) + .catch(function(error) { + console.error('Error fetching notebook capabilities:', error); + ngToast.danger({ + content: 'Failed to fetch notebook capabilities', + verticalPosition: 'bottom', + timeout: 3000, + }); + }); + }; + /** Init the new controller */ const initNotebook = function() { noteVarShareService.clear(); + initializeRevisionSupported(); if ($routeParams.revisionId) { websocketMsgSrv.getNoteByRevision($routeParams.noteId, $routeParams.revisionId); } else { diff --git a/zeppelin-web/src/components/navbar/navbar.controller.js b/zeppelin-web/src/components/navbar/navbar.controller.js index 503b9cd9aa..b35c60eac9 100644 --- a/zeppelin-web/src/components/navbar/navbar.controller.js +++ b/zeppelin-web/src/components/navbar/navbar.controller.js @@ -31,7 +31,6 @@ function NavCtrl($scope, $rootScope, $http, $routeParams, $location, vm.TRASH_FOLDER_ID = TRASH_FOLDER_ID; vm.isFilterNote = isFilterNote; vm.numberOfNotesDisplayed = 10; - let revisionSupported = false; $scope.query = {q: ''}; @@ -263,13 +262,6 @@ function NavCtrl($scope, $rootScope, $http, $routeParams, $location, return 'top'; }; - $scope.$on('configurationsInfo', function(scope, event) { - // Server send this parameter is String - if(event.configurations['isRevisionSupported']==='true') { - revisionSupported = true; - } - }); - $scope.resolveNewUiHref = function() { if (location.pathname === '/') { return '/new'; @@ -277,8 +269,4 @@ function NavCtrl($scope, $rootScope, $http, $routeParams, $location, return '/'; } }; - - $rootScope.isRevisionSupported = function() { - return revisionSupported; - }; } diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java index 07ac519651..e8b92b3cc1 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java @@ -848,7 +848,7 @@ public class Notebook { } } - public Boolean isRevisionSupported() { + public boolean isRevisionSupported() { if(!zConf.getBoolean(ConfVars.ZEPPELIN_NOTEBOOK_VERSIONED_MODE_ENABLE)) { return false; }