Skip to content

Commit 5c3d0f1

Browse files
tkislanArtmanncoderabbitai[bot]jamesbhobbs
authored
feat: Support Deepnote input blocks (#42)
* 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: Support Deepnote input blocks * feat: Move DEEPNOTE_VSCODE_RAW_CONTENT_KEY into constants file * feedback * feat: Add Deepnote input blocks converters * refactor: Remove debug logs and refine metadata parsing in Deepnote converters * feat: Add chart big number converter tests * Reformat test code * Refactor ChartBigNumberBlockConverter tests to use deepStrictEqual for assertions * Remove debug console.log * docs and metadata changes. * fix: Spread operator object fallback * 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: 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 * feat: Update input create default values to match those in deepnote app Signed-off-by: Tomas Kislan <tomas@kislan.sk> * feat: Display input block type in notebook cell status bar Signed-off-by: Tomas Kislan <tomas@kislan.sk> * 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 30e3d16 commit 5c3d0f1

8 files changed

+1839
-0
lines changed
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
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 {
7+
DeepnoteTextInputMetadataSchema,
8+
DeepnoteTextareaInputMetadataSchema,
9+
DeepnoteSelectInputMetadataSchema,
10+
DeepnoteSliderInputMetadataSchema,
11+
DeepnoteCheckboxInputMetadataSchema,
12+
DeepnoteDateInputMetadataSchema,
13+
DeepnoteDateRangeInputMetadataSchema,
14+
DeepnoteFileInputMetadataSchema,
15+
DeepnoteButtonMetadataSchema
16+
} from '../deepnoteSchemas';
17+
import { parseJsonWithFallback } from '../dataConversionUtils';
18+
import { DEEPNOTE_VSCODE_RAW_CONTENT_KEY } from './constants';
19+
20+
export abstract class BaseInputBlockConverter<T extends z.ZodObject> implements BlockConverter {
21+
abstract schema(): T;
22+
abstract getSupportedType(): string;
23+
abstract defaultConfig(): z.infer<T>;
24+
25+
applyChangesToBlock(block: DeepnoteBlock, cell: NotebookCellData): void {
26+
block.content = '';
27+
28+
const config = this.schema().safeParse(parseJsonWithFallback(cell.value));
29+
30+
if (config.success !== true) {
31+
block.metadata = {
32+
...(block.metadata ?? {}),
33+
[DEEPNOTE_VSCODE_RAW_CONTENT_KEY]: cell.value
34+
};
35+
return;
36+
}
37+
38+
if (block.metadata != null) {
39+
delete block.metadata[DEEPNOTE_VSCODE_RAW_CONTENT_KEY];
40+
}
41+
42+
block.metadata = {
43+
...(block.metadata ?? {}),
44+
...config.data
45+
};
46+
}
47+
48+
canConvert(blockType: string): boolean {
49+
return blockType.toLowerCase() === this.getSupportedType();
50+
}
51+
52+
convertToCell(block: DeepnoteBlock): NotebookCellData {
53+
const deepnoteJupyterRawContentResult = z.string().safeParse(block.metadata?.[DEEPNOTE_VSCODE_RAW_CONTENT_KEY]);
54+
const deepnoteMetadataResult = this.schema().safeParse(block.metadata);
55+
56+
if (deepnoteMetadataResult.error != null) {
57+
console.error('Error parsing deepnote input metadata:', deepnoteMetadataResult.error);
58+
console.debug('Metadata:', JSON.stringify(block.metadata));
59+
}
60+
61+
const configStr = deepnoteJupyterRawContentResult.success
62+
? deepnoteJupyterRawContentResult.data
63+
: deepnoteMetadataResult.success
64+
? JSON.stringify(deepnoteMetadataResult.data, null, 2)
65+
: JSON.stringify(this.defaultConfig(), null, 2);
66+
67+
const cell = new NotebookCellData(NotebookCellKind.Code, configStr, 'json');
68+
69+
return cell;
70+
}
71+
72+
getSupportedTypes(): string[] {
73+
return [this.getSupportedType()];
74+
}
75+
}
76+
77+
export class InputTextBlockConverter extends BaseInputBlockConverter<typeof DeepnoteTextInputMetadataSchema> {
78+
private readonly DEFAULT_INPUT_TEXT_CONFIG = DeepnoteTextInputMetadataSchema.parse({});
79+
80+
schema() {
81+
return DeepnoteTextInputMetadataSchema;
82+
}
83+
getSupportedType() {
84+
return 'input-text';
85+
}
86+
defaultConfig() {
87+
return this.DEFAULT_INPUT_TEXT_CONFIG;
88+
}
89+
}
90+
91+
export class InputTextareaBlockConverter extends BaseInputBlockConverter<typeof DeepnoteTextareaInputMetadataSchema> {
92+
private readonly DEFAULT_INPUT_TEXTAREA_CONFIG = DeepnoteTextareaInputMetadataSchema.parse({});
93+
94+
schema() {
95+
return DeepnoteTextareaInputMetadataSchema;
96+
}
97+
getSupportedType() {
98+
return 'input-textarea';
99+
}
100+
defaultConfig() {
101+
return this.DEFAULT_INPUT_TEXTAREA_CONFIG;
102+
}
103+
}
104+
105+
export class InputSelectBlockConverter extends BaseInputBlockConverter<typeof DeepnoteSelectInputMetadataSchema> {
106+
private readonly DEFAULT_INPUT_SELECT_CONFIG = DeepnoteSelectInputMetadataSchema.parse({});
107+
108+
schema() {
109+
return DeepnoteSelectInputMetadataSchema;
110+
}
111+
getSupportedType() {
112+
return 'input-select';
113+
}
114+
defaultConfig() {
115+
return this.DEFAULT_INPUT_SELECT_CONFIG;
116+
}
117+
}
118+
119+
export class InputSliderBlockConverter extends BaseInputBlockConverter<typeof DeepnoteSliderInputMetadataSchema> {
120+
private readonly DEFAULT_INPUT_SLIDER_CONFIG = DeepnoteSliderInputMetadataSchema.parse({});
121+
122+
schema() {
123+
return DeepnoteSliderInputMetadataSchema;
124+
}
125+
getSupportedType() {
126+
return 'input-slider';
127+
}
128+
defaultConfig() {
129+
return this.DEFAULT_INPUT_SLIDER_CONFIG;
130+
}
131+
}
132+
133+
export class InputCheckboxBlockConverter extends BaseInputBlockConverter<typeof DeepnoteCheckboxInputMetadataSchema> {
134+
private readonly DEFAULT_INPUT_CHECKBOX_CONFIG = DeepnoteCheckboxInputMetadataSchema.parse({});
135+
136+
schema() {
137+
return DeepnoteCheckboxInputMetadataSchema;
138+
}
139+
getSupportedType() {
140+
return 'input-checkbox';
141+
}
142+
defaultConfig() {
143+
return this.DEFAULT_INPUT_CHECKBOX_CONFIG;
144+
}
145+
}
146+
147+
export class InputDateBlockConverter extends BaseInputBlockConverter<typeof DeepnoteDateInputMetadataSchema> {
148+
private readonly DEFAULT_INPUT_DATE_CONFIG = DeepnoteDateInputMetadataSchema.parse({});
149+
150+
schema() {
151+
return DeepnoteDateInputMetadataSchema;
152+
}
153+
getSupportedType() {
154+
return 'input-date';
155+
}
156+
defaultConfig() {
157+
return this.DEFAULT_INPUT_DATE_CONFIG;
158+
}
159+
}
160+
161+
export class InputDateRangeBlockConverter extends BaseInputBlockConverter<typeof DeepnoteDateRangeInputMetadataSchema> {
162+
private readonly DEFAULT_INPUT_DATE_RANGE_CONFIG = DeepnoteDateRangeInputMetadataSchema.parse({});
163+
164+
schema() {
165+
return DeepnoteDateRangeInputMetadataSchema;
166+
}
167+
getSupportedType() {
168+
return 'input-date-range';
169+
}
170+
defaultConfig() {
171+
return this.DEFAULT_INPUT_DATE_RANGE_CONFIG;
172+
}
173+
}
174+
175+
export class InputFileBlockConverter extends BaseInputBlockConverter<typeof DeepnoteFileInputMetadataSchema> {
176+
private readonly DEFAULT_INPUT_FILE_CONFIG = DeepnoteFileInputMetadataSchema.parse({});
177+
178+
schema() {
179+
return DeepnoteFileInputMetadataSchema;
180+
}
181+
getSupportedType() {
182+
return 'input-file';
183+
}
184+
defaultConfig() {
185+
return this.DEFAULT_INPUT_FILE_CONFIG;
186+
}
187+
}
188+
189+
export class ButtonBlockConverter extends BaseInputBlockConverter<typeof DeepnoteButtonMetadataSchema> {
190+
private readonly DEFAULT_BUTTON_CONFIG = DeepnoteButtonMetadataSchema.parse({});
191+
192+
schema() {
193+
return DeepnoteButtonMetadataSchema;
194+
}
195+
getSupportedType() {
196+
return 'button';
197+
}
198+
defaultConfig() {
199+
return this.DEFAULT_BUTTON_CONFIG;
200+
}
201+
}

0 commit comments

Comments
 (0)