jupyterlab_tabular_data_viewer_extension 1.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +29 -0
- package/README.md +145 -0
- package/lib/document.d.ts +8 -0
- package/lib/document.js +9 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +214 -0
- package/lib/request.d.ts +8 -0
- package/lib/request.js +35 -0
- package/lib/widget.d.ts +127 -0
- package/lib/widget.js +644 -0
- package/package.json +217 -0
- package/schema/plugin.json +32 -0
- package/src/__tests__/jupyterlab_tabular_data_viewer_extension.spec.ts +9 -0
- package/src/document.ts +11 -0
- package/src/index.ts +276 -0
- package/src/request.ts +46 -0
- package/src/widget.ts +787 -0
- package/style/base.css +269 -0
- package/style/index.css +1 -0
- package/style/index.js +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jupyterlab_tabular_data_viewer_extension",
|
|
3
|
+
"version": "1.1.20",
|
|
4
|
+
"description": "Jupyterlab extension to browse tabular data files (Parquet, Excel, CSV, TSV) with filtering and sorting capabilities",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jupyter",
|
|
7
|
+
"jupyterlab",
|
|
8
|
+
"jupyterlab-extension",
|
|
9
|
+
"parquet",
|
|
10
|
+
"excel",
|
|
11
|
+
"csv",
|
|
12
|
+
"tsv",
|
|
13
|
+
"tabular-data"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/stellarshenson/jupyterlab_tabular_data_viewer_extension",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/stellarshenson/jupyterlab_tabular_data_viewer_extension/issues"
|
|
18
|
+
},
|
|
19
|
+
"license": "BSD-3-Clause",
|
|
20
|
+
"author": {
|
|
21
|
+
"name": "Stellars Henson",
|
|
22
|
+
"email": "konrad.jelen@gmail.com"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
|
|
26
|
+
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
|
|
27
|
+
"schema/*.json",
|
|
28
|
+
"src/**/*.{ts,tsx}"
|
|
29
|
+
],
|
|
30
|
+
"main": "lib/index.js",
|
|
31
|
+
"types": "lib/index.d.ts",
|
|
32
|
+
"style": "style/index.css",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/stellarshenson/jupyterlab_tabular_data_viewer_extension.git"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "jlpm build:lib && jlpm build:labextension:dev",
|
|
39
|
+
"build:prod": "jlpm clean && jlpm build:lib:prod && jlpm build:labextension",
|
|
40
|
+
"build:labextension": "jupyter labextension build .",
|
|
41
|
+
"build:labextension:dev": "jupyter labextension build --development True .",
|
|
42
|
+
"build:lib": "tsc --sourceMap",
|
|
43
|
+
"build:lib:prod": "tsc",
|
|
44
|
+
"clean": "jlpm clean:lib",
|
|
45
|
+
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
46
|
+
"clean:lintcache": "rimraf .eslintcache .stylelintcache",
|
|
47
|
+
"clean:labextension": "rimraf jupyterlab_tabular_data_viewer_extension/labextension jupyterlab_tabular_data_viewer_extension/_version.py",
|
|
48
|
+
"clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache",
|
|
49
|
+
"eslint": "jlpm eslint:check --fix",
|
|
50
|
+
"eslint:check": "eslint . --cache --ext .ts,.tsx",
|
|
51
|
+
"install:extension": "jlpm build",
|
|
52
|
+
"lint": "jlpm stylelint && jlpm prettier && jlpm eslint",
|
|
53
|
+
"lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check",
|
|
54
|
+
"prettier": "jlpm prettier:base --write --list-different",
|
|
55
|
+
"prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
|
|
56
|
+
"prettier:check": "jlpm prettier:base --check",
|
|
57
|
+
"stylelint": "jlpm stylelint:check --fix",
|
|
58
|
+
"stylelint:check": "stylelint --cache \"style/**/*.css\"",
|
|
59
|
+
"test": "jest --coverage",
|
|
60
|
+
"watch": "run-p watch:src watch:labextension",
|
|
61
|
+
"watch:src": "tsc -w --sourceMap",
|
|
62
|
+
"watch:labextension": "jupyter labextension watch ."
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@jupyterlab/application": "^4.0.0",
|
|
66
|
+
"@jupyterlab/apputils": "^4.0.0",
|
|
67
|
+
"@jupyterlab/coreutils": "^6.0.0",
|
|
68
|
+
"@jupyterlab/docregistry": "^4.0.0",
|
|
69
|
+
"@jupyterlab/services": "^7.0.0",
|
|
70
|
+
"@lumino/widgets": "^2.0.0",
|
|
71
|
+
"rimraf": "^6.1.0"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@jupyterlab/builder": "^4.0.0",
|
|
75
|
+
"@jupyterlab/testutils": "^4.0.0",
|
|
76
|
+
"@types/jest": "^29.2.0",
|
|
77
|
+
"@types/json-schema": "^7.0.11",
|
|
78
|
+
"@types/react": "^18.0.26",
|
|
79
|
+
"@types/react-addons-linked-state-mixin": "^0.14.22",
|
|
80
|
+
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
|
81
|
+
"@typescript-eslint/parser": "^6.1.0",
|
|
82
|
+
"css-loader": "^6.7.1",
|
|
83
|
+
"eslint": "^8.36.0",
|
|
84
|
+
"eslint-config-prettier": "^8.8.0",
|
|
85
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
86
|
+
"jest": "^29.2.0",
|
|
87
|
+
"mkdirp": "^1.0.3",
|
|
88
|
+
"npm-run-all2": "^7.0.1",
|
|
89
|
+
"prettier": "^3.0.0",
|
|
90
|
+
"source-map-loader": "^1.0.2",
|
|
91
|
+
"style-loader": "^3.3.1",
|
|
92
|
+
"stylelint": "^15.10.1",
|
|
93
|
+
"stylelint-config-recommended": "^13.0.0",
|
|
94
|
+
"stylelint-config-standard": "^34.0.0",
|
|
95
|
+
"stylelint-csstree-validator": "^3.0.0",
|
|
96
|
+
"stylelint-prettier": "^4.0.0",
|
|
97
|
+
"typescript": "~5.8.0",
|
|
98
|
+
"yjs": "^13.5.0"
|
|
99
|
+
},
|
|
100
|
+
"sideEffects": [
|
|
101
|
+
"style/*.css",
|
|
102
|
+
"style/index.js"
|
|
103
|
+
],
|
|
104
|
+
"styleModule": "style/index.js",
|
|
105
|
+
"publishConfig": {
|
|
106
|
+
"access": "public"
|
|
107
|
+
},
|
|
108
|
+
"jupyterlab": {
|
|
109
|
+
"discovery": {
|
|
110
|
+
"server": {
|
|
111
|
+
"managers": [
|
|
112
|
+
"pip"
|
|
113
|
+
],
|
|
114
|
+
"base": {
|
|
115
|
+
"name": "jupyterlab_tabular_data_viewer_extension"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"extension": true,
|
|
120
|
+
"outputDir": "jupyterlab_tabular_data_viewer_extension/labextension",
|
|
121
|
+
"schemaDir": "schema"
|
|
122
|
+
},
|
|
123
|
+
"eslintIgnore": [
|
|
124
|
+
"node_modules",
|
|
125
|
+
"dist",
|
|
126
|
+
"coverage",
|
|
127
|
+
"**/*.d.ts",
|
|
128
|
+
"tests",
|
|
129
|
+
"**/__tests__",
|
|
130
|
+
"ui-tests"
|
|
131
|
+
],
|
|
132
|
+
"eslintConfig": {
|
|
133
|
+
"extends": [
|
|
134
|
+
"eslint:recommended",
|
|
135
|
+
"plugin:@typescript-eslint/eslint-recommended",
|
|
136
|
+
"plugin:@typescript-eslint/recommended",
|
|
137
|
+
"plugin:prettier/recommended"
|
|
138
|
+
],
|
|
139
|
+
"parser": "@typescript-eslint/parser",
|
|
140
|
+
"parserOptions": {
|
|
141
|
+
"project": "tsconfig.json",
|
|
142
|
+
"sourceType": "module"
|
|
143
|
+
},
|
|
144
|
+
"plugins": [
|
|
145
|
+
"@typescript-eslint"
|
|
146
|
+
],
|
|
147
|
+
"rules": {
|
|
148
|
+
"@typescript-eslint/naming-convention": [
|
|
149
|
+
"error",
|
|
150
|
+
{
|
|
151
|
+
"selector": "interface",
|
|
152
|
+
"format": [
|
|
153
|
+
"PascalCase"
|
|
154
|
+
],
|
|
155
|
+
"custom": {
|
|
156
|
+
"regex": "^I[A-Z]",
|
|
157
|
+
"match": true
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
"@typescript-eslint/no-unused-vars": [
|
|
162
|
+
"warn",
|
|
163
|
+
{
|
|
164
|
+
"args": "none"
|
|
165
|
+
}
|
|
166
|
+
],
|
|
167
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
168
|
+
"@typescript-eslint/no-namespace": "off",
|
|
169
|
+
"@typescript-eslint/no-use-before-define": "off",
|
|
170
|
+
"@typescript-eslint/quotes": [
|
|
171
|
+
"error",
|
|
172
|
+
"single",
|
|
173
|
+
{
|
|
174
|
+
"avoidEscape": true,
|
|
175
|
+
"allowTemplateLiterals": false
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
"curly": [
|
|
179
|
+
"error",
|
|
180
|
+
"all"
|
|
181
|
+
],
|
|
182
|
+
"eqeqeq": "error",
|
|
183
|
+
"prefer-arrow-callback": "error"
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"prettier": {
|
|
187
|
+
"singleQuote": true,
|
|
188
|
+
"trailingComma": "none",
|
|
189
|
+
"arrowParens": "avoid",
|
|
190
|
+
"endOfLine": "auto",
|
|
191
|
+
"overrides": [
|
|
192
|
+
{
|
|
193
|
+
"files": "package.json",
|
|
194
|
+
"options": {
|
|
195
|
+
"tabWidth": 4
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
"stylelint": {
|
|
201
|
+
"extends": [
|
|
202
|
+
"stylelint-config-recommended",
|
|
203
|
+
"stylelint-config-standard",
|
|
204
|
+
"stylelint-prettier/recommended"
|
|
205
|
+
],
|
|
206
|
+
"plugins": [
|
|
207
|
+
"stylelint-csstree-validator"
|
|
208
|
+
],
|
|
209
|
+
"rules": {
|
|
210
|
+
"csstree/validator": true,
|
|
211
|
+
"property-no-vendor-prefix": null,
|
|
212
|
+
"selector-class-pattern": "^([a-z][A-z\\d]*)(-[A-z\\d]+)*$",
|
|
213
|
+
"selector-no-vendor-prefix": null,
|
|
214
|
+
"value-no-vendor-prefix": null
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Tabular Data Viewer Extension",
|
|
3
|
+
"description": "Settings for the Tabular Data Viewer Extension. Supports Parquet, Excel, CSV, and TSV files.",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"enableParquet": {
|
|
7
|
+
"title": "Enable Parquet files",
|
|
8
|
+
"description": "Use this extension to view .parquet files",
|
|
9
|
+
"type": "boolean",
|
|
10
|
+
"default": true
|
|
11
|
+
},
|
|
12
|
+
"enableExcel": {
|
|
13
|
+
"title": "Enable Excel files",
|
|
14
|
+
"description": "Use this extension to view .xlsx files",
|
|
15
|
+
"type": "boolean",
|
|
16
|
+
"default": true
|
|
17
|
+
},
|
|
18
|
+
"enableCSV": {
|
|
19
|
+
"title": "Enable CSV files",
|
|
20
|
+
"description": "Use this extension to view .csv files",
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"default": true
|
|
23
|
+
},
|
|
24
|
+
"enableTSV": {
|
|
25
|
+
"title": "Enable TSV files",
|
|
26
|
+
"description": "Use this extension to view .tsv files",
|
|
27
|
+
"type": "boolean",
|
|
28
|
+
"default": true
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"additionalProperties": false
|
|
32
|
+
}
|
package/src/document.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DocumentWidget } from '@jupyterlab/docregistry';
|
|
2
|
+
import { TabularDataViewer } from './widget';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A document widget for tabular data files (Parquet, Excel)
|
|
6
|
+
*/
|
|
7
|
+
export class TabularDataDocument extends DocumentWidget<TabularDataViewer> {
|
|
8
|
+
constructor(options: DocumentWidget.IOptions<TabularDataViewer>) {
|
|
9
|
+
super(options);
|
|
10
|
+
}
|
|
11
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JupyterFrontEnd,
|
|
3
|
+
JupyterFrontEndPlugin
|
|
4
|
+
} from '@jupyterlab/application';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
IDocumentWidget,
|
|
8
|
+
DocumentRegistry,
|
|
9
|
+
ABCWidgetFactory
|
|
10
|
+
} from '@jupyterlab/docregistry';
|
|
11
|
+
|
|
12
|
+
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
13
|
+
|
|
14
|
+
import { TabularDataViewer } from './widget';
|
|
15
|
+
import { TabularDataDocument } from './document';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A widget factory for Parquet files
|
|
19
|
+
*/
|
|
20
|
+
class TabularDataWidgetFactory extends ABCWidgetFactory<
|
|
21
|
+
IDocumentWidget<TabularDataViewer>
|
|
22
|
+
> {
|
|
23
|
+
private _setLastContextMenuRow: (row: any) => void;
|
|
24
|
+
private _setActiveWidget: (widget: TabularDataViewer) => void;
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
options: DocumentRegistry.IWidgetFactoryOptions,
|
|
28
|
+
setLastContextMenuRow: (row: any) => void,
|
|
29
|
+
setActiveWidget: (widget: TabularDataViewer) => void
|
|
30
|
+
) {
|
|
31
|
+
super(options);
|
|
32
|
+
this._setLastContextMenuRow = setLastContextMenuRow;
|
|
33
|
+
this._setActiveWidget = setActiveWidget;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create a new widget given a context
|
|
38
|
+
*/
|
|
39
|
+
protected createNewWidget(
|
|
40
|
+
context: DocumentRegistry.Context
|
|
41
|
+
): IDocumentWidget<TabularDataViewer> {
|
|
42
|
+
// console.log(`[Tabular Data Viewer] Creating widget for file: ${context.path}`);
|
|
43
|
+
// console.log(`[Tabular Data Viewer] File type: ${context.contentsModel?.type}, Format: ${context.contentsModel?.format}`);
|
|
44
|
+
|
|
45
|
+
const content = new TabularDataViewer(context.path, this._setLastContextMenuRow);
|
|
46
|
+
const widget = new TabularDataDocument({ content, context });
|
|
47
|
+
widget.title.label = context.path.split('/').pop() || 'Tabular Data File';
|
|
48
|
+
|
|
49
|
+
// Track this as the active widget when context menu is used
|
|
50
|
+
this._setActiveWidget(content);
|
|
51
|
+
|
|
52
|
+
return widget;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Settings interface
|
|
58
|
+
*/
|
|
59
|
+
interface ISettings {
|
|
60
|
+
enableParquet: boolean;
|
|
61
|
+
enableExcel: boolean;
|
|
62
|
+
enableCSV: boolean;
|
|
63
|
+
enableTSV: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Initialization data for the jupyterlab_tabular_data_viewer_extension extension.
|
|
68
|
+
*/
|
|
69
|
+
const plugin: JupyterFrontEndPlugin<void> = {
|
|
70
|
+
id: 'jupyterlab_tabular_data_viewer_extension:plugin',
|
|
71
|
+
description:
|
|
72
|
+
'Jupyterlab extension to allow simple browsing of tabular data files (Parquet, Excel) with filtering and sorting capabilities',
|
|
73
|
+
autoStart: true,
|
|
74
|
+
requires: [ISettingRegistry],
|
|
75
|
+
activate: async (app: JupyterFrontEnd, settingRegistry: ISettingRegistry) => {
|
|
76
|
+
// console.log(
|
|
77
|
+
// 'JupyterLab extension jupyterlab_tabular_data_viewer_extension is activated!'
|
|
78
|
+
// );
|
|
79
|
+
|
|
80
|
+
const { docRegistry, commands, contextMenu } = app;
|
|
81
|
+
|
|
82
|
+
// Track last right-clicked row for context menu
|
|
83
|
+
let lastContextMenuRow: any = null;
|
|
84
|
+
let activeWidget: TabularDataViewer | null = null;
|
|
85
|
+
|
|
86
|
+
// Load settings
|
|
87
|
+
let settings: ISettings = {
|
|
88
|
+
enableParquet: true,
|
|
89
|
+
enableExcel: true,
|
|
90
|
+
enableCSV: true,
|
|
91
|
+
enableTSV: true
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// console.log('[Tabular Data Viewer] Default settings:', settings);
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// console.log('[Tabular Data Viewer] Loading settings from registry with id:', plugin.id);
|
|
98
|
+
const pluginSettings = await settingRegistry.load(plugin.id);
|
|
99
|
+
settings = pluginSettings.composite as unknown as ISettings;
|
|
100
|
+
// console.log('[Tabular Data Viewer] Loaded settings:', settings);
|
|
101
|
+
// console.log('[Tabular Data Viewer] Settings detail - enableParquet:', settings.enableParquet, 'enableExcel:', settings.enableExcel);
|
|
102
|
+
|
|
103
|
+
// Watch for settings changes
|
|
104
|
+
pluginSettings.changed.connect(() => {
|
|
105
|
+
settings = pluginSettings.composite as unknown as ISettings;
|
|
106
|
+
// console.log('[Tabular Data Viewer] Settings changed:', settings);
|
|
107
|
+
});
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('[Tabular Data Viewer] Failed to load settings:', error);
|
|
110
|
+
// console.log('[Tabular Data Viewer] Using default settings:', settings);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Command to copy row as JSON
|
|
114
|
+
const copyRowCommand = 'tabular-data-viewer:copy-row-json';
|
|
115
|
+
commands.addCommand(copyRowCommand, {
|
|
116
|
+
label: 'Copy Row as JSON',
|
|
117
|
+
caption: 'Copy the row data as JSON to clipboard',
|
|
118
|
+
isEnabled: () => {
|
|
119
|
+
return lastContextMenuRow !== null;
|
|
120
|
+
},
|
|
121
|
+
execute: async () => {
|
|
122
|
+
if (lastContextMenuRow) {
|
|
123
|
+
const jsonString = JSON.stringify(lastContextMenuRow, null, 2);
|
|
124
|
+
await navigator.clipboard.writeText(jsonString);
|
|
125
|
+
// console.log('Row copied to clipboard as JSON');
|
|
126
|
+
|
|
127
|
+
// Clean up highlight after copy
|
|
128
|
+
if (activeWidget) {
|
|
129
|
+
activeWidget.getCleanupHighlight()();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Add to context menu for tabular data viewer rows
|
|
136
|
+
contextMenu.addItem({
|
|
137
|
+
command: copyRowCommand,
|
|
138
|
+
selector: '.jp-TabularDataViewer-row',
|
|
139
|
+
rank: 10
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Register file types based on settings
|
|
143
|
+
// console.log('[Tabular Data Viewer] Starting file type registration...');
|
|
144
|
+
// console.log('[Tabular Data Viewer] Current settings state:', settings);
|
|
145
|
+
const binaryFileTypes: string[] = [];
|
|
146
|
+
const textFileTypes: string[] = [];
|
|
147
|
+
|
|
148
|
+
// Register Parquet file type if enabled
|
|
149
|
+
if (settings.enableParquet) {
|
|
150
|
+
try {
|
|
151
|
+
docRegistry.addFileType({
|
|
152
|
+
name: 'parquet',
|
|
153
|
+
displayName: 'Parquet',
|
|
154
|
+
extensions: ['.parquet'],
|
|
155
|
+
mimeTypes: ['application/x-parquet'],
|
|
156
|
+
iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon',
|
|
157
|
+
contentType: 'file',
|
|
158
|
+
fileFormat: 'base64'
|
|
159
|
+
});
|
|
160
|
+
binaryFileTypes.push('parquet');
|
|
161
|
+
// console.log('[Tabular Data Viewer] Parquet file type registered');
|
|
162
|
+
} catch (e) {
|
|
163
|
+
console.warn('[Tabular Data Viewer] Parquet file type already registered', e);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Register Excel file type if enabled
|
|
168
|
+
if (settings.enableExcel) {
|
|
169
|
+
try {
|
|
170
|
+
docRegistry.addFileType({
|
|
171
|
+
name: 'xlsx-parquet-viewer',
|
|
172
|
+
displayName: 'Excel (Parquet Viewer)',
|
|
173
|
+
extensions: ['.xlsx'],
|
|
174
|
+
mimeTypes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
|
|
175
|
+
iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon',
|
|
176
|
+
contentType: 'file',
|
|
177
|
+
fileFormat: 'base64'
|
|
178
|
+
});
|
|
179
|
+
binaryFileTypes.push('xlsx-parquet-viewer');
|
|
180
|
+
// console.log('[Tabular Data Viewer] Excel file type registered');
|
|
181
|
+
} catch (e) {
|
|
182
|
+
console.warn('[Tabular Data Viewer] Excel file type already registered', e);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Register CSV file type if enabled
|
|
187
|
+
if (settings.enableCSV) {
|
|
188
|
+
try {
|
|
189
|
+
docRegistry.addFileType({
|
|
190
|
+
name: 'csv-tabular-viewer',
|
|
191
|
+
displayName: 'CSV (Tabular Viewer)',
|
|
192
|
+
extensions: ['.csv'],
|
|
193
|
+
mimeTypes: ['text/csv'],
|
|
194
|
+
iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon',
|
|
195
|
+
contentType: 'file',
|
|
196
|
+
fileFormat: 'text'
|
|
197
|
+
});
|
|
198
|
+
textFileTypes.push('csv-tabular-viewer');
|
|
199
|
+
// console.log('[Tabular Data Viewer] CSV file type registered');
|
|
200
|
+
} catch (e) {
|
|
201
|
+
console.warn('[Tabular Data Viewer] CSV file type already registered', e);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Register TSV file type if enabled
|
|
206
|
+
if (settings.enableTSV) {
|
|
207
|
+
try {
|
|
208
|
+
docRegistry.addFileType({
|
|
209
|
+
name: 'tsv-tabular-viewer',
|
|
210
|
+
displayName: 'TSV (Tabular Viewer)',
|
|
211
|
+
extensions: ['.tsv'],
|
|
212
|
+
mimeTypes: ['text/tab-separated-values'],
|
|
213
|
+
iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon',
|
|
214
|
+
contentType: 'file',
|
|
215
|
+
fileFormat: 'text'
|
|
216
|
+
});
|
|
217
|
+
textFileTypes.push('tsv-tabular-viewer');
|
|
218
|
+
// console.log('[Tabular Data Viewer] TSV file type registered');
|
|
219
|
+
} catch (e) {
|
|
220
|
+
console.warn('[Tabular Data Viewer] TSV file type already registered', e);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Create binary factory for Parquet and Excel files
|
|
225
|
+
if (binaryFileTypes.length > 0) {
|
|
226
|
+
const binaryFactory = new TabularDataWidgetFactory(
|
|
227
|
+
{
|
|
228
|
+
name: 'Tabular Data Viewer (Binary)',
|
|
229
|
+
modelName: 'base64',
|
|
230
|
+
fileTypes: binaryFileTypes,
|
|
231
|
+
defaultFor: binaryFileTypes,
|
|
232
|
+
defaultRendered: binaryFileTypes,
|
|
233
|
+
readOnly: true
|
|
234
|
+
},
|
|
235
|
+
(row: any) => {
|
|
236
|
+
lastContextMenuRow = row;
|
|
237
|
+
},
|
|
238
|
+
(widget: TabularDataViewer) => {
|
|
239
|
+
activeWidget = widget;
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
docRegistry.addWidgetFactory(binaryFactory);
|
|
244
|
+
// console.log(`[Tabular Data Viewer] Binary factory registered for: ${binaryFileTypes.join(', ')}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Create text factory for CSV and TSV files
|
|
248
|
+
if (textFileTypes.length > 0) {
|
|
249
|
+
const textFactory = new TabularDataWidgetFactory(
|
|
250
|
+
{
|
|
251
|
+
name: 'Tabular Data Viewer (Text)',
|
|
252
|
+
modelName: 'text',
|
|
253
|
+
fileTypes: textFileTypes,
|
|
254
|
+
defaultFor: textFileTypes,
|
|
255
|
+
defaultRendered: textFileTypes,
|
|
256
|
+
readOnly: true
|
|
257
|
+
},
|
|
258
|
+
(row: any) => {
|
|
259
|
+
lastContextMenuRow = row;
|
|
260
|
+
},
|
|
261
|
+
(widget: TabularDataViewer) => {
|
|
262
|
+
activeWidget = widget;
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
docRegistry.addWidgetFactory(textFactory);
|
|
267
|
+
// console.log(`[Tabular Data Viewer] Text factory registered for: ${textFileTypes.join(', ')}`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (binaryFileTypes.length === 0 && textFileTypes.length === 0) {
|
|
271
|
+
console.warn('[Tabular Data Viewer] No file types enabled in settings');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
export default plugin;
|
package/src/request.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { URLExt } from '@jupyterlab/coreutils';
|
|
2
|
+
|
|
3
|
+
import { ServerConnection } from '@jupyterlab/services';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Call the server extension
|
|
7
|
+
*
|
|
8
|
+
* @param endPoint API REST end point for the extension
|
|
9
|
+
* @param init Initial values for the request
|
|
10
|
+
* @returns The response body interpreted as JSON
|
|
11
|
+
*/
|
|
12
|
+
export async function requestAPI<T>(
|
|
13
|
+
endPoint = '',
|
|
14
|
+
init: RequestInit = {}
|
|
15
|
+
): Promise<T> {
|
|
16
|
+
// Make request to Jupyter API
|
|
17
|
+
const settings = ServerConnection.makeSettings();
|
|
18
|
+
const requestUrl = URLExt.join(
|
|
19
|
+
settings.baseUrl,
|
|
20
|
+
'jupyterlab-tabular-data-viewer-extension', // our server extension's API namespace
|
|
21
|
+
endPoint
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
let response: Response;
|
|
25
|
+
try {
|
|
26
|
+
response = await ServerConnection.makeRequest(requestUrl, init, settings);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
throw new ServerConnection.NetworkError(error as any);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let data: any = await response.text();
|
|
32
|
+
|
|
33
|
+
if (data.length > 0) {
|
|
34
|
+
try {
|
|
35
|
+
data = JSON.parse(data);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.log('Not a JSON response body.', response);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
throw new ServerConnection.ResponseError(response, data.message || data);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return data;
|
|
46
|
+
}
|