Skip to content

Commit 5cce202

Browse files
authored
Merge pull request #204 from Open-STEM/kq-bugs
Fixed upload action and rename artifact and addressed other issues
2 parents 723feb5 + f36bb09 commit 5cce202

11 files changed

Lines changed: 108 additions & 82 deletions

File tree

.github/workflows/release.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ jobs:
1111
release:
1212
name: Release pushed tag
1313
runs-on: ubuntu-latest
14+
strategy:
15+
matrix:
16+
node-version: [20]
1417

1518
steps:
1619
- name: Checkout
@@ -31,7 +34,11 @@ jobs:
3134
with:
3235
type: 'zip'
3336
directory: './dist'
34-
filename: xrpweb-v${{ github.run_number }}.zip
37+
filename: ../xrpweb-v${{ github.run_number }}.zip
38+
- name: Debug - List files
39+
run: |
40+
ls -la
41+
ls -la dist/
3542
- name: Create Release
3643
id: create_new_release
3744
uses: softprops/action-gh-release@v2.3.3
@@ -45,6 +52,6 @@ jobs:
4552
with:
4653
repo_token: ${{ secrets.GITHUB_TOKEN }}
4754
file: xrpweb-v${{ github.run_number }}.zip
48-
asset_name: xrpweb-v${{ github.run_number }}.zip
55+
asset_name: artifacts.zip
4956
tag: ${{ github.ref }}
5057
overwrite: true

public/CHANGELOG.txt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Version 2.0.10
1+
# Version 2.0.11
22

33
#### Bluetooth support
44
<img height="10%" width="10%" src="src/assets/images/Bluetooth_FM_Black.png"/></img>
@@ -34,10 +34,6 @@
3434
* Support the New Puppet Protocol for communication with the XRP Bluetooth (advanced users) [See XPP](https://xrpcode.io/docs/puppet_protocol)
3535

3636
#### Bug Fixes
37-
* Fixed various bugs with the Block Editor where the change indicator would not show
38-
* [New File button on Folder Tree](https://github.com/Open-STEM/XRPWeb/issues/195)
39-
* [New Directory button on Folder Tree](https://github.com/Open-STEM/XRPWeb/issues/194)
40-
* [Monaco Editor not resize properly](https://github.com/Open-STEM/XRPWeb/issues/186)
41-
* [Rename file in File System Tree doesn't reflect the changes in the open tab](https://github.com/Open-STEM/XRPWeb/issues/185)
42-
* [Change AI Chat to Code Buddy on the Tab title](https://github.com/Open-STEM/XRPWeb/issues/183)
43-
* [If a program is loaded into the editor after Web browser refresh, and if the file was edited on the XRP, this program won't run](https://github.com/Open-STEM/XRPWeb/issues/176)
37+
* [File SaveAs dialog not using name](https://github.com/Open-STEM/XRPWeb/issues/205)
38+
* [Google Drive Export to PC resulted with zero bytes](https://github.com/Open-STEM/XRPWeb/issues/206)
39+
* [Google Drive Onetime notification](https://github.com/Open-STEM/XRPWeb/issues/198)

src/components/blockly.tsx

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ function blocklyToPython(ws: Workspace) {
150150
function BlocklyEditor({ tabId, tabName }: BlocklyEditorProps) {
151151
const [toolboxKey, setToolboxKey] = useState(0); // Force re-render when toolbox updates
152152
const [isLoading, setIsLoading] = useState<boolean>(true);
153-
const [isListenerSet, setIsListenerSet] = useState(false);
154153
const [name, setName] = useState<string>(tabName);
155154
const nameRef = useRef(name);
156155
const isLoadingRef = useRef(isLoading);
@@ -225,15 +224,22 @@ function BlocklyEditor({ tabId, tabName }: BlocklyEditorProps) {
225224

226225
const ws = EditorMgr.getInstance().getEditorSession(tabId)?.workspace;
227226
if (ws) {
228-
Blockly.serialization.workspaces.load(JSON.parse(loadContent.content), ws);
229-
// @ts-expect-error - it is a valid function
230-
ws.scrollCenter();
231-
// @ts-expect-error - it is a valid function
232-
ws.zoomToFit();
227+
try {
228+
Blockly.Events.disable();
229+
Blockly.serialization.workspaces.load(JSON.parse(loadContent.content), ws);
230+
// @ts-expect-error - it is a valid function
231+
ws.scrollCenter();
232+
// @ts-expect-error - it is a valid function
233+
ws.zoomToFit();
234+
} finally {
235+
Blockly.Events.enable();
236+
}
233237
}
234238
if (session) {
235239
EditorMgr.getInstance().SaveToLocalStorage(session, loadContent.content);
236240
}
241+
setIsLoading(false);
242+
isLoadingRef.current = false;
237243
});
238244

239245
AppMgr.getInstance().on(EventType.EVENT_EDITOR, (type) => {
@@ -265,11 +271,16 @@ function BlocklyEditor({ tabId, tabName }: BlocklyEditorProps) {
265271
setTimeout(() => {
266272
const newWs = Blockly.getMainWorkspace();
267273
if (newWs) {
268-
Blockly.serialization.workspaces.load(content, newWs);
269-
// @ts-expect-error - it is a valid function
270-
newWs.scrollCenter();
271-
// @ts-expect-error - it is a valid function
272-
newWs.zoomToFit();
274+
try {
275+
Blockly.Events.disable();
276+
Blockly.serialization.workspaces.load(content, newWs);
277+
// @ts-expect-error - it is a valid function
278+
newWs.scrollCenter();
279+
// @ts-expect-error - it is a valid function
280+
newWs.zoomToFit();
281+
} finally {
282+
Blockly.Events.enable();
283+
}
273284
}
274285
}, 100);
275286
}
@@ -324,56 +335,43 @@ function BlocklyEditor({ tabId, tabName }: BlocklyEditorProps) {
324335

325336
// Call setupLanguage to initialize Blockly locale
326337
setupLanguage();
338+
327339
// Set up workspace change listener for live content tracking
328-
const setupWorkspaceListener = () => {
329-
const ws = Blockly.getMainWorkspace();
330-
if (ws) {
331-
// Listen for workspace changes
332-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
333-
const changeListener = (event: any) => {
334-
if (event.type === Blockly.Events.FINISHED_LOADING) {
335-
setIsLoading(false);
336-
return;
337-
}
338-
if (isLoadingRef.current &&
339-
(event.type === Blockly.Events.BLOCK_CREATE ||
340-
event.type === Blockly.Events.BLOCK_DELETE ||
341-
event.type === Blockly.Events.BLOCK_CHANGE)
342-
) { return; }
343-
if (event.type === Blockly.Events.VIEWPORT_CHANGE || event.isUiEvent) { return; }
344-
try {
345-
console.log('Workspace changed, saving session:', nameRef.current);
346-
EditorMgr.getInstance().updateEditorSessionChange(tabId, true);
347-
const code = blocklyToPython(ws);
348-
EditorMgr.getInstance().SaveToLocalStorage(EditorMgr.getInstance().getEditorSession(tabId) as EditorSession, code);
349-
} catch (e) {
350-
console.warn('Failed to serialize Blockly workspace:', e);
351-
}
352-
};
353-
354-
ws.addChangeListener(changeListener);
355-
356-
// Store the listener for cleanup
357-
return changeListener;
358-
}
359-
return null;
360-
};
340+
const ws = Blockly.getMainWorkspace();
341+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
342+
let changeListener: ((event: any) => void) | null = null;
361343

362-
let listener = null;
363-
if (!isListenerSet) {
364-
listener = setupWorkspaceListener();
365-
setIsListenerSet(true);
344+
if (ws) {
345+
// Listen for workspace changes
346+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
347+
changeListener = (event: any) => {
348+
if (event.type === Blockly.Events.FINISHED_LOADING) {
349+
setIsLoading(false);
350+
isLoadingRef.current = false;
351+
return;
352+
}
353+
if (isLoadingRef.current) { return; }
354+
if (event.type === Blockly.Events.VIEWPORT_CHANGE || event.isUiEvent) { return; }
355+
try {
356+
console.log('Workspace changed, saving session:', nameRef.current);
357+
EditorMgr.getInstance().updateEditorSessionChange(tabId, true);
358+
const code = blocklyToPython(ws);
359+
EditorMgr.getInstance().SaveToLocalStorage(EditorMgr.getInstance().getEditorSession(tabId) as EditorSession, code);
360+
} catch (e) {
361+
console.warn('Failed to serialize Blockly workspace:', e);
362+
}
363+
};
364+
365+
ws.addChangeListener(changeListener);
366366
}
367367

368368
return () => {
369369
// Cleanup listener on unmount
370-
const ws = Blockly.getMainWorkspace();
371-
if (ws && isListenerSet) {
372-
// @ts-expect-error - listener may be null
373-
ws.removeChangeListener(listener);
370+
if (ws && changeListener) {
371+
ws.removeChangeListener(changeListener);
374372
}
375373
}
376-
}, [isListenerSet, saveEditor, tabId]);
374+
}, [saveEditor, tabId]);
377375

378376
return (
379377
<BlocklyWorkspace

src/components/dialogs/filesaveasdlg.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ function FileSaveAsDialg(fileSaveAsProps: FileSaveAsProps) {
8686
const session = EditorMgr.getInstance().getEditorSession(activeTab);
8787
if (session) {
8888
setSelectedFolder('/' + session.path.split('/')[1]);
89+
setFilename(session.name);
8990
}
90-
setFilename(activeTab);
9191
}
9292
}, [activeTab]);
9393

@@ -111,11 +111,13 @@ function FileSaveAsDialg(fileSaveAsProps: FileSaveAsProps) {
111111
<label className="text-mountain-mist-700 dark:text-mountain-mist-300">
112112
{t('destFolder')}: {selectedFolder}
113113
</label>
114-
<FolderTree
115-
treeData={JSON.stringify(folderList)}
116-
theme=""
117-
onSelected={handleFolderSelection}
118-
/>
114+
<div className='h-48 w-full overflow-y-auto border border-shark-300 dark:border-shark-600'>
115+
<FolderTree
116+
treeData={JSON.stringify(folderList)}
117+
theme=""
118+
onSelected={handleFolderSelection}
119+
/>
120+
</div>
119121
<label className="text-sm text-mountain-mist-700 dark:text-mountain-mist-300">{t('filename')}</label>
120122
<div>
121123
<input

src/components/dialogs/newfiledlg.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,19 +178,21 @@ function NewFileDlg(newFileProps: NewFileProps) {
178178
};
179179

180180
return (
181-
<div className="flex flex-col items-center gap-4 rounded-md border border-mountain-mist-700 p-8 shadow-md transition-all dark:border-shark-500 dark:bg-shark-950">
181+
<div className="flex flex-col items-center gap-4 rounded-md border border-mountain-mist-700 p-8 shadow-md transition-all dark:border-shark-500 dark:bg-shark-950 w-96 max-h-[90vh] overflow-y-auto">
182182
<div className="flex w-[90%] flex-col items-center">
183183
<h1 className="text-lg font-bold text-mountain-mist-700 dark:text-mountain-mist-300">{t('newFile')}</h1>
184184
<p className="text-sm text-mountain-mist-700 dark:text-mountain-mist-300">{t('chooseNewFile')}</p>
185185
</div>
186186
<hr className="w-full border-mountain-mist-600" />
187187
<form id="fileOptionId" className="flex w-full flex-col gap-2">
188188
<span className="text-sm text-mountain-mist-700 dark:text-mountain-mist-300">{t('destFolder')}</span>
189-
<FolderTree
190-
treeData={JSON.stringify(folderList)}
191-
theme=""
192-
onSelected={handleFolderSelection}
193-
/>
189+
<div className='h-48 w-full overflow-y-auto border border-shark-300 dark:border-shark-600'>
190+
<FolderTree
191+
treeData={JSON.stringify(folderList)}
192+
theme=""
193+
onSelected={handleFolderSelection}
194+
/>
195+
</div>
194196
<label className="text-sm text-mountain-mist-700 dark:text-mountain-mist-300" htmlFor="filesId">
195197
{t('fileType')}
196198
</label>

src/components/dialogs/uploadfiledlg.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ function UploadFileDlg({ files, toggleDialog }: UploadFileDlgProps) {
7777
<h1 className="text-lg font-bold text-mountain-mist-700 dark:text-mountain-mist-300">{t('uploadFiles')}</h1>
7878
</div>
7979
<hr className="w-full border-mountain-mist-600 dark:border-mountain-mist-200" />
80-
<FolderTree treeData={JSON.stringify(folderItem)} theme="" onSelected={handleFolderSelection} />
80+
<div className='h-48 w-full overflow-y-auto border border-shark-300 dark:border-shark-600'>
81+
<FolderTree treeData={JSON.stringify(folderItem)} theme="" onSelected={handleFolderSelection} />
82+
</div>
8183
<label className="text-mountain-mist-700 dark:text-mountain-mist-300">{t('destFolder')}: {selectedFolder}</label>
8284
<label className="text-mountain-mist-700 dark:text-mountain-mist-300">{t('filesToUpload')}: {fileList?.length}</label>
8385
<ul className='flex flex-col gap-2'>

src/components/folder-tree.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import EditorMgr, { EdSearchParams } from '@/managers/editormgr';
2525
import Login from '@/widgets/login';
2626
import { UserProfile } from '@/services/google-auth';
2727
import CreateNodeDlg from './dialogs/create-node-dlg';
28+
import { StorageKeys } from '@/utils/localstorage';
2829

2930
type TreeProps = {
3031
treeData: string | null;
@@ -585,6 +586,14 @@ function FolderTree(treeProps: TreeProps) {
585586
}
586587

587588
fireGoogleUserTree(username ?? '');
589+
590+
const firstTimeLogin = localStorage.getItem(StorageKeys.GOOGLE_FIRST_TIME_LOGIN) === null || localStorage.getItem(StorageKeys.GOOGLE_FIRST_TIME_LOGIN) === 'true';
591+
if (firstTimeLogin) {
592+
localStorage.setItem(StorageKeys.GOOGLE_FIRST_TIME_LOGIN, 'false');
593+
// put up a dialog to inform user that the Google Drive notification about owner created folder and files
594+
setDialogContent(<AlertDialog toggleDialog={toggleDialog} alertMessage={t('googleDriveNotification')} />);
595+
toggleDialog();
596+
}
588597
}
589598

590599
/**

src/components/navbar.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -459,13 +459,20 @@ function NavBar({ layoutref }: NavBarProps) {
459459
console.log(t('exportToPC'));
460460
const session = EditorMgr.getInstance().getEditorSession(activeTab);
461461
if (session) {
462-
CommandToXRPMgr.getInstance()
463-
.getFileContents(session.path)
464-
.then((content) => {
465-
const data: string = new TextDecoder().decode(new Uint8Array(content));
466-
const blob = new Blob([data], { type: 'text/plain;charset=utf-8' });
467-
FileSaver.saveAs(blob, session.name);
462+
if (authService.isLogin) {
463+
// download the file from Google Drive and save to PC
464+
driveService.getFileContents(session.gpath || '').then((fileContent) => {
465+
FileSaver.saveAs(new Blob([fileContent || '']), session.name);
468466
});
467+
} else if (isConnected) {
468+
CommandToXRPMgr.getInstance()
469+
.getFileContents(session.path)
470+
.then((content) => {
471+
const data: string = new TextDecoder().decode(new Uint8Array(content));
472+
const blob = new Blob([data], { type: 'text/plain;charset=utf-8' });
473+
FileSaver.saveAs(blob, session.name);
474+
});
475+
}
469476
} else {
470477
setDialogContent(
471478
<AlertDialog alertMessage={t('no-activetab')} toggleDialog={toggleDialog} />,

src/utils/i18n/locales/en/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"googleLoginTooltip": "Sign in with your Google account to access files stored in Google Drive.",
6161
"googlogoutTooltip": "Sign out of your Google account.",
6262
"not-google-drive-file": "This file can not be saved to Google Drive because it was not associated with Google Drive! Please try savinging it to XRP!",
63+
"googleDriveNotification": "When using Google Drive mode, all folders and files created will be owned by the Google account that is logged in. If you add Google Drive folders or files directly through your Google Drive account, these files are not visible in XRP.",
6364
"userfoldername": "User Folder Name",
6465
"goouserfoldername": "Google User Folder Name",
6566
"chooseFolder": "Choose a Folder",

src/utils/i18n/locales/es/es.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"user-folder": "Nombre de Carpeta de Usuario",
5959
"google-drive-folder": "Nombre de Carpeta de Google Drive",
6060
"not-google-drive-file": "¡Este archivo no se puede guardar en Google Drive porque no se asocia con Google Drive! Por favor intente guardar el archivo en XRP!",
61+
"googleDriveNotification": "Cuando se utiliza el modo Google Drive, todas las carpetas y archivos creados serán propiedad de la cuenta de Google que haya iniciado sesión. Si agrega carpetas o archivos de Google Drive directamente a través de su cuenta de Google Drive, estos archivos no serán visibles en XRP.",
6162
"userfoldername": "Nombre de Carpeta de Usuario",
6263
"goouserfoldername": "Nombre de Carpeta de Usuario de Google",
6364
"chooseFolder": "Elija una Carpeta",

0 commit comments

Comments
 (0)