Commit 3919a47e authored by Frank Bergmann's avatar Frank Bergmann

- Fixed server-side download

- Added client-side scripts
parent 84468bf2
/*
* ]project-open[ FS Sync
* Copyright (c) 2018 ]project-open[
* Authors:
* - Gonzalo Pérez de Olaguer Córdoba <gonzalo.perez@project-open.com>
* - Frank Bergmann <frank.bergmann@project-open.com>
*
* This code is licensed under the GNU GPL version 2.0 or later
*
* This is the application window script.
* It creates the application window.
*
* This script requires Sencha Ext/JS 4.2.1
*/
/* Load Electron inter process communication (IPC) */
const {ipcRenderer} = require('electron')
Ext.Loader.setPath('POSync', '.');
Ext.Loader.setConfig({disableCaching: false});
Ext.require([
'POSync.model.File',
'POSync.model.Project',
'POSync.model.LocalFile',
'POSync.model.Operation',
'POSync.store.Files',
'POSync.store.Projects',
'POSync.store.LocalFiles',
'POSync.store.Operations',
'POSync.view.LoginPanel',
'POSync.view.ProjectsPanel',
'POSync.controller.Gui',
'POSync.controller.Connection'
]);
var node_version = process.versions.node;
var chrome_version = process.versions.chrome;
var electron_version = process.versions.electron;
var extjs_version = Ext.getVersion().version;
/*
* Debugging function that sets margin, border, padding and
* background color to help identify the layout of the views
*/
var bg_colors = ["#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff" ];
/************************************************************
*
* GUI
*
************************************************************/
/*
* A form field to select a local directory.
*/
Ext.define('Ext.ux.DirField', {
extend: 'Ext.form.field.Trigger',
alias: 'widget.dirfield',
/* Clicking the button opens a select directory dialog provided by electron */
onTriggerClick: function() {
const {dialog} = require('electron').remote;
var path = dialog.showOpenDialog({
title: 'Select the top directory to synchronize',
properties: ['openDirectory']
});
if (path)
this.setValue (path);
}
});
function set_defaults (level, opts) {
/* set to true(false) to enable(disable) coloured layouts */
if (false) {
if (!opts)
opts = {};
opts.style = {
margin: '2px',
padding: '2px',
border: '1px solid black',
background: bg_colors[level % 6],
};
}
return opts;
}
/* The application GUI */
Ext.define('POSync.view.Viewport', {
extend: 'Ext.container.Viewport',
itemId: 'panel',
layout: 'fit',
defaults: set_defaults(0),
items: {
xtype: 'panel',
title: ']project-open[ Sync 1.0.0',
defaults: set_defaults(1),
layout: 'fit',
items: {
xtype: 'tabpanel',
defaults: set_defaults(2, {
layout: 'fit',
defaults: set_defaults(3)
}),
items: [
Ext.create('POSync.view.LoginPanel'),
{
title: 'Projects',
items: {
xtype: 'grid',
itemId: 'projects',
store: 'Projects',
/* FIXME: emptyText initially not shown */
emptyText: 'No projects available',
columns: [{
text: 'Id',
dataIndex: 'project_id',
align: 'right',
flex: 1
}, {
text: 'Number',
dataIndex: 'project_nr',
flex: 2
}, {
text: 'Name',
dataIndex: 'project_name',
flex: 7
}]
}
},{
title: 'Files',
items: {
xtype: 'treepanel',
itemId: 'files',
store: 'Files',
rootVisible: false,
useArrows: true,
/* FIXME: emptyText initially not shown */
emptyText: 'No files available',
tbar: {
xtype: 'combobox',
fieldLabel: 'Select a project',
store: 'Projects',
queryMode: 'local',
displayField: 'full_name',
valueField: 'project_id',
editable: false,
forceSelection: true,
emptyText: 'No project selected',
},
columns: [{
xtype: 'treecolumn',
text: 'Name',
dataIndex: 'name',
flex: 6
}, {
text: 'Title',
dataIndex: 'title',
flex: 6
}, {
text: 'Description',
dataIndex: 'description',
flex: 6
}, {
text: 'Length',
dataIndex: 'content_length',
align: 'right',
flex: 2
}, {
text: 'Publish Date',
dataIndex: 'publish_date',
flex: 6
}, {
text: 'Id',
dataIndex: 'id',
align: 'right',
flex: 1,
hidden: true
}, {
text: 'Version',
dataIndex: 'version_id',
align: 'right',
flex: 1,
hidden: true
}, {
text: 'Sha1',
dataIndex: 'sha1',
flex: 6,
hidden: false
}, {
text: 'Level',
dataIndex: 'level',
align: 'right',
flex: 1,
hidden: true
}, {
text: 'Expanded',
dataIndex: 'expanded',
flex: 1,
hidden: true
}, {
text: 'Leaf',
dataIndex: 'leaf',
flex: 1,
hidden: true
}, {
text: 'Type',
dataIndex: 'type',
flex: 3,
hidden: false
}, {
text: 'IconCls',
dataIndex: 'iconCls',
flex: 4,
hidden: true
}, {
text: 'Mime Type',
dataIndex: 'mime_type',
flex: 3,
hidden: true
}]
}
},{
title: 'Local directory',
items: {
xtype: 'treepanel',
itemId: 'localdir',
store: 'LocalFiles',
rootVisible: false,
useArrows: true,
/* FIXME: emptyText initially not shown */
emptyText: 'No files available',
columns: [{
xtype: 'treecolumn',
text: 'Name',
dataIndex: 'name',
flex: 6
}, {
text: 'Type',
dataIndex: 'type',
flex: 3,
hidden: false
}, {
text: 'Size',
dataIndex: 'size',
align: 'right',
flex: 2,
hidden: false
}, {
text: 'Date',
dataIndex: 'date',
flex: 6,
hidden: false
}, {
text: 'Sha1',
dataIndex: 'sha1',
flex: 6,
hidden: false
}, {
text: 'Depth',
dataIndex: 'depth',
align: 'right',
flex: 1,
hidden: true
}, {
text: 'Expandable',
dataIndex: 'expandable',
flex: 1,
hidden: true
}, {
text: 'Expanded',
dataIndex: 'expanded',
flex: 1,
hidden: true
}, {
text: 'Leaf',
dataIndex: 'leaf',
flex: 1,
hidden: true
}]
}
},{
title: 'About',
bodyPadding: 10,
/* FIXME: mailto: doesn't work. electron handles it as a local file */
html: [
']project-open[ Sync',
'version 1.0.0',
'Copyright &copy; 2018 ]project-open[ Business Solutions, S.L.',
'Authors:',
'- <a href="mailto:gonzalo.perez@project-open.com">Gonzalo Pérez de Olaguer Córdoba</a>',
'- <a href="mailto:frank.bergmann@project-open.com">Frank Bergmann</a>',
'This code is licensed under the GNU GPL version 2.0 or later',
'',
'<table>' +
'<tr><td>Node version</td><td>' + node_version + '</td></tr>' +
'<tr><td>Chrome version</td><td>' + chrome_version + '</td></tr>' +
'<tr><td>Electron version</td><td>' + electron_version + '</td></tr>' +
'<tr><td>ExtJS version</td><td>' + extjs_version + '</td></tr>' +
'</table>'
].join('<br/>')
}]
},
buttons: [{
text: 'Login',
action: 'login'
}, {
text: 'Projects',
action: 'projects'
}, {
text: 'Files',
action: 'files'
}, {
text: 'Local directory',
action: 'localdir'
}, {
text: 'Sync',
action: 'sync'
}]
}
/* End of POSync.view.Viewport */
});
/************************************************************
*
* Application
*
************************************************************/
var app = Ext.application({
name: 'POSync',
id: 'POSync',
itemId: 'POSync',
autoCreateViewport: true,
models: ['Project', 'File', 'LocalFile', 'Operation'],
stores: ['Projects', 'Files', 'LocalFiles', 'Operations'],
controllers: ['Gui', 'Connection'],
})
// vi: set ts=8 sts=4 sw=4 et :
/************************************************************
*
* Connection Controller
*
************************************************************/
Ext.define('POSync.controller.Connection', {
extend: 'Ext.app.Controller',
id: 'Connection',
refs: [
{ ref: 'panel', selector: '#panel'},
{ ref: 'projects', selector: '#panel #projects'},
{ ref: 'files', selector: '#panel #files'},
{ ref: 'operations', selector: '#panel #operations'},
{ ref: 'localDir', selector: '#panel #localdir'},
],
/* This is called before the viewport is created */
init: function() {
console.log ('Connection.init');
this.control({
});
},
/* This is called after the viewport is created */
onLaunch: function() {
var me = this;
console.log ('Connection.onLaunch: controller onLaunch');
this.projectsStore = this.getProjects().getStore();
this.filesStore = this.getFiles().getStore();
this.localDirStore = this.getLocalDir().getStore();
this.operationsStore = Ext.StoreManager.get('Operations');
var app = this.getApplication();
this.guiController = app.getController('Gui');
// receives an even when clicking "sync" on Tray icon
ipcRenderer.on('sync', (event, arg) => {
console.log('sync: '+arg);
me.sync();
});
},
/* FIXME: no easy way to know if login is successful */
login: function (request_options) {
var me = this;
console.log('Connection.login');
/* Send the login request */
var configData = this.guiController.configData;
console.log ('Connection.login: url('+configData.url+') email('+configData.email+') password('+configData.password+')');
Ext.Ajax.request({
url: configData.url + '/intranet/auto-login-token',
params: {
email: configData.email,
password: configData.password
},
callback: function (options, success, response) {
if (!success) {
console.log('Connection.login: not successfull');
// FIXME: Write some message somewhere
return;
}
var responseJsonString = response.responseText;
var responseObject = JSON.parse(responseJsonString);
if (!responseObject) {
console.log('Connection.login: error parsing responseText='+responseText);
// FIXME: Write some message somewhere
return;
}
var token = responseObject.token;
if (!token) {
console.log('Connection.login: no token in responseText='+responseText);
// FIXME: Write some message somewhere
return;
}
console.log('Connection.login: token='+token);
configData.token = token;
// load the list of projects available to the user
me.loadProjects();
}
});
},
/* Send a request to get the list of projects */
loadProjects: function () {
var me = this;
console.log('Connection.loadProjects:');
// Check if already there
if (this.projectsStore.isLoaded) return;
var configData = this.guiController.configData;
var proxy = this.projectsStore.getProxy();
var baseUrl = configData.url;
proxy.url = baseUrl+"/intranet-rest/im_project";
proxy.extraParams = {
format: 'json',
query: 'parent_id is NULL' // Select only top-level projects
};
this.projectsStore.load({
callback: function (records,operation,success) {
if (!success) {
console.log('Connection.loadProjects: not successfull');
// FIXME: Write some message somewhere
return;
}
me.projectsStore.isLoaded = success; // mark the store as loaded
}
});
},
/* Send requests to load the files of all projects */
loadFiles: function (projectId, successCallback) {
var me = this;
console.log('Gui.loadFiles: project_id='+projectId);
// Skip if already loaded
//if (''+me.filesStore.isLoaded == ''+projectId) return;
var configData = this.guiController.configData;
var proxy = me.filesStore.getProxy();
var baseUrl = configData.url;
proxy.url = baseUrl+"/intranet-rest-fs-openacs/file-tree.json";
proxy.extraParams = {
format: 'json',
object_id: projectId
};
me.filesStore.load({
callback: function (records,operation,success) {
if (!success) {
console.log('Connection.login: not successfull');
// FIXME: Write some message somewhere
return;
}
me.filesStore.isLoaded = projectId;
// Execute callback
successCallback && successCallback.call(me, projectId);
}
});
},
/*
* Get the local directory data and load the LocalFiles store.
* directory-tree provides a tree with the following fields:
*/
loadLocalDirectory: function (projectId) {
console.log('Connection.loadLocalDirectory: '+projectId);
// Skip if already loaded
// if (''+this.localDirStore.isLoaded == ''+projectId) return;
var configData = this.guiController.configData;
if (!this.projectsStore.isLoaded) { alert('Projects not yet loaded'); return; }
// Get the project path
var project = this.projectsStore.getById(''+projectId);
var path = configData.topdir+'/'+project.get('project_path');
// make sure the path exists
var fs = require('fs');
if (!fs.existsSync(path)) { fs.mkdir(path); }
// Get the contents
const dirTree = require ('directory-tree');
const tree = dirTree (path);
this.fixLocalTree (tree);
this.localDirStore.loadTree (tree);
this.localDirStore.isLoaded = projectId;
},
/* Fix a tree before loading it */
fixLocalTree: function (tree) {
if (tree) {
if (tree.type == 'directory') {
tree.type = 'folder';
tree.size = '';
tree.expandable = true;
tree.expanded = tree.children && tree.children.length > 0;
tree.leaf = false;
tree.mime_type = '';
} else {
const cp = require('child_process');
// tree.type = cp.execFileSync('/usr/bin/file', ['--brief', '--mime-type', tree.path]).toString();
// tree.sha1 = cp.execFileSync('/usr/bin/sha1sum', [tree.path]).toString().substr(0,40);
// tree.date = cp.execFileSync('/usr/bin/stat', ['-c', '%y', tree.path]).toString();
tree.type = 'unknown';
tree.sha1 = '<sha1>';
tree.date = '<date>';
tree.expandable = false;
tree.expanded = false;
tree.leaf = true;
tree.mime_type = tree.type;
}
tree.iconCls = 'icon-' + tree.type;
if (tree.children) {
var me = this;
tree.children.forEach (function(child) {
me.fixLocalTree (child);
});
}
}
},
/**
* Start the synchronization
* by loading the files store from the server.
*/
sync: function (projectId) {
var me = this;
console.log('Connection.sync');
// Load the list of files and continue with syncCallback
this.loadFiles(projectId, me.syncCallback);
},
/**
* The list of files has arrived.
* Now we can start with the actual sync
*/
syncCallback: function(projectId) {
var me = this;
console.log('Connection.syncCallback');
// Clean up the operations store
me.operationsStore.removeAll();
var root = me.filesStore.getRootNode();
if (''+me.projectsStore.isLoaded != ''+projectId) this.loadLocalDirectory(projectId);
root.cascadeBy(function(file) {
// Exclude folders and the root
if ("folder" == file.get('type')) return;
if ("root" == file.get('id')) return;
var pathArray = file.getPathArray();
console.log('Connection.sync: path='+pathArray);
console.log(file);
var localFileFound = me.localDirStore.searchUsingPathArray(pathArray);
console.log(localFileFound);
if (!localFileFound) {
var operation = Ext.create('POSync.model.Operation', {
id: 'op_'+file.get('id'),
file_id: file.get('id'),
file_path: pathArray.join('/'),
file_name: file.get('name'),
mime_type: file.get('mime_type'),
file_sha1: null,
op: 'create'
});
me.operationsStore.add(operation);
}
});
me.syncExecOperations(projectId);
},
/**
* Takes a store with sync "Operations" and executes them.
* This performs the actual sync.
*/
syncExecOperations: function(projectId) {
var me = this;
console.log('Connection.syncExecOperations');
me.operationsStore.each(function(op) {
console.log('Connection.syncExecOperations: op');
console.log(op);
var operation = op.get('op');
switch (operation) {
case 'create':
me.syncCreate(projectId, op);
break
default:
alert('syncExecOperations: Internal error: unknown operation='+operation);
}
});
},
/**
* Download a single file.
*
* Called from syncExecOperations, which in turn
* loops through the list of operations created during
* sync.
*/
syncCreate: function(projectId, op) {
var me = this;
console.log('Connection.syncCreate');
console.log(op);
var configData = this.guiController.configData;
var fileId = op.get('file_id');
var filePath = op.get('file_path');
var fileName = op.get('file_name');
var mimeType = op.get('mime_type');
// Get the project path
var project = this.projectsStore.getById(''+projectId);
var projectPath = configData.topdir+'/'+project.get('project_path');
var path = projectPath+'/'+filePath;
// make sure the path exists
var fs = require('fs');
if (!fs.existsSync(path)) { fs.mkdir(path); }
var requestUrl = configData.url + '/intranet-rest-fs-openacs/download?file_id='+fileId;
var xhr = new XMLHttpRequest();
xhr.open("GET", requestUrl);
xhr.responseType = "arraybuffer";
// xhr.responseType = "blob";
xhr.onload = function () {
// Asynchronously saving files after they have been downloaded
if (this.status === 200) {
console.log('Connection.syncCreate: successful download - saving');
// Decode the response encoded by server in base64
var responseBuffer = xhr.response;
var buf64 = new Buffer(responseBuffer, 'base64'); // decode
// make sure the path exists and write the file
var fs = require('fs');
if (!fs.existsSync(path)) { fs.mkdir(path); }
fs.writeFile(path+"/"+fileName, buf64, function() {});
console.log('Connection.syncCreate: written file='+filePath);
} else {
console.log('Connection.syncCreate: download status='+this.status);
}
};
xhr.send();
}
/* End of POSync.controller.Connection */
});
/************************************************************
*
* GUI Controller
*
************************************************************/
/*
* A single controller for the whole GUI
*/
Ext.define('POSync.controller.Gui', {
extend: 'Ext.app.Controller',
is: 'Gui',
refs: [
{ ref: 'panel', selector: '#panel'},
{ ref: 'configPanel', selector: '#panel #config'},
{ ref: 'projects', selector: '#panel #projects'},
{ ref: 'files', selector: '#panel #files'},
{ ref: 'operations', selector: '#panel #operations'},
{ ref: 'projectSelector', selector: '#panel #files combobox'},
{ ref: 'localDir', selector: '#panel #localdir'},
{ ref: 'filterSelector', selector: '#panel #syncdir combobox'}
],
/************************************************************
*
* Initialization
*
************************************************************/
/* Default values for the configuration data */
configDefaults: {
url: 'http://demo.project-open.net',
email: 'ben.bigboss@tigerpond.com',
password: 'ben',
topdir: './topdir',
},
/* Not really used right now, but canonical values of data
* should be placed somewhere.
*/
configData: {
changed: false,
url: null,
email: null,
password: null,
topdir: null,
form_is_valid: null,
selected_project_id: null,
token: null
},
/* This is called before the viewport is created */
init: function() {
console.log ('Gui.init: controller initialization');
this.control({
'#panel #config field': { change: this.onFieldChanged },
'#panel toolbar > button': { click: this.onButtonClicked },
'#panel #projects': { select: this.onProjectSelectedInProjects },
'#panel #files combobox': { select: this.onProjectSelectedInFiles },
});
},
/* This is called after the viewport is created */
onLaunch: function() {
console.log ('Gui.onLaunch: controller onLaunch');
this.projectsStore = this.getProjects().getStore();
this.filesStore = this.getFiles().getStore();
this.localDirStore = this.getLocalDir().getStore();
var app = this.getApplication();
this.connectionController = app.getController('Connection');
this.initConfiguration ();
this.recoverState ();
},
/* Initialize the configuration data */
initConfiguration: function () {
var configPanel = this.getConfigPanel();
console.log('Gui.initConfiguration: config('+configPanel.id+')');
const Store = require ('electron-store');
const configStore = new Store ({name: 'config'});
/* Initialize each configuration value to the saved one
* or to the default value if none is already saved.
*/
var defaults = this.configDefaults;
for (var name in defaults) {
var d = defaults[name];
var v = configStore.get(name, d);
var e = configPanel.down('[name='+name+']');
e.setValue(v);
this.configData[name] = v;
/* Save the configuration value whenever it changes */
e.on('change', function() {
var name = this.name;
var value = this.getValue();
console.log ('Gui.initConfiguration.onChange('+name+'): changed to '+value+') - saving to configStore');
configStore.set(name, value);
});
}
},
/* Recover the application state */
recoverState: function () {
var panel = this.getPanel();
console.log('Gui.recoverState: panel('+panel.id+')');
const Store = require ('electron-store');
const stateStore = new Store ({name: 'state'});
var w = stateStore.get('panel.width', 500);
var h = stateStore.get('panel.height', 300);
panel.setSize(w,h);
panel.on ('resize', function() {
var s = panel.getSize();
stateStore.set({panel: s});
});
},
/************************************************************
*
* Configuration data changes
*
************************************************************/
onFieldChanged: function (field, newValue, oldValue, eOpts) {
var name = field.name;
console.log ('Gui.onFieldChanged: field('+name+') changed from oldValue('+oldValue+') to newValue('+newValue+') eOpts('+eOpts+')');
if (name in this.configDefaults && this.configData[name] != newValue) {
console.log ('Gui.onFieldChanged: field('+name+') changed from('+this.configData[name]+') to('+newValue+')');
this.configData[name] = newValue;
this.configData.changed = true;
}
},
/************************************************************
*
* Button actions
*
************************************************************/
onButtonClicked: function (button, event, eOpts) {
console.log ('Gui.onButtonClicked: button clicked button('+button.getText()+') action('+button.action+') event('+event+') eOpts('+eOpts+')');
switch (button.action) {
case 'login':
console.log('Gui.onButtonClicked: login clicked');
if (this.formIsValid()) {
this.connectionController.login();
} else {
console.log('Connection.login: form is not valid - cancelling request');
alert('Form is not valid');
}
break;
case 'projects':
console.log('Gui.onButtonClicked: projects clicked');
this.connectionController.loadProjects();
break;
case 'files':
console.log('Gui.onButtonClicked: files clicked');
this.connectionController.loadFiles(45956);
break;
case 'localdir':
console.log('Gui.onButtonClicked: localdir clicked');
this.connectionController.loadLocalDirectory(45956);
break;
case 'sync':
console.log('Gui.onButtonClicked: sync clicked');
this.connectionController.sync(45956);
break;
}
},
/************************************************************
*
* Project selection
*
************************************************************/
/* Project selected by clicking a row in the projects panel */
onProjectSelectedInProjects: function (row, record, index, eOpts) {
var id = record.get('project_id');
console.log ('Gui.onProjectSelectedInProjects: id('+id+')');
this.selectProject (record);
},
/* Project selected in the selection box in the files panel */
onProjectSelectedInFiles: function (combo, records, eOpts) {
/* The combobox must be configured for 'single' selection mode */
var id = records[0].get('project_id');
console.log ('Gui.onProjectSelectedInFiles: id('+id+')');
this.selectProject (records[0]);
},
/* Select the specified project and load its files */
selectProject: function (project) {
var id = project.get('project_id');
console.log('Gui.selectProject (project) id('+id+')');
console.log(project);
if (this.configData.selected_project_id != id) {
this.configData.selected_project_id = id;
/* Update the selected row in the projects panel */
this.getProjects().getSelectionModel().select (project);
/* Update the selected project in the combobox of the files panel */
this.getProjectSelector().select(project);
/* Load the files of the selected project */
var me = this;
project.getFile(function(file,operation){
me.selectedProjectFilesLoaded (project,file,operation);
});
}
},
/* Called whenever the list of files of the selected project have been received */
selectedProjectFilesLoaded: function (project,file,operation) {
var pid = project ? project.get('project_id') : 'undef';
var fid = file ? file.get('id') : 'undef';
console.log('Gui.selectedProjectFilesLoaded(project,file,operation): project_id('+pid+') file_id('+fid+')');
console.log(project);
console.log(file);
console.log(operation);
/* Show the files in the Files panel */
this.getFiles().setRootNode(file);
/* Update sync remote project files */
this.syncRemoteFiles (project,file);
},
/************************************************************
*
* Filter selection
*
************************************************************/
/* Project selected in the selection box in the files panel */
onFilterSelected: function (combo, records, eOpts) {
/* The combobox must be configured for 'single' selection mode */
var id = records[0].get('id');
console.log ('Gui.onFilterSelected(combo,records,eOpts): id('+id+')');
console.log(combo);
console.log(records);
console.log(eOpts);
this.filterSyncNodes (id);
},
/* Select the specified project and load its files
*
* WARNING: esto ha sido un puto infierno. He probado MUCHAS formas
* de hacerlo y todas fallaban por una u otra razón. Ésta parece que funciona.
*/
filterSyncNodes: function (id) {
console.log('Gui.filterSyncNodes: id('+id+')');
var view = this.getSyncDir().getView();
this.syncDirStore.forEachRecord (function (record) {
var v = record.filteredBy (id);
var el = Ext.get(view.getNode (record));
/* el is defined only for currently expanded nodes */
if (el)
el.setDisplayed(v);
});
},
/* Check if the form data is valid */
formIsValid: function () {
var config = this.getConfigPanel();
this.configData.url = config.down('[name=url]').getValue();
this.configData.email = config.down('[name=email]').getValue();
this.configData.password = config.down('[name=password]').getValue();
this.configData.topdir = config.down('[name=topdir]').getValue();
this.configData.form_is_valid = config.getForm().isValid();
var msg = [
'form ' + (this.configData.form_is_valid ? 'is' : 'is not') + ' valid and '
+ (this.configData.changed ? 'is' : 'is not') + ' changed',
'URL : "' + this.configData.url + '"',
'Email : "' + this.configData.email + '"',
'Password: "' + this.configData.password + '"',
'Topdir : "' + this.configData.topdir + '"'
].join('\n');
console.log (msg);
return this.configData.form_is_valid;
},
/************************************************************
*
* Window management
*
************************************************************/
/* Hide the window but keep the tray icon */
hideWindow: function () {
console.log('Gui.hideWindow');
const { remote } = require('electron');
/* FIXME: should be the Gui window of this controller's application */
remote.BrowserWindow.getFocusedWindow().hide();
},
/* Close the window and remove the tray icon */
closeWindow: function () {
console.log('Gui.closeWindow');
const { remote } = require('electron');
/* FIXME: should be the Gui window of this controller's application */
remote.BrowserWindow.getFocusedWindow().close();
},
});
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>]project-open[ filestorage synchronization</title>
<!--- <script type="text/javascript" src="ext/ext-all.js"></script> -->
<script type="text/javascript" src="ext/ext-all-debug-w-comments.js"></script>
<link rel="stylesheet" href="ext/resources/css/ext-all-gray.css" type="text/css" media="screen">
<script type="text/javascript" src="app.js"></script>
</head>
<body>
<h1>]project-open[ filestorage synchronization</h1>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</body>
</html>
<!-- vi: set ts=8 sts=2 sw=2 et : -->
/*
* ]project-open[ filestorage synchronization
* Copyright (c) 2018 Gonzalo Pérez de Olaguer Córdoba <gonzalo.perez@project-open.com>
* This code is licensed under the GNU GPL version 2.0 or later
*
* This is the electron initialization script.
* It creates a tray icon to control de application.
*/
const {app, Menu, Tray, BrowserWindow, ipcMain} = require('electron')
let tray = null
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win = null
function createWindow () {
/* Persistent state */
const Store = require('electron-store');
const state_store = new Store({ name: 'state' });
w = state_store.get('win.width', 1200)
h = state_store.get('win.height', 600)
// Create the browser window.
win = new BrowserWindow({
title: ']project-open[ filestorage synchronization',
icon: './images/window.png',
show: false,
width: w, height: h
})
// and load the index.html of the app.
win.loadFile('index.html')
// Open the DevTools.
win.webContents.openDevTools()
// Emitted once when the window is ready to be shown.
// fraber 2018-12-18: Don't show by default
// win.once('ready-to-show', () => { win.show() })
// Emitted when the window is closed.
win.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.
win = null
})
// Emitted when the window is resized.
win.on('resize', () => {
s = win.getSize()
state_store.set({win:{width:s[0],height:s[1]}})
})
}
function showWindow () {
if (win === null) {
createWindow()
} else {
win.show()
}
}
function hideWindow () {
if (win !== null) {
win.hide()
}
}
function closeWindow () {
if (win !== null) {
win.close()
}
}
function toggleWindow () {
if (win === null) {
createWindow()
} else if (win.isVisible()) {
win.hide()
} else {
win.show()
}
}
function sync () {
if (win === null) {
createWindow()
}
// Send an IPC event to the Browser window
win.webContents.send('sync', 'sync');
}
function create_tray_icon () {
tray = new Tray('./images/tray.png')
const contextMenu = Menu.buildFromTemplate([
{label: 'Sync', click: sync},
// {label: 'Show', click: showWindow},
// {label: 'Hide', click: hideWindow},
{label: 'Quit', click: closeWindow}
])
tray.setToolTip(']project-open[ filestorage synchronization')
tray.setContextMenu(contextMenu)
tray.on ('click', toggleWindow)
// Create window and start application, but don't show by default
createWindow();
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', create_tray_icon)
/*
* Data related to a file.
*
* Only the fields required by this application are specified here.
*/
Ext.define('POSync.model.File', {
extend: 'Ext.data.TreeModel',
idProperty: 'id',
fields: [
'id', // The system wide unique ID for this object (-> cr_items.item_id)
// FIXME: could better be file_id
'name', // The name and extension (without path) of the file or folder
'version_id', // The active version of the file (-> cr_revisions.revision_id) (empty string for folders)
'description', // Description of the file or folder
'title', // Title of the file or folder
'iconCls', // Used by ExtJS for the icon, seems to work
// FIXME: should be generated automatically from 'type' (icon-TYPE)
'content_length', // File length in bytes (empty string for folders)
'sha1', // sha-1 Hash of the content (empty string for folders)
'expanded', // true or false (without quotes), default state for tree
'type', // 'folder' for folders and the mime-type for file
'leaf', // false for folders, true for files
// added by SALO
'level', // FIXME: let ExtJS calculate this
'mime_type', // FIXME: same as 'type' for files, and empty string for folders
'publish_date', // empty string for folders
'children' // undefined for files, a (possibly empty) array for folders
],
/**
* Returns the path of the file, starting with root.
*/
getPathArray: function() {
var me = this;
// Skip the root and the 1st level folder, which refers to the project itself.
if ("root" == me.get('id')) return [];
if ("root" == me.get('parentId')) return [];
var fileType = me.get('type');
var parentId = me.get('parentId');
if (!parentId) return [me.get('name')];
var fileStore = Ext.StoreManager.get('Files');
var parent = fileStore.getById(parentId);
if (!parent) return [me.get('name')];
var parentPath = parent.getPathArray();
// For a file return just the path (=parentPath)
if ("folder" != fileType) return parentPath;
// For a folder, add the folder name to the path
parentPath.push(me.get('name'));
return parentPath;
}
});
\ No newline at end of file
/*
* Data related to a local file.
*
* This data is provided by the electron-tree module.
*/
Ext.define('POSync.model.LocalFile', {
extend: 'Ext.data.TreeModel',
idProperty: 'path',
fields: [
'path', // The full path of the file or directory
'name', // The name (with extension) of the file or directory
'extension', // The extension of the file or directory
'size', // The size in bytes
'type', // Either 'directory' or 'file'
'children', // List of files and subdirectories (for directories only)
// Added for internal sencha management
'expandable', // true if directory contents are shown
'expanded', // true if directory contents are shown
'leaf', // true if node has no children
'sha1',
'date',
'mime_type',
'iconCls'
],
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'children'
}
}
});
/*
* What should we do during sync?
*/
Ext.define('POSync.model.Operation', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [
'id',
'file_id',
'file_path',
'file_name',
'mime_type',
'file_sha1',
'op'
]
});
\ No newline at end of file
/*
* Data related to a project.
*
* Only the fields required by this application are specified here.
*/
Ext.define('POSync.model.Project', {
extend: 'Ext.data.Model',
idProperty: 'project_id',
fields: [
'id',
'project_id', // The primary key or object_id of the project
'project_name', // The name of the project
'creation_user', // User_id of the guy creating the project
'project_nr', // The short name of the project.
'project_path', // The short name of the project.
'project_wbs', // WBS code
'parent_id', // The parent of the project or NULL for a main project
'tree_sortkey', // A strange bitstring that determines the hierarchical position
'company_id', // Company for whom the project has been created
'project_status_id', // 76=open, 81=closed, ...
'project_type_id', // 100=Task, 101=Ticket, 2501=Gantt Project, ...
'start_date', // '2001-01-01 00:00:00+01'
'end_date',
'project_lead_id', // Project manager
'percent_completed', // 0 - 100: Defines what has already been done.
'description',
'note',
{ /* used to display in selection boxes */
name: 'full_name',
convert: function (value, record) {
return record.get('project_nr') + ' - ' + record.get('project_name');
}
}
]
});
{
"name": "posync",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "8.10.38",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.38.tgz",
"integrity": "sha512-EibsnbJerd0hBFaDjJStFrVbVBAtOy4dgL8zZFw0uOvPqzBAX59Ci8cgjg3+RgJIWhsB5A4c+pi+D4P9tQQh/A==",
"dev": true
},
"ajv": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz",
"integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
"array-find-index": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
"integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
"dev": true
},
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"dev": true,
"requires": {
"safer-buffer": "~2.1.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
"dev": true
},
"aws4": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
"dev": true
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
"requires": {
"tweetnacl": "^0.14.3"
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"builtin-modules": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
"dev": true
},
"camelcase": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
"integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
"dev": true
},
"camelcase-keys": {
"version": "2.1.0",
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
"dev": true,
"requires": {
"camelcase": "^2.0.0",
"map-obj": "^1.0.0"
}
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true
},
"combined-stream": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
"dev": true,
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"conf": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/conf/-/conf-2.1.0.tgz",
"integrity": "sha512-IcWtHiBjeNtyCG+XK/v9Pz8Q4+nsyvO60Zabn6SsHTR2TMaLN6os/jrUtuQnATb12RI82RHKt+PVEXTsH6XMXQ==",
"requires": {
"dot-prop": "^4.1.0",
"env-paths": "^1.0.0",
"make-dir": "^1.0.0",
"pkg-up": "^2.0.0",
"write-file-atomic": "^2.3.0"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
"integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
"dev": true,
"requires": {
"array-find-index": "^1.0.1"
}
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0"
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"directory-tree": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-2.1.1.tgz",
"integrity": "sha512-9uaftXCRHRntOsmeSxTMLNp52N0tb5eSXkLTIdbDnuC85lleB6/Xub6CG4swSrkS5XXHA56OpTiRj5ntRlsjCg=="
},
"dot-prop": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
"integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
"requires": {
"is-obj": "^1.0.0"
}
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"electron": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/electron/-/electron-2.0.14.tgz",
"integrity": "sha512-8HLVZuscZxVhoMUL6RlF5kMcwGUAMWw5HNwrEmRgzZyBIBbdCO4aMo9z0qknnPTUDROz8xXZFNhFvBXDu61g5Q==",
"dev": true,
"requires": {
"@types/node": "^8.0.24",
"electron-download": "^3.0.1",
"extract-zip": "^1.0.3"
}
},
"electron-download": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz",
"integrity": "sha1-LP1U1pZsAZxNSa1l++Zcyc3vaMg=",
"dev": true,
"requires": {
"debug": "^2.2.0",
"fs-extra": "^0.30.0",
"home-path": "^1.0.1",
"minimist": "^1.2.0",
"nugget": "^2.0.0",
"path-exists": "^2.1.0",
"rc": "^1.1.2",
"semver": "^5.3.0",
"sumchecker": "^1.2.0"
},
"dependencies": {
"path-exists": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"dev": true,
"requires": {
"pinkie-promise": "^2.0.0"
}
}
}
},
"electron-store": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/electron-store/-/electron-store-2.0.0.tgz",
"integrity": "sha512-1WCFYHsYvZBqDsoaS0Relnz0rd81ZkBAI0Fgx7Nq2UWU77rSNs1qxm4S6uH7TCZ0bV3LQpJFk7id/is/ZgoOPA==",
"requires": {
"conf": "^2.0.0"
}
},
"env-paths": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA="
},
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"requires": {
"is-arrayish": "^0.2.1"
}
},
"es6-promise": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz",
"integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==",
"dev": true
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"dev": true
},
"extract-zip": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
"integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
"dev": true,
"requires": {
"concat-stream": "1.6.2",
"debug": "2.6.9",
"mkdirp": "0.5.1",
"yauzl": "2.4.1"
}
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true
},
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"dev": true
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
"dev": true
},
"fd-slicer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
"dev": true,
"requires": {
"pend": "~1.2.0"
}
},
"file-type": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-10.6.0.tgz",
"integrity": "sha512-GNOg09GC+rZzxetGZFoL7QOnWXRqvWuEdKURIJlr0d6MW107Iwy6voG1PPOrm5meG6ls59WkBmBMAZdVSVajRQ=="
},
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"requires": {
"locate-path": "^2.0.0"
}
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
"dev": true
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"fs-extra": {
"version": "0.30.0",
"resolved": "http://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
"integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^2.1.0",
"klaw": "^1.0.0",
"path-is-absolute": "^1.0.0",
"rimraf": "^2.2.8"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"get-stdin": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
"dev": true
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0"
}
},
"glob": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
"dev": true
},
"har-validator": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
"dev": true,
"requires": {
"ajv": "^6.5.5",
"har-schema": "^2.0.0"
}
},
"home-path": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/home-path/-/home-path-1.0.6.tgz",
"integrity": "sha512-wo+yjrdAtoXt43Vy92a+0IPCYViiyLAHyp0QVS4xL/tfvVz5sXIW1ubLZk3nhVkD92fQpUMKX+fzMjr5F489vw==",
"dev": true
},
"hosted-git-info": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
"integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
"dev": true
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
}
},
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
},
"indent-string": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
"integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
"dev": true,
"requires": {
"repeating": "^2.0.0"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
},
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"is-builtin-module": {
"version": "1.0.0",
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"dev": true,
"requires": {
"builtin-modules": "^1.0.0"
}
},
"is-finite": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
"integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
"dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"is-obj": {
"version": "1.0.1",
"resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true
},
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
"dev": true
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"dev": true
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
},
"jsonfile": {
"version": "2.4.0",
"resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6"
}
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
}
},
"klaw": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
"integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.9"
}
},
"load-json-file": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^2.2.0",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0",
"strip-bom": "^2.0.0"
},
"dependencies": {
"pify": {
"version": "2.3.0",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
}
}
},
"locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
"integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
"requires": {
"p-locate": "^2.0.0",
"path-exists": "^3.0.0"
}
},
"loud-rejection": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
"integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
"dev": true,
"requires": {
"currently-unhandled": "^0.4.1",
"signal-exit": "^3.0.0"
}
},
"make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"requires": {
"pify": "^3.0.0"
}
},
"map-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
"integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
"dev": true
},
"meow": {
"version": "3.7.0",
"resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
"dev": true,
"requires": {
"camelcase-keys": "^2.0.0",
"decamelize": "^1.1.2",
"loud-rejection": "^1.0.0",
"map-obj": "^1.0.1",
"minimist": "^1.1.3",
"normalize-package-data": "^2.3.4",
"object-assign": "^4.0.1",
"read-pkg-up": "^1.0.1",
"redent": "^1.0.0",
"trim-newlines": "^1.0.0"
}
},
"mime-db": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
"integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==",
"dev": true
},
"mime-types": {
"version": "2.1.21",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
"integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
"dev": true,
"requires": {
"mime-db": "~1.37.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
}
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"normalize-package-data": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
"dev": true,
"requires": {
"hosted-git-info": "^2.1.4",
"is-builtin-module": "^1.0.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
},
"nugget": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz",
"integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=",
"dev": true,
"requires": {
"debug": "^2.1.3",
"minimist": "^1.1.0",
"pretty-bytes": "^1.0.2",
"progress-stream": "^1.1.0",
"request": "^2.45.0",
"single-line-log": "^1.1.2",
"throttleit": "0.0.2"
}
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"dev": true
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true
},
"object-keys": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
"integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
"dev": true
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
},
"p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
"integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
"requires": {
"p-try": "^1.0.0"
}
},
"p-locate": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
"requires": {
"p-limit": "^1.1.0"
}
},
"p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"dev": true,
"requires": {
"error-ex": "^1.2.0"
}
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-type": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
},
"dependencies": {
"pify": {
"version": "2.3.0",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
}
}
},
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
"dev": true
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
},
"pinkie": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
"dev": true
},
"pinkie-promise": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
"dev": true,
"requires": {
"pinkie": "^2.0.0"
}
},
"pkg-up": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
"integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
"requires": {
"find-up": "^2.1.0"
}
},
"pretty-bytes": {
"version": "1.0.4",
"resolved": "http://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz",
"integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=",
"dev": true,
"requires": {
"get-stdin": "^4.0.1",
"meow": "^3.1.0"
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true
},
"progress-stream": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz",
"integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=",
"dev": true,
"requires": {
"speedometer": "~0.1.2",
"through2": "~0.2.3"
}
},
"psl": {
"version": "1.1.29",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
"integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==",
"dev": true
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"dev": true
},
"rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true,
"requires": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
}
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
"dev": true,
"requires": {
"load-json-file": "^1.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^1.0.0"
}
},
"read-pkg-up": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
"dev": true,
"requires": {
"find-up": "^1.0.0",
"read-pkg": "^1.0.0"
},
"dependencies": {
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"dev": true,
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"path-exists": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"dev": true,
"requires": {
"pinkie-promise": "^2.0.0"
}
}
}
},
"readable-stream": {
"version": "1.1.14",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"redent": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
"integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
"dev": true,
"requires": {
"indent-string": "^2.1.0",
"strip-indent": "^1.0.1"
}
},
"repeating": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
"integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
"dev": true,
"requires": {
"is-finite": "^1.0.0"
}
},
"request": {
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"dev": true,
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.0",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.4.3",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
}
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true,
"requires": {
"glob": "^7.0.5"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
"dev": true
},
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"single-line-log": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz",
"integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=",
"dev": true,
"requires": {
"string-width": "^1.0.1"
}
},
"spdx-correct": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
"integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
"dev": true,
"requires": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-exceptions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
"integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
"dev": true
},
"spdx-expression-parse": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
"dev": true,
"requires": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-license-ids": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz",
"integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==",
"dev": true
},
"speedometer": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz",
"integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=",
"dev": true
},
"sshpk": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz",
"integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==",
"dev": true,
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
}
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"dev": true
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
"requires": {
"is-utf8": "^0.2.0"
}
},
"strip-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
"integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
"dev": true,
"requires": {
"get-stdin": "^4.0.1"
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true
},
"sumchecker": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-1.3.1.tgz",
"integrity": "sha1-ebs7RFbdBPGOvbwNcDodHa7FEF0=",
"dev": true,
"requires": {
"debug": "^2.2.0",
"es6-promise": "^4.0.5"
}
},
"throttleit": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz",
"integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=",
"dev": true
},
"through2": {
"version": "0.2.3",
"resolved": "http://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
"integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
"dev": true,
"requires": {
"readable-stream": "~1.1.9",
"xtend": "~2.1.1"
}
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"dev": true,
"requires": {
"psl": "^1.1.24",
"punycode": "^1.4.1"
},
"dependencies": {
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
}
}
},
"trim-newlines": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
"integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
"dev": true
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
"requires": {
"safe-buffer": "^5.0.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
"dev": true,
"requires": {
"punycode": "^2.1.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
"dev": true
},
"validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
"requires": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
}
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"write-file-atomic": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz",
"integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==",
"requires": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
}
},
"xtend": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
"integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
"dev": true,
"requires": {
"object-keys": "~0.4.0"
}
},
"yauzl": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
"integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
"dev": true,
"requires": {
"fd-slicer": "~1.0.1"
}
}
}
}
{
"name": "posync",
"version": "1.0.0",
"description": "Primera prueba con electron.",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"files": [
"index.html",
"app.js",
"ext",
"images",
"topdir"
],
"author": "salo",
"license": "ISC",
"devDependencies": {
"electron": "^2.0.8"
},
"dependencies": {
"directory-tree": "^2.1.0",
"electron-store": "^2.0.0",
"file-type": "^10.4.0"
}
}
/*
* DataStore for files.
*
* This is a read-only store.
* Proxy URL depends on application's configuration settings.
*/
Ext.define('POSync.store.Files', {
storeId: 'Files',
extend: 'Ext.data.TreeStore',
requires: 'POSync.model.File',
model: 'POSync.model.File',
nodeParam: 'object_id',
root: {
expanded: true,
children: []
},
proxy: {
type: 'ajax',
url: '/intranet-rest-fs-openacs/file-tree.json',
reader: {
type: 'json',
root: 'children'
}
}
});
/*
* DataStore for local files.
*
* Proxy URL depends on application's configuration settings.
*/
Ext.define('POSync.store.LocalFiles', {
extend: 'Ext.data.TreeStore',
requires: 'POSync.model.LocalFile',
model: 'POSync.model.LocalFile',
isLoaded: null, // ID of project loaded
root: {
expanded: true,
children: []
},
/* Load the store with the specified tree */
loadTree: function (tree) {
var proxy = this.getProxy();
proxy.data = tree;
this.load();
},
/**
* Check if a file with the given path exists
*/
searchUsingPathArray: function(pathArray) {
var me = this;
var root = me.getRootNode();
// console.log(root);
// Iterate through the pathArray elements from
// the top to find the file in the local folder
var node = root;
for (var i = 0; i < pathArray.length; i++) {
var path = pathArray[i];
// Check all children
var child = null;
var children = node.children;
if (!children) return null;
for (var j = 0; j < children.length; j++) {
var childName = children[j].get('name');
if (path == childName) {
child = children[j];
}
}
if (!child) return null;
node = child;
}
}
});
/*
* DataStore for Sync operations
*/
Ext.define('POSync.store.Operations', {
storeId: 'operations',
extend: 'Ext.data.Store',
requires: 'POSync.model.Operation',
model: 'POSync.model.Operation'
});
/*
* DataStore for projects.
*
* This is a read-only store.
* Proxy URL depends on application's configuration settings.
*/
Ext.define('POSync.store.Projects', {
storeId: 'Projects',
extend: 'Ext.data.Store',
model: 'POSync.model.Project',
autoLoad: false, // Allow the application to set extraParams
remoteFilter: true, // Do not filter on the Sencha side
pageSize: 100000, // Load all projects, no matter what size(?)
isLoaded: false,
proxy: {
type: 'rest', // Standard ]po[ REST interface for loading
url: '/intranet-rest/im_project',
appendId: true,
timeout: 300000,
extraParams: {
format: 'json',
query: 'parent_id is NULL' // Select only top-level projects
// deref_p: '1' // We don't need company_name etc.
// This should be overwrittten during load.
},
reader: {
type: 'json', // Tell the Proxy Reader to parse JSON
root: 'data', // Where do the data start in the JSON file?
totalProperty: 'total' // Total number of tickets for pagination
},
writer: {
type: 'json' // Allow Sencha to write ticket changes
}
}
});
Ext.define('POSync.view.LoginPanel', {
alias: 'loginPanel',
extend: 'Ext.panel.Panel',
title: 'Configuration',
items: {
xtype: 'form',
itemId: 'config',
bodyPadding: 10,
defaults: {
anchor: '100%',
xtype: 'textfield',
allowBlank: false
},
items: [{
name: 'url',
inputType: 'url',
// vtype: 'url',
regexp: '/(((^https?)|(^ftp)):\/\/((([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*)|(localhost|LOCALHOST))\/?)/',
fieldLabel: 'Server URL',
emptyText: 'Enter here the URL of ]project-open[ server',
}, {
name: 'email',
inputType: 'email',
vtype: 'email',
fieldLabel: 'Email',
emptyText: 'Enter here the email to use as login name',
}, {
name: 'password',
inputType: 'password',
fieldLabel: 'Password',
emptyText: 'Enter here your login password',
}, {
name: 'topdir',
xtype: 'dirfield',
fieldLabel: 'Local directory',
/* FIXME: without an emptyText renders to height zero */
emptyText: 'Click the arrow to select the local directory to sync',
}]
}
});
// Currently not used, because moving it creates an error
Ext.define('POSync.view.ProjectsPanel', {
alias: 'projectsPanel',
extend: 'Ext.panel.Panel',
title: 'Projects',
items: {
xtype: 'grid',
itemId: 'projects',
store: 'Projects',
/* FIXME: emptyText initially not shown */
emptyText: 'No projects available',
columns: [{
text: 'Id',
dataIndex: 'project_id',
align: 'right',
flex: 1
}, {
text: 'Number',
dataIndex: 'project_nr',
flex: 2
}, {
text: 'Name',
dataIndex: 'project_name',
flex: 7
}]
}
});
......@@ -9,8 +9,8 @@ ad_page_contract {
@author Frank Bergmann
@cvs-id $Id$
} {
{ file_id "" }
{ version_id "" }
{ file_id:integer "" }
{ version_id:integer "" }
}
if {"" eq $file_id && "" ne $version_id} {
......@@ -31,13 +31,15 @@ set content_root [fs::get_root_folder]
set template_root [db_string template_root "select content_template__get_root_folder()"]
set user_id [ad_conn user_id]
set storage_area_key "CR_FILES"
set path [cr_fs_path $storage_area_key]
set filename [db_string filename "select :path || content from cr_revisions where revision_id = :version_id"]
set filename [db_string filename "select :path || content from cr_revisions where revision_id = :version_id" -default ""]
if {"" eq $filename} {
# version_id not found
doc_return 404 "text/plain" "Not found"
ad_script_abort
}
set binary_content ""
if {[catch {
......@@ -51,7 +53,7 @@ if {[catch {
}
ad_return_complaint 1 "$path - $filename - len=[string length $binary_content] - sha1=[ns_sha1 $binary_content]"
# ad_return_complaint 1 "$path - $filename - len=[string length $binary_content] - sha1=[ns_sha1 $binary_content]"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment