Skip to content

Commit

Permalink
FIxes: #111 - File open from application main menu
Browse files Browse the repository at this point in the history
  • Loading branch information
jarrodek committed Dec 22, 2018
1 parent 1f96da4 commit c85eda1
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 2 deletions.
23 changes: 22 additions & 1 deletion app.js
Expand Up @@ -22,7 +22,7 @@ class ArcInit {
/* global ipc, ArcContextMenu, ArcElectronDrive, OAuth2Handler,
ThemeManager, ArcPreferencesProxy, CookieBridge, WorkspaceManager,
FilesystemProxy, ElectronAmfService, versionInfo, WindowSearchService,
UpgradeHelper */
UpgradeHelper, ImportFilePrePprocessor */
this.created = false;
this.contextActions = new ArcContextMenu();
this.driveBridge = new ArcElectronDrive();
Expand All @@ -34,6 +34,15 @@ class ArcInit {
this.amfService = new ElectronAmfService();
this.search = new WindowSearchService();
}
/**
* @return {ImportFilePrePprocessor} Instance of import processor class.
*/
get importPreprocessor() {
if (!this.__importPreprocessor) {
this.__importPreprocessor = new ImportFilePrePprocessor();
}
return this.__importPreprocessor;
}
/**
* Reference to the main application window.
*
Expand Down Expand Up @@ -273,8 +282,20 @@ class ArcInit {
case 'open-requests-workspace': app.openWorkspace(); break;
case 'open-web-socket': app.openWebSocket(); break;
case 'popup-menu': this._toggleMenuWindow(); break;
case 'process-external-file': this.processExternalFile(args[0]); break;
default:
console.warn('Unknown command', action, args);
}
}

processExternalFile(filePath) {
return this.importPreprocessor.processFile(filePath)
.catch((cause) => {
this.app.notifyError(cause.message);
console.error(cause);
});
}

/**
* Remote API command.
* Sends number of tabs command to the main process.
Expand Down
2 changes: 2 additions & 0 deletions dev-changelog.md
Expand Up @@ -29,6 +29,8 @@
- Fixed units in Task manager
- Task manager now renders processes names more accurately
- Adding release channels. Now app support Stable, Beta, and Unstable release channels. Access settings in "About ARC" screen.
- Task manager may no show memory info [electron#16179](https://github.com/electron/electron/issues/16179)
- Adding new "File" menu entry to open a file from the filesystem [#111](https://github.com/advanced-rest-client/arc-electron/issues/111)

## Requests

Expand Down
4 changes: 4 additions & 0 deletions menus/darwin.json
Expand Up @@ -68,6 +68,10 @@
"label": "New window",
"command": "application:new-window",
"accelerator": "CommandOrControl+n"
}, {
"label": "Open file",
"command": "application:open-file",
"accelerator": "CommandOrControl+Shift+o"
}, {
"label": "Open saved request",
"command": "application:open-saved",
Expand Down
4 changes: 4 additions & 0 deletions menus/linux.json
Expand Up @@ -13,6 +13,10 @@
"label": "New Window",
"command": "application:new-window",
"accelerator": "CommandOrControl+n"
}, {
"label": "Open file",
"command": "application:open-file",
"accelerator": "CommandOrControl+Shift+o"
}, {
"label": "Open saved request",
"command": "application:open-saved",
Expand Down
4 changes: 4 additions & 0 deletions menus/win.json
Expand Up @@ -13,6 +13,10 @@
"label": "New Window",
"command": "application:new-window",
"accelerator": "CommandOrControl+n"
}, {
"label": "Open file",
"command": "application:open-file",
"accelerator": "CommandOrControl+Shift+o"
}, {
"label": "Open saved request",
"command": "application:open-saved",
Expand Down
4 changes: 4 additions & 0 deletions scripts/main/arc-environment.js
Expand Up @@ -12,6 +12,7 @@ const {AppPrompts} = require('./app-prompts');
const {Oauth2Identity} = require('@advanced-rest-client/electron-oauth2');
const {ThemesProtocolHandler} = require('./theme-protocol');
const {ComponentsProtocolHandler} = require('./components-protocol');
const {AssetImport} = require('./asset-import');
const log = require('./logger');

class ArcEnvironment {
Expand Down Expand Up @@ -216,6 +217,9 @@ class ArcEnvironment {
log.debug('Opening task manager.');
this.wm.openTaskManager();
break;
case 'open-file':
AssetImport.openAssetDialog(win);
break;
case 'open-privacy-policy':
case 'open-documentation':
case 'open-faq':
Expand Down
29 changes: 29 additions & 0 deletions scripts/main/asset-import.js
@@ -0,0 +1,29 @@
const {dialog} = require('electron');
const log = require('./logger');

class AssetImport {
/**
* Opens a dialog to open a file and notifies the window about new content.
*
* @param {BrowserWindow} bWindow
*/
static openAssetDialog(bWindow) {
log.debug('Opening file import dialog.');
dialog.showOpenDialog(bWindow, {
title: 'Select file to import',
buttonLabel: 'Import',
properties: ['openFile'],
filters: [
{name: 'All supported files', extensions: ['arc', 'json', 'raml', 'yaml', 'zip']}
]
}, (filePaths) => {
if (!filePaths || !filePaths[0]) {
log.debug('Import dialog was canceled.');
return;
}
log.debug('Sending file path to open in UI thread: ' + filePaths[0]);
bWindow.webContents.send('command', 'process-external-file', filePaths[0]);
});
}
}
module.exports.AssetImport = AssetImport;
13 changes: 13 additions & 0 deletions scripts/renderer/filesystem-proxy.js
@@ -1,5 +1,6 @@
const {ipcRenderer: ipc} = require('electron');
const fs = require('fs-extra');
const path = require('path');
/**
* This class is a proxy to access user filesystem from the renderer process.
*
Expand Down Expand Up @@ -76,6 +77,18 @@ class FilesystemProxy {
}
return data;
}
/**
* Allows to read file from user filesystem.
* @param {String} path File path to ready
* @return {Promise<Buffer>}
*/
readFile(path) {
return fs.readFile(path);
}

extname(filePath) {
return path.extname(filePath);
}
}

module.exports.FilesystemProxy = FilesystemProxy;
85 changes: 85 additions & 0 deletions scripts/renderer/import-file-preprocessor.js
@@ -0,0 +1,85 @@
const fs = require('fs-extra');
const path = require('path');
class ImportFilePrePprocessor {
/**
* Recognizes file type and sends to appropriate parser.
* @param {String} filePath Location of the file.
* @return {Promise}
*/
processFile(filePath) {
if (!filePath) {
throw new Error('Argument not set');
}
return fs.readFile(filePath)
.then((buffer) => {
const ext = path.extname(filePath);
if (this._isApiFile(ext)) {
return this._notifyApiParser(buffer);
}
// Only JSON files left. It can be either ARC, Postam or OAS
return this._discoverFile(buffer);
});
}

_isApiFile(ext) {
const apiTypes = [
'.zip', '.yaml', '.raml'
];
return apiTypes.indexOf(ext) !== -1;
}

_dispatch(type, detail) {
const e = new CustomEvent(type, {
bubbles: true,
cancelable: true,
detail
});
document.body.dispatchEvent(e);
return e;
}

/**
* Dispatches `api-process-file` to parse API data usingseparate module.
* In ARC electron it is `@advanced-rest-client/electron-amf-service`
* node module. In other it might be other component.
* @param {File} file User file.
* @return {Promise}
*/
_notifyApiParser(file) {
const e = this._dispatch('api-process-file', {
file
});
if (!e.defaultPrevented) {
return Promise.reject(new Error('API processor not available'));
}
return e.detail.result
.then((api) => {
this._dispatch('api-data-ready', {
model: api.model,
type: api.type
});
});
}

_discoverFile(buffer) {
const content = buffer.toString().trim();
if (content[0] !== '{') {
return Promise.reject(new Error('Unsupported file.'));
}
let data;
try {
data = JSON.parse(content);
} catch (_) {
return Promise.reject(new Error('Unknown file format.'));
}
if (data.swagger) {
return this._notifyApiParser(buffer);
}

const e = this._dispatch('import-process-data', {
data
});
return e.detail.result;
}
}
module.exports.ImportFilePrePprocessor = ImportFilePrePprocessor;
2 changes: 2 additions & 0 deletions scripts/renderer/preload.js
Expand Up @@ -15,6 +15,7 @@ const {FilesystemProxy} = require('./filesystem-proxy');
const {ElectronAmfService} = require('../packages/amf-service');
const {WindowSearchService} = require('../packages/search-service/renderer');
const {UpgradeHelper} = require('./upgrade-helper');
const {ImportFilePrePprocessor} = require('./import-file-preprocessor');
const setImmediateFn = setImmediate;
const versions = process.versions;
const env = {};
Expand Down Expand Up @@ -46,6 +47,7 @@ process.once('loaded', () => {
global.WindowSearchService = WindowSearchService;
global.Jexl = Jexl;
global.UpgradeHelper = UpgradeHelper;
global.ImportFilePrePprocessor = ImportFilePrePprocessor;
global.versionInfo = {
chrome: versions.chrome,
appVersion: app.getVersion()
Expand Down
8 changes: 7 additions & 1 deletion src/arc-electron.html
Expand Up @@ -571,7 +571,7 @@
window.addEventListener('process-loading-start', this._processStartHandler);
window.addEventListener('process-loading-stop', this._processStopHandler);
window.addEventListener('process-error', this._processErrorHandler);
this.addEventListener('api-data-ready', this._apiDataHandler);
window.addEventListener('api-data-ready', this._apiDataHandler);
this.addEventListener('process-exchange-asset-data', this._exchangeAssetHandler);
Polymer.RenderStatus.afterNextRender(this, () => {
this._variablesButton = this.shadowRoot.querySelector('#varToggleButton');
Expand Down Expand Up @@ -1298,6 +1298,12 @@
closeActiveTab() {
this.workspace.closeActiveTab();
}

processExternalFile(file) {
if (!file) {
throw new Error('"file" argument is required.');
}
}
}
window.customElements.define(ArcElectron.is, ArcElectron);
// listeners: {
Expand Down

0 comments on commit c85eda1

Please sign in to comment.