variable-explorer 0.1.0__py3-none-any.whl
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.
- variable_explorer/__init__.py +7 -0
- variable_explorer/_version.py +4 -0
- variable_explorer/kernel/__init__.py +5 -0
- variable_explorer/kernel/comm_handler.py +255 -0
- variable_explorer/kernel/data_provider.py +235 -0
- variable_explorer/kernel/editor.py +88 -0
- variable_explorer/kernel/introspection.py +186 -0
- variable_explorer/kernel/serialization.py +73 -0
- variable_explorer/kernel/sorter.py +34 -0
- variable_explorer/kernel/statistics.py +101 -0
- variable_explorer/labextension/build_log.json +726 -0
- variable_explorer/labextension/package.json +96 -0
- variable_explorer/labextension/schemas/variable-explorer/package.json.orig +91 -0
- variable_explorer/labextension/schemas/variable-explorer/plugin.json +75 -0
- variable_explorer/labextension/static/lib_index_js.88a2cd3be0f2bf49f0eb.js +1417 -0
- variable_explorer/labextension/static/lib_index_js.88a2cd3be0f2bf49f0eb.js.map +1 -0
- variable_explorer/labextension/static/remoteEntry.a8ed3dcc7548f0b68f93.js +576 -0
- variable_explorer/labextension/static/remoteEntry.a8ed3dcc7548f0b68f93.js.map +1 -0
- variable_explorer/labextension/static/style.js +4 -0
- variable_explorer/labextension/static/style_index_js-data_font_woff2_charset_utf-8_base64_d09GMgABAAAAABmsAAsAAAAANbQAABlcAAEAAAAAA-5c9677.c69a59632d259bde8f84.js +785 -0
- variable_explorer/labextension/static/style_index_js-data_font_woff2_charset_utf-8_base64_d09GMgABAAAAABmsAAsAAAAANbQAABlcAAEAAAAAA-5c9677.c69a59632d259bde8f84.js.map +1 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-community_dist_package_main_esm_mjs.c38425b170e91e5db052.js +50347 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-community_dist_package_main_esm_mjs.c38425b170e91e5db052.js.map +1 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-community_styles_ag-grid_css-node_modules_ag-grid-community_styl-7d25f0.7424d30423d9f1c112f6.js +8124 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-community_styles_ag-grid_css-node_modules_ag-grid-community_styl-7d25f0.7424d30423d9f1c112f6.js.map +1 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-react_dist_package_index_esm_mjs.ca52d36c364e6562240a.js +2917 -0
- variable_explorer/labextension/static/vendors-node_modules_ag-grid-react_dist_package_index_esm_mjs.ca52d36c364e6562240a.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/build_log.json +726 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/install.json +5 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/package.json +96 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/schemas/variable-explorer/package.json.orig +91 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/schemas/variable-explorer/plugin.json +75 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/lib_index_js.88a2cd3be0f2bf49f0eb.js +1417 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/lib_index_js.88a2cd3be0f2bf49f0eb.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/remoteEntry.a8ed3dcc7548f0b68f93.js +576 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/remoteEntry.a8ed3dcc7548f0b68f93.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/style.js +4 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/style_index_js-data_font_woff2_charset_utf-8_base64_d09GMgABAAAAABmsAAsAAAAANbQAABlcAAEAAAAAA-5c9677.c69a59632d259bde8f84.js +785 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/style_index_js-data_font_woff2_charset_utf-8_base64_d09GMgABAAAAABmsAAsAAAAANbQAABlcAAEAAAAAA-5c9677.c69a59632d259bde8f84.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-community_dist_package_main_esm_mjs.c38425b170e91e5db052.js +50347 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-community_dist_package_main_esm_mjs.c38425b170e91e5db052.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-community_styles_ag-grid_css-node_modules_ag-grid-community_styl-7d25f0.7424d30423d9f1c112f6.js +8124 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-community_styles_ag-grid_css-node_modules_ag-grid-community_styl-7d25f0.7424d30423d9f1c112f6.js.map +1 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-react_dist_package_index_esm_mjs.ca52d36c364e6562240a.js +2917 -0
- variable_explorer-0.1.0.data/data/share/jupyter/labextensions/variable-explorer/static/vendors-node_modules_ag-grid-react_dist_package_index_esm_mjs.ca52d36c364e6562240a.js.map +1 -0
- variable_explorer-0.1.0.dist-info/METADATA +80 -0
- variable_explorer-0.1.0.dist-info/RECORD +49 -0
- variable_explorer-0.1.0.dist-info/WHEEL +4 -0
- variable_explorer-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,1417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
(self["webpackChunkvariable_explorer"] = self["webpackChunkvariable_explorer"] || []).push([["lib_index_js"],{
|
|
3
|
+
|
|
4
|
+
/***/ "./lib/comm/CommManager.js"
|
|
5
|
+
/*!*********************************!*\
|
|
6
|
+
!*** ./lib/comm/CommManager.js ***!
|
|
7
|
+
\*********************************/
|
|
8
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
9
|
+
|
|
10
|
+
__webpack_require__.r(__webpack_exports__);
|
|
11
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
12
|
+
/* harmony export */ CommManager: () => (/* binding */ CommManager)
|
|
13
|
+
/* harmony export */ });
|
|
14
|
+
/* harmony import */ var _lumino_signaling__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @lumino/signaling */ "webpack/sharing/consume/default/@lumino/signaling");
|
|
15
|
+
/* harmony import */ var _lumino_signaling__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_lumino_signaling__WEBPACK_IMPORTED_MODULE_0__);
|
|
16
|
+
|
|
17
|
+
const COMM_TARGET = 'variable_explorer';
|
|
18
|
+
const INIT_CODE = `
|
|
19
|
+
try:
|
|
20
|
+
from variable_explorer.kernel import init_comm as _ve_init
|
|
21
|
+
_ve_init()
|
|
22
|
+
del _ve_init
|
|
23
|
+
except ImportError as e:
|
|
24
|
+
print(f"Variable Explorer: kernel package not found: {e}")
|
|
25
|
+
except Exception as e:
|
|
26
|
+
print(f"Variable Explorer: init error: {e}")
|
|
27
|
+
`.trim();
|
|
28
|
+
class CommManager {
|
|
29
|
+
constructor() {
|
|
30
|
+
this._comm = null;
|
|
31
|
+
this._kernel = null;
|
|
32
|
+
this._messageReceived = new _lumino_signaling__WEBPACK_IMPORTED_MODULE_0__.Signal(this);
|
|
33
|
+
this._connectionChanged = new _lumino_signaling__WEBPACK_IMPORTED_MODULE_0__.Signal(this);
|
|
34
|
+
this._isConnected = false;
|
|
35
|
+
}
|
|
36
|
+
get messageReceived() {
|
|
37
|
+
return this._messageReceived;
|
|
38
|
+
}
|
|
39
|
+
get connectionChanged() {
|
|
40
|
+
return this._connectionChanged;
|
|
41
|
+
}
|
|
42
|
+
get isConnected() {
|
|
43
|
+
return this._isConnected;
|
|
44
|
+
}
|
|
45
|
+
async connect(kernel) {
|
|
46
|
+
// Disconnect existing
|
|
47
|
+
this.disconnect();
|
|
48
|
+
this._kernel = kernel;
|
|
49
|
+
// Inject the Python init code
|
|
50
|
+
const future = kernel.requestExecute({
|
|
51
|
+
code: INIT_CODE,
|
|
52
|
+
silent: true,
|
|
53
|
+
store_history: false
|
|
54
|
+
});
|
|
55
|
+
await future.done;
|
|
56
|
+
// Open a comm from the frontend
|
|
57
|
+
this._comm = kernel.createComm(COMM_TARGET);
|
|
58
|
+
// Handle incoming messages
|
|
59
|
+
this._comm.onMsg = (msg) => {
|
|
60
|
+
const data = msg.content.data;
|
|
61
|
+
if (data && data.type) {
|
|
62
|
+
this._messageReceived.emit(data);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
this._comm.onClose = () => {
|
|
66
|
+
this._setConnected(false);
|
|
67
|
+
};
|
|
68
|
+
// Open the comm channel
|
|
69
|
+
await this._comm.open({}).done;
|
|
70
|
+
this._setConnected(true);
|
|
71
|
+
// Listen for kernel shutdown/restart
|
|
72
|
+
kernel.statusChanged.connect(this._onKernelStatus, this);
|
|
73
|
+
}
|
|
74
|
+
send(msg) {
|
|
75
|
+
if (this._comm && this._isConnected) {
|
|
76
|
+
this._comm.send(msg);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
refresh() {
|
|
80
|
+
this.send({ type: 'refresh' });
|
|
81
|
+
}
|
|
82
|
+
disconnect() {
|
|
83
|
+
if (this._kernel) {
|
|
84
|
+
this._kernel.statusChanged.disconnect(this._onKernelStatus, this);
|
|
85
|
+
}
|
|
86
|
+
if (this._comm) {
|
|
87
|
+
try {
|
|
88
|
+
this._comm.close({});
|
|
89
|
+
}
|
|
90
|
+
catch (_a) {
|
|
91
|
+
// Comm may already be closed
|
|
92
|
+
}
|
|
93
|
+
this._comm = null;
|
|
94
|
+
}
|
|
95
|
+
this._kernel = null;
|
|
96
|
+
this._setConnected(false);
|
|
97
|
+
}
|
|
98
|
+
_setConnected(connected) {
|
|
99
|
+
if (this._isConnected !== connected) {
|
|
100
|
+
this._isConnected = connected;
|
|
101
|
+
this._connectionChanged.emit(connected);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
_onKernelStatus(kernel, status) {
|
|
105
|
+
if (status === 'restarting' || status === 'dead') {
|
|
106
|
+
this._setConnected(false);
|
|
107
|
+
this._comm = null;
|
|
108
|
+
}
|
|
109
|
+
if (status === 'idle' && !this._isConnected && this._kernel) {
|
|
110
|
+
// Kernel restarted — try to reconnect
|
|
111
|
+
this.connect(this._kernel).catch(e => {
|
|
112
|
+
console.error('Variable Explorer: reconnect failed', e);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/***/ },
|
|
120
|
+
|
|
121
|
+
/***/ "./lib/components/CellReferenceBar.js"
|
|
122
|
+
/*!********************************************!*\
|
|
123
|
+
!*** ./lib/components/CellReferenceBar.js ***!
|
|
124
|
+
\********************************************/
|
|
125
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
126
|
+
|
|
127
|
+
__webpack_require__.r(__webpack_exports__);
|
|
128
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
129
|
+
/* harmony export */ CellReferenceBar: () => (/* binding */ CellReferenceBar)
|
|
130
|
+
/* harmony export */ });
|
|
131
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
132
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
133
|
+
|
|
134
|
+
const CellReferenceBar = ({ rowIndex, colName, value }) => {
|
|
135
|
+
const displayValue = value == null ? 'null' : String(value);
|
|
136
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-cell-reference-bar" },
|
|
137
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-cell-location" },
|
|
138
|
+
"Row ",
|
|
139
|
+
rowIndex.toLocaleString(),
|
|
140
|
+
" / Col: ",
|
|
141
|
+
colName),
|
|
142
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-cell-value", title: displayValue }, displayValue)));
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
/***/ },
|
|
147
|
+
|
|
148
|
+
/***/ "./lib/components/DataGrid.js"
|
|
149
|
+
/*!************************************!*\
|
|
150
|
+
!*** ./lib/components/DataGrid.js ***!
|
|
151
|
+
\************************************/
|
|
152
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
153
|
+
|
|
154
|
+
__webpack_require__.r(__webpack_exports__);
|
|
155
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
156
|
+
/* harmony export */ DataGrid: () => (/* binding */ DataGrid)
|
|
157
|
+
/* harmony export */ });
|
|
158
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
159
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
160
|
+
/* harmony import */ var ag_grid_react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ag-grid-react */ "webpack/sharing/consume/default/ag-grid-react/ag-grid-react");
|
|
161
|
+
/* harmony import */ var _HistogramHeader__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./HistogramHeader */ "./lib/components/HistogramHeader.js");
|
|
162
|
+
/* harmony import */ var _utils_colorScales__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils/colorScales */ "./lib/utils/colorScales.js");
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
const DataGrid = ({ rows, columns, columnStats, totalRows, sortModel, hiddenColumns, loading, onSortChanged, onLoadMore, onCellSelected, onCellEdit }) => {
|
|
168
|
+
const gridRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);
|
|
169
|
+
// Build a stats lookup map
|
|
170
|
+
const statsMap = react__WEBPACK_IMPORTED_MODULE_0__.useMemo(() => {
|
|
171
|
+
const map = {};
|
|
172
|
+
for (const s of columnStats) {
|
|
173
|
+
map[s.name] = s;
|
|
174
|
+
}
|
|
175
|
+
return map;
|
|
176
|
+
}, [columnStats]);
|
|
177
|
+
// Build AG Grid column definitions
|
|
178
|
+
const colDefs = react__WEBPACK_IMPORTED_MODULE_0__.useMemo(() => {
|
|
179
|
+
// Row index column
|
|
180
|
+
const indexCol = {
|
|
181
|
+
headerName: '#',
|
|
182
|
+
colId: '__index__',
|
|
183
|
+
valueGetter: (params) => {
|
|
184
|
+
var _a;
|
|
185
|
+
return ((_a = params.node) === null || _a === void 0 ? void 0 : _a.rowIndex) != null ? params.node.rowIndex : '';
|
|
186
|
+
},
|
|
187
|
+
width: 70,
|
|
188
|
+
pinned: 'left',
|
|
189
|
+
sortable: true,
|
|
190
|
+
resizable: false,
|
|
191
|
+
cellStyle: {
|
|
192
|
+
color: 'var(--jp-ui-font-color2)',
|
|
193
|
+
fontWeight: '500',
|
|
194
|
+
fontSize: '11px'
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const dataCols = columns
|
|
198
|
+
.filter(c => !hiddenColumns.has(c.name))
|
|
199
|
+
.map(col => {
|
|
200
|
+
const stats = statsMap[col.name];
|
|
201
|
+
const def = {
|
|
202
|
+
headerName: col.name,
|
|
203
|
+
field: col.name,
|
|
204
|
+
sortable: true,
|
|
205
|
+
resizable: true,
|
|
206
|
+
editable: true,
|
|
207
|
+
minWidth: 80,
|
|
208
|
+
headerComponent: _HistogramHeader__WEBPACK_IMPORTED_MODULE_2__.HistogramHeader,
|
|
209
|
+
headerComponentParams: {
|
|
210
|
+
displayName: col.name,
|
|
211
|
+
stats: stats
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
// Conditional formatting
|
|
215
|
+
if (col.isNumeric && (stats === null || stats === void 0 ? void 0 : stats.histogram) && stats.histogram.type === 'numeric') {
|
|
216
|
+
const h = stats.histogram;
|
|
217
|
+
def.cellStyle = (params) => {
|
|
218
|
+
if (params.value == null) {
|
|
219
|
+
return { backgroundColor: 'var(--jp-layout-color2)', opacity: 0.5 };
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
backgroundColor: (0,_utils_colorScales__WEBPACK_IMPORTED_MODULE_3__.numericHeatmap)(params.value, h.min, h.max),
|
|
223
|
+
color: 'var(--jp-ui-font-color0)'
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
else if (col.isBool) {
|
|
228
|
+
def.cellStyle = (params) => {
|
|
229
|
+
if (params.value == null) {
|
|
230
|
+
return { backgroundColor: 'var(--jp-layout-color2)', opacity: 0.5 };
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
backgroundColor: (0,_utils_colorScales__WEBPACK_IMPORTED_MODULE_3__.booleanColor)(params.value),
|
|
234
|
+
color: '#fff',
|
|
235
|
+
fontWeight: '600',
|
|
236
|
+
textAlign: 'center'
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
// Format numbers
|
|
241
|
+
if (col.isNumeric) {
|
|
242
|
+
def.valueFormatter = (params) => {
|
|
243
|
+
if (params.value == null)
|
|
244
|
+
return '';
|
|
245
|
+
const val = Number(params.value);
|
|
246
|
+
if (Number.isInteger(val))
|
|
247
|
+
return val.toLocaleString();
|
|
248
|
+
return val.toLocaleString(undefined, { maximumFractionDigits: 4 });
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
// Format dates
|
|
252
|
+
if (col.isDatetime) {
|
|
253
|
+
def.valueFormatter = (params) => {
|
|
254
|
+
if (params.value == null)
|
|
255
|
+
return '';
|
|
256
|
+
return new Date(params.value).toLocaleString();
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return def;
|
|
260
|
+
});
|
|
261
|
+
return [indexCol, ...dataCols];
|
|
262
|
+
}, [columns, statsMap, hiddenColumns]);
|
|
263
|
+
// Handle sort
|
|
264
|
+
const handleSortChanged = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((event) => {
|
|
265
|
+
const colState = event.api.getColumnState();
|
|
266
|
+
const sorted = colState.filter((c) => c.sort);
|
|
267
|
+
// If the index column (#) is being sorted, clear all sorts → reset to original order
|
|
268
|
+
if (sorted.some((c) => c.colId === '__index__')) {
|
|
269
|
+
event.api.applyColumnState({ defaultState: { sort: null } });
|
|
270
|
+
onSortChanged([]);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const newSortModel = sorted
|
|
274
|
+
.sort((a, b) => (a.sortIndex || 0) - (b.sortIndex || 0))
|
|
275
|
+
.map((c) => ({
|
|
276
|
+
colId: c.colId,
|
|
277
|
+
sort: c.sort
|
|
278
|
+
}));
|
|
279
|
+
onSortChanged(newSortModel);
|
|
280
|
+
}, [onSortChanged]);
|
|
281
|
+
// Handle cell click
|
|
282
|
+
const handleCellClicked = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((event) => {
|
|
283
|
+
if (event.colDef.field && event.rowIndex != null) {
|
|
284
|
+
onCellSelected(event.rowIndex, event.colDef.field, event.value);
|
|
285
|
+
}
|
|
286
|
+
}, [onCellSelected]);
|
|
287
|
+
// Handle cell edit
|
|
288
|
+
const handleCellEditRequest = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((event) => {
|
|
289
|
+
if (event.colDef.field && event.rowIndex != null) {
|
|
290
|
+
onCellEdit(event.rowIndex, event.colDef.field, String(event.newValue));
|
|
291
|
+
// Optimistic update
|
|
292
|
+
const rowNode = event.api.getRowNode(String(event.rowIndex));
|
|
293
|
+
if (rowNode) {
|
|
294
|
+
rowNode.setDataValue(event.colDef.field, event.newValue);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}, [onCellEdit]);
|
|
298
|
+
// Infinite scroll: load more rows when scrolled near bottom
|
|
299
|
+
const handleBodyScrollEnd = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((event) => {
|
|
300
|
+
if (loading)
|
|
301
|
+
return;
|
|
302
|
+
const lastRow = event.api.getLastDisplayedRow();
|
|
303
|
+
if (lastRow >= rows.length - 200 && rows.length < totalRows) {
|
|
304
|
+
onLoadMore(rows.length);
|
|
305
|
+
}
|
|
306
|
+
}, [loading, rows.length, totalRows, onLoadMore]);
|
|
307
|
+
// Detect JupyterLab dark theme
|
|
308
|
+
const isDark = document.body.getAttribute('data-jp-theme-light') === 'false';
|
|
309
|
+
const themeClass = isDark ? 'ag-theme-quartz-dark' : 'ag-theme-quartz';
|
|
310
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-grid-wrapper" },
|
|
311
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: themeClass, style: { width: '100%', height: '100%' } },
|
|
312
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement(ag_grid_react__WEBPACK_IMPORTED_MODULE_1__.AgGridReact, { ref: gridRef, rowData: rows, columnDefs: colDefs, defaultColDef: {
|
|
313
|
+
sortable: true,
|
|
314
|
+
resizable: true,
|
|
315
|
+
minWidth: 60
|
|
316
|
+
}, headerHeight: 64, rowHeight: 28, animateRows: false, suppressMovableColumns: false, readOnlyEdit: true, onSortChanged: handleSortChanged, onCellClicked: handleCellClicked, onCellEditRequest: handleCellEditRequest, onBodyScrollEnd: handleBodyScrollEnd, getRowId: (params) => { var _a, _b, _c; return String((_c = (_a = params.data.__row_index__) !== null && _a !== void 0 ? _a : (_b = params.node) === null || _b === void 0 ? void 0 : _b.rowIndex) !== null && _c !== void 0 ? _c : 0); }, loading: loading }))));
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
/***/ },
|
|
321
|
+
|
|
322
|
+
/***/ "./lib/components/HistogramHeader.js"
|
|
323
|
+
/*!*******************************************!*\
|
|
324
|
+
!*** ./lib/components/HistogramHeader.js ***!
|
|
325
|
+
\*******************************************/
|
|
326
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
327
|
+
|
|
328
|
+
__webpack_require__.r(__webpack_exports__);
|
|
329
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
330
|
+
/* harmony export */ HistogramHeader: () => (/* binding */ HistogramHeader)
|
|
331
|
+
/* harmony export */ });
|
|
332
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
333
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
334
|
+
/* harmony import */ var _utils_histogramRenderer__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/histogramRenderer */ "./lib/utils/histogramRenderer.js");
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
function getTooltipText(histogram, mouseX, mouseY, canvasWidth, canvasHeight) {
|
|
338
|
+
const fmt = (v) => {
|
|
339
|
+
if (Number.isInteger(v) && Math.abs(v) < 1e6)
|
|
340
|
+
return v.toLocaleString();
|
|
341
|
+
return v.toLocaleString(undefined, { maximumFractionDigits: 2 });
|
|
342
|
+
};
|
|
343
|
+
if (histogram.type === 'numeric') {
|
|
344
|
+
const { counts, edges } = histogram;
|
|
345
|
+
const binIndex = Math.floor((mouseX / canvasWidth) * counts.length);
|
|
346
|
+
if (binIndex < 0 || binIndex >= counts.length)
|
|
347
|
+
return null;
|
|
348
|
+
return `${fmt(edges[binIndex])} \u2013 ${fmt(edges[binIndex + 1])}: ${counts[binIndex].toLocaleString()}`;
|
|
349
|
+
}
|
|
350
|
+
if (histogram.type === 'categorical') {
|
|
351
|
+
const { labels, counts } = histogram;
|
|
352
|
+
const barCount = Math.min(labels.length, 8);
|
|
353
|
+
// Bars are drawn horizontally, stacked vertically
|
|
354
|
+
const barHeight = canvasHeight / barCount;
|
|
355
|
+
const barIndex = Math.floor(mouseY / barHeight);
|
|
356
|
+
if (barIndex < 0 || barIndex >= barCount)
|
|
357
|
+
return null;
|
|
358
|
+
return `${labels[barIndex]}: ${counts[barIndex].toLocaleString()}`;
|
|
359
|
+
}
|
|
360
|
+
if (histogram.type === 'boolean') {
|
|
361
|
+
const total = histogram.trueCount + histogram.falseCount + histogram.nullCount;
|
|
362
|
+
if (total === 0)
|
|
363
|
+
return null;
|
|
364
|
+
const trueWidth = (histogram.trueCount / total) * canvasWidth;
|
|
365
|
+
const falseWidth = (histogram.falseCount / total) * canvasWidth;
|
|
366
|
+
if (mouseX < trueWidth) {
|
|
367
|
+
return `True: ${histogram.trueCount.toLocaleString()} (${Math.round(100 * histogram.trueCount / total)}%)`;
|
|
368
|
+
}
|
|
369
|
+
else if (mouseX < trueWidth + falseWidth) {
|
|
370
|
+
return `False: ${histogram.falseCount.toLocaleString()} (${Math.round(100 * histogram.falseCount / total)}%)`;
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
return `Null: ${histogram.nullCount.toLocaleString()} (${Math.round(100 * histogram.nullCount / total)}%)`;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
const HistogramHeader = ({ displayName, stats, column, setSort, api }) => {
|
|
379
|
+
const canvasRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);
|
|
380
|
+
const tooltipRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);
|
|
381
|
+
const [sortState, setSortState] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);
|
|
382
|
+
const [tooltip, setTooltip] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);
|
|
383
|
+
// Draw histogram when stats change
|
|
384
|
+
react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
|
|
385
|
+
const canvas = canvasRef.current;
|
|
386
|
+
if (!canvas || !(stats === null || stats === void 0 ? void 0 : stats.histogram))
|
|
387
|
+
return;
|
|
388
|
+
(0,_utils_histogramRenderer__WEBPACK_IMPORTED_MODULE_1__.drawHistogram)(canvas, stats.histogram);
|
|
389
|
+
}, [stats]);
|
|
390
|
+
// Track sort state
|
|
391
|
+
react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
|
|
392
|
+
var _a;
|
|
393
|
+
if (!column || !api)
|
|
394
|
+
return;
|
|
395
|
+
const onSortChanged = () => {
|
|
396
|
+
var _a;
|
|
397
|
+
const colState = (_a = api.getColumnState) === null || _a === void 0 ? void 0 : _a.call(api);
|
|
398
|
+
if (colState) {
|
|
399
|
+
const myState = colState.find((s) => s.colId === column.getColId());
|
|
400
|
+
setSortState((myState === null || myState === void 0 ? void 0 : myState.sort) || null);
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
(_a = api.addEventListener) === null || _a === void 0 ? void 0 : _a.call(api, 'sortChanged', onSortChanged);
|
|
404
|
+
return () => {
|
|
405
|
+
var _a;
|
|
406
|
+
(_a = api.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(api, 'sortChanged', onSortChanged);
|
|
407
|
+
};
|
|
408
|
+
}, [column, api]);
|
|
409
|
+
const handleClick = (e) => {
|
|
410
|
+
if (!setSort)
|
|
411
|
+
return;
|
|
412
|
+
let nextSort;
|
|
413
|
+
if (sortState === null) {
|
|
414
|
+
nextSort = 'asc';
|
|
415
|
+
}
|
|
416
|
+
else if (sortState === 'asc') {
|
|
417
|
+
nextSort = 'desc';
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
nextSort = '';
|
|
421
|
+
}
|
|
422
|
+
setSort(nextSort, e.shiftKey);
|
|
423
|
+
};
|
|
424
|
+
const handleCanvasMouseMove = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((e) => {
|
|
425
|
+
if (!(stats === null || stats === void 0 ? void 0 : stats.histogram) || !canvasRef.current)
|
|
426
|
+
return;
|
|
427
|
+
const rect = canvasRef.current.getBoundingClientRect();
|
|
428
|
+
const mouseX = e.clientX - rect.left;
|
|
429
|
+
const mouseY = e.clientY - rect.top;
|
|
430
|
+
const text = getTooltipText(stats.histogram, mouseX, mouseY, rect.width, rect.height);
|
|
431
|
+
if (text) {
|
|
432
|
+
setTooltip({ text, x: e.clientX, y: rect.top - 4 });
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
setTooltip(null);
|
|
436
|
+
}
|
|
437
|
+
}, [stats]);
|
|
438
|
+
const handleCanvasMouseLeave = react__WEBPACK_IMPORTED_MODULE_0__.useCallback(() => {
|
|
439
|
+
setTooltip(null);
|
|
440
|
+
}, []);
|
|
441
|
+
const sortIcon = sortState === 'asc' ? ' \u25b2' : sortState === 'desc' ? ' \u25bc' : '';
|
|
442
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-histogram-header", style: { width: '100%' } },
|
|
443
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-header-label", onClick: handleClick, title: `Click to sort by ${displayName}` },
|
|
444
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, displayName),
|
|
445
|
+
sortIcon && react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-sort-icon" }, sortIcon)),
|
|
446
|
+
(stats === null || stats === void 0 ? void 0 : stats.histogram) && (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { style: { position: 'relative', width: '100%' } },
|
|
447
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("canvas", { ref: canvasRef, width: 120, height: 30, style: { width: '100%', height: '30px', cursor: 'crosshair' }, onMouseMove: handleCanvasMouseMove, onMouseLeave: handleCanvasMouseLeave }),
|
|
448
|
+
tooltip && (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { ref: tooltipRef, className: "ve-histogram-tooltip", style: { left: tooltip.x, top: tooltip.y, transform: 'translate(-50%, -100%)' } }, tooltip.text.split('\n').map((line, i) => (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { key: i }, line)))))))));
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
/***/ },
|
|
453
|
+
|
|
454
|
+
/***/ "./lib/components/MetadataSidebar.js"
|
|
455
|
+
/*!*******************************************!*\
|
|
456
|
+
!*** ./lib/components/MetadataSidebar.js ***!
|
|
457
|
+
\*******************************************/
|
|
458
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
459
|
+
|
|
460
|
+
__webpack_require__.r(__webpack_exports__);
|
|
461
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
462
|
+
/* harmony export */ MetadataSidebar: () => (/* binding */ MetadataSidebar)
|
|
463
|
+
/* harmony export */ });
|
|
464
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
465
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
466
|
+
|
|
467
|
+
function formatBytes(bytes) {
|
|
468
|
+
if (bytes < 1024)
|
|
469
|
+
return `${bytes} B`;
|
|
470
|
+
if (bytes < 1024 * 1024)
|
|
471
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
472
|
+
if (bytes < 1024 * 1024 * 1024)
|
|
473
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
474
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
475
|
+
}
|
|
476
|
+
const MetadataSidebar = ({ columns, columnStats, hiddenColumns, onToggleColumn, selectedVarInfo }) => {
|
|
477
|
+
var _a, _b, _c, _d;
|
|
478
|
+
const [filter, setFilter] = react__WEBPACK_IMPORTED_MODULE_0__.useState('');
|
|
479
|
+
const [selectedCol, setSelectedCol] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);
|
|
480
|
+
const [propertiesHeight, setPropertiesHeight] = react__WEBPACK_IMPORTED_MODULE_0__.useState(220);
|
|
481
|
+
const handleRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);
|
|
482
|
+
const statsMap = react__WEBPACK_IMPORTED_MODULE_0__.useMemo(() => {
|
|
483
|
+
const map = {};
|
|
484
|
+
for (const s of columnStats) {
|
|
485
|
+
map[s.name] = s;
|
|
486
|
+
}
|
|
487
|
+
return map;
|
|
488
|
+
}, [columnStats]);
|
|
489
|
+
const filtered = react__WEBPACK_IMPORTED_MODULE_0__.useMemo(() => {
|
|
490
|
+
if (!filter)
|
|
491
|
+
return columns;
|
|
492
|
+
const lower = filter.toLowerCase();
|
|
493
|
+
return columns.filter(c => c.name.toLowerCase().includes(lower));
|
|
494
|
+
}, [columns, filter]);
|
|
495
|
+
const selectedStats = selectedCol ? statsMap[selectedCol] : null;
|
|
496
|
+
const selectedColDef = selectedCol ? columns.find(c => c.name === selectedCol) : null;
|
|
497
|
+
// Horizontal resize for properties panel
|
|
498
|
+
const onHandleMouseDown = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((e) => {
|
|
499
|
+
var _a;
|
|
500
|
+
e.preventDefault();
|
|
501
|
+
e.stopPropagation();
|
|
502
|
+
const startY = e.clientY;
|
|
503
|
+
const baseHeight = propertiesHeight;
|
|
504
|
+
const doc = ((_a = handleRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument) || document;
|
|
505
|
+
const onMouseMove = (moveEvent) => {
|
|
506
|
+
moveEvent.preventDefault();
|
|
507
|
+
const delta = startY - moveEvent.clientY; // dragging up = increase height
|
|
508
|
+
setPropertiesHeight(Math.max(80, Math.min(500, baseHeight + delta)));
|
|
509
|
+
};
|
|
510
|
+
const onMouseUp = () => {
|
|
511
|
+
doc.removeEventListener('mousemove', onMouseMove);
|
|
512
|
+
doc.removeEventListener('mouseup', onMouseUp);
|
|
513
|
+
doc.body.style.cursor = '';
|
|
514
|
+
doc.body.style.userSelect = '';
|
|
515
|
+
};
|
|
516
|
+
doc.addEventListener('mousemove', onMouseMove);
|
|
517
|
+
doc.addEventListener('mouseup', onMouseUp);
|
|
518
|
+
doc.body.style.cursor = 'row-resize';
|
|
519
|
+
doc.body.style.userSelect = 'none';
|
|
520
|
+
}, [propertiesHeight]);
|
|
521
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-metadata-sidebar" },
|
|
522
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-metadata-header" },
|
|
523
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", null, "Columns"),
|
|
524
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { style: { fontSize: '11px', fontWeight: 'normal', opacity: 0.6 } }, columns.length)),
|
|
525
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("input", { className: "ve-metadata-search", type: "text", placeholder: "Filter columns...", value: filter, onChange: e => setFilter(e.target.value) }),
|
|
526
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-metadata-columns" }, filtered.map(col => {
|
|
527
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { key: col.name, className: "ve-metadata-column-item", onClick: () => setSelectedCol(col.name), style: {
|
|
528
|
+
cursor: 'pointer',
|
|
529
|
+
background: col.name === selectedCol ? 'var(--jp-layout-color2)' : undefined
|
|
530
|
+
} },
|
|
531
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("input", { type: "checkbox", checked: !hiddenColumns.has(col.name), onChange: () => onToggleColumn(col.name), onClick: e => e.stopPropagation() }),
|
|
532
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-col-name", title: col.name }, col.name),
|
|
533
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-col-type" }, col.dtype)));
|
|
534
|
+
})),
|
|
535
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { ref: handleRef, className: "ve-resize-handle-horizontal", onMouseDown: onHandleMouseDown }),
|
|
536
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-properties-panel", style: { height: propertiesHeight, minHeight: 80 } }, selectedStats && selectedColDef ? (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
537
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("h4", null,
|
|
538
|
+
"Column: ",
|
|
539
|
+
selectedCol),
|
|
540
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("table", { className: "ve-properties-table" },
|
|
541
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tbody", null,
|
|
542
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
543
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Name"),
|
|
544
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedColDef.name)),
|
|
545
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
546
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Type"),
|
|
547
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedColDef.dtype)),
|
|
548
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
549
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Nulls"),
|
|
550
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.nullCount.toLocaleString())),
|
|
551
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
552
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Unique"),
|
|
553
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.uniqueCount.toLocaleString())),
|
|
554
|
+
((_a = selectedStats.histogram) === null || _a === void 0 ? void 0 : _a.type) === 'numeric' && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
555
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
556
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Min"),
|
|
557
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.histogram.min.toLocaleString(undefined, { maximumFractionDigits: 4 }))),
|
|
558
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
559
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Max"),
|
|
560
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.histogram.max.toLocaleString(undefined, { maximumFractionDigits: 4 }))),
|
|
561
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
562
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Mean"),
|
|
563
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.histogram.mean.toLocaleString(undefined, { maximumFractionDigits: 4 }))),
|
|
564
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
565
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Std"),
|
|
566
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.histogram.std.toLocaleString(undefined, { maximumFractionDigits: 4 }))))),
|
|
567
|
+
((_b = selectedStats.histogram) === null || _b === void 0 ? void 0 : _b.type) === 'boolean' && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
568
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
569
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "True"),
|
|
570
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.histogram.trueCount.toLocaleString())),
|
|
571
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
572
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "False"),
|
|
573
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.histogram.falseCount.toLocaleString())))),
|
|
574
|
+
((_c = selectedStats.histogram) === null || _c === void 0 ? void 0 : _c.type) === 'categorical' && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
575
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
576
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Top values"),
|
|
577
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedStats.histogram.labels.slice(0, 5).map((label, i) => {
|
|
578
|
+
var _a;
|
|
579
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { key: i, style: { fontSize: '11px' } },
|
|
580
|
+
label,
|
|
581
|
+
": ",
|
|
582
|
+
selectedStats.histogram.type === 'categorical'
|
|
583
|
+
? (_a = selectedStats.histogram.counts[i]) === null || _a === void 0 ? void 0 : _a.toLocaleString()
|
|
584
|
+
: ''));
|
|
585
|
+
}))))))))) : selectedVarInfo ? (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
586
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("h4", null, "Dataset"),
|
|
587
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("table", { className: "ve-properties-table" },
|
|
588
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tbody", null,
|
|
589
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
590
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Name"),
|
|
591
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedVarInfo.name)),
|
|
592
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
593
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Type"),
|
|
594
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedVarInfo.typeName)),
|
|
595
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
596
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Shape"),
|
|
597
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, selectedVarInfo.shape.map(s => s.toLocaleString()).join(' \u00d7 '))),
|
|
598
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
599
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Memory"),
|
|
600
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, formatBytes(selectedVarInfo.memoryBytes))),
|
|
601
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
602
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Variables"),
|
|
603
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, columns.length)),
|
|
604
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("tr", null,
|
|
605
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, "Observations"),
|
|
606
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("td", null, (_d = selectedVarInfo.shape[0]) === null || _d === void 0 ? void 0 : _d.toLocaleString())))))) : (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { style: { fontSize: '12px', opacity: 0.5, textAlign: 'center', paddingTop: 12 } }, "Click a column for details")))));
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
/***/ },
|
|
611
|
+
|
|
612
|
+
/***/ "./lib/components/ResizeHandle.js"
|
|
613
|
+
/*!****************************************!*\
|
|
614
|
+
!*** ./lib/components/ResizeHandle.js ***!
|
|
615
|
+
\****************************************/
|
|
616
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
617
|
+
|
|
618
|
+
__webpack_require__.r(__webpack_exports__);
|
|
619
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
620
|
+
/* harmony export */ ResizeHandle: () => (/* binding */ ResizeHandle)
|
|
621
|
+
/* harmony export */ });
|
|
622
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
623
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
624
|
+
|
|
625
|
+
const ResizeHandle = ({ onResizeStart, onResize, direction, invert }) => {
|
|
626
|
+
const handleRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);
|
|
627
|
+
const onMouseDown = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((e) => {
|
|
628
|
+
var _a;
|
|
629
|
+
e.preventDefault();
|
|
630
|
+
e.stopPropagation();
|
|
631
|
+
const startX = e.clientX;
|
|
632
|
+
const baseWidth = onResizeStart();
|
|
633
|
+
// Use the ownerDocument so this works in detached popup windows
|
|
634
|
+
const doc = ((_a = handleRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument) || document;
|
|
635
|
+
const onMouseMove = (moveEvent) => {
|
|
636
|
+
moveEvent.preventDefault();
|
|
637
|
+
const delta = moveEvent.clientX - startX;
|
|
638
|
+
const newWidth = invert ? baseWidth - delta : baseWidth + delta;
|
|
639
|
+
onResize(newWidth);
|
|
640
|
+
};
|
|
641
|
+
const onMouseUp = () => {
|
|
642
|
+
doc.removeEventListener('mousemove', onMouseMove);
|
|
643
|
+
doc.removeEventListener('mouseup', onMouseUp);
|
|
644
|
+
doc.body.style.cursor = '';
|
|
645
|
+
doc.body.style.userSelect = '';
|
|
646
|
+
};
|
|
647
|
+
doc.addEventListener('mousemove', onMouseMove);
|
|
648
|
+
doc.addEventListener('mouseup', onMouseUp);
|
|
649
|
+
doc.body.style.cursor = 'col-resize';
|
|
650
|
+
doc.body.style.userSelect = 'none';
|
|
651
|
+
}, [onResizeStart, onResize, invert]);
|
|
652
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { ref: handleRef, className: "ve-resize-handle", onMouseDown: onMouseDown }));
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
/***/ },
|
|
657
|
+
|
|
658
|
+
/***/ "./lib/components/StatusBar.js"
|
|
659
|
+
/*!*************************************!*\
|
|
660
|
+
!*** ./lib/components/StatusBar.js ***!
|
|
661
|
+
\*************************************/
|
|
662
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
663
|
+
|
|
664
|
+
__webpack_require__.r(__webpack_exports__);
|
|
665
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
666
|
+
/* harmony export */ StatusBar: () => (/* binding */ StatusBar)
|
|
667
|
+
/* harmony export */ });
|
|
668
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
669
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
670
|
+
|
|
671
|
+
const StatusBar = ({ selectedVar, totalRows, totalCols, sortModel, connected }) => {
|
|
672
|
+
const sortDisplay = sortModel.length > 0
|
|
673
|
+
? sortModel.map(s => `${s.colId} ${s.sort}`).join(', ')
|
|
674
|
+
: 'none';
|
|
675
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-status-bar" },
|
|
676
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-status-item", style: { color: connected ? 'var(--jp-success-color1)' : 'var(--jp-error-color1)' } }, connected ? '\u25cf Connected' : '\u25cb Disconnected'),
|
|
677
|
+
selectedVar && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
678
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-status-separator" }, "|"),
|
|
679
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-status-item" },
|
|
680
|
+
"Vars: ",
|
|
681
|
+
totalCols),
|
|
682
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-status-separator" }, "|"),
|
|
683
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-status-item" },
|
|
684
|
+
"Obs: ",
|
|
685
|
+
totalRows.toLocaleString()),
|
|
686
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-status-separator" }, "|"),
|
|
687
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-status-item" },
|
|
688
|
+
"Sorted: ",
|
|
689
|
+
sortDisplay)))));
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
/***/ },
|
|
694
|
+
|
|
695
|
+
/***/ "./lib/components/VariableExplorerApp.js"
|
|
696
|
+
/*!***********************************************!*\
|
|
697
|
+
!*** ./lib/components/VariableExplorerApp.js ***!
|
|
698
|
+
\***********************************************/
|
|
699
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
700
|
+
|
|
701
|
+
__webpack_require__.r(__webpack_exports__);
|
|
702
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
703
|
+
/* harmony export */ VariableExplorerApp: () => (/* binding */ VariableExplorerApp)
|
|
704
|
+
/* harmony export */ });
|
|
705
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
706
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
707
|
+
/* harmony import */ var _VariableList__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./VariableList */ "./lib/components/VariableList.js");
|
|
708
|
+
/* harmony import */ var _DataGrid__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./DataGrid */ "./lib/components/DataGrid.js");
|
|
709
|
+
/* harmony import */ var _MetadataSidebar__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./MetadataSidebar */ "./lib/components/MetadataSidebar.js");
|
|
710
|
+
/* harmony import */ var _CellReferenceBar__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./CellReferenceBar */ "./lib/components/CellReferenceBar.js");
|
|
711
|
+
/* harmony import */ var _StatusBar__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./StatusBar */ "./lib/components/StatusBar.js");
|
|
712
|
+
/* harmony import */ var _ResizeHandle__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./ResizeHandle */ "./lib/components/ResizeHandle.js");
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
const VariableExplorerApp = ({ commManager }) => {
|
|
721
|
+
const [connected, setConnected] = react__WEBPACK_IMPORTED_MODULE_0__.useState(commManager.isConnected);
|
|
722
|
+
const [variables, setVariables] = react__WEBPACK_IMPORTED_MODULE_0__.useState([]);
|
|
723
|
+
const [selectedVar, setSelectedVar] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);
|
|
724
|
+
const [rows, setRows] = react__WEBPACK_IMPORTED_MODULE_0__.useState([]);
|
|
725
|
+
const [totalRows, setTotalRows] = react__WEBPACK_IMPORTED_MODULE_0__.useState(0);
|
|
726
|
+
const [columns, setColumns] = react__WEBPACK_IMPORTED_MODULE_0__.useState([]);
|
|
727
|
+
const [columnStats, setColumnStats] = react__WEBPACK_IMPORTED_MODULE_0__.useState([]);
|
|
728
|
+
const [sortModel, setSortModel] = react__WEBPACK_IMPORTED_MODULE_0__.useState([]);
|
|
729
|
+
const [cellSelection, setCellSelection] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);
|
|
730
|
+
const [showSidebar, setShowSidebar] = react__WEBPACK_IMPORTED_MODULE_0__.useState(true);
|
|
731
|
+
const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);
|
|
732
|
+
const [hiddenColumns, setHiddenColumns] = react__WEBPACK_IMPORTED_MODULE_0__.useState(new Set());
|
|
733
|
+
// Panel sizing
|
|
734
|
+
const [leftWidth, setLeftWidth] = react__WEBPACK_IMPORTED_MODULE_0__.useState(220);
|
|
735
|
+
const [rightWidth, setRightWidth] = react__WEBPACK_IMPORTED_MODULE_0__.useState(280);
|
|
736
|
+
const onLeftResizeStart = react__WEBPACK_IMPORTED_MODULE_0__.useCallback(() => leftWidth, [leftWidth]);
|
|
737
|
+
const onLeftResize = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((newWidth) => {
|
|
738
|
+
setLeftWidth(Math.max(120, Math.min(500, newWidth)));
|
|
739
|
+
}, []);
|
|
740
|
+
// For the right panel, dragging right = panel shrinks, so invert
|
|
741
|
+
const onRightResizeStart = react__WEBPACK_IMPORTED_MODULE_0__.useCallback(() => rightWidth, [rightWidth]);
|
|
742
|
+
const onRightResize = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((newWidth) => {
|
|
743
|
+
// ResizeHandle sends base + delta. For the right side,
|
|
744
|
+
// we want: base - delta = base - (newWidth - base) = 2*base - newWidth
|
|
745
|
+
// But we don't have base here. Instead, let's just negate in the component.
|
|
746
|
+
setRightWidth(Math.max(150, Math.min(500, newWidth)));
|
|
747
|
+
}, []);
|
|
748
|
+
// Listen for connection changes
|
|
749
|
+
react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
|
|
750
|
+
const onConnectionChanged = (_, isConnected) => {
|
|
751
|
+
setConnected(isConnected);
|
|
752
|
+
if (!isConnected) {
|
|
753
|
+
setVariables([]);
|
|
754
|
+
setSelectedVar(null);
|
|
755
|
+
setRows([]);
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
commManager.connectionChanged.connect(onConnectionChanged);
|
|
759
|
+
return () => {
|
|
760
|
+
commManager.connectionChanged.disconnect(onConnectionChanged);
|
|
761
|
+
};
|
|
762
|
+
}, [commManager]);
|
|
763
|
+
// Listen for kernel messages
|
|
764
|
+
react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
|
|
765
|
+
const onMessage = (_, msg) => {
|
|
766
|
+
switch (msg.type) {
|
|
767
|
+
case 'variable_list':
|
|
768
|
+
setVariables(msg.variables);
|
|
769
|
+
break;
|
|
770
|
+
case 'data_page': {
|
|
771
|
+
const dp = msg;
|
|
772
|
+
if (dp.startRow === 0) {
|
|
773
|
+
setRows(dp.rows);
|
|
774
|
+
}
|
|
775
|
+
else {
|
|
776
|
+
setRows(prev => [...prev, ...dp.rows]);
|
|
777
|
+
}
|
|
778
|
+
setTotalRows(dp.totalRows);
|
|
779
|
+
setColumns(dp.columns);
|
|
780
|
+
setLoading(false);
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
case 'column_stats': {
|
|
784
|
+
const cs = msg;
|
|
785
|
+
setColumnStats(cs.stats);
|
|
786
|
+
break;
|
|
787
|
+
}
|
|
788
|
+
case 'error':
|
|
789
|
+
console.error('Variable Explorer kernel error:', msg.message);
|
|
790
|
+
setLoading(false);
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
commManager.messageReceived.connect(onMessage);
|
|
795
|
+
return () => {
|
|
796
|
+
commManager.messageReceived.disconnect(onMessage);
|
|
797
|
+
};
|
|
798
|
+
}, [commManager]);
|
|
799
|
+
const onSelectVariable = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((name, childKey) => {
|
|
800
|
+
setSelectedVar(name);
|
|
801
|
+
setRows([]);
|
|
802
|
+
setSortModel([]);
|
|
803
|
+
setCellSelection(null);
|
|
804
|
+
setHiddenColumns(new Set());
|
|
805
|
+
setLoading(true);
|
|
806
|
+
commManager.send({
|
|
807
|
+
type: 'get_data',
|
|
808
|
+
variable: name,
|
|
809
|
+
startRow: 0,
|
|
810
|
+
endRow: 1000,
|
|
811
|
+
childKey
|
|
812
|
+
});
|
|
813
|
+
commManager.send({
|
|
814
|
+
type: 'get_stats',
|
|
815
|
+
variable: name
|
|
816
|
+
});
|
|
817
|
+
}, [commManager]);
|
|
818
|
+
const onLoadMore = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((startRow) => {
|
|
819
|
+
if (selectedVar) {
|
|
820
|
+
commManager.send({
|
|
821
|
+
type: 'get_data',
|
|
822
|
+
variable: selectedVar,
|
|
823
|
+
startRow,
|
|
824
|
+
endRow: startRow + 1000,
|
|
825
|
+
sortModel: sortModel.length > 0 ? sortModel : undefined
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
}, [commManager, selectedVar, sortModel]);
|
|
829
|
+
const onSortChanged = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((newSortModel) => {
|
|
830
|
+
setSortModel(newSortModel);
|
|
831
|
+
setRows([]);
|
|
832
|
+
setLoading(true);
|
|
833
|
+
if (selectedVar) {
|
|
834
|
+
commManager.send({
|
|
835
|
+
type: 'get_data',
|
|
836
|
+
variable: selectedVar,
|
|
837
|
+
startRow: 0,
|
|
838
|
+
endRow: 1000,
|
|
839
|
+
sortModel: newSortModel.length > 0 ? newSortModel : undefined
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
}, [commManager, selectedVar]);
|
|
843
|
+
const onCellSelected = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((rowIndex, colName, value) => {
|
|
844
|
+
setCellSelection({ rowIndex, colName, value });
|
|
845
|
+
}, []);
|
|
846
|
+
const onCellEdit = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((rowIndex, column, newValue) => {
|
|
847
|
+
if (selectedVar) {
|
|
848
|
+
commManager.send({
|
|
849
|
+
type: 'edit_cell',
|
|
850
|
+
variable: selectedVar,
|
|
851
|
+
rowIndex,
|
|
852
|
+
column,
|
|
853
|
+
newValue
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
}, [commManager, selectedVar]);
|
|
857
|
+
const onToggleColumn = react__WEBPACK_IMPORTED_MODULE_0__.useCallback((colName) => {
|
|
858
|
+
setHiddenColumns(prev => {
|
|
859
|
+
const next = new Set(prev);
|
|
860
|
+
if (next.has(colName)) {
|
|
861
|
+
next.delete(colName);
|
|
862
|
+
}
|
|
863
|
+
else {
|
|
864
|
+
next.add(colName);
|
|
865
|
+
}
|
|
866
|
+
return next;
|
|
867
|
+
});
|
|
868
|
+
}, []);
|
|
869
|
+
const onRefresh = react__WEBPACK_IMPORTED_MODULE_0__.useCallback(() => {
|
|
870
|
+
commManager.refresh();
|
|
871
|
+
if (selectedVar) {
|
|
872
|
+
onSelectVariable(selectedVar);
|
|
873
|
+
}
|
|
874
|
+
}, [commManager, selectedVar, onSelectVariable]);
|
|
875
|
+
const selectedVarInfo = variables.find(v => v.name === selectedVar);
|
|
876
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-main-container" },
|
|
877
|
+
cellSelection && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(_CellReferenceBar__WEBPACK_IMPORTED_MODULE_4__.CellReferenceBar, { rowIndex: cellSelection.rowIndex, colName: cellSelection.colName, value: cellSelection.value })),
|
|
878
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-content-area" },
|
|
879
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { style: { width: leftWidth, minWidth: 120, flexShrink: 0 } },
|
|
880
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement(_VariableList__WEBPACK_IMPORTED_MODULE_1__.VariableList, { variables: variables, selectedVar: selectedVar, onSelect: onSelectVariable })),
|
|
881
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement(_ResizeHandle__WEBPACK_IMPORTED_MODULE_6__.ResizeHandle, { direction: "horizontal", onResizeStart: onLeftResizeStart, onResize: onLeftResize }),
|
|
882
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-grid-container" },
|
|
883
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-grid-toolbar" },
|
|
884
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-toolbar-title" },
|
|
885
|
+
selectedVar || 'Select a variable',
|
|
886
|
+
selectedVarInfo && (react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { style: { fontWeight: 'normal', opacity: 0.6, marginLeft: 8, fontSize: '12px' } },
|
|
887
|
+
selectedVarInfo.typeName,
|
|
888
|
+
" (",
|
|
889
|
+
selectedVarInfo.shape.map(s => s.toLocaleString()).join(' \u00d7 '),
|
|
890
|
+
")"))),
|
|
891
|
+
selectedVar && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
892
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("button", { onClick: onRefresh, title: "Refresh data" }, "\u21BB Refresh"),
|
|
893
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("button", { onClick: () => setShowSidebar(!showSidebar), title: "Toggle metadata sidebar" },
|
|
894
|
+
showSidebar ? 'Hide' : 'Show',
|
|
895
|
+
" Metadata")))),
|
|
896
|
+
selectedVar && columns.length > 0 ? (react__WEBPACK_IMPORTED_MODULE_0__.createElement(_DataGrid__WEBPACK_IMPORTED_MODULE_2__.DataGrid, { rows: rows, columns: columns, columnStats: columnStats, totalRows: totalRows, sortModel: sortModel, hiddenColumns: hiddenColumns, loading: loading, onSortChanged: onSortChanged, onLoadMore: onLoadMore, onCellSelected: onCellSelected, onCellEdit: onCellEdit })) : (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-empty-state" }, loading ? (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-loading" },
|
|
897
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-spinner" }))) : !connected ? (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
898
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-empty-icon" }, "\uD83D\uDD0C"),
|
|
899
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", null, "Not connected to a kernel"),
|
|
900
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { style: { fontSize: '12px', marginTop: 8, opacity: 0.7 } }, "Open a notebook and run a cell to connect"))) : (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
901
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-empty-icon" }, "\uD83D\uDCCA"),
|
|
902
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", null, variables.length === 0
|
|
903
|
+
? 'No variables in kernel namespace'
|
|
904
|
+
: 'Select a DataFrame to view its contents')))))),
|
|
905
|
+
showSidebar && selectedVar && columnStats.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,
|
|
906
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement(_ResizeHandle__WEBPACK_IMPORTED_MODULE_6__.ResizeHandle, { direction: "horizontal", onResizeStart: onRightResizeStart, onResize: onRightResize, invert: true }),
|
|
907
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { style: { width: rightWidth, minWidth: 150, flexShrink: 0 } },
|
|
908
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement(_MetadataSidebar__WEBPACK_IMPORTED_MODULE_3__.MetadataSidebar, { columns: columns, columnStats: columnStats, hiddenColumns: hiddenColumns, onToggleColumn: onToggleColumn, selectedVarInfo: selectedVarInfo || null }))))),
|
|
909
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement(_StatusBar__WEBPACK_IMPORTED_MODULE_5__.StatusBar, { selectedVar: selectedVar, totalRows: totalRows, totalCols: columns.length, sortModel: sortModel, connected: connected })));
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
/***/ },
|
|
914
|
+
|
|
915
|
+
/***/ "./lib/components/VariableList.js"
|
|
916
|
+
/*!****************************************!*\
|
|
917
|
+
!*** ./lib/components/VariableList.js ***!
|
|
918
|
+
\****************************************/
|
|
919
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
920
|
+
|
|
921
|
+
__webpack_require__.r(__webpack_exports__);
|
|
922
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
923
|
+
/* harmony export */ VariableList: () => (/* binding */ VariableList)
|
|
924
|
+
/* harmony export */ });
|
|
925
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
926
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
927
|
+
|
|
928
|
+
function formatBytes(bytes) {
|
|
929
|
+
if (bytes < 1024)
|
|
930
|
+
return `${bytes} B`;
|
|
931
|
+
if (bytes < 1024 * 1024)
|
|
932
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
933
|
+
if (bytes < 1024 * 1024 * 1024)
|
|
934
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
935
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
936
|
+
}
|
|
937
|
+
function formatShape(shape) {
|
|
938
|
+
if (shape.length === 0)
|
|
939
|
+
return 'scalar';
|
|
940
|
+
if (shape.length === 1)
|
|
941
|
+
return `${shape[0].toLocaleString()} items`;
|
|
942
|
+
return shape.map(s => s.toLocaleString()).join(' \u00d7 ');
|
|
943
|
+
}
|
|
944
|
+
function getTypeBadgeClass(typeName) {
|
|
945
|
+
const lower = typeName.toLowerCase();
|
|
946
|
+
if (lower === 'dataframe')
|
|
947
|
+
return 've-type-dataframe';
|
|
948
|
+
if (lower === 'series')
|
|
949
|
+
return 've-type-series';
|
|
950
|
+
if (lower === 'ndarray')
|
|
951
|
+
return 've-type-ndarray';
|
|
952
|
+
if (lower === 'list' || lower === 'tuple')
|
|
953
|
+
return 've-type-list';
|
|
954
|
+
if (lower === 'dict')
|
|
955
|
+
return 've-type-dict';
|
|
956
|
+
return 've-type-other';
|
|
957
|
+
}
|
|
958
|
+
function getKindLabel(kind) {
|
|
959
|
+
switch (kind) {
|
|
960
|
+
case 'list_of_dicts': return 'records';
|
|
961
|
+
case 'list_of_lists': return 'matrix';
|
|
962
|
+
case 'list_of_dataframes': return 'container';
|
|
963
|
+
case 'dict_of_dataframes': return 'container';
|
|
964
|
+
case 'dict_of_lists': return 'table';
|
|
965
|
+
case 'dict_of_dicts': return 'nested';
|
|
966
|
+
case 'list_scalar': return 'values';
|
|
967
|
+
case 'dict_scalar': return 'record';
|
|
968
|
+
default: return '';
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
const VariableList = ({ variables, selectedVar, onSelect }) => {
|
|
972
|
+
const [filter, setFilter] = react__WEBPACK_IMPORTED_MODULE_0__.useState('');
|
|
973
|
+
const filtered = react__WEBPACK_IMPORTED_MODULE_0__.useMemo(() => {
|
|
974
|
+
if (!filter)
|
|
975
|
+
return variables;
|
|
976
|
+
const lower = filter.toLowerCase();
|
|
977
|
+
return variables.filter(v => v.name.toLowerCase().includes(lower) || v.typeName.toLowerCase().includes(lower));
|
|
978
|
+
}, [variables, filter]);
|
|
979
|
+
const sorted = react__WEBPACK_IMPORTED_MODULE_0__.useMemo(() => {
|
|
980
|
+
return [...filtered].sort((a, b) => {
|
|
981
|
+
if (a.isTabular !== b.isTabular)
|
|
982
|
+
return a.isTabular ? -1 : 1;
|
|
983
|
+
return a.name.localeCompare(b.name);
|
|
984
|
+
});
|
|
985
|
+
}, [filtered]);
|
|
986
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-variable-list" },
|
|
987
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-variable-list-header" },
|
|
988
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("input", { className: "ve-variable-search", type: "text", placeholder: "Filter objects...", value: filter, onChange: e => setFilter(e.target.value) })),
|
|
989
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-variable-items" }, sorted.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { style: { padding: '12px 8px', textAlign: 'center', opacity: 0.5, fontSize: '12px' } }, variables.length === 0 ? 'No variables' : 'No matches')) : (sorted.map(v => {
|
|
990
|
+
const kindLabel = getKindLabel(v.tabularKind);
|
|
991
|
+
return (react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { key: v.name, className: `ve-variable-item ${v.name === selectedVar ? 've-selected' : ''}`, onClick: () => v.isTabular && onSelect(v.name), style: { opacity: v.isTabular ? 1 : 0.6, cursor: v.isTabular ? 'pointer' : 'default' }, title: v.isTabular ? `Click to view ${v.name}` : `${v.name} (${v.typeName})` },
|
|
992
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' } },
|
|
993
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-var-name" }, v.name),
|
|
994
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: `ve-type-badge ${getTypeBadgeClass(v.typeName)}` }, v.typeName),
|
|
995
|
+
kindLabel && (react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", { className: "ve-kind-label" }, kindLabel))),
|
|
996
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("div", { className: "ve-var-meta" },
|
|
997
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", null, formatShape(v.shape)),
|
|
998
|
+
react__WEBPACK_IMPORTED_MODULE_0__.createElement("span", null, formatBytes(v.memoryBytes)))));
|
|
999
|
+
})))));
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
/***/ },
|
|
1004
|
+
|
|
1005
|
+
/***/ "./lib/index.js"
|
|
1006
|
+
/*!**********************!*\
|
|
1007
|
+
!*** ./lib/index.js ***!
|
|
1008
|
+
\**********************/
|
|
1009
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
1010
|
+
|
|
1011
|
+
__webpack_require__.r(__webpack_exports__);
|
|
1012
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1013
|
+
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
|
|
1014
|
+
/* harmony export */ });
|
|
1015
|
+
/* harmony import */ var _jupyterlab_notebook__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @jupyterlab/notebook */ "webpack/sharing/consume/default/@jupyterlab/notebook");
|
|
1016
|
+
/* harmony import */ var _jupyterlab_notebook__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_jupyterlab_notebook__WEBPACK_IMPORTED_MODULE_0__);
|
|
1017
|
+
/* harmony import */ var _jupyterlab_console__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @jupyterlab/console */ "webpack/sharing/consume/default/@jupyterlab/console");
|
|
1018
|
+
/* harmony import */ var _jupyterlab_console__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_jupyterlab_console__WEBPACK_IMPORTED_MODULE_1__);
|
|
1019
|
+
/* harmony import */ var _jupyterlab_apputils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @jupyterlab/apputils */ "webpack/sharing/consume/default/@jupyterlab/apputils");
|
|
1020
|
+
/* harmony import */ var _jupyterlab_apputils__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_jupyterlab_apputils__WEBPACK_IMPORTED_MODULE_2__);
|
|
1021
|
+
/* harmony import */ var _jupyterlab_ui_components__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @jupyterlab/ui-components */ "webpack/sharing/consume/default/@jupyterlab/ui-components");
|
|
1022
|
+
/* harmony import */ var _jupyterlab_ui_components__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_jupyterlab_ui_components__WEBPACK_IMPORTED_MODULE_3__);
|
|
1023
|
+
/* harmony import */ var _comm_CommManager__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./comm/CommManager */ "./lib/comm/CommManager.js");
|
|
1024
|
+
/* harmony import */ var _components_VariableExplorerApp__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/VariableExplorerApp */ "./lib/components/VariableExplorerApp.js");
|
|
1025
|
+
/* harmony import */ var _utils_stylesheetCloner__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./utils/stylesheetCloner */ "./lib/utils/stylesheetCloner.js");
|
|
1026
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
1027
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_7__);
|
|
1028
|
+
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! react-dom */ "webpack/sharing/consume/default/react-dom");
|
|
1029
|
+
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_8__);
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
const PLUGIN_ID = 'variable-explorer:plugin';
|
|
1040
|
+
const COMMAND_ID = 'variable-explorer:open';
|
|
1041
|
+
/**
|
|
1042
|
+
* Manages the detached Variable Explorer window and its React tree.
|
|
1043
|
+
*/
|
|
1044
|
+
class VariableExplorerManager {
|
|
1045
|
+
constructor() {
|
|
1046
|
+
this._commManager = new _comm_CommManager__WEBPACK_IMPORTED_MODULE_4__.CommManager();
|
|
1047
|
+
this._externalWindow = null;
|
|
1048
|
+
this._root = null;
|
|
1049
|
+
this._pollTimer = null;
|
|
1050
|
+
}
|
|
1051
|
+
get commManager() {
|
|
1052
|
+
return this._commManager;
|
|
1053
|
+
}
|
|
1054
|
+
get isOpen() {
|
|
1055
|
+
return this._externalWindow !== null && !this._externalWindow.closed;
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Open the Variable Explorer in a detached window.
|
|
1059
|
+
*/
|
|
1060
|
+
open() {
|
|
1061
|
+
if (this.isOpen) {
|
|
1062
|
+
this._externalWindow.focus();
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
const width = Math.min(1400, screen.availWidth * 0.8);
|
|
1066
|
+
const height = Math.min(900, screen.availHeight * 0.8);
|
|
1067
|
+
const left = Math.round((screen.availWidth - width) / 2);
|
|
1068
|
+
const top = Math.round((screen.availHeight - height) / 2);
|
|
1069
|
+
this._externalWindow = window.open('', 'variable-explorer', `width=${width},height=${height},left=${left},top=${top},menubar=no,toolbar=no,location=no,status=no,resizable=yes,scrollbars=no`);
|
|
1070
|
+
if (!this._externalWindow) {
|
|
1071
|
+
console.error('Variable Explorer: Popup blocked.');
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
const doc = this._externalWindow.document;
|
|
1075
|
+
doc.write(`<!DOCTYPE html>
|
|
1076
|
+
<html>
|
|
1077
|
+
<head>
|
|
1078
|
+
<meta charset="utf-8">
|
|
1079
|
+
<title>Variable Explorer</title>
|
|
1080
|
+
<style>
|
|
1081
|
+
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; }
|
|
1082
|
+
#ve-root { width: 100%; height: 100%; }
|
|
1083
|
+
</style>
|
|
1084
|
+
</head>
|
|
1085
|
+
<body>
|
|
1086
|
+
<div id="ve-root"></div>
|
|
1087
|
+
</body>
|
|
1088
|
+
</html>`);
|
|
1089
|
+
doc.close();
|
|
1090
|
+
(0,_utils_stylesheetCloner__WEBPACK_IMPORTED_MODULE_6__.cloneStylesheets)(document, doc);
|
|
1091
|
+
// Copy theme
|
|
1092
|
+
const parentBody = document.body;
|
|
1093
|
+
const childBody = doc.body;
|
|
1094
|
+
for (let i = 0; i < parentBody.attributes.length; i++) {
|
|
1095
|
+
const attr = parentBody.attributes[i];
|
|
1096
|
+
if (attr.name.startsWith('data-jp-')) {
|
|
1097
|
+
childBody.setAttribute(attr.name, attr.value);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
childBody.className = parentBody.className;
|
|
1101
|
+
const container = doc.getElementById('ve-root');
|
|
1102
|
+
react_dom__WEBPACK_IMPORTED_MODULE_8__.render(react__WEBPACK_IMPORTED_MODULE_7__.createElement(_components_VariableExplorerApp__WEBPACK_IMPORTED_MODULE_5__.VariableExplorerApp, {
|
|
1103
|
+
commManager: this._commManager,
|
|
1104
|
+
autoDetach: false
|
|
1105
|
+
}), container);
|
|
1106
|
+
this._root = container;
|
|
1107
|
+
this._pollTimer = window.setInterval(() => {
|
|
1108
|
+
if (this._externalWindow && this._externalWindow.closed) {
|
|
1109
|
+
this._cleanup();
|
|
1110
|
+
}
|
|
1111
|
+
}, 500);
|
|
1112
|
+
this._externalWindow.addEventListener('beforeunload', () => {
|
|
1113
|
+
this._cleanup();
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
_cleanup() {
|
|
1117
|
+
if (this._pollTimer !== null) {
|
|
1118
|
+
window.clearInterval(this._pollTimer);
|
|
1119
|
+
this._pollTimer = null;
|
|
1120
|
+
}
|
|
1121
|
+
if (this._root) {
|
|
1122
|
+
try {
|
|
1123
|
+
react_dom__WEBPACK_IMPORTED_MODULE_8__.unmountComponentAtNode(this._root);
|
|
1124
|
+
}
|
|
1125
|
+
catch ( /* */_a) { /* */ }
|
|
1126
|
+
this._root = null;
|
|
1127
|
+
}
|
|
1128
|
+
this._externalWindow = null;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
const plugin = {
|
|
1132
|
+
id: PLUGIN_ID,
|
|
1133
|
+
description: 'A Spyder/Stata-grade variable explorer for JupyterLab',
|
|
1134
|
+
autoStart: true,
|
|
1135
|
+
requires: [_jupyterlab_notebook__WEBPACK_IMPORTED_MODULE_0__.INotebookTracker],
|
|
1136
|
+
optional: [_jupyterlab_apputils__WEBPACK_IMPORTED_MODULE_2__.ICommandPalette, _jupyterlab_console__WEBPACK_IMPORTED_MODULE_1__.IConsoleTracker],
|
|
1137
|
+
activate: (app, notebookTracker, palette, consoleTracker) => {
|
|
1138
|
+
console.log('Variable Explorer extension activated');
|
|
1139
|
+
const manager = new VariableExplorerManager();
|
|
1140
|
+
const connectToKernel = async (kernel) => {
|
|
1141
|
+
if (!kernel)
|
|
1142
|
+
return;
|
|
1143
|
+
try {
|
|
1144
|
+
await manager.commManager.connect(kernel);
|
|
1145
|
+
}
|
|
1146
|
+
catch (e) {
|
|
1147
|
+
console.error('Variable Explorer: Failed to connect to kernel', e);
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
notebookTracker.currentChanged.connect(async (_, notebook) => {
|
|
1151
|
+
if (!notebook)
|
|
1152
|
+
return;
|
|
1153
|
+
const session = notebook.sessionContext;
|
|
1154
|
+
session.ready.then(() => {
|
|
1155
|
+
var _a;
|
|
1156
|
+
connectToKernel((_a = session.session) === null || _a === void 0 ? void 0 : _a.kernel);
|
|
1157
|
+
});
|
|
1158
|
+
session.kernelChanged.connect((_, args) => {
|
|
1159
|
+
if (args.newValue) {
|
|
1160
|
+
connectToKernel(args.newValue);
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
});
|
|
1164
|
+
if (consoleTracker) {
|
|
1165
|
+
consoleTracker.currentChanged.connect(async (_, consolePanel) => {
|
|
1166
|
+
if (!consolePanel)
|
|
1167
|
+
return;
|
|
1168
|
+
const session = consolePanel.sessionContext;
|
|
1169
|
+
session.ready.then(() => {
|
|
1170
|
+
var _a;
|
|
1171
|
+
connectToKernel((_a = session.session) === null || _a === void 0 ? void 0 : _a.kernel);
|
|
1172
|
+
});
|
|
1173
|
+
session.kernelChanged.connect((_, args) => {
|
|
1174
|
+
if (args.newValue) {
|
|
1175
|
+
connectToKernel(args.newValue);
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
// Register command — the schema declares this as a toolbar button + menu item
|
|
1181
|
+
app.commands.addCommand(COMMAND_ID, {
|
|
1182
|
+
label: 'Variable Explorer',
|
|
1183
|
+
caption: 'Open Variable Explorer in a separate window',
|
|
1184
|
+
icon: _jupyterlab_ui_components__WEBPACK_IMPORTED_MODULE_3__.spreadsheetIcon,
|
|
1185
|
+
execute: () => {
|
|
1186
|
+
var _a;
|
|
1187
|
+
manager.open();
|
|
1188
|
+
const currentNotebook = notebookTracker.currentWidget;
|
|
1189
|
+
if (currentNotebook) {
|
|
1190
|
+
const kernel = (_a = currentNotebook.sessionContext.session) === null || _a === void 0 ? void 0 : _a.kernel;
|
|
1191
|
+
connectToKernel(kernel);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
if (palette) {
|
|
1196
|
+
palette.addItem({
|
|
1197
|
+
command: COMMAND_ID,
|
|
1198
|
+
category: 'Variable Explorer'
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
};
|
|
1203
|
+
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (plugin);
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
/***/ },
|
|
1207
|
+
|
|
1208
|
+
/***/ "./lib/utils/colorScales.js"
|
|
1209
|
+
/*!**********************************!*\
|
|
1210
|
+
!*** ./lib/utils/colorScales.js ***!
|
|
1211
|
+
\**********************************/
|
|
1212
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
1213
|
+
|
|
1214
|
+
__webpack_require__.r(__webpack_exports__);
|
|
1215
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1216
|
+
/* harmony export */ booleanColor: () => (/* binding */ booleanColor),
|
|
1217
|
+
/* harmony export */ numericHeatmap: () => (/* binding */ numericHeatmap)
|
|
1218
|
+
/* harmony export */ });
|
|
1219
|
+
/** Color scale utilities for conditional formatting */
|
|
1220
|
+
function numericHeatmap(value, min, max) {
|
|
1221
|
+
if (value == null || isNaN(value))
|
|
1222
|
+
return 'transparent';
|
|
1223
|
+
const range = max - min;
|
|
1224
|
+
if (range === 0)
|
|
1225
|
+
return 'rgba(100, 149, 237, 0.15)';
|
|
1226
|
+
const t = Math.max(0, Math.min(1, (value - min) / range));
|
|
1227
|
+
// Blue (cold) → transparent (mid) → Red (hot)
|
|
1228
|
+
if (t < 0.5) {
|
|
1229
|
+
const s = 1 - t * 2; // 1..0
|
|
1230
|
+
return `rgba(66, 133, 244, ${(s * 0.25).toFixed(3)})`;
|
|
1231
|
+
}
|
|
1232
|
+
const s = (t - 0.5) * 2; // 0..1
|
|
1233
|
+
return `rgba(234, 67, 53, ${(s * 0.25).toFixed(3)})`;
|
|
1234
|
+
}
|
|
1235
|
+
function booleanColor(value) {
|
|
1236
|
+
if (value === true || value === 1) {
|
|
1237
|
+
return 'rgba(52, 168, 83, 0.7)'; // Green
|
|
1238
|
+
}
|
|
1239
|
+
if (value === false || value === 0) {
|
|
1240
|
+
return 'rgba(66, 133, 244, 0.7)'; // Blue
|
|
1241
|
+
}
|
|
1242
|
+
return 'rgba(128, 128, 128, 0.3)'; // Gray for null
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
/***/ },
|
|
1247
|
+
|
|
1248
|
+
/***/ "./lib/utils/histogramRenderer.js"
|
|
1249
|
+
/*!****************************************!*\
|
|
1250
|
+
!*** ./lib/utils/histogramRenderer.js ***!
|
|
1251
|
+
\****************************************/
|
|
1252
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
1253
|
+
|
|
1254
|
+
__webpack_require__.r(__webpack_exports__);
|
|
1255
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1256
|
+
/* harmony export */ drawHistogram: () => (/* binding */ drawHistogram)
|
|
1257
|
+
/* harmony export */ });
|
|
1258
|
+
/** Canvas-based mini histogram rendering for column headers */
|
|
1259
|
+
function drawHistogram(canvas, data) {
|
|
1260
|
+
const ctx = canvas.getContext('2d');
|
|
1261
|
+
if (!ctx)
|
|
1262
|
+
return;
|
|
1263
|
+
const dpr = window.devicePixelRatio || 1;
|
|
1264
|
+
const w = canvas.clientWidth;
|
|
1265
|
+
const h = canvas.clientHeight;
|
|
1266
|
+
canvas.width = w * dpr;
|
|
1267
|
+
canvas.height = h * dpr;
|
|
1268
|
+
ctx.scale(dpr, dpr);
|
|
1269
|
+
ctx.clearRect(0, 0, w, h);
|
|
1270
|
+
switch (data.type) {
|
|
1271
|
+
case 'numeric':
|
|
1272
|
+
drawNumericHistogram(ctx, w, h, data);
|
|
1273
|
+
break;
|
|
1274
|
+
case 'categorical':
|
|
1275
|
+
drawCategoricalHistogram(ctx, w, h, data);
|
|
1276
|
+
break;
|
|
1277
|
+
case 'boolean':
|
|
1278
|
+
drawBooleanBar(ctx, w, h, data);
|
|
1279
|
+
break;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
function drawNumericHistogram(ctx, w, h, data) {
|
|
1283
|
+
const { counts } = data;
|
|
1284
|
+
if (counts.length === 0)
|
|
1285
|
+
return;
|
|
1286
|
+
const maxCount = Math.max(...counts);
|
|
1287
|
+
if (maxCount === 0)
|
|
1288
|
+
return;
|
|
1289
|
+
const barWidth = w / counts.length;
|
|
1290
|
+
const padding = 1;
|
|
1291
|
+
// Get computed style for theming
|
|
1292
|
+
const style = getComputedStyle(document.documentElement);
|
|
1293
|
+
const barColor = style.getPropertyValue('--jp-brand-color1').trim() || '#1976d2';
|
|
1294
|
+
for (let i = 0; i < counts.length; i++) {
|
|
1295
|
+
const barHeight = (counts[i] / maxCount) * (h - 2);
|
|
1296
|
+
const x = i * barWidth + padding / 2;
|
|
1297
|
+
const y = h - barHeight - 1;
|
|
1298
|
+
ctx.fillStyle = barColor;
|
|
1299
|
+
ctx.globalAlpha = 0.6;
|
|
1300
|
+
ctx.fillRect(x, y, barWidth - padding, barHeight);
|
|
1301
|
+
}
|
|
1302
|
+
ctx.globalAlpha = 1.0;
|
|
1303
|
+
}
|
|
1304
|
+
function drawCategoricalHistogram(ctx, w, h, data) {
|
|
1305
|
+
const { counts } = data;
|
|
1306
|
+
if (counts.length === 0)
|
|
1307
|
+
return;
|
|
1308
|
+
const maxCount = Math.max(...counts);
|
|
1309
|
+
if (maxCount === 0)
|
|
1310
|
+
return;
|
|
1311
|
+
const barHeight = h / Math.min(counts.length, 8);
|
|
1312
|
+
const padding = 1;
|
|
1313
|
+
const colors = [
|
|
1314
|
+
'#1976d2', '#388e3c', '#f57c00', '#7b1fa2',
|
|
1315
|
+
'#c62828', '#00838f', '#4e342e', '#546e7a'
|
|
1316
|
+
];
|
|
1317
|
+
for (let i = 0; i < Math.min(counts.length, 8); i++) {
|
|
1318
|
+
const barWidth = (counts[i] / maxCount) * (w - 2);
|
|
1319
|
+
const y = i * barHeight + padding / 2;
|
|
1320
|
+
ctx.fillStyle = colors[i % colors.length];
|
|
1321
|
+
ctx.globalAlpha = 0.6;
|
|
1322
|
+
ctx.fillRect(1, y, barWidth, barHeight - padding);
|
|
1323
|
+
}
|
|
1324
|
+
ctx.globalAlpha = 1.0;
|
|
1325
|
+
}
|
|
1326
|
+
function drawBooleanBar(ctx, w, h, data) {
|
|
1327
|
+
const total = data.trueCount + data.falseCount + data.nullCount;
|
|
1328
|
+
if (total === 0)
|
|
1329
|
+
return;
|
|
1330
|
+
const trueWidth = (data.trueCount / total) * w;
|
|
1331
|
+
const falseWidth = (data.falseCount / total) * w;
|
|
1332
|
+
const barY = h * 0.2;
|
|
1333
|
+
const barH = h * 0.6;
|
|
1334
|
+
// True (green)
|
|
1335
|
+
ctx.fillStyle = 'rgba(52, 168, 83, 0.7)';
|
|
1336
|
+
ctx.fillRect(0, barY, trueWidth, barH);
|
|
1337
|
+
// False (blue)
|
|
1338
|
+
ctx.fillStyle = 'rgba(66, 133, 244, 0.7)';
|
|
1339
|
+
ctx.fillRect(trueWidth, barY, falseWidth, barH);
|
|
1340
|
+
// Null (gray)
|
|
1341
|
+
if (data.nullCount > 0) {
|
|
1342
|
+
ctx.fillStyle = 'rgba(128, 128, 128, 0.4)';
|
|
1343
|
+
ctx.fillRect(trueWidth + falseWidth, barY, w - trueWidth - falseWidth, barH);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
/***/ },
|
|
1349
|
+
|
|
1350
|
+
/***/ "./lib/utils/stylesheetCloner.js"
|
|
1351
|
+
/*!***************************************!*\
|
|
1352
|
+
!*** ./lib/utils/stylesheetCloner.js ***!
|
|
1353
|
+
\***************************************/
|
|
1354
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
1355
|
+
|
|
1356
|
+
__webpack_require__.r(__webpack_exports__);
|
|
1357
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1358
|
+
/* harmony export */ cloneStylesheets: () => (/* binding */ cloneStylesheets)
|
|
1359
|
+
/* harmony export */ });
|
|
1360
|
+
/** Clone stylesheets from the main document to a detached window */
|
|
1361
|
+
function cloneStylesheets(source, target) {
|
|
1362
|
+
var _a;
|
|
1363
|
+
// Copy <link> stylesheets
|
|
1364
|
+
const links = source.querySelectorAll('link[rel="stylesheet"]');
|
|
1365
|
+
links.forEach(link => {
|
|
1366
|
+
const clone = target.createElement('link');
|
|
1367
|
+
clone.rel = 'stylesheet';
|
|
1368
|
+
clone.href = link.href;
|
|
1369
|
+
target.head.appendChild(clone);
|
|
1370
|
+
});
|
|
1371
|
+
// Copy <style> elements
|
|
1372
|
+
const styles = source.querySelectorAll('style');
|
|
1373
|
+
styles.forEach(style => {
|
|
1374
|
+
const clone = target.createElement('style');
|
|
1375
|
+
clone.textContent = style.textContent;
|
|
1376
|
+
target.head.appendChild(clone);
|
|
1377
|
+
});
|
|
1378
|
+
// Copy inline style sheets that might be injected by webpack
|
|
1379
|
+
for (let i = 0; i < source.styleSheets.length; i++) {
|
|
1380
|
+
const sheet = source.styleSheets[i];
|
|
1381
|
+
if (!sheet.href && ((_a = sheet.ownerNode) === null || _a === void 0 ? void 0 : _a.nodeName) === 'STYLE') {
|
|
1382
|
+
// Already copied above via querySelectorAll('style')
|
|
1383
|
+
continue;
|
|
1384
|
+
}
|
|
1385
|
+
try {
|
|
1386
|
+
// Try to access cssRules (may fail for cross-origin sheets)
|
|
1387
|
+
if (sheet.cssRules) {
|
|
1388
|
+
let cssText = '';
|
|
1389
|
+
for (let j = 0; j < sheet.cssRules.length; j++) {
|
|
1390
|
+
cssText += sheet.cssRules[j].cssText + '\n';
|
|
1391
|
+
}
|
|
1392
|
+
if (cssText && !sheet.href) {
|
|
1393
|
+
const styleEl = target.createElement('style');
|
|
1394
|
+
styleEl.textContent = cssText;
|
|
1395
|
+
target.head.appendChild(styleEl);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
catch (_b) {
|
|
1400
|
+
// Cross-origin stylesheet — skip
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
// Copy body data attributes for theme detection
|
|
1404
|
+
const bodyAttrs = source.body.attributes;
|
|
1405
|
+
for (let i = 0; i < bodyAttrs.length; i++) {
|
|
1406
|
+
const attr = bodyAttrs[i];
|
|
1407
|
+
if (attr.name.startsWith('data-jp-')) {
|
|
1408
|
+
target.body.setAttribute(attr.name, attr.value);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
|
|
1414
|
+
/***/ }
|
|
1415
|
+
|
|
1416
|
+
}]);
|
|
1417
|
+
//# sourceMappingURL=lib_index_js.88a2cd3be0f2bf49f0eb.js.map
|