better error messages, more robust csv uploading

This commit is contained in:
Max Ogden 2011-09-16 21:56:23 -07:00
parent 935e0d15a0
commit fe8df046da
10 changed files with 145 additions and 98 deletions

6
app.js
View File

@ -115,12 +115,6 @@ ddoc.lists = {
}
}
ddoc.validate_doc_update = function (newDoc, oldDoc, userCtx) {
if (newDoc._deleted === true && userCtx.roles.indexOf('_admin') === -1) {
throw "Only admin can delete documents on this database.";
}
};
couchapp.loadAttachments(ddoc, path.join(__dirname, 'attachments'));
module.exports = ddoc;

View File

@ -6,16 +6,8 @@
<link rel="stylesheet" href="style/reset.css" media="screen">
<link rel="stylesheet" href="style/data-table.css" media="screen">
<link rel="stylesheet" href="style/style.css" media="screen">
<script type="text/javascript" src="script/lib/jquery-1.6.1.min.js"></script>
<!-- only using jqueryui for draggable -- a lighter solution would be nice -->
<script type="text/javascript" src="script/lib/jquery-ui-1.8.14.custom.min.js"></script>
<script type="text/javascript" src="script/lib/jquery.mustache.js"></script>
<script type="text/javascript" src="script/lib/jquery.couch2.js"></script>
<script type="text/javascript" src="script/lib/jquery.hotkeys.js"></script>
<script type="text/javascript" src="script/lib/sammy-0.6.3.min.js"></script>
<script type="text/javascript" src="script/lib/underscore.js"></script>
<script type="text/javascript" src="script/lib/microevent.js"></script>
<script type="text/javascript" src="script/lib/traverse.js"></script>
<script type="text/javascript" src="script/deps-min.js"></script>
<script type="text/javascript" src="script/util.js"></script>
<script type="text/javascript" src="script/costco.js"></script>
<script type="text/javascript" src="script/recline.js"></script>
@ -32,7 +24,10 @@
<div class="project-actions"></div>
<div class="project-controls"></div>
</div>
<div class="main_content"></div>
<div class="main_content">
<div class="left-panel"></div>
<div class="right-panel"></div>
</div>
</div>
<div id="notification-container">
@ -94,43 +89,40 @@
<script type='text/mustache' class="generatingTemplate"><div class="loading">Loading...</div></script>
<script type='text/mustache' class="tableContainerTemplate">
<div id="right-panel">
<div id="tool-panel">
<div id="summary-bar">
<span id="docCount"></span>
<div id="tool-panel">
<div id="summary-bar">
<span id="docCount"></span>
</div>
<div id="download">
</div>
</div>
<div id="view-panel">
<div class="viewpanel-header">
<div class="viewpanel-pagesize">
<span>
Show:
</span>
<a href="javascript:{}" class="viewPanel-pagingControls-page action">5</a>
<a href="javascript:{}" class="viewPanel-pagingControls-page selected">10</a>
<a href="javascript:{}" class="viewPanel-pagingControls-page action">25</a>
<a href="javascript:{}" class="viewPanel-pagingControls-page action">50</a>
<span>
rows
</span>
</div>
<div id="download">
<div class="viewpanel-sorting">
</div>
<div class="viewpanel-paging">
<a href="javascript:{}" class="first inaction">« first</a>
<a href="javascript:{}" class="previous inaction"> previous</a>
<span class="viewpanel-pagingcount">
1 - 10
</span>
<a href="javascript:{}" class="next action">next </a>
<a href="javascript:{}" class="last action">last »</a>
</div>
</div>
<div id="view-panel">
<div class="viewpanel-header">
<div class="viewpanel-pagesize">
<span>
Show:
</span>
<a href="javascript:{}" class="viewPanel-pagingControls-page action">5</a>
<a href="javascript:{}" class="viewPanel-pagingControls-page selected">10</a>
<a href="javascript:{}" class="viewPanel-pagingControls-page action">25</a>
<a href="javascript:{}" class="viewPanel-pagingControls-page action">50</a>
<span>
rows
</span>
</div>
<div class="viewpanel-sorting">
</div>
<div class="viewpanel-paging">
<a href="javascript:{}" class="first inaction">« first</a>
<a href="javascript:{}" class="previous inaction"> previous</a>
<span class="viewpanel-pagingcount">
1 - 10
</span>
<a href="javascript:{}" class="next action">next </a>
<a href="javascript:{}" class="last action">last »</a>
</div>
</div>
<div class="data-table-container">
</div>
<div class="data-table-container">
</div>
</div>
</script>
@ -304,7 +296,7 @@
Paste in an array of JSON objects representing the documents that you would like to insert into the database.
</p>
<p class="info">
<code>[{woo: "pizza"}, {tasty: "muffins"}]</code>
<code>[{"woo": "pizza"}, {"tasty": "muffins"}]</code>
</p>
<div class="menu-container data-table-cell-editor">
<textarea class="data-table-cell-copypaste-editor" bind="textarea">{{value}}</textarea>

View File

@ -45,12 +45,12 @@ onmessage = function(message) {
var docs = parseCSV(message.data.data);
var req = new XMLHttpRequest();
req.onprogress = req.upload.onprogress = function(e) {
if(e.lengthComputable) postMessage(JSON.stringify({ percent: (e.loaded / e.total) * 100 }));
if(e.lengthComputable) postMessage({ percent: (e.loaded / e.total) * 100 });
};
req.onreadystatechange = function() { if (req.readyState == 4) postMessage(JSON.stringify( {done: true} )) };
req.onreadystatechange = function() { if (req.readyState == 4) postMessage({done: true, response: req.responseText}) };
req.open('POST', message.data.url);
req.setRequestHeader('Content-Type', 'application/json');
req.send(JSON.stringify({docs: docs}));

View File

@ -90,7 +90,14 @@ var costco = function() {
if(!docs.length) dfd.resolve("Failed: No docs specified");
couch.request({url: app.baseURL + "api/_bulk_docs", type: "POST", data: JSON.stringify({docs: docs})})
.then(
function(resp) {ensureCommit().then(function() { dfd.resolve(resp) })},
function(resp) {ensureCommit().then(function() {
var error = couch.responseError(resp);
if (error) {
dfd.reject(error);
} else {
dfd.resolve(resp);
}
})},
function(err) { dfd.reject(err.responseText) }
);
return dfd.promise();
@ -119,25 +126,29 @@ var costco = function() {
data: event.target.result
};
var worker = new Worker('script/costco-csv-worker.js');
worker.onmessage = function(message) {
message = JSON.parse(message.data);
console.log(message)
if (message.done) {
util.hide('dialog');
util.notify("Data uploaded successfully!");
recline.initializeTable(app.offset);
} else if (message.percent) {
if (message.percent === 100) {
util.notify("Waiting for CouchDB...", {persist: true, loader: true})
} else {
util.notify("Uploading... " + message.percent + "%");
}
} else {
util.notify(JSON.stringify(message));
}
};
worker.postMessage(payload);
worker.onmessage = function(event) {
var message = event.data;
if (message.done) {
var error = couch.responseError(JSON.parse(message.response))
console.log('e',error)
if (error) {
app.emitter.emit(error, 'error');
} else {
util.notify("Data uploaded successfully!");
recline.initializeTable(app.offset);
}
util.hide('dialog');
} else if (message.percent) {
if (message.percent === 100) {
util.notify("Waiting for CouchDB...", {persist: true, loader: true})
} else {
util.notify("Uploading... " + message.percent + "%");
}
} else {
util.notify(JSON.stringify(message));
}
};
worker.postMessage(payload);
};
} else {
util.notify('File not selected. Please try again');

19
attachments/script/deps-min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -10,9 +10,32 @@
url: "/"
};
couch.errors = {
forbidden: "You aren't allowed to do that."
}
couch.responseError = function(response) {
if(_.isArray(response) && (response.length > 0) ) response = response[0];
if (response.error) return couch.errors[response.error];
}
couch.request = function(opts) {
var ajaxOpts = $.extend({}, defaults, opts);
return $.ajax(ajaxOpts).promise();
var ajaxOpts = $.extend({}, defaults, opts)
, dfd = $.Deferred()
;
$.ajax(ajaxOpts).then(
function(successResponse) {
var error = couch.responseError(successResponse);
if (error) app.emitter.emit(error, 'error');
dfd.resolve(successResponse);
},
function(errorResponse) {
app.emitter.emit("Fatal XHR Error", 'error');
}
)
return dfd.promise();
}
couch.get = function(url) {

View File

@ -122,7 +122,12 @@ var recline = function() {
}
function getPageSize() {
return parseInt($(".viewpanel-pagesize .selected").text());
var pagination = $(".viewpanel-pagesize .selected");
if (pagination.length > 0) {
return parseInt(pagination.text())
} else {
return 10;
}
}
function fetchRows(id, skip) {
@ -158,9 +163,9 @@ var recline = function() {
)
}
function getDbInfo() {
function getDbInfo(url) {
var dfd = $.Deferred();
return couch.request({url: app.baseURL + "api"}).then(function(dbInfo) {
return couch.request({url: url}).then(function(dbInfo) {
app.dbInfo = dbInfo;
$.extend(app.dbInfo, {
@ -176,18 +181,15 @@ var recline = function() {
}
function bootstrap() {
util.registerEmitter();
function bootstrap(id) {
app.dbPath = app.baseURL + "api/";
util.listenFor(['esc', 'return']);
getDbInfo().then(function( dbInfo ) {
util.render('tableContainer', app.container);
util.render('title', 'project-title', app.dbInfo);
getDbInfo(app.dbPath).then(function( dbInfo ) {
util.render('title', 'project-title', dbInfo);
util.render( 'generating', 'project-actions' );
updateDocCount(app.dbInfo.doc_count);
couch.session().then(function(session) {
if ( session.userCtx.name ) {
var text = "Sign out";
@ -196,24 +198,26 @@ var recline = function() {
}
util.render('controls', 'project-controls', {text: text});
})
initializeTable();
})
}
function initializeTable(offset) {
util.render( 'tableContainer', 'right-panel' );
showDialog('busy');
couch.request({url: app.baseURL + 'api/headers'}).then(function ( headers ) {
couch.request({url: app.dbPath + 'headers'}).then(function ( headers ) {
util.hide('dialog');
getDbInfo().then(function(dbInfo) {
getDbInfo(app.dbPath).then(function(dbInfo) {
updateDocCount(dbInfo.doc_count);
});
app.headers = headers;
app.csvUrl = app.baseURL + 'api/csv?headers=' + escape(JSON.stringify(headers));
app.csvUrl = app.dbPath + 'csv?headers=' + escape(JSON.stringify(headers));
util.render( 'actions', 'project-actions', $.extend({}, app.dbInfo, {url: app.csvUrl}) );
fetchRows(false, offset);
})
}
return {
formatDiskSize: formatDiskSize,

View File

@ -1,6 +1,7 @@
var app = {
baseURL: util.getBaseURL(document.location.pathname),
container: 'main_content'
container: 'main_content',
emitter: util.registerEmitter()
};
app.handler = function(route) {
@ -227,7 +228,6 @@ app.after = {
},
function (err) {
util.hide('dialog');
util.notify("Error uploading: " + err.responseText);
}
);
} else {
@ -246,6 +246,10 @@ app.sammy = $.sammy(function () {
});
$(function() {
app.emitter.on('error', function(error) {
util.notify("Server error: " + error);
})
util.traverse = require('traverse');
app.sammy.run();
})

View File

@ -32,7 +32,7 @@ var util = function() {
};
};
MicroEvent.mixin(Emitter);
app.emitter = new Emitter();
return new Emitter();
}
function listenFor(keys) {

View File

@ -450,7 +450,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
font-size: 11px;
}
#left-panel {
.left-panel {
position: fixed;
overflow: hidden;
padding: 0px;
@ -459,14 +459,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
background: #e3e9ff;
}
#left-panel .ui-tabs .ui-tabs-panel {
.left-panel .ui-tabs .ui-tabs-panel {
border-left: none;
border-right: none;
border-bottom: none;
padding: 0;
}
#right-panel {
.right-panel {
position: fixed;
top: 40px;
left: 0px;