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/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Stellars Henson
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# jupyterlab_tabular_data_viewer_extension
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://www.npmjs.com/package/jupyterlab_tabular_data_viewer_extension)
|
|
5
|
+
[](https://pypi.org/project/jupyterlab-tabular-data-viewer-extension/)
|
|
6
|
+
[](https://pepy.tech/project/jupyterlab-tabular-data-viewer-extension)
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
View and browse Parquet, Excel, CSV, and TSV files directly in JupyterLab. Double-click any .parquet, .xlsx, .csv, or .tsv file to open it in a simple, spreadsheet-like table view - no code required. Navigate through your data, inspect values, and explore the structure of your tabular data files with interactive column resizing and advanced filtering capabilities.
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
**Supported File Formats:**
|
|
16
|
+
- **Parquet files** (.parquet) - Full support with efficient columnar data reading
|
|
17
|
+
- **Excel files** (.xlsx) - Reads first worksheet only. Excel files must be simple tabular data without merged cells, complex formulas, or advanced formatting. Files with these features may not display correctly or fail to load
|
|
18
|
+
- **CSV files** (.csv) - Comma-separated values with UTF-8 encoding (fallback to latin1)
|
|
19
|
+
- **TSV files** (.tsv) - Tab-separated values with UTF-8 encoding (fallback to latin1)
|
|
20
|
+
|
|
21
|
+
**Core viewing and navigation:**
|
|
22
|
+
- Simple table display showing your data in familiar spreadsheet format
|
|
23
|
+
- Column headers with field names and simplified datatype indicators
|
|
24
|
+
- Interactive column resizing - drag column borders to adjust width independently
|
|
25
|
+
- Progressive loading - starts with 500 rows, automatically loads more as you scroll
|
|
26
|
+
- File statistics (column count, row count, file size) at a glance
|
|
27
|
+
- Fixed status bar remains visible during horizontal scrolling
|
|
28
|
+
- Handles large files efficiently with server-side processing
|
|
29
|
+
|
|
30
|
+
**Advanced filtering and sorting:**
|
|
31
|
+
- Column sorting with three-state toggle (ascending, descending, off)
|
|
32
|
+
- Per-column filtering with substring or regex pattern matching
|
|
33
|
+
- Case-insensitive search option
|
|
34
|
+
- Numerical filters supporting comparison operators (`>`, `<`, `>=`, `<=`, `=`)
|
|
35
|
+
- Clear filters functionality to reset all active filters
|
|
36
|
+
- Multiple filters work together to narrow down results
|
|
37
|
+
|
|
38
|
+
**Additional features:**
|
|
39
|
+
- Right-click context menu on rows to copy data as JSON
|
|
40
|
+
- Configurable file type support via Settings - Enable/disable Parquet, Excel, or CSV/TSV handling
|
|
41
|
+
- All features work seamlessly across all supported file formats
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
Requires JupyterLab 4.0.0 or higher.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install jupyterlab_tabular_data_viewer_extension
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Uninstall:
|
|
52
|
+
```bash
|
|
53
|
+
pip uninstall jupyterlab_tabular_data_viewer_extension
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
Configure file type support through JupyterLab Settings:
|
|
59
|
+
|
|
60
|
+
1. Open **Settings → Settings Editor**
|
|
61
|
+
2. Search for "Parquet Viewer Extension"
|
|
62
|
+
3. Configure options:
|
|
63
|
+
- **Enable Parquet files** - Default: enabled
|
|
64
|
+
- **Enable Excel files** - Default: disabled (enable to view .xlsx files)
|
|
65
|
+
|
|
66
|
+
When a file type is disabled, files open with JupyterLab's default handler instead.
|
|
67
|
+
|
|
68
|
+
## Troubleshooting
|
|
69
|
+
|
|
70
|
+
Verify both extension components are enabled if the extension doesn't work:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Check server extension
|
|
74
|
+
jupyter server extension list
|
|
75
|
+
|
|
76
|
+
# Check frontend extension
|
|
77
|
+
jupyter labextension list
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Both commands should show `jupyterlab_tabular_data_viewer_extension` as enabled. Reinstall if either is missing or disabled.
|
|
81
|
+
|
|
82
|
+
## Development Setup
|
|
83
|
+
|
|
84
|
+
Requires NodeJS for building TypeScript frontend. Uses `jlpm` (JupyterLab's pinned yarn version) for consistency.
|
|
85
|
+
|
|
86
|
+
**Initial setup:**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Create virtual environment
|
|
90
|
+
python -m venv .venv
|
|
91
|
+
source .venv/bin/activate
|
|
92
|
+
|
|
93
|
+
# Install in editable mode
|
|
94
|
+
pip install --editable ".[dev,test]"
|
|
95
|
+
|
|
96
|
+
# Link frontend and enable server extension
|
|
97
|
+
jupyter labextension develop . --overwrite
|
|
98
|
+
jupyter server extension enable jupyterlab_tabular_data_viewer_extension
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Development workflow:**
|
|
102
|
+
|
|
103
|
+
Use two terminals for efficient development:
|
|
104
|
+
- Terminal 1: `jlpm watch` (auto-rebuild on file changes)
|
|
105
|
+
- Terminal 2: `jupyter lab` (run development instance)
|
|
106
|
+
|
|
107
|
+
Refresh browser after changes to see updates. Build generates source maps for debugging.
|
|
108
|
+
|
|
109
|
+
Enable deeper debugging with unminimized JupyterLab build:
|
|
110
|
+
```bash
|
|
111
|
+
jupyter lab build --minimize=False
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Removing development installation:**
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
jupyter server extension disable jupyterlab_tabular_data_viewer_extension
|
|
118
|
+
pip uninstall jupyterlab_tabular_data_viewer_extension
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Then delete the `jupyterlab_tabular_data_viewer_extension` symlink from your `labextensions` directory (find with `jupyter labextension list`).
|
|
122
|
+
|
|
123
|
+
## Testing
|
|
124
|
+
|
|
125
|
+
Three-tier testing strategy: Python backend, TypeScript frontend, and integration tests.
|
|
126
|
+
|
|
127
|
+
**Python tests** (pytest with coverage):
|
|
128
|
+
```bash
|
|
129
|
+
pip install -e ".[test]"
|
|
130
|
+
jupyter labextension develop . --overwrite
|
|
131
|
+
pytest -vv -r ap --cov jupyterlab_tabular_data_viewer_extension
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**TypeScript tests** (Jest):
|
|
135
|
+
```bash
|
|
136
|
+
jlpm
|
|
137
|
+
jlpm test
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Integration tests** (Playwright + Galata):
|
|
141
|
+
Simulates real user interactions to validate complete workflows. See [ui-tests README](./ui-tests/README.md) for detailed instructions.
|
|
142
|
+
|
|
143
|
+
## Packaging and Release
|
|
144
|
+
|
|
145
|
+
See [RELEASE.md](RELEASE.md) for instructions on building distributable packages and publishing releases.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DocumentWidget } from '@jupyterlab/docregistry';
|
|
2
|
+
import { TabularDataViewer } from './widget';
|
|
3
|
+
/**
|
|
4
|
+
* A document widget for tabular data files (Parquet, Excel)
|
|
5
|
+
*/
|
|
6
|
+
export declare class TabularDataDocument extends DocumentWidget<TabularDataViewer> {
|
|
7
|
+
constructor(options: DocumentWidget.IOptions<TabularDataViewer>);
|
|
8
|
+
}
|
package/lib/document.js
ADDED
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { ABCWidgetFactory } from '@jupyterlab/docregistry';
|
|
2
|
+
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
3
|
+
import { TabularDataViewer } from './widget';
|
|
4
|
+
import { TabularDataDocument } from './document';
|
|
5
|
+
/**
|
|
6
|
+
* A widget factory for Parquet files
|
|
7
|
+
*/
|
|
8
|
+
class TabularDataWidgetFactory extends ABCWidgetFactory {
|
|
9
|
+
constructor(options, setLastContextMenuRow, setActiveWidget) {
|
|
10
|
+
super(options);
|
|
11
|
+
this._setLastContextMenuRow = setLastContextMenuRow;
|
|
12
|
+
this._setActiveWidget = setActiveWidget;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create a new widget given a context
|
|
16
|
+
*/
|
|
17
|
+
createNewWidget(context) {
|
|
18
|
+
// console.log(`[Tabular Data Viewer] Creating widget for file: ${context.path}`);
|
|
19
|
+
// console.log(`[Tabular Data Viewer] File type: ${context.contentsModel?.type}, Format: ${context.contentsModel?.format}`);
|
|
20
|
+
const content = new TabularDataViewer(context.path, this._setLastContextMenuRow);
|
|
21
|
+
const widget = new TabularDataDocument({ content, context });
|
|
22
|
+
widget.title.label = context.path.split('/').pop() || 'Tabular Data File';
|
|
23
|
+
// Track this as the active widget when context menu is used
|
|
24
|
+
this._setActiveWidget(content);
|
|
25
|
+
return widget;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Initialization data for the jupyterlab_tabular_data_viewer_extension extension.
|
|
30
|
+
*/
|
|
31
|
+
const plugin = {
|
|
32
|
+
id: 'jupyterlab_tabular_data_viewer_extension:plugin',
|
|
33
|
+
description: 'Jupyterlab extension to allow simple browsing of tabular data files (Parquet, Excel) with filtering and sorting capabilities',
|
|
34
|
+
autoStart: true,
|
|
35
|
+
requires: [ISettingRegistry],
|
|
36
|
+
activate: async (app, settingRegistry) => {
|
|
37
|
+
// console.log(
|
|
38
|
+
// 'JupyterLab extension jupyterlab_tabular_data_viewer_extension is activated!'
|
|
39
|
+
// );
|
|
40
|
+
const { docRegistry, commands, contextMenu } = app;
|
|
41
|
+
// Track last right-clicked row for context menu
|
|
42
|
+
let lastContextMenuRow = null;
|
|
43
|
+
let activeWidget = null;
|
|
44
|
+
// Load settings
|
|
45
|
+
let settings = {
|
|
46
|
+
enableParquet: true,
|
|
47
|
+
enableExcel: true,
|
|
48
|
+
enableCSV: true,
|
|
49
|
+
enableTSV: true
|
|
50
|
+
};
|
|
51
|
+
// console.log('[Tabular Data Viewer] Default settings:', settings);
|
|
52
|
+
try {
|
|
53
|
+
// console.log('[Tabular Data Viewer] Loading settings from registry with id:', plugin.id);
|
|
54
|
+
const pluginSettings = await settingRegistry.load(plugin.id);
|
|
55
|
+
settings = pluginSettings.composite;
|
|
56
|
+
// console.log('[Tabular Data Viewer] Loaded settings:', settings);
|
|
57
|
+
// console.log('[Tabular Data Viewer] Settings detail - enableParquet:', settings.enableParquet, 'enableExcel:', settings.enableExcel);
|
|
58
|
+
// Watch for settings changes
|
|
59
|
+
pluginSettings.changed.connect(() => {
|
|
60
|
+
settings = pluginSettings.composite;
|
|
61
|
+
// console.log('[Tabular Data Viewer] Settings changed:', settings);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error('[Tabular Data Viewer] Failed to load settings:', error);
|
|
66
|
+
// console.log('[Tabular Data Viewer] Using default settings:', settings);
|
|
67
|
+
}
|
|
68
|
+
// Command to copy row as JSON
|
|
69
|
+
const copyRowCommand = 'tabular-data-viewer:copy-row-json';
|
|
70
|
+
commands.addCommand(copyRowCommand, {
|
|
71
|
+
label: 'Copy Row as JSON',
|
|
72
|
+
caption: 'Copy the row data as JSON to clipboard',
|
|
73
|
+
isEnabled: () => {
|
|
74
|
+
return lastContextMenuRow !== null;
|
|
75
|
+
},
|
|
76
|
+
execute: async () => {
|
|
77
|
+
if (lastContextMenuRow) {
|
|
78
|
+
const jsonString = JSON.stringify(lastContextMenuRow, null, 2);
|
|
79
|
+
await navigator.clipboard.writeText(jsonString);
|
|
80
|
+
// console.log('Row copied to clipboard as JSON');
|
|
81
|
+
// Clean up highlight after copy
|
|
82
|
+
if (activeWidget) {
|
|
83
|
+
activeWidget.getCleanupHighlight()();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// Add to context menu for tabular data viewer rows
|
|
89
|
+
contextMenu.addItem({
|
|
90
|
+
command: copyRowCommand,
|
|
91
|
+
selector: '.jp-TabularDataViewer-row',
|
|
92
|
+
rank: 10
|
|
93
|
+
});
|
|
94
|
+
// Register file types based on settings
|
|
95
|
+
// console.log('[Tabular Data Viewer] Starting file type registration...');
|
|
96
|
+
// console.log('[Tabular Data Viewer] Current settings state:', settings);
|
|
97
|
+
const binaryFileTypes = [];
|
|
98
|
+
const textFileTypes = [];
|
|
99
|
+
// Register Parquet file type if enabled
|
|
100
|
+
if (settings.enableParquet) {
|
|
101
|
+
try {
|
|
102
|
+
docRegistry.addFileType({
|
|
103
|
+
name: 'parquet',
|
|
104
|
+
displayName: 'Parquet',
|
|
105
|
+
extensions: ['.parquet'],
|
|
106
|
+
mimeTypes: ['application/x-parquet'],
|
|
107
|
+
iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon',
|
|
108
|
+
contentType: 'file',
|
|
109
|
+
fileFormat: 'base64'
|
|
110
|
+
});
|
|
111
|
+
binaryFileTypes.push('parquet');
|
|
112
|
+
// console.log('[Tabular Data Viewer] Parquet file type registered');
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
console.warn('[Tabular Data Viewer] Parquet file type already registered', e);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Register Excel file type if enabled
|
|
119
|
+
if (settings.enableExcel) {
|
|
120
|
+
try {
|
|
121
|
+
docRegistry.addFileType({
|
|
122
|
+
name: 'xlsx-parquet-viewer',
|
|
123
|
+
displayName: 'Excel (Parquet Viewer)',
|
|
124
|
+
extensions: ['.xlsx'],
|
|
125
|
+
mimeTypes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
|
|
126
|
+
iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon',
|
|
127
|
+
contentType: 'file',
|
|
128
|
+
fileFormat: 'base64'
|
|
129
|
+
});
|
|
130
|
+
binaryFileTypes.push('xlsx-parquet-viewer');
|
|
131
|
+
// console.log('[Tabular Data Viewer] Excel file type registered');
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
console.warn('[Tabular Data Viewer] Excel file type already registered', e);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Register CSV file type if enabled
|
|
138
|
+
if (settings.enableCSV) {
|
|
139
|
+
try {
|
|
140
|
+
docRegistry.addFileType({
|
|
141
|
+
name: 'csv-tabular-viewer',
|
|
142
|
+
displayName: 'CSV (Tabular Viewer)',
|
|
143
|
+
extensions: ['.csv'],
|
|
144
|
+
mimeTypes: ['text/csv'],
|
|
145
|
+
iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon',
|
|
146
|
+
contentType: 'file',
|
|
147
|
+
fileFormat: 'text'
|
|
148
|
+
});
|
|
149
|
+
textFileTypes.push('csv-tabular-viewer');
|
|
150
|
+
// console.log('[Tabular Data Viewer] CSV file type registered');
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
console.warn('[Tabular Data Viewer] CSV file type already registered', e);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Register TSV file type if enabled
|
|
157
|
+
if (settings.enableTSV) {
|
|
158
|
+
try {
|
|
159
|
+
docRegistry.addFileType({
|
|
160
|
+
name: 'tsv-tabular-viewer',
|
|
161
|
+
displayName: 'TSV (Tabular Viewer)',
|
|
162
|
+
extensions: ['.tsv'],
|
|
163
|
+
mimeTypes: ['text/tab-separated-values'],
|
|
164
|
+
iconClass: 'jp-MaterialIcon jp-SpreadsheetIcon',
|
|
165
|
+
contentType: 'file',
|
|
166
|
+
fileFormat: 'text'
|
|
167
|
+
});
|
|
168
|
+
textFileTypes.push('tsv-tabular-viewer');
|
|
169
|
+
// console.log('[Tabular Data Viewer] TSV file type registered');
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
console.warn('[Tabular Data Viewer] TSV file type already registered', e);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Create binary factory for Parquet and Excel files
|
|
176
|
+
if (binaryFileTypes.length > 0) {
|
|
177
|
+
const binaryFactory = new TabularDataWidgetFactory({
|
|
178
|
+
name: 'Tabular Data Viewer (Binary)',
|
|
179
|
+
modelName: 'base64',
|
|
180
|
+
fileTypes: binaryFileTypes,
|
|
181
|
+
defaultFor: binaryFileTypes,
|
|
182
|
+
defaultRendered: binaryFileTypes,
|
|
183
|
+
readOnly: true
|
|
184
|
+
}, (row) => {
|
|
185
|
+
lastContextMenuRow = row;
|
|
186
|
+
}, (widget) => {
|
|
187
|
+
activeWidget = widget;
|
|
188
|
+
});
|
|
189
|
+
docRegistry.addWidgetFactory(binaryFactory);
|
|
190
|
+
// console.log(`[Tabular Data Viewer] Binary factory registered for: ${binaryFileTypes.join(', ')}`);
|
|
191
|
+
}
|
|
192
|
+
// Create text factory for CSV and TSV files
|
|
193
|
+
if (textFileTypes.length > 0) {
|
|
194
|
+
const textFactory = new TabularDataWidgetFactory({
|
|
195
|
+
name: 'Tabular Data Viewer (Text)',
|
|
196
|
+
modelName: 'text',
|
|
197
|
+
fileTypes: textFileTypes,
|
|
198
|
+
defaultFor: textFileTypes,
|
|
199
|
+
defaultRendered: textFileTypes,
|
|
200
|
+
readOnly: true
|
|
201
|
+
}, (row) => {
|
|
202
|
+
lastContextMenuRow = row;
|
|
203
|
+
}, (widget) => {
|
|
204
|
+
activeWidget = widget;
|
|
205
|
+
});
|
|
206
|
+
docRegistry.addWidgetFactory(textFactory);
|
|
207
|
+
// console.log(`[Tabular Data Viewer] Text factory registered for: ${textFileTypes.join(', ')}`);
|
|
208
|
+
}
|
|
209
|
+
if (binaryFileTypes.length === 0 && textFileTypes.length === 0) {
|
|
210
|
+
console.warn('[Tabular Data Viewer] No file types enabled in settings');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
export default plugin;
|
package/lib/request.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Call the server extension
|
|
3
|
+
*
|
|
4
|
+
* @param endPoint API REST end point for the extension
|
|
5
|
+
* @param init Initial values for the request
|
|
6
|
+
* @returns The response body interpreted as JSON
|
|
7
|
+
*/
|
|
8
|
+
export declare function requestAPI<T>(endPoint?: string, init?: RequestInit): Promise<T>;
|
package/lib/request.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { URLExt } from '@jupyterlab/coreutils';
|
|
2
|
+
import { ServerConnection } from '@jupyterlab/services';
|
|
3
|
+
/**
|
|
4
|
+
* Call the server extension
|
|
5
|
+
*
|
|
6
|
+
* @param endPoint API REST end point for the extension
|
|
7
|
+
* @param init Initial values for the request
|
|
8
|
+
* @returns The response body interpreted as JSON
|
|
9
|
+
*/
|
|
10
|
+
export async function requestAPI(endPoint = '', init = {}) {
|
|
11
|
+
// Make request to Jupyter API
|
|
12
|
+
const settings = ServerConnection.makeSettings();
|
|
13
|
+
const requestUrl = URLExt.join(settings.baseUrl, 'jupyterlab-tabular-data-viewer-extension', // our server extension's API namespace
|
|
14
|
+
endPoint);
|
|
15
|
+
let response;
|
|
16
|
+
try {
|
|
17
|
+
response = await ServerConnection.makeRequest(requestUrl, init, settings);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
throw new ServerConnection.NetworkError(error);
|
|
21
|
+
}
|
|
22
|
+
let data = await response.text();
|
|
23
|
+
if (data.length > 0) {
|
|
24
|
+
try {
|
|
25
|
+
data = JSON.parse(data);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.log('Not a JSON response body.', response);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
throw new ServerConnection.ResponseError(response, data.message || data);
|
|
33
|
+
}
|
|
34
|
+
return data;
|
|
35
|
+
}
|
package/lib/widget.d.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Widget } from '@lumino/widgets';
|
|
2
|
+
/**
|
|
3
|
+
* Parquet viewer widget
|
|
4
|
+
*/
|
|
5
|
+
export declare class TabularDataViewer extends Widget {
|
|
6
|
+
private _filePath;
|
|
7
|
+
private _columns;
|
|
8
|
+
private _data;
|
|
9
|
+
private _totalRows;
|
|
10
|
+
private _unfilteredTotalRows;
|
|
11
|
+
private _currentOffset;
|
|
12
|
+
private _limit;
|
|
13
|
+
private _loading;
|
|
14
|
+
private _hasMore;
|
|
15
|
+
private _filters;
|
|
16
|
+
private _sortBy;
|
|
17
|
+
private _sortOrder;
|
|
18
|
+
private _fileSize;
|
|
19
|
+
private _caseInsensitive;
|
|
20
|
+
private _useRegex;
|
|
21
|
+
private _contextMenuOpen;
|
|
22
|
+
private _columnWidths;
|
|
23
|
+
private _resizing;
|
|
24
|
+
private _tableContainer;
|
|
25
|
+
private _table;
|
|
26
|
+
private _thead;
|
|
27
|
+
private _tbody;
|
|
28
|
+
private _filterRow;
|
|
29
|
+
private _headerRow;
|
|
30
|
+
private _statusBar;
|
|
31
|
+
private _statusLeft;
|
|
32
|
+
private _statusRight;
|
|
33
|
+
private _caseInsensitiveCheckbox;
|
|
34
|
+
private _regexCheckbox;
|
|
35
|
+
private _setLastContextMenuRow;
|
|
36
|
+
private _cleanupHighlight;
|
|
37
|
+
private _menuObserver;
|
|
38
|
+
constructor(filePath: string, setLastContextMenuRow: (row: any) => void);
|
|
39
|
+
/**
|
|
40
|
+
* Start observing for menu removal when context menu opens
|
|
41
|
+
*/
|
|
42
|
+
private _startMenuObserver;
|
|
43
|
+
/**
|
|
44
|
+
* Get cleanup function to clear highlight (for external use)
|
|
45
|
+
*/
|
|
46
|
+
getCleanupHighlight(): () => void;
|
|
47
|
+
/**
|
|
48
|
+
* Initialize the viewer by loading metadata and initial data
|
|
49
|
+
*/
|
|
50
|
+
private _initialize;
|
|
51
|
+
/**
|
|
52
|
+
* Load file metadata (columns, types, row count)
|
|
53
|
+
*/
|
|
54
|
+
private _loadMetadata;
|
|
55
|
+
/**
|
|
56
|
+
* Load data from server
|
|
57
|
+
*/
|
|
58
|
+
private _loadData;
|
|
59
|
+
/**
|
|
60
|
+
* Render table headers with filter inputs
|
|
61
|
+
*/
|
|
62
|
+
private _renderHeaders;
|
|
63
|
+
/**
|
|
64
|
+
* Render data rows
|
|
65
|
+
*/
|
|
66
|
+
private _renderData;
|
|
67
|
+
/**
|
|
68
|
+
* Start column resize
|
|
69
|
+
*/
|
|
70
|
+
private _startResize;
|
|
71
|
+
/**
|
|
72
|
+
* Handle column resize drag
|
|
73
|
+
*/
|
|
74
|
+
private _doResize;
|
|
75
|
+
/**
|
|
76
|
+
* Stop column resize
|
|
77
|
+
*/
|
|
78
|
+
private _stopResize;
|
|
79
|
+
/**
|
|
80
|
+
* Apply filter to a column
|
|
81
|
+
*/
|
|
82
|
+
private _applyFilter;
|
|
83
|
+
/**
|
|
84
|
+
* Simplify type names for display
|
|
85
|
+
*/
|
|
86
|
+
private _simplifyType;
|
|
87
|
+
/**
|
|
88
|
+
* Check if column type is numeric
|
|
89
|
+
*/
|
|
90
|
+
private _isNumericType;
|
|
91
|
+
/**
|
|
92
|
+
* Get filter placeholder based on column type
|
|
93
|
+
*/
|
|
94
|
+
private _getFilterPlaceholder;
|
|
95
|
+
/**
|
|
96
|
+
* Handle scroll event for progressive loading
|
|
97
|
+
*/
|
|
98
|
+
private _onScroll;
|
|
99
|
+
/**
|
|
100
|
+
* Toggle sort on a column
|
|
101
|
+
*/
|
|
102
|
+
private _toggleSort;
|
|
103
|
+
/**
|
|
104
|
+
* Update sort indicators in column headers
|
|
105
|
+
*/
|
|
106
|
+
private _updateSortIndicators;
|
|
107
|
+
/**
|
|
108
|
+
* Clear all filters
|
|
109
|
+
*/
|
|
110
|
+
private _clearFilters;
|
|
111
|
+
/**
|
|
112
|
+
* Format file size to human-readable string
|
|
113
|
+
*/
|
|
114
|
+
private _formatFileSize;
|
|
115
|
+
/**
|
|
116
|
+
* Update status bar
|
|
117
|
+
*/
|
|
118
|
+
private _updateStatusBar;
|
|
119
|
+
/**
|
|
120
|
+
* Show error message
|
|
121
|
+
*/
|
|
122
|
+
private _showError;
|
|
123
|
+
/**
|
|
124
|
+
* Dispose of the widget
|
|
125
|
+
*/
|
|
126
|
+
dispose(): void;
|
|
127
|
+
}
|