Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions zeppelin-web-angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
11 changes: 11 additions & 0 deletions zeppelin-web-angular/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -116,6 +122,7 @@ export interface EditorSettingReceived {
completionSupport: boolean;
editOnDblClick: boolean;
language: string;
completionKey?: string;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -159,6 +160,10 @@ export interface ParagraphItem {
fontSize: any;
}

export type ImportParagraphItem = Omit<ParagraphItem, 'progress'> & {
progress?: number;
};

export interface SendParagraph {
id: string;
title?: string;
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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');
});
8 changes: 8 additions & 0 deletions zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"noEmit": true,
"types": ["node"]
},
"include": ["src/**/*.spec.ts"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading