Implemented runtime using NWjs to open pgAdmin4 in a standalone window

instead of the system tray and web browser. Used NWjs to get rid of QT
and C++. Fixes #5967

Use cheroot as the default production server for pgAdmin4. Fixes #5017
This commit is contained in:
Akshay Joshi
2021-01-29 13:38:27 +05:30
parent a0271c7656
commit 102ffd141c
392 changed files with 3388 additions and 7599 deletions

View File

@@ -0,0 +1,44 @@
@import "../../node_modules/bootstrap/dist/css/bootstrap.css";
.card {
margin: 0.25rem !important;
}
#status-text {
font-size: medium;
align-self: center;
}
#server_log_label {
font-weight: 500;
}
.btn-primary {
color: #fff;
background-color: #326690;
border-color: #326690;
}
.btn-primary:hover {
color: #fff;
background-color: #285274;
border-color: #254b6a;
}
.btn-primary:focus, .btn-primary.focus {
color: #fff;
background-color: #285274;
border-color: #254b6a;
box-shadow: 0 0 0 0 rgba(81, 125, 161, 0.5);
}
.btn-primary.disabled, .btn-primary:disabled {
color: #fff;
background-color: #326690;
border-color: #326690;
}
.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active, .show > .btn-primary.dropdown-toggle {
color: #fff;
background-color: #254b6a;
border-color: #224461;
}
.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus, .show > .btn-primary.dropdown-toggle:focus {
box-shadow: 0 0 0 0 rgba(81, 125, 161, 0.5);
}

View File

@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>pgAdmin 4 Configuration</title>
<link rel="stylesheet" href="../css/pgadmin-desktop.css"/>
<style>
body, html {
font-size: 14px;
background-color: #ebeef3;
}
</style>
</head>
<body>
<div class="card shadow-sm">
<div class="card-header h6">Fixed Port</div>
<div class="card-body">
<div class="form-group">
<label>By default, the pgAdmin 4 uses a random port number to ensure it can always run successfully. If you need to use a predictable port number, you can set one here. Note that if the port is already in use, the application will be unable to start.</label>
</div>
<div class="form-inline">
<div class="form-check mr-3">
<label class="form-check-label mr-2" for="fixedPortCheck">Fixed port number?</label>
<input type="checkbox" class="form-check-input" id="fixedPortCheck"
data-name="fixed_port"/>
</div>
<div class="form-group">
<label class="mr-1" for="portNo">Port Number</label>
<input type="number" class="form-control" id="portNo" min="1025" max="65535" value="5050" style="min-width: 100px;">
</div>
</div>
</div>
</div>
<div class="card shadow-sm mt-3">
<div class="card-header h6">Connection Timeout</div>
<div class="card-body">
<div class="form-group">
<label>Connection Timeout will define how long to wait for pgAdmin to start before throwing the error. By default, pgAdmin wait for 90 seconds.
</label>
</div>
<div class="form-inline">
<div class="form-group">
<label class="mr-2">Timeout</label>
<input type="number" class="form-control" id="timeOut" min="10" max="600" value="90" style="min-width: 80px;">
<label class="ml-1">seconds</label>
</div>
</div>
</div>
</div>
<div class="p-2 d-flex fixed-bottom shadow bg-white">
<div class="mr-auto" id="status-text"></div>
<div class="ml-auto">
<button id="btnSave" type="submit" class="btn btn-primary" disabled>Save</button>
</div>
</div>
<script type="text/javascript" src="../js/configure.js"></script>
</body>
</html>

View File

@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title>pgAdmin 4</title>
<style>
body, html {
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 14px;
margin: 0 10px;
background-color: #fff;
}
.bg {
background-image: url("../../assets/welcome_logo.svg");
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: contain;
overflow: hidden;
display: flex;
}
.loader-text {
margin-top: auto;
margin-left: auto;
margin-right: auto;
margin-bottom: 10px;
}
</style>
<script type="text/javascript">
let platform = require("os").platform;
</script>
</head>
<body>
<div class="bg">
<span id="loader-text-status" class="loader-text"></span>
</div>
<script type="text/javascript" src="../js/pgadmin.js"></script>
</body>
</html>

View File

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Fatal Error</title>
<link rel="stylesheet" href="../css/pgadmin-desktop.css"/>
<style>
body, html {
font-size: 14px;
background-color: #ebeef3;
}
</style>
</head>
<body>
<div class="card shadow-sm">
<div class="card-body">
<label id="server_error_label" style=" color: red; font-size: large;"></label>
<textarea id="server_error_log" style="min-width: 750px; min-height: 300px; resize: none;" readonly></textarea>
</div>
<div class="p-2 d-flex fixed-bottom shadow bg-white">
<div class="mr-auto" id="status-text"></div>
<div class="ml-auto">
<button id="btnConfigure" class="btn btn-primary">Configure...</button>
</div>
</div>
</div>
<script type="text/javascript" src="../js/server_error.js"></script>
</body>
</html>

View File

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>pgAdmin 4 Log</title>
<link rel="stylesheet" href="../css/pgadmin-desktop.css"/>
<style>
body, html {
font-size: 14px;
background-color: #ebeef3;
}
</style>
</head>
<body>
<div class="card shadow-sm">
<div class="card-body">
<label id="server_log_label">Server Log: </label>
<textarea id="server_log" style="min-width: 750px; min-height: 300px;resize: none;" readonly></textarea>
</div>
<div class="p-2 d-flex fixed-bottom shadow bg-white">
<div class="mr-auto" id="status-text"></div>
<div class="ml-auto">
<button id="btnReload" class="btn btn-primary">Reload</button>
</div>
</div>
</div>
<script type="text/javascript" src="../js/view_log.js"></script>
</body>
</html>

View File

@@ -0,0 +1,91 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
const misc = require('../js/misc.js');
// Get the window object of view log window
var gui = require('nw.gui');
var configWindow = gui.Window.get();
function checkConfiguration() {
if (document.getElementById('fixedPortCheck').checked) {
var fixedPort = parseInt(document.getElementById('portNo').value);
// get the available TCP port
misc.getAvailablePort(fixedPort)
.then(() => {
saveConfiguration();
})
.catch(() => {
alert('The specified fixed port is already in use. Please provide any other valid port.');
});
} else {
saveConfiguration();
}
}
function saveConfiguration() {
misc.ConfigureStore.set('fixedPort', document.getElementById('fixedPortCheck').checked);
misc.ConfigureStore.set('portNo', parseInt(document.getElementById('portNo').value));
misc.ConfigureStore.set('connectionTimeout', parseInt(document.getElementById('timeOut').value));
misc.ConfigureStore.saveConfig();
document.getElementById('status-text').innerHTML = 'Configuration Saved';
if (confirm('The pgAdmin 4 must be restarted for changes to take effect.\n\n Do you want to quit the application?') == true) {
misc.cleanupAndQuitApp();
}
configWindow.close();
}
function onCheckChange() {
if (this.checked) {
document.getElementById('portNo').removeAttribute('disabled');
} else {
document.getElementById('portNo').setAttribute('disabled', 'disabled');
}
// Enable/Disable Save button
enableDisableSaveButton();
}
function enableDisableSaveButton() {
var configData = misc.ConfigureStore.getConfigData();
if (configData['fixedPort'] != document.getElementById('fixedPortCheck').checked ||
configData['portNo'] != document.getElementById('portNo').value ||
configData['connectionTimeout'] != document.getElementById('timeOut').value) {
document.getElementById('btnSave').removeAttribute('disabled');
} else {
document.getElementById('btnSave').setAttribute('disabled', 'disabled');
}
}
configWindow.on('loaded', function() {
document.getElementById('status-text').innerHTML = '';
// Get the config data from the file.
var configData = misc.ConfigureStore.getConfigData();
// Set the GUI value as per configuration.
if (configData['fixedPort']) {
document.getElementById('fixedPortCheck').checked = true;
document.getElementById('portNo').disabled = false;
} else {
document.getElementById('fixedPortCheck').checked = false;
document.getElementById('portNo').disabled = true;
}
document.getElementById('portNo').value = configData['portNo'];
document.getElementById('timeOut').value = configData['connectionTimeout'];
// Add event listeners
document.getElementById('btnSave').addEventListener('click', checkConfiguration);
document.getElementById('fixedPortCheck').addEventListener('change', onCheckChange);
document.getElementById('portNo').addEventListener('change', enableDisableSaveButton);
document.getElementById('timeOut').addEventListener('change', enableDisableSaveButton);
});

316
runtime/src/js/misc.js Normal file
View File

@@ -0,0 +1,316 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
const fs = require('fs');
const path = require('path');
const net = require('net');
const {platform, homedir} = require('os');
var pgadminServerProcess = null;
var pgAdminWindowObject = null;
// This function is used to check whether directory is present or not
// if not present then create it recursively
const createDir = (dirName) => {
if (!fs.existsSync(dirName)) {
fs.mkdirSync(dirName, {recursive: true});
}
};
// This function is used to get the python executable path
// based on the platform. Use this for deployment.
const getPythonPath = () => {
var pythonPath = '';
switch (platform()) {
case 'win32':
pythonPath = '../python/python.exe';
break;
case 'darwin':
pythonPath = '../../Frameworks/Python.framework/Versions/Current/bin/python3';
break;
case 'linux':
pythonPath = '../venv/bin/python3';
break;
default:
if (platform().startsWith('win')) {
pythonPath = '../python/python.exe';
} else {
pythonPath = '../venv/bin/python3';
}
}
return pythonPath;
};
// This function is used to get the [roaming] app data path
// based on the platform. Use this for config etc.
const getAppDataPath = () => {
var appDataPath = '';
switch (platform()) {
case 'win32':
appDataPath = path.join(process.env.APPDATA, 'pgadmin');
break;
case 'darwin':
appDataPath = path.join(homedir(), 'Library', 'Preferences', 'pgadmin');
break;
case 'linux':
if ('XDG_CONFIG_HOME' in process.env) {
appDataPath = path.join(process.env.XDG_CONFIG_HOME, 'pgadmin');
} else {
appDataPath = path.join(homedir(), '.config', 'pgadmin');
}
break;
default:
if (platform().startsWith('win')) {
appDataPath = path.join(process.env.APPDATA, 'pgadmin');
} else {
if ('XDG_CONFIG_HOME' in process.env) {
appDataPath = path.join(process.env.XDG_CONFIG_HOME, 'pgadmin');
} else {
appDataPath = path.join(homedir(), '.config', 'pgadmin');
}
}
}
// Create directory if not exists
createDir(appDataPath);
return appDataPath;
};
// This function is used to get the [local] app data path
// based on the platform. Use this for logs etc.
const getLocalAppDataPath = () => {
var localAppDataPath = '';
switch (platform()) {
case 'win32':
localAppDataPath = path.join(process.env.LOCALAPPDATA, 'pgadmin');
break;
case 'darwin':
localAppDataPath = path.join(homedir(), 'Library', 'Application Support', 'pgadmin');
break;
case 'linux':
if ('XDG_DATA_HOME' in process.env) {
localAppDataPath = path.join(process.env.XDG_DATA_HOME, 'pgadmin');
} else {
localAppDataPath = path.join(homedir(), '.local', 'share', 'pgadmin');
}
break;
default:
if (platform().startsWith('win')) {
localAppDataPath = path.join(process.env.LOCALAPPDATA, 'pgadmin');
} else {
if ('XDG_DATA_HOME' in process.env) {
localAppDataPath = path.join(process.env.XDG_DATA_HOME, 'pgadmin');
} else {
localAppDataPath = path.join(homedir(), '.local', 'share', 'pgadmin');
}
}
}
// Create directory if not exists
createDir(localAppDataPath);
return localAppDataPath;
};
// This function is used to get the random available TCP port
// if fixedPort is set to 0. Else check whether port is in used or not.
const getAvailablePort = (fixedPort) => {
return new Promise(function(resolve, reject) {
const server = net.createServer();
server.listen(fixedPort, '127.0.0.1');
server.on('error', (e) => {
reject(e.code);
});
server.on('listening', () => {
var serverPort = server.address().port;
server.close();
resolve(serverPort);
});
});
};
// Get the app data folder path
const currentTime = (new Date()).getTime();
const serverLogFile = path.join(getLocalAppDataPath(), 'pgadmin4.' + currentTime.toString() + '.log');
const configFileName = path.join(getAppDataPath(), 'runtime_config.json');
const DEFAULT_CONFIG_DATA = {'fixedPort': false, 'portNo': 5050, 'connectionTimeout': 90, 'windowWidth': 1300, 'windowHeight': 900};
// This function is used to read the file and return the content
const readServerLog = () => {
var data = null;
if (fs.existsSync(serverLogFile)) {
data = fs.readFileSync(serverLogFile, 'utf8');
} else {
var errMsg = 'Unable to read file ' + serverLogFile + ' not found.';
console.warn(errMsg);
return errMsg;
}
return data;
};
// This function is used to write the data into the log file
const writeServerLog = (data) => {
data = data + '\n';
if (fs.existsSync(serverLogFile)) {
fs.writeFileSync(serverLogFile, data, {flag: 'a+'});
} else {
fs.writeFileSync(serverLogFile, data, {flag: 'w'});
}
};
// This function is used to remove the log file
const removeLogFile = () => {
if (fs.existsSync(serverLogFile)) {
fs.rmSync(serverLogFile);
}
};
// This function used to set the object of pgAdmin server process.
const setProcessObject = (processObject) => {
pgadminServerProcess = processObject;
};
// This function used to set the object of pgAdmin window.
const setPgAdminWindowObject = (windowObject) => {
pgAdminWindowObject = windowObject;
};
// This function is used to get the server log file.
const getServerLogFile = () => {
return serverLogFile;
};
// This function is used to get the runtime config file.
const getRunTimeConfigFile = () => {
return configFileName;
};
// This function is used to kill the server process, remove the log files
// and quit the application.
const cleanupAndQuitApp = () => {
// Remove the server log file on exit
removeLogFile();
// Killing pgAdmin4 server process if application quits
if (pgadminServerProcess != null) {
try {
process.kill(pgadminServerProcess.pid);
}
catch (e) {
console.warn('Failed to kill server process.');
}
}
if (pgAdminWindowObject != null) {
// Close the window.
pgAdminWindowObject.close(true);
// Remove all the cookies.
pgAdminWindowObject.cookies.getAll({}, function(cookies) {
try {
cookies.forEach(function(cookie) {
pgAdminWindowObject.cookies.remove({url: 'http://' + cookie.domain, name: cookie.name});
});
} catch (error) {
console.warn('Failed to remove cookies.');
} finally {
pgAdminWindowObject = null;
// Quit Application
nw.App.quit();
}
});
} else {
// Quit Application
nw.App.quit();
}
};
var ConfigureStore = {
fileName: configFileName,
jsonData: {},
init: function() {
if (!this.readConfig()){
this.jsonData = DEFAULT_CONFIG_DATA;
this.saveConfig();
}
},
// This function is used to write configuration data
saveConfig: function() {
fs.writeFileSync(this.fileName, JSON.stringify(this.jsonData, null, 4), {flag: 'w'});
},
// This function is used to read the configuration data
readConfig: function() {
if (fs.existsSync(this.fileName)) {
try {
this.jsonData = JSON.parse(fs.readFileSync(this.fileName));
} catch (error) {
/* If the file is not present or invalid JSON data in file */
this.jsonData = {};
}
} else {
var errMsg = 'Unable to read file ' + this.fileName + ' not found.';
console.warn(errMsg);
return false;
}
return true;
},
getConfigData: function() {
return this.jsonData;
},
get: function(key, if_not_value) {
if(this.jsonData[key] != undefined) {
return this.jsonData[key];
} else {
return if_not_value;
}
},
set: function(key, value) {
if(typeof key === 'object'){
this.jsonData = {
...this.jsonData,
...key,
};
} else {
if(value === '' || value == null || typeof(value) == 'undefined') {
if(this.jsonData[key] != undefined) {
delete this.jsonData[key];
}
} else {
this.jsonData[key] = value;
}
}
},
};
module.exports = {
readServerLog: readServerLog,
writeServerLog: writeServerLog,
getAvailablePort: getAvailablePort,
getPythonPath: getPythonPath,
setProcessObject: setProcessObject,
cleanupAndQuitApp: cleanupAndQuitApp,
getServerLogFile: getServerLogFile,
getRunTimeConfigFile: getRunTimeConfigFile,
setPgAdminWindowObject: setPgAdminWindowObject,
ConfigureStore: ConfigureStore,
};

300
runtime/src/js/pgadmin.js Normal file
View File

@@ -0,0 +1,300 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const misc = require('../js/misc.js');
const spawn = require('child_process').spawn;
var pgadminServerProcess = null;
var startPageUrl = null;
var serverCheckUrl = null;
var serverPort = 5050;
// Paths to the rest of the app
var pythonPath = misc.getPythonPath();
var pgadminFile = '../web/pgAdmin4.py';
var configFile = '../web/config.py';
// Override the paths above, if a developer needs to
if (fs.existsSync('dev_config.json')) {
try {
var dev_config = JSON.parse(fs.readFileSync('dev_config.json'));
pythonPath = dev_config['pythonPath'];
pgadminFile = dev_config['pgadminFile'];
} catch (error) {
// Meh.
}
}
// This function is used to create UUID
function createUUID() {
var dt = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (dt + Math.random()*16)%16 | 0;
dt = Math.floor(dt/16);
return (c=='x' ? r :(r&0x3|0x8)).toString(16);
});
return uuid;
}
// This functions is used to start the pgAdmin4 server by spawning a
// separate process.
function startDesktopMode() {
// Return if pgadmin server process is already spawned
// Added check for debugging purpose.
if (pgadminServerProcess != null)
return;
var UUID = createUUID();
// Set the environment variable so that pgAdmn 4 server
// start listening on that port.
process.env.PGADMIN_INT_PORT = serverPort;
process.env.PGADMIN_INT_KEY = UUID;
process.env.PGADMIN_SERVER_MODE = 'OFF';
// Start Page URL
startPageUrl = 'http://127.0.0.1:' + serverPort + '/?key=' + UUID;
serverCheckUrl = 'http://127.0.0.1:' + serverPort + '/misc/ping?key=' + UUID;
document.getElementById('loader-text-status').innerHTML = 'Starting pgAdmin 4...';
// Write Python Path, pgAdmin file path and command in log file.
var command = path.resolve(pythonPath) + ' ' + path.resolve(pgadminFile);
misc.writeServerLog('Python Path: "' + path.resolve(pythonPath) + '"');
misc.writeServerLog('Runtime Config File: "' + path.resolve(misc.getRunTimeConfigFile()) + '"');
misc.writeServerLog('pgAdmin Config File: "' + path.resolve(configFile) + '"');
misc.writeServerLog('Webapp Path: "' + path.resolve(pgadminFile) + '"');
misc.writeServerLog('pgAdmin Command: "' + command + '"');
// Spawn the process to start pgAdmin4 server.
pgadminServerProcess = spawn(pythonPath, [pgadminFile]);
pgadminServerProcess.on('error', function(err) {
// Log the error into the log file if process failed to launch
misc.writeServerLog('Failed to lauch pgAdmin4 with below error:');
misc.writeServerLog(err);
});
pgadminServerProcess.stdout.setEncoding('utf8');
pgadminServerProcess.stdout.on('data', (chunk) => {
misc.writeServerLog(chunk);
});
pgadminServerProcess.stderr.setEncoding('utf8');
pgadminServerProcess.stderr.on('data', (chunk) => {
if (chunk.indexOf('Runtime Open Configuration') > -1) {
// Create and launch new window and open pgAdmin url
nw.Window.open('src/html/configure.html', {
'frame': true,
'width': 600,
'height': 420,
'position': 'center',
'resizable': false,
'focus': true,
'show': true,
});
} else if (chunk.indexOf('Runtime Open View Log') > -1) {
// Create and launch new window and open pgAdmin url
nw.Window.open('src/html/view_log.html', {
'frame': true,
'width': 790,
'height': 425,
'position': 'center',
'resizable': false,
'focus': true,
'show': true,
});
} else {
misc.writeServerLog(chunk);
}
});
// This function is used to ping the pgAdmin4 server whether it
// it is started or not.
function pingServer() {
return axios.get(serverCheckUrl);
}
var connectionTimeout = misc.ConfigureStore.get('connectionTimeout', 90) * 1000;
var currentTime = (new Date).getTime();
var endTime = currentTime + connectionTimeout;
var midTime1 = currentTime + (connectionTimeout/2);
var midTime2 = currentTime + (connectionTimeout*2/3);
var pingInProgress = false;
// ping pgAdmin server every 1 second.
var intervalID = setInterval(function() {
// If ping request is already send and response is not
// received no need to send another request.
if (pingInProgress)
return;
pingServer().then(() => {
pingInProgress = false;
document.getElementById('loader-text-status').innerHTML = 'pgAdmin 4 started';
// Set the pgAdmin process object to misc
misc.setProcessObject(pgadminServerProcess);
clearInterval(intervalID);
launchPgAdminWindow();
}).catch(() => {
pingInProgress = false;
var curTime = (new Date).getTime();
// if the connection timeout has lapsed then throw an error
// and stop pinging the server.
if (curTime >= endTime) {
clearInterval(intervalID);
splashWindow.hide();
nw.Window.open('src/html/server_error.html', {
'frame': true,
'width': 790,
'height': 430,
'position': 'center',
'resizable': false,
'focus': true,
'show': true,
});
}
if (curTime > midTime1) {
if(curTime < midTime2) {
document.getElementById('loader-text-status').innerHTML = 'Taking longer than usual...';
} else {
document.getElementById('loader-text-status').innerHTML = 'Almost there...';
}
} else {
document.getElementById('loader-text-status').innerHTML = 'Waiting for pgAdmin 4 to start...';
}
});
pingInProgress = true;
}, 1000);
}
// This function is used to hide the splash screen and create/launch
// new window to render pgAdmin4 page.
function launchPgAdminWindow() {
// Create and launch new window and open pgAdmin url
misc.writeServerLog('Application Server URL: ' + startPageUrl);
var winWidth = misc.ConfigureStore.get('windowWidth', 1300);
var winHeight = misc.ConfigureStore.get('windowHeight', 900);
nw.Window.open(startPageUrl, {
'icon': '../../assets/pgAdmin4.png',
'frame': true,
'width': winWidth,
'height': winHeight,
'position': 'center',
'resizable': true,
'min_width': 400,
'min_height': 200,
'focus': true,
'show': false,
}, (pgadminWindow)=> {
// Set pgAdmin4 Windows Object
misc.setPgAdminWindowObject(pgadminWindow);
pgadminWindow.on('close', function() {
misc.cleanupAndQuitApp();
});
// set up handler for new-win-policy event.
// Set the width and height for the new window.
pgadminWindow.on('new-win-policy', function(frame, url, policy) {
policy.setNewWindowManifest({
'icon': '../../assets/pgAdmin4.png',
'frame': true,
'width': winWidth,
'height': winHeight,
'position': 'center',
});
});
pgadminWindow.on('loaded', function() {
// Hide the splash screen
splashWindow.hide();
/* Make the new window opener to null as it is
* nothing but a splash screen. We will have to make it null,
* so that open in new browser tab will work.
*/
pgadminWindow.window.opener = null;
// Show new window
pgadminWindow.show();
pgadminWindow.focus();
});
pgadminWindow.on('resize', function(width, height) {
// Set the width and height for the new window on resize.
pgadminWindow.on('new-win-policy', function(frame, url, policy) {
policy.setNewWindowManifest({
'icon': '../../assets/pgAdmin4.png',
'frame': true,
'width': width,
'height': height,
'position': 'center',
});
});
misc.ConfigureStore.set('windowWidth', width);
misc.ConfigureStore.set('windowHeight', height);
misc.ConfigureStore.saveConfig();
});
});
}
// Get the gui object of NW.js
var gui = require('nw.gui');
var splashWindow = gui.Window.get();
// Always clear the cache before starting the application.
nw.App.clearCache();
// Create Mac Builtin Menu
if (platform() == 'darwin') {
var macMenu = new gui.Menu({type: 'menubar'});
macMenu.createMacBuiltin('pgAdmin 4');
gui.Window.get().menu = macMenu;
}
splashWindow.on('loaded', function() {
// Initialize the ConfigureStore
misc.ConfigureStore.init();
var fixedPortCheck = misc.ConfigureStore.get('fixedPort', false);
if (fixedPortCheck) {
serverPort = misc.ConfigureStore.get('portNo');
//Start the pgAdmin in Desktop mode.
startDesktopMode();
} else {
// get the available TCP port by sending port no to 0.
misc.getAvailablePort(0)
.then((pythonApplicationPort) => {
serverPort = pythonApplicationPort;
//Start the pgAdmin in Desktop mode.
startDesktopMode();
})
.catch((errCode) => {
if (fixedPortCheck && errCode == 'EADDRINUSE') {
alert('The specified fixed port is already in use. Please provide any other valid port.');
} else {
alert(errCode);
}
});
}
});
splashWindow.on('close', function() {
misc.cleanupAndQuitApp();
});

View File

@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
const misc = require('../js/misc.js');
// Get the window object of server error window
var gui = require('nw.gui');
var errorWindow = gui.Window.get();
errorWindow.on('loaded', function() {
document.getElementById('server_error_label').innerHTML = 'The pgAdmin 4 server could not be contacted:';
document.getElementById('server_error_log').innerHTML = misc.readServerLog();
document.getElementById('btnConfigure').addEventListener('click', function() {
nw.Window.open('src/html/configure.html', {
'frame': true,
'width': 600,
'height': 420,
'position': 'center',
'resizable': false,
'focus': true,
'show': true,
});
});
});
errorWindow.on('close', function() {
misc.cleanupAndQuitApp();
});

View File

@@ -0,0 +1,27 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
const misc = require('../js/misc.js');
// Get the window object of view log window
var gui = require('nw.gui');
var logWindow = gui.Window.get();
logWindow.on('loaded', function() {
document.getElementById('status-text').innerHTML = '';
document.getElementById('server_log_label').innerHTML = 'Server Log: ' + '(' + misc.getServerLogFile() + ')';
document.getElementById('server_log').innerHTML = misc.readServerLog();
document.getElementById('btnReload').addEventListener('click', function() {
document.getElementById('server_log').innerHTML = 'Loading logs...';
setTimeout(function() {
document.getElementById('server_log').innerHTML = misc.readServerLog();
}, 500);
document.getElementById('status-text').innerHTML = 'Logs reloaded successfully';
});
});