From 15ce4eb17904353db18ab8c0d82a2f36c9d374a6 Mon Sep 17 00:00:00 2001 From: YONGJAE LEE Date: Thu, 17 Sep 2026 04:17:58 +0900 Subject: [PATCH] [ZEPPELIN-6664] Add notebook core SDK wire fields --- zeppelin-web-angular/package.json | 1 + zeppelin-web-angular/pom.xml | 11 ++ .../interfaces/message-notebook.interface.ts | 11 +- .../interfaces/message-paragraph.interface.ts | 13 +++ .../interfaces/notebook-wire-fields.spec.ts | 101 ++++++++++++++++++ .../projects/zeppelin-sdk/tsconfig.spec.json | 8 ++ .../paragraph-base/paragraph-base.spec.ts | 1 + 7 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/notebook-wire-fields.spec.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index c5e994ea0ae2..492b631cb840 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 9c62c32d14b6..93b28c184ec2 100644 --- a/zeppelin-web-angular/pom.xml +++ b/zeppelin-web-angular/pom.xml @@ -155,6 +155,17 @@ + + npm typecheck sdk contracts + + npm + + test + + run typecheck:sdk-contracts + + + npm typecheck notebook core 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 665e8dfd71f6..ff9697307b91 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, 'paragraphs' | 'version'> & { + paragraphs: ImportParagraphItem[]; + version?: string; +}; + export interface ImportNote { - note: Exclude['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 f9e01351e2ea..dab0a6533332 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 & { + 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 000000000000..471d556498c4 --- /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().toHaveProperty('progress').toEqualTypeOf(); + expectTypeOf>().toHaveProperty('version').toEqualTypeOf(); + expectTypeOf().toHaveProperty('completionKey').toEqualTypeOf(); + expectTypeOf().toHaveProperty('angularObject').toEqualTypeOf< + | { + name: string; + object: unknown; + noteId?: string; + paragraphId?: string; + } + | undefined + >(); + expectTypeOf().toHaveProperty('interpreterGroupId').toEqualTypeOf(); + 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().toHaveProperty('version').toEqualTypeOf(); + expectTypeOf() + .toHaveProperty('progress') + .toEqualTypeOf(); + 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['version']>().toEqualTypeOf(); + 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 000000000000..436d2bfdf28d --- /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 34d5cc441834..9794f25b07b3 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,