Skip to content

Commit eadd26d

Browse files
tkislanArtmanncoderabbitai[bot]jamesbhobbs
authored
feat: Implement deepnote big number chart support and renderer (#41)
* feat: Set up a custom renderer for data frames. * wip * feat: Implement deepnote big number chart support and renderer * refactor: Clean up debug logs and improve big number block conversion handling * feat: Pass block metadata to cell outputs for renderer to access * feat: Set up a custom renderer for data frames. * wip * add the table state. * page size handling * add page navigation * Generate Python code before executing the cell. * clean up * pr feedback. * Update build/esbuild/build.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat: Move DEEPNOTE_VSCODE_RAW_CONTENT_KEY into constants file * feedback * feat: Add chart big number converter tests * Reformat test code * Refactor ChartBigNumberBlockConverter tests to use deepStrictEqual for assertions * docs and metadata changes. * Merge remote-tracking branch 'origin/chris/display-data-frames' into tomaskislan/grn-4762-support-big-number-blocks * use the latest blocks package. * add the packages permission * simplify execution flow. * remove copyright header * clean up the code * revert controller changes * pr feedback * pr feedback * fix the tests * guard metadata spread against undefined. * fix: Merge cleanup * More merge cleanup * Fix test * feat: Add big number chart json config execution support * fix: Enhance error handling for big number metadata parsing and improve chart big number renderer logic * refactor: Simplify chart big number renderer by directly rendering to the element and improve cleanup logic for unmounting components * Fix import * fix: Change deepnote_big_number_comparison_type to string type for better flexibility * fix: Remove constants, accidentaly added to wrong branch * Fix imports * fix: Remove unused code * feat(big-number): Integrate react-error-boundary for error handling and enhance big number output rendering * Update test snapshots * fix: Fix spell check in test Signed-off-by: Tomas Kislan <tomas@kislan.sk> --------- Signed-off-by: Tomas Kislan <tomas@kislan.sk> Co-authored-by: Christoffer Artmann <artgaard@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: James Hobbs <15235276+jamesbhobbs@users.noreply.github.com>
1 parent 8597009 commit eadd26d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1039
-53
lines changed

build/esbuild/build.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,18 @@ async function buildAll() {
331331
path.join(extensionFolder, 'dist', 'webviews', 'webview-side', 'dataframeRenderer', 'dataframeRenderer.js'),
332332
{ target: 'web', watch: isWatchMode }
333333
),
334+
build(
335+
path.join(extensionFolder, 'src', 'webviews', 'webview-side', 'chart-big-number-renderer', 'index.ts'),
336+
path.join(
337+
extensionFolder,
338+
'dist',
339+
'webviews',
340+
'webview-side',
341+
'chartBigNumberRenderer',
342+
'chartBigNumberRenderer.js'
343+
),
344+
{ target: 'web', watch: isWatchMode }
345+
),
334346
build(
335347
path.join(extensionFolder, 'src', 'webviews', 'webview-side', 'vega-renderer', 'index.ts'),
336348
path.join(extensionFolder, 'dist', 'webviews', 'webview-side', 'vegaRenderer', 'vegaRenderer.js'),

package-lock.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,15 @@
18481848
],
18491849
"requiresMessaging": "optional"
18501850
},
1851+
{
1852+
"id": "deepnote-chart-big-number-renderer",
1853+
"displayName": "Deepnote Chart Big Number Renderer",
1854+
"entrypoint": "./dist/webviews/webview-side/chartBigNumberRenderer/chartBigNumberRenderer.js",
1855+
"mimeTypes": [
1856+
"application/vnd.deepnote.chart.big-number+json"
1857+
],
1858+
"requiresMessaging": "optional"
1859+
},
18511860
{
18521861
"id": "deepnote-vega-renderer",
18531862
"displayName": "Deepnote Vega Chart Renderer",
@@ -2235,7 +2244,8 @@
22352244
"vscode-tas-client": "^0.1.84",
22362245
"ws": "^6.2.3",
22372246
"zeromq": "^6.5.0",
2238-
"zeromqold": "npm:zeromq@^6.0.0-beta.6"
2247+
"zeromqold": "npm:zeromq@^6.0.0-beta.6",
2248+
"zod": "^4.1.12"
22392249
},
22402250
"devDependencies": {
22412251
"@actions/core": "^1.11.1",

src/kernels/execution/cellExecution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import type * as KernelMessage from '@jupyterlab/services/lib/kernel/messages';
55
import { NotebookCell, NotebookCellExecution, workspace, NotebookCellOutput } from 'vscode';
66

7+
import { createPythonCode } from '@deepnote/blocks';
78
import type { Kernel } from '@jupyterlab/services';
89
import { CellExecutionCreator } from './cellExecutionCreator';
910
import { analyzeKernelErrors, createOutputWithErrorMessageForDisplay } from '../../platform/errors/errorUtils';
@@ -32,7 +33,6 @@ import { KernelError } from '../errors/kernelError';
3233
import { getCachedSysPrefix } from '../../platform/interpreter/helpers';
3334
import { getCellMetadata } from '../../platform/common/utils';
3435
import { NotebookCellExecutionState, notebookCellExecutions } from '../../platform/notebooks/cellExecutionStateService';
35-
import { createPythonCode } from '@deepnote/blocks';
3636
import { DeepnoteDataConverter } from '../../notebooks/deepnote/deepnoteDataConverter';
3737

3838
/**

src/kernels/execution/cellExecutionMessageHandler.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
window,
2525
extensions
2626
} from 'vscode';
27+
import { coerce, SemVer } from 'semver';
2728

2829
import type { Kernel } from '@jupyterlab/services';
2930
import { CellExecutionCreator } from './cellExecutionCreator';
@@ -45,7 +46,7 @@ import { handleTensorBoardDisplayDataOutput } from './executionHelpers';
4546
import { Identifiers, RendererExtension, WIDGET_MIMETYPE } from '../../platform/common/constants';
4647
import { CellOutputDisplayIdTracker } from './cellDisplayIdTracker';
4748
import { createDeferred } from '../../platform/common/utils/async';
48-
import { coerce, SemVer } from 'semver';
49+
import { CHART_BIG_NUMBER_MIME_TYPE } from '../../platform/deepnote/deepnoteConstants';
4950

5051
// Helper interface for the set_next_input execute reply payload
5152
interface ISetNextInputPayload {
@@ -1181,6 +1182,15 @@ export class CellExecutionMessageHandler implements IDisposable {
11811182
const output = translateCellDisplayOutput(
11821183
new NotebookCellOutput(outputToBeUpdated.outputItems, outputToBeUpdated.outputContainer.metadata)
11831184
);
1185+
1186+
const data = msg.content.data;
1187+
// deepnote-toolkit returns the text/plain mime type for big number outputs
1188+
// and for the custom renderer to be used, we need to return the application/vnd.deepnote.chart.big-number+json mime type
1189+
if (outputToBeUpdated.cell.metadata['__deepnotePocket']?.['type'] === 'big-number') {
1190+
data[CHART_BIG_NUMBER_MIME_TYPE] = data['text/plain'];
1191+
delete data['text/plain'];
1192+
}
1193+
11841194
const newOutput = cellOutputToVSCCellOutput(
11851195
{
11861196
...output,

src/kernels/execution/helpers.ts

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,32 @@
22
// Licensed under the MIT License.
33

44
import type * as nbformat from '@jupyterlab/nbformat';
5-
import { NotebookCellOutput, NotebookCellOutputItem, NotebookCell, Position, Range } from 'vscode';
5+
import { NotebookCell, NotebookCellOutput, NotebookCellOutputItem, Position, Range } from 'vscode';
66
// eslint-disable-next-line @typescript-eslint/no-require-imports
77
import type { KernelMessage } from '@jupyterlab/services';
88
import fastDeepEqual from 'fast-deep-equal';
9-
import * as path from '../../platform/vscode-path/path';
10-
import * as uriPath from '../../platform/vscode-path/resources';
9+
import { Pocket } from '../../platform/deepnote/pocket';
1110
import { PYTHON_LANGUAGE } from '../../platform/common/constants';
1211
import { concatMultilineString, splitMultilineString } from '../../platform/common/utils';
12+
import { StopWatch } from '../../platform/common/utils/stopWatch';
13+
import { base64ToUint8Array, uint8ArrayToBase64 } from '../../platform/common/utils/string';
14+
import { CHART_BIG_NUMBER_MIME_TYPE } from '../../platform/deepnote/deepnoteConstants';
15+
import { getExtensionSpecificStack } from '../../platform/errors/errors';
16+
import { createOutputWithErrorMessageForDisplay } from '../../platform/errors/errorUtils';
17+
import { getCachedEnvironment, getVersion } from '../../platform/interpreter/helpers';
1318
import { logger } from '../../platform/logging';
19+
import type { NotebookCellExecutionState } from '../../platform/notebooks/cellExecutionStateService';
20+
import * as path from '../../platform/vscode-path/path';
21+
import * as uriPath from '../../platform/vscode-path/resources';
1422
import { sendTelemetryEvent, Telemetry } from '../../telemetry';
15-
import { createOutputWithErrorMessageForDisplay } from '../../platform/errors/errorUtils';
16-
import { CellExecutionCreator } from './cellExecutionCreator';
17-
import { IKernelController, KernelConnectionMetadata } from '../types';
1823
import {
19-
isPythonKernelConnection,
2024
getInterpreterFromKernelConnectionMetadata,
21-
kernelConnectionMetadataHasKernelModel,
22-
getKernelRegistrationInfo
25+
getKernelRegistrationInfo,
26+
isPythonKernelConnection,
27+
kernelConnectionMetadataHasKernelModel
2328
} from '../helpers';
24-
import { StopWatch } from '../../platform/common/utils/stopWatch';
25-
import { getExtensionSpecificStack } from '../../platform/errors/errors';
26-
import { getCachedEnvironment, getVersion } from '../../platform/interpreter/helpers';
27-
import { base64ToUint8Array, uint8ArrayToBase64 } from '../../platform/common/utils/string';
28-
import type { NotebookCellExecutionState } from '../../platform/notebooks/cellExecutionStateService';
29+
import { IKernelController, KernelConnectionMetadata } from '../types';
30+
import { CellExecutionCreator } from './cellExecutionCreator';
2931

3032
export enum CellOutputMimeTypes {
3133
error = 'application/vnd.code.notebook.error',
@@ -260,6 +262,9 @@ function translateDisplayDataOutput(
260262
}
261263
}
262264
*/
265+
const deepnotePocket = cellMetadata?.__deepnotePocket as Pocket | undefined;
266+
const deepnoteBlockType = deepnotePocket?.type;
267+
263268
const metadata = getOutputMetadata(output, cellIndex, cellId, cellMetadata);
264269
// If we have SVG or PNG, then add special metadata to indicate whether to display `open plot`
265270
if ('image/svg+xml' in output.data || 'image/png' in output.data) {
@@ -269,7 +274,9 @@ function translateDisplayDataOutput(
269274
if (output.data) {
270275
// eslint-disable-next-line no-restricted-syntax
271276
for (const key in output.data) {
272-
items.push(convertJupyterOutputToBuffer(key, output.data[key]));
277+
// TODO - remove this once this is handled in the deepnote-toolkit
278+
let effectiveKey = deepnoteBlockType === 'big-number' ? CHART_BIG_NUMBER_MIME_TYPE : key;
279+
items.push(convertJupyterOutputToBuffer(effectiveKey, output.data[key] ?? output.data[effectiveKey]));
273280
}
274281
}
275282

src/notebooks/deepnote/converters/blockConverter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { NotebookCellData } from 'vscode';
22

3-
import type { DeepnoteBlock } from '../deepnoteTypes';
3+
import type { DeepnoteBlock } from '../../../platform/deepnote/deepnoteTypes';
44

55
export interface BlockConverter {
66
applyChangesToBlock(block: DeepnoteBlock, cell: NotebookCellData): void;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { NotebookCellData, NotebookCellKind } from 'vscode';
2+
import { z } from 'zod';
3+
4+
import type { BlockConverter } from './blockConverter';
5+
import type { DeepnoteBlock } from '../../../platform/deepnote/deepnoteTypes';
6+
import { DeepnoteBigNumberMetadataSchema } from '../deepnoteSchemas';
7+
import { parseJsonWithFallback } from '../dataConversionUtils';
8+
import { DEEPNOTE_VSCODE_RAW_CONTENT_KEY } from './constants';
9+
10+
const DEFAULT_BIG_NUMBER_CONFIG = DeepnoteBigNumberMetadataSchema.parse({});
11+
12+
export class ChartBigNumberBlockConverter implements BlockConverter {
13+
applyChangesToBlock(block: DeepnoteBlock, cell: NotebookCellData): void {
14+
block.content = '';
15+
16+
const config = DeepnoteBigNumberMetadataSchema.safeParse(parseJsonWithFallback(cell.value));
17+
18+
if (config.success !== true) {
19+
block.metadata = {
20+
...block.metadata,
21+
[DEEPNOTE_VSCODE_RAW_CONTENT_KEY]: cell.value
22+
};
23+
24+
return;
25+
}
26+
27+
if (block.metadata != null) {
28+
delete block.metadata[DEEPNOTE_VSCODE_RAW_CONTENT_KEY];
29+
}
30+
31+
block.metadata = {
32+
...(block.metadata ?? {}),
33+
...config.data
34+
};
35+
}
36+
37+
canConvert(blockType: string): boolean {
38+
return blockType.toLowerCase() === 'big-number';
39+
}
40+
41+
convertToCell(block: DeepnoteBlock): NotebookCellData {
42+
const deepnoteJupyterRawContentResult = z.string().safeParse(block.metadata?.[DEEPNOTE_VSCODE_RAW_CONTENT_KEY]);
43+
const deepnoteBigNumberMetadataResult = DeepnoteBigNumberMetadataSchema.safeParse(block.metadata);
44+
45+
if (deepnoteBigNumberMetadataResult.error != null) {
46+
console.error('Error parsing deepnote big number metadata:', deepnoteBigNumberMetadataResult.error);
47+
console.debug('Metadata:', JSON.stringify(block.metadata));
48+
}
49+
50+
const configStr = deepnoteJupyterRawContentResult.success
51+
? deepnoteJupyterRawContentResult.data
52+
: deepnoteBigNumberMetadataResult.success
53+
? JSON.stringify(deepnoteBigNumberMetadataResult.data, null, 2)
54+
: JSON.stringify(DEFAULT_BIG_NUMBER_CONFIG, null, 2);
55+
56+
const cell = new NotebookCellData(NotebookCellKind.Code, configStr, 'json');
57+
58+
return cell;
59+
}
60+
61+
getSupportedTypes(): string[] {
62+
return ['big-number'];
63+
}
64+
}

0 commit comments

Comments
 (0)