@gen3/workspaces 0.12.45 → 0.12.46

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.
@@ -5,7 +5,6 @@ var React = require('react');
5
5
  var frontend = require('@gen3/frontend');
6
6
  var core = require('@mantine/core');
7
7
  var react = require('@iconify-icon/react');
8
- var cookiesNext = require('cookies-next');
9
8
  var core$1 = require('@gen3/core');
10
9
  var useDeepCompare = require('use-deep-compare');
11
10
  var notifications = require('@mantine/notifications');
@@ -177,13 +176,74 @@ const FreeWorkspace = ({ assetBaseUrl = '/api/workspace-assets/free', onReady, o
177
176
  const [loading, setLoading] = React.useState(true);
178
177
  const [loadError, setLoadError] = React.useState(false);
179
178
  const [retryCount, setRetryCount] = React.useState(0);
179
+ const [jupyterReady, setJupyterReady] = React.useState(false);
180
180
  const iframeRef = React.useRef(null);
181
+ const broadcastChannelRef = React.useRef(null);
181
182
  const url = `${assetBaseUrl}/lab/index.html`;
182
183
  const handleRetry = React.useCallback(()=>{
183
184
  setLoadError(false);
184
185
  setLoading(true);
185
186
  setRetryCount((n)=>n + 1);
186
187
  }, []);
188
+ // set up BroadcastChannel
189
+ React.useEffect(()=>{
190
+ if (!broadcastChannelRef?.current) {
191
+ broadcastChannelRef.current = new BroadcastChannel(frontend.ACTIVITY_CHANNEL);
192
+ }
193
+ return ()=>{
194
+ if (broadcastChannelRef.current) {
195
+ broadcastChannelRef.current.close();
196
+ broadcastChannelRef.current = null;
197
+ }
198
+ };
199
+ }, []);
200
+ // Handle setting up iframe event listeners
201
+ React.useEffect(()=>{
202
+ if (!jupyterReady) return;
203
+ const updateUserActivity = ()=>{
204
+ const timestamp = Date.now();
205
+ if (broadcastChannelRef.current) {
206
+ broadcastChannelRef.current.postMessage({
207
+ type: 'activity-update',
208
+ timestamp
209
+ });
210
+ }
211
+ };
212
+ const iframe = iframeRef.current;
213
+ if (!iframe?.contentWindow) {
214
+ return;
215
+ }
216
+ try {
217
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
218
+ if (iframeDoc) {
219
+ iframeDoc.addEventListener('mousedown', updateUserActivity);
220
+ iframeDoc.addEventListener('keypress', updateUserActivity);
221
+ iframeDoc.addEventListener('scroll', updateUserActivity);
222
+ iframeDoc.addEventListener('click', updateUserActivity);
223
+ iframeDoc.addEventListener('touchstart', updateUserActivity);
224
+ }
225
+ } catch (error) {
226
+ console.warn('Cannot access iframe content - cross-origin restriction', error);
227
+ }
228
+ return ()=>{
229
+ if (iframe?.contentWindow) {
230
+ try {
231
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
232
+ if (iframeDoc) {
233
+ iframeDoc.removeEventListener('mousedown', updateUserActivity);
234
+ iframeDoc.removeEventListener('keypress', updateUserActivity);
235
+ iframeDoc.removeEventListener('scroll', updateUserActivity);
236
+ iframeDoc.removeEventListener('click', updateUserActivity);
237
+ iframeDoc.removeEventListener('touchstart', updateUserActivity);
238
+ }
239
+ } catch {
240
+ // Ignore cleanup errors
241
+ }
242
+ }
243
+ };
244
+ }, [
245
+ jupyterReady
246
+ ]);
187
247
  if (loadError) {
188
248
  return /*#__PURE__*/ jsxRuntime.jsx("div", {
189
249
  children: /*#__PURE__*/ jsxRuntime.jsxs(core.Card, {
@@ -235,6 +295,7 @@ const FreeWorkspace = ({ assetBaseUrl = '/api/workspace-assets/free', onReady, o
235
295
  className: "min-h-0 flex-1 border-0",
236
296
  onLoad: ()=>{
237
297
  setLoading(false);
298
+ setJupyterReady(true);
238
299
  onReady?.();
239
300
  },
240
301
  onError: ()=>{
@@ -634,7 +695,9 @@ const workspaceShutdownAlertLimit = 30000; // 5 minutes: 5 * 60 * 1000 TODO Figu
634
695
  ]);
635
696
  useDeepCompare.useDeepCompareEffect(()=>{
636
697
  // TODO: add better error logging
637
- console.log('useJEGWorkspaceResourceMonitor', error);
698
+ if (error) {
699
+ console.log('useJEGWorkspaceResourceMonitor', error);
700
+ }
638
701
  }, [
639
702
  error
640
703
  ]);
@@ -996,6 +1059,7 @@ const MicroContainerReduxPanel = ({ compact = false })=>{
996
1059
  const [retryCount, setRetryCount] = React.useState(0);
997
1060
  const [jupyterReady, setJupyterReady] = React.useState(false);
998
1061
  const iframeRef = React.useRef(null);
1062
+ const broadcastChannelRef = React.useRef(null);
999
1063
  const { status } = useMicroContainerReduxContext();
1000
1064
  const normalizedBase = assetBaseUrl.replace(/\/$/, '');
1001
1065
  // Scoped notebook path for session isolation
@@ -1015,11 +1079,71 @@ const MicroContainerReduxPanel = ({ compact = false })=>{
1015
1079
  const userHash = btoa(userId || 'anonymous').substring(0, 8);
1016
1080
  scopedNotebookPath = `/workspace/${userHash}/${notebookName}.ipynb`;
1017
1081
  }
1018
- if (process.env.NODE_ENV === 'development') {
1019
- // NOTE: This cookie can only be accessed from the client side
1020
- // in development mode. Otherwise, the cookie is set as httpOnly
1021
- cookiesNext.getCookie('credentials_token');
1022
- }
1082
+ // let accessToken = undefined;
1083
+ // if (process.env.NODE_ENV === 'development') {
1084
+ // // NOTE: This cookie can only be accessed from the client side
1085
+ // // in development mode. Otherwise, the cookie is set as httpOnly
1086
+ // accessToken = getCookie('credentials_token');
1087
+ // }
1088
+ // set up BroadcastChannel
1089
+ React.useEffect(()=>{
1090
+ if (!broadcastChannelRef?.current) {
1091
+ broadcastChannelRef.current = new BroadcastChannel(frontend.ACTIVITY_CHANNEL);
1092
+ }
1093
+ return ()=>{
1094
+ if (broadcastChannelRef.current) {
1095
+ broadcastChannelRef.current.close();
1096
+ broadcastChannelRef.current = null;
1097
+ }
1098
+ };
1099
+ }, []);
1100
+ // Handle setting up iframe event listeners
1101
+ React.useEffect(()=>{
1102
+ if (!jupyterReady) return;
1103
+ const updateUserActivity = ()=>{
1104
+ const timestamp = Date.now();
1105
+ if (broadcastChannelRef.current) {
1106
+ broadcastChannelRef.current.postMessage({
1107
+ type: 'activity-update',
1108
+ timestamp
1109
+ });
1110
+ }
1111
+ };
1112
+ const iframe = iframeRef.current;
1113
+ if (!iframe?.contentWindow) {
1114
+ return;
1115
+ }
1116
+ try {
1117
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
1118
+ if (iframeDoc) {
1119
+ iframeDoc.addEventListener('mousedown', updateUserActivity);
1120
+ iframeDoc.addEventListener('keypress', updateUserActivity);
1121
+ iframeDoc.addEventListener('scroll', updateUserActivity);
1122
+ iframeDoc.addEventListener('click', updateUserActivity);
1123
+ iframeDoc.addEventListener('touchstart', updateUserActivity);
1124
+ }
1125
+ } catch (error) {
1126
+ console.warn('Cannot access iframe content - cross-origin restriction', error);
1127
+ }
1128
+ return ()=>{
1129
+ if (iframe?.contentWindow) {
1130
+ try {
1131
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
1132
+ if (iframeDoc) {
1133
+ iframeDoc.removeEventListener('mousedown', updateUserActivity);
1134
+ iframeDoc.removeEventListener('keypress', updateUserActivity);
1135
+ iframeDoc.removeEventListener('scroll', updateUserActivity);
1136
+ iframeDoc.removeEventListener('click', updateUserActivity);
1137
+ iframeDoc.removeEventListener('touchstart', updateUserActivity);
1138
+ }
1139
+ } catch {
1140
+ // Ignore cleanup errors
1141
+ }
1142
+ }
1143
+ };
1144
+ }, [
1145
+ jupyterReady
1146
+ ]);
1023
1147
  /* ---- Wait for JupyterLite app inside the iframe --------------- */ React.useEffect(()=>{
1024
1148
  if (!iframeRef.current || loadError) return;
1025
1149
  if (jupyterReady) return;
@@ -1211,6 +1335,7 @@ const MicroContainerReduxPanel = ({ compact = false })=>{
1211
1335
  className: "min-h-0 flex-1 border-0",
1212
1336
  onLoad: ()=>{
1213
1337
  setLoading(false);
1338
+ setJupyterReady(true);
1214
1339
  },
1215
1340
  onError: ()=>{
1216
1341
  setLoadError(true);