more-compute 0.1.2__py3-none-any.whl → 0.1.4__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.
- frontend/.DS_Store +0 -0
- frontend/.gitignore +41 -0
- frontend/README.md +36 -0
- frontend/__init__.py +1 -0
- frontend/app/favicon.ico +0 -0
- frontend/app/globals.css +1537 -0
- frontend/app/layout.tsx +173 -0
- frontend/app/page.tsx +11 -0
- frontend/components/AddCellButton.tsx +42 -0
- frontend/components/Cell.tsx +244 -0
- frontend/components/CellButton.tsx +58 -0
- frontend/components/CellOutput.tsx +70 -0
- frontend/components/ErrorDisplay.tsx +208 -0
- frontend/components/ErrorModal.tsx +154 -0
- frontend/components/MarkdownRenderer.tsx +84 -0
- frontend/components/Notebook.tsx +520 -0
- frontend/components/Sidebar.tsx +46 -0
- frontend/components/popups/ComputePopup.tsx +879 -0
- frontend/components/popups/FilterPopup.tsx +427 -0
- frontend/components/popups/FolderPopup.tsx +171 -0
- frontend/components/popups/MetricsPopup.tsx +168 -0
- frontend/components/popups/PackagesPopup.tsx +112 -0
- frontend/components/popups/PythonPopup.tsx +292 -0
- frontend/components/popups/SettingsPopup.tsx +68 -0
- frontend/eslint.config.mjs +25 -0
- frontend/lib/api.ts +469 -0
- frontend/lib/settings.ts +87 -0
- frontend/lib/websocket-native.ts +202 -0
- frontend/lib/websocket.ts +134 -0
- frontend/next-env.d.ts +6 -0
- frontend/next.config.mjs +17 -0
- frontend/next.config.ts +7 -0
- frontend/package-lock.json +5676 -0
- frontend/package.json +41 -0
- frontend/postcss.config.mjs +5 -0
- frontend/public/assets/icons/add.svg +1 -0
- frontend/public/assets/icons/check.svg +1 -0
- frontend/public/assets/icons/copy.svg +1 -0
- frontend/public/assets/icons/folder.svg +1 -0
- frontend/public/assets/icons/metric.svg +1 -0
- frontend/public/assets/icons/packages.svg +1 -0
- frontend/public/assets/icons/play.svg +1 -0
- frontend/public/assets/icons/python.svg +265 -0
- frontend/public/assets/icons/setting.svg +1 -0
- frontend/public/assets/icons/stop.svg +1 -0
- frontend/public/assets/icons/trash.svg +1 -0
- frontend/public/assets/icons/up-down.svg +1 -0
- frontend/public/assets/icons/x.svg +1 -0
- frontend/public/file.svg +1 -0
- frontend/public/fonts/Fira.ttf +0 -0
- frontend/public/fonts/Tiempos.woff2 +0 -0
- frontend/public/fonts/VeraMono.ttf +0 -0
- frontend/public/globe.svg +1 -0
- frontend/public/next.svg +1 -0
- frontend/public/vercel.svg +1 -0
- frontend/public/window.svg +1 -0
- frontend/tailwind.config.ts +29 -0
- frontend/tsconfig.json +27 -0
- frontend/types/notebook.ts +58 -0
- kernel_run.py +7 -0
- {more_compute-0.1.2.dist-info → more_compute-0.1.4.dist-info}/METADATA +1 -1
- more_compute-0.1.4.dist-info/RECORD +86 -0
- {more_compute-0.1.2.dist-info → more_compute-0.1.4.dist-info}/top_level.txt +1 -0
- morecompute/__version__.py +1 -0
- more_compute-0.1.2.dist-info/RECORD +0 -26
- {more_compute-0.1.2.dist-info → more_compute-0.1.4.dist-info}/WHEEL +0 -0
- {more_compute-0.1.2.dist-info → more_compute-0.1.4.dist-info}/entry_points.txt +0 -0
- {more_compute-0.1.2.dist-info → more_compute-0.1.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Cell, ExecutionResult } from '@/types/notebook';
|
|
2
|
+
|
|
3
|
+
export class WebSocketService {
|
|
4
|
+
private ws: WebSocket | null = null;
|
|
5
|
+
private listeners: Map<string, Function[]> = new Map();
|
|
6
|
+
private reconnectAttempts = 0;
|
|
7
|
+
private maxReconnectAttempts = 5;
|
|
8
|
+
private url: string = '';
|
|
9
|
+
|
|
10
|
+
connect(url: string = 'ws://localhost:8888/ws'): Promise<void> {
|
|
11
|
+
this.url = url;
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
try {
|
|
14
|
+
this.ws = new WebSocket(this.url);
|
|
15
|
+
|
|
16
|
+
this.ws.onopen = () => {
|
|
17
|
+
console.log('Connected to server');
|
|
18
|
+
this.reconnectAttempts = 0;
|
|
19
|
+
this.emit('connect', null);
|
|
20
|
+
resolve();
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
this.ws.onerror = (error) => {
|
|
24
|
+
console.error('WebSocket error:', error);
|
|
25
|
+
this.emit('disconnect', null);
|
|
26
|
+
reject(error);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
this.ws.onclose = (ev) => {
|
|
30
|
+
console.log('Disconnected from server', { code: ev.code, reason: ev.reason, wasClean: ev.wasClean });
|
|
31
|
+
this.emit('disconnect', null);
|
|
32
|
+
this.handleDisconnect();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
this.ws.onmessage = (event) => {
|
|
36
|
+
try {
|
|
37
|
+
const data = JSON.parse(event.data);
|
|
38
|
+
console.log('[WS RECV]', data);
|
|
39
|
+
this.handleMessage(data);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('Failed to parse message:', error);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
} catch (error) {
|
|
45
|
+
reject(error);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private handleMessage(data: any) {
|
|
51
|
+
const messageType = data.type;
|
|
52
|
+
const messageData = data.data;
|
|
53
|
+
|
|
54
|
+
// Map FastAPI message types to our expected events
|
|
55
|
+
switch (messageType) {
|
|
56
|
+
case 'notebook_data':
|
|
57
|
+
this.emit('notebook_loaded', messageData);
|
|
58
|
+
break;
|
|
59
|
+
case 'notebook_updated':
|
|
60
|
+
this.emit('notebook_updated', messageData);
|
|
61
|
+
break;
|
|
62
|
+
case 'execution_start':
|
|
63
|
+
this.emit('execution_start', messageData);
|
|
64
|
+
break;
|
|
65
|
+
case 'stream_output':
|
|
66
|
+
this.emit('stream_output', messageData);
|
|
67
|
+
break;
|
|
68
|
+
case 'execution_result':
|
|
69
|
+
this.emit('execution_result', messageData);
|
|
70
|
+
break;
|
|
71
|
+
case 'execution_complete': // This may be sent by some legacy paths
|
|
72
|
+
this.emit('execution_complete', messageData);
|
|
73
|
+
break;
|
|
74
|
+
case 'execution_error':
|
|
75
|
+
this.emit('execution_error', messageData);
|
|
76
|
+
break;
|
|
77
|
+
case 'execution_interrupted':
|
|
78
|
+
this.emit('execution_interrupted', messageData);
|
|
79
|
+
break;
|
|
80
|
+
case 'cell_updated': // Note: This is now handled by notebook_updated
|
|
81
|
+
this.emit('cell_updated', messageData);
|
|
82
|
+
break;
|
|
83
|
+
case 'cell_added':
|
|
84
|
+
this.emit('cell_added', messageData);
|
|
85
|
+
break;
|
|
86
|
+
case 'cell_deleted':
|
|
87
|
+
this.emit('cell_deleted', messageData);
|
|
88
|
+
break;
|
|
89
|
+
case 'kernel_status':
|
|
90
|
+
this.emit('kernel_status', messageData);
|
|
91
|
+
break;
|
|
92
|
+
case 'packages_updated':
|
|
93
|
+
// Notify listeners and also broadcast a DOM event for decoupled UIs
|
|
94
|
+
this.emit('packages_updated', messageData);
|
|
95
|
+
try {
|
|
96
|
+
window.dispatchEvent(new CustomEvent('mc:packages-updated', { detail: messageData }));
|
|
97
|
+
} catch {}
|
|
98
|
+
break;
|
|
99
|
+
case 'error':
|
|
100
|
+
this.emit('error', messageData);
|
|
101
|
+
break;
|
|
102
|
+
default:
|
|
103
|
+
console.warn('Unknown message type:', messageType);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private handleDisconnect() {
|
|
108
|
+
this.emit('disconnect', null);
|
|
109
|
+
// Attempt to reconnect
|
|
110
|
+
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
111
|
+
this.reconnectAttempts++;
|
|
112
|
+
console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
this.connect(this.url).catch(console.error);
|
|
115
|
+
}, 1000 * this.reconnectAttempts);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
on(event: string, callback: Function) {
|
|
120
|
+
if (!this.listeners.has(event)) {
|
|
121
|
+
this.listeners.set(event, []);
|
|
122
|
+
}
|
|
123
|
+
this.listeners.get(event)!.push(callback);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
off(event: string, callback: Function) {
|
|
127
|
+
const callbacks = this.listeners.get(event);
|
|
128
|
+
if (callbacks) {
|
|
129
|
+
const index = callbacks.indexOf(callback);
|
|
130
|
+
if (index > -1) {
|
|
131
|
+
callbacks.splice(index, 1);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private emit(event: string, data: any) {
|
|
137
|
+
const callbacks = this.listeners.get(event);
|
|
138
|
+
if (callbacks) {
|
|
139
|
+
callbacks.forEach(callback => callback(data));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private send(type: string, data: any = {}) {
|
|
144
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
145
|
+
this.ws.send(JSON.stringify({ type, data }));
|
|
146
|
+
} else {
|
|
147
|
+
console.error('WebSocket is not connected');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Notebook operations
|
|
152
|
+
loadNotebook(notebookName: string) {
|
|
153
|
+
this.send('load_notebook', { notebook_name: notebookName });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
saveNotebook() {
|
|
157
|
+
this.send('save_notebook');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Cell operations
|
|
161
|
+
addCell(index: number, cellType: 'code' | 'markdown', source: string = '') {
|
|
162
|
+
this.send('add_cell', {
|
|
163
|
+
index,
|
|
164
|
+
cell_type: cellType,
|
|
165
|
+
source,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
deleteCell(cellIndex: number) {
|
|
170
|
+
this.send('delete_cell', { cell_index: cellIndex });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
updateCell(cellIndex: number, source: string) {
|
|
174
|
+
this.send('update_cell', {
|
|
175
|
+
cell_index: cellIndex,
|
|
176
|
+
source,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
executeCell(cellIndex: number, source: string) {
|
|
181
|
+
this.send('execute_cell', {
|
|
182
|
+
cell_index: cellIndex,
|
|
183
|
+
source,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Kernel operations
|
|
188
|
+
resetKernel() {
|
|
189
|
+
this.send('reset_kernel');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
interruptKernel(cellIndex?: number) {
|
|
193
|
+
this.send('interrupt_kernel', { cell_index: cellIndex });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
disconnect() {
|
|
197
|
+
if (this.ws) {
|
|
198
|
+
this.ws.close();
|
|
199
|
+
this.ws = null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { io, Socket } from 'socket.io-client';
|
|
2
|
+
import { Cell, ExecutionResult } from '@/types/notebook';
|
|
3
|
+
|
|
4
|
+
export class WebSocketService {
|
|
5
|
+
private socket: Socket | null = null;
|
|
6
|
+
private listeners: Map<string, Function[]> = new Map();
|
|
7
|
+
|
|
8
|
+
connect(url: string = 'ws://localhost:8000'): Promise<void> {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
// For development, connect directly to the backend WebSocket
|
|
11
|
+
const wsUrl = process.env.NODE_ENV === 'production'
|
|
12
|
+
? '/ws'
|
|
13
|
+
: 'ws://localhost:8000/ws';
|
|
14
|
+
|
|
15
|
+
// Use native WebSocket for FastAPI compatibility
|
|
16
|
+
const ws = new WebSocket(wsUrl);
|
|
17
|
+
|
|
18
|
+
// Wrap WebSocket in Socket.IO-like interface
|
|
19
|
+
this.socket = this.createSocketWrapper(ws);
|
|
20
|
+
|
|
21
|
+
this.socket.on('connect', () => {
|
|
22
|
+
console.log('Connected to server');
|
|
23
|
+
resolve();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
this.socket.on('connect_error', (error) => {
|
|
27
|
+
console.error('Connection error:', error);
|
|
28
|
+
reject(error);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
this.socket.on('disconnect', () => {
|
|
32
|
+
console.log('Disconnected from server');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Set up event forwarding
|
|
36
|
+
this.setupEventForwarding();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private setupEventForwarding() {
|
|
41
|
+
if (!this.socket) return;
|
|
42
|
+
|
|
43
|
+
// Forward common events
|
|
44
|
+
const events = [
|
|
45
|
+
'notebook_loaded',
|
|
46
|
+
'cell_added',
|
|
47
|
+
'cell_deleted',
|
|
48
|
+
'cell_updated',
|
|
49
|
+
'execution_result',
|
|
50
|
+
'kernel_status',
|
|
51
|
+
'error',
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
events.forEach(event => {
|
|
55
|
+
this.socket!.on(event, (data) => {
|
|
56
|
+
this.emit(event, data);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
on(event: string, callback: Function) {
|
|
62
|
+
if (!this.listeners.has(event)) {
|
|
63
|
+
this.listeners.set(event, []);
|
|
64
|
+
}
|
|
65
|
+
this.listeners.get(event)!.push(callback);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
off(event: string, callback: Function) {
|
|
69
|
+
const callbacks = this.listeners.get(event);
|
|
70
|
+
if (callbacks) {
|
|
71
|
+
const index = callbacks.indexOf(callback);
|
|
72
|
+
if (index > -1) {
|
|
73
|
+
callbacks.splice(index, 1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private emit(event: string, data: any) {
|
|
79
|
+
const callbacks = this.listeners.get(event);
|
|
80
|
+
if (callbacks) {
|
|
81
|
+
callbacks.forEach(callback => callback(data));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Notebook operations
|
|
86
|
+
loadNotebook(notebookName: string) {
|
|
87
|
+
this.socket?.emit('load_notebook', { notebook_name: notebookName });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
saveNotebook() {
|
|
91
|
+
this.socket?.emit('save_notebook');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Cell operations
|
|
95
|
+
addCell(index: number, cellType: 'code' | 'markdown', source: string = '') {
|
|
96
|
+
this.socket?.emit('add_cell', {
|
|
97
|
+
index,
|
|
98
|
+
cell_type: cellType,
|
|
99
|
+
source,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
deleteCell(cellIndex: number) {
|
|
104
|
+
this.socket?.emit('delete_cell', { cell_index: cellIndex });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
updateCell(cellIndex: number, source: string) {
|
|
108
|
+
this.socket?.emit('update_cell', {
|
|
109
|
+
cell_index: cellIndex,
|
|
110
|
+
source,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
executeCell(cellIndex: number, source: string) {
|
|
115
|
+
this.socket?.emit('execute_cell', {
|
|
116
|
+
cell_index: cellIndex,
|
|
117
|
+
source,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Kernel operations
|
|
122
|
+
resetKernel() {
|
|
123
|
+
this.socket?.emit('reset_kernel');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interruptKernel() {
|
|
127
|
+
this.socket?.emit('interrupt_kernel');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
disconnect() {
|
|
131
|
+
this.socket?.disconnect();
|
|
132
|
+
this.socket = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
frontend/next-env.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="next" />
|
|
2
|
+
/// <reference types="next/image-types/global" />
|
|
3
|
+
/// <reference path="./.next/types/routes.d.ts" />
|
|
4
|
+
|
|
5
|
+
// NOTE: This file should not be edited
|
|
6
|
+
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
frontend/next.config.mjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** @type {import('next').NextConfig} */
|
|
2
|
+
const nextConfig = {
|
|
3
|
+
async rewrites() {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
source: '/ws/:path*',
|
|
7
|
+
destination: 'http://localhost:8000/ws/:path*',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
source: '/api/:path*',
|
|
11
|
+
destination: 'http://localhost:8000/api/:path*',
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default nextConfig;
|