Skip to content

Commit fa87e85

Browse files
Enabled large file downloads for desktop users within the query tool. #3369
1 parent 2cb69f0 commit fa87e85

17 files changed

Lines changed: 342 additions & 103 deletions

File tree

runtime/.eslintrc.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//////////////////////////////////////////////////////////////
99
import globals from 'globals';
1010
import js from '@eslint/js';
11+
import unusedImports from 'eslint-plugin-unused-imports';
1112

1213
export default [
1314
js.configs.recommended,
@@ -34,6 +35,9 @@ export default [
3435
'platform': 'readonly',
3536
},
3637
},
38+
'plugins': {
39+
'unused-imports': unusedImports,
40+
},
3741
'rules': {
3842
'indent': [
3943
'error',
@@ -55,6 +59,17 @@ export default [
5559
'no-console': ['error', { allow: ['warn', 'error'] }],
5660
// We need to exclude below for RegEx case
5761
'no-useless-escape': 0,
62+
'no-unused-vars': 'off',
63+
'unused-imports/no-unused-imports': 'error',
64+
'unused-imports/no-unused-vars': [
65+
'warn',
66+
{
67+
'vars': 'all',
68+
'varsIgnorePattern': '^_',
69+
'args': 'after-used',
70+
'argsIgnorePattern': '^_',
71+
},
72+
],
5873
},
5974
},
6075
];

runtime/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
"packageManager": "yarn@3.8.7",
1414
"devDependencies": {
1515
"electron": "36.1.0",
16-
"eslint": "^9.26.0"
16+
"eslint": "^9.26.0",
17+
"eslint-plugin-unused-imports": "^4.1.4"
1718
},
1819
"dependencies": {
1920
"axios": "^1.9.0",
2021
"electron-context-menu": "^4.0.5",
21-
"electron-dl": "^4.0.0",
22-
"electron-store": "^10.0.0"
22+
"electron-store": "^10.0.1"
2323
}
2424
}

runtime/src/js/pgadmin.js

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { spawn } from 'child_process';
1616
import { fileURLToPath } from 'url';
1717
import { setupMenu } from './menu.js';
1818
import contextMenu from 'electron-context-menu';
19-
import { CancelError, download } from 'electron-dl';
19+
import { setupProgressInfo } from './progress.js';
2020

2121
const configStore = new Store({
2222
defaults: {
@@ -35,6 +35,7 @@ let configureWindow = null,
3535
viewLogWindow = null;
3636

3737
let serverPort = 5050;
38+
let baseUrl = `http://127.0.0.1:${serverPort}`;
3839
let appStartTime = (new Date()).getTime();
3940
const __dirname = path.dirname(fileURLToPath(import.meta.url));
4041

@@ -153,28 +154,6 @@ function reloadApp() {
153154
currWin.webContents.reload();
154155
}
155156

156-
async function desktopFileDownload(payload) {
157-
const currWin = BrowserWindow.getFocusedWindow();
158-
try {
159-
await download(currWin, payload.downloadUrl, {
160-
filename: payload.fileName,
161-
saveAs: payload.prompt_for_download_location,
162-
onProgress: (progress) => {
163-
currWin.webContents.send('download-progress', progress);
164-
},
165-
onCompleted: (item) => {
166-
currWin.webContents.send('download-complete', item);
167-
if (payload.automatically_open_downloaded_file)
168-
shell.openPath(item.path);
169-
},
170-
});
171-
} catch (error) {
172-
if (!(error instanceof CancelError)) {
173-
misc.writeServerLog(error);
174-
}
175-
}
176-
}
177-
178157
// This functions is used to start the pgAdmin4 server by spawning a
179158
// separate process.
180159
function startDesktopMode() {
@@ -192,8 +171,9 @@ function startDesktopMode() {
192171
process.env.PGADMIN_SERVER_MODE = 'OFF';
193172

194173
// Start Page URL
195-
startPageUrl = 'http://127.0.0.1:' + serverPort + '/?key=' + UUID;
196-
serverCheckUrl = 'http://127.0.0.1:' + serverPort + '/misc/ping?key=' + UUID;
174+
baseUrl = `http://127.0.0.1:${serverPort}`;
175+
startPageUrl = baseUrl + '/?key=' + UUID;
176+
serverCheckUrl = baseUrl + '/misc/ping?key=' + UUID;
197177

198178
// Write Python Path, pgAdmin file path and command in log file.
199179
misc.writeServerLog('pgAdmin Runtime Environment');
@@ -356,6 +336,8 @@ function launchPgAdminWindow() {
356336
'reloadApp': reloadApp,
357337
});
358338

339+
setupProgressInfo(pgAdminMainScreen);
340+
359341
pgAdminMainScreen.loadURL(startPageUrl);
360342

361343
const bounds = configStore.get('bounds');
@@ -429,7 +411,6 @@ ipcMain.on('log', (text) => ()=>{
429411
misc.writeServerLog(text);
430412
});
431413
ipcMain.on('reloadApp', reloadApp);
432-
ipcMain.on('onFileDownload', (_, payload) => desktopFileDownload(payload));
433414
ipcMain.handle('checkPortAvailable', async (_e, fixedPort)=>{
434415
try {
435416
await misc.getAvailablePort(fixedPort);

runtime/src/js/pgadmin_preload.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,18 @@ contextBridge.exposeInMainWorld('electronUI', {
2424
showSaveDialog: (options) => ipcRenderer.invoke('showSaveDialog', options),
2525
log: (text)=> ipcRenderer.send('log', text),
2626
reloadApp: ()=>{ipcRenderer.send('reloadApp');},
27-
onFileDownload: (payload) => ipcRenderer.send('onFileDownload', payload),
27+
28+
// progress bar
29+
setBadge: (count) => {
30+
ipcRenderer.send('set-badge', count);
31+
},
32+
clearBadge: () => {
33+
ipcRenderer.send('clear-badge');
34+
},
35+
setProgress: (value) => {
36+
ipcRenderer.send('set-progress', value);
37+
},
38+
clearProgress: () => {
39+
ipcRenderer.send('clear-progress');
40+
},
2841
});

runtime/src/js/progress.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { app, ipcMain } from 'electron';
2+
3+
export function setupProgressInfo(mainWindow) {
4+
ipcMain.on('set-badge', (event, count) => {
5+
const badgeCount = parseInt(count, 10);
6+
if (!isNaN(badgeCount)) {
7+
// Set the application badge count (works on macOS and Linux)
8+
app.setBadgeCount(badgeCount);
9+
}
10+
});
11+
12+
// Listen for 'clear-badge' message from renderer process
13+
ipcMain.on('clear-badge', () => {
14+
// Setting count to 0 removes the badge
15+
app.setBadgeCount(0);
16+
});
17+
18+
// Listen for 'set-progress' message from renderer process
19+
ipcMain.on('set-progress', (event, progress) => {
20+
const progressValue = parseFloat(progress);
21+
if (mainWindow && !isNaN(progressValue) && progressValue >= 0 && progressValue <= 1) {
22+
// Set the progress bar on the taskbar icon (works on Windows, macOS, Unity)
23+
// Value should be between 0 and 1.
24+
// Use -1 to enter indeterminate mode (or remove the bar).
25+
mainWindow.setProgressBar(progressValue);
26+
} else if (mainWindow && progress === -1) {
27+
mainWindow.setProgressBar(-1); // Clear or set to indeterminate
28+
}
29+
});
30+
31+
// Listen for 'clear-progress' message from renderer process
32+
ipcMain.on('clear-progress', () => {
33+
if (mainWindow) {
34+
// Setting progress to -1 removes the progress bar
35+
mainWindow.setProgressBar(-1);
36+
}
37+
});
38+
}

runtime/yarn.lock

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ __metadata:
751751
languageName: node
752752
linkType: hard
753753

754-
"electron-store@npm:^10.0.0":
754+
"electron-store@npm:^10.0.1":
755755
version: 10.0.1
756756
resolution: "electron-store@npm:10.0.1"
757757
dependencies:
@@ -881,6 +881,19 @@ __metadata:
881881
languageName: node
882882
linkType: hard
883883

884+
"eslint-plugin-unused-imports@npm:^4.1.4":
885+
version: 4.1.4
886+
resolution: "eslint-plugin-unused-imports@npm:4.1.4"
887+
peerDependencies:
888+
"@typescript-eslint/eslint-plugin": ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0
889+
eslint: ^9.0.0 || ^8.0.0
890+
peerDependenciesMeta:
891+
"@typescript-eslint/eslint-plugin":
892+
optional: true
893+
checksum: 1f4ce3e3972699345513840f3af1b783033dbc3a3e85b62ce12b3f6a89fd8c92afe46d0c00af40bacb14465445983ba0ccc326a6fd5132553061fb0e47bcba19
894+
languageName: node
895+
linkType: hard
896+
884897
"eslint-scope@npm:^8.3.0":
885898
version: 8.3.0
886899
resolution: "eslint-scope@npm:8.3.0"
@@ -1886,9 +1899,9 @@ __metadata:
18861899
axios: ^1.9.0
18871900
electron: 36.1.0
18881901
electron-context-menu: ^4.0.5
1889-
electron-dl: ^4.0.0
1890-
electron-store: ^10.0.0
1902+
electron-store: ^10.0.1
18911903
eslint: ^9.26.0
1904+
eslint-plugin-unused-imports: ^4.1.4
18921905
languageName: unknown
18931906
linkType: soft
18941907

web/pgadmin/dashboard/static/js/Dashboard.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import Replication from './Replication';
4040
import { getExpandCell } from '../../../static/js/components/PgReactTableStyled';
4141
import CodeMirror from '../../../static/js/components/ReactCodeMirror';
4242
import GetAppRoundedIcon from '@mui/icons-material/GetAppRounded';
43-
import { downloadFile } from '../../../static/js/utils';
43+
import { downloadTextData } from '../../../static/js/download';
4444
import RefreshButton from './components/RefreshButtons';
4545

4646
function parseData(data) {
@@ -451,7 +451,7 @@ function Dashboard({
451451
let fileName = 'data-' + new Date().getTime() + extension;
452452

453453
try {
454-
downloadFile(respData, fileName, `text/${type}`);
454+
downloadTextData(respData, fileName, `text/${type}`);
455455
} catch {
456456
setSsMsg(gettext('Failed to download the logs.'));
457457
}

web/pgadmin/misc/file_manager/static/js/components/FileManager.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import Uploader from './Uploader';
3232
import GridView from './GridView';
3333
import convert from 'convert-units';
3434
import PropTypes from 'prop-types';
35-
import { downloadBlob } from '../../../../../static/js/utils';
35+
import { downloadBlob } from '../../../../../static/js/download';
3636
import ErrorBoundary from '../../../../../static/js/helpers/ErrorBoundary';
3737
import { MY_STORAGE } from './FileManagerConstants';
3838
import _ from 'lodash';

web/pgadmin/static/js/Explain/svg_download.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//
88
//////////////////////////////////////////////////////////////
99
import getApiInstance from '../api_instance';
10-
import { downloadFile } from '../utils';
10+
import { downloadTextData } from '../download';
1111

1212
function convertImageURLtoDataURI(api, image) {
1313
return new Promise(function(resolve, reject) {
@@ -43,6 +43,6 @@ export function downloadSvg(svg, svgName) {
4343
}
4444

4545
Promise.all(image_promises).then(function() {
46-
downloadFile(svgElement.outerHTML, svgName, 'image/svg+xml');
46+
downloadTextData(svgElement.outerHTML, svgName, 'image/svg+xml');
4747
});
4848
}

web/pgadmin/static/js/api_instance.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,16 @@ export function parseApiError(error, withData=false) {
5858
}
5959

6060
export function callFetch(url, options, headers={}) {
61-
return fetch(url, {
61+
return fetch(url, getFetchOptions(options, headers));
62+
}
63+
64+
export function getFetchOptions(options, headers={}) {
65+
return {
6266
...options,
6367
headers: {
6468
'Content-type': 'application/json',
6569
[pgAdmin.csrf_token_header]: pgAdmin.csrf_token,
6670
...headers,
6771
}
68-
});
72+
};
6973
}

0 commit comments

Comments
 (0)