mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
Added import from URI ability (#160)
* Added import from URI ability * Add protocol handlers * Fix for keymap setting on read-only mode * Refactored some main components out * Protocols shoudl work now
This commit is contained in:
parent
47e1dccebc
commit
7b8d26c292
4
.npmrc
4
.npmrc
@ -1,4 +0,0 @@
|
||||
runtime=electron
|
||||
target=1.6.5
|
||||
target_arch=x64
|
||||
disturl=https://atom.io/download/atom-shell
|
@ -31,8 +31,9 @@ Development on Insomnia can be done on Windows, Mac, and Linux with few requirem
|
||||
requires [NodeJS 7.4](https://nodejs.org) and [Git](https://git-scm.com/) to get started.
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
# Install dependencies and build addons for Electron
|
||||
npm install
|
||||
npm run rebuild
|
||||
|
||||
# Start app
|
||||
npm run dev
|
||||
|
12
app/__tests__/package.test.js
Normal file
12
app/__tests__/package.test.js
Normal file
@ -0,0 +1,12 @@
|
||||
import * as appPackage from '../package.json';
|
||||
import * as globalPackage from '../../package.json';
|
||||
|
||||
describe('package.json', () => {
|
||||
it('all app dependencies should be same in global', () => {
|
||||
for (const name of Object.keys(appPackage.dependencies)) {
|
||||
const expected = globalPackage.dependencies[name];
|
||||
const actual = appPackage.dependencies[name];
|
||||
expect(`${name}::${actual}`).toBe(`${name}::${expected}`);
|
||||
}
|
||||
});
|
||||
});
|
@ -26,6 +26,14 @@ export function isMac () {
|
||||
return getAppPlatform() === 'darwin';
|
||||
}
|
||||
|
||||
export function isLinux () {
|
||||
return getAppPlatform() === 'linux';
|
||||
}
|
||||
|
||||
export function isWindows () {
|
||||
return getAppPlatform() === 'win32';
|
||||
}
|
||||
|
||||
export function isDevelopment () {
|
||||
return getAppEnvironment() === 'development';
|
||||
}
|
||||
@ -48,6 +56,7 @@ export const CHANGELOG_PAGE = 'https://insomnia.rest/changelog/';
|
||||
export const STATUS_CODE_RENDER_FAILED = -333;
|
||||
export const LARGE_RESPONSE_MB = 5;
|
||||
export const FLEXIBLE_URL_REGEX = /^(http|https):\/\/[0-9a-zA-Z\-_.]+[/\w.\-+=:\][@%^*&!#?;]*/;
|
||||
export const CHECK_FOR_UPDATES_INTERVAL = 1000 * 60 * 60 * 3; // 3 hours
|
||||
|
||||
// Hotkeys
|
||||
export const MOD_SYM = isMac() ? '⌘' : 'ctrl';
|
||||
|
@ -3,6 +3,11 @@ import * as db from './database';
|
||||
import * as models from '../models';
|
||||
import {getAppVersion} from './constants';
|
||||
import * as misc from './misc';
|
||||
import {showModal} from '../ui/components/modals/index';
|
||||
import AlertModal from '../ui/components/modals/alert-modal';
|
||||
import * as fetch from './fetch';
|
||||
import fs from 'fs';
|
||||
import {trackEvent} from '../analytics/index';
|
||||
|
||||
const EXPORT_FORMAT = 3;
|
||||
|
||||
@ -23,6 +28,43 @@ const MODELS = {
|
||||
[EXPORT_TYPE_ENVIRONMENT]: models.environment
|
||||
};
|
||||
|
||||
export async function importUri (workspaceId, uri) {
|
||||
let rawText;
|
||||
if (uri.match(/^(http|https):\/\//)) {
|
||||
const response = await fetch.rawFetch(uri);
|
||||
rawText = await response.text();
|
||||
} else if (uri.match(/^(file):\/\//)) {
|
||||
const path = uri.replace(/^(file):\/\//, '');
|
||||
rawText = fs.readFileSync(path, 'utf8');
|
||||
} else {
|
||||
throw new Error(`Invalid import URI ${uri}`);
|
||||
}
|
||||
|
||||
const workspace = await models.workspace.getById(workspaceId);
|
||||
const result = await importRaw(workspace, rawText);
|
||||
const {summary, source, error} = result;
|
||||
|
||||
if (error) {
|
||||
showModal(AlertModal, {title: 'Import Failed', message: error});
|
||||
return;
|
||||
}
|
||||
|
||||
let statements = Object.keys(summary).map(type => {
|
||||
const count = summary[type].length;
|
||||
const name = models.getModelName(type, count);
|
||||
return count === 0 ? null : `${count} ${name}`;
|
||||
}).filter(s => s !== null);
|
||||
|
||||
let message;
|
||||
if (statements.length === 0) {
|
||||
message = 'Nothing was found to import.';
|
||||
} else {
|
||||
message = `You imported ${statements.join(', ')}!`;
|
||||
}
|
||||
showModal(AlertModal, {title: 'Import Succeeded', message});
|
||||
trackEvent('Import', 'Success', source);
|
||||
}
|
||||
|
||||
export async function importRaw (workspace, rawContent, generateNewIds = false) {
|
||||
let results;
|
||||
try {
|
||||
|
@ -92,6 +92,9 @@ export function prettifyJson (json, indentChars) {
|
||||
}
|
||||
newJson += currentChar;
|
||||
break;
|
||||
case '\r':
|
||||
// Skip windows return characters
|
||||
break;
|
||||
default:
|
||||
newJson += currentChar;
|
||||
break;
|
||||
|
@ -1,192 +1,39 @@
|
||||
import reboot from 'electron-squirrel-startup';
|
||||
if (reboot) {
|
||||
import needsRestart from 'electron-squirrel-startup';
|
||||
import electron from 'electron';
|
||||
import {isDevelopment, isMac} from './common/constants';
|
||||
import * as errorHandling from './main/error-handling';
|
||||
import * as updates from './main/updates';
|
||||
import {createWindow} from './main/window-utils';
|
||||
|
||||
// Handle potential auto-update
|
||||
if (needsRestart) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
import fs from 'fs';
|
||||
import Raven from 'raven';
|
||||
import path from 'path';
|
||||
import electron from 'electron';
|
||||
import * as packageJSON from './package.json';
|
||||
import LocalStorage from './common/local-storage';
|
||||
// Initialize some things
|
||||
errorHandling.init();
|
||||
updates.init();
|
||||
|
||||
// Some useful helpers
|
||||
const IS_DEV = process.env.INSOMNIA_ENV === 'development';
|
||||
const IS_MAC = process.platform === 'darwin';
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
const IS_LINUX = !IS_MAC && !IS_WINDOWS;
|
||||
|
||||
const ravenClient = Raven.config('https://786e43ae199c4757a9ea4a48a9abd17d@sentry.io/109702', {
|
||||
environment: process.env.INSOMNIA_ENV || 'production',
|
||||
release: packageJSON.version,
|
||||
logger: 'electron.main'
|
||||
});
|
||||
|
||||
if (!IS_DEV) {
|
||||
ravenClient.install();
|
||||
function addUrlToOpen (e, url) {
|
||||
e.preventDefault();
|
||||
args.push(url);
|
||||
}
|
||||
|
||||
const {app, dialog, shell, ipcMain, autoUpdater, Menu, BrowserWindow} = electron;
|
||||
const {version: appVersion, productName: appName} = packageJSON;
|
||||
const {app, ipcMain} = electron;
|
||||
|
||||
const UPDATE_URLS = {
|
||||
// Add `r` param to help cache bust
|
||||
darwin: `https://updates.insomnia.rest/builds/check/mac?v=${appVersion}`,
|
||||
linux: `https://updates.insomnia.rest/builds/check/linux?v=${appVersion}`,
|
||||
win32: `https://downloads.insomnia.rest/win`
|
||||
};
|
||||
const args = process.argv.slice(1);
|
||||
|
||||
let localStorage = null;
|
||||
// Set as default protocol
|
||||
app.setAsDefaultProtocolClient(`insomnia${isDevelopment() ? 'dev' : ''}`);
|
||||
|
||||
let mainWindow = null;
|
||||
let hasPromptedForUpdates = false;
|
||||
app.on('open-url', addUrlToOpen);
|
||||
|
||||
// Enable this for CSS grid layout :)
|
||||
app.commandLine.appendSwitch('enable-experimental-web-platform-features');
|
||||
|
||||
process.on('uncaughtException', e => {
|
||||
if (IS_DEV) {
|
||||
console.error(e);
|
||||
} else {
|
||||
ravenClient.captureError(e, {});
|
||||
}
|
||||
});
|
||||
|
||||
autoUpdater.on('error', e => {
|
||||
if (IS_DEV) {
|
||||
console.error(e);
|
||||
} else {
|
||||
// Don't report autoUpdater error. They are way too noisy
|
||||
}
|
||||
});
|
||||
|
||||
autoUpdater.on('update-not-available', () => {
|
||||
console.log('-- Update Not Available --');
|
||||
});
|
||||
|
||||
autoUpdater.on('update-available', () => {
|
||||
console.log('-- Update Available --');
|
||||
});
|
||||
|
||||
autoUpdater.on('update-downloaded', (e, releaseNotes, releaseName, releaseDate, updateUrl) => {
|
||||
console.log(`-- Update Downloaded ${releaseName} --`);
|
||||
showUpdateNotification();
|
||||
});
|
||||
|
||||
function checkForUpdates () {
|
||||
if (hasPromptedForUpdates) {
|
||||
// We've already prompted for updates. Don't bug the user anymore
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_DEV) {
|
||||
console.log('-- Skipping update check in Development --');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IS_LINUX) {
|
||||
try {
|
||||
autoUpdater.setFeedURL(UPDATE_URLS[process.platform]);
|
||||
autoUpdater.checkForUpdates();
|
||||
} catch (e) {
|
||||
// This will fail in development
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showUnresponsiveModal () {
|
||||
dialog.showMessageBox({
|
||||
type: 'info',
|
||||
buttons: ['Cancel', 'Reload'],
|
||||
defaultId: 1,
|
||||
cancelId: 0,
|
||||
title: 'Unresponsive',
|
||||
message: 'Insomnia has become unresponsive. Do you want to reload?'
|
||||
}, id => {
|
||||
if (id === 1) {
|
||||
mainWindow.destroy();
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showUpdateNotification () {
|
||||
if (hasPromptedForUpdates) {
|
||||
return;
|
||||
}
|
||||
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.send('update-available');
|
||||
hasPromptedForUpdates = true;
|
||||
}
|
||||
|
||||
function trackEvent (...args) {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.send('analytics-track-event', args);
|
||||
}
|
||||
|
||||
ipcMain.on('check-for-updates', () => {
|
||||
console.log('-- Checking for Updates --');
|
||||
checkForUpdates();
|
||||
});
|
||||
|
||||
function saveBounds () {
|
||||
if (!mainWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fullscreen = mainWindow.isFullScreen();
|
||||
|
||||
// Only save the size if we're not in fullscreen
|
||||
if (!fullscreen) {
|
||||
localStorage.setItem('bounds', mainWindow.getBounds());
|
||||
localStorage.setItem('fullscreen', false);
|
||||
} else {
|
||||
localStorage.setItem('fullscreen', true);
|
||||
}
|
||||
}
|
||||
|
||||
function getBounds () {
|
||||
let bounds = {};
|
||||
let fullscreen = false;
|
||||
try {
|
||||
bounds = localStorage.getItem('bounds', {});
|
||||
fullscreen = localStorage.getItem('fullscreen', false);
|
||||
} catch (e) {
|
||||
// This should never happen, but if it does...!
|
||||
console.error('Failed to parse window bounds', e);
|
||||
}
|
||||
|
||||
return {bounds, fullscreen};
|
||||
}
|
||||
|
||||
function saveZoomFactor (zoomFactor) {
|
||||
localStorage.setItem('zoomFactor', zoomFactor);
|
||||
}
|
||||
|
||||
function getZoomFactor () {
|
||||
let zoomFactor = 1;
|
||||
try {
|
||||
zoomFactor = localStorage.getItem('zoomFactor', 1);
|
||||
} catch (e) {
|
||||
// This should never happen, but if it does...!
|
||||
console.error('Failed to parse zoomFactor', e);
|
||||
}
|
||||
|
||||
return zoomFactor;
|
||||
}
|
||||
|
||||
// Quit when all windows are closed (except on Mac).
|
||||
app.on('window-all-closed', () => {
|
||||
if (!IS_MAC) {
|
||||
if (!isMac()) {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
@ -207,307 +54,26 @@ app.on('activate', (e, hasVisibleWindows) => {
|
||||
|
||||
// When the app is first launched
|
||||
app.on('ready', () => {
|
||||
initLocalStorage();
|
||||
createWindow();
|
||||
checkForUpdates();
|
||||
app.removeListener('open-url', addUrlToOpen);
|
||||
const window = createWindow();
|
||||
|
||||
// Handle URLs sent via command line args
|
||||
ipcMain.once('app-ready', () => {
|
||||
args.length && window.send('run-command', args[0]);
|
||||
});
|
||||
|
||||
// Called when second instance launched with args (Windows)
|
||||
app.makeSingleInstance(args => {
|
||||
args.length && window.send('run-command', args[0]);
|
||||
});
|
||||
|
||||
// Handle URLs when app already open
|
||||
app.addListener('open-url', (e, url) => {
|
||||
window.send('run-command', url);
|
||||
// Apparently a timeout is needed because Chrome steals back focus immediately
|
||||
// after opening the URL.
|
||||
setTimeout(() => {
|
||||
window.focus();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
function initLocalStorage () {
|
||||
const localStoragePath = path.join(app.getPath('userData'), 'localStorage');
|
||||
localStorage = new LocalStorage(localStoragePath);
|
||||
}
|
||||
|
||||
function createWindow () {
|
||||
const zoomFactor = getZoomFactor();
|
||||
const {bounds, fullscreen} = getBounds();
|
||||
const {x, y, width, height} = bounds;
|
||||
|
||||
// Make sure we don't place the window outside of the visible space
|
||||
let maxX = 0;
|
||||
let maxY = 0;
|
||||
for (const d of electron.screen.getAllDisplays()) {
|
||||
// Set the maximum placement location to 50 pixels short of the end
|
||||
maxX = Math.max(maxX, d.bounds.x + d.bounds.width - 50);
|
||||
maxY = Math.max(maxY, d.bounds.y + d.bounds.height - 50);
|
||||
}
|
||||
const finalX = Math.min(maxX, x);
|
||||
const finalY = Math.min(maxX, y);
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
// Make sure we don't initialize the window outside the bounds
|
||||
x: finalX,
|
||||
y: finalY,
|
||||
fullscreen: fullscreen,
|
||||
fullscreenable: true,
|
||||
title: appName,
|
||||
width: width || 1200,
|
||||
height: height || 600,
|
||||
minHeight: 500,
|
||||
minWidth: 500,
|
||||
acceptFirstMouse: true,
|
||||
icon: path.resolve(__dirname, 'static/icon.png'),
|
||||
webPreferences: {
|
||||
zoomFactor: zoomFactor
|
||||
}
|
||||
});
|
||||
|
||||
let _resizeTimeout = null;
|
||||
mainWindow.on('resize', e => {
|
||||
saveBounds();
|
||||
|
||||
clearTimeout(_resizeTimeout);
|
||||
_resizeTimeout = setTimeout(() => {
|
||||
trackEvent('Window', 'Resize');
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
let _moveTimeout = null;
|
||||
mainWindow.on('move', e => {
|
||||
saveBounds();
|
||||
|
||||
clearTimeout(_moveTimeout);
|
||||
_moveTimeout = setTimeout(() => {
|
||||
trackEvent('Window', 'Move');
|
||||
}, 1000);
|
||||
});
|
||||
mainWindow.on('unresponsive', e => {
|
||||
showUnresponsiveModal();
|
||||
trackEvent('Window', 'Unresponsive');
|
||||
});
|
||||
|
||||
// and load the app.html of the app.
|
||||
// TODO: Use path.join for this
|
||||
mainWindow.loadURL(`file://${__dirname}/renderer.html`);
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', () => {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null;
|
||||
trackEvent('Window', 'Close');
|
||||
});
|
||||
|
||||
require('electron-context-menu')({});
|
||||
|
||||
let template = [
|
||||
{
|
||||
label: 'Application',
|
||||
submenu: [
|
||||
{
|
||||
label: `About ${appName}`,
|
||||
role: 'about',
|
||||
visible: IS_MAC
|
||||
},
|
||||
{
|
||||
type: 'separator',
|
||||
visible: IS_MAC
|
||||
},
|
||||
{
|
||||
label: 'Preferences',
|
||||
accelerator: 'CmdOrCtrl+,',
|
||||
click: function (menuItem, window, e) {
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.send('toggle-preferences');
|
||||
trackEvent('App Menu', 'Preferences');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Changelog',
|
||||
click: function (menuItem, window, e) {
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.send('toggle-changelog');
|
||||
trackEvent('App Menu', 'Changelog');
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator',
|
||||
visible: IS_MAC
|
||||
},
|
||||
{
|
||||
role: 'hide',
|
||||
visible: IS_MAC
|
||||
},
|
||||
{
|
||||
role: 'hideothers',
|
||||
visible: IS_MAC
|
||||
},
|
||||
{type: 'separator'},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function () {
|
||||
app.quit();
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [{
|
||||
label: 'Undo',
|
||||
accelerator: 'CmdOrCtrl+Z',
|
||||
selector: 'undo:'
|
||||
}, {
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+CmdOrCtrl+Z',
|
||||
selector: 'redo:'
|
||||
}, {
|
||||
type: 'separator'
|
||||
}, {
|
||||
label: 'Cut',
|
||||
accelerator: 'CmdOrCtrl+X',
|
||||
selector: 'cut:'
|
||||
}, {
|
||||
label: 'Copy',
|
||||
accelerator: 'CmdOrCtrl+C',
|
||||
selector: 'copy:'
|
||||
}, {
|
||||
label: 'Paste',
|
||||
accelerator: 'CmdOrCtrl+V',
|
||||
selector: 'paste:'
|
||||
}, {
|
||||
label: 'Select All',
|
||||
accelerator: 'CmdOrCtrl+A',
|
||||
selector: 'selectAll:'
|
||||
}]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
role: 'togglefullscreen'
|
||||
},
|
||||
{
|
||||
label: 'Actual Size',
|
||||
accelerator: 'CmdOrCtrl+0',
|
||||
click: () => {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const zoomFactor = 1;
|
||||
window.webContents.setZoomFactor(zoomFactor);
|
||||
saveZoomFactor(zoomFactor);
|
||||
trackEvent('App Menu', 'Zoom Reset');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Zoom In',
|
||||
accelerator: IS_MAC ? 'CmdOrCtrl+Plus' : 'CmdOrCtrl+=',
|
||||
click: () => {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const zoomFactor = Math.min(1.8, getZoomFactor() + 0.05);
|
||||
window.webContents.setZoomFactor(zoomFactor);
|
||||
|
||||
saveZoomFactor(zoomFactor);
|
||||
trackEvent('App Menu', 'Zoom In');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Zoom Out',
|
||||
accelerator: 'CmdOrCtrl+-',
|
||||
click: () => {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const zoomFactor = Math.max(0.5, getZoomFactor() - 0.05);
|
||||
window.webContents.setZoomFactor(zoomFactor);
|
||||
saveZoomFactor(zoomFactor);
|
||||
trackEvent('App Menu', 'Zoom Out');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Sidebar',
|
||||
accelerator: 'CmdOrCtrl+\\',
|
||||
click: () => {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.send('toggle-sidebar');
|
||||
trackEvent('App Menu', 'Toggle Sidebar');
|
||||
}
|
||||
}
|
||||
]
|
||||
}, {
|
||||
label: 'Window',
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{role: 'minimize'},
|
||||
...(IS_MAC ? [{role: 'close'}] : [])
|
||||
]
|
||||
}, {
|
||||
label: 'Help',
|
||||
role: 'help',
|
||||
id: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Contact Support',
|
||||
click: () => {
|
||||
trackEvent('App Menu', 'Contact');
|
||||
shell.openExternal('https://insomnia.rest/documentation/support-and-feedback/');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Insomnia Help',
|
||||
accelerator: 'CmdOrCtrl+?',
|
||||
click: () => {
|
||||
trackEvent('App Menu', 'Help');
|
||||
shell.openExternal('https://insomnia.rest/documentation/');
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
if (IS_DEV || process.env.INSOMNIA_FORCE_DEBUG) {
|
||||
template.push({
|
||||
label: 'Developer',
|
||||
position: 'before=help',
|
||||
submenu: [{
|
||||
label: 'Reload',
|
||||
accelerator: 'CmdOrCtrl+R',
|
||||
click: function () {
|
||||
mainWindow.reload();
|
||||
}
|
||||
}, {
|
||||
label: 'Toggle DevTools',
|
||||
accelerator: 'Alt+CmdOrCtrl+I',
|
||||
click: function () {
|
||||
mainWindow.toggleDevTools();
|
||||
}
|
||||
}, {
|
||||
label: 'Resize to Default',
|
||||
click: function () {
|
||||
mainWindow.setBounds({x: 100, y: 100, width: 1000, height: 480});
|
||||
}
|
||||
}, {
|
||||
label: 'Take Screenshot',
|
||||
click: function () {
|
||||
mainWindow.capturePage(image => {
|
||||
const buffer = image.toPNG();
|
||||
const dir = app.getPath('desktop');
|
||||
fs.writeFileSync(path.join(dir, `Screenshot-${new Date()}.png`), buffer);
|
||||
});
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
|
||||
}
|
||||
|
28
app/main/error-handling.js
Normal file
28
app/main/error-handling.js
Normal file
@ -0,0 +1,28 @@
|
||||
import Raven from 'raven';
|
||||
import {getAppVersion, isDevelopment} from '../common/constants';
|
||||
|
||||
export function init () {
|
||||
_initSentry();
|
||||
}
|
||||
|
||||
function _initSentry () {
|
||||
let ravenClient = null;
|
||||
|
||||
if (!isDevelopment()) {
|
||||
ravenClient = Raven.config('https://786e43ae199c4757a9ea4a48a9abd17d@sentry.io/109702', {
|
||||
environment: isDevelopment() ? 'development' : 'production',
|
||||
release: getAppVersion(),
|
||||
logger: 'electron.main'
|
||||
});
|
||||
|
||||
ravenClient.install();
|
||||
}
|
||||
|
||||
process.on('uncaughtException', e => {
|
||||
if (ravenClient) {
|
||||
ravenClient.captureException(e, {});
|
||||
} else {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
77
app/main/updates.js
Normal file
77
app/main/updates.js
Normal file
@ -0,0 +1,77 @@
|
||||
import electron from 'electron';
|
||||
import {CHECK_FOR_UPDATES_INTERVAL, getAppVersion, isDevelopment, isLinux} from '../common/constants';
|
||||
|
||||
const {autoUpdater, BrowserWindow} = electron;
|
||||
|
||||
const UPDATE_URLS = {
|
||||
darwin: `https://updates.insomnia.rest/builds/check/mac?v=${getAppVersion()}`,
|
||||
linux: `https://updates.insomnia.rest/builds/check/linux?v=${getAppVersion()}`,
|
||||
win32: `https://downloads.insomnia.rest/win`
|
||||
};
|
||||
|
||||
let hasPromptedForUpdates = false;
|
||||
|
||||
export function init () {
|
||||
// Check for updates immediately
|
||||
_checkForUpdates();
|
||||
|
||||
// Check for updates on an interval
|
||||
setInterval(_checkForUpdates, CHECK_FOR_UPDATES_INTERVAL);
|
||||
|
||||
autoUpdater.on('error', e => {
|
||||
// NOTE: Don't report autoUpdater errors to Sentry. They are way too noisy.
|
||||
if (isDevelopment()) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
autoUpdater.on('update-not-available', () => {
|
||||
console.log('-- Update Not Available --');
|
||||
});
|
||||
|
||||
autoUpdater.on('update-available', () => {
|
||||
console.log('-- Update Available --');
|
||||
});
|
||||
|
||||
autoUpdater.on('update-downloaded', (e, releaseNotes, releaseName, releaseDate, updateUrl) => {
|
||||
console.log(`-- Update Downloaded ${releaseName} --`);
|
||||
_showUpdateNotification();
|
||||
});
|
||||
}
|
||||
|
||||
function _showUpdateNotification () {
|
||||
if (hasPromptedForUpdates) {
|
||||
return;
|
||||
}
|
||||
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.send('update-available');
|
||||
hasPromptedForUpdates = true;
|
||||
}
|
||||
|
||||
function _checkForUpdates () {
|
||||
if (hasPromptedForUpdates) {
|
||||
// We've already prompted for updates. Don't bug the user anymore
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDevelopment()) {
|
||||
console.log('-- Skipping update check in Development --');
|
||||
return;
|
||||
} else {
|
||||
console.log('-- Checking for Updates --');
|
||||
}
|
||||
|
||||
if (!isLinux()) {
|
||||
try {
|
||||
autoUpdater.setFeedURL(UPDATE_URLS[process.platform]);
|
||||
autoUpdater.checkForUpdates();
|
||||
} catch (e) {
|
||||
// This will fail in development
|
||||
}
|
||||
}
|
||||
}
|
354
app/main/window-utils.js
Normal file
354
app/main/window-utils.js
Normal file
@ -0,0 +1,354 @@
|
||||
import electron from 'electron';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import LocalStorage from '../common/local-storage';
|
||||
import {getAppName, isDevelopment, isMac} from '../common/constants';
|
||||
|
||||
const {app, Menu, BrowserWindow, shell, dialog} = electron;
|
||||
|
||||
let mainWindow = null;
|
||||
let localStorage = null;
|
||||
|
||||
export function createWindow () {
|
||||
const zoomFactor = getZoomFactor();
|
||||
const {bounds, fullscreen} = getBounds();
|
||||
const {x, y, width, height} = bounds;
|
||||
|
||||
// Make sure we don't place the window outside of the visible space
|
||||
let maxX = 0;
|
||||
let maxY = 0;
|
||||
for (const d of electron.screen.getAllDisplays()) {
|
||||
// Set the maximum placement location to 50 pixels short of the end
|
||||
maxX = Math.max(maxX, d.bounds.x + d.bounds.width - 50);
|
||||
maxY = Math.max(maxY, d.bounds.y + d.bounds.height - 50);
|
||||
}
|
||||
const finalX = Math.min(maxX, x);
|
||||
const finalY = Math.min(maxX, y);
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
// Make sure we don't initialize the window outside the bounds
|
||||
x: finalX,
|
||||
y: finalY,
|
||||
fullscreen: fullscreen,
|
||||
fullscreenable: true,
|
||||
title: getAppName(),
|
||||
width: width || 1200,
|
||||
height: height || 600,
|
||||
minHeight: 500,
|
||||
minWidth: 500,
|
||||
acceptFirstMouse: true,
|
||||
icon: path.resolve(__dirname, 'static/icon.png'),
|
||||
webPreferences: {
|
||||
zoomFactor: zoomFactor
|
||||
}
|
||||
});
|
||||
|
||||
let _resizeTimeout = null;
|
||||
mainWindow.on('resize', e => {
|
||||
saveBounds();
|
||||
|
||||
clearTimeout(_resizeTimeout);
|
||||
_resizeTimeout = setTimeout(() => {
|
||||
trackEvent('Window', 'Resize');
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
let _moveTimeout = null;
|
||||
mainWindow.on('move', e => {
|
||||
saveBounds();
|
||||
|
||||
clearTimeout(_moveTimeout);
|
||||
_moveTimeout = setTimeout(() => {
|
||||
trackEvent('Window', 'Move');
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
mainWindow.on('unresponsive', e => {
|
||||
showUnresponsiveModal();
|
||||
trackEvent('Window', 'Unresponsive');
|
||||
});
|
||||
|
||||
// and load the app.html of the app.
|
||||
// TODO: Use path.join for this
|
||||
mainWindow.loadURL(`file://${__dirname}/renderer.html`);
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', () => {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null;
|
||||
trackEvent('Window', 'Close');
|
||||
});
|
||||
|
||||
const applicationMenu = {
|
||||
label: 'Application',
|
||||
submenu: [
|
||||
...(isMac() ? [
|
||||
{label: `About ${getAppName()}`, role: 'about'},
|
||||
{type: 'separator'}
|
||||
] : []),
|
||||
{
|
||||
label: 'Preferences',
|
||||
accelerator: 'CmdOrCtrl+,',
|
||||
click: function (menuItem, window, e) {
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
window.webContents.send('toggle-preferences');
|
||||
trackEvent('App Menu', 'Preferences');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Changelog',
|
||||
click: function (menuItem, window, e) {
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
window.webContents.send('toggle-changelog');
|
||||
trackEvent('App Menu', 'Changelog');
|
||||
}
|
||||
},
|
||||
...(isMac() ? [
|
||||
{type: 'separator'},
|
||||
{role: 'hide'},
|
||||
{role: 'hideothers'}
|
||||
] : []),
|
||||
{type: 'separator'},
|
||||
{label: 'Quit', accelerator: 'Command+Q', click: () => app.quit()}
|
||||
]
|
||||
};
|
||||
|
||||
const editMenu = {
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:'},
|
||||
{label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:'},
|
||||
{type: 'separator'},
|
||||
{label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:'},
|
||||
{label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:'},
|
||||
{label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:'},
|
||||
{label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:'}
|
||||
]
|
||||
};
|
||||
|
||||
const viewMenu = {
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{role: 'togglefullscreen'},
|
||||
{
|
||||
label: 'Actual Size',
|
||||
accelerator: 'CmdOrCtrl+0',
|
||||
click: () => {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const zoomFactor = 1;
|
||||
window.webContents.setZoomFactor(zoomFactor);
|
||||
saveZoomFactor(zoomFactor);
|
||||
trackEvent('App Menu', 'Zoom Reset');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Zoom In',
|
||||
accelerator: isMac() ? 'CmdOrCtrl+Plus' : 'CmdOrCtrl+=',
|
||||
click: () => {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const zoomFactor = Math.min(1.8, getZoomFactor() + 0.05);
|
||||
window.webContents.setZoomFactor(zoomFactor);
|
||||
|
||||
saveZoomFactor(zoomFactor);
|
||||
trackEvent('App Menu', 'Zoom In');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Zoom Out',
|
||||
accelerator: 'CmdOrCtrl+-',
|
||||
click: () => {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const zoomFactor = Math.max(0.5, getZoomFactor() - 0.05);
|
||||
window.webContents.setZoomFactor(zoomFactor);
|
||||
saveZoomFactor(zoomFactor);
|
||||
trackEvent('App Menu', 'Zoom Out');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Sidebar',
|
||||
accelerator: 'CmdOrCtrl+\\',
|
||||
click: () => {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.send('toggle-sidebar');
|
||||
trackEvent('App Menu', 'Toggle Sidebar');
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const windowMenu = {
|
||||
label: 'Window',
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{role: 'minimize'},
|
||||
...(isMac() ? [{role: 'close'}] : [])
|
||||
]
|
||||
};
|
||||
|
||||
const helpMenu = {
|
||||
label: 'Help',
|
||||
role: 'help',
|
||||
id: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Contact Support',
|
||||
click: () => {
|
||||
trackEvent('App Menu', 'Contact');
|
||||
shell.openExternal('https://insomnia.rest/documentation/support-and-feedback/');
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Insomnia Help',
|
||||
accelerator: 'CmdOrCtrl+?',
|
||||
click: () => {
|
||||
trackEvent('App Menu', 'Help');
|
||||
shell.openExternal('https://insomnia.rest/documentation/');
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const developerMenu = {
|
||||
label: 'Developer',
|
||||
position: 'before=help',
|
||||
submenu: [{
|
||||
label: 'Reload',
|
||||
accelerator: 'CmdOrCtrl+R',
|
||||
click: () => mainWindow.reload()
|
||||
}, {
|
||||
label: 'Toggle DevTools',
|
||||
accelerator: 'Alt+CmdOrCtrl+I',
|
||||
click: () => mainWindow.toggleDevTools()
|
||||
}, {
|
||||
label: 'Resize to Default',
|
||||
click: () => mainWindow.setBounds({x: 100, y: 100, width: 1000, height: 480})
|
||||
}, {
|
||||
label: 'Take Screenshot',
|
||||
click: function () {
|
||||
mainWindow.capturePage(image => {
|
||||
const buffer = image.toPNG();
|
||||
const dir = app.getPath('desktop');
|
||||
fs.writeFileSync(path.join(dir, `Screenshot-${new Date()}.png`), buffer);
|
||||
});
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
let template = [];
|
||||
|
||||
template.push(applicationMenu);
|
||||
template.push(editMenu);
|
||||
template.push(viewMenu);
|
||||
template.push(windowMenu);
|
||||
template.push(helpMenu);
|
||||
|
||||
if (isDevelopment() || process.env.INSOMNIA_FORCE_DEBUG) {
|
||||
template.push(developerMenu);
|
||||
}
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
|
||||
|
||||
require('electron-context-menu')({});
|
||||
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
function showUnresponsiveModal () {
|
||||
dialog.showMessageBox({
|
||||
type: 'info',
|
||||
buttons: ['Cancel', 'Reload'],
|
||||
defaultId: 1,
|
||||
cancelId: 0,
|
||||
title: 'Unresponsive',
|
||||
message: 'Insomnia has become unresponsive. Do you want to reload?'
|
||||
}, id => {
|
||||
if (id === 1) {
|
||||
mainWindow.destroy();
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function trackEvent (...args) {
|
||||
const window = BrowserWindow.getFocusedWindow();
|
||||
if (!window || !window.webContents) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.webContents.send('analytics-track-event', args);
|
||||
}
|
||||
|
||||
function saveBounds () {
|
||||
if (!mainWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fullscreen = mainWindow.isFullScreen();
|
||||
|
||||
// Only save the size if we're not in fullscreen
|
||||
if (!fullscreen) {
|
||||
localStorage.setItem('bounds', mainWindow.getBounds());
|
||||
localStorage.setItem('fullscreen', false);
|
||||
} else {
|
||||
localStorage.setItem('fullscreen', true);
|
||||
}
|
||||
}
|
||||
|
||||
function getBounds () {
|
||||
let bounds = {};
|
||||
let fullscreen = false;
|
||||
try {
|
||||
bounds = localStorage.getItem('bounds', {});
|
||||
fullscreen = localStorage.getItem('fullscreen', false);
|
||||
} catch (e) {
|
||||
// This should never happen, but if it does...!
|
||||
console.error('Failed to parse window bounds', e);
|
||||
}
|
||||
|
||||
return {bounds, fullscreen};
|
||||
}
|
||||
|
||||
function saveZoomFactor (zoomFactor) {
|
||||
localStorage.setItem('zoomFactor', zoomFactor);
|
||||
}
|
||||
|
||||
function getZoomFactor () {
|
||||
let zoomFactor = 1;
|
||||
try {
|
||||
zoomFactor = localStorage.getItem('zoomFactor', 1);
|
||||
} catch (e) {
|
||||
// This should never happen, but if it does...!
|
||||
console.error('Failed to parse zoomFactor', e);
|
||||
}
|
||||
|
||||
return zoomFactor;
|
||||
}
|
||||
|
||||
function initLocalStorage () {
|
||||
const localStoragePath = path.join(app.getPath('userData'), 'localStorage');
|
||||
localStorage = new LocalStorage(localStoragePath);
|
||||
}
|
||||
|
||||
initLocalStorage();
|
@ -1,28 +1,27 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "insomnia",
|
||||
"version": "5.0.10",
|
||||
"version": "5.0.12",
|
||||
"productName": "Insomnia",
|
||||
"longName": "Insomnia REST Client",
|
||||
"description": "Debug APIs like a human, not a robot",
|
||||
"homepage": "https://insomnia.rest",
|
||||
"author": "Insomnia <support@insomnia.rest>",
|
||||
"main": "main.js",
|
||||
"main": "main.min.js",
|
||||
"dependencies": {
|
||||
"electron-context-menu": "~0.8.0",
|
||||
"electron-squirrel-startup": "~1.0.0",
|
||||
"electron-context-menu": "0.9.0",
|
||||
"electron-squirrel-startup": "1.0.0",
|
||||
"hkdf": "0.0.2",
|
||||
"httpsnippet": "1.16.5",
|
||||
"insomnia-importers": "~1.3.1",
|
||||
"jsonpath": "~0.2.9",
|
||||
"mkdirp": "~0.5.1",
|
||||
"nedb": "~1.8.0",
|
||||
"node-forge": "~0.7.0",
|
||||
"insomnia-importers": "1.3.3",
|
||||
"jsonpath": "0.2.11",
|
||||
"mkdirp": "0.5.1",
|
||||
"nedb": "1.8.0",
|
||||
"node-forge": "0.7.0",
|
||||
"node-libcurl": "git://github.com/getinsomnia/node-libcurl.git#3fc2afea435f3548eedbef9c68d3fee642dfcddb",
|
||||
"raven": "~1.1.2",
|
||||
"request": "~2.71.0",
|
||||
"raven": "1.1.2",
|
||||
"srp-js": "0.2.0",
|
||||
"tough-cookie": "~2.3.1",
|
||||
"vkbeautify": "~0.99.1"
|
||||
"tough-cookie": "2.3.1",
|
||||
"vkbeautify": "0.99.1"
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,6 @@
|
||||
<script>
|
||||
// UPDATE HANDLERS
|
||||
(function () {
|
||||
const CHECK_FOR_UPDATES_INTERVAL = 1000 * 60 * 60 * 3; // 3 hours
|
||||
|
||||
function showUpdateNotification () {
|
||||
console.log('-- Update Available --');
|
||||
|
||||
@ -37,12 +35,6 @@
|
||||
// you relaunch too soon it doesn't work the first time.
|
||||
setTimeout(showUpdateNotification, 1000 * 10);
|
||||
});
|
||||
|
||||
function checkForUpdates () {
|
||||
ipcRenderer.send('check-for-updates');
|
||||
}
|
||||
|
||||
setInterval(checkForUpdates, CHECK_FOR_UPDATES_INTERVAL);
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
|
@ -450,8 +450,8 @@ export async function createOrUpdateConfig (resourceGroupId, syncMode) {
|
||||
}
|
||||
|
||||
export async function logout () {
|
||||
await resetLocalData();
|
||||
await session.logout();
|
||||
await resetLocalData();
|
||||
}
|
||||
|
||||
export async function cancelTrial () {
|
||||
|
@ -360,12 +360,17 @@ class CodeEditor extends PureComponent {
|
||||
lineNumbers: !hideGutters && !hideLineNumbers,
|
||||
foldGutter: !hideGutters && !hideLineNumbers,
|
||||
lineWrapping: lineWrapping,
|
||||
keyMap: keyMap || 'default',
|
||||
matchBrackets: !noMatchBrackets,
|
||||
lint: !noLint && !readOnly,
|
||||
gutters: []
|
||||
};
|
||||
|
||||
// Only set keyMap if we're not read-only. This is so things like
|
||||
// ctrl-a work on read-only mode.
|
||||
if (!readOnly && keyMap) {
|
||||
options.keyMap = keyMap;
|
||||
}
|
||||
|
||||
if (indentSize) {
|
||||
options.tabSize = indentSize;
|
||||
options.indentUnit = indentSize;
|
||||
|
@ -53,11 +53,16 @@ class SettingsModal extends PureComponent {
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
_handleImport () {
|
||||
_handleImportFile () {
|
||||
this.props.handleImportFile();
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
_handleImportUri (uri) {
|
||||
this.props.handleImportUri(uri);
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
_handleChangeTheme (theme, persist = true) {
|
||||
document.body.setAttribute('theme', theme);
|
||||
|
||||
@ -148,7 +153,8 @@ class SettingsModal extends PureComponent {
|
||||
<ImportExport
|
||||
handleExportAll={this._handleExportAllToFile}
|
||||
handleExportWorkspace={this._handleExportWorkspace}
|
||||
handleImport={this._handleImport}
|
||||
handleImportFile={this._handleImportFile}
|
||||
handleImportUri={this._handleImportUri}
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel className="scrollable">
|
||||
@ -178,6 +184,7 @@ SettingsModal.propTypes = {
|
||||
handleExportWorkspaceToFile: PropTypes.func.isRequired,
|
||||
handleExportAllToFile: PropTypes.func.isRequired,
|
||||
handleImportFile: PropTypes.func.isRequired,
|
||||
handleImportUri: PropTypes.func.isRequired,
|
||||
|
||||
// Properties
|
||||
settings: PropTypes.object.isRequired
|
||||
|
@ -1,13 +1,25 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import {Dropdown, DropdownButton, DropdownItem, DropdownDivider} from '../base/dropdown';
|
||||
import PromptModal from '../modals/prompt-modal';
|
||||
import Link from '../base/link';
|
||||
import {showModal} from '../modals/index';
|
||||
|
||||
@autobind
|
||||
class ImportExport extends PureComponent {
|
||||
async _handleImportUri () {
|
||||
const uri = await showModal(PromptModal, {
|
||||
headerName: 'Import Data from URL',
|
||||
submitName: 'Fetch and Import',
|
||||
label: 'URL',
|
||||
placeholder: 'https://website.com/insomnia-import.json'
|
||||
});
|
||||
this.props.handleImportUri(uri);
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
handleImport,
|
||||
handleImportFile,
|
||||
handleExportAll,
|
||||
handleExportWorkspace
|
||||
} = this.props;
|
||||
@ -15,7 +27,8 @@ class ImportExport extends PureComponent {
|
||||
return (
|
||||
<div>
|
||||
<p className="no-margin-top">
|
||||
Import format will be automatically detected (<strong>Insomnia, Postman v2, HAR, Curl</strong>)
|
||||
Import format will be automatically detected (<strong>Insomnia, Postman v2, HAR,
|
||||
Curl</strong>)
|
||||
</p>
|
||||
<p>
|
||||
Don't see your format here?
|
||||
@ -29,18 +42,29 @@ class ImportExport extends PureComponent {
|
||||
</DropdownButton>
|
||||
<DropdownDivider>Choose Export Type</DropdownDivider>
|
||||
<DropdownItem onClick={handleExportWorkspace}>
|
||||
<i className="fa fa-home"></i>
|
||||
<i className="fa fa-home"/>
|
||||
Current Workspace
|
||||
</DropdownItem>
|
||||
<DropdownItem onClick={handleExportAll}>
|
||||
<i className="fa fa-empty"></i>
|
||||
<i className="fa fa-empty"/>
|
||||
All Workspaces
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
|
||||
<button className="btn btn--clicky" onClick={handleImport}>
|
||||
Import Data
|
||||
</button>
|
||||
<Dropdown outline>
|
||||
<DropdownButton className="btn btn--clicky">
|
||||
Import Data <i className="fa fa-caret-down"></i>
|
||||
</DropdownButton>
|
||||
<DropdownDivider>Choose Import Type</DropdownDivider>
|
||||
<DropdownItem onClick={handleImportFile}>
|
||||
<i className="fa fa-file-o"/>
|
||||
From File
|
||||
</DropdownItem>
|
||||
<DropdownItem onClick={this._handleImportUri}>
|
||||
<i className="fa fa-link"/>
|
||||
From URL
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
</div>
|
||||
<p className="italic faint">
|
||||
* Tip: You can also paste Curl commands into the URL bar
|
||||
@ -51,7 +75,8 @@ class ImportExport extends PureComponent {
|
||||
}
|
||||
|
||||
ImportExport.propTypes = {
|
||||
handleImport: PropTypes.func.isRequired,
|
||||
handleImportFile: PropTypes.func.isRequired,
|
||||
handleImportUri: PropTypes.func.isRequired,
|
||||
handleExportAll: PropTypes.func.isRequired,
|
||||
handleExportWorkspace: PropTypes.func.isRequired
|
||||
};
|
||||
|
@ -132,6 +132,10 @@ class Wrapper extends PureComponent {
|
||||
this.props.handleImportFileToWorkspace(this.props.activeWorkspace._id);
|
||||
}
|
||||
|
||||
_handleImportUri (uri) {
|
||||
this.props.handleImportUriToWorkspace(this.props.activeWorkspace._id, uri);
|
||||
}
|
||||
|
||||
_handleExportWorkspaceToFile () {
|
||||
this.props.handleExportFile(this.props.activeWorkspace._id);
|
||||
}
|
||||
@ -401,6 +405,7 @@ class Wrapper extends PureComponent {
|
||||
handleExportWorkspaceToFile={this._handleExportWorkspaceToFile}
|
||||
handleExportAllToFile={handleExportFile}
|
||||
handleImportFile={this._handleImportFile}
|
||||
handleImportUri={this._handleImportUri}
|
||||
settings={settings}
|
||||
/>
|
||||
<RequestSwitcherModal
|
||||
@ -447,6 +452,7 @@ Wrapper.propTypes = {
|
||||
handleActivateRequest: PropTypes.func.isRequired,
|
||||
handleSetSidebarFilter: PropTypes.func.isRequired,
|
||||
handleImportFileToWorkspace: PropTypes.func.isRequired,
|
||||
handleImportUriToWorkspace: PropTypes.func.isRequired,
|
||||
handleExportFile: PropTypes.func.isRequired,
|
||||
handleSetActiveWorkspace: PropTypes.func.isRequired,
|
||||
handleSetActiveEnvironment: PropTypes.func.isRequired,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import fs from 'fs';
|
||||
import {parse as urlParse} from 'url';
|
||||
import {ipcRenderer} from 'electron';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {connect} from 'react-redux';
|
||||
@ -662,11 +663,23 @@ class App extends PureComponent {
|
||||
showModal(SettingsModal);
|
||||
});
|
||||
|
||||
ipcRenderer.on('run-command', (e, commandUri) => {
|
||||
const parsed = urlParse(commandUri, true);
|
||||
|
||||
const command = `${parsed.hostname}${parsed.pathname}`;
|
||||
const args = JSON.parse(JSON.stringify(parsed.query));
|
||||
args.workspaceId = args.workspaceId || this.props.activeWorkspace._id;
|
||||
|
||||
this.props.handleCommand(command, args);
|
||||
});
|
||||
|
||||
ipcRenderer.on('toggle-changelog', () => {
|
||||
showModal(ChangelogModal);
|
||||
});
|
||||
|
||||
ipcRenderer.on('toggle-sidebar', this._handleToggleSidebar);
|
||||
|
||||
process.nextTick(() => ipcRenderer.send('app-ready'));
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
@ -728,6 +741,7 @@ App.propTypes = {
|
||||
sidebarWidth: PropTypes.number.isRequired,
|
||||
paneWidth: PropTypes.number.isRequired,
|
||||
paneHeight: PropTypes.number.isRequired,
|
||||
handleCommand: PropTypes.func.isRequired,
|
||||
activeWorkspace: PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
@ -823,6 +837,8 @@ function mapDispatchToProps (dispatch) {
|
||||
|
||||
handleSetActiveWorkspace: global.setActiveWorkspace,
|
||||
handleImportFileToWorkspace: global.importFile,
|
||||
handleImportUriToWorkspace: global.importUri,
|
||||
handleCommand: global.newCommand,
|
||||
handleExportFile: global.exportFile,
|
||||
handleMoveRequest: _moveRequest,
|
||||
handleMoveRequestGroup: _moveRequestGroup
|
||||
|
@ -118,6 +118,7 @@
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.modal__footer > *:last-child {
|
||||
|
@ -169,7 +169,7 @@
|
||||
.sidebar__list-root {
|
||||
// Add some space above so it's not so squished
|
||||
border-top: 1px solid @hl-sm;
|
||||
padding-top: @padding-xs;
|
||||
padding-top: @padding-xxs;
|
||||
padding-bottom: @padding-md;
|
||||
box-shadow: inset 0 2rem 2rem -2rem rgba(0, 0, 0, 0.03);
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import electron from 'electron';
|
||||
import React from 'react';
|
||||
import {combineReducers} from 'redux';
|
||||
import fs from 'fs';
|
||||
|
||||
import {importRaw, exportJSON} from '../../../common/import';
|
||||
import * as importUtils from '../../../common/import';
|
||||
import {trackEvent} from '../../../analytics';
|
||||
import AlertModal from '../../components/modals/alert-modal';
|
||||
import {showModal} from '../../components/modals';
|
||||
@ -21,6 +22,7 @@ const SET_ACTIVE_WORKSPACE = 'global/activate-workspace';
|
||||
const COMMAND_ALERT = 'app/alert';
|
||||
const COMMAND_LOGIN = 'app/auth/login';
|
||||
const COMMAND_TRIAL_END = 'app/billing/trial-end';
|
||||
const COMMAND_IMPORT_URI = 'app/import';
|
||||
|
||||
// ~~~~~~~~ //
|
||||
// REDUCERS //
|
||||
@ -68,18 +70,25 @@ export const reducer = combineReducers({
|
||||
// ~~~~~~~ //
|
||||
|
||||
export function newCommand (command, args) {
|
||||
// TODO: Make this use reducer when Modals ported to Redux
|
||||
if (command === COMMAND_ALERT) {
|
||||
const {message, title} = args;
|
||||
showModal(AlertModal, {title, message});
|
||||
} else if (command === COMMAND_LOGIN) {
|
||||
const {title, message} = args;
|
||||
showModal(LoginModal, {title, message});
|
||||
} else if (command === COMMAND_TRIAL_END) {
|
||||
showModal(PaymentNotificationModal);
|
||||
}
|
||||
|
||||
return {type: command, ...args};
|
||||
return async dispatch => {
|
||||
// TODO: Make this use reducer when Modals ported to Redux
|
||||
if (command === COMMAND_ALERT) {
|
||||
const {message, title} = args;
|
||||
showModal(AlertModal, {title, message});
|
||||
} else if (command === COMMAND_LOGIN) {
|
||||
const {title, message} = args;
|
||||
showModal(LoginModal, {title, message});
|
||||
} else if (command === COMMAND_TRIAL_END) {
|
||||
showModal(PaymentNotificationModal);
|
||||
} else if (command === COMMAND_IMPORT_URI) {
|
||||
await showModal(AlertModal, {
|
||||
title: 'Confirm Data Import',
|
||||
message: <span>Do you really want to import <code>{args.uri}</code>?</span>,
|
||||
addCancel: true
|
||||
});
|
||||
dispatch(importUri(args.workspaceId, args.uri));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function loadStart () {
|
||||
@ -114,7 +123,6 @@ export function importFile (workspaceId) {
|
||||
return async dispatch => {
|
||||
dispatch(loadStart());
|
||||
|
||||
const workspace = await models.workspace.getById(workspaceId);
|
||||
const options = {
|
||||
title: 'Import Insomnia Data',
|
||||
buttonLabel: 'Import',
|
||||
@ -132,53 +140,48 @@ export function importFile (workspaceId) {
|
||||
if (!paths) {
|
||||
// It was cancelled, so let's bail out
|
||||
dispatch(loadStop());
|
||||
trackEvent('Import', 'Cancel');
|
||||
trackEvent('Import File', 'Cancel');
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's import all the paths!
|
||||
for (const path of paths) {
|
||||
try {
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const uri = `file://${path}`;
|
||||
await importUtils.importUri(workspaceId, uri);
|
||||
trackEvent('Import File', 'Success');
|
||||
} catch (err) {
|
||||
showModal(AlertModal, {title: 'Import Failed', message: err + ''});
|
||||
trackEvent('Import File', 'Failure');
|
||||
} finally {
|
||||
dispatch(loadStop());
|
||||
|
||||
const result = await importRaw(workspace, data);
|
||||
const {summary, source, error} = result;
|
||||
|
||||
if (error) {
|
||||
showModal(AlertModal, {title: 'Import Failed', message: error});
|
||||
return;
|
||||
}
|
||||
|
||||
let statements = Object.keys(summary).map(type => {
|
||||
const count = summary[type].length;
|
||||
const name = models.getModelName(type, count);
|
||||
return count === 0 ? null : `${count} ${name}`;
|
||||
}).filter(s => s !== null);
|
||||
|
||||
let message;
|
||||
if (statements.length === 0) {
|
||||
message = 'Nothing was found to import.';
|
||||
} else {
|
||||
message = `You imported ${statements.join(', ')}!`;
|
||||
}
|
||||
showModal(AlertModal, {title: 'Import Succeeded', message});
|
||||
trackEvent('Import', 'Success', source);
|
||||
} catch (e) {
|
||||
showModal(AlertModal, {title: 'Import Failed', message: e + ''});
|
||||
trackEvent('Import', 'Failure');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function importUri (workspaceId, uri) {
|
||||
return async dispatch => {
|
||||
dispatch(loadStart());
|
||||
try {
|
||||
await importUtils.importUri(workspaceId, uri);
|
||||
trackEvent('Import URI', 'Success');
|
||||
} catch (err) {
|
||||
trackEvent('Import URI', 'Failure');
|
||||
showModal(AlertModal, {title: 'Import Failed', message: err + ''});
|
||||
} finally {
|
||||
dispatch(loadStop());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function exportFile (workspaceId = null) {
|
||||
return async dispatch => {
|
||||
dispatch(loadStart());
|
||||
|
||||
const workspace = await models.workspace.getById(workspaceId);
|
||||
const json = await exportJSON(workspace);
|
||||
const json = await importUtils.exportJSON(workspace);
|
||||
const options = {
|
||||
title: 'Export Insomnia Data',
|
||||
buttonLabel: 'Export',
|
||||
|
@ -50,6 +50,5 @@ test_script:
|
||||
# global handlers #
|
||||
#---------------------------------#
|
||||
|
||||
#deploy_script:
|
||||
# - npm run build-n-package:win
|
||||
# - ps: ls .\dist\win\* | % { Push-AppveyorArtifact $_.FullName }
|
||||
deploy_script:
|
||||
- ps: If ($env:APPVEYOR_REPO_TAG -Match "true") {npm run build-n-package:win ; ls .\dist\win\* | % { Push-AppveyorArtifact $_.FullName }}
|
||||
|
163
package.json
163
package.json
@ -16,10 +16,10 @@
|
||||
"test:coverage": "cross-env NODE_ENV=test jest --coverage --silent && open ./coverage/lcov-report/index.html",
|
||||
"test:watch": "cross-env NODE_ENV=test jest --silent --watch",
|
||||
"test": "npm run test:lint && cross-env NODE_ENV=test jest --silent",
|
||||
"start-hot": "npm run build-main && cross-env HOT=1 INSOMNIA_ENV=development electron -r babel-register ./app/main.min.js",
|
||||
"start-hot": "npm run build-main && cross-env HOT=1 INSOMNIA_ENV=development electron app",
|
||||
"build-main": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.config.electron.babel.js",
|
||||
"hot-server": "webpack-dev-server --config ./webpack/webpack.config.development.babel.js",
|
||||
"dev": "concurrently --kill-others \"npm run hot-server\" \"npm run start-hot\"",
|
||||
"dev": "concurrently --kill-others 'npm run hot-server' 'npm run start-hot'",
|
||||
"build:clean": "rm -rf ./build/* && rm -rf ./dist/* && mkdirp ./build",
|
||||
"build:renderer": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.production.babel.js",
|
||||
"build:main": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.electron.babel.js",
|
||||
@ -67,6 +67,14 @@
|
||||
"build": {
|
||||
"appId": "com.insomnia.app",
|
||||
"category": "public.app-category.developer-tools",
|
||||
"protocols": [
|
||||
{
|
||||
"name": "Insomnia",
|
||||
"role": "Viewer",
|
||||
"schemes": ["insomnia"]
|
||||
}
|
||||
],
|
||||
"fileAssociations": [],
|
||||
"directories": {
|
||||
"app": "build",
|
||||
"output": "dist"
|
||||
@ -99,88 +107,87 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"autobind-decorator": "^1.3.4",
|
||||
"classnames": "~2.2.5",
|
||||
"clone": "~2.1.0",
|
||||
"codemirror": "~5.24.2",
|
||||
"electron-context-menu": "~0.8.0",
|
||||
"electron-squirrel-startup": "~1.0.0",
|
||||
"autobind-decorator": "1.3.4",
|
||||
"classnames": "2.2.5",
|
||||
"clone": "2.1.0",
|
||||
"codemirror": "5.24.2",
|
||||
"electron-context-menu": "0.9.0",
|
||||
"electron-squirrel-startup": "1.0.0",
|
||||
"hkdf": "0.0.2",
|
||||
"html-entities": "^1.2.0",
|
||||
"html-entities": "1.2.0",
|
||||
"httpsnippet": "1.16.5",
|
||||
"iconv-lite": "^0.4.15",
|
||||
"insomnia-importers": "~1.3.1",
|
||||
"jsonlint": "~1.6.2",
|
||||
"jsonpath": "~0.2.11",
|
||||
"mime-types": "~2.1.14",
|
||||
"mkdirp": "~0.5.1",
|
||||
"moment": "^2.18.1",
|
||||
"nedb": "~1.8.0",
|
||||
"node-forge": "~0.7.0",
|
||||
"iconv-lite": "0.4.15",
|
||||
"insomnia-importers": "1.3.3",
|
||||
"jsonlint": "1.6.2",
|
||||
"jsonpath": "0.2.11",
|
||||
"mime-types": "2.1.14",
|
||||
"mkdirp": "0.5.1",
|
||||
"moment": "2.18.1",
|
||||
"nedb": "1.8.0",
|
||||
"node-forge": "0.7.0",
|
||||
"node-libcurl": "git://github.com/getinsomnia/node-libcurl.git#3fc2afea435f3548eedbef9c68d3fee642dfcddb",
|
||||
"nunjucks": "~3.0.0",
|
||||
"raven": "~1.1.2",
|
||||
"react": "~15.4.2",
|
||||
"react-dnd": "~2.2.3",
|
||||
"react-dnd-html5-backend": "~2.2.3",
|
||||
"react-dom": "~15.4.2",
|
||||
"react-redux": "~5.0.3",
|
||||
"react-tabs": "~0.8.2",
|
||||
"redux": "~3.3.1",
|
||||
"redux-thunk": "~2.0.1",
|
||||
"request": "~2.74.0",
|
||||
"reselect": "~2.5.4",
|
||||
"nunjucks": "3.0.0",
|
||||
"raven": "1.1.2",
|
||||
"react": "15.4.2",
|
||||
"react-dnd": "2.2.3",
|
||||
"react-dnd-html5-backend": "2.2.3",
|
||||
"react-dom": "15.4.2",
|
||||
"react-redux": "5.0.3",
|
||||
"react-tabs": "0.8.2",
|
||||
"redux": "3.3.1",
|
||||
"redux-thunk": "2.0.1",
|
||||
"reselect": "2.5.4",
|
||||
"srp-js": "0.2.0",
|
||||
"tough-cookie": "~2.3.1",
|
||||
"uuid": "~3.0.0",
|
||||
"vkbeautify": "~0.99.1",
|
||||
"whatwg-fetch": "~2.0.1",
|
||||
"xmldom": "~0.1.22",
|
||||
"xpath": "~0.0.23"
|
||||
"tough-cookie": "2.3.1",
|
||||
"uuid": "3.0.0",
|
||||
"vkbeautify": "0.99.1",
|
||||
"whatwg-fetch": "2.0.1",
|
||||
"xmldom": "0.1.22",
|
||||
"xpath": "0.0.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.23.0",
|
||||
"babel-core": "~6.23.1",
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-jest": "~19.0.0",
|
||||
"babel-loader": "~6.3.2",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-plugin-transform-object-rest-spread": "~6.23.0",
|
||||
"babel-plugin-transform-regenerator": "~6.22.0",
|
||||
"babel-plugin-transform-runtime": "~6.15.0",
|
||||
"babel-polyfill": "~6.23.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"babel-preset-react": "~6.23.0",
|
||||
"babel-preset-react-hmre": "~1.1.1",
|
||||
"concurrently": "~2.0.0",
|
||||
"cross-env": "~2.0.0",
|
||||
"css-loader": "~0.26.2",
|
||||
"electron": "~1.6.5",
|
||||
"electron-builder": "~10.17.3",
|
||||
"electron-rebuild": "^1.5.7",
|
||||
"eslint": "^3.16.1",
|
||||
"eslint-config-semistandard": "^7.0.0",
|
||||
"eslint-config-standard": "^7.0.0",
|
||||
"eslint-plugin-filenames": "^1.1.0",
|
||||
"eslint-plugin-html": "^2.0.1",
|
||||
"eslint-plugin-jest": "^19.0.1",
|
||||
"eslint-plugin-json": "^1.2.0",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-react": "^6.10.0",
|
||||
"eslint-plugin-standard": "^2.1.1",
|
||||
"file-loader": "~0.10.1",
|
||||
"jest": "~19.0.2",
|
||||
"less": "~2.7.2",
|
||||
"less-loader": "~2.2.3",
|
||||
"react-hot-loader": "~3.0.0-beta.6",
|
||||
"redux-mock-store": "~1.0.2",
|
||||
"style-loader": "~0.13.2",
|
||||
"url-loader": "^0.5.8",
|
||||
"webpack": "~2.2.1",
|
||||
"webpack-dev-middleware": "~1.10.1",
|
||||
"webpack-dev-server": "^2.4.1",
|
||||
"webpack-hot-middleware": "~2.17.1",
|
||||
"webpack-target-electron-renderer": "~0.4.0"
|
||||
"babel-cli": "6.23.0",
|
||||
"babel-core": "6.23.1",
|
||||
"babel-eslint": "7.1.1",
|
||||
"babel-jest": "19.0.0",
|
||||
"babel-loader": "6.3.2",
|
||||
"babel-plugin-transform-decorators-legacy": "1.3.4",
|
||||
"babel-plugin-transform-object-rest-spread": "6.23.0",
|
||||
"babel-plugin-transform-regenerator": "6.22.0",
|
||||
"babel-plugin-transform-runtime": "6.15.0",
|
||||
"babel-polyfill": "6.23.0",
|
||||
"babel-preset-es2015": "6.22.0",
|
||||
"babel-preset-react": "6.23.0",
|
||||
"babel-preset-react-hmre": "1.1.1",
|
||||
"concurrently": "2.0.0",
|
||||
"cross-env": "2.0.0",
|
||||
"css-loader": "0.26.2",
|
||||
"electron": "1.6.6",
|
||||
"electron-builder": "10.17.3",
|
||||
"electron-rebuild": "1.5.7",
|
||||
"eslint": "3.16.1",
|
||||
"eslint-config-semistandard": "7.0.0",
|
||||
"eslint-config-standard": "7.0.0",
|
||||
"eslint-plugin-filenames": "1.1.0",
|
||||
"eslint-plugin-html": "2.0.1",
|
||||
"eslint-plugin-jest": "19.0.1",
|
||||
"eslint-plugin-json": "1.2.0",
|
||||
"eslint-plugin-promise": "3.5.0",
|
||||
"eslint-plugin-react": "6.10.0",
|
||||
"eslint-plugin-standard": "2.1.1",
|
||||
"file-loader": "0.10.1",
|
||||
"jest": "19.0.2",
|
||||
"less": "2.7.2",
|
||||
"less-loader": "2.2.3",
|
||||
"react-hot-loader": "3.0.0-beta.6",
|
||||
"redux-mock-store": "1.0.2",
|
||||
"style-loader": "0.13.2",
|
||||
"url-loader": "0.5.8",
|
||||
"webpack": "2.2.1",
|
||||
"webpack-dev-middleware": "1.10.1",
|
||||
"webpack-dev-server": "2.4.1",
|
||||
"webpack-hot-middleware": "2.17.1",
|
||||
"webpack-target-electron-renderer": "0.4.0"
|
||||
},
|
||||
"devEngines": {
|
||||
"node": "6.x",
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
APP_VERSION=$(node -e "console.log(require('./build/package.json').version)")
|
||||
HASH=$(md5 ./dist/insomnia-*.deb)
|
||||
|
||||
echo "$HASH for $APP_VERSION"
|
@ -1,19 +1,27 @@
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const productionConfig = require('./webpack.config.production.babel');
|
||||
|
||||
let devtool;
|
||||
let plugins;
|
||||
const output = {
|
||||
libraryTarget: 'commonjs2'
|
||||
libraryTarget: 'commonjs2',
|
||||
filename: 'main.min.js'
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
output.path = path.join(__dirname, '../app');
|
||||
output.filename = 'main.min.js';
|
||||
devtool = 'eval-source-map';
|
||||
plugins = [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('development'),
|
||||
'process.env.INSOMNIA_ENV': JSON.stringify('development')
|
||||
})
|
||||
]
|
||||
} else {
|
||||
output.path = path.join(__dirname, '../build');
|
||||
output.filename = 'main.js';
|
||||
devtool = productionConfig.devtool;
|
||||
plugins = productionConfig.plugins;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@ -27,5 +35,6 @@ module.exports = {
|
||||
__dirname: false,
|
||||
__filename: false
|
||||
},
|
||||
target: 'electron-main'
|
||||
target: 'electron-main',
|
||||
plugins: plugins
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user