This is an automated email from the ASF dual-hosted git repository.

tbonelee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 89b014e44d [ZEPPELIN-6664] Add notebook core SDK wire fields
89b014e44d is described below

commit 89b014e44d662a74ed65dc6c8c037a348632a00e
Author: YONGJAE LEE (이용재) <[email protected]>
AuthorDate: Fri Sep 25 19:04:20 2026 +0900

    [ZEPPELIN-6664] Add notebook core SDK wire fields
    
    ### What is this PR for?
    Declare five notebook WebSocket fields that the server already sends but 
the SDK types omitted, so Shared Notebook Core can build on typed values 
instead of casts. This PR adds those declarations only; it does not model every 
payload variant or every nullable nested value.
    
    * `ParagraphItem.progress: number`: 
`zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Paragraph.java:78` 
(primitive `int`, always serialized). Declared fields enumerated across 
`Paragraph.java:73-99`, 
`zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/Job.java:84-93`
 and `JobWithProgressPoller.java:23`.
    * `Note.note.version?: string`: 
`zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Note.java:77`, 
range `Note.java:73-98`. Optional because a personalized `GET_NOTE` returns 
`getUserNote()` (`Note.java:948-967`, reached from 
`NotebookService.java:147-151`), which is built without a version.
    * `EditorSettingReceived.editor.completionKey?: string`: emitted by 
`NotebookServer.java:2240-2248` through `NotebookService.java:1244-1246` and 
`InterpreterSettingManager.java:616-685`, which returns the interpreter's 
editor map (for example 
`livy/src/main/resources/interpreter-setting.json:137`). Optional because many 
editor blocks and the default map (`InterpreterSettingManager.java:111-113`) 
omit it.
    * `AngularObjectRemove.angularObject?` and `.interpreterGroupId?`: sent 
only by `NotebookServer.java:1495-1498`; the other emit site 
(`NotebookServer.java:2218-2231`) omits both. Nested fields come from 
`zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java:42-49`.
 Correcting loosely typed payload shapes is tracked by ZEPPELIN-6676.
    
    `ImportNote` keeps using `ImportParagraphItem`, where `progress` and 
`version` stay optional, because an imported note file is user input and may 
not carry them. TypeScript callers that construct a received `ParagraphItem` 
now have to set `progress`; the paragraph test fixture in this PR does so.
    
    ### What type of PR is it?
    Improvement
    
    ### Todos
    * [x] Declare the five fields
    * [x] Add a type-level contract spec, typechecked in the Maven `test` phase
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/ZEPPELIN-6664
    
    ### How should this be tested?
    The first command typechecks the contract spec and the second executes it. 
The third checks WebSocket operation names and message-map consistency, not 
payload fields.
    
    ```bash
    cd zeppelin-web-angular
    npm run typecheck:sdk-contracts
    npx vitest run --config vitest.shell.config.mts 
projects/zeppelin-sdk/src/interfaces/notebook-wire-fields.spec.ts
    npm run check:websocket-contract
    ```
    
    ### Screenshots (if appropriate)
    N/A
    
    ### Questions:
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    
    
    Closes #5480 from voidmatcha/ZEPPELIN-6664-sdk-notebook-fields.
    
    Signed-off-by: ChanHo Lee <[email protected]>
---
 zeppelin-web-angular/package.json                  |   1 +
 zeppelin-web-angular/pom.xml                       |  11 +++
 .../src/interfaces/message-notebook.interface.ts   |  11 ++-
 .../src/interfaces/message-paragraph.interface.ts  |  13 +++
 .../src/interfaces/notebook-wire-fields.spec.ts    | 101 +++++++++++++++++++++
 .../projects/zeppelin-sdk/tsconfig.spec.json       |   8 ++
 .../app/core/paragraph-base/paragraph-base.spec.ts |   1 +
 7 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/zeppelin-web-angular/package.json 
b/zeppelin-web-angular/package.json
index c5e994ea0a..492b631cb8 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -23,6 +23,7 @@
     "lint:react": "cd projects/zeppelin-react && npm run lint",
     "lint:fix:react": "cd projects/zeppelin-react && npm run lint:fix",
     "typecheck:notebook-core": "tsc -p 
projects/zeppelin-notebook-core/tsconfig.json --noEmit && tsc -p 
projects/zeppelin-notebook-core/tsconfig.spec.json --noEmit && npm run 
build-project:notebook-core && tsc -p 
projects/zeppelin-react/tsconfig.notebook-core.dist.json --noEmit && tsc -p 
projects/zeppelin-react/tsconfig.notebook-core.json --noEmit",
+    "typecheck:sdk-contracts": "tsc -p 
projects/zeppelin-sdk/tsconfig.spec.json --noEmit",
     "test:notebook-core": "vitest run --config 
vitest.notebook-core.config.mts",
     "test:shell": "vitest run --config vitest.shell.config.mts",
     "test:eslint-rules": "node --test eslint-rules/*.test.js",
diff --git a/zeppelin-web-angular/pom.xml b/zeppelin-web-angular/pom.xml
index 9c62c32d14..93b28c184e 100644
--- a/zeppelin-web-angular/pom.xml
+++ b/zeppelin-web-angular/pom.xml
@@ -155,6 +155,17 @@
             </configuration>
           </execution>
 
+          <execution>
+            <id>npm typecheck sdk contracts</id>
+            <goals>
+              <goal>npm</goal>
+            </goals>
+            <phase>test</phase>
+            <configuration>
+              <arguments>run typecheck:sdk-contracts</arguments>
+            </configuration>
+          </execution>
+
           <execution>
             <id>npm typecheck notebook core</id>
             <goals>
diff --git 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
index fca5c07198..e4058a3f12 100644
--- 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
+++ 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
@@ -10,7 +10,7 @@
  * limitations under the License.
  */
 
-import { ParagraphItem } from './message-paragraph.interface';
+import { ImportParagraphItem, ParagraphItem } from 
'./message-paragraph.interface';
 
 interface ID {
   id: string;
@@ -59,11 +59,17 @@ export interface Note {
     angularObjects: NoteAngularObjects;
     config: NoteConfig;
     info: NoteInfo;
+    version?: string;
   };
 }
 
+export type ImportNoteData = Omit<NonNullable<Note['note']>, 'paragraphs' | 
'version'> & {
+  paragraphs: ImportParagraphItem[];
+  version?: string;
+};
+
 export interface ImportNote {
-  note: Exclude<Required<Note>['note'], 'path'>;
+  note: ImportNoteData;
 }
 
 export interface NoteAngularObjects {
@@ -116,6 +122,7 @@ export interface EditorSettingReceived {
     completionSupport: boolean;
     editOnDblClick: boolean;
     language: string;
+    completionKey?: string;
   };
 }
 
diff --git 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
index f9e01351e2..dab0a65333 100644
--- 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
+++ 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
@@ -140,6 +140,7 @@ export interface ParagraphItem {
   // eslint-disable-next-line  @typescript-eslint/no-explicit-any
   apps: any[];
   progressUpdateIntervalMs: number;
+  progress: number;
   jobName: string;
   id: string;
   dateCreated: string;
@@ -159,6 +160,10 @@ export interface ParagraphItem {
   fontSize: any;
 }
 
+export type ImportParagraphItem = Omit<ParagraphItem, 'progress'> & {
+  progress?: number;
+};
+
 export interface SendParagraph {
   id: string;
   title?: string;
@@ -214,6 +219,14 @@ export interface AngularObjectRemove {
   noteId: string;
   paragraphId: string;
   name: string;
+  angularObject?: {
+    name: string;
+    object: unknown;
+    // Omitted for global (noteId) and note (paragraphId) scoped objects.
+    noteId?: string;
+    paragraphId?: string;
+  };
+  interpreterGroupId?: string;
 }
 
 export interface AngularObjectUpdate {
diff --git 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/notebook-wire-fields.spec.ts
 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/notebook-wire-fields.spec.ts
new file mode 100644
index 0000000000..471d556498
--- /dev/null
+++ 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/notebook-wire-fields.spec.ts
@@ -0,0 +1,101 @@
+/*
+ * 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 { expect, expectTypeOf, it } from 'vitest';
+
+import { EditorSettingReceived, ImportNote, Note } from 
'./message-notebook.interface';
+import { AngularObjectRemove, ImportParagraphItem, ParagraphItem } from 
'./message-paragraph.interface';
+
+it('separates received wire fields from backward-compatible import input', () 
=> {
+  
expectTypeOf<ParagraphItem>().toHaveProperty('progress').toEqualTypeOf<number>();
+  
expectTypeOf<NonNullable<Note['note']>>().toHaveProperty('version').toEqualTypeOf<string
 | undefined>();
+  
expectTypeOf<EditorSettingReceived['editor']>().toHaveProperty('completionKey').toEqualTypeOf<string
 | undefined>();
+  
expectTypeOf<AngularObjectRemove>().toHaveProperty('angularObject').toEqualTypeOf<
+    | {
+        name: string;
+        object: unknown;
+        noteId?: string;
+        paragraphId?: string;
+      }
+    | undefined
+  >();
+  
expectTypeOf<AngularObjectRemove>().toHaveProperty('interpreterGroupId').toEqualTypeOf<string
 | undefined>();
+  const legacyImportParagraph = {
+    text: '%md legacy import',
+    user: 'anonymous',
+    dateUpdated: '2026-09-14T00:00:00.000Z',
+    config: {},
+    settings: { params: {}, forms: {} },
+    apps: [],
+    progressUpdateIntervalMs: 500,
+    jobName: 'paragraph',
+    id: 'paragraph-1',
+    dateCreated: '2026-09-14T00:00:00.000Z',
+    status: 'READY',
+    aborted: false,
+    lineNumbers: false,
+    fontSize: 9
+  } satisfies ImportParagraphItem;
+  const importWithoutVersion: ImportNote = {
+    note: {
+      paragraphs: [legacyImportParagraph],
+      name: 'Imported note',
+      id: 'imported-note',
+      path: '/Imported note',
+      defaultInterpreterGroup: '',
+      noteParams: {},
+      noteForms: {},
+      angularObjects: {},
+      config: {
+        releaseresource: false,
+        isZeppelinNotebookCronEnable: false,
+        looknfeel: 'default',
+        personalizedMode: 'false'
+      },
+      info: {}
+    }
+  };
+
+  
expectTypeOf<ImportNote['note']>().toHaveProperty('version').toEqualTypeOf<string
 | undefined>();
+  expectTypeOf<ImportNote['note']['paragraphs'][number]>()
+    .toHaveProperty('progress')
+    .toEqualTypeOf<number | undefined>();
+  expect(importWithoutVersion.note).not.toHaveProperty('version');
+  
expect(importWithoutVersion.note.paragraphs[0]).not.toHaveProperty('progress');
+});
+
+it('accepts the personalized GET_NOTE response without a version', () => {
+  // NotebookService.getNote returns Note.getUserNote for personalized 
notebooks.
+  // That copy is constructed with Note(), so its nullable version is omitted 
by Message serialization.
+  const personalizedNote: Note = {
+    note: {
+      paragraphs: [],
+      name: 'Personalized note',
+      id: 'personalized-note',
+      path: '/Personalized note',
+      defaultInterpreterGroup: '',
+      noteParams: {},
+      noteForms: {},
+      angularObjects: {},
+      config: {
+        releaseresource: false,
+        isZeppelinNotebookCronEnable: false,
+        looknfeel: 'default',
+        personalizedMode: 'true'
+      },
+      info: {}
+    }
+  };
+
+  expectTypeOf<NonNullable<Note['note']>['version']>().toEqualTypeOf<string | 
undefined>();
+  expect(personalizedNote.note).not.toHaveProperty('version');
+});
diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json 
b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json
new file mode 100644
index 0000000000..436d2bfdf2
--- /dev/null
+++ b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json
@@ -0,0 +1,8 @@
+{
+  "extends": "../../tsconfig.base.json",
+  "compilerOptions": {
+    "noEmit": true,
+    "types": ["node"]
+  },
+  "include": ["src/**/*.spec.ts"]
+}
diff --git 
a/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.spec.ts 
b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.spec.ts
index 34d5cc4418..9794f25b07 100644
--- a/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.spec.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.spec.ts
@@ -49,6 +49,7 @@ const paragraph = (id: string, status = 'RUNNING', 
dateStarted = '2026-01-01T00:
   config: {},
   settings: { params: {}, forms: {} },
   apps: [],
+  progress: 0,
   progressUpdateIntervalMs: 500,
   jobName: '',
   aborted: false,

Reply via email to