NodeJS open local file using the default preview - node.js

I am trying to create a desktop app using electron which includes a function where a user can open a desired file saved in the local storage. Sine I am using MacOS, I want to use nodejs to be able to open the file (e.g. PDF doc) in the default preview software. is there any way to do this?
Thank you in advance.

A portable way is to make use of the Electron's shell API, specifically the shell.openPath method:
const { shell } = require('electron');
shell.openPath("/fullpath/to/file");
It is available both in the main process and in the renderer process, and it can also be used to open a folder in the Finder.

if anyone is wondering I found a way of using
const { exec } = require('child_process')
exec('open ~/path/to/file')
this used command shell (terminal) to open it. If there is any other better way to do it please let us know!

Related

AppImage from electron-builder with file system not working

I’m using Electron Builder to compile my Electron app to an .AppImage file, and I’m using the fs module to write to an .json file, but it’s not working in the appimage format (it’s working fine when I have the normal version not made with Electron Builder). I can still read from the file.
The code (preload):
setSettings: (value) => {fs.writeFileSync(path.join(__dirname, "settings.json"), JSON.stringify(value), "utf8")}
The code (on the website):
api.setSettings(settings);
The project: https://github.com/Nils75owo/crazyshit
That's not a problem with AppImage or Electron Builder but with the way you're packaging your app. Since you didn't post your package.json*, I can only guess what's wrong, but probably you haven't changed Electron Builder's default behaviour regarding packing your application.
By default, Electron Builder compiles your application, including all resources, into a single archive file in the ASAR format (think of it like the TAR format). Electron includes a patched version of the fs module to be able to read from the ASAR file, but writing to it is obviously not supported.
You have two options to mitigate this problem: Either you store your settings somewhere in the user's directory (which is the way I'd go, see below) or you refrain from packing your application to an ASAR file, but that will leave all your JavaScript code outside the executable in a simple folder. (Note that ASAR is not capable of keeping your code confidential, because there are applications which can extract such archives, but it makes it at least a little harder for attackers or curious eyes to get a copy of your code.)
To disable packing to ASAR, simply tell Electron Builder that you don't want it to compile an archive. Thus, in your package.json, include the following:
{
// ... other options
"build": {
// ... other build options
"asar": false
}
}
However, as I mentioned above, it's probably wiser to store settings in a common place where advanced users can actually find (and probably edit, mostly for troubleshooting) them. On Linux, one such folder would be ~/.config, where you could create a subdirectory for your application.
To get the specific application data path on a cross-platform basis, you can query Electron's app module from within the main process. You can do so like this:
const { app } = require ("electron"),
path = require ("path");
var configPath;
try {
configPath = path.join (app.getPath ("appData"), "your-app-name");
} catch (error) {
console.error (error);
app.quit ();
}
If you however have correctly set your application's name (by using app.setName ("...");), you can instead simply use app.getPath ("userData"); and omit the path joining. Take a look at the documentation!
For my Electron Applications, I typically choose to store settings in a common hidden directory (one example for a name could be the brand under which you plan to market the application) in the user's home directory and I then have separate directories for each application. But how you organise this is up to you completely.
* For the future, please refrain from directing us to a GitHub repository and instead include all information (and code is information too) needed to replicate/understand your problem in your question. That'd save us a lot of time and could potentially get you answers faster. Thanks!

Upload action using Nightwatch.js

I am trying to create an action for nightwatch that will upload files to a given upload form. Is it possible to create that kind of action in nightwatch? The nightwatch is integrated into a nodejs application and is running in a selenium webdriver.
Use AutoIT to create an executable for the upload action. Execute the executable using the exec function of the Node. Upload.exe is the executable file compililed from the AutoIt script.
exec('START "" .\\src\\Resources\\Upload.exe', function(err) {
console.log('err: ' + err);})
This question is already asked here.
The approved answer gives this solution:
.setValue('input#fileUpload', require('path').resolve(__dirname + '/testfile.txt'))
You can take a look here at the discussion that led to this fix.

In Electron, how to allow users to pick a file path

I have an Electron App in which when users click on a button I want to open file explorer (or Finder on Mac) for users to choose a path in their file system. Then I want to use this path to save a file.
The second part is quiet easy to achieve. I just need to use writeFile() from node File System API.
However I have gone through the full list of node File System API and I have found nothing allowing me to do the first part.
You should use dialogue module. Simple example for showing the file explorer will be:
const {dialog} = require('electron')
console.log(dialog.showOpenDialog({properties: ['openFile', 'openDirectory', 'multiSelections']}))
Check this link for more information.

How to embed a mac app extension in an Electron app?

I'm trying to embed a Finder Sync extension written in Swift in my app written with Electron. How can I manage to make them work together and communicate with each other? I have read the Apple documentation but it only explains how to add a target to a native application. I also noticed that I can manually inject the .appex compiled file (produced by XCode) in the application Plugins folder using electron builder.
How can I develop and test the extension in XCode and embed it correctly in a custom Electron app?
Any suggestion?
Thank you very much for any suggestion
Create PlugIns folder in your Electron root folder.
Copy the .appex file into PlugIns folder.
If you are using electron-builder, modify the package.json file - add:
"extraFiles": ["PlugIns/"] in the "mac" section.
Build. The Contents of your app package will contain the PlugIns folder and your appex file inside, and the appex will get loaded into your app's process.
How to embed a mac app extension in an Electron app?
I would compile it as an independent binary and include it in some dir to be executed from the electron app using child_process.execFile
You can use arguments when executing the binary with execFile, here is an example (using promise)
const util = require('util');
const execFile = util.promisify(require('child_process').execFile);
async function FinderSyncExtPlugin(ARGUMENTS) {
const { stdout } = await execFile('YourBinary', ARGUMENTS);
console.log(stdout);
}
FinderSyncExtPlugin(['argument1','argument2','...']);
You could then use the stdout to know the status/result of the requested operation.

Electron Node.js node localstorage osx mkdir permission denied

I am working with Electron and Node.js. We have developed an application that works fine on windows and as a requirement had to package it for mac os. I packaged the application using electron-packager, the packaging process completes and package is generated. Double clicking it throws an error that permission denied for mkdir, as i am using node localstorage to maintain some settings on the user's local machine. somehow mac doesn't local storage to create folder in the root of the application. Any help in this matter will be great. Thanks
First off, is the code in question in the main process or in a renderer process? If it is the latter, you don't need to use 'node-localstorage', because you can use the renderer's native LocalStorage. If you are in the main process, then you need to provide your own storage strategy so using 'node-localstorage' is a viable option.
In any case, you need to carefully consider where to store the data; for starters, let's look at where Electron's renderer processes would store its LocalStorage data: this differs based on the OS, but you can get and set the paths using the app module -- the path in question is userData, which on OS X would default to ~/Library/Application Support/<App Name>. Electron uses that folder to persist cookies, caches, LocalStorage etc. so I would suggest using that folder as well. (Otherwise, refer to XDG defaults for good defaults)
What your example above was trying to do is store your 'errorLogDb' in the current working directory, which might depend on your OS, where your App is installed, how you executed it, etc.
Finally, it's a good idea to differentiate between your 'production' app and your app during development and testing, because you might not want to use the same storage folders for every environment. In any case, just writing to './errorLogDb' is likely to cause lots of headaches so I'd be thankful for the permission denied error.
this strategy worked for me:
const { LocalStorage } = require('node-localstorage');
let ls;
mb.on('ready', () => {
let prefsPath = mb.app.getPath('userData') + '/prefs';
ls = new LocalStorage(prefsPath);
loadPrefs();
});
mb.on('after-create-window', () => { /* ls... */ }
exports.togglePref = () => { /* ls... */ }

Resources